|
|
//+---------------------------------------------------------------------------
//
// 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; }
|