Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2468 lines
72 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: msgina.c
//
// Contents: Microsoft Logon GUI DLL
//
// History: 7-14-94 RichardW Created
//
//----------------------------------------------------------------------------
#include "msgina.h"
// Link Window
#include "shlobj.h"
#include "shlobjp.h"
#include <accctrl.h>
#include <aclapi.h>
#include "tsperf.h"
HINSTANCE hDllInstance; // My instance, for resource loading
HINSTANCE hAppInstance; // App instance, for dialogs, etc.
PWLX_DISPATCH_VERSION_1_4 pWlxFuncs; // Ptr to table of functions
PWLX_DISPATCH_VERSION_1_4 pTrueTable ; // Ptr to table in winlogon
DWORD SafeBootMode;
BOOL g_IsTerminalServer;
BOOL g_Console = TRUE;
BOOL VersionMismatch ;
DWORD InterfaceVersion ;
HKEY WinlogonKey ;
int TSAuthenticatedLogon(PGLOBALS pGlobals);
BOOL
WINAPI
DllMain(
HINSTANCE hInstance,
DWORD dwReason,
LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls ( hInstance );
hDllInstance = hInstance;
g_IsTerminalServer = !!(USER_SHARED_DATA->SuiteMask & (1 << TerminalServer));
#if DBG
InitDebugSupport();
#endif
InitializeSecurityGlobals();
_Shell_DllMain(hInstance, dwReason);
return(TRUE);
case DLL_PROCESS_DETACH:
_Shell_DllMain(hInstance, dwReason);
FreeSecurityGlobals();
return(TRUE);
default:
return(TRUE);
}
}
BOOL
WINAPI
WlxNegotiate(
DWORD dwWinlogonVersion,
DWORD *pdwDllVersion
)
{
InterfaceVersion = dwWinlogonVersion ;
if (dwWinlogonVersion < WLX_CURRENT_VERSION)
{
DebugLog(( DEB_WARN, "Old WLX interface (%x)\n", dwWinlogonVersion ));
if ( dwWinlogonVersion < WLX_VERSION_1_1 )
{
return FALSE ;
}
VersionMismatch = TRUE ;
}
*pdwDllVersion = WLX_CURRENT_VERSION;
DebugLog((DEB_TRACE, "Negotiate: successful!\n"));
return(TRUE);
}
BOOL GetDefaultCADSetting(void)
{
BOOL bDisableCad = FALSE;
NT_PRODUCT_TYPE NtProductType;
//
// Servers and workstations in a domain will default to requiring CAD.
// Workstations in a workgroup won't require CAD (by default). Note,
// the default CAD setting can be overwritten by either a machine
// preference or machine policy.
//
RtlGetNtProductType(&NtProductType);
if ( IsWorkstation(NtProductType) )
{
if ( !IsMachineDomainMember() ) // This function is doing some caching
{ // so we don't need to be brighter here
bDisableCad = TRUE;
}
}
return bDisableCad;
}
#define MSGINA_ANIM_FAST_TIME 20
#define MSGINA_ANIM_REMOTE_TIME 100
#define MSGINA_ANIM_SLOW_TIME 500
//
// GetAnimationTimeInterval
// Purpose:
// Retreive animation time interval in ms. There are different settings depending
// on w/not we are remote
//
//
// Params:
// pGlobals - IN global settings
//
// Returns:
// Animation timeslice in milliseconds.
//
DWORD GetAnimationTimeInterval(PGLOBALS pGlobals)
{
DWORD dwAnimationTimeSlice;
if (IsActiveConsoleSession()) {
//Console defaults
dwAnimationTimeSlice = MSGINA_ANIM_FAST_TIME;
}
else if (pGlobals->MuGlobals.fSlowAnimationRate) {
//Remote but reduced animation
dwAnimationTimeSlice = MSGINA_ANIM_SLOW_TIME;
}
else {
//Remote but with anim
dwAnimationTimeSlice = MSGINA_ANIM_REMOTE_TIME;
}
return dwAnimationTimeSlice;
}
BOOL GetDisableCad(PGLOBALS pGlobals)
// Returns whether or not the user should be required to press C-A-D before
// logging on. TRUE == Disable CAD, FALSE == Require CAD
{
DWORD dwSize;
DWORD dwType;
HKEY hKey;
BOOL fDisableCad = GetDefaultCADSetting();
dwSize = sizeof(fDisableCad);
RegQueryValueEx (WinlogonKey, DISABLE_CAD, NULL, &dwType,
(LPBYTE) &fDisableCad , &dwSize);
//
// Check if C+A+D is disabled via policy
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0, KEY_READ,
&hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(fDisableCad);
RegQueryValueEx (hKey, DISABLE_CAD, NULL, &dwType,
(LPBYTE) &fDisableCad , &dwSize);
RegCloseKey (hKey);
}
//
// By default do a fast animation for the progress band
//
pGlobals->MuGlobals.fSlowAnimationRate = FALSE;
//
// Check if C+A+D is disabled for remote Hydra clients and copy the client name
//
if (g_IsTerminalServer ) {
HANDLE dllHandle;
//
// Load winsta.dll
//
dllHandle = LoadLibraryW(L"winsta.dll");
if (dllHandle) {
PWINSTATION_QUERY_INFORMATION pfnWinstationQueryInformation;
pfnWinstationQueryInformation = (PWINSTATION_QUERY_INFORMATION) GetProcAddress(
dllHandle,
"WinStationQueryInformationW"
);
if (pfnWinstationQueryInformation) {
WINSTATIONCLIENT ClientData;
ULONG Length;
//
// Get the CAD disable data from the client
//
if ( pfnWinstationQueryInformation( SERVERNAME_CURRENT,
LOGONID_CURRENT,
WinStationClient,
&ClientData,
sizeof(ClientData),
&Length ) ) {
//
// Take the client settings only if the CAD is not globally disabled for the server,
// and, if this is not the console active session.
//
if (!fDisableCad && !IsActiveConsoleSession() )
{
fDisableCad = ClientData.fDisableCtrlAltDel;
}
//
// Copy the Client Name, even console has a client name now, due to PTS and console disconnect features.
//
//
lstrcpyn(pGlobals->MuGlobals.ClientName, ClientData.ClientName, CLIENTNAME_LENGTH);
if (ClientData.PerformanceFlags &
TS_PERF_DISABLE_MENUANIMATIONS) {
pGlobals->MuGlobals.fSlowAnimationRate = TRUE;
}
}
else
{
if (!IsActiveConsoleSession()) {
fDisableCad = TRUE;
}
// TS start could have been delayed until 60seconds post first console login.
// Hence, it is safe to assume that this is the console session, besides,
// we are initing some benign env var.
lstrcpyn(pGlobals->MuGlobals.ClientName,L"Console", CLIENTNAME_LENGTH );
}
}
FreeLibrary(dllHandle);
}
}
// Friendly UI on -> ALWAYS disable CAD.
if (ShellIsFriendlyUIActive())
{
fDisableCad = TRUE;
}
return fDisableCad;
}
BOOL GetSCForceOption()
// Returns whether or not the user should be required to use a SC to logon
// TRUE == ForceSCLogon, FALSE == Non ForceSCLogon
{
DWORD dwSize;
DWORD dwType;
HKEY hKey;
BOOL fForceSCLogon = FALSE;
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_POLICY_KEY, 0, KEY_READ,
&hKey) == ERROR_SUCCESS )
{
dwSize = sizeof(fForceSCLogon);
RegQueryValueEx(hKey, FORCE_SC_LOGON, NULL, &dwType,
(LPBYTE) &fForceSCLogon , &dwSize);
RegCloseKey (hKey);
}
return fForceSCLogon;
}
BOOL
MsGinaSetOption(
HANDLE hWlx,
DWORD Option,
ULONG_PTR Value,
ULONG_PTR * OldValue
)
{
return FALSE ;
}
BOOL
MsGinaGetOption(
HANDLE hWlx,
DWORD Option,
ULONG_PTR * Value
)
{
return FALSE ;
}
PWLX_DISPATCH_VERSION_1_4
GetFixedUpTable(
PVOID FakeTable
)
{
int err ;
PVOID p ;
PWLX_DISPATCH_VERSION_1_4 pNewTable ;
DWORD dwSize ;
DWORD dwType ;
pNewTable = LocalAlloc( LMEM_FIXED, sizeof( WLX_DISPATCH_VERSION_1_4 ) );
if ( !pNewTable )
{
return NULL ;
}
dwSize = sizeof( PVOID );
err = RegQueryValueEx(
WinlogonKey,
TEXT("Key"),
NULL,
&dwType,
(PUCHAR) &p,
&dwSize );
if ( (err == 0) &&
(dwType == REG_BINARY) &&
(dwSize == sizeof( PVOID ) ) )
{
pTrueTable = p ;
switch ( InterfaceVersion )
{
case WLX_VERSION_1_1:
dwSize = sizeof( WLX_DISPATCH_VERSION_1_1 );
break;
case WLX_VERSION_1_2:
case WLX_VERSION_1_3:
case WLX_VERSION_1_4:
dwSize = sizeof( WLX_DISPATCH_VERSION_1_2 );
break;
}
RtlCopyMemory(
pNewTable,
FakeTable,
dwSize );
pNewTable->WlxGetOption = MsGinaGetOption ;
pNewTable->WlxSetOption = MsGinaSetOption ;
pNewTable->WlxCloseUserDesktop = pTrueTable->WlxCloseUserDesktop ;
pNewTable->WlxWin31Migrate = pTrueTable->WlxWin31Migrate ;
pNewTable->WlxQueryClientCredentials = pTrueTable->WlxQueryClientCredentials ;
pNewTable->WlxQueryInetConnectorCredentials = pTrueTable->WlxQueryInetConnectorCredentials ;
pNewTable->WlxDisconnect = pTrueTable->WlxDisconnect ;
pNewTable->WlxQueryTerminalServicesData = pTrueTable->WlxQueryTerminalServicesData ;
pNewTable->WlxQueryConsoleSwitchCredentials = pTrueTable->WlxQueryConsoleSwitchCredentials ;
pNewTable->WlxQueryTsLogonCredentials = pTrueTable->WlxQueryTsLogonCredentials;
}
else
{
LocalFree( pNewTable );
pNewTable = NULL ;
}
return pNewTable ;
}
extern DWORD g_dwMainThreadId; // declared in status.c (used to "fix" a thread safety issue)
BOOL
WINAPI
WlxInitialize(
LPWSTR lpWinsta,
HANDLE hWlx,
PVOID pvReserved,
PVOID pWinlogonFunctions,
PVOID *pWlxContext
)
{
PGLOBALS pGlobals;
HKEY hKey;
DWORD dwSize, dwType;
DWORD dwStringMemory;
DWORD dwAutoLogonCount ;
DWORD dwNoLockWksta ;
// Upon which bitmaps should our text be painted.
BOOL fTextOnLarge;
BOOL fTextOnSmall;
ULONG_PTR ProbeValue ;
PWLX_GET_OPTION GetOptCall ;
BOOL DoFixup ;
BOOL DidFixup ;
int err ;
err = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
WINLOGON_KEY,
0,
KEY_READ | KEY_WRITE,
&WinlogonKey );
if ( err != 0 )
{
return FALSE ;
}
DoFixup = TRUE ;
DidFixup = FALSE ;
if ( VersionMismatch )
{
pWlxFuncs = GetFixedUpTable( pWinlogonFunctions );
if ( pWlxFuncs )
{
DidFixup = TRUE ;
}
else
{
pWlxFuncs = (PWLX_DISPATCH_VERSION_1_4) pWinlogonFunctions ;
DidFixup = FALSE ;
}
}
else
{
pWlxFuncs = (PWLX_DISPATCH_VERSION_1_4) pWinlogonFunctions ;
}
//
// Probe the callback table to make sure we're ok:
//
try
{
GetOptCall = pWlxFuncs->WlxGetOption ;
if ( GetOptCall( hWlx,
WLX_OPTION_DISPATCH_TABLE_SIZE,
&ProbeValue ) )
{
if ( ProbeValue == sizeof( WLX_DISPATCH_VERSION_1_4 ) )
{
DoFixup = FALSE ;
}
}
}
except ( EXCEPTION_EXECUTE_HANDLER )
{
NOTHING ;
}
if ( DoFixup && !DidFixup )
{
pWlxFuncs = GetFixedUpTable( pWinlogonFunctions );
}
if ( !pWlxFuncs )
{
return FALSE ;
}
pGlobals = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GLOBALS));
if ( !pGlobals )
{
return FALSE ;
}
if ( !NT_SUCCESS ( RtlInitializeCriticalSection( &pGlobals->csGlobals ) ) )
{
LocalFree( pGlobals );
return FALSE ;
}
if ( !InitHKeyCurrentUserSupport() )
{
RtlDeleteCriticalSection( &pGlobals->csGlobals );
LocalFree( pGlobals );
return FALSE ;
}
// Reserve enough memory for 4 strings of length MAX_STRING_BYTES
dwStringMemory = (MAX_STRING_BYTES * sizeof (WCHAR)) * 4;
pGlobals->LockedMemory = VirtualAlloc(
NULL,
dwStringMemory,
MEM_COMMIT,
PAGE_READWRITE);
if ( pGlobals->LockedMemory == NULL )
{
CleanupHKeyCurrentUserSupport();
RtlDeleteCriticalSection( &pGlobals->csGlobals );
LocalFree( pGlobals );
return FALSE ;
}
VirtualLock( pGlobals->LockedMemory, dwStringMemory);
memset( pGlobals->LockedMemory, 0, dwStringMemory );
pGlobals->UserName = pGlobals->LockedMemory ;
pGlobals->Domain = pGlobals->UserName + MAX_STRING_BYTES ;
pGlobals->Password = pGlobals->Domain + MAX_STRING_BYTES ;
pGlobals->OldPassword = pGlobals->Password + MAX_STRING_BYTES ;
*pWlxContext = (PVOID) pGlobals;
pGlobals->hGlobalWlx = hWlx;
pWlxFuncs->WlxUseCtrlAltDel(hWlx);
if ( DCacheInitialize() )
{
pGlobals->Cache = DCacheCreate();
}
else
{
pGlobals->Cache = NULL ;
}
if ( pGlobals->Cache == NULL )
{
CleanupHKeyCurrentUserSupport();
RtlDeleteCriticalSection(&pGlobals->csGlobals);
VirtualFree( pGlobals->LockedMemory, 0, MEM_RELEASE );
LocalFree (pGlobals);
DebugLog((DEB_ERROR, "Failed to init domain cache!\n"));
return(FALSE);
}
dwSize = sizeof( dwNoLockWksta );
if ( RegQueryValueEx(
WinlogonKey,
DISABLE_LOCK_WKSTA,
0,
&dwType,
(PUCHAR) &dwNoLockWksta,
&dwSize ) == 0 )
{
if ( dwNoLockWksta == 2 )
{
dwNoLockWksta = 0 ;
RegSetValueEx(
WinlogonKey,
DISABLE_LOCK_WKSTA,
0,
REG_DWORD,
(PUCHAR) &dwNoLockWksta,
sizeof( DWORD ) );
}
}
if (!InitializeAuthentication(pGlobals))
{
*pWlxContext = NULL;
CleanupHKeyCurrentUserSupport();
RtlDeleteCriticalSection(&pGlobals->csGlobals);
VirtualFree( pGlobals->LockedMemory, 0, MEM_RELEASE );
LocalFree (pGlobals);
DebugLog((DEB_ERROR, "Failed to init authentication!\n"));
return(FALSE);
}
//
// Start by clearing the entire Multi-User Globals
//
RtlZeroMemory( &pGlobals->MuGlobals, sizeof(pGlobals->MuGlobals) );
//
// Get our SessionId and save in globals
//
pGlobals->MuGlobals.SessionId = NtCurrentPeb()->SessionId;
if (pGlobals->MuGlobals.SessionId != 0) {
g_Console = FALSE;
}
//
// if this is a TS session, we can't run if there is a version
// mismatch. Fail out now.
//
if ( (!g_Console) &&
(VersionMismatch ) )
{
*pWlxContext = NULL;
CleanupHKeyCurrentUserSupport();
RtlDeleteCriticalSection(&pGlobals->csGlobals);
LocalFree (pGlobals);
DebugLog((DEB_ERROR, "Failed to init authentication!\n"));
return(FALSE);
}
//
// this actually starts the s/c thread.
//
if( g_Console )
{
ULONG_PTR Value ;
pWlxFuncs->WlxGetOption(pGlobals->hGlobalWlx,
WLX_OPTION_SMART_CARD_PRESENT,
&Value);
}
//
// If this is auto admin logon, or ctrl+alt+del is disabled,
// generate a fake SAS right now. Don't attempt AutoLogon unless on Console
//
if ((g_Console && GetProfileInt( APPLICATION_NAME, TEXT("AutoAdminLogon"), 0) ) ||
GetDisableCad(pGlobals))
{
dwSize = sizeof( DWORD );
if ( RegQueryValueEx( WinlogonKey, AUTOLOGONCOUNT_KEY, NULL,
&dwType, (LPBYTE) &dwAutoLogonCount,
&dwSize ) == 0 )
{
//
// AutoLogonCount value was present. Check the value:
//
if ( dwAutoLogonCount == 0 )
{
//
// Went to zero. Reset everything:
//
RegDeleteValue( WinlogonKey, AUTOLOGONCOUNT_KEY );
RegDeleteValue( WinlogonKey, DEFAULT_PASSWORD_KEY );
RegSetValueEx( WinlogonKey, AUTOADMINLOGON_KEY, 0,
REG_SZ, (LPBYTE) TEXT("0"), 2 * sizeof(WCHAR) );
}
else
{
//
// Decrement the count, and try the logon:
//
dwAutoLogonCount-- ;
RegSetValueEx( WinlogonKey, AUTOLOGONCOUNT_KEY,
0, REG_DWORD, (LPBYTE) &dwAutoLogonCount,
sizeof( DWORD ) );
KdPrint(( "AutoAdminLogon = 1\n" ));
pWlxFuncs->WlxSasNotify(pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
}
}
else
{
//
// AutoLogonCount not present
//
KdPrint(( "AutoAdminLogon = 1\n" ));
pWlxFuncs->WlxSasNotify( pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL );
}
}
//
// get the safeboot mode
//
if (RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
TEXT("system\\currentcontrolset\\control\\safeboot\\option"),
0,
KEY_READ,
& hKey
) == ERROR_SUCCESS)
{
dwSize = sizeof(DWORD);
RegQueryValueEx (
hKey,
TEXT("OptionValue"),
NULL,
&dwType,
(LPBYTE) &SafeBootMode,
&dwSize
);
RegCloseKey( hKey );
}
//
// Load branding images
//
LoadBrandingImages(FALSE, &fTextOnLarge, &fTextOnSmall);
//
// Create fonts
//
CreateFonts(&pGlobals->GinaFonts);
//
// Draw localized text on branding images
//
PaintBitmapText(&pGlobals->GinaFonts, fTextOnLarge, fTextOnSmall);
//
// Initialize consumer windows changes
//
_Shell_Initialize(pGlobals);
//
// Initialize this global that's used in status.c. We know that WlxInitialize is called
// on the main thread of winlogon.
//
g_dwMainThreadId = GetCurrentThreadId();
return(TRUE);
}
VOID
WINAPI
WlxDisplaySASNotice(PVOID pContext)
{
PGLOBALS pGlobals = (PGLOBALS)pContext;
INITCOMMONCONTROLSEX icce;
icce.dwSize = sizeof (icce);
icce.dwICC = ICC_ANIMATE_CLASS;
InitCommonControlsEx(&icce);
// Need to register the link window
LinkWindow_RegisterClass();
pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
hDllInstance,
(LPTSTR) IDD_WELCOME_DIALOG,
NULL,
WelcomeDlgProc,
(LPARAM) pContext );
}
PWSTR
AllocAndExpandProfilePath(
PGLOBALS pGlobals,
LPWSTR lpUserName)
{
WCHAR szPath[MAX_PATH];
WCHAR szFullPath[MAX_PATH];
WCHAR szServerName[UNCLEN+1];
WCHAR szUserName[100];
DWORD cFullPath;
PWSTR pszFullPath;
DWORD dwPathLen=0;
//
// Set up the logon server environment variable:
//
dwPathLen = pGlobals->Profile->LogonServer.Length;
// Truncation would be bad but should never happen (all machine names less
// UNCLEN chars). But LogonServer.Buffer might not be NULL terminated.
ASSERT(sizeof(szServerName) >= 2*sizeof(WCHAR) + dwPathLen + sizeof(WCHAR));
if (sizeof(szServerName) < 2*sizeof(WCHAR) + dwPathLen + sizeof(WCHAR)) // all lengths in bytes
{
dwPathLen = sizeof(szServerName) - 3*sizeof(WCHAR); // Won't overflow now
}
szServerName[0] = L'\\';
szServerName[1] = L'\\';
CopyMemory( &szServerName[2],
pGlobals->Profile->LogonServer.Buffer,
dwPathLen );
szServerName[dwPathLen / sizeof(WCHAR) + 2] = L'\0';
SetEnvironmentVariable(LOGONSERVER_VARIABLE, szServerName);
dwPathLen = lstrlen(pGlobals->MuGlobals.TSData.ProfilePath);
if (!g_Console && (dwPathLen > 0)) {
//
// See if the user specified a Terminal Server profile path.
// If so, we override the regular profile path
//
if (dwPathLen < MAX_PATH)
{
lstrcpy(szPath, pGlobals->MuGlobals.TSData.ProfilePath);
}
else
{
lstrcpy(szPath, NULL_STRING);
}
} else {
dwPathLen = pGlobals->Profile->ProfilePath.Length;
if (dwPathLen == 0)
{
return(NULL);
}
//
// Copy the profile path locally
//
if (dwPathLen <= (MAX_PATH-1)*sizeof(WCHAR))
{
CopyMemory( szPath,
pGlobals->Profile->ProfilePath.Buffer,
dwPathLen);
szPath[dwPathLen / sizeof(WCHAR)] = L'\0';
}
else
{
lstrcpy(szPath, NULL_STRING);
}
}
if (lpUserName && *lpUserName) {
szUserName[0] = TEXT('\0');
GetEnvironmentVariableW (USERNAME_VARIABLE, szUserName, 100);
SetEnvironmentVariableW (USERNAME_VARIABLE, lpUserName);
}
//
// Expand the profile path using current settings:
//
cFullPath = ExpandEnvironmentStrings(szPath, szFullPath, MAX_PATH);
if ((cFullPath) && (cFullPath <= MAX_PATH))
{
pszFullPath = LocalAlloc(LMEM_FIXED, cFullPath * sizeof(WCHAR));
if (pszFullPath)
{
CopyMemory( pszFullPath, szFullPath, cFullPath * sizeof(WCHAR));
}
}
else
{
pszFullPath = NULL;
}
if (lpUserName && *lpUserName) {
if (szUserName[0] != TEXT('\0'))
SetEnvironmentVariableW (USERNAME_VARIABLE, szUserName);
else
SetEnvironmentVariableW (USERNAME_VARIABLE, NULL);
}
return(pszFullPath);
}
PWSTR
AllocPolicyPath(
PGLOBALS pGlobals)
{
LPWSTR pszPath = NULL;
if (2 * sizeof(WCHAR) + pGlobals->Profile->LogonServer.Length + sizeof(L"\\netlogon\\ntconfig.pol") <= MAX_PATH * sizeof(WCHAR))
{
pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
if ( pszPath )
{
pszPath[0] = L'\\';
pszPath[1] = L'\\';
CopyMemory( &pszPath[2],
pGlobals->Profile->LogonServer.Buffer,
pGlobals->Profile->LogonServer.Length );
wcscpy( &pszPath[ pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2],
L"\\netlogon\\ntconfig.pol" );
}
}
return(pszPath);
}
PWSTR
AllocNetDefUserProfilePath(
PGLOBALS pGlobals)
{
LPWSTR pszPath = NULL;
if (2 * sizeof(WCHAR) + pGlobals->Profile->LogonServer.Length + sizeof(L"\\netlogon\\Default User") <= MAX_PATH * sizeof(WCHAR))
{
pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
if ( pszPath )
{
//
// Set up the logon server environment variable:
//
pszPath[0] = L'\\';
pszPath[1] = L'\\';
CopyMemory( &pszPath[2],
pGlobals->Profile->LogonServer.Buffer,
pGlobals->Profile->LogonServer.Length );
wcscpy( &pszPath[ pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2],
L"\\netlogon\\Default User" );
}
}
return(pszPath);
}
PWSTR
AllocServerName(
PGLOBALS pGlobals)
{
LPWSTR pszPath = NULL;
if (2 * sizeof(WCHAR) + pGlobals->Profile->LogonServer.Length + 1 <= MAX_PATH * sizeof(WCHAR))
{
pszPath = LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
if ( pszPath )
{
//
// Set up the logon server environment variable:
//
pszPath[0] = L'\\';
pszPath[1] = L'\\';
CopyMemory( &pszPath[2],
pGlobals->Profile->LogonServer.Buffer,
pGlobals->Profile->LogonServer.Length );
pszPath[pGlobals->Profile->LogonServer.Length / sizeof(WCHAR) + 2] = L'\0';
}
}
return(pszPath);
}
VOID
DetermineDnsDomain(
PGLOBALS pGlobals
)
{
DWORD dwError = ERROR_SUCCESS;
LPTSTR lpUserName = NULL, lpTemp;
ULONG ulUserNameSize;
pGlobals->DnsDomain = NULL;
if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
{
ulUserNameSize = 75; // Pick a default size. We'll expand if necessary
lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
if (!lpUserName)
{
dwError = GetLastError();
if( dwError == ERROR_SUCCESS )
{
ASSERT(FALSE && "LocalAlloc failed w/out setting last error");
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
}
else
{
DWORD dwCount = 0;
while (TRUE)
{
if (GetUserNameEx (NameDnsDomain, lpUserName, &ulUserNameSize))
{
dwError = ERROR_SUCCESS;
break;
}
else
{
dwError = GetLastError();
//
// If the call failed due to insufficient memory, realloc
// the buffer and try again.
//
if ((dwError == ERROR_INSUFFICIENT_BUFFER) || (dwError == ERROR_MORE_DATA))
{
LocalFree(lpUserName);
lpUserName = LocalAlloc (LPTR, ulUserNameSize * sizeof(TCHAR));
if (!lpUserName) {
dwError = GetLastError();
if( dwError == ERROR_SUCCESS )
{
ASSERT(FALSE && "LocalAlloc failed w/out setting last error");
dwError = ERROR_NOT_ENOUGH_MEMORY;
}
break; // Can't recover
}
}
else if (dwError == ERROR_NO_SUCH_DOMAIN)
{
// We just logged on so we know that the domain exists
// This is what happens with NT4 domain though since we try
// to query the DNS domain name and it doesn't exists
// Let's fall back to our old logic
break;
}
else if (dwError == ERROR_NONE_MAPPED)
{
// That's what's returned for local users.
break;
}
else
{
dwCount++;
if (dwCount > 3)
{
break;
}
}
}
}
}
RevertToSelf();
}
else
{
dwError = GetLastError();
}
if (dwError == ERROR_SUCCESS)
{
//
// At this point lpUserName contains something like domain.company.com\someuser
// We are only interested in the dns domain name
lpTemp = lpUserName;
while (*lpTemp && ((*lpTemp) != TEXT('\\')))
lpTemp++;
if (*lpTemp != TEXT('\\'))
{
DebugLog((DEB_ERROR, "DetermineDnsDomain: Failed to find slash in DNS style name\n"));
dwError = ERROR_INVALID_DATA;
}
else
{
*lpTemp = TEXT('\0');
pGlobals->DnsDomain = DupString(lpUserName);
}
}
if (dwError != ERROR_SUCCESS)
{
//
// If GetUserNameEx didn't yield a DNS name, fall back on the old code.
//
PDOMAIN_CACHE_ENTRY Entry ;
Entry = DCacheLocateEntry(
pGlobals->Cache,
pGlobals->FlatDomain.Buffer );
if ( Entry )
{
if ( Entry->Type == DomainNt5 )
{
pGlobals->DnsDomain = DupString( Entry->DnsName.Buffer );
}
else
{
//
// For all intended purposes, this is good enough.
// winlogon needs to know for sure for policy (419926)
//
pGlobals->DnsDomain = DupString( L"\\NT4" );
}
DCacheDereferenceEntry( Entry );
}
else
{
//
// winlogon needs to know this as well. errors and not-found
// were assumed NT5
//
pGlobals->DnsDomain = DupString( L"\\XFOREST" );
}
}
if (lpUserName)
{
LocalFree(lpUserName);
}
//
// Don't leave with pGlobals->DnsDomain set to NULL
//
if ( pGlobals->DnsDomain == NULL)
{
pGlobals->DnsDomain = DupString( L"" );
}
}
PWSTR
AllocVolatileEnvironment(
PGLOBALS pGlobals)
{
BOOL DeepShare;
LPWSTR pszEnv;
DWORD dwSize;
TCHAR lpHomeShare[MAX_PATH] = TEXT("");
TCHAR lpHomePath[MAX_PATH] = TEXT("");
TCHAR lpHomeDrive[4] = TEXT("");
TCHAR lpHomeDirectory[MAX_PATH] = TEXT("");
BOOL TSHomeDir = FALSE;
PVOID lpEnvironment = NULL; // Dummy environment
BOOL bUserHasHomedir = TRUE;
//
// Set the home directory environment variables
// in a dummy environment block
//
if ( !g_Console ) {
// See if the user specified a TerminalServer Home Directory.
// If so, we override the regular directory
if (lstrlen(pGlobals->MuGlobals.TSData.HomeDir) > 0) {
ASSERT(sizeof(lpHomeDirectory) >= sizeof(pGlobals->MuGlobals.TSData.HomeDir));
lstrcpy(lpHomeDirectory, pGlobals->MuGlobals.TSData.HomeDir);
TSHomeDir = TRUE;
}
if (lstrlen(pGlobals->MuGlobals.TSData.HomeDirDrive) > 0) {
ASSERT(sizeof(lpHomeDrive) >= sizeof(pGlobals->MuGlobals.TSData.HomeDirDrive));
lstrcpy(lpHomeDrive, pGlobals->MuGlobals.TSData.HomeDirDrive);
TSHomeDir = TRUE;
}
}
if (!TSHomeDir) {
if (pGlobals->Profile->HomeDirectoryDrive.Length &&
(pGlobals->Profile->HomeDirectoryDrive.Length + sizeof(TCHAR)) <= sizeof(lpHomeDrive)) {
memcpy(lpHomeDrive, pGlobals->Profile->HomeDirectoryDrive.Buffer,
pGlobals->Profile->HomeDirectoryDrive.Length);
lpHomeDrive[pGlobals->Profile->HomeDirectoryDrive.Length / sizeof(TCHAR)] = 0;
}
if (pGlobals->Profile->HomeDirectory.Length &&
(pGlobals->Profile->HomeDirectory.Length + sizeof(TCHAR)) <= (MAX_PATH*sizeof(TCHAR))) {
memcpy(lpHomeDirectory, pGlobals->Profile->HomeDirectory.Buffer,
pGlobals->Profile->HomeDirectory.Length);
lpHomeDirectory[pGlobals->Profile->HomeDirectory.Length / sizeof(TCHAR)] = 0;
}
}
//
// Note : we are passing in a null environment because here we are only
// interested in parsing the homedirectory and set it in the volatile
// environment. We are not interested in setting it in the
// environment block here.
//
// Also over here, we are only interested in setting up the
// HOMESHARE and HOMEPATH variables in such a way that
// %HOMESHARE%%HOMEPATH% points to the homedir. This is done
// so that when folder redirection calls SHGetFolderPath, it will be
// able to expand the paths properly. Therefore, at this point
// it is not really necessary to pay attention to the
// ConnectHomeDirToRoot policy because that policy might get changed
// during policy processing anyway and will be picked up when the
// shell starts up. Note: the values of HOMESHARE, HOMEPATH and
// HOMEDRIVE will be updated correctly when the shell starts up
//
// At this point we do not map the home directory for 2 reasons:
// (a) We are not aware of the ConnectHomeDirToRoot setting here.
// (b) We do not want to do the network mapping twice : once here
// and once when the shell starts up.
//
// Also, we do not want to set the home directory variables in the
// volatile environment if it is not specified in the user object.
// This prevents us from stomping over logon scripts that might
// be setting the homedirectory variables themselves rather than
// relying on the values set on the user object.
//
if (!lpHomeDirectory[0])
bUserHasHomedir = FALSE;
if (bUserHasHomedir)
SetHomeDirectoryEnvVars(&lpEnvironment,
lpHomeDirectory,
lpHomeDrive,
lpHomeShare,
lpHomePath,
&DeepShare);
if ( pGlobals->DnsDomain == NULL )
{
DetermineDnsDomain( pGlobals );
}
dwSize = lstrlen (LOGONSERVER_VARIABLE) + 3
+ lstrlen (pGlobals->Profile->LogonServer.Buffer) + 3;
if (bUserHasHomedir)
{
if (L'\0' == lpHomeShare[0])
{
// Set the homedrive variable only if the home directory is not
// a UNC path
dwSize += lstrlen (HOMEDRIVE_VARIABLE) + 1 + lstrlen (lpHomeDrive) + 3;
}
else
{
// Set the homeshare variable only if the home directory is a UNC path
dwSize += lstrlen (HOMESHARE_VARIABLE) + 1 + lstrlen (lpHomeShare) + 3;
}
dwSize += lstrlen (HOMEPATH_VARIABLE) + 1 + lstrlen (lpHomePath) + 3;
}
if ( pGlobals->DnsDomain )
{
dwSize += (lstrlen( USERDNSDOMAIN_VARIABLE ) + 3 +
lstrlen( pGlobals->DnsDomain ) + 3 );
}
if (g_IsTerminalServer) {
dwSize += lstrlen (CLIENTNAME_VARIABLE) + 1 + lstrlen (pGlobals->MuGlobals.ClientName) + 3;
}
pszEnv = LocalAlloc(LPTR, dwSize * sizeof(WCHAR));
if ( pszEnv )
{
LPWSTR pszEnvTmp;
lstrcpy (pszEnv, LOGONSERVER_VARIABLE);
lstrcat (pszEnv, L"=\\\\");
lstrcat (pszEnv, pGlobals->Profile->LogonServer.Buffer);
pszEnvTmp = pszEnv + (lstrlen( pszEnv ) + 1);
if (bUserHasHomedir)
{
if (L'\0' == lpHomeShare[0])
{
// Set the homedrive variable only if it is not a UNC path
lstrcpy (pszEnvTmp, HOMEDRIVE_VARIABLE);
lstrcat (pszEnvTmp, L"=");
lstrcat (pszEnvTmp, lpHomeDrive);
pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
}
else
{
// Set the homeshare variable only if it is a UNC path
lstrcpy (pszEnvTmp, HOMESHARE_VARIABLE);
lstrcat (pszEnvTmp, L"=");
lstrcat (pszEnvTmp, lpHomeShare);
pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
}
// Set the homepath variable
lstrcpy (pszEnvTmp, HOMEPATH_VARIABLE);
lstrcat (pszEnvTmp, L"=");
lstrcat (pszEnvTmp, lpHomePath);
pszEnvTmp += (lstrlen(pszEnvTmp) + 1);
}
// This check doesn't match the check above
// It is safe though.
if (( pGlobals->DnsDomain ) && (*(pGlobals->DnsDomain)))
{
lstrcpy( pszEnvTmp, USERDNSDOMAIN_VARIABLE );
lstrcat( pszEnvTmp, L"=" );
lstrcat( pszEnvTmp, pGlobals->DnsDomain );
pszEnvTmp += (lstrlen( pszEnvTmp ) + 1 );
}
if (g_IsTerminalServer) {
lstrcpy (pszEnvTmp, CLIENTNAME_VARIABLE);
lstrcat (pszEnvTmp, L"=");
lstrcat (pszEnvTmp, pGlobals->MuGlobals.ClientName);
pszEnvTmp += (lstrlen( pszEnvTmp ) + 1 );
}
*pszEnvTmp++ = L'\0';
}
return(pszEnv);
}
BOOL
ForceAutoLogon(
VOID
)
{
HKEY hkey;
BOOL fForceKeySet = FALSE;
BOOL fHaveAutoLogonCount = FALSE;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hkey))
{
DWORD dwValue;
DWORD dwType;
DWORD dwSize = sizeof (dwValue);
if (ERROR_SUCCESS == RegQueryValueEx(hkey,
AUTOLOGONCOUNT_KEY,
NULL,
&dwType,
(LPBYTE) &dwValue,
&dwSize ))
{
fHaveAutoLogonCount = TRUE;
}
dwSize = sizeof (dwValue);
if (ERROR_SUCCESS == RegQueryValueEx(hkey,
FORCEAUTOLOGON_KEY,
NULL,
&dwType,
(LPBYTE) &dwValue,
&dwSize ))
{
//
// Check the value as a REG_SZ since all the other autologon values
// are stored as REG_SZs. Check it as a REG_DWORD for back-compat.
//
if (dwType == REG_DWORD)
{
if (0 != dwValue)
{
fForceKeySet = TRUE;
}
}
else if (dwType == REG_SZ)
{
//
// Reread the value for consistency with the way other
// autologon values are read/checked.
//
if (GetProfileInt(APPLICATION_NAME, FORCEAUTOLOGON_KEY, 0) != 0)
{
fForceKeySet = TRUE;
}
}
}
RegCloseKey(hkey);
}
return (fHaveAutoLogonCount || fForceKeySet);
}
/****************************************************************************\
*
* FUNCTION: CreateFolderAndACLit_Worker
*
* PURPOSE: Create a home-dir folder for the user, and set the proper security
* such that only the user and the admin have access to the folder.
*
* PARAMS: [in ] szPath the full path, could be UNC or local
* [in ] pUserSID user SID
* [out] pdwErr error code if anything fails.
*
* RETURNS: TRUE if all went ok
* FALSE if a bad home dir path was specified.
*
* HISTORY:
* TsUserEX ( Alhen's code which was based on EricB's DSPROP_CreateHomeDirectory )
*
*
\****************************************************************************/
#define ACE_COUNT 2
BOOLEAN CreateFolderAndACLit_Worker ( PWCHAR szPath , PSID pUserSID, PDWORD pdwErr , BOOLEAN pathIsLocal )
{
SECURITY_ATTRIBUTES securityAttributes;
BOOLEAN rc;
PSID psidAdmins = NULL;
*pdwErr = 0;
ZeroMemory( &securityAttributes , sizeof( SECURITY_ATTRIBUTES ) );
//
// Apply ACL on the TS Home Dir irrespective of whether its a local or UNC Path
// Add the ACE for the owner and administrators only
//
{
// build a DACL
PSID pAceSid[ACE_COUNT];
PACL pDacl;
SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
SECURITY_DESCRIPTOR securityDescriptor;
PSECURITY_DESCRIPTOR pSecurityDescriptor = &securityDescriptor;
int i;
EXPLICIT_ACCESS rgAccessEntry[ACE_COUNT] = {0};
OBJECTS_AND_SID rgObjectsAndSid[ACE_COUNT] = {0};
if (!AllocateAndInitializeSid(&NtAuth,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdmins ) )
{
DebugLog(( DEB_ERROR, "AllocateAndInitializeSid failed\n" ));
*pdwErr = GetLastError( );
rc=FALSE;
goto done;
}
pAceSid[0] = pUserSID;
pAceSid[1] = psidAdmins;
for ( i = 0 ; i < ACE_COUNT; i++)
{
rgAccessEntry[i].grfAccessPermissions = GENERIC_ALL;
rgAccessEntry[i].grfAccessMode = GRANT_ACCESS;
rgAccessEntry[i].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
// build the trustee structs
//
BuildTrusteeWithObjectsAndSid(&(rgAccessEntry[i].Trustee),
&(rgObjectsAndSid[i]),
NULL,
NULL,
pAceSid[i]);
}
// add the entries to the ACL
//
*pdwErr = SetEntriesInAcl( ACE_COUNT, rgAccessEntry, NULL, &pDacl );
if( *pdwErr != 0 )
{
DebugLog(( DEB_ERROR, "SetEntriesInAcl() failed\n" ));
rc = FALSE;
goto done;
}
// build a security descriptor and initialize it
// in absolute format
if( !InitializeSecurityDescriptor( pSecurityDescriptor , SECURITY_DESCRIPTOR_REVISION ) )
{
DebugLog(( DEB_ERROR, "InitializeSecurityDescriptor() failed\n" ) );
*pdwErr = GetLastError( );
rc=FALSE;
goto done;
}
// add DACL to security descriptor (must be in absolute format)
if( !SetSecurityDescriptorDacl( pSecurityDescriptor,
TRUE, // bDaclPresent
pDacl,
FALSE // bDaclDefaulted
) )
{
DebugLog(( DEB_ERROR, "SetSecurityDescriptorDacl() failed\n" ));
*pdwErr = GetLastError( );
rc=FALSE;
goto done;
}
// set the owner of the directory
if( !SetSecurityDescriptorOwner( pSecurityDescriptor ,
pUserSID ,
FALSE // bOwnerDefaulted
) )
{
DebugLog(( DEB_ERROR, "SetSecurityDescriptorOwner() failed\n" ));
*pdwErr = GetLastError( );
rc= FALSE;
goto done;
}
if ( ! IsValidSecurityDescriptor( pSecurityDescriptor ) )
{
DebugLog(( DEB_ERROR , "BAD security desc\n") );
}
// build a SECURITY_ATTRIBUTES struct as argument for
// CreateDirectory()
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
securityAttributes.bInheritHandle = FALSE;
if( !CreateDirectory( szPath , &securityAttributes ) )
{
*pdwErr = GetLastError( );
rc = FALSE;
goto done;
}
else
{
rc = TRUE;
}
}
done:
if( psidAdmins != NULL )
{
FreeSid( psidAdmins );
}
return rc;
}
/****************************************************************************\
*
* FUNCTION: TermServ_CreateHomePathAndACLit
*
* PURPOSE: create the TS specific user home folder and ACL it such that only
* user and Admins have access to it.
*
* PARAMS: PGLOABLS, from which TSData and userSid are used
*
* RETURNS: TRUE if all went ok
* FALSE if a bad home dir path was specified.
*
* HISTORY:
*
*
\****************************************************************************/
BOOLEAN TermServ_CreateHomePathAndACLit( PGLOBALS pG )
{
BOOLEAN rc;
DWORD dwErr = NO_ERROR;
BOOLEAN pathIsLocal;
DWORD dwFileAttribs;
WLX_TERMINAL_SERVICES_DATA *pTSData;
pTSData = & pG->MuGlobals.TSData;
DebugLog((DEB_ERROR, "pTSData->HomeDir = %ws \n", pTSData->HomeDir ));
if (pTSData->HomeDir[0] == L'\0')
{
// no TS specific path, we are done.
return TRUE;
}
// check for empty strings, which means no TS specific path.
// decide if this is a UNC path to home dir or a local path
if( pTSData->HomeDir[1] == TEXT( ':' ) && pTSData->HomeDir[2] == TEXT( '\\' ) )
{
pathIsLocal = TRUE; // we have a string starting with something like "D:\"
}
else if ( pTSData->HomeDir[0] == TEXT( '\\' ) && pTSData->HomeDir[1] == TEXT( '\\' ) )
{
pathIsLocal = FALSE; // we have a string like "\\", which means a UNC path
}
else
{
// we seem to have a bad path, set it to empty so that
// the default paths will be used by userenv's code for settin up
// stuff
pTSData->HomeDirDrive[0] = pTSData->HomeDir[0] = TEXT('\0');
DebugLog((DEB_ERROR, "Bad path for Terminal Services home folder" ));
return FALSE;
}
dwFileAttribs = GetFileAttributes( pTSData->HomeDir );
if (dwFileAttribs == - 1)
{
dwErr = GetLastError();
if (dwErr == ERROR_FILE_NOT_FOUND)
{
// We need to create the home DIR here, userenv does not create home folders.
rc = CreateFolderAndACLit_Worker( pTSData->HomeDir , pG->UserProcessData.UserSid , &dwErr , pathIsLocal );
}
else
{
rc = FALSE;
}
}
else if ( dwFileAttribs & FILE_ATTRIBUTE_DIRECTORY )
{
DebugLog((DEB_WARN , ("Homedir folder already exists\n")));
rc = TRUE;
}
else
{
// there is a file there, so we can't create a dir...
DebugLog((DEB_ERROR , "File with the same name already exists: %s\n", pTSData->HomeDir ));
rc = FALSE;
}
if (!rc)
{
DebugLog((DEB_ERROR, "TerminalServerCreatedirWorker() returned error = %d\n",dwErr ));
// we seem to have a bad path, set it to empty so that
// the default paths will be used by userenv's code for settin up
// stuff
pTSData->HomeDirDrive[0] = pTSData->HomeDir[0] = TEXT('\0');
}
return rc;
}
int
WINAPI
WlxLoggedOutSAS(
PVOID pWlxContext,
DWORD dwSasType,
PLUID pAuthenticationId,
PSID pLogonSid,
PDWORD pdwOptions,
PHANDLE phToken,
PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
PVOID * pProfile
)
{
PGLOBALS pGlobals;
INT_PTR result = 0;
PWLX_PROFILE_V2_0 pWlxProfile;
PUNICODE_STRING FlatUser ;
PUNICODE_STRING FlatDomain ;
NTSTATUS Status ;
DWORD dwNewSasType;
pGlobals = (PGLOBALS) pWlxContext;
pGlobals->LogonSid = pLogonSid;
if (ForceAutoLogon())
{
pGlobals->IgnoreAutoAdminLogon = FALSE;
}
else
{
pGlobals->IgnoreAutoAdminLogon = (*pdwOptions) & WLX_OPTION_IGNORE_AUTO_LOGON;
}
// Clear out user process information
ZeroMemory(&pGlobals->UserProcessData, sizeof(pGlobals->UserProcessData));
if (dwSasType == WLX_SAS_TYPE_AUTHENTICATED) {
pGlobals->IgnoreAutoAdminLogon = TRUE;
result = TSAuthenticatedLogon(pGlobals);
} else {
ULONG_PTR ulOption;
do {
if (result == MSGINA_DLG_SMARTCARD_INSERTED) {
dwNewSasType = WLX_SAS_TYPE_SC_INSERT;
} else {
dwNewSasType = dwSasType;
}
// Make sure we monitor SC events
ulOption = 1;
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx,
WLX_OPTION_USE_SMART_CARD,
ulOption,
NULL );
result = Logon(pGlobals, dwNewSasType );
if ( result == MSGINA_DLG_SUCCESS )
{
if ( (pGlobals->SmartCardOption == 0) || (!pGlobals->SmartCardLogon) )
{
// As no action will be taken on SC removal, we can filter these events
ulOption = 0;
}
else
{
//
// Continue to monitor the s/c device
//
NOTHING ;
}
}
else
{
if (result != MSGINA_DLG_SMARTCARD_INSERTED)
{
// This will force winlogon to forget the last sc event
ulOption = 0;
}
}
if (ulOption == 0)
{
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx,
WLX_OPTION_USE_SMART_CARD,
0,
NULL );
}
} while (result == MSGINA_DLG_SMARTCARD_INSERTED || result == MSGINA_DLG_SMARTCARD_REMOVED);
}
if (result == MSGINA_DLG_SUCCESS)
{
DebugLog((DEB_TRACE, "Successful Logon of %ws\\%ws\n", pGlobals->Domain, pGlobals->UserName));
*phToken = pGlobals->UserProcessData.UserToken;
*pAuthenticationId = pGlobals->LogonId;
*pdwOptions = 0;
//
// Set up the flat/UPN stuff:
//
pGlobals->FlatUserName = pGlobals->UserNameString ;
pGlobals->FlatDomain = pGlobals->DomainString ;
//
// Since win2k domains and later support multiple language sets, and map
// similar names to the same account for accessibility from non-nls
// systems (e.g., a user account named "User" can be used to log on
// as both "User" and "U-with-an-umlaut-ser", we need to always do
// this lookup to get the "real" name
//
if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
{
Status = LsaGetUserName( &FlatUser, &FlatDomain );
if ( NT_SUCCESS( Status ) )
{
//
// Initialize the TS Profile path and Home dir globals. Also get
// all TS specific user-config data which is used in winlogon
//
//For WlxQueryTerminalServicesData() we need NT type names rather than
//UPN names, if we pass a UPN name it will try to resolve it
//(through ADS API) to NT name anyway. Besides, ADS API cannot
//resolve some UPN names and takes a long time to execute.
//So let's pass in an NT user and domain names.
//
LPWSTR wszFlatUserName, wszFlatDomainName;
wszFlatUserName = (LPWSTR)LocalAlloc(LPTR,
FlatUser->Length+sizeof(WCHAR));
wszFlatDomainName = (LPWSTR)LocalAlloc(LPTR,
FlatDomain->Length+sizeof(WCHAR));
if(wszFlatUserName && wszFlatDomainName)
{
// Sizes are OK given allocation.
// Zero term'ed since LPTR was used.
memcpy(wszFlatUserName, FlatUser->Buffer,
FlatUser->Length);
memcpy(wszFlatDomainName, FlatDomain->Buffer,
FlatDomain->Length);
pWlxFuncs->WlxQueryTerminalServicesData(pGlobals->hGlobalWlx,
&pGlobals->MuGlobals.TSData, wszFlatUserName, wszFlatDomainName);
}
else
{
pWlxFuncs->WlxQueryTerminalServicesData(pGlobals->hGlobalWlx,
&pGlobals->MuGlobals.TSData,pGlobals->UserName , pGlobals->Domain);
}
if(wszFlatUserName)
{
LocalFree(wszFlatUserName);
}
if(wszFlatDomainName)
{
LocalFree(wszFlatDomainName);
}
//
// if duplication fails revert back to the original string
//
if( !DuplicateUnicodeString(&pGlobals->FlatUserName,
FlatUser ) )
{
pGlobals->FlatUserName = pGlobals->UserNameString ;
}
if ( !DuplicateUnicodeString(&pGlobals->FlatDomain,
FlatDomain ) )
{
pGlobals->FlatDomain = pGlobals->DomainString ;
}
if ( pGlobals->UserName[0] == L'\0' )
{
//
// Weird case of UPN/SC, no UPN could be found. Use
// the flat name
//
dwNewSasType = FlatUser->Length;
if (MAX_STRING_BYTES*sizeof(WCHAR) <= dwNewSasType + sizeof(WCHAR))
{
dwNewSasType = MAX_STRING_BYTES * sizeof(WCHAR) - sizeof(WCHAR);
}
memcpy( pGlobals->UserName, FlatUser->Buffer, dwNewSasType);
pGlobals->UserName[dwNewSasType / sizeof(WCHAR)] = 0;
RtlInitUnicodeString( &pGlobals->UserNameString,
pGlobals->UserName );
}
LsaFreeMemory( FlatUser->Buffer );
LsaFreeMemory( FlatUser );
LsaFreeMemory( FlatDomain->Buffer );
LsaFreeMemory( FlatDomain );
}
else
{
pWlxFuncs->WlxQueryTerminalServicesData(pGlobals->hGlobalWlx,
&pGlobals->MuGlobals.TSData,pGlobals->UserName , pGlobals->Domain);
}
RevertToSelf();
}
// TS Specific - Send the credentials used for logging on and smartcard info to TermSrv
// These credentials are used by TermSrv to send back notification to the client
// Do this only for remote sessions as this is not relevant for sessions logged on from active console
if (!IsActiveConsoleSession()) {
_WinStationUpdateClientCachedCredentials( pGlobals->Domain, pGlobals->UserName, (BOOLEAN) pGlobals->SmartCardLogon );
}
DisplayPostShellLogonMessages(pGlobals);
pMprNotifyInfo->pszUserName = DupString( pGlobals->FlatUserName.Buffer );
pMprNotifyInfo->pszDomain = DupString(pGlobals->FlatDomain.Buffer );
RevealPassword( &pGlobals->PasswordString );
pMprNotifyInfo->pszPassword = DupString(pGlobals->Password);
HidePassword( &pGlobals->Seed, &pGlobals->PasswordString);
if (pGlobals->OldPasswordPresent)
{
RevealPassword( &pGlobals->OldPasswordString );
pMprNotifyInfo->pszOldPassword = DupString(pGlobals->OldPassword);
HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
}
else
{
pMprNotifyInfo->pszOldPassword = NULL;
}
PostShellPasswordErase(pGlobals);
if ( !g_Console )
{
if ( ImpersonateLoggedOnUser( pGlobals->UserProcessData.UserToken ) )
{
TermServ_CreateHomePathAndACLit( pGlobals );
RevertToSelf();
}
}
pWlxProfile = (PWLX_PROFILE_V2_0) LocalAlloc(LMEM_FIXED,
sizeof(WLX_PROFILE_V2_0));
if (pWlxProfile)
{
DWORD dwSize;
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
BOOL bDomainLogon = TRUE;
//
// See if we logged on locally vs domain (vs cached)
// Optimized logon uses cached logon, but it should be treated
// as an ordinary domain logon.
//
if ((pGlobals->Profile->UserFlags & LOGON_CACHED_ACCOUNT) &&
(pGlobals->OptimizedLogonStatus != OLS_LogonIsCached)) {
bDomainLogon = FALSE;
} else {
dwSize = MAX_COMPUTERNAME_LENGTH+1;
if (GetComputerName (szComputerName, &dwSize)) {
if (!lstrcmpi (pGlobals->Domain, szComputerName)) {
DebugLog((DEB_TRACE, "WlxLoggedOutSAS: User logged on locally.\n"));
bDomainLogon = FALSE;
}
}
}
pWlxProfile->dwType = WLX_PROFILE_TYPE_V2_0;
pWlxProfile->pszProfile = AllocAndExpandProfilePath(pGlobals, pMprNotifyInfo->pszUserName);
pWlxProfile->pszPolicy = (bDomainLogon ? AllocPolicyPath(pGlobals) : NULL);
pWlxProfile->pszNetworkDefaultUserProfile =
(bDomainLogon ? AllocNetDefUserProfilePath(pGlobals) : NULL);
pWlxProfile->pszServerName = (bDomainLogon ? AllocServerName(pGlobals) : NULL);
pWlxProfile->pszEnvironment = AllocVolatileEnvironment(pGlobals);
}
*pProfile = (PVOID) pWlxProfile;
return(WLX_SAS_ACTION_LOGON);
}
else if (DLG_SHUTDOWN(result))
{
if (result & MSGINA_DLG_REBOOT_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
}
else if (result & MSGINA_DLG_POWEROFF_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
}
else if (result & MSGINA_DLG_SLEEP_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_SLEEP);
}
else if (result & MSGINA_DLG_SLEEP2_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_SLEEP2);
}
else if (result & MSGINA_DLG_HIBERNATE_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
}
else
return(WLX_SAS_ACTION_SHUTDOWN);
}
else if ( result == MSGINA_DLG_USER_LOGOFF ) {
return( WLX_SAS_ACTION_LOGOFF );
}
else if (result == MSGINA_DLG_SWITCH_CONSOLE)
{
return (WLX_SAS_ACTION_SWITCH_CONSOLE);
}
else
{
if ( pGlobals->RasUsed )
{
//
// Shut down RAS connections on auth failure.
//
HangupRasConnections( pGlobals );
}
return(WLX_SAS_ACTION_NONE);
}
}
int
WINAPI
WlxLoggedOnSAS(
PVOID pWlxContext,
DWORD dwSasType,
PVOID pReserved
)
{
PGLOBALS pGlobals;
INT_PTR Result;
DWORD dwType ;
DWORD cbData ;
DWORD dwValue ;
BOOL OkToLock = TRUE ;
HKEY hkeyPolicy ;
pGlobals = (PGLOBALS) pWlxContext;
if ( pGlobals->SmartCardOption &&
dwSasType == WLX_SAS_TYPE_SC_REMOVE &&
pGlobals->SmartCardLogon )
{
if ( pGlobals->SmartCardOption == 1 )
{
dwValue = 0;
cbData = sizeof(dwValue);
RegQueryValueEx(
WinlogonKey, DISABLE_LOCK_WKSTA,
0, &dwType, (LPBYTE)&dwValue, &cbData);
if (dwValue)
{
OkToLock = FALSE ;
}
if (OpenHKeyCurrentUser(pGlobals)) {
if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser,
WINLOGON_POLICY_KEY,
0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
{
dwValue = 0;
cbData = sizeof(dwValue);
if ((ERROR_SUCCESS != RegQueryValueEx(hkeyPolicy, DISABLE_LOCK_WKSTA,
0, &dwType, (LPBYTE)&dwValue, &cbData)) ||
(dwType != REG_DWORD))
{
dwValue = 0;
}
if (dwValue)
{
OkToLock = FALSE ;
}
RegCloseKey( hkeyPolicy );
}
CloseHKeyCurrentUser(pGlobals);
}
if ( OkToLock)
{
return WLX_SAS_ACTION_LOCK_WKSTA ;
}
}
else if ( pGlobals->SmartCardOption == 2 )
{
if (OpenHKeyCurrentUser(pGlobals)) {
if (RegOpenKeyEx(pGlobals->UserProcessData.hCurrentUser, EXPLORER_POLICY_KEY,
0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS)
{
dwValue = 0;
cbData = sizeof(dwValue);
if ((ERROR_SUCCESS != RegQueryValueEx(hkeyPolicy, NOLOGOFF,
0, &dwType, (LPBYTE)&dwValue, &cbData)) ||
(dwType != REG_DWORD))
{
dwValue = 0;
}
if (dwValue)
{
OkToLock = FALSE ;
}
RegCloseKey( hkeyPolicy );
}
CloseHKeyCurrentUser(pGlobals);
}
if ( OkToLock)
{
return WLX_SAS_ACTION_FORCE_LOGOFF ;
}
}
return WLX_SAS_ACTION_NONE ;
}
if ( dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL ) {
return( WLX_SAS_ACTION_NONE );
}
Result = SecurityOptions(pGlobals);
DebugLog((DEB_TRACE, "Result from SecurityOptions is %d (%#x)\n", Result, Result));
switch (Result & ~MSGINA_DLG_FLAG_MASK)
{
case MSGINA_DLG_SUCCESS:
case MSGINA_DLG_FAILURE:
default:
return(WLX_SAS_ACTION_NONE);
case MSGINA_DLG_LOCK_WORKSTATION:
return(WLX_SAS_ACTION_LOCK_WKSTA);
case MSGINA_DLG_TASKLIST:
return(WLX_SAS_ACTION_TASKLIST);
case MSGINA_DLG_USER_LOGOFF:
return(WLX_SAS_ACTION_LOGOFF);
case MSGINA_DLG_FORCE_LOGOFF:
return(WLX_SAS_ACTION_FORCE_LOGOFF);
case MSGINA_DLG_SHUTDOWN:
if (Result & MSGINA_DLG_REBOOT_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
}
else if (Result & MSGINA_DLG_POWEROFF_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
}
else if (Result & MSGINA_DLG_SLEEP_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_SLEEP);
}
else if (Result & MSGINA_DLG_SLEEP2_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_SLEEP2);
}
else if (Result & MSGINA_DLG_HIBERNATE_FLAG)
{
return(WLX_SAS_ACTION_SHUTDOWN_HIBERNATE);
}
else
return(WLX_SAS_ACTION_SHUTDOWN);
}
}
BOOL
WINAPI
WlxIsLockOk(
PVOID pWlxContext
)
{
PGLOBALS pGlobals = (PGLOBALS) pWlxContext ;
// Stop filtering SC events so SC unlock works
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx,
WLX_OPTION_USE_SMART_CARD,
1,
NULL
);
return(TRUE);
}
BOOL
WINAPI
WlxIsLogoffOk(
PVOID pWlxContext
)
{
return(TRUE);
}
VOID
WINAPI
WlxLogoff(
PVOID pWlxContext
)
{
PGLOBALS pGlobals;
pGlobals = (PGLOBALS) pWlxContext;
pGlobals->UserName[0] = L'\0';
pGlobals->UserProcessData.UserToken = NULL;
if (pGlobals->UserProcessData.RestrictedToken != NULL)
{
NtClose(pGlobals->UserProcessData.RestrictedToken);
pGlobals->UserProcessData.RestrictedToken = NULL;
}
if ( pGlobals->FlatUserName.Buffer != pGlobals->UserNameString.Buffer )
{
LocalFree( pGlobals->FlatUserName.Buffer );
}
if ( pGlobals->FlatDomain.Buffer != pGlobals->DomainString.Buffer )
{
LocalFree( pGlobals->FlatDomain.Buffer );
}
if (pGlobals->UserProcessData.UserSid != NULL)
{
LocalFree(pGlobals->UserProcessData.UserSid);
}
if( NULL != pGlobals->UserProcessData.NewThreadTokenSD )
{
FreeSecurityDescriptor(pGlobals->UserProcessData.NewThreadTokenSD);
pGlobals->UserProcessData.NewThreadTokenSD = NULL;
}
if (pGlobals->UserProcessData.pEnvironment) {
VirtualFree(pGlobals->UserProcessData.pEnvironment, 0, MEM_RELEASE);
pGlobals->UserProcessData.pEnvironment = NULL;
}
pGlobals->UserProcessData.Flags = 0 ;
if ( pGlobals->DnsDomain )
{
LocalFree( pGlobals->DnsDomain );
pGlobals->DnsDomain = NULL ;
}
if (pGlobals->Profile)
{
LsaFreeReturnBuffer(pGlobals->Profile);
pGlobals->Profile = NULL;
}
//
// No need to zero/NULL pGlobals->OldPassword since it's hashed
//
pGlobals->OldPasswordPresent = 0;
// reset transfered credentials flag.
pGlobals->TransderedCredentials = FALSE;
//
// Only handle AutoAdminLogon if on the console
//
if (!g_Console)
{
return;
}
if (GetProfileInt( APPLICATION_NAME, TEXT("AutoAdminLogon"), 0))
{
//
// If this is auto admin logon, generate a fake SAS right now.
//
pWlxFuncs->WlxSasNotify(pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
}
return;
}
VOID
WINAPI
WlxShutdown(
PVOID pWlxContext,
DWORD ShutdownType
)
{
//
// Initialize consumer windows changes
//
_Shell_Terminate();
return;
}
BOOL
WINAPI
WlxScreenSaverNotify(
PVOID pWlxContext,
BOOL * fSecure)
{
if (*fSecure)
{ // If it is a secure screen saver,
// this is equivalent to a lock
*fSecure = WlxIsLockOk(pWlxContext);
}
return( TRUE );
}
BOOL
WINAPI
WlxNetworkProviderLoad(
PVOID pWlxContext,
PWLX_MPR_NOTIFY_INFO pMprNotifyInfo
)
{
// Obsolete
return FALSE ;
}
VOID
WINAPI
WlxReconnectNotify(
PVOID pWlxContext)
{
_Shell_Reconnect();
}
VOID
WINAPI
WlxDisconnectNotify(
PVOID pWlxContext)
{
_Shell_Disconnect();
}
//+---------------------------------------------------------------------------
//
// Function: GetErrorDescription
//
// Synopsis: Returns the message from ntdll corresponding to the status
// code.
//
// Arguments: [ErrorCode] --
// [Description] --
// [DescriptionSize] --
//
// History: 5-02-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
GetErrorDescription(
DWORD ErrorCode,
LPWSTR Description,
DWORD DescriptionSize
)
{
HMODULE Module ;
//
// First, try to determine what kind of error code it is:
//
//
// Some people disguise win32 error codes in HRESULTs. While
// this is annoying, it can be handled.
//
if ( ( ErrorCode & 0xFFFF0000 ) == 0x80070000 )
{
ErrorCode = ErrorCode & 0x0000FFFF ;
}
if ( (ErrorCode > 0) && (ErrorCode < 0x00010000) )
{
//
// Looks like a winerror:
//
Module = GetModuleHandle( TEXT("kernel32.dll") );
}
else if ( (0xC0000000 & ErrorCode ) == 0xC0000000 )
{
//
// Looks like an NT status
//
Module = GetModuleHandle( TEXT("ntdll.dll" ) );
}
else
{
Module = GetModuleHandle( TEXT("kernel32.dll" ) );
}
return FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_HMODULE,
(LPCVOID) Module,
ErrorCode,
0,
Description,
DescriptionSize,
NULL );
}
/*=============================================================================
== Local Procedures Defined
=============================================================================*/
/******************************************************************************
*
* FreeAutoLogonInfo
*
* Free WLX_CLIENT_CREDENTAILS_INFO and data strings returned
* from winlogon.
*
* ENTRY:
* pGlobals (input)
* pointer to GLOBALS struct
*
* EXIT:
* nothing
*
*****************************************************************************/
VOID
FreeAutoLogonInfo( PGLOBALS pGlobals )
{
PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pAutoLogon;
pAutoLogon = pGlobals->MuGlobals.pAutoLogon;
if( pAutoLogon == NULL ) {
return;
}
if ( pAutoLogon->pszUserName ) {
LocalFree( pAutoLogon->pszUserName );
}
if ( pAutoLogon->pszDomain ) {
LocalFree( pAutoLogon->pszDomain );
}
if ( pAutoLogon->pszPassword ) {
ZeroMemory(pAutoLogon->pszPassword, wcslen(pAutoLogon->pszPassword) * sizeof(WCHAR));
LocalFree( pAutoLogon->pszPassword );
}
LocalFree( pAutoLogon );
pGlobals->MuGlobals.pAutoLogon = NULL;
}