|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: mslogon.c
//
// Contents: Microsoft Logon GUI DLL
//
// History: 7-14-94 RichardW Created
//
//----------------------------------------------------------------------------
#include "msgina.h"
#include "shtdnp.h"
#include "authmon.h"
#include <stdio.h>
#include <wchar.h>
#include <wincrypt.h>
#include <sclogon.h>
#include "shlwapi.h"
#include "shlwapip.h"
#include "winsta.h"
#include "wtsapi32.h"
#include <keymgr.h>
#include <passrec.h>
typedef void (WINAPI *RUNDLLPROC)(HWND hWndStub,HINSTANCE hInstance,LPWSTR szCommandLine,int nShow);
typedef struct _MSGINA_LOGON_PARAMETERS { PGLOBALS pGlobals; DWORD SasType; } MSGINA_LOGON_PARAMETERS, * PMSGINA_LOGON_PARAMETERS ;
#define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
//
// Number of seconds we will display the legal notices
// before timing out.
//
#define LEGAL_NOTICE_TIMEOUT 120
#define LOGON_SLEEP_PERIOD 750
#define WM_LOGONPROMPT WM_USER + 257
#define WM_LOGONCOMPLETE WM_USER + 258
#define WM_HANDLEFAILEDLOGON WM_USER + 259
#define WM_DCACHE_COMPLETE WM_USER + 260
#define MAX_CAPTION_LENGTH 256
// Maximum size of a UPN name we allow at present
#define MAX_UPN_NAME_SIZE 520
typedef struct FAILEDLOGONINFO_t { PGLOBALS pGlobals; NTSTATUS Status; NTSTATUS SubStatus; TCHAR UserName[UNLEN + DNLEN + 2]; TCHAR Domain[DNLEN + 1]; } FAILEDLOGONINFO, *PFAILEDLOGONINFO;
typedef struct _LEGALINFO { LPTSTR NoticeText; LPTSTR CaptionText; } LEGALINFO, *PLEGALINFO;
// Also defined in wstrpc.c
#define INET_CONNECTOR_EVENT_NAME L"Global\\TermSrvInetConnectorEvent"
#define TERMSERV_EVENTSOURCE L"TermService"
// Also defined in icaevent.mc
#define EVENT_BAD_TSINTERNET_USER 1007
//
// Globals:
//
static WNDPROC OldCBWndProc;
HICON hSteadyFlag; HICON hWavingFlag; HICON hAuditFull;
extern HICON hLockedIcon; BOOL IsPswBackupAvailable; BOOL s_fAttemptedAutoLogon;
BOOL g_fHelpAssistantLogon = FALSE;
//
// Prototypes:
//
INT_PTR DisplayLegalNotices( PGLOBALS pGlobals );
BOOL GetLegalNotices( LPTSTR lpSubKey, LPTSTR *NoticeText, LPTSTR *CaptionText );
INT_PTR WINAPI LogonDlgCBProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
INT_PTR WINAPI LogonDlgUsernameProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
INT_PTR WINAPI LogonDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );
BOOL LogonDlgInit( HWND hDlg, BOOL bAutoLogon, DWORD SasType );
NTSTATUS UpnFromCert( IN PCCERT_CONTEXT pCert, IN OUT DWORD *pcUpn, IN OUT LPWSTR pUPN );
BOOL WINAPI QuerySwitchConsoleCredentials( PGLOBALS pGlobals, HANDLE * phUserToken, PLUID pLogonId);
// Global structure for a failed logon filled in by the worker thread to be consumed
// by the ui thread.
FAILEDLOGONINFO g_failinfo;
void PostFailedLogonMessage(HWND hDlg, PGLOBALS pGlobals, NTSTATUS Status, NTSTATUS SubStatus, PWCHAR UserName, PWCHAR Domain );
INT_PTR HandleFailedLogon( HWND hDlg );
VOID ReportBootGood( PGLOBALS pGlobals );
VOID LogonShowOptions( PGLOBALS pGlobals, HWND hDlg, BOOL fShow, BOOL fSticky);
VOID AttemptLogonSetControls( PGLOBALS pGlobals, HWND hDlg );
INT_PTR AttemptLogon( HWND hDlg );
DWORD AttemptLogonThread( PGLOBALS pGlobals );
BOOL GetAndAllocateLogonSid( HANDLE hToken, PSID *pLogonSid );
BOOL GetSessionZeroUser(LPTSTR szUser); BOOL FastUserSwitchingEnabled();
//
// control tables for showing/hiding options
//
static UINT ctrlNoShutdown[] = { IDOK, IDCANCEL, };
static UINT ctrlNoCancel[] = { IDOK, };
static UINT ctrlNoDomain[] = { IDOK, IDCANCEL, IDD_LOGON_SHUTDOWN, IDD_LOGON_OPTIONS, IDD_LOGON_RASBOX, IDD_KBLAYOUT_ICON, };
static UINT ctrlNoRAS[] = { IDOK, IDCANCEL, IDD_LOGON_SHUTDOWN, IDD_LOGON_OPTIONS, IDD_KBLAYOUT_ICON, };
static UINT ctrlNoOptions[] = { IDOK, IDCANCEL, IDD_LOGON_SHUTDOWN, IDD_KBLAYOUT_ICON, };
static UINT ctrlNoLegalBanner[] = { IDD_LOGON_NAME_LABEL, IDD_LOGON_NAME, IDD_LOGON_PASSWORD_LABEL, IDD_LOGON_PASSWORD, IDD_LOGON_DOMAIN_LABEL, IDD_LOGON_DOMAIN, IDD_LOGON_RASBOX, IDD_KBLAYOUT_ICON, IDOK, IDCANCEL, IDD_LOGON_SHUTDOWN, IDD_LOGON_OPTIONS, };
static UINT ctrlNoUserName[] = { IDD_LOGON_PASSWORD_LABEL, IDD_LOGON_PASSWORD, IDD_LOGON_DOMAIN_LABEL, IDD_LOGON_DOMAIN, IDD_LOGON_RASBOX, IDD_KBLAYOUT_ICON, IDOK, IDCANCEL, IDD_LOGON_SHUTDOWN, IDD_LOGON_OPTIONS, };
// --------------------------------------------------------------------------
// ::DisableEditSubClassProc
//
// Arguments: hwnd = See the platform SDK under WindowProc.
// uMsg = See the platform SDK under WindowProc.
// wParam = See the platform SDK under WindowProc.
// lParam = See the platform SDK under WindowProc.
// uiID = ID assigned at subclass time.
// dwRefData = reference data assigned at subclass time.
//
// Returns: LRESULT
//
// Purpose: comctl32 subclass callback function. This allows us to not
// process WM_CUT/WM_COPY/WM_PASTE/WM_CLEAR/WM_UNDO and any
// other messages to be discarded.
//
// History: 2001-02-18 vtan created
// --------------------------------------------------------------------------
LRESULT CALLBACK DisableEditSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData)
{ LRESULT lResult;
switch (uMsg) { case WM_CUT: case WM_COPY: case WM_PASTE: case WM_CLEAR: case WM_UNDO: case WM_CONTEXTMENU: lResult = FALSE; break; default: lResult = DefSubclassProc(hwnd, uMsg, wParam, lParam); break; } return(lResult); }
INT_PTR WINAPI LegalDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
switch (message) { case WM_INITDIALOG: { PLEGALINFO pLegalInfo;
pLegalInfo = (PLEGALINFO) lParam;
SetWindowText (hDlg, pLegalInfo->CaptionText); SetWindowText (GetDlgItem(hDlg, IDD_LEGALTEXT), pLegalInfo->NoticeText);
CentreWindow(hDlg);
// Ensure the window is topmost so it's not obscured by the welcome screen.
SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
return( TRUE ); }
case WM_COMMAND: { if (LOWORD(wParam) == IDOK) { EndDialog(hDlg, IDOK); } } break; }
return FALSE; }
/***************************************************************************\
* FUNCTION: DisplayLegalNotices * * PURPOSE: Puts up a dialog box containing legal notices, if any. * * RETURNS: MSGINA_DLG_SUCCESS - the dialog was shown and dismissed successfully. * MSGINA_DLG_FAILURE - the dialog could not be shown * DLG_INTERRUPTED() - a set defined in winlogon.h * * HISTORY: * * Robertre 6-30-93 Created * \***************************************************************************/
INT_PTR DisplayLegalNotices( PGLOBALS pGlobals ) { INT_PTR Result = MSGINA_DLG_SUCCESS; LPTSTR NoticeText; LPTSTR CaptionText; LEGALINFO LegalInfo;
if (GetLegalNotices( WINLOGON_POLICY_KEY, &NoticeText, &CaptionText )) {
LegalInfo.NoticeText = NoticeText; LegalInfo.CaptionText = CaptionText;
_Shell_LogonStatus_Hide();
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx, hDllInstance, (LPTSTR) IDD_LEGALMSG, NULL, LegalDlgProc, (LPARAM) &LegalInfo );
_Shell_LogonStatus_Show();
Free( NoticeText ); Free( CaptionText ); } else if (GetLegalNotices( WINLOGON_KEY, &NoticeText, &CaptionText )) {
LegalInfo.NoticeText = NoticeText; LegalInfo.CaptionText = CaptionText;
_Shell_LogonStatus_Hide();
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LEGAL_NOTICE_TIMEOUT);
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx, hDllInstance, (LPTSTR) IDD_LEGALMSG, NULL, LegalDlgProc, (LPARAM) &LegalInfo );
_Shell_LogonStatus_Show();
Free( NoticeText ); Free( CaptionText ); }
return( Result ); }
/***************************************************************************\
* FUNCTION: GetLegalNotices * * PURPOSE: Get legal notice information out of the registry. * * RETURNS: TRUE - Output parameters contain valid data * FALSE - No data returned. * * HISTORY: * * Robertre 6-30-93 Created * \***************************************************************************/ BOOL GetLegalNotices( LPTSTR lpSubKey, LPTSTR *NoticeText, LPTSTR *CaptionText ) { LPTSTR lpCaption, lpText; HKEY hKey; DWORD dwSize, dwType, dwMaxSize = 0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxSize, NULL, NULL);
lpCaption = Alloc (dwMaxSize);
if (!lpCaption) { RegCloseKey(hKey); return FALSE; }
lpText = Alloc (dwMaxSize);
if (!lpText) { Free(lpCaption); RegCloseKey(hKey); return FALSE; }
dwSize = dwMaxSize; RegQueryValueEx(hKey, LEGAL_NOTICE_CAPTION_KEY, 0, &dwType, (LPBYTE)lpCaption, &dwSize);
dwSize = dwMaxSize; RegQueryValueEx(hKey, LEGAL_NOTICE_TEXT_KEY, 0, &dwType, (LPBYTE)lpText, &dwSize);
RegCloseKey(hKey);
if (*lpCaption && *lpText) { *CaptionText = lpCaption; *NoticeText = lpText; return TRUE; }
Free(lpCaption); Free(lpText); }
return FALSE; }
/***************************************************************************\
* FUNCTION: Logon * * PURPOSE: Display the logon UI depending on the SAS type. * * RETURNS: - * * NOTES: If the logon is successful, the global structure is filled in * with the logon information. * * HISTORY: * 12-09-91 daviddv Comments. * \***************************************************************************/
INT_PTR Logon( PGLOBALS pGlobals, DWORD SasType ) { INT_PTR Result; MSGINA_LOGON_PARAMETERS Parm ;
if ( SasType == WLX_SAS_TYPE_SC_REMOVE ) { return WLX_SAS_ACTION_NONE ; }
if( !g_Console ) { //
// Check if current session is HelpAssistant Session, HelpAssisant
// session can not be console session.
//
g_fHelpAssistantLogon = WinStationIsHelpAssistantSession( SERVERNAME_CURRENT, LOGONID_CURRENT ); }
if ( SasType == WLX_SAS_TYPE_SC_INSERT ) { PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx, WLX_OPTION_SMART_CARD_INFO, (ULONG_PTR *) &ScInfo );
//
// Validate the SC info against some common user
// errors before the PIN dialog appears
//
if ( ScInfo ) { if ( ( ScInfo->pszReader ) && ( ScInfo->pszCard == NULL ) ) { //
// The card could not be read. Might not be
// inserted correctly.
//
LocalFree(ScInfo);
TimeoutMessageBox( NULL, pGlobals, IDS_CARD_NOT_RECOGNIZED, IDS_LOGON_MESSAGE, MB_OK | MB_ICONEXCLAMATION, LOGON_TIMEOUT );
return WLX_SAS_ACTION_NONE; }
if ( ( ScInfo->pszReader ) && ( ScInfo->pszCryptoProvider == NULL ) ) { //
// Got a card, but the CSP for it could not be
// found.
//
LocalFree(ScInfo);
TimeoutMessageBox( NULL, pGlobals, IDS_CARD_CSP_NOT_RECOGNIZED, IDS_LOGON_MESSAGE, MB_OK | MB_ICONEXCLAMATION, LOGON_TIMEOUT );
return WLX_SAS_ACTION_NONE; }
LocalFree(ScInfo); } }
//
// Asynchronously update domain cache if necessary.
// We won't ask to wait so this routine will do no UI.
// i.e. we can ignore the result.
//
// Result = UpdateDomainCache(pGlobals, NULL, FALSE);
// ASSERT(!DLG_INTERRUPTED(Result));
if( !g_fHelpAssistantLogon ) { //
// See if there are legal notices in the registry.
// If so, put them up in a message box
//
Result = DisplayLegalNotices( pGlobals ); if ( Result != MSGINA_DLG_SUCCESS ) { return(WLX_SAS_ACTION_NONE); } //
// Get the latest audit log status and store in our globals
// If the audit log is full we show a different logon dialog.
//
GetAuditLogStatus(pGlobals); } else { //
// fake it so audit log is not full, setting is from GetAuditLogStatus()
//
pGlobals->AuditLogFull = FALSE; pGlobals->AuditLogNearFull = FALSE; }
Parm.pGlobals = pGlobals ; Parm.SasType = SasType ;
//
// Take their username and password and try to log them on
//
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, ( (GetDisableCad(pGlobals) && IsActiveConsoleSession()) ? TIMEOUT_NONE : LOGON_TIMEOUT));
Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx, hDllInstance, MAKEINTRESOURCE(IDD_LOGON_DIALOG), NULL, LogonDlgProc, (LPARAM) &Parm );
if ( Result == WLX_SAS_ACTION_LOGON ) { if ( (pGlobals->SmartCardOption == 0) || (!pGlobals->SmartCardLogon) ) { // As no action will be taken on SC removal, we can filter these events
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx, WLX_OPTION_USE_SMART_CARD, 0, NULL ); } else { //
// Continue to monitor the s/c device
//
NOTHING ; } }
return(Result); }
/***************************************************************************\
* FUNCTION: LogonDlgCBProc * * PURPOSE: Processes messages for Logon dialog combo box * * RETURNS: Return value depends on message being sent. * * HISTORY: * * 05-21-93 RobertRe Created. * \***************************************************************************/
INT_PTR WINAPI LogonDlgCBProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { TCHAR KeyPressed;
// DbgPrint("message = %X\n",message);
switch (message) { case WM_CHAR: { KeyPressed = (TCHAR) wParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)KeyPressed);
//
// This fake CBN_SELCHANGE message will cause the
// "Please wait..." dialog box to appear even if
// the character pressed doesn't exist in the combobox yet.
//
PostMessage (GetParent(hwnd), WM_COMMAND, MAKELONG(0, CBN_SELCHANGE), 0); break; } }
return CallWindowProc(OldCBWndProc,hwnd,message,wParam,lParam); }
INT_PTR CALLBACK DomainCacheDlgProc( HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam ) { PGLOBALS pGlobals ;
DebugLog(( DEB_TRACE_DOMAIN, "DomainCacheDlgProc( %p, %x, %p, %p )\n", hDlg, Message, wParam, lParam ));
switch ( Message ) { case WM_INITDIALOG:
pGlobals = (PGLOBALS) lParam ;
if ( DCacheSetNotifyWindowIfNotReady( pGlobals->Cache, hDlg, WM_DCACHE_COMPLETE ) ) { EndDialog( hDlg, TRUE ); }
return TRUE ;
case WM_DCACHE_COMPLETE:
EndDialog( hDlg, TRUE );
return TRUE ;
default:
return FALSE ; } }
BOOL IsAutoLogonUserInteractiveLogonRestricted (HWND hDlg)
{ WCHAR szUsername[UNLEN + 1]; // sizeof('\0')
return((GetDlgItemText(hDlg, IDD_LOGON_NAME, szUsername, ARRAYSIZE(szUsername)) != 0) && !ShellIsUserInteractiveLogonAllowed(szUsername)); }
BOOL HasDefaultPassword (TCHAR *pszPassword, int cchPassword)
{ DWORD dwType, dwPasswordSize;
dwType = REG_NONE; dwPasswordSize = cchPassword * sizeof(TCHAR); return(ERROR_SUCCESS == RegQueryValueEx(WinlogonKey, DEFAULT_PASSWORD_KEY, NULL, &dwType, (LPBYTE)pszPassword, &dwPasswordSize) && (REG_SZ == dwType)); }
// ==========================================================================================
// Logon dialog has 2 formats, one that looks like logon dialog box, another that looks like
// unlock desktop dialogbox. When user connects to session 0 from remote (tsclient) the
// dialog that appears at console // need to change to unlock computer. so if session 0 is in
// use, and if this session is created at active console. we change logon dialog to look like
// "unlock computer" dialog.
// This function SwitchLogonLocked does most of the stuff related to switching these
// dialog controls.
// Parameters:
// HWND hDlg - dialog window handle,
// BOOL bShowLocked - if true show locked dialog, if false show normal logon dialog.
// BOOL bInit - TRUE when this function is called for the first time.
// ==========================================================================================
static bLocked = TRUE; BOOL IsthisUnlockWindowsDialog () { return bLocked; }
BOOL SwitchLogonLocked(HWND hDlg, BOOL bShowLocked, BOOL bInit) { UINT rgidLockControls[] = {IDC_GROUP_UNLOCK, IDD_UNLOCK_ICON, IDD_UNLOCK_MESSAGE, IDD_UNLOCK_NAME_INFO}; static LockedControlHeight = 0; BOOL bShutdownWithoutLogon;
int i;
if (bShowLocked == bLocked && !bInit) { // nothing to do.
return TRUE; }
if (bInit) { { //
// remember the reference rectangle height (groupbox) for control movements.
//
RECT rectLockedControls; HWND hWnd = GetDlgItem(hDlg, rgidLockControls[0]); GetWindowRect(hWnd, &rectLockedControls); LockedControlHeight = rectLockedControls.bottom - rectLockedControls.top;
//
// this group box was only for reference, now hide it forever.
//
ShowWindow(hWnd, SW_HIDE);
}
bLocked = TRUE; if ( !hLockedIcon ) { hLockedIcon = LoadImage( hDllInstance, MAKEINTRESOURCE( IDI_LOCKED), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); }
SendMessage( GetDlgItem( hDlg, IDD_UNLOCK_ICON), STM_SETICON, (WPARAM)hLockedIcon, 0 );
}
// lets move controls arround, depending upon if lock controls are to be shown or not.
if (bLocked != bShowLocked) { if (bShowLocked) { MoveChildren(hDlg, 0, LockedControlHeight); for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++) { HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]); ASSERT(hWnd); EnableWindow(hWnd, TRUE); ShowWindow(hWnd, SW_SHOW); }
} else { for ( i = 1; i < sizeof(rgidLockControls)/sizeof(rgidLockControls[0]); i++) { HWND hWnd = GetDlgItem(hDlg, rgidLockControls[i]); ASSERT(hWnd); ShowWindow(hWnd, SW_HIDE); EnableWindow(hWnd, FALSE); } MoveChildren(hDlg, 0, -LockedControlHeight); } }
// some more processing
{ if (bShowLocked) { TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2]; TCHAR szMessage[MAX_STRING_BYTES]; TCHAR szFinalMessage[MAX_STRING_BYTES]; if (GetSessionZeroUser(szUser)) { LoadString(hDllInstance, IDS_LOCKED_EMAIL_NFN_MESSAGE, szMessage, MAX_STRING_BYTES); _snwprintf(szFinalMessage, sizeof(szFinalMessage)/sizeof(TCHAR), szMessage, szUser ); } else { //
// for some reason we could not get the current session zero user.
//
LoadString(hDllInstance, IDS_LOCKED_NO_USER_MESSAGE, szFinalMessage, MAX_STRING_BYTES); }
SetDlgItemText(hDlg, IDD_UNLOCK_NAME_INFO, szFinalMessage); }
//
// update the dialog box caption, accordingly
//
{ TCHAR szCaption[MAX_CAPTION_LENGTH]; LoadString(hDllInstance, bShowLocked ? IDS_CAPTION_UNLOCK_DIALOG : IDS_CAPTION_LOGON_DIALOG, szCaption, ARRAYSIZE(szCaption)); if ( szCaption[0] != TEXT('\0') ) SetWindowText( hDlg, szCaption ); } }
bLocked = bShowLocked;
if ( SafeBootMode == SAFEBOOT_MINIMAL ) { bShutdownWithoutLogon = TRUE ; } else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession()) { bShutdownWithoutLogon = FALSE ; } else { bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE); }
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, bShutdownWithoutLogon);
InvalidateRect(hDlg, NULL, TRUE);
return TRUE; }
/***************************************************************************\
* FUNCTION: LogonDlgProc * * PURPOSE: Processes messages for Logon dialog * * RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully * MSGINA_DLG_FAILURE - the logon failed, * DLG_INTERRUPTED() - a set defined in winlogon.h * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
#define WM_HIDEOURSELVES (WM_USER + 1000)
INT_PTR WINAPI LogonDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA); INT_PTR Result; HWND CBHandle; BOOL fDisconnectOnTsAutoLogonFailure = FALSE; static BOOL bSessionZeroInUse = FALSE; static int iSessionRegistrationCount = 0; static BOOL bSmartCardInserted = FALSE;
switch (message) {
case WM_INITDIALOG: { TCHAR PasswordBuffer[127]; BOOL bAutoLogon; PMSGINA_LOGON_PARAMETERS pParam ;
pParam = (PMSGINA_LOGON_PARAMETERS) lParam ; pGlobals = pParam->pGlobals ;
SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pGlobals);
// Hide the keyboard accelerator keys to start
SendMessage(hDlg, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0);
// Limit the maximum password length to 127
SendDlgItemMessage(hDlg, IDD_LOGON_PASSWORD, EM_SETLIMITTEXT, (WPARAM) 127, 0);
s_fAttemptedAutoLogon = FALSE;
//
// Check if auto logon is enabled.
//
pGlobals->AutoAdminLogon = GetProfileInt( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, 0 ) != 0; bAutoLogon = !pGlobals->IgnoreAutoAdminLogon;
if ( !pGlobals->AutoAdminLogon || (!g_Console) || ((GetAsyncKeyState(VK_SHIFT) < 0) && (GetProfileInt( APPLICATION_NAME, IGNORE_SHIFT_OVERRIDE_KEY, 0 ) == 0)) ) { bAutoLogon = FALSE; }
KdPrint(("AutoAdminLogon = %d, IgnoreAutoAdminLogon = %d, bAutoLogon = %d\n", pGlobals->AutoAdminLogon, pGlobals->IgnoreAutoAdminLogon, bAutoLogon ));
//
// Subclass the domain list control so we can filter messages
//
CBHandle = GetDlgItem(hDlg,IDD_LOGON_DOMAIN); SetWindowLongPtr(CBHandle, GWLP_USERDATA, 0); OldCBWndProc = (WNDPROC) SetWindowLongPtr(CBHandle, GWLP_WNDPROC, (LONG_PTR)LogonDlgCBProc);
//
// Subclass the user name and password edit also so we can disable edits
//
SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME) , DisableEditSubClassProc, IDD_LOGON_NAME , 0); SetWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD, 0);
ShellReleaseLogonMutex(FALSE);
if (!LogonDlgInit(hDlg, bAutoLogon, pParam->SasType )) { bSmartCardInserted = FALSE; EndDialog(hDlg, MSGINA_DLG_FAILURE); return(TRUE); }
//
// If the default user for auto logon is present and the user is
// restricted (interactive logon denied) then disable auto logon.
//
if (bAutoLogon && IsAutoLogonUserInteractiveLogonRestricted(hDlg)) { bAutoLogon = FALSE; }
//
// If CAD is disabled, then gray out the Cancel button
//
if (GetDisableCad(pGlobals) && IsActiveConsoleSession()) EnableDlgItem(hDlg, IDCANCEL, FALSE);
//
// this dialog has 2 formats, one that looks like logon dialog box,
// another that looks like unlock desktop dialogbox.
// we choose locked one, if session 0 is in use, and if this session is created at
// active console.
//
if (g_IsTerminalServer && IsActiveConsoleSession() && NtCurrentPeb()->SessionId != 0 && !FastUserSwitchingEnabled() && !_ShellIsFriendlyUIActive()) { TCHAR szUser[USERNAME_LENGTH + DOMAIN_LENGTH + 2]; //
// we are at temporary session created at console...
//
// check if a user is logged on at console session
bSessionZeroInUse = GetSessionZeroUser(szUser); if (WinStationRegisterConsoleNotification(SERVERNAME_CURRENT, hDlg, NOTIFY_FOR_ALL_SESSIONS)) { iSessionRegistrationCount++; } } else { //
// this is not active console nonzero session.
//
bSessionZeroInUse = FALSE; }
//
//
// now switch the control, accordigly to show logon or unlock dialog
//
SwitchLogonLocked(hDlg, bSessionZeroInUse, TRUE);
if (g_IsTerminalServer) { BOOL fForceUPN; BOOL fPopulateFields = TRUE; BOOL fResult = FALSE; PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pAutoLogon; //
// Query network WinStation client credentials for
// auto logon
//
pGlobals->MuGlobals.pAutoLogon = LocalAlloc( LPTR, sizeof(WLX_CLIENT_CREDENTIALS_INFO_V2_0) );
if (pGlobals->MuGlobals.pAutoLogon) {
pGlobals->MuGlobals.pAutoLogon->dwType = WLX_CREDENTIAL_TYPE_V2_0;
if (NtCurrentPeb()->SessionId != 0) { fResult = pWlxFuncs->WlxQueryTsLogonCredentials( pGlobals->MuGlobals.pAutoLogon ); }
if ( fResult && (pGlobals->MuGlobals.pAutoLogon->pszUserName[0] || pGlobals->MuGlobals.pAutoLogon->pszDomain[0] )) {
pAutoLogon = pGlobals->MuGlobals.pAutoLogon; fDisconnectOnTsAutoLogonFailure = pAutoLogon->fDisconnectOnLogonFailure;
SetupCursor(TRUE); // hourglass cursor
fForceUPN = GetProfileInt( APPLICATION_NAME, TEXT("TSForceUPN"), FALSE ); if (fForceUPN) { fPopulateFields = FALSE; // never show old SAM style is UPN is forced
}
if (pAutoLogon->pszDomain[0] == TEXT('\0') && fForceUPN) { fForceUPN = FALSE; // domain name not provided, can't apply policy
}
if (fForceUPN && pGlobals->MuGlobals.pAutoLogon->pszUserName[0] ) { LRESULT iDomain; HWND hwndDomain; PDOMAIN_CACHE_ENTRY Entry ; ULONG nSize;
// Performance issue. We don't want to perform a UPN conversion
// for local machine accounts (or unknown domains). When this
// happens, the lookup will take a LONG time.
hwndDomain = GetDlgItem( hDlg, IDD_LOGON_DOMAIN ); iDomain = SendMessage( hwndDomain, CB_FINDSTRING, (WPARAM) -1, (LPARAM) pAutoLogon->pszDomain ); fForceUPN = FALSE; // don't do the conversion
if (iDomain != CB_ERR) { Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomain, 0); if ( Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR && Entry != NULL) { switch (Entry->Type) { case DomainNt5: fForceUPN = TRUE; // Attempt the conversion
break; } } }
// Convert the domain\username into UPN format.
// and make sure the dialog is in UPN form.
// 2000/10/09 vtan: this function used to have two stack variables
// szOldStyle and szUPNName that were TCHARs of MAX_UPN_NAME_SIZE size. The
// fix for this makes these dynamically allocated to save stack space
{ TCHAR *pszOldStyle; TCHAR *pszUPNName;
pszOldStyle = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR)); pszUPNName = (TCHAR*)LocalAlloc(LMEM_FIXED, MAX_UPN_NAME_SIZE * sizeof(TCHAR)); if ((pszOldStyle != NULL) && (pszUPNName != NULL)) { wsprintf(pszOldStyle, TEXT("%s\\%s"), pAutoLogon->pszDomain, pAutoLogon->pszUserName); nSize = MAX_PATH; fResult = TranslateName( pszOldStyle, NameSamCompatible, NameUserPrincipal, pszUPNName, &nSize ); if (fResult) { // We now have the UPN form of the user account.
SetDlgItemText( hDlg, IDD_LOGON_NAME, pszUPNName); } } if (pszOldStyle != NULL) { LocalFree(pszOldStyle); } if (pszUPNName != NULL) { LocalFree(pszUPNName); } } }
if (fPopulateFields) { // display the old SAM style
SetDlgItemText( hDlg, IDD_LOGON_NAME, pAutoLogon->pszUserName ); SendMessage( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ), CB_SELECTSTRING, (WPARAM) -1, (LPARAM) pAutoLogon->pszDomain ); } else { // Enable or disable the domain box depending on whether a UPN name has been typed
EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN));
// Since we're forcing UPN, hide the options dialog, but don't make it sticky
LogonShowOptions(pGlobals, hDlg, FALSE, FALSE); }
// See if the administrator always wants password prompting
if ( TRUE == g_fHelpAssistantLogon || !pAutoLogon->fPromptForPassword ) { SetDlgItemText( hDlg, IDD_LOGON_PASSWORD, pAutoLogon->pszPassword ); }
DCacheSetDefaultEntry( pGlobals->Cache, pAutoLogon->pszDomain, NULL );
if( TRUE == g_fHelpAssistantLogon || !pGlobals->MuGlobals.pAutoLogon->fPromptForPassword ) { FreeAutoLogonInfo( pGlobals );
// Drop through as if Enter had been pressed...
wParam = IDOK;
goto go_logon; } else { FreeAutoLogonInfo( pGlobals ); } } else { FreeAutoLogonInfo( pGlobals ); } } } if (pGlobals->SmartCardLogon) {
if ( GetProfileString(APPLICATION_NAME, TEXT("DefaultPIN"), TEXT(""), PasswordBuffer, ARRAYSIZE(PasswordBuffer)) != 0 ) { // Ensure we never write more than 127 chars into the password box
PasswordBuffer[126] = 0; SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer); goto go_logon; } }
// save off the auto logon attempt.
s_fAttemptedAutoLogon = (bAutoLogon != FALSE);
if (bAutoLogon) { GetWindowRect(hDlg, &pGlobals->rcDialog); SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0); } else { switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF)) { case SHELL_LOGONDIALOG_NONE: default: { //
// If auto logon isn't enabled, set the focus to the
// password edit control and leave.
//
return(SetPasswordFocus(hDlg)); } case SHELL_LOGONDIALOG_LOGON: { GetWindowRect(hDlg, &pGlobals->rcDialog); SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0); goto go_logon; } case SHELL_LOGONDIALOG_EXTERNALHOST: { return(TRUE); } } }
//
// Attempt to auto logon. If no default password
// specified, then this is a one shot attempt, which handles
// the case when auto logging on as Administrator.
//
if (HasDefaultPassword(PasswordBuffer, ARRAYSIZE(PasswordBuffer)) != FALSE) { // Ensure we never write more than 127 chars into the password box
PasswordBuffer[126] = 0; SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer); } else { NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES ObjectAttributes; LSA_HANDLE LsaHandle = NULL; UNICODE_STRING SecretName; PUNICODE_STRING SecretValue = NULL;
//
// Set up the object attributes to open the Lsa policy object
//
InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, (HANDLE)NULL, NULL);
//
// Open the local LSA policy object
//
Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &LsaHandle ); if (NT_SUCCESS(Status)) { RtlInitUnicodeString( &SecretName, DEFAULT_PASSWORD_KEY );
Status = LsaRetrievePrivateData( LsaHandle, &SecretName, &SecretValue ); if (NT_SUCCESS(Status)) {
if ( SecretValue->Length > 0 ) {
//
// If the password fits in the buffer, copy it there
// and null terminate
//
if (SecretValue->Length < sizeof(PasswordBuffer) - sizeof(WCHAR)) {
RtlCopyMemory( PasswordBuffer, SecretValue->Buffer, SecretValue->Length ); PasswordBuffer[SecretValue->Length/sizeof(WCHAR)] = L'\0'; SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
} else { Status = STATUS_INVALID_PARAMETER; } }
LsaFreeMemory(SecretValue); } LsaClose(LsaHandle); }
if (!NT_SUCCESS(Status)) { WriteProfileString( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, TEXT("0") ); }
}
go_logon:
// Drop through as if Enter had been pressed...
wParam = IDOK; }
// nb: deliberate drop through from above
case WM_COMMAND: switch (HIWORD(wParam)) {
case CBN_DROPDOWN: case CBN_SELCHANGE:
DebugLog((DEB_TRACE, "Got CBN_DROPDOWN\n"));
if ( !pGlobals->ListPopulated ) { WCHAR Buffer[ 2 ];
if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache ) { pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx, hDllInstance, (LPTSTR) IDD_WAITDOMAINCACHEVALID_DIALOG, hDlg, DomainCacheDlgProc, (LPARAM) pGlobals );
}
if ( DCacheGetCacheState( pGlobals->Cache ) == DomainCacheReady ) { PDOMAIN_CACHE_ARRAY ActiveArrayBackup ;
ActiveArrayBackup = pGlobals->ActiveArray;
pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
if ( pGlobals->ActiveArray ) { DCacheFreeArray( ActiveArrayBackup ); // Not needed anymore
Buffer[ 0 ] = (WCHAR) GetWindowLongPtr( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ), GWLP_USERDATA ); Buffer[ 1 ] = L'\0';
DCachePopulateListBoxFromArray( pGlobals->ActiveArray, GetDlgItem( hDlg, IDD_LOGON_DOMAIN ), Buffer );
pGlobals->ListPopulated = TRUE ; } else { //
// Restore the old array, otherwise the pointers in the
// combo items will point to freed memory
//
pGlobals->ActiveArray = ActiveArrayBackup ; } } }
break;
default:
switch (LOWORD(wParam)) {
case IDD_LOGON_NAME: { switch(HIWORD(wParam)) { case EN_CHANGE: { EnableDomainForUPN((HWND) lParam, GetDlgItem(hDlg, IDD_LOGON_DOMAIN)); return TRUE; } } } break; case IDOK:
//
// Deal with combo-box UI requirements
//
if (HandleComboBoxOK(hDlg, IDD_LOGON_DOMAIN)) { return(TRUE); }
Result = AttemptLogon( hDlg );
if (Result == MSGINA_DLG_FAILURE) { if (!fDisconnectOnTsAutoLogonFailure && !g_fHelpAssistantLogon ) { // Let the user try again
// Clear the password field and set focus to it
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL); SetPasswordFocus(hDlg); } else { bSmartCardInserted = FALSE; EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF); }
return(TRUE); }
return(TRUE);
case IDCANCEL: { if (!_Shell_LogonDialog_Cancel()) { // If this is TS and the user hit ESC at the smart card pin prompt
// we want to switch to the password dialog
if (/*!g_Console && !IsActiveConsoleSession() && */pGlobals->SmartCardLogon) { EndDialog(hDlg, bSmartCardInserted ? MSGINA_DLG_SMARTCARD_REMOVED : MSGINA_DLG_FAILURE); bSmartCardInserted = FALSE; return TRUE; }
//
// Allow logon screen to go away if not at console
//
bSmartCardInserted = FALSE; EndDialog(hDlg, !g_Console ? MSGINA_DLG_USER_LOGOFF : MSGINA_DLG_FAILURE);
if (g_Console && !IsActiveConsoleSession()) {
pWlxFuncs->WlxDisconnect(); } } return(TRUE); }
case IDD_LOGON_SHUTDOWN: //
// This is a normal shutdown request
//
// Check they know what they're doing and find
// out if they want to reboot too.
//
// Note that we definitely don't want disconnect or logofff
// here since no one is logged on
Result = WinlogonShutdownDialog(hDlg, pGlobals, (SHTDN_DISCONNECT | SHTDN_LOGOFF));
if (DLG_SHUTDOWN(Result)) { _Shell_LogonDialog_ShuttingDown(); bSmartCardInserted = FALSE; EndDialog(hDlg, Result); } return(TRUE);
case IDD_LOGON_OPTIONS: LogonShowOptions(pGlobals, hDlg, !pGlobals->LogonOptionsShown, TRUE); return(TRUE);
} break;
} break;
case WM_TIMER: { switch (wParam) { case 0: { HDC hDC;
RtlEnterCriticalSection(&pGlobals->csGlobals);
if ( pGlobals->LogonInProgress ) { if (pGlobals->cxBand != 0) { pGlobals->xBandOffset = (pGlobals->xBandOffset+5) % pGlobals->cxBand; } } else { pGlobals->xBandOffset = 0; KillTimer(hDlg, 0); }
RtlLeaveCriticalSection(&pGlobals->csGlobals);
hDC = GetDC(hDlg); if ( hDC ) { PaintBranding(hDlg, hDC, pGlobals->xBandOffset, TRUE, TRUE, COLOR_BTNFACE); ReleaseDC(hDlg, hDC); }
return FALSE; } case TIMER_MYLANGUAGECHECK: { LayoutCheckHandler(hDlg, LAYOUT_DEF_USER); break; } } break; }
case WM_ERASEBKGND: return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, TRUE, COLOR_BTNFACE);
case WM_QUERYNEWPALETTE: return BrandingQueryNewPalete(hDlg);
case WM_PALETTECHANGED: return BrandingPaletteChanged(hDlg, (HWND)wParam);
case WM_LOGONCOMPLETE: { _Shell_LogonDialog_LogonCompleted(lParam, pGlobals->UserName, pGlobals->Domain); Result = lParam;
//
// Discard the logon in progress dialog if one is displayed
//
RtlEnterCriticalSection(&pGlobals->csGlobals); pGlobals->LogonInProgress = FALSE; RtlLeaveCriticalSection(&pGlobals->csGlobals);
AttemptLogonSetControls(pGlobals, hDlg);
if (Result == MSGINA_DLG_FAILURE) { if (fDisconnectOnTsAutoLogonFailure || g_fHelpAssistantLogon) { //
// If TermSrv Internet Connector is on
// don't allow a second chance at the logon dialog
//
//
// disconnect immediatly when fail to logon as helpassisant
//
bSmartCardInserted = FALSE; EndDialog(hDlg, MSGINA_DLG_USER_LOGOFF); break; }
if (s_fAttemptedAutoLogon != FALSE) { s_fAttemptedAutoLogon = FALSE; switch (_Shell_LogonDialog_Init(hDlg, SHELL_LOGONDIALOG_LOGGEDOFF)) { case SHELL_LOGONDIALOG_LOGON: goto go_logon; break; case SHELL_LOGONDIALOG_NONE: case SHELL_LOGONDIALOG_EXTERNALHOST: default: break; } }
if (!_Shell_LogonDialog_UIHostActive()) { // Let the user try again - clear the password
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL); SetPasswordFocus(hDlg);
// the logon failed, so lets ensure we show the options pane so they can update
// their domain selection if needed.
if ( !pGlobals->LogonOptionsShown ) LogonShowOptions(pGlobals, hDlg, TRUE, FALSE); } return(TRUE); }
//
// Initialize the TS Profile path and Home dir globals. Also get
// all TS specific user-config data which is used in winlogon
//
if (!g_Console) //only do this for non-console sessions
{ HANDLE ImpersonationHandle; BOOL rc;
// DbgPrint("Calling WlxQueryTerminalServicesData() for %ws %ws\n",pGlobals->UserName,pGlobals->Domain);
ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL); ASSERT(ImpersonationHandle); if (ImpersonationHandle != NULL) { //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.
PUNICODE_STRING pFlatUser ; PUNICODE_STRING pFlatDomain ;
LPWSTR wszFlatUserName, wszFlatDomainName; if(NT_SUCCESS(LsaGetUserName( &pFlatUser, &pFlatDomain ))) { wszFlatUserName = (LPWSTR)LocalAlloc(LPTR, pFlatUser->Length+sizeof(WCHAR)); wszFlatDomainName = (LPWSTR)LocalAlloc(LPTR, pFlatDomain->Length+sizeof(WCHAR));
if(wszFlatUserName && wszFlatDomainName) { memcpy(wszFlatUserName, pFlatUser->Buffer, pFlatUser->Length);
memcpy(wszFlatDomainName, pFlatDomain->Buffer, pFlatDomain->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); }
LsaFreeMemory( pFlatUser->Buffer ); LsaFreeMemory( pFlatUser ); LsaFreeMemory( pFlatDomain->Buffer ); LsaFreeMemory( pFlatDomain ); } else { pWlxFuncs->WlxQueryTerminalServicesData(pGlobals->hGlobalWlx, &pGlobals->MuGlobals.TSData,pGlobals->UserName , pGlobals->Domain); }
rc = StopImpersonating(ImpersonationHandle); ASSERT(rc); } }
bSmartCardInserted = FALSE; EndDialog( hDlg, Result ); break; }
case WM_HANDLEFAILEDLOGON: { INT_PTR Result;
if (_Shell_LogonDialog_LogonDisplayError(g_failinfo.Status, g_failinfo.SubStatus)) { if (!IsWindowVisible(hDlg)) { //
// The dialog was hidden for automatic logon. An error occurred.
// Show the dialog so the error can be seen and the problem corrected.
//
SetWindowPos(hDlg, NULL, 0, 0, pGlobals->rcDialog.right - pGlobals->rcDialog.left, pGlobals->rcDialog.bottom - pGlobals->rcDialog.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER); ShowWindow(hDlg, SW_SHOW); } Result = HandleFailedLogon(hDlg); } else { Result = MSGINA_DLG_FAILURE; } SendMessage(hDlg, WM_LOGONCOMPLETE, 0, (LPARAM) Result); return TRUE; } case WLX_WM_SAS:
// Give the consumer logon part a chance to handle the SAS
// or to key off the fact that a SAS has occurred.
(BOOL)_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam);
if ((wParam == WLX_SAS_TYPE_TIMEOUT) || (wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) ) { //
// If this was a timeout, return false, and let winlogon
// kill us later
//
bSmartCardInserted = FALSE; return(FALSE); } if ( wParam == WLX_SAS_TYPE_SC_INSERT ) {
//
// If a password logon is already taking place then ignore this sas
//
if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon) { return(TRUE); }
bSmartCardInserted = TRUE; EndDialog( hDlg, MSGINA_DLG_SMARTCARD_INSERTED );
} else if ( wParam == WLX_SAS_TYPE_SC_REMOVE ) {
//
// If a password logon is already taking place then ignore this sas
//
if (pGlobals->LogonInProgress && !pGlobals->SmartCardLogon) { return(TRUE); }
if ( bSmartCardInserted ) {
bSmartCardInserted = FALSE; EndDialog( hDlg, MSGINA_DLG_SMARTCARD_REMOVED );
} else if ( pGlobals->SmartCardLogon ) {
// If this was a s/c initiated logon, then cancel
// the dialog. Otherwise, ignore it.
bSmartCardInserted = FALSE; EndDialog( hDlg, MSGINA_DLG_FAILURE ); }
} else if ( wParam == WLX_SAS_TYPE_AUTHENTICATED ) { bSmartCardInserted = FALSE; _Shell_LogonDialog_LogonCompleted(MSGINA_DLG_SWITCH_CONSOLE, pGlobals->UserName, pGlobals->Domain); EndDialog( hDlg, MSGINA_DLG_SWITCH_CONSOLE ); }
return(TRUE);
case WM_WTSSESSION_CHANGE: ASSERT(iSessionRegistrationCount < 2); //
// its possible, that we unregister for notification in wm_destroy and still receive this notification,
// as the notification may already have been sent.
//
if (iSessionRegistrationCount == 1) { if (lParam == 0) { //
// we are interested only in logon/logoff messages from session 0.
//
if (wParam == WTS_SESSION_LOGON || wParam == WTS_SESSION_LOGOFF) { bSessionZeroInUse = (wParam == WTS_SESSION_LOGON); SwitchLogonLocked(hDlg, bSessionZeroInUse, FALSE); } } } break;
case WM_DESTROY: // if registered for notification unregister now.
if (iSessionRegistrationCount) { WinStationUnRegisterConsoleNotification (SERVERNAME_CURRENT, hDlg); iSessionRegistrationCount--; ASSERT(iSessionRegistrationCount == 0); } _Shell_LogonDialog_Destroy();
FreeLayoutInfo(LAYOUT_DEF_USER); if ( pGlobals->ActiveArray ) { DCacheFreeArray( pGlobals->ActiveArray ); pGlobals->ActiveArray = NULL ; }
RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_NAME), DisableEditSubClassProc, IDD_LOGON_NAME); RemoveWindowSubclass(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), DisableEditSubClassProc, IDD_LOGON_PASSWORD);
break;
case WM_HIDEOURSELVES: ShowWindow(hDlg, SW_HIDE); break;
default: if (_Shell_LogonDialog_DlgProc(hDlg, message, wParam, lParam) != FALSE) { return(TRUE); } }
return(FALSE); }
/***************************************************************************\
* FUNCTION: LogonDlgInit * * PURPOSE: Handles initialization of logon dialog * * RETURNS: TRUE on success, FALSE on failure * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
BOOL LogonDlgInit( HWND hDlg, BOOL bAutoLogon, DWORD SasType ) { PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA); LPTSTR String = NULL; TCHAR LogonMsg[MAX_PATH]; BOOL RemoveLegalBanner; BOOL ShowOptions = FALSE; HKEY hKey; int err; DWORD RasDisable; DWORD RasForce; STRING Narrow; SECURITY_STATUS Status; RECT rc, rc2; BOOL bHasLangIcon = FALSE; ULONG CacheFlags ;
//
// Populate Security Package List:
//
RtlInitString( &Narrow, MICROSOFT_KERBEROS_NAME_A );
Status = LsaLookupAuthenticationPackage( pGlobals->LsaHandle, &Narrow, &pGlobals->SmartCardLogonPackage );
//
// this (potential) failure is not critical. If it fails, then s/c logons later
// will fail.
//
RtlInitString( &Narrow, NEGOSSP_NAME_A );
Status = LsaLookupAuthenticationPackage( pGlobals->LsaHandle, &Narrow, &pGlobals->PasswordLogonPackage );
if ( !NT_SUCCESS( Status ) ) { return FALSE ; }
//
// Update the caption for certain banks
//
SetWelcomeCaption(hDlg);
//
// Get username and domain last used to login
//
//
// Ignore the default user name unless on the active console
//
if (IsActiveConsoleSession()) { String = NULL;
if ( pGlobals->AutoAdminLogon && pGlobals->IgnoreAutoAdminLogon) { String = AllocAndGetProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, TEXT("")); }
if ( (!String) || (!String[0]) ) { if ( String ) { Free(String); }
String = AllocAndGetProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, TEXT("")); }
if ( String ) { if (!bAutoLogon && (ReadWinlogonBoolValue(DONT_DISPLAY_LAST_USER_KEY, FALSE) == TRUE)) { String[0] = 0; }
SetDlgItemText(hDlg, IDD_LOGON_NAME, String); Free(String); } }
GetProfileString( APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, TEXT(""), pGlobals->Domain, MAX_STRING_BYTES );
if ( !DCacheValidateCache( pGlobals->Cache ) ) { ASSERT( pGlobals->ActiveArray == NULL );
DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, TRUE );
} else { //
// Set the current default:
//
DCacheSetDefaultEntry( pGlobals->Cache, pGlobals->Domain, NULL ); }
CacheFlags = DCacheGetFlags( pGlobals->Cache );
if ( ( CacheFlags & DCACHE_NO_CACHE ) && ( SafeBootMode != SAFEBOOT_MINIMAL ) && ( ( pGlobals->AutoAdminLogon ) || ( CacheFlags & DCACHE_DEF_UNKNOWN ) ) ) { //
// Must wait for the cache to be populated
//
DCacheUpdateFull( pGlobals->Cache, pGlobals->Domain );
CacheFlags = DCacheGetFlags( pGlobals->Cache ); }
pGlobals->ListPopulated = FALSE ;
pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
if ( pGlobals->ActiveArray ) { DCachePopulateListBoxFromArray( pGlobals->ActiveArray, GetDlgItem( hDlg, IDD_LOGON_DOMAIN ), NULL ); } else { EndDialog( hDlg, MSGINA_DLG_FAILURE ); }
pGlobals->ShowRasBox = FALSE;
if (g_Console) {
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\RAS"), 0, KEY_READ, & hKey );
if ( err == 0 ) { RegCloseKey( hKey );
if ( GetRasDialOutProtocols() && ( ( CacheFlags & DCACHE_MEMBER ) != 0 ) ) { pGlobals->ShowRasBox = TRUE; }
}
}
//
// If the audit log is full then display the banner, otherwise
// load the text from the resource if that gives us a string
// then set the control.
//
// Should neither of these apply then remove the control.
// The log full info is only displayed at the console so we
// don't disclose too much info in TS sessions.
//
RemoveLegalBanner = FALSE;
if ( pGlobals->AuditLogFull && !GetSystemMetrics(SM_REMOTESESSION)) { if ( LoadString( hDllInstance, IDS_LOGON_LOG_FULL, LogonMsg, MAX_PATH ) ) { SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, LogonMsg ); } else { RemoveLegalBanner = TRUE; } } else { String = AllocAndGetProfileString( APPLICATION_NAME, LOGON_MSG_KEY, TEXT("") ); if ( String ) { if ( *String ) { SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, String ); } else { RemoveLegalBanner = TRUE; }
Free( String ); } else { RemoveLegalBanner = TRUE; } }
if ( RemoveLegalBanner ) { GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_ANNOUNCE), &rc); MoveControls(hDlg, ctrlNoLegalBanner, sizeof(ctrlNoLegalBanner)/sizeof(ctrlNoLegalBanner[0]), 0, rc.top-rc.bottom, TRUE);
ShowDlgItem(hDlg, IDD_LOGON_ANNOUNCE, FALSE); }
//
// Smart Card Specific Stuff:
//
if ( SasType == WLX_SAS_TYPE_SC_INSERT ) { //
// remove the user name fields
//
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_NAME), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc2);
MoveControls(hDlg, ctrlNoUserName, sizeof(ctrlNoUserName)/sizeof(ctrlNoUserName[0]), 0, -(rc2.top-rc.top), TRUE);
ShowDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE); EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, FALSE);
ShowDlgItem(hDlg, IDD_LOGON_NAME, FALSE); EnableDlgItem(hDlg, IDD_LOGON_NAME, FALSE); SetDlgItemText( hDlg, IDD_LOGON_NAME, TEXT(""));
LoadString(hDllInstance, IDS_PIN, LogonMsg, MAX_PATH); SetDlgItemText( hDlg, IDD_LOGON_PASSWORD_LABEL, LogonMsg );
pGlobals->SmartCardLogon = TRUE;
} else { pGlobals->SmartCardLogon = FALSE; }
//
// If this is safe boot and/or we are not part of a domain then lets
// remove the domain and nix out the RAS box.
//
if ((SafeBootMode == SAFEBOOT_MINIMAL) || (!IsMachineDomainMember()) || (SasType == WLX_SAS_TYPE_SC_INSERT) || (ForceNoDomainUI())) { ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE); EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, FALSE); ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE); EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, FALSE);
pGlobals->ShowDomainBox = FALSE;
// Shorten the window since the domain box isn't used
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2);
MoveControls(hDlg, ctrlNoDomain, ARRAYSIZE(ctrlNoDomain), 0, -(rc2.bottom-rc.bottom), TRUE); } else { pGlobals->ShowDomainBox = TRUE; }
bHasLangIcon = DisplayLanguageIcon(hDlg, LAYOUT_DEF_USER, GetKeyboardLayout(0));
//
// Handle showing the RAS box if needed
//
if ( pGlobals->ShowRasBox ) { RasDisable = GetProfileInt( APPLICATION_NAME, RAS_DISABLE, 0 ); RasForce = GetProfileInt( APPLICATION_NAME, RAS_FORCE, 0 );
if (RasForce) { CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 1 ); } else { CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 ); }
// SM_CLEANBOOT tells us we are in safe mode. In this case, disable since tapisrv isn't started
if (RasDisable || RasForce || GetSystemMetrics(SM_CLEANBOOT)) { EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE); } else { EnableDlgItem(hDlg, IDD_LOGON_RASBOX, TRUE); } } else { // If the domain box is hidden, then we'll have to shorten the dialog by the distance
// between the RAS box and the password box instead of the distance between the
// RAS box and the domain box since the RAS and Domain boxes will be on top of each other
BOOL fUsePassword = !pGlobals->ShowDomainBox;
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 ); EnableDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE); ShowDlgItem(hDlg, IDD_LOGON_RASBOX, FALSE);
GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2); if (!bHasLangIcon) { MoveControls(hDlg, ctrlNoRAS, sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]), 0, -(rc2.bottom-rc.bottom), TRUE); }
}
// Centre the window on the screen and bring it to the front
pGlobals->xBandOffset = 0; // band is not animated yet
SizeForBranding(hDlg, TRUE);
// Position the window at the same coords as the welcome window
if ((pGlobals->rcWelcome.right - pGlobals->rcWelcome.left) != 0) { SetWindowPos(hDlg, NULL, pGlobals->rcWelcome.left, pGlobals->rcWelcome.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } else { CentreWindow(hDlg); }
//
// Handle showing and hiding the logon bits
//
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { DWORD dwType, dwSize = sizeof(ShowOptions);
RegQueryValueEx (hKey, SHOW_LOGON_OPTIONS, NULL, &dwType, (LPBYTE)&ShowOptions, &dwSize);
RegCloseKey (hKey); }
pGlobals->LogonOptionsShown = TRUE;
LogonShowOptions(pGlobals, hDlg, ShowOptions, TRUE);
// Success
return TRUE; }
/****************************************************************************\
* * FUNCTION: LogonShowOptions * * PURPOSE: Hide the options part of the logon dialog * * RETURNS: Nothing * * HISTORY: * * 15-dec-97 daviddv - Created * \****************************************************************************/ VOID LogonShowOptions(PGLOBALS pGlobals, HWND hDlg, BOOL fShow, BOOL fSticky) { HKEY hKey; RECT rc, rc2; INT dy = 0; INT dx = 0; TCHAR szBuffer[32]; BOOL bHasLangIcon = TRUE; DWORD RasDisable; DWORD RasForce;
if ( pGlobals->LogonOptionsShown != fShow ) { BOOL bShutdownWithoutLogon;
//
// Show/hide domain if it is present in the dialog
//
if (pGlobals->ShowDomainBox) { GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_PASSWORD), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), &rc2); dy += rc2.bottom-rc.bottom; }
//
// If RAS is present then lets ensure that we remove that.
//
if (GetKeyboardLayoutList(0,NULL) < 2) { bHasLangIcon = FALSE; }
if ( pGlobals->ShowRasBox || bHasLangIcon) { // Since the domain box may be hidden with the RAS box directly over
// top of it, we may need to use the space between the RAS box and the password
// box
BOOL fUsePassword = !pGlobals->ShowDomainBox;
GetWindowRect(GetDlgItem(hDlg, fUsePassword ? IDD_LOGON_PASSWORD : IDD_LOGON_DOMAIN), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_RASBOX), &rc2); dy += rc2.bottom-rc.bottom; }
MoveControls(hDlg, ctrlNoRAS, sizeof(ctrlNoRAS)/sizeof(ctrlNoRAS[0]), 0, fShow ? dy:-dy, TRUE);
// Handle showing or hiding the shutdown button
// and moving other controls.
ShowDlgItem(hDlg, IDD_KBLAYOUT_ICON, fShow); EnableWindow(GetDlgItem(hDlg, IDD_KBLAYOUT_ICON), fShow); ShowDlgItem(hDlg, IDD_LOGON_SHUTDOWN, fShow);
// Move the OK and Cancel buttons over if we are hiding shutdown
// ..Calculate one "button space". Assumes shutdown will always be on the left of options
GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_LOGON_OPTIONS), &rc2);
dx = rc2.left - rc.left;
// Move OK and Cancel left or right 1 button space
MoveControls(hDlg, ctrlNoShutdown, sizeof(ctrlNoShutdown)/sizeof(ctrlNoShutdown[0]), fShow ? -dx:dx, 0, FALSE);
//
// if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
// instead of the 2 buttons OK and Cancel
//
if ( SafeBootMode == SAFEBOOT_MINIMAL ) { bShutdownWithoutLogon = TRUE ; } else if (IsthisUnlockWindowsDialog() || !IsActiveConsoleSession()) { bShutdownWithoutLogon = FALSE ; } else { bShutdownWithoutLogon = ReadWinlogonBoolValue(SHUTDOWN_WITHOUT_LOGON_KEY, TRUE); }
EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, (fShow) && (bShutdownWithoutLogon));
if ( pGlobals->ShowRasBox ) { ShowDlgItem(hDlg, IDD_LOGON_RASBOX, fShow); RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE,0); RasForce = GetProfileInt(APPLICATION_NAME, RAS_FORCE, 0);
// Never enable RAS for cleanboot
if (!GetSystemMetrics(SM_CLEANBOOT) && !RasForce && !RasDisable) { EnableWindow(GetDlgItem(hDlg, IDD_LOGON_RASBOX), fShow); } }
if ( pGlobals->ShowDomainBox ) { ShowDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, fShow); EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL), fShow); ShowDlgItem(hDlg, IDD_LOGON_DOMAIN, fShow); EnableWindow(GetDlgItem(hDlg, IDD_LOGON_DOMAIN), fShow); }
if ( fSticky ) { if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS) { RegSetValueEx(hKey, SHOW_LOGON_OPTIONS, 0, REG_DWORD, (LPBYTE)&fShow, sizeof(fShow)); RegCloseKey (hKey); } } }
//
// Change the options button to reflect the open/close state
//
LoadString(hDllInstance, fShow ? IDS_LESSOPTIONS:IDS_MOREOPTIONS, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]));
SetDlgItemText(hDlg, IDD_LOGON_OPTIONS, szBuffer);
pGlobals->LogonOptionsShown = fShow;
// Enable or disable the domain box depending on whether a UPN name has been typed
EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN)); }
/***************************************************************************\
* FUNCTION: AttemptLogonSetControls * * PURPOSE: Sets up the logon UI to animating and controls to the * correct state. * * HISTORY: * * 02-05-98 diz Created * \***************************************************************************/
VOID AttemptLogonSetControls( PGLOBALS pGlobals, HWND hDlg ) { DWORD RasDisable; static BOOL sbRasBoxOriginalyEnabled; static BOOL sbShutDownOriginallyEnabled;
RtlEnterCriticalSection( &pGlobals->csGlobals );
EnableDlgItem(hDlg, IDD_LOGON_NAME_LABEL, !pGlobals->LogonInProgress); EnableDlgItem(hDlg, IDD_LOGON_NAME, !pGlobals->LogonInProgress); EnableDlgItem(hDlg, IDD_LOGON_PASSWORD_LABEL, !pGlobals->LogonInProgress); EnableDlgItem(hDlg, IDD_LOGON_PASSWORD, !pGlobals->LogonInProgress); EnableDlgItem(hDlg, IDD_LOGON_DOMAIN_LABEL, !pGlobals->LogonInProgress);
EnableDlgItem(hDlg, IDD_LOGON_DOMAIN, !pGlobals->LogonInProgress);
// If no logon is in progress, we want to enable domain box based on whether
// a UPN has been typed
if (!pGlobals->LogonInProgress) { EnableDomainForUPN(GetDlgItem(hDlg, IDD_LOGON_NAME), GetDlgItem(hDlg, IDD_LOGON_DOMAIN)); }
//
// MakarP: we should not enable all these control when !pGlobals->LogonInProgress, they should really be reverted back to their original state.
// but for now I am just looking after IDD_LOGON_RASBOX in remote connection cases to fix bug #267270
//
if (pGlobals->LogonInProgress) { sbRasBoxOriginalyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_RASBOX)); RasDisable = GetProfileInt(APPLICATION_NAME, RAS_DISABLE, 0); EnableDlgItem(hDlg, IDD_LOGON_RASBOX, !RasDisable && !pGlobals->LogonInProgress);
sbShutDownOriginallyEnabled = IsWindowEnabled(GetDlgItem(hDlg, IDD_LOGON_SHUTDOWN)); EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, !pGlobals->LogonInProgress); } else { EnableDlgItem(hDlg, IDD_LOGON_RASBOX, sbRasBoxOriginalyEnabled); EnableDlgItem(hDlg, IDD_LOGON_SHUTDOWN, sbShutDownOriginallyEnabled); }
EnableDlgItem(hDlg, IDD_KBLAYOUT_ICON, !pGlobals->LogonInProgress); EnableDlgItem(hDlg, IDD_LOGON_OPTIONS, !pGlobals->LogonInProgress);
//
// if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
// instead of the 2 buttons OK and Cancel
//
EnableDlgItem(hDlg, IDOK, !pGlobals->LogonInProgress);
if ( !GetDisableCad(pGlobals) ) EnableDlgItem(hDlg, IDCANCEL, !pGlobals->LogonInProgress);
RtlLeaveCriticalSection( &pGlobals->csGlobals ); }
/***************************************************************************\
* FUNCTION: AttemptLogon * * PURPOSE: Tries to the log the user on using the current values in the * logon dialog controls * * RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully * MSGINA_DLG_FAILURE - the logon failed, * DLG_INTERRUPTED() - a set defined in winlogon.h * * NOTES: If the logon is successful, the global structure is filled in * with the logon information. * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
INT_PTR AttemptLogon( HWND hDlg ) { PGLOBALS pGlobals = (PGLOBALS)GetWindowLongPtr(hDlg, GWLP_USERDATA); PWCHAR UserName = pGlobals->UserName; PWCHAR Domain = pGlobals->Domain; PWCHAR Password = pGlobals->Password; PDOMAIN_CACHE_ENTRY Entry ; RECT rc; HANDLE hThread; DWORD tid; BOOL timeout; PUCHAR Dummy; BOOL RasBox;
UserName[0] = TEXT('\0'); Domain[0] = TEXT('\0'); Password[0] = TEXT('\0');
//
// Hide the password so it doesn't make it to the pagefile in
// cleartext. Do this before getting the username and password
// so that it can't easily be identified (by association with
// the username and password) if we should crash or be rebooted
// before getting a chance to encode it.
//
GetDlgItemText(hDlg, IDD_LOGON_PASSWORD, Password, MAX_STRING_BYTES); RtlInitUnicodeString(&pGlobals->PasswordString, Password); pGlobals->Seed = 0; // Causes the encode routine to assign a seed
HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
//
// Now get the username and domain
//
if ( pGlobals->SmartCardLogon == FALSE ) { HWND hwndDomain = GetDlgItem(hDlg, IDD_LOGON_DOMAIN);
if (hwndDomain != NULL) { INT iDomainSel = (INT)SendMessage(hwndDomain, CB_GETCURSEL, 0, 0);
GetDlgItemText(hDlg, IDD_LOGON_NAME, UserName, MAX_STRING_BYTES);
//
// is this the magical "this computer" entry???
//
Entry = (PDOMAIN_CACHE_ENTRY) SendMessage( hwndDomain, CB_GETITEMDATA, (WPARAM)iDomainSel, 0); } else { Entry = (PDOMAIN_CACHE_ENTRY) CB_ERR; } if ( Entry != (PDOMAIN_CACHE_ENTRY) CB_ERR ) { wcscpy( Domain, Entry->FlatName.Buffer ); } else { Domain[0] = L'\0'; }
} else { UserName[0] = TEXT('\0'); Domain[0] = TEXT('\0') ; }
// If we are forcing a NoDomainUI, populate the domain with the local machine name now
if (ForceNoDomainUI()) { DWORD chSize = MAX_STRING_BYTES;
if (GetComputerName(Domain, &chSize)) { NOTHING; } else { *Domain = 0; } }
//
// If there is a at-sign in the name, assume that means that a UPN logon
// attempt is being made. Set the domain to NULL.
//
if ( wcschr( UserName, L'@' ) ) { Domain[0] = TEXT('\0'); }
RtlInitUnicodeString(&pGlobals->UserNameString, UserName); RtlInitUnicodeString(&pGlobals->DomainString, Domain);
//
// Ok, is the RASbox checked?
//
RasBox = IsDlgButtonChecked( hDlg, IDD_LOGON_RASBOX ); pGlobals->RasUsed = FALSE;
if ( RasBox == BST_CHECKED ) { //
// Reset the current timeout so that they neatly clean up before
// winlogon up and blows them away.
//
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, 5 * 60 );
if ( !PopupRasPhonebookDlg( hDlg, pGlobals, &timeout) ) { return( MSGINA_DLG_FAILURE ); }
pGlobals->RasUsed = TRUE;
//
// Reinitialize strings in case they've changed
//
RtlInitUnicodeString( &pGlobals->UserNameString, UserName );
//
// Ping Netlogon to allow us to go out on the net again...
//
I_NetLogonControl2(NULL, NETLOGON_CONTROL_TRANSPORT_NOTIFY, 1, (LPBYTE) &Dummy, &Dummy );
Sleep ((DWORD) ReadWinlogonBoolValue(TEXT("RASSleepTime"), 3000)); RefreshPolicy(TRUE); }
//
// Process arguments before kicking off the thread
//
pGlobals->hwndLogon = hDlg;
RtlEnterCriticalSection( &pGlobals->csGlobals ); pGlobals->LogonInProgress = TRUE ; RtlLeaveCriticalSection( &pGlobals->csGlobals );
GetClientRect(hDlg, &rc); pGlobals->cxBand = rc.right-rc.left;
SetTimer(hDlg, 0, 20, NULL); // setup the progress timer
//
// Kick off real logon thread
//
// Set timeout to infinite while attempting to logon
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, TIMEOUT_NONE );
hThread = CreateThread( NULL, 0, AttemptLogonThread, pGlobals, 0, &tid );
if (hThread) { CloseHandle( hThread ); } else { //
// CreateThread failed, likely because of low memory.
// Inform the user.
//
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, GetLastError(), 0, NULL, NULL);
RtlEnterCriticalSection( &pGlobals->csGlobals ); pGlobals->LogonInProgress = FALSE ; RtlLeaveCriticalSection( &pGlobals->csGlobals ); return MSGINA_DLG_FAILURE ; }
AttemptLogonSetControls(pGlobals, hDlg);
return MSGINA_DLG_SUCCESS; }
BOOL ReplacedPossibleDisplayName (WCHAR *pszUsername)
{ BOOL fReplaced; DWORD dwIndex, dwReturnedEntryCount; NET_API_STATUS nasCode; NET_DISPLAY_USER *pNDU;
fReplaced = FALSE; dwIndex = 0; nasCode = NetQueryDisplayInformation(NULL, 1, dwIndex, 1, sizeof(NET_DISPLAY_USER), &dwReturnedEntryCount, (void**)&pNDU); while (!fReplaced && (dwReturnedEntryCount > 0) && (NERR_Success == nasCode) || (ERROR_MORE_DATA == nasCode)) { fReplaced = (lstrcmpiW(pNDU->usri1_full_name, pszUsername) == 0); if (fReplaced) { lstrcpyW(pszUsername, pNDU->usri1_name); } nasCode = NetApiBufferFree(pNDU); if (!fReplaced) { nasCode = NetQueryDisplayInformation(NULL, 1, ++dwIndex, 1, sizeof(NET_DISPLAY_USER), &dwReturnedEntryCount, (void**)&pNDU); } } return(fReplaced); }
BOOL ReplacedLogonName (PGLOBALS pGlobals)
{ BOOL fReplaced;
fReplaced = ReplacedPossibleDisplayName(pGlobals->UserName); if (fReplaced) { RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName); } return(fReplaced); }
DWORD AttemptLogonThread( PGLOBALS pGlobals ) { STRING PackageName; PSID LogonSid; LUID LogonId = { 0, 0 }; HANDLE UserToken = NULL; HANDLE RestrictedToken; BOOL PasswordExpired, ChangedLogonName; NTSTATUS FinalStatus; NTSTATUS Status = STATUS_SUCCESS; NTSTATUS SubStatus = STATUS_SUCCESS; INT_PTR Result = MSGINA_DLG_FAILURE; ULONG LogonPackage; BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)]; PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer; PVOID AuthInfo ; ULONG AuthInfoSize ; UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ]; PTOKEN_USER pTokenUser ; ULONG TokenInfoSize ; PUCHAR SmartCardInfo ; SECURITY_LOGON_TYPE logonType; PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
#ifdef SMARTCARD_DOGFOOD
DWORD StartTime = 0, EndTime = 0; #endif
//
// Store the logon time
// Do this before calling Lsa so we know if logon is successful that
// the password-must-change time will be greater than this time.
// If we grabbed this time after calling the lsa, this might not be true.
//
if ( IsActiveConsoleSession() ) { // this is the console logon;
logonType = Interactive; } else { // remote sessions user must have the SeRemoteInteractiveLogonRight right which
// is granted to a user due to their membership in the new Remote-Desktop Users group.
logonType = RemoteInteractive; }
GetSystemTimeAsFileTime( (LPFILETIME) &pGlobals->LogonTime );
DebugLog((DEB_TRACE, "In Attempt Logon!\n"));
if ( pGlobals->RasUsed ) { if ( DCacheGetCacheState( pGlobals->Cache ) < DomainCacheRegistryCache ) { //
// We are using really stale data. Poke the cache to get it to use the
// now made RAS connection
//
DCacheUpdateMinimal( pGlobals->Cache, NULL, TRUE ); } }
//
// Generate a unique sid for this logon
//
LogonSid = pGlobals->LogonSid;
SetupCursor( TRUE );
FinalStatus = STATUS_SUCCESS;
if ( wcschr( pGlobals->UserName, L'\\' ) || wcschr( pGlobals->UserName, L'/' ) ) { FinalStatus = STATUS_LOGON_FAILURE ; Status = FinalStatus ; }
// clear card and reader name
pGlobals->Smartcard[0] = TEXT('\0'); pGlobals->SmartcardReader[0] = TEXT('\0');
if ( NT_SUCCESS( FinalStatus ) ) { if ( pGlobals->SmartCardLogon ) { pGlobals->AuthenticationPackage = pGlobals->SmartCardLogonPackage ; } else { pGlobals->AuthenticationPackage = pGlobals->PasswordLogonPackage ;
}
if ( pGlobals->SmartCardLogon ) { pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx, WLX_OPTION_SMART_CARD_INFO, (ULONG_PTR *) &ScInfo );
if ( !ScInfo ) { goto exit; }
SmartCardInfo = ScBuildLogonInfo( ScInfo->pszCard, ScInfo->pszReader, ScInfo->pszContainer, ScInfo->pszCryptoProvider );
if(ScInfo->pszCard && ScInfo->pszReader) {
wcsncpy( pGlobals->Smartcard, ScInfo->pszCard, sizeof(pGlobals->Smartcard) / sizeof(TCHAR) - 1 );
wcsncpy( pGlobals->SmartcardReader, ScInfo->pszReader, sizeof(pGlobals->SmartcardReader) / sizeof(TCHAR) - 1 ); }
#ifndef SMARTCARD_DOGFOOD
LocalFree( ScInfo ); #endif
AuthInfo = FormatSmartCardCredentials( &pGlobals->PasswordString, SmartCardInfo, FALSE, NULL, &AuthInfoSize );
LocalFree( SmartCardInfo );
} else { AuthInfo = FormatPasswordCredentials( &pGlobals->UserNameString, &pGlobals->DomainString, &pGlobals->PasswordString, FALSE, NULL, &AuthInfoSize );
}
//
// Actually try to logon the user
//
#ifdef SMARTCARD_DOGFOOD
StartTime = GetTickCount(); #endif
FinalStatus = WinLogonUser( pGlobals->LsaHandle, pGlobals->AuthenticationPackage, logonType, AuthInfo, AuthInfoSize, LogonSid, &LogonId, &UserToken, &pGlobals->UserProcessData.Quotas, (PVOID *)&pGlobals->Profile, &pGlobals->ProfileLength, &SubStatus, &pGlobals->OptimizedLogonStatus);
#ifdef SMARTCARD_DOGFOOD
EndTime = GetTickCount(); #endif
Status = FinalStatus; }
SetupCursor( FALSE );
RtlEnterCriticalSection( &pGlobals->csGlobals ); pGlobals->LogonInProgress = FALSE; RtlLeaveCriticalSection( &pGlobals->csGlobals );
DebugLog((DEB_TRACE, "WinLogonUser returned %#x\n", Status));
PasswordExpired = (((Status == STATUS_ACCOUNT_RESTRICTION) && (SubStatus == STATUS_PASSWORD_EXPIRED)) || (Status == STATUS_PASSWORD_MUST_CHANGE));
//
// If the account has expired we let them change their password and
// automatically retry the logon with the new password.
//
if (PasswordExpired) { _Shell_LogonDialog_HideUIHost();
if (Status == STATUS_PASSWORD_MUST_CHANGE) {
Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_MUST_CHANGE, IDS_LOGON_MESSAGE, MB_OK | MB_ICONSTOP | MB_SETFOREGROUND, TIMEOUT_CURRENT);
} else {
Result = TimeoutMessageBox(pGlobals->hwndLogon, pGlobals, IDS_PASSWORD_EXPIRED, IDS_LOGON_MESSAGE, MB_OK | MB_ICONSTOP | MB_SETFOREGROUND, TIMEOUT_CURRENT);
}
if (DLG_INTERRUPTED(Result)) goto exit;
//
// Copy the old password for mpr notification later
//
RevealPassword( &pGlobals->PasswordString ); wcsncpy(pGlobals->OldPassword, pGlobals->Password, MAX_STRING_BYTES); pGlobals->OldSeed = 0; RtlInitUnicodeString(&pGlobals->OldPasswordString, pGlobals->OldPassword); HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString); pGlobals->OldPasswordPresent = 1;
//
// Let the user change their password
//
LogonPackage = pGlobals->AuthenticationPackage ;
RtlInitString(&PackageName, MSV1_0_PACKAGE_NAME ); Status = LsaLookupAuthenticationPackage ( pGlobals->LsaHandle, &PackageName, &pGlobals->AuthenticationPackage );
if (!NT_SUCCESS(Status)) {
DebugLog((DEB_ERROR, "Failed to find %s authentication package, status = 0x%lx", MSV1_0_PACKAGE_NAME, Status));
Result = MSGINA_DLG_FAILURE; goto exit; }
Result = ChangePasswordLogon(pGlobals->hwndLogon, pGlobals, pGlobals->UserName, pGlobals->Domain, pGlobals->Password);
pGlobals->AuthenticationPackage = LogonPackage ;
if (DLG_INTERRUPTED(Result)) goto exit;
if (Result == MSGINA_DLG_FAILURE) { // The user doesn't want to, or failed to change their password.
goto exit; } }
// Special handling for failed logon on personal or professional
// machines that are NOT joined to a domain. In this case it's
// probably a user who disabled friendly UI and only knows of
// their "display name" not their real "logon name". This
// transparently maps one to the other to allow logons using
// the "display name".
ChangedLogonName = ((FinalStatus == STATUS_LOGON_FAILURE) && (IsOS(OS_PERSONAL) || IsOS(OS_PROFESSIONAL)) && !IsMachineDomainMember() && ReplacedLogonName(pGlobals));
if (PasswordExpired || ChangedLogonName) {
//
// Retry the logon with the changed password
//
//
// Generate a unique sid for this logon
//
LogonSid = pGlobals->LogonSid;
AuthInfo = FormatPasswordCredentials( &pGlobals->UserNameString, &pGlobals->DomainString, &pGlobals->PasswordString, FALSE, NULL, &AuthInfoSize );
Status = WinLogonUser( pGlobals->LsaHandle, pGlobals->AuthenticationPackage, logonType, AuthInfo, AuthInfoSize, LogonSid, &LogonId, &UserToken, &pGlobals->UserProcessData.Quotas, (PVOID *)&pGlobals->Profile, &pGlobals->ProfileLength, &SubStatus, &pGlobals->OptimizedLogonStatus);
}
//
// Deal with a terminally failed logon attempt
//
if (!NT_SUCCESS(Status)) { //
// Do lockout processing
//
LockoutHandleFailedLogon(pGlobals);
Result = MSGINA_DLG_FAILEDMSGSENT;
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, SubStatus, pGlobals->UserName, pGlobals->Domain);
goto exit; }
//
// The user logged on successfully
//
//
// Do lockout processing
//
LockoutHandleSuccessfulLogon(pGlobals);
//
// If the audit log is full, check they're an admin
//
if (pGlobals->AuditLogFull) {
//
// The audit log is full, so only administrators are allowed to logon.
//
if (!UserToken || !TestTokenForAdmin(UserToken)) {
//
// The user is not an administrator, boot 'em.
//
LsaFreeReturnBuffer(pGlobals->Profile); pGlobals->Profile = NULL; NtClose(UserToken);
Result = MSGINA_DLG_FAILEDMSGSENT;
// Post a specific substatus so we can display a meaningful error message
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, STATUS_LOGON_FAILURE, IDS_LOGON_LOG_FULL, pGlobals->UserName, pGlobals->Domain);
goto exit; } else { //
// If we are in a session, we didn't display the log full onfo on the welcome
// screen, so tell the admin
//
if (GetSystemMetrics(SM_REMOTESESSION)) { TimeoutMessageBox( pGlobals->hwndLogon, pGlobals, IDS_LOGON_LOG_FULL_ADMIN, IDS_LOGON_MESSAGE, MB_OK | MB_ICONSTOP | MB_SETFOREGROUND, TIMEOUT_CURRENT); } } }
//
// Hide ourselves before letting other credential managers put
// up dialogs
//
#if 0
ShowWindow(hDlg, SW_HIDE); #endif
//
// Create a filtered version of the token for running normal applications
// if so indicated by a registry setting
//
if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) {
TokenGroups->Groups[0].Attributes = 0; TokenGroups->Groups[0].Sid = gAdminSid; TokenGroups->GroupCount = 1;
Status = NtFilterToken( UserToken, DISABLE_MAX_PRIVILEGE, TokenGroups, // disable the administrators sid
NULL, // no privileges
NULL, &RestrictedToken ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status)); RestrictedToken = NULL; }
//
// Now set the default dacl for the token
//
{ PACL Dacl = NULL; ULONG DaclLength = 0; TOKEN_DEFAULT_DACL DefaultDacl;
DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid); Dacl = Alloc(DaclLength); Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION, GENERIC_ALL, LogonSid ); ASSERT(NT_SUCCESS(Status)); DefaultDacl.DefaultDacl = Dacl; Status = NtSetInformationToken( RestrictedToken, TokenDefaultDacl, &DefaultDacl, sizeof(TOKEN_DEFAULT_DACL) ); ASSERT(NT_SUCCESS(Status));
Free(Dacl); }
} else { RestrictedToken = NULL; }
//
// Notify credential managers of the successful logon
//
pTokenUser = (PTOKEN_USER) UserBuffer ; Status = NtQueryInformationToken( UserToken, TokenUser, pTokenUser, sizeof( UserBuffer ), &TokenInfoSize );
if ( NT_SUCCESS( Status ) ) { pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED, RtlLengthSid( pTokenUser->User.Sid ) );
if ( pGlobals->UserProcessData.UserSid ) { RtlCopyMemory( pGlobals->UserProcessData.UserSid, pTokenUser->User.Sid, RtlLengthSid( pTokenUser->User.Sid ) ); } else { Status = STATUS_NO_MEMORY ; } }
if ( !NT_SUCCESS( Status ) ) {
LsaFreeReturnBuffer(pGlobals->Profile); pGlobals->Profile = NULL; NtClose(UserToken);
Result = MSGINA_DLG_FAILEDMSGSENT;
PostFailedLogonMessage(pGlobals->hwndLogon, pGlobals, Status, 0, pGlobals->UserName, pGlobals->Domain);
goto exit; }
pGlobals->UserProcessData.RestrictedToken = RestrictedToken; pGlobals->UserProcessData.UserToken = UserToken; pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
pGlobals->MprLogonScripts = NULL;
pGlobals->ExtraApps = NULL ;
//
// If we get here, the system works well enough for the user to have
// actually logged on. Profile failures aren't fixable by last known
// good anyway. Therefore, declare the boot good.
//
ReportBootGood(pGlobals);
//
// Set up the system for the new user
//
pGlobals->LogonId = LogonId; if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) { if (pGlobals->Profile->FullName.Length > MAX_STRING_LENGTH) { wcsncpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, MAX_STRING_LENGTH); *(pGlobals->UserFullName + MAX_STRING_LENGTH) = UNICODE_NULL; } else { lstrcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer); }
} else {
//
// No profile - set full name = NULL
pGlobals->UserFullName[0] = 0; ASSERT( lstrlen(pGlobals->UserFullName) == 0); }
if ( pGlobals->SmartCardLogon ) { PCCERT_CONTEXT Cert ; PKERB_SMART_CARD_PROFILE ScProfile ;
//
// Need to fix up the user name with the name (UPN) from the
// certificate, so that unlock, etc. work correctly.
//
ScProfile = (PKERB_SMART_CARD_PROFILE) pGlobals->Profile ;
pGlobals->UserName[0] = 0 ;
try { Cert = CertCreateCertificateContext( X509_ASN_ENCODING, ScProfile->CertificateData, ScProfile->CertificateSize );
if ( Cert ) { // Even though the name is MAX_STRING_BYTES, the way it is used
// throughout the code, it is used as a character counter
// (Grrr, crappy gina code)
//
DWORD dwLen = MAX_STRING_BYTES; if(STATUS_SUCCESS == UpnFromCert(Cert, &dwLen, pGlobals->UserName)) { RtlInitUnicodeString( &pGlobals->UserNameString, pGlobals->UserName ); }
CertFreeCertificateContext( Cert ); } } except( EXCEPTION_EXECUTE_HANDLER ) { pGlobals->UserName[0] = L'\0'; }
//
// If this is still 0 on exit, the code that sets up the flat name
// will copy the flat name into UserName, so the failure case is
// easy.
//
}
pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 );
//
// WE SHOULD NOT WRITE INTO THE REGISTRY.
// CLupu
//
//
// Update our default username and domain ready for the next logon
//
//
// Update the default username & domain only if on the console. Otherwise
// we'll break AutoAdminLogon by changing the user name.
//
if ( g_Console ) { if ( (!pGlobals->AutoAdminLogon) && (SafeBootMode != SAFEBOOT_MINIMAL ) ) { WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName); WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain); }
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName); WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
}
if ( pGlobals->Domain[0] ) { DCacheSetDefaultEntry( pGlobals->Cache, pGlobals->Domain, NULL ); }
Result = MSGINA_DLG_SUCCESS;
exit:
#ifdef SMARTCARD_DOGFOOD
if (pGlobals->SmartCardLogon) {
switch (SubStatus) { case STATUS_SMARTCARD_WRONG_PIN: case STATUS_SMARTCARD_CARD_BLOCKED: case STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED: case STATUS_SMARTCARD_NO_CARD: case STATUS_SMARTCARD_NO_KEY_CONTAINER: case STATUS_SMARTCARD_NO_CERTIFICATE: case STATUS_SMARTCARD_NO_KEYSET: case STATUS_SMARTCARD_IO_ERROR: case STATUS_SMARTCARD_SUBSYSTEM_FAILURE: case STATUS_SMARTCARD_CERT_EXPIRED: case STATUS_SMARTCARD_CERT_REVOKED: case STATUS_ISSUING_CA_UNTRUSTED: case STATUS_REVOCATION_OFFLINE_C: case STATUS_PKINIT_CLIENT_FAILURE: FinalStatus = SubStatus; break;
default: break; // do NOTHING
}
// write logon data to database
AuthMonitor( AuthOperLogon, g_Console, &pGlobals->UserNameString, &pGlobals->DomainString, (ScInfo ? ScInfo->pszCard : NULL), (ScInfo ? ScInfo->pszReader : NULL), (PKERB_SMART_CARD_PROFILE) pGlobals->Profile, EndTime - StartTime, FinalStatus ); }
if (ScInfo) { LocalFree( ScInfo ); } #endif
// Only send a logon complete message if we haven't sent a failed
// message. The failed message will send a logon complete message
// when its done.
if (Result != MSGINA_DLG_FAILEDMSGSENT) { PostMessage(pGlobals->hwndLogon, WM_LOGONCOMPLETE, 0, Result); }
return 0L; }
/****************************************************************************\
* * FUNCTION: PostFailedLogonMessage * * PURPOSE: Posts a message to the UI thread telling it to display a dialog that * tells the user why their logon attempt failed. * * The window on the UI thread must correctly handle WM_HANDLEFAILEDLOGON * by calling HandleFailedLogon and the Free'ing the structure * * RETURNS: void * * HISTORY: * * 12-09-91 Davidc Created. * \****************************************************************************/ void PostFailedLogonMessage(HWND hDlg, PGLOBALS pGlobals, NTSTATUS Status, NTSTATUS SubStatus, PWCHAR UserName, PWCHAR Domain )
{ g_failinfo.pGlobals = pGlobals; g_failinfo.Status = Status; g_failinfo.SubStatus = SubStatus; if ( UserName ) { lstrcpyn(g_failinfo.UserName, UserName, ARRAYSIZE(g_failinfo.UserName)); } else { g_failinfo.UserName[0] = L'\0'; }
if ( Domain ) { lstrcpyn(g_failinfo.Domain, Domain, ARRAYSIZE(g_failinfo.Domain)); } else { g_failinfo.Domain[0] = L'\0' ; }
PostMessage(hDlg, WM_HANDLEFAILEDLOGON, 0 , 0); }
INT_PTR CALLBACK FailDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { RUNDLLPROC fptr; HMODULE hDll;
switch (message) { case WM_INITDIALOG: { CentreWindow(hDlg); return( TRUE ); }
case WM_COMMAND: { if (LOWORD(wParam) == IDOK) { EndDialog(hDlg, IDOK); } if (LOWORD(wParam) == IDC_RECOVER) { // Will eventually supply username to the recover wizard
// We use a single export from KEYMGR.DLL for this operation. When this operation completes,
// we don't use the DLL again without unlikely user intervention. We could DELAYLOAD keymgr.dll,
// but explicitly loading and unloading this DLL permits us to minimize the memory footprint of msgina.
hDll = LoadLibraryW(L"keymgr.dll"); if (hDll) { fptr = (RUNDLLPROC) GetProcAddress(hDll,(LPCSTR)"PRShowRestoreFromMsginaW"); // next stmt will be removed eventually when we pass the username
if (fptr) { fptr(hDlg,NULL,g_failinfo.UserName,0); } FreeLibrary(hDll); EndDialog(hDlg,IDOK); } } } break; }
return FALSE; }
/****************************************************************************\
* * FUNCTION: HandleFailedLogon * * PURPOSE: Tells the user why their logon attempt failed. * * RETURNS: MSGINA_DLG_FAILURE - we told them what the problem was successfully. * DLG_INTERRUPTED() - a set of return values - see winlogon.h * * HISTORY: * * 12-09-91 Davidc Created. * \****************************************************************************/
INT_PTR HandleFailedLogon( HWND hDlg ) { INT_PTR Result = 0xffffffff; DWORD Win32Error ; TCHAR *Buffer1 = NULL; TCHAR *Buffer2 = NULL; TCHAR *Buffer3 = NULL; PGLOBALS pGlobals = g_failinfo.pGlobals; NTSTATUS Status = g_failinfo.Status; NTSTATUS SubStatus = g_failinfo.SubStatus; PWCHAR Domain = g_failinfo.Domain; DWORD BUStatus = 0xffffffff;
UINT uiMsgId = 0xabab; // abab is out of range value for default handler at the bottom of this
// routine. 0 indicates that the user has a psw reset disk
// -1 means that Buffer1 & 2 contain the message
// otherwise there is a corresponding resource message
//
// for remote sessions, we must set finite timeout value for messagebox.
// so that the session does not remain there forever
//
DWORD TimeOut = IsActiveConsoleSession() ? TIMEOUT_CURRENT : 20;
switch (Status) {
case STATUS_LOGON_FAILURE: case STATUS_NAME_TOO_LONG: // Returned if username is too long
if (SubStatus == IDS_LOGON_LOG_FULL) { uiMsgId = IDS_LOGON_LOG_FULL; } else if (pGlobals->SmartCardLogon) { switch(SubStatus) { case STATUS_SMARTCARD_WRONG_PIN: uiMsgId = IDS_STATUS_SMARTCARD_WRONG_PIN; break; case STATUS_SMARTCARD_CARD_BLOCKED: uiMsgId = IDS_STATUS_SMARTCARD_CARD_BLOCKED; break; case STATUS_SMARTCARD_NO_CARD: uiMsgId = IDS_STATUS_SMARTCARD_NO_CARD; break; case STATUS_SMARTCARD_NO_KEY_CONTAINER: uiMsgId = IDS_STATUS_SMARTCARD_NO_KEY_CONTAINER; break; case STATUS_SMARTCARD_NO_CERTIFICATE: uiMsgId = IDS_STATUS_SMARTCARD_NO_CERTIFICATE; break; case STATUS_SMARTCARD_NO_KEYSET: uiMsgId = IDS_STATUS_SMARTCARD_NO_KEYSET; break; case STATUS_SMARTCARD_IO_ERROR: uiMsgId = IDS_STATUS_SMARTCARD_IO_ERROR; break; case STATUS_SMARTCARD_SUBSYSTEM_FAILURE: uiMsgId = IDS_STATUS_SMARTCARD_SUBSYSTEM_FAILURE; break; case STATUS_SMARTCARD_CERT_REVOKED: uiMsgId = IDS_STATUS_SMARTCARD_CERT_REVOKED; break; case STATUS_ISSUING_CA_UNTRUSTED: uiMsgId = IDS_STATUS_ISSUING_CA_UNTRUSTED; break; case STATUS_REVOCATION_OFFLINE_C: uiMsgId = IDS_STATUS_REVOCATION_OFFLINE_C; break; case STATUS_PKINIT_CLIENT_FAILURE: uiMsgId = IDS_STATUS_PKINIT_CLIENT_FAILURE; break; case STATUS_SMARTCARD_CERT_EXPIRED: uiMsgId = IDS_STATUS_SMARTCARD_CERT_EXPIRED; break; default: uiMsgId = IDS_INCORRECT_NAME_OR_PWD_SC; } } else { // Non-smartcard logon case:
// Find out if the user who attempted logon has a password backup disk
// that could be used to reset the password. If so, present a dialog that
// offers that possibility. Else simple message box. (see passrec.h)
if ((0 == PRQueryStatus(NULL,g_failinfo.UserName,&BUStatus)) && (0 == GetSystemMetrics(SM_REMOTESESSION))) { if (BUStatus == 0) { uiMsgId = 0; break; } } // Else UI message is generic one
uiMsgId = IDS_INCORRECT_NAME_OR_PWD; } break;
case STATUS_NOT_SUPPORTED: case STATUS_PKINIT_NAME_MISMATCH: case STATUS_PKINIT_FAILURE:
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR)); Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
if ((Buffer1 == NULL) || (Buffer2 == NULL)) { uiMsgId = IDS_STATUS_SERVER_SIDE_ERROR_NOINSERT; } else { LoadString(hDllInstance, IDS_STATUS_SERVER_SIDE_ERROR, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Status );
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, MAX_STRING_BYTES);
uiMsgId = (DWORD)-1; }
break;
case STATUS_ACCOUNT_RESTRICTION:
switch (SubStatus) { case STATUS_INVALID_LOGON_HOURS: uiMsgId = IDS_INVALID_LOGON_HOURS; break;
case STATUS_INVALID_WORKSTATION: uiMsgId = IDS_INVALID_WORKSTATION; break;
case STATUS_ACCOUNT_DISABLED: uiMsgId = IDS_ACCOUNT_DISABLED; break;
case STATUS_ACCOUNT_EXPIRED: uiMsgId = IDS_ACCOUNT_EXPIRED2; break;
case STATUS_SMARTCARD_LOGON_REQUIRED: uiMsgId = IDS_SMARTCARD_REQUIRED; break;
default: uiMsgId = IDS_ACCOUNT_RESTRICTION; break; } break;
case STATUS_NO_LOGON_SERVERS:
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR)); Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
if ((Buffer1 == NULL) || (Buffer2 == NULL)) { uiMsgId = IDS_LOGON_NO_DOMAIN_NOINSERT; } else { LoadString(hDllInstance, IDS_LOGON_NO_DOMAIN, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Domain);
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, MAX_STRING_BYTES);
uiMsgId = (DWORD)-1; } break;
case STATUS_LOGON_TYPE_NOT_GRANTED: uiMsgId = IDS_LOGON_TYPE_NOT_GRANTED; break;
case STATUS_NO_TRUST_LSA_SECRET: uiMsgId = IDS_NO_TRUST_LSA_SECRET; break;
case STATUS_TRUSTED_DOMAIN_FAILURE: uiMsgId = IDS_TRUSTED_DOMAIN_FAILURE; break;
case STATUS_TRUSTED_RELATIONSHIP_FAILURE: uiMsgId = IDS_TRUSTED_RELATIONSHIP_FAILURE; break;
case STATUS_ACCOUNT_EXPIRED: uiMsgId = IDS_ACCOUNT_EXPIRED; break;
case STATUS_NETLOGON_NOT_STARTED: uiMsgId = IDS_NETLOGON_NOT_STARTED; break;
case STATUS_ACCOUNT_LOCKED_OUT: uiMsgId = IDS_ACCOUNT_LOCKED; break;
case ERROR_CTX_LOGON_DISABLED: uiMsgId = IDS_MULTIUSER_LOGON_DISABLED; break;
case ERROR_CTX_WINSTATION_ACCESS_DENIED: uiMsgId = IDS_MULTIUSER_WINSTATION_ACCESS_DENIED; break;
case SCARD_E_NO_SMARTCARD: case SCARD_E_UNKNOWN_CARD: //
// Card not recognized (although we should never get this far)
//
uiMsgId = IDS_CARD_NOT_RECOGNIZED; break;
case NTE_PROV_DLL_NOT_FOUND: //
// Card's CSP not found (although we should never get this far)
//
uiMsgId = IDS_CARD_CSP_NOT_RECOGNIZED; break;
case STATUS_TIME_DIFFERENCE_AT_DC: uiMsgId = IDS_TIME_DIFFERENCE_AT_DC; break;
default:
WLPrint(("Logon failure status = 0x%lx, sub-status = 0x%lx", Status, SubStatus));
Buffer1 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR)); Buffer2 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR)); Buffer3 = LocalAlloc(LPTR, MAX_STRING_BYTES * sizeof(TCHAR));
if ((Buffer1 == NULL) || (Buffer2 == NULL) || (Buffer3 == NULL)) { uiMsgId = IDS_UNKNOWN_LOGON_FAILURE_NOINSERT; } else { LoadString(hDllInstance, IDS_UNKNOWN_LOGON_FAILURE, Buffer1, MAX_STRING_BYTES);
if ( NT_ERROR( Status ) ) { Win32Error = RtlNtStatusToDosError( Status ); } else { //
// Probably an HRESULT:
//
Win32Error = Status ; }
GetErrorDescription( Win32Error, Buffer3, MAX_STRING_BYTES);
_snwprintf(Buffer2, MAX_STRING_BYTES, Buffer1, Buffer3 );
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, MAX_STRING_BYTES);
uiMsgId = (DWORD)-1; } break; }
_Shell_LogonDialog_HideUIHost();
switch (uiMsgId) { case 0: // User has a password reset disk - present the option to use it along with the usual
// help message
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx,LOGON_TIMEOUT); Result = pWlxFuncs->WlxDialogBoxParam(pGlobals->hGlobalWlx, hDllInstance, (LPTSTR) IDD_FAILLOGONHELP_DIALOG, hDlg, FailDlgProc, 0); break;
case (DWORD)-1: Result = TimeoutMessageBoxlpstr(hDlg, pGlobals, Buffer2, Buffer1, MB_OK | MB_ICONEXCLAMATION, TimeOut); break;
default: Result = TimeoutMessageBox(hDlg, pGlobals, uiMsgId, IDS_LOGON_MESSAGE, MB_OK | MB_ICONEXCLAMATION, TimeOut); }
if (Buffer1 != NULL) LocalFree(Buffer1); if (Buffer2 != NULL) LocalFree(Buffer2); if (Buffer3 != NULL) LocalFree(Buffer3);
if (!DLG_INTERRUPTED(Result)) { Result = MSGINA_DLG_FAILURE; }
return(Result); }
VOID ReportBootGoodThread (LPVOID lpDummy) { HANDLE hInstDll; // PGLOBALS pGlobals = (PGLOBALS)lpDummy;
// SetThreadDesktop(pGlobals->hdeskParent);
hInstDll = LoadLibrary (TEXT("msgina.dll"));
NotifyBootConfigStatus(TRUE);
if (hInstDll) { FreeLibraryAndExitThread(hInstDll, TRUE); } else { ExitThread (TRUE); } }
/****************************************************************************\
* * FUNCTION: ReportBootGood * * PURPOSE: Discover if reporting boot success is responsibility of * winlogon or not. * If it is, report boot success. * Otherwise, do nothing. * * RETURNS: Nothing * * HISTORY: * * 02-Feb-1993 bryanwi - created * \****************************************************************************/ VOID ReportBootGood(PGLOBALS pGlobals) { static DWORD fDoIt = (DWORD) -1; // -1 == uninited
// 0 == don't do it, or done
// 1 == do it
PWCH pchData; DWORD cb, cbCopied; HANDLE hThread; DWORD dwThreadID;
if (fDoIt == -1) {
if ((pchData = Alloc(cb = sizeof(TCHAR)*128)) == NULL) { return; }
pchData[0] = TEXT('0'); cbCopied = GetProfileString(APPLICATION_NAME, REPORT_BOOT_OK_KEY, TEXT("0"), (LPTSTR)pchData, 128);
fDoIt = 0; if (pchData[0] != TEXT('0')) {
//
// "ReportBootGood" is present, and has some value other than
// '0', so report success.
//
fDoIt = 1; }
Free((TCHAR *)pchData); }
if (fDoIt == 1) {
hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)ReportBootGoodThread, pGlobals, CREATE_SUSPENDED, &dwThreadID);
if (hThread) { SetThreadPriority (hThread, THREAD_PRIORITY_LOWEST); ResumeThread (hThread); CloseHandle (hThread);
} else { NotifyBootConfigStatus(TRUE); } fDoIt = 0; }
return; }
//+---------------------------------------------------------------------------
//
// Function: UpnFromCert
//
// Notes:
//
//----------------------------------------------------------------------------
NTSTATUS UpnFromCert( IN PCCERT_CONTEXT pCert, IN OUT DWORD *pcUpn, IN OUT LPWSTR pUPN ) { NTSTATUS Status = STATUS_SUCCESS; ULONG ExtensionIndex = 0; PCERT_ALT_NAME_INFO AltName=NULL; PCERT_NAME_VALUE PrincipalNameBlob = NULL;
//
// Get the client name from the cert
//
// See if cert has UPN in AltSubjectName->otherName
for(ExtensionIndex = 0; ExtensionIndex < pCert->pCertInfo->cExtension; ExtensionIndex++) { if(strcmp(pCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId, szOID_SUBJECT_ALT_NAME2) == 0) { DWORD AltNameStructSize = 0; ULONG CertAltNameIndex = 0; if(CryptDecodeObjectEx(pCert->dwCertEncodingType, X509_ALTERNATE_NAME, pCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData, pCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (PVOID)&AltName, &AltNameStructSize)) {
for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++) { PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex]; if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) && (NULL != AltNameEntry->pOtherName) && (0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId))) { DWORD PrincipalNameBlobSize = 0;
// We found a UPN!
if(CryptDecodeObjectEx(pCert->dwCertEncodingType, X509_UNICODE_ANY_STRING, AltNameEntry->pOtherName->Value.pbData, AltNameEntry->pOtherName->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (PVOID)&PrincipalNameBlob, &PrincipalNameBlobSize)) { if(PrincipalNameBlob->Value.cbData + sizeof(WCHAR) > *pcUpn) { Status = STATUS_BUFFER_OVERFLOW; } else { *pcUpn = PrincipalNameBlob->Value.cbData + sizeof(WCHAR);
CopyMemory(pUPN, PrincipalNameBlob->Value.pbData, PrincipalNameBlob->Value.cbData); *(WCHAR *)((PBYTE)pUPN+PrincipalNameBlob->Value.cbData) = 0; }
LocalFree(PrincipalNameBlob); PrincipalNameBlob = NULL; LocalFree(AltName); AltName = NULL;
goto Finished; } } } LocalFree(AltName); AltName = NULL; } } }
//
// If the name was not found in the UPN, then
// we grab it the old way.
if ( !CertGetNameString( pCert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, pUPN, *pcUpn ) ) { Status = GetLastError(); }
Finished:
return Status ; }
//+---------------------------------------------------------------------------
//
// Function:TSAuthenticatedLogon
//
// Notes: This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
// in the context of the console session (sessionid 0) winlogon.
// This type of logon is for Single Session Terminal Server. When a user
// logs on from a remote TS session, we pass the credentials from the remote session
// to the console session and do an auto-logon. This routine queries the credentials
// logs on the user on the console sesion
//
//
//----------------------------------------------------------------------------
INT_PTR TSAuthenticatedLogon(PGLOBALS pGlobals) { PSID LogonSid; LUID LogonId; HANDLE UserToken; HANDLE RestrictedToken; INT_PTR Result = MSGINA_DLG_SUCCESS; UCHAR UserBuffer[ SID_MAX_SUB_AUTHORITIES * sizeof( DWORD ) + 8 + sizeof( TOKEN_USER ) ]; PTOKEN_USER pTokenUser ; ULONG TokenInfoSize ; NTSTATUS Status; BYTE GroupsBuffer[sizeof(TOKEN_GROUPS)+sizeof(SID_AND_ATTRIBUTES)]; PTOKEN_GROUPS TokenGroups = (PTOKEN_GROUPS) GroupsBuffer;
if (!QuerySwitchConsoleCredentials(pGlobals,&UserToken,&LogonId)) { Result = MSGINA_DLG_FAILEDMSGSENT; goto exit; }
if (pGlobals->SmartCardLogon) { wcscpy(pGlobals->Password,L""); wcscpy(pGlobals->OldPassword,L""); } else { wcscpy(pGlobals->Password,L""); RtlInitUnicodeString(&pGlobals->PasswordString,pGlobals->Password); wcscpy(pGlobals->OldPassword,L""); RtlInitUnicodeString(&pGlobals->OldPasswordString,pGlobals->OldPassword); }
RtlInitUnicodeString(&pGlobals->UserNameString, pGlobals->UserName); RtlInitUnicodeString(&pGlobals->DomainString, pGlobals->Domain); pGlobals->RasUsed = FALSE;
pGlobals->hwndLogon = NULL;
//
// Generate a unique sid for this logon
//
if (!GetAndAllocateLogonSid(UserToken,&(pGlobals->LogonSid))) { Result = MSGINA_DLG_FAILEDMSGSENT;
if (pGlobals->Profile) { VirtualFree(pGlobals->Profile, 0, MEM_RELEASE); pGlobals->Profile = NULL; pGlobals->ProfileLength = 0; }
goto exit; }
LogonSid = pGlobals->LogonSid;
//
// The user logged on successfully
//
//
// Create a filtered version of the token for running normal applications
// if so indicated by a registry setting
//
if (GetProfileInt( APPLICATION_NAME, RESTRICT_SHELL, 0) != 0) { TokenGroups->Groups[0].Attributes = 0; TokenGroups->Groups[0].Sid = gAdminSid; TokenGroups->GroupCount = 1; Status = NtFilterToken( UserToken, DISABLE_MAX_PRIVILEGE, TokenGroups, // disable the administrators sid
NULL, // no privileges
NULL, &RestrictedToken ); if (!NT_SUCCESS(Status)) { DebugLog((DEB_ERROR, "Failed to filter token: 0x%%x\n", Status)); RestrictedToken = NULL; } //
// Now set the default dacl for the token
//
{ PACL Dacl = NULL; ULONG DaclLength = 0; TOKEN_DEFAULT_DACL DefaultDacl; DaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(LogonSid); Dacl = Alloc(DaclLength); Status = RtlCreateAcl(Dacl,DaclLength, ACL_REVISION); ASSERT(NT_SUCCESS(Status)); Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION, GENERIC_ALL, LogonSid ); ASSERT(NT_SUCCESS(Status)); DefaultDacl.DefaultDacl = Dacl; Status = NtSetInformationToken( RestrictedToken, TokenDefaultDacl, &DefaultDacl, sizeof(TOKEN_DEFAULT_DACL) ); ASSERT(NT_SUCCESS(Status)); Free(Dacl); } } else { RestrictedToken = NULL; } //
// Notify credential managers of the successful logon
//
pTokenUser = (PTOKEN_USER) UserBuffer ; Status = NtQueryInformationToken( UserToken, TokenUser, pTokenUser, sizeof( UserBuffer ), &TokenInfoSize );
if ( NT_SUCCESS( Status ) ) { pGlobals->UserProcessData.UserSid = LocalAlloc( LMEM_FIXED, RtlLengthSid( pTokenUser->User.Sid ) );
if ( pGlobals->UserProcessData.UserSid ) { RtlCopyMemory( pGlobals->UserProcessData.UserSid, pTokenUser->User.Sid, RtlLengthSid( pTokenUser->User.Sid ) ); } else { Status = STATUS_NO_MEMORY ; } }
if ( !NT_SUCCESS( Status ) ) {
if (pGlobals->Profile) { VirtualFree(pGlobals->Profile, 0, MEM_RELEASE); pGlobals->Profile = NULL; pGlobals->ProfileLength = 0; } NtClose(UserToken);
Result = MSGINA_DLG_FAILEDMSGSENT;
goto exit; }
pGlobals->UserProcessData.RestrictedToken = RestrictedToken; pGlobals->UserProcessData.UserToken = UserToken; pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pWinlogonSid);
pGlobals->MprLogonScripts = NULL;
pGlobals->ExtraApps = NULL ;
//
// If we get here, the system works well enough for the user to have
// actually logged on. Profile failures aren't fixable by last known
// good anyway. Therefore, declare the boot good.
//
ReportBootGood(pGlobals);
//
// Set up the system for the new user
//
pGlobals->LogonId = LogonId; if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) { if (pGlobals->Profile->FullName.Length > MAX_STRING_LENGTH) { wcsncpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, MAX_STRING_LENGTH); *(pGlobals->UserFullName + MAX_STRING_LENGTH) = UNICODE_NULL; } else { lstrcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer); }
} else {
//
// No profile - set full name = NULL
pGlobals->UserFullName[0] = 0; ASSERT( lstrlen(pGlobals->UserFullName) == 0); }
//
// Update our default username and domain ready for the next logon
//
//
// Update the default username & domain only if on the console. Otherwise
// we'll break AutoAdminLogon by changing the user name.
//
if ( g_Console ) { if ( (!pGlobals->AutoAdminLogon) && (SafeBootMode != SAFEBOOT_MINIMAL ) ) { WriteProfileString(APPLICATION_NAME, DEFAULT_USER_NAME_KEY, pGlobals->UserName); WriteProfileString(APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain); }
WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_USER_NAME_KEY, pGlobals->UserName); WriteProfileString(APPLICATION_NAME, TEMP_DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
}
if ( pGlobals->Domain[0] == '\0' ) {
GetProfileString( APPLICATION_NAME, DEFAULT_DOMAIN_NAME_KEY, TEXT(""), pGlobals->Domain, MAX_STRING_BYTES ); }
if ( !DCacheValidateCache( pGlobals->Cache ) ) { ASSERT( pGlobals->ActiveArray == NULL );
DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, TRUE );
} else { //
// Set the current default:
//
DCacheSetDefaultEntry( pGlobals->Cache, pGlobals->Domain, NULL ); }
Result = MSGINA_DLG_SUCCESS;
exit:
return Result;
}
PWSTR AllocAndDuplicateString( PWSTR pszString, int len) { PWSTR pszNewString;
if (!pszString || !len) { return(NULL); }
pszNewString = LocalAlloc(LMEM_FIXED, (len + 2)*sizeof(WCHAR)); if (pszNewString) { wcsncpy(pszNewString, pszString, len); pszNewString[len] = UNICODE_NULL; }
return(pszNewString);
}
BOOL WINAPI WlxGetConsoleSwitchCredentials ( PVOID pWlxContext, PVOID pInfo ) { PGLOBALS pGlobals = (PGLOBALS) pWlxContext; PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 pReq = (PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0)pInfo; BOOL bReturn = FALSE;
if (pReq->dwType != WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0) { return FALSE; }
//
// Initialize allocated pointers.
//
pReq->UserName = NULL; pReq->Domain = NULL; pReq->LogonScript = NULL; pReq->HomeDirectory = NULL; pReq->FullName = NULL; pReq->ProfilePath = NULL; pReq->HomeDirectoryDrive = NULL; pReq->LogonServer = NULL; pReq->PrivateData = NULL;
pReq->LogonId = pGlobals->LogonId; pReq->UserToken = pGlobals->UserProcessData.UserToken; pReq->LogonTime = pGlobals->LogonTime; pReq->SmartCardLogon = pGlobals->SmartCardLogon;
pReq->UserName = AllocAndDuplicateString(pGlobals->UserName, (DWORD) wcslen(pGlobals->UserName));
pReq->Domain = AllocAndDuplicateString(pGlobals->Domain, (DWORD) wcslen(pGlobals->Domain)); //
// Quota Information
//
pReq->Quotas.PagedPoolLimit = pGlobals->UserProcessData.Quotas.PagedPoolLimit; pReq->Quotas.NonPagedPoolLimit = pGlobals->UserProcessData.Quotas.NonPagedPoolLimit; pReq->Quotas.MinimumWorkingSetSize = pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize; pReq->Quotas.MaximumWorkingSetSize = pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize; pReq->Quotas.PagefileLimit = pGlobals->UserProcessData.Quotas.PagefileLimit; pReq->Quotas.TimeLimit = pGlobals->UserProcessData.Quotas.TimeLimit; //
// Profile Information
//
pReq->ProfileLength = pGlobals->ProfileLength; pReq->UserFlags = pGlobals->Profile->UserFlags; pReq->MessageType = pGlobals->Profile->MessageType; pReq->LogonCount = pGlobals->Profile->LogonCount; pReq->BadPasswordCount = pGlobals->Profile->BadPasswordCount; pReq->ProfileLogonTime = pGlobals->Profile->LogonTime; pReq->LogoffTime = pGlobals->Profile->LogoffTime; pReq->KickOffTime = pGlobals->Profile->KickOffTime; pReq->PasswordLastSet = pGlobals->Profile->PasswordLastSet; pReq->PasswordCanChange = pGlobals->Profile->PasswordCanChange; pReq->PasswordMustChange = pGlobals->Profile->PasswordMustChange;
pReq->LogonScript = AllocAndDuplicateString(pGlobals->Profile->LogonScript.Buffer, pGlobals->Profile->LogonScript.Length/sizeof(WCHAR)); pReq->HomeDirectory = AllocAndDuplicateString(pGlobals->Profile->HomeDirectory.Buffer, pGlobals->Profile->HomeDirectory.Length/sizeof(WCHAR)); pReq->FullName = AllocAndDuplicateString(pGlobals->Profile->FullName.Buffer, pGlobals->Profile->FullName.Length/sizeof(WCHAR));
pReq->ProfilePath = AllocAndDuplicateString(pGlobals->Profile->ProfilePath.Buffer, pGlobals->Profile->ProfilePath.Length/sizeof(WCHAR));
pReq->HomeDirectoryDrive = AllocAndDuplicateString(pGlobals->Profile->HomeDirectoryDrive.Buffer, pGlobals->Profile->HomeDirectoryDrive.Length/sizeof(WCHAR)); pReq->LogonServer = AllocAndDuplicateString(pGlobals->Profile->LogonServer.Buffer, pGlobals->Profile->LogonServer.Length/sizeof(WCHAR)); pReq->PrivateDataLen = PASSWORD_HASH_SIZE; pReq->PrivateData = (PBYTE)AllocAndDuplicateString((PWSTR)pGlobals->PasswordHash, PASSWORD_HASH_SIZE ); if (pReq->PrivateData == NULL) { goto done; }
memcpy(pReq->PrivateData, pGlobals->PasswordHash, PASSWORD_HASH_SIZE );
bReturn = TRUE; done: if (!bReturn) { if (pReq->UserName != NULL) { LocalFree(pReq->UserName); } if (pReq->Domain != NULL) { LocalFree(pReq->Domain); } if (pReq->LogonScript != NULL) { LocalFree(pReq->LogonScript); } if (pReq->HomeDirectory != NULL) { LocalFree(pReq->HomeDirectory); } if (pReq->FullName != NULL) { LocalFree(pReq->FullName); } if (pReq->ProfilePath != NULL) { LocalFree(pReq->ProfilePath); } if (pReq->HomeDirectoryDrive != NULL) { LocalFree(pReq->HomeDirectoryDrive); } if (pReq->LogonServer != NULL) { LocalFree(pReq->LogonServer); } if (pReq->PrivateData != NULL) { LocalFree(pReq->PrivateData); } } return bReturn; }
//+---------------------------------------------------------------------------
//
// Function: QuerySwitchConsoleCredentials
//
// Notes:
//
// Query credentials from session connecting to console to do switch console
// This routine gets called in response to WLX_SAS_TYPE_AUTHENTICATED
// in the context of the console session (sessionid 0) winlogon.
// This type of logon is for Single Session Terminal Server. When a user
// logs on from a remote TS session, we pass the credentials from the remote session
// to the console session and do an auto-logon. This routine queries the credentials,
// logs on the user on the console sesion
//
//
//----------------------------------------------------------------------------
BOOL WINAPI QuerySwitchConsoleCredentials(PGLOBALS pGlobals, HANDLE * phUserToken, PLUID pLogonId) { WLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 CredInfo;
RtlZeroMemory(&CredInfo,sizeof(CredInfo));
CredInfo.dwType = WLX_CONSOLESWITCHCREDENTIAL_TYPE_V1_0;
if (!pWlxFuncs->WlxQueryConsoleSwitchCredentials(&CredInfo)){ return FALSE; }
if (!CredInfo.UserToken || !CredInfo.UserName) { //return false if any of the critical information is missing
return FALSE; }
pGlobals->Profile = (PMSV1_0_INTERACTIVE_PROFILE) VirtualAlloc(NULL, sizeof(MSV1_0_INTERACTIVE_PROFILE), MEM_COMMIT, PAGE_READWRITE);
if (pGlobals->Profile == NULL) { goto returnerror; }
//
// Token, LUID
//
*pLogonId = CredInfo.LogonId; *phUserToken = CredInfo.UserToken; pGlobals->LogonTime = CredInfo.LogonTime; pGlobals->SmartCardLogon = CredInfo.SmartCardLogon;
pGlobals->SmartCardOption = GetProfileInt( APPLICATION_NAME, SC_REMOVE_OPTION, 0 ); //
// Quota Information
//
pGlobals->UserProcessData.Quotas.PagedPoolLimit = CredInfo.Quotas.PagedPoolLimit ; pGlobals->UserProcessData.Quotas.NonPagedPoolLimit = CredInfo.Quotas.NonPagedPoolLimit; pGlobals->UserProcessData.Quotas.MinimumWorkingSetSize = CredInfo.Quotas.MinimumWorkingSetSize; pGlobals->UserProcessData.Quotas.MaximumWorkingSetSize = CredInfo.Quotas.MaximumWorkingSetSize; pGlobals->UserProcessData.Quotas.PagefileLimit = CredInfo.Quotas.PagefileLimit; pGlobals->UserProcessData.Quotas.TimeLimit = CredInfo.Quotas.TimeLimit; //
// Profile Information
//
pGlobals->ProfileLength = CredInfo.ProfileLength; pGlobals->Profile->UserFlags = CredInfo.UserFlags; pGlobals->Profile->MessageType = CredInfo.MessageType; pGlobals->Profile->LogonCount = CredInfo.LogonCount; pGlobals->Profile->BadPasswordCount = CredInfo.BadPasswordCount; pGlobals->Profile->LogonTime = CredInfo.ProfileLogonTime; pGlobals->Profile->LogoffTime = CredInfo.LogoffTime; pGlobals->Profile->KickOffTime = CredInfo.KickOffTime; pGlobals->Profile->PasswordLastSet = CredInfo.PasswordLastSet; pGlobals->Profile->PasswordCanChange = CredInfo.PasswordCanChange; pGlobals->Profile->PasswordMustChange = CredInfo.PasswordMustChange; RtlInitUnicodeString(&pGlobals->Profile->LogonScript, CredInfo.LogonScript); RtlInitUnicodeString(&pGlobals->Profile->HomeDirectory, CredInfo.HomeDirectory); RtlInitUnicodeString(&pGlobals->Profile->FullName, CredInfo.FullName); RtlInitUnicodeString(&pGlobals->Profile->ProfilePath, CredInfo.ProfilePath); RtlInitUnicodeString(&pGlobals->Profile->HomeDirectoryDrive, CredInfo.HomeDirectoryDrive); RtlInitUnicodeString(&pGlobals->Profile->LogonServer, CredInfo.LogonServer);
if (CredInfo.UserName) { wcscpy(pGlobals->UserName,CredInfo.UserName); LocalFree(CredInfo.UserName); } else { wcscpy(pGlobals->UserName,L""); }
if (CredInfo.Domain) { wcscpy(pGlobals->Domain,CredInfo.Domain); LocalFree(CredInfo.Domain); } else { wcscpy(pGlobals->Domain,L""); }
if (CredInfo.PrivateDataLen) { RtlCopyMemory(pGlobals->PasswordHash,CredInfo.PrivateData, CredInfo.PrivateDataLen ); LocalFree(CredInfo.PrivateData); } else {
RtlZeroMemory(pGlobals->PasswordHash,PASSWORD_HASH_SIZE); } pGlobals->TransderedCredentials = TRUE;
return TRUE;
returnerror: if (CredInfo.UserName) { LocalFree(CredInfo.UserName); }
if (CredInfo.Domain) { LocalFree(CredInfo.Domain); }
if (CredInfo.LogonScript) { LocalFree(CredInfo.LogonScript); }
if (CredInfo.HomeDirectory) { LocalFree(CredInfo.HomeDirectory); }
if (CredInfo.FullName) { LocalFree(CredInfo.FullName); }
if (CredInfo.ProfilePath) { LocalFree(CredInfo.ProfilePath); }
if (CredInfo.HomeDirectoryDrive) { LocalFree(CredInfo.HomeDirectoryDrive); }
if (CredInfo.LogonServer) { LocalFree(CredInfo.LogonServer); }
if (CredInfo.UserToken) { CloseHandle(CredInfo.UserToken); } if (pGlobals->Profile) { VirtualFree(pGlobals->Profile, 0, MEM_RELEASE); pGlobals->Profile = NULL; pGlobals->ProfileLength = 0; } return FALSE;
}
BOOL GetAndAllocateLogonSid( HANDLE hToken, PSID *pLogonSid ) { PTOKEN_GROUPS ptgGroups = NULL; DWORD cbBuffer = 512; // allocation size
DWORD dwSidLength; // required size to hold Sid
UINT i; // Sid index counter
BOOL bSuccess = FALSE; // assume this function will fail
*pLogonSid = NULL; // invalidate pointer
//
// initial allocation attempts
//
ptgGroups=(PTOKEN_GROUPS)Alloc(cbBuffer); if(ptgGroups == NULL) return FALSE;
__try {
//
// obtain token information. reallocate memory if necessary
//
while(!GetTokenInformation( hToken, TokenGroups, ptgGroups, cbBuffer, &cbBuffer)) {
//
// if appropriate, reallocate memory, otherwise bail
//
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { //
// attempt to reallocate buffer
//
if((ptgGroups=(PTOKEN_GROUPS)ReAlloc( ptgGroups, cbBuffer)) == NULL) __leave; } else __leave; }
//
// Get the logon Sid by looping through the Sids in the token
//
for(i = 0 ; i < ptgGroups->GroupCount ; i++) { if(ptgGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID) {
//
// insure we are dealing with a valid Sid
//
if(!IsValidSid(ptgGroups->Groups[i].Sid)) __leave;
//
// get required allocation size to copy the Sid
//
dwSidLength=GetLengthSid(ptgGroups->Groups[i].Sid);
//
// allocate storage for the Logon Sid
//
if((*pLogonSid=(PSID *)Alloc( dwSidLength)) == NULL) __leave;
//
// copy the Logon Sid to the storage we just allocated
//
if(!CopySid(dwSidLength, *pLogonSid, ptgGroups->Groups[i].Sid)) __leave;
bSuccess=TRUE; // indicate success...
break; // ...and get out
} }
} // try
__finally {
//
// free allocated resources
//
if(ptgGroups != NULL) Free(ptgGroups);
if(!bSuccess) { if(*pLogonSid != NULL) { Free(*pLogonSid); *pLogonSid = NULL; } }
} // finally
return bSuccess; }
|