|
|
//e+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: mslock.c
//
// Contents: Microsoft Logon GUI DLL
//
// History: 7-14-94 RichardW Created
//
//----------------------------------------------------------------------------
#include "msgina.h"
#include <stdio.h>
#include <wchar.h>
#include "shlwapi.h"
#include "shlwapip.h"
#define WM_SMARTCARD_ASYNC_MESSAGE (WM_USER + 201)
#define WM_SMARTCARD_ERROR_DISPLAY_1 (WM_USER + 202)
#define WM_SMARTCARD_ERROR_DISPLAY_2 (WM_USER + 203)
#define MSGINA_DLG_ASYNC_PROCESSING 122
static UINT ctrlNoDomain[] = { IDOK, IDCANCEL, IDD_UNLOCK_OPTIONS, IDD_KBLAYOUT_ICON, };
static UINT ctrlNoUserName[] = { IDD_UNLOCK_DOMAIN, IDD_UNLOCK_DOMAIN_LABEL, IDD_UNLOCK_PASSWORD, IDC_UNLOCK_PASSWORD_LABEL, IDOK, IDCANCEL, IDD_UNLOCK_OPTIONS, IDD_KBLAYOUT_ICON, };
//
// Define the structure used to pass data into the lock dialogs
//
typedef enum _LOCKED_STATE_DIALOGS { LockedDialog, PasswordDialog, PINDialog } LOCKED_STATE_DIALOGS ;
typedef enum _ACTION_TAKEN { None, SmartCardInserted, SmartCardRemoved, CancelHit } ACTION_TAKEN ;
typedef struct { PGLOBALS pGlobals; TIME LockTime; } LOCK_DATA; typedef LOCK_DATA *PLOCK_DATA;
typedef struct _UNLOCK_DLG_STATE { PGLOBALS pGlobals ; DWORD dwSasType ; ACTION_TAKEN ActionTaken; BOOL fKillTimer; BOOL fUserBeingPrompted; BOOL fCardRemoved; } UNLOCK_DLG_STATE, * PUNLOCK_DLG_STATE ;
typedef struct _ASYNC_UNLOCK_DATA { PGLOBALS pGlobals; HWND hDlg; PUNLOCK_DLG_STATE pUnlockDlgState; UNICODE_STRING UserName; UNICODE_STRING Domain; UNICODE_STRING Password; DWORD Reserved; } ASYNC_UNLOCK_DATA, * PASYNC_UNLOCK_DATA;
typedef struct _UNLOCK_MESSAGE { NTSTATUS Status ; UINT Resource ; } UNLOCK_MESSAGE, * PUNLOCK_MESSAGE ;
UNLOCK_MESSAGE UnlockMessages[] = { { STATUS_LOGON_FAILURE, IDS_UNLOCK_FAILED_BAD_PWD }, { STATUS_INVALID_LOGON_HOURS, IDS_INVALID_LOGON_HOURS }, { STATUS_INVALID_WORKSTATION, IDS_INVALID_WORKSTATION }, { STATUS_ACCOUNT_DISABLED, IDS_ACCOUNT_DISABLED }, { STATUS_NO_LOGON_SERVERS, IDS_LOGON_NO_DOMAIN }, { STATUS_LOGON_TYPE_NOT_GRANTED, IDS_LOGON_TYPE_NOT_GRANTED }, { STATUS_NO_TRUST_LSA_SECRET, IDS_NO_TRUST_LSA_SECRET }, { STATUS_TRUSTED_DOMAIN_FAILURE, IDS_TRUSTED_DOMAIN_FAILURE }, { STATUS_TRUSTED_RELATIONSHIP_FAILURE, IDS_TRUSTED_RELATIONSHIP_FAILURE }, { STATUS_ACCOUNT_EXPIRED, IDS_ACCOUNT_EXPIRED }, { STATUS_NETLOGON_NOT_STARTED, IDS_NETLOGON_NOT_STARTED }, { STATUS_ACCOUNT_LOCKED_OUT, IDS_ACCOUNT_LOCKED }, { STATUS_SMARTCARD_WRONG_PIN, IDS_STATUS_SMARTCARD_WRONG_PIN_UNLOCK }, { STATUS_SMARTCARD_CARD_BLOCKED, IDS_STATUS_SMARTCARD_CARD_BLOCKED_UNLOCK }, { STATUS_SMARTCARD_NO_CARD, IDS_STATUS_SMARTCARD_NO_CARD_UNLOCK }, { STATUS_SMARTCARD_NO_KEY_CONTAINER, IDS_STATUS_SMARTCARD_NO_KEY_CONTAINER_UNLOCK }, { STATUS_SMARTCARD_NO_CERTIFICATE, IDS_STATUS_SMARTCARD_NO_CERTIFICATE_UNLOCK }, { STATUS_SMARTCARD_NO_KEYSET, IDS_STATUS_SMARTCARD_NO_KEYSET_UNLOCK }, { STATUS_SMARTCARD_IO_ERROR, IDS_STATUS_SMARTCARD_IO_ERROR_UNLOCK }, { STATUS_SMARTCARD_CERT_EXPIRED, IDS_STATUS_SMARTCARD_CERT_EXPIRED_UNLOCK }, { STATUS_SMARTCARD_CERT_REVOKED, IDS_STATUS_SMARTCARD_CERT_REVOKED_UNLOCK }, { STATUS_ISSUING_CA_UNTRUSTED, IDS_STATUS_ISSUING_CA_UNTRUSTED_UNLOCK }, { STATUS_REVOCATION_OFFLINE_C, IDS_STATUS_REVOCATION_OFFLINE_C_UNLOCK }, { STATUS_PKINIT_CLIENT_FAILURE, IDS_STATUS_PKINIT_CLIENT_FAILURE_UNLOCK } };
//
// Private prototypes
//
BOOL LockedDlgInit(HWND, PGLOBALS); BOOL UnlockDlgInit(HWND, PGLOBALS, DWORD SasType); INT_PTR AttemptUnlock(HWND, PGLOBALS, PUNLOCK_DLG_STATE); BOOL WINAPI LogoffWaitDlgProc(HWND, UINT, DWORD, LONG); VOID UnlockShowOptions(PGLOBALS pGlobals, HWND hDlg, BOOL fShow); VOID DisplaySmartCardUnlockErrMessage(PGLOBALS pGlobals, HWND hDlg, DWORD dwErrorType, NTSTATUS Status, INT_PTR *pResult); BOOL ValidateSC(PGLOBALS pGlobals);
HICON hLockedIcon = NULL; HICON hUnlockIcon = NULL;
// declared in mslogon.c
LRESULT CALLBACK DisableEditSubClassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uiID, DWORD_PTR dwRefData); BOOL ReplacedPossibleDisplayName (WCHAR *pszUsername);
void SetLockedInfo( PGLOBALS pGlobals, HWND hDlg, UINT ControlId) { TCHAR Buffer1[MAX_STRING_BYTES]; TCHAR Buffer2[MAX_STRING_BYTES];
//
// Set the locked message
//
if ( pGlobals->Domain[0] == TEXT('\0') ) { if (lstrlen(pGlobals->UserFullName) == 0) {
//
// There is no full name, so don't try to print one out
//
LoadString(hDllInstance, IDS_LOCKED_EMAIL_NFN_MESSAGE, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName );
} else {
LoadString(hDllInstance, IDS_LOCKED_EMAIL_MESSAGE, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName, pGlobals->UserFullName); }
} else { if (lstrlen(pGlobals->UserFullName) == 0) {
//
// There is no full name, so don't try to print one out
//
LoadString(hDllInstance, IDS_LOCKED_NFN_MESSAGE, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName );
} else {
LoadString(hDllInstance, IDS_LOCKED_MESSAGE, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName, pGlobals->UserFullName); } }
SetWindowText(GetDlgItem(hDlg, ControlId), Buffer2);
}
/***************************************************************************\
* FUNCTION: LockedDlgProc * * PURPOSE: Processes messages for the workstation locked dialog * * RETURNS: * DLG_SUCCESS - the user pressed Ctrl-Alt-Del * DLG_LOGOFF() - the user was asynchronously logged off. * DLG_SCREEN_SAVER_TIMEOUT - the screen-saver should be started * DLG_FAILURE - the dialog could not be displayed. * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
INT_PTR CALLBACK LockedDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) {
PGLOBALS pGlobals = (PGLOBALS) GetWindowLongPtr( hDlg, GWLP_USERDATA);
switch (message) { case WM_INITDIALOG: SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
pGlobals = (PGLOBALS) lParam ;
if (GetDisableCad(pGlobals)) { // Set our size to zero so we we don't appear
SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
pWlxFuncs->WlxSasNotify( pGlobals->hGlobalWlx, WLX_SAS_TYPE_CTRL_ALT_DEL ); } else { if (!LockedDlgInit(hDlg, pGlobals)) { EndDialog(hDlg, DLG_FAILURE); } } return(TRUE);
case WLX_WM_SAS: if ( wParam != WLX_SAS_TYPE_SC_REMOVE && wParam != WLX_SAS_TYPE_SC_FIRST_READER_ARRIVED && wParam != WLX_SAS_TYPE_SC_LAST_READER_REMOVED ) { EndDialog(hDlg, MSGINA_DLG_SUCCESS); } return(TRUE);
case WM_ERASEBKGND: return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, FALSE, COLOR_BTNFACE);
case WM_QUERYNEWPALETTE: return BrandingQueryNewPalete(hDlg);
case WM_PALETTECHANGED: return BrandingPaletteChanged(hDlg, (HWND)wParam); }
// We didn't process this message
return FALSE; }
/***************************************************************************\
* FUNCTION: LockedDlgInit * * PURPOSE: Handles initialization of locked workstation dialog * * RETURNS: TRUE on success, FALSE on failure * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
BOOL LockedDlgInit( HWND hDlg, PGLOBALS pGlobals ) {
ULONG_PTR Value;
SetWelcomeCaption(hDlg); SetLockedInfo(pGlobals, hDlg, IDD_LOCKED_NAME_INFO); SetupSystemMenu(hDlg);
// Size for the branding image we are going to add.
SizeForBranding(hDlg, FALSE);
if ( !hLockedIcon ) { hLockedIcon = LoadImage( hDllInstance, MAKEINTRESOURCE( IDI_LOCKED), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); }
SendMessage( GetDlgItem(hDlg, IDD_LOCKED_ICON), STM_SETICON, (WPARAM)hLockedIcon, 0 );
// Stop filtering SC events so SC unlock works
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx, WLX_OPTION_USE_SMART_CARD, 1, NULL );
//
// is this a smartcard gina?
//
pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx, WLX_OPTION_SMART_CARD_PRESENT, &Value );
if ( Value ) { TCHAR szInsertCard[256]; szInsertCard[0] = 0;
// Also change unlock message to mention smartcard
LoadString(hDllInstance, IDS_INSERTCARDORSAS_UNLOCK, szInsertCard, ARRAYSIZE(szInsertCard));
SetDlgItemText(hDlg, IDD_LOCKED_INSTRUCTIONS, szInsertCard); }
CentreWindow(hDlg);
return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: WlxDisplayLockedNotice
//
// Synopsis:
//
// Effects:
//
// Arguments: [pWlxContext] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 6-16-98 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID WINAPI WlxDisplayLockedNotice( PVOID pWlxContext ) { PGLOBALS pGlobals;
pGlobals = (PGLOBALS) pWlxContext;
GetSystemTimeAsFileTime( (LPFILETIME) &pGlobals->LockTime);
pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, LOGON_TIMEOUT); pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx, hDllInstance, (LPWSTR) MAKEINTRESOURCE(IDD_LOCKED_DIALOG), NULL, LockedDlgProc, (LPARAM) pGlobals );
}
BOOL SmartCardInsterted( PGLOBALS pGlobals) { PWLX_SC_NOTIFICATION_INFO ScInfo = NULL ;
pWlxFuncs->WlxGetOption( pGlobals->hGlobalWlx, WLX_OPTION_SMART_CARD_INFO, (ULONG_PTR *) &ScInfo );
if ( ScInfo ) { LocalFree(ScInfo); return (TRUE); } else { return (FALSE); } }
int WINAPI WlxWkstaLockedSAS( PVOID pWlxContext, DWORD dwSasType ) { PGLOBALS pGlobals; DWORD Result; UNLOCK_DLG_STATE UnlockDlgState ; BOOL fContinue = FALSE; LOCKED_STATE_DIALOGS PreviousState; LOCKED_STATE_DIALOGS CurrentState; pGlobals = (PGLOBALS) pWlxContext;
UnlockDlgState.pGlobals = pGlobals ; UnlockDlgState.dwSasType = dwSasType ; UnlockDlgState.ActionTaken = None ; //
// Set the previous state based on whether CAD is disabled, and
// the current SAS type
//
if (GetDisableCad(pGlobals)) { PreviousState = PasswordDialog;
//
// If the CAD is disabled, then go directly to the PIN dialog
//
if (SmartCardInsterted(pGlobals)) { UnlockDlgState.dwSasType = WLX_SAS_TYPE_SC_INSERT; CurrentState = PINDialog; } else { CurrentState = PasswordDialog; } } else { PreviousState = LockedDialog;
//
// Set the current state based on the SAS we are receiving
//
if (dwSasType == WLX_SAS_TYPE_SC_INSERT) { CurrentState = PINDialog; } else { CurrentState = PasswordDialog; } } do { UnlockDlgState.ActionTaken = None; fContinue = FALSE;
Result = pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx, hDllInstance, MAKEINTRESOURCE(IDD_UNLOCK_DIALOG), NULL, (DLGPROC) UnlockDlgProc, (LPARAM) &UnlockDlgState ); //
// Make a transition based on the current dialog
// (the one that has just ended)
//
switch (CurrentState) { case PasswordDialog:
//
// If the password dialog was just being displayed
// and a smartcard was inserted, then loop back
// and display the PIN dialog, otherwise, if the
// password dialog was dismissed for any other reason,
// then get out.
//
if (UnlockDlgState.ActionTaken == SmartCardInserted) { PreviousState = PasswordDialog; CurrentState = PINDialog; UnlockDlgState.dwSasType = WLX_SAS_TYPE_SC_INSERT; // go to PIN dlg
fContinue = TRUE; } break;
case PINDialog:
//
// If the PIN dialog was just being displayed
// and a smartcard was removed or cancel was hit, AND
// the dialog that was displayed before this was the
// password dialog, then loop back and display the
// password dialog again, otherwise, if the PIN dialog
// was dismissed for any other reason, then get out.
//
if ((UnlockDlgState.ActionTaken == SmartCardRemoved) || (UnlockDlgState.ActionTaken == CancelHit)) { if (PreviousState == PasswordDialog) { CurrentState = PasswordDialog; UnlockDlgState.dwSasType = WLX_SAS_TYPE_CTRL_ALT_DEL; // go to PWD Dlg
fContinue = TRUE; } } break; } } while (fContinue);
switch (Result) { case MSGINA_DLG_SUCCESS:
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 ); }
CheckPasswordExpiry( pGlobals, FALSE ); return(WLX_SAS_ACTION_UNLOCK_WKSTA);
case MSGINA_DLG_FAILURE: case WLX_DLG_INPUT_TIMEOUT: case WLX_DLG_SCREEN_SAVER_TIMEOUT: return(WLX_SAS_ACTION_NONE);
case WLX_DLG_USER_LOGOFF: return(WLX_SAS_ACTION_LOGOFF);
case MSGINA_DLG_FORCE_LOGOFF: return(WLX_SAS_ACTION_FORCE_LOGOFF);
default: DebugLog((DEB_WARN, "Unexpected return code from UnlockDlgProc, %d\n", Result)); return(WLX_SAS_ACTION_NONE);
} }
BOOL ValidateSC( PGLOBALS pGlobals) { 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 FALSE; }
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 FALSE; }
LocalFree(ScInfo); }
return TRUE;
}
/***************************************************************************\
* FUNCTION: UnlockDlgProc * * PURPOSE: Processes messages for the workstation unlock dialog * * RETURNS: * DLG_SUCCESS - the user unlocked the workstation successfully. * DLG_FAILURE - the user failed to unlock the workstation. * DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h) * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
static UINT ctrlNoCancel[] = { IDOK, };
INT_PTR CALLBACK UnlockDlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { PGLOBALS pGlobals = NULL; INT_PTR Result; PUNLOCK_DLG_STATE pUnlockDlgState;
pUnlockDlgState = (PUNLOCK_DLG_STATE) GetWindowLongPtr(hDlg, GWLP_USERDATA);
if (message != WM_INITDIALOG) { pGlobals = pUnlockDlgState->pGlobals; }
switch (message) { case WM_INITDIALOG:
pUnlockDlgState = (PUNLOCK_DLG_STATE) lParam ;
// Screen saver will run if set to expire >= 2 minutes
pWlxFuncs->WlxSetTimeout(pUnlockDlgState->pGlobals->hGlobalWlx, (GetDisableCad(pUnlockDlgState->pGlobals) ? TIMEOUT_NONE : LOGON_TIMEOUT) );
// Limit the maximum password length to 127
SendDlgItemMessage(hDlg, IDD_UNLOCK_PASSWORD, EM_SETLIMITTEXT, (WPARAM) 127, 0);
SetWindowLongPtr(hDlg, GWLP_USERDATA, (ULONG_PTR) pUnlockDlgState );
//
// If this is an sc insert, then make sure the card is inserted correctly.
//
if ( pUnlockDlgState->dwSasType == WLX_SAS_TYPE_SC_INSERT ) { if (!ValidateSC( pUnlockDlgState->pGlobals )) { EndDialog(hDlg, DLG_FAILURE); } }
if (!UnlockDlgInit(hDlg, pUnlockDlgState->pGlobals, pUnlockDlgState->dwSasType )) { EndDialog(hDlg, DLG_FAILURE); }
// Disable edits in username / password box
SetWindowSubclass(GetDlgItem(hDlg, IDD_UNLOCK_NAME) , DisableEditSubClassProc, IDD_UNLOCK_NAME , 0); SetWindowSubclass(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), DisableEditSubClassProc, IDD_UNLOCK_PASSWORD, 0);
return(SetPasswordFocus(hDlg));
case WM_ERASEBKGND: return PaintBranding(hDlg, (HDC)wParam, 0, FALSE, FALSE, COLOR_BTNFACE);
case WM_QUERYNEWPALETTE: return BrandingQueryNewPalete(hDlg);
case WM_PALETTECHANGED: return BrandingPaletteChanged(hDlg, (HWND)wParam);
case WM_COMMAND: switch (LOWORD(wParam)) { case IDD_UNLOCK_NAME: switch (HIWORD(wParam)) { case EN_CHANGE: // Ensure the domain box is enabled/disabled correctly
// in case of a UPN name
EnableDomainForUPN((HWND) lParam, GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN)); return TRUE; default: break; } break; case IDCANCEL:
pUnlockDlgState->ActionTaken = CancelHit; EndDialog(hDlg, DLG_FAILURE); return TRUE;
case IDOK:
//
// Deal with combo-box UI requirements
//
if (HandleComboBoxOK(hDlg, IDD_UNLOCK_DOMAIN)) { return(TRUE); }
Result = AttemptUnlock(hDlg, pGlobals, pUnlockDlgState);
if (Result != MSGINA_DLG_ASYNC_PROCESSING) { //
// If they failed, let them try again, otherwise get out.
//
if (Result != DLG_FAILURE) { EndDialog(hDlg, Result); } // Clear the password field
SetDlgItemText(hDlg, IDD_UNLOCK_PASSWORD, NULL); SetPasswordFocus(hDlg); } else { //
// Let the async thread do the work, then it will send a
// WM_SMARTCARD_ASYNC_MESSAGE message when it is done.
// Meanwhile, disable controls so they don't get mucked with
//
EnableWindow( GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), FALSE ); EnableWindow( GetDlgItem(hDlg, IDOK), FALSE ); EnableWindow( GetDlgItem(hDlg, IDCANCEL), FALSE ); EnableWindow( GetDlgItem(hDlg, IDC_UNLOCK_PASSWORD_LABEL), FALSE ); } return TRUE;
case IDD_UNLOCK_OPTIONS: UnlockShowOptions(pGlobals, hDlg, !pGlobals->UnlockOptionsShown); return TRUE; } break;
case WM_SMARTCARD_ASYNC_MESSAGE:
switch (wParam) { case MSGINA_DLG_SUCCESS:
EndDialog(hDlg, MSGINA_DLG_SUCCESS); break;
case MSGINA_DLG_FORCE_LOGOFF: EndDialog(hDlg, MSGINA_DLG_FORCE_LOGOFF); break;
case MSGINA_DLG_FAILURE:
EnableWindow( GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), TRUE ); EnableWindow( GetDlgItem(hDlg, IDOK), TRUE ); EnableWindow( GetDlgItem(hDlg, IDCANCEL), TRUE ); EnableWindow( GetDlgItem(hDlg, IDC_UNLOCK_PASSWORD_LABEL), TRUE );
// Clear the password field
SetDlgItemText(hDlg, IDD_UNLOCK_PASSWORD, NULL); SetPasswordFocus(hDlg); break; } break;
case WM_SMARTCARD_ERROR_DISPLAY_1:
DisplaySmartCardUnlockErrMessage(pGlobals, hDlg, 1, (NTSTATUS) wParam, (INT_PTR *) lParam); return (TRUE); break;
case WM_SMARTCARD_ERROR_DISPLAY_2:
DisplaySmartCardUnlockErrMessage(pGlobals, hDlg, 2, (NTSTATUS) wParam, (INT_PTR *) lParam); return (TRUE); break;
case WLX_WM_SAS:
// Ignore it
if ( wParam == WLX_SAS_TYPE_CTRL_ALT_DEL ) { return( TRUE ); }
//
// If we are in the middle of a smart card unlock then...
//
if ( pGlobals->LogonInProgress ) { //
// SC_REMOVE is really the only interesting SAS, if we get it,
// kill the dialog.
//
if ( wParam == WLX_SAS_TYPE_SC_REMOVE ) { //
// If the card removal happened while the user is being
// prompted for a yes/no question, then just note that
// we got the removal and deal with it after the questions
// is answered.
//
// Otherwise, kill the dialog
//
if ( pUnlockDlgState->fUserBeingPrompted ) { pUnlockDlgState->fCardRemoved = TRUE; ShowWindow(hDlg, SW_HIDE); } else { pUnlockDlgState->ActionTaken = SmartCardRemoved; EndDialog(hDlg, DLG_FAILURE); } } return( TRUE ); }
//
// If this is an insert and we are in the password state, then
// go to the PIN state
//
if ( ( wParam == WLX_SAS_TYPE_SC_INSERT ) && ( IsWindowVisible( GetDlgItem( hDlg, IDD_UNLOCK_OPTIONS ) ) == TRUE ) ) { //
// Check for some common SC problems before ending the dialog and
// going to the PIN state
//
if ( !ValidateSC( pGlobals ) ) { return( TRUE ); }
pUnlockDlgState->ActionTaken = SmartCardInserted; EndDialog(hDlg, DLG_FAILURE); }
//
// if this is a smart card unlock, if it is removed, kill the dialog.
//
if ( ( wParam == WLX_SAS_TYPE_SC_REMOVE ) && ( IsWindowVisible( GetDlgItem( hDlg, IDD_UNLOCK_OPTIONS ) ) == FALSE ) ) { pUnlockDlgState->ActionTaken = SmartCardRemoved; EndDialog(hDlg, DLG_FAILURE); } else if(wParam == WLX_SAS_TYPE_SC_REMOVE) { //
// Already in the password dialog
//
return ( TRUE ); }
if ( wParam == WLX_SAS_TYPE_AUTHENTICATED ) { EndDialog( hDlg, MSGINA_DLG_SUCCESS ); return TRUE; } else if ( wParam == WLX_SAS_TYPE_USER_LOGOFF ) { EndDialog( hDlg, MSGINA_DLG_USER_LOGOFF ); return TRUE; }
return( FALSE );
case WM_CLOSE: break;
case WM_DESTROY:
FreeLayoutInfo (LAYOUT_CUR_USER);
if ( pGlobals->ActiveArray ) { DCacheFreeArray( pGlobals->ActiveArray ); pGlobals->ActiveArray = NULL ; }
RemoveWindowSubclass(GetDlgItem(hDlg, IDD_UNLOCK_NAME), DisableEditSubClassProc, IDD_UNLOCK_NAME); RemoveWindowSubclass(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), DisableEditSubClassProc, IDD_UNLOCK_PASSWORD);
break;
case WM_TIMER:
if ( wParam == 0 ) { HDC hDC;
RtlEnterCriticalSection(&pGlobals->csGlobals);
if ( pGlobals->LogonInProgress ) { if (pGlobals->cxBand != 0) { pGlobals->xBandOffset = (pGlobals->xBandOffset+5) % pGlobals->cxBand; } } if ( !pGlobals->LogonInProgress || pUnlockDlgState->fKillTimer ) { pGlobals->xBandOffset = 0; KillTimer(hDlg, 0);
//
// Reset timeout to normal
//
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, (GetDisableCad(pGlobals) ? TIMEOUT_NONE : LOGON_TIMEOUT));
}
RtlLeaveCriticalSection(&pGlobals->csGlobals);
hDC = GetDC(hDlg); if ( hDC ) { PaintBranding( hDlg, hDC, pGlobals->xBandOffset, TRUE, FALSE, COLOR_BTNFACE ); ReleaseDC( hDlg, hDC ); }
return FALSE; } else if ( wParam == TIMER_MYLANGUAGECHECK ) { LayoutCheckHandler(hDlg, LAYOUT_CUR_USER); }
break; }
// We didn't process the message
return(FALSE); }
/***************************************************************************\
* FUNCTION: UnlockDlgInit * * PURPOSE: Handles initialization of security options dialog * * RETURNS: TRUE on success, FALSE on failure * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
static UINT ctrlNoOptions[] = { IDOK, IDCANCEL, IDD_KBLAYOUT_ICON, };
BOOL UnlockDlgInit( HWND hDlg, PGLOBALS pGlobals, DWORD SasType ) { RECT rc, rc2; WCHAR Label[ MAX_PATH ];
int err ; DWORD dwSize ; DWORD dwType ; DWORD dwValue ;
dwSize = sizeof( DWORD ); dwValue = 0 ;
err = RegQueryValueEx( WinlogonKey, FORCE_UNLOCK_LOGON, 0, &dwType, (PBYTE) &dwValue, &dwSize );
if ( err || ( dwType != REG_DWORD ) ) { dwValue = 0 ; }
if ( dwValue ) { pGlobals->UnlockBehavior |= UNLOCK_FORCE_AUTHENTICATION ; } else { pGlobals->UnlockBehavior &= ~(UNLOCK_FORCE_AUTHENTICATION ); }
SetWelcomeCaption( hDlg );
SetLockedInfo( pGlobals, hDlg, IDD_UNLOCK_NAME_INFO );
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 );
DisplayLanguageIcon (hDlg, LAYOUT_CUR_USER, GetKeyboardLayout(0));
// Size for the branding image we are going to add.
SizeForBranding(hDlg, FALSE);
pGlobals->xBandOffset = 0;
//
// Fill in the username
//
if ( SasType == WLX_SAS_TYPE_SC_INSERT ) { RECT rc = {0}; RECT rc2 = {0};
//
// No username, hide the field and move other controls up
//
GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_MESSAGE), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), &rc2);
MoveControls(hDlg, ctrlNoUserName, sizeof(ctrlNoUserName)/sizeof(ctrlNoUserName[0]), 0, -(rc2.top-rc.top), TRUE);
// Hide the unnecessary text for SC insert
ShowDlgItem( hDlg, IDD_UNLOCK_MESSAGE, FALSE); ShowDlgItem( hDlg, IDD_UNLOCK_NAME_INFO, FALSE);
// Also remove the unlock icon; when the dialog gets this small, there
// isn't room for this guy and the kblayout icon.
ShowDlgItem( hDlg, IDD_UNLOCK_ICON, FALSE);
ShowDlgItem( hDlg, IDD_UNLOCK_NAME, FALSE ); EnableWindow( GetDlgItem(hDlg, IDD_UNLOCK_NAME), FALSE ); ShowDlgItem( hDlg, IDC_UNLOCK_NAME_LABEL, FALSE );
// Disable and hide domain
ShowDlgItem( hDlg, IDD_UNLOCK_DOMAIN, FALSE ); EnableWindow( GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), FALSE); ShowDlgItem( hDlg, IDD_UNLOCK_DOMAIN_LABEL, FALSE);
LoadString(hDllInstance, IDS_PIN, Label, MAX_PATH); SetDlgItemText( hDlg, IDC_UNLOCK_PASSWORD_LABEL, Label );
GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), &rc2);
MoveControls(hDlg, ctrlNoDomain, ARRAYSIZE(ctrlNoDomain), 0, -(rc2.bottom-rc.bottom), TRUE);
pGlobals->ShowDomainBox = FALSE;
//
// The options button is useless, remove it
//
GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_OPTIONS), &rc2);
MoveControls(hDlg, ctrlNoOptions, sizeof(ctrlNoOptions)/sizeof(ctrlNoOptions[0]), rc2.right-rc.right, 0, FALSE);
ShowDlgItem(hDlg, IDD_UNLOCK_OPTIONS, FALSE);
// Stop filtering SC events so SC unlock works
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx, WLX_OPTION_USE_SMART_CARD, 1, NULL ); } else if (ForceNoDomainUI()) { RECT rc = {0}; RECT rc2 = {0};
// Populate username
SetDlgItemText(hDlg, IDD_UNLOCK_NAME, pGlobals->UserName);
// Disable and hide domain
ShowDlgItem( hDlg, IDD_UNLOCK_DOMAIN, FALSE ); EnableWindow( GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), FALSE); ShowDlgItem( hDlg, IDD_UNLOCK_DOMAIN_LABEL, FALSE);
GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), &rc2);
MoveControls(hDlg, ctrlNoDomain, ARRAYSIZE(ctrlNoDomain), 0, -(rc2.bottom-rc.bottom), TRUE);
pGlobals->ShowDomainBox = FALSE; } else { SetDlgItemText(hDlg, IDD_UNLOCK_NAME, pGlobals->UserName);
pGlobals->ShowDomainBox = TRUE;
// Stop filtering SC events so SC unlock works
pWlxFuncs->WlxSetOption( pGlobals->hGlobalWlx, WLX_OPTION_USE_SMART_CARD, 1, NULL ); }
//
// Get trusted domain list and select appropriate domain
//
if ( !DCacheValidateCache( pGlobals->Cache ) ) { ASSERT( pGlobals->ActiveArray == NULL );
DCacheUpdateMinimal( pGlobals->Cache, pGlobals->Domain, TRUE );
}
pGlobals->ActiveArray = DCacheCopyCacheArray( pGlobals->Cache );
if ( pGlobals->ActiveArray ) { DCachePopulateListBoxFromArray( pGlobals->ActiveArray, GetDlgItem( hDlg, IDD_UNLOCK_DOMAIN ), pGlobals->Domain ); } else { EndDialog( hDlg, MSGINA_DLG_FAILURE ); }
#if 0
//
// Ensure that the domain the user logged on with is always in the
// combo-box so even if the Lsa is in a bad way the user will always
// be able to unlock the workstation. Don't do this if the user is logged
// in locally or else we'll get TWO local machines in the list
//
cchComputer = ARRAYSIZE(szComputer); szComputer[0] = 0; GetComputerName(szComputer, &cchComputer);
if ( pGlobals->Domain[0] && (0 != lstrcmpi(szComputer, pGlobals->Domain))) { HWND hwndDomain = GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN); if (SendMessage(hwndDomain, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pGlobals->Domain) == CB_ERR) { DebugLog((DEB_ERROR, "Domain combo-box doesn't contain logged on domain, adding it manually for unlock\n")); SendMessage(hwndDomain, CB_ADDSTRING, 0, (LPARAM)pGlobals->Domain); } } #endif
//
// If we are not part fo the domain then lets rip out the domain field,
// and if we do that lets remove the options button.
//
if ( !IsMachineDomainMember() ) { //
// If we're not part of a domain, make sure to hide the domain field
//
GetWindowRect(GetDlgItem(hDlg, IDCANCEL), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_OPTIONS), &rc2);
MoveControls(hDlg, ctrlNoOptions, sizeof(ctrlNoOptions)/sizeof(ctrlNoOptions[0]), rc2.right-rc.right, 0, FALSE);
ShowDlgItem(hDlg, IDD_UNLOCK_DOMAIN_LABEL, FALSE); ShowDlgItem(hDlg, IDD_UNLOCK_DOMAIN, FALSE); ShowDlgItem(hDlg, IDD_UNLOCK_OPTIONS, FALSE); }
// remove the cancel button if no C-A-D required
// NOTE: if we are going to the PIN dialog we always need a cancel button
if ((GetDisableCad(pGlobals)) && (SasType != WLX_SAS_TYPE_SC_INSERT)) EnableDlgItem(hDlg, IDCANCEL, FALSE);
// Position window on screen
CentreWindow(hDlg);
// Hide the options pane
pGlobals->UnlockOptionsShown = TRUE; UnlockShowOptions(pGlobals, hDlg, FALSE);
return TRUE; }
VOID DisplaySmartCardUnlockErrMessage( PGLOBALS pGlobals, HWND hDlg, DWORD dwErrorType, NTSTATUS Status, INT_PTR *pResult) { int i; UINT Resource = 0; TCHAR Buffer1[MAX_STRING_BYTES]; TCHAR Buffer2[MAX_STRING_BYTES]; BOOL fStringFound = FALSE;
if ( dwErrorType == 1 ) { *pResult = TimeoutMessageBox(hDlg, pGlobals, IDS_FORCE_LOGOFF_WARNING, IDS_WINDOWS_MESSAGE, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2, TIMEOUT_CURRENT);
return; } //
// At this point we need to display an error message, and the just
// relinquish control back to the unlock dialog thread
//
for ( i = 0 ; i < sizeof( UnlockMessages ) / sizeof( UNLOCK_MESSAGE ) ; i++ ) { if ( UnlockMessages[i].Status == Status ) { if (Status == STATUS_LOGON_FAILURE) { Resource = IDS_UNLOCK_FAILED_BAD_PIN ; } else { Resource = UnlockMessages[i].Resource ; } break; } }
if ( Resource != 0 ) { if( Resource == IDS_LOGON_NO_DOMAIN ) { // Need to build the domain name into the string.
LoadString(hDllInstance, Resource, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain); } else { LoadString(hDllInstance, Resource, Buffer2, MAX_STRING_BYTES); }
fStringFound = TRUE; }
if ( !fStringFound ) { //
// They're not the logged on user and they're not an admin.
// Tell them they failed to unlock the workstation.
//
if ( lstrlen(pGlobals->UserFullName) == 0 ) { if ( pGlobals->Domain[0] == L'\0' ) { LoadString(hDllInstance, IDS_UNLOCK_FAILED_EMAIL_NFN, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName );
} else { LoadString(hDllInstance, IDS_UNLOCK_FAILED_NFN, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName ); }
} else { if ( pGlobals->Domain[0] == L'\0' ) { LoadString(hDllInstance, IDS_UNLOCK_FAILED_EMAIL, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName, pGlobals->UserFullName );
} else { LoadString(hDllInstance, IDS_UNLOCK_FAILED, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName, pGlobals->UserFullName ); } } }
LoadString(hDllInstance, IDS_WORKSTATION_LOCKED, Buffer1, MAX_STRING_BYTES);
*pResult = TimeoutMessageBoxlpstr( hDlg, pGlobals, Buffer2, Buffer1, MB_OK | MB_ICONSTOP, TIMEOUT_CURRENT); }
//+---------------------------------------------------------------------------
//
// Function: SmartCardUnlockLogonThread
//
// Synopsis: Does the logon call in an async thread so that a pulsing bar
// can be shown in the UI.
//
// Arguments: [pData] --
//
// History:
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD WINAPI SmartCardUnlockLogonThread( PASYNC_UNLOCK_DATA pData) { INT_PTR Result; BOOL IsLoggedOnUser; BOOL IsAdmin; NTSTATUS Status; BOOL Unlocked; PGLOBALS pGlobals = pData->pGlobals; //
// Kick off the call to the LSA
//
Unlocked = UnlockLogon( pData->pGlobals, TRUE, pData->UserName.Buffer, pData->Domain.Buffer, &pData->Password, &Status, &IsAdmin, &IsLoggedOnUser, NULL, NULL );
//
// Logon thread is done running, so stop showing the pulsing bar
//
pData->pUnlockDlgState->fKillTimer = TRUE;
//
// Get rid of the PIN
//
RtlZeroMemory( pData->Password.Buffer, pData->Password.Length ); if ( Unlocked && IsLoggedOnUser ) { pGlobals->SmartCardLogon = TRUE;
//
// Logon succeeded, so tell the main thread that
//
PostMessage( pData->hDlg, WM_SMARTCARD_ASYNC_MESSAGE, MSGINA_DLG_SUCCESS, 0 );
goto Return; } else if ( Unlocked && IsAdmin) { //
// This is an admin trying to logon over another user, so send a message to the
// main dialog so it can ask the user if they would like to continue
//
pData->pUnlockDlgState->fUserBeingPrompted = TRUE; SendMessage( pData->hDlg, WM_SMARTCARD_ERROR_DISPLAY_1, Status, (LPARAM) &Result ); //
// If the smart card was removed while the user was being prompted, and
// the user elected not to logoff the current user, then just go back
// to the locked dialog
//
if ( (pData->pUnlockDlgState->fCardRemoved) && (Result != MSGINA_DLG_SUCCESS) ) { //
// Simulate the "card removed" SAS
//
pGlobals->LogonInProgress = FALSE; PostMessage( pData->hDlg, WLX_WM_SAS, WLX_SAS_TYPE_SC_REMOVE, (LPARAM) NULL ); } else { //
// Post the result of the prompt back to the main thread and then get out of this thread
//
PostMessage( pData->hDlg, WM_SMARTCARD_ASYNC_MESSAGE, (Result == MSGINA_DLG_SUCCESS) ? MSGINA_DLG_FORCE_LOGOFF : MSGINA_DLG_FAILURE, Result ); }
goto Return; } //
// At this point an error occurred, so ask the main thread to display an error message,
//
SendMessage( pData->hDlg, WM_SMARTCARD_ERROR_DISPLAY_2, Status, (LPARAM) &Result ); if (DLG_INTERRUPTED(Result)) { Result = SetInterruptFlag( MSGINA_DLG_FAILURE ) ; }
//
// Let the main thread know that this thread is exiting
//
PostMessage( pData->hDlg, WM_SMARTCARD_ASYNC_MESSAGE, MSGINA_DLG_FAILURE, Result );
Return:
pGlobals->LogonInProgress = FALSE;
LocalFree( pData );
return( 0 ); }
//+---------------------------------------------------------------------------
//
// Function: UnlockLogonThread
//
// Synopsis: Does the logon call in an async thread so that the user
// unlock is faster.
//
// Arguments: [pData] --
//
// History: 7-03-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD WINAPI UnlockLogonThread( PASYNC_UNLOCK_DATA pData) { BOOL Ignored ; NTSTATUS Status ; //
// Give everything a moment to switch back, restart, etc.
//
Sleep( 500 );
//
// Kick off the call to the LSA
//
UnlockLogon( pData->pGlobals, FALSE, pData->UserName.Buffer, pData->Domain.Buffer, &pData->Password, &Status, &Ignored, &Ignored, NULL, NULL );
//
// Get rid of the password, then free the parameters
//
RtlZeroMemory( pData->Password.Buffer, pData->Password.Length );
LocalFree( pData );
return( 0 );
}
//+---------------------------------------------------------------------------
//
// Function: UnlockLogonAsync
//
// Synopsis: Sets up the async thread so that
//
// Effects:
//
// Arguments: [pGlobals] --
// [UserName] --
// [Domain] --
// [PasswordString] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 7-03-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL UnlockLogonAsync( IN PGLOBALS pGlobals, IN PUNLOCK_DLG_STATE pUnlockDlgState, IN PWCHAR UserName, IN PWCHAR Domain, IN PUNICODE_STRING PasswordString, IN HWND hDlg, IN BOOL SmartCardUnlock ) { DWORD UserLength; DWORD DomainLength; PASYNC_UNLOCK_DATA pData; HANDLE Thread; DWORD Tid;
UserLength = (DWORD) wcslen( UserName ) * sizeof(WCHAR); DomainLength = (DWORD) wcslen( Domain ) * sizeof(WCHAR);
pData = LocalAlloc( LMEM_FIXED, sizeof( ASYNC_UNLOCK_DATA ) + UserLength + DomainLength + PasswordString->Length + 3 * sizeof(WCHAR) );
if ( !pData ) { return FALSE; }
pData->pGlobals = pGlobals; pData->hDlg = hDlg; pData->pUnlockDlgState = pUnlockDlgState; pData->UserName.Length = (WORD)UserLength; pData->UserName.MaximumLength = (WORD)(UserLength + sizeof(WCHAR)); pData->UserName.Buffer = (PWSTR) (pData + 1); CopyMemory( pData->UserName.Buffer, UserName, UserLength + sizeof(WCHAR) );
pData->Domain.Length = (WORD)DomainLength; pData->Domain.MaximumLength = (WORD)(DomainLength + sizeof(WCHAR)); pData->Domain.Buffer = pData->UserName.Buffer + (UserLength / 2) + 1; CopyMemory( pData->Domain.Buffer, Domain, DomainLength + sizeof(WCHAR) );
pData->Password.Length = PasswordString->Length; pData->Password.MaximumLength = PasswordString->Length + sizeof(WCHAR) ; pData->Password.Buffer = pData->Domain.Buffer + (DomainLength / 2) + 1; CopyMemory( pData->Password.Buffer, PasswordString->Buffer, PasswordString->Length + 2);
Thread = CreateThread( NULL, 0, SmartCardUnlock ? SmartCardUnlockLogonThread: UnlockLogonThread, pData, 0, &Tid );
if ( Thread ) { CloseHandle( Thread );
} else { ZeroMemory( pData->Password.Buffer, pData->Password.Length );
LocalFree( pData );
return ( FALSE ); }
return ( TRUE ); }
/***************************************************************************\
* FUNCTION: AttemptUnlock * * PURPOSE: Tries to unlock the workstation using the current values in the * unlock dialog controls * * RETURNS: * DLG_SUCCESS - the user unlocked the workstation successfully. * DLG_FAILURE - the user failed to unlock the workstation. * DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h) * * HISTORY: * * 12-09-91 Davidc Created. * \***************************************************************************/
INT_PTR AttemptUnlock( HWND hDlg, PGLOBALS pGlobals, PUNLOCK_DLG_STATE pUnlockDlgState) { TCHAR UserName[MAX_STRING_BYTES]; TCHAR Domain[MAX_STRING_BYTES]; TCHAR Password[MAX_STRING_BYTES]; UCHAR PasswordHash[ PASSWORD_HASH_SIZE ]; BOOL Unlocked; BOOL DifferentAccount; INT_PTR Result; UNICODE_STRING PasswordString; TCHAR Buffer1[MAX_STRING_BYTES]; TCHAR Buffer2[MAX_STRING_BYTES]; UCHAR IgnoreSeed; DWORD StringSize; BOOL SmartCardUnlock ; BOOL IsAdmin = FALSE; BOOL IsLoggedOnUser ; BOOL AlreadyLogged ; BOOL NewPassword ; NTSTATUS Status = STATUS_SUCCESS ; HWND hwndDomain = GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN); INT iDomainSelection; PDOMAIN_CACHE_ENTRY Entry ; BOOL PasswordExpiryWarning; PVOID ProfileBuffer; ULONG ProfileBufferLength; BOOL fStringFound = FALSE; RECT rc;
UserName[0] = TEXT('\0'); Domain[0] = TEXT('\0'); Password[0] = TEXT('\0'); Buffer1[0] = TEXT('\0'); Buffer2[0] = TEXT('\0');
//
// We need to do some things differently when a smart card is used. The way to
// tell is find out if the username field is active.
//
AlreadyLogged = FALSE ; NewPassword = FALSE ; Unlocked = FALSE;
if ( !IsWindowEnabled( GetDlgItem( hDlg, IDD_UNLOCK_NAME ) ) ) { SmartCardUnlock = TRUE ;
DifferentAccount = TRUE ; } else { SmartCardUnlock = FALSE ;
StringSize = GetDlgItemText(hDlg, IDD_UNLOCK_NAME, UserName, MAX_STRING_BYTES); if (StringSize == MAX_STRING_BYTES) { UserName[MAX_STRING_BYTES-1] = TEXT('\0'); }
//
// check to see if this is the fancy "my computer" entry or the somewhat less fancy
// "use the UPN" entry
//
iDomainSelection = (INT)SendMessage(hwndDomain, CB_GETCURSEL, 0, 0); Entry = (PDOMAIN_CACHE_ENTRY) SendMessage(hwndDomain, CB_GETITEMDATA, (WPARAM)iDomainSelection, 0);
if ( Entry == (PDOMAIN_CACHE_ENTRY) CB_ERR ) { //
// Our list is hosed in some way.
//
GetDlgItemText( hDlg, IDD_UNLOCK_DOMAIN, Domain, MAX_STRING_BYTES ); } else { wcscpy( Domain, Entry->FlatName.Buffer ); }
// If we are forcing a NoDomainUI, populate the domain with the local machine name now
if (ForceNoDomainUI()) { DWORD chSize = ARRAYSIZE(Domain); if (!GetComputerName(Domain, &chSize)) { *Domain = 0; } }
if ( wcschr( UserName, TEXT('@') ) ) { Domain[0] = TEXT('\0'); }
DifferentAccount = (lstrcmpi(UserName, pGlobals->UserName)) || (lstrcmpi(Domain, pGlobals->Domain)) ; }
StringSize = GetDlgItemText(hDlg, IDD_UNLOCK_PASSWORD, Password, MAX_STRING_BYTES); if (StringSize == MAX_STRING_BYTES) { Password[MAX_STRING_BYTES-1] = TEXT('\0'); }
RtlInitUnicodeString( &PasswordString, Password ); HashPassword(&PasswordString, PasswordHash );
//
// Check if this is the logged-on user. Do it through the security package
// if this was a smart card logon to begin with, if this is a smart card unlock,
// or if we're supposed to under all circumstances.
//
//
// Also check if password expiry warning will appear after unklocking. If so, then
// for a hit to the DC to update our profile info to make sure the user didn't
// already change their password on another machine.
//
PasswordExpiryWarning = ShouldPasswordExpiryWarningBeShown(pGlobals, FALSE, NULL);
if ( ( PasswordExpiryWarning ) || ( pGlobals->UnlockBehavior & UNLOCK_FORCE_AUTHENTICATION ) || ( SmartCardUnlock ) || ( pGlobals->SmartCardLogon ) || ( DifferentAccount ) ) { //
// Init profile buffer
//
ProfileBuffer = NULL;
AlreadyLogged = TRUE ;
if ( SmartCardUnlock ) { //
// Use the LogonInProgress bool to signal the fact that SmartCardAsyncUnlock
// is in progress
//
pGlobals->LogonInProgress = TRUE;
GetClientRect( hDlg, &rc ); pGlobals->cxBand = rc.right-rc.left; pUnlockDlgState->fKillTimer = FALSE; pUnlockDlgState->fUserBeingPrompted = FALSE; pUnlockDlgState->fCardRemoved = FALSE;
SetTimer(hDlg, 0, 20, NULL);
// Set timeout to infinite while attempting to logon
pWlxFuncs->WlxSetTimeout( pGlobals->hGlobalWlx, TIMEOUT_NONE ); //
// Kick off the thread to do the unlock
//
if (UnlockLogonAsync( pGlobals, pUnlockDlgState, UserName, Domain, &PasswordString, hDlg, TRUE )) { HidePassword( &IgnoreSeed, &PasswordString ); return ( MSGINA_DLG_ASYNC_PROCESSING ); } else { //Status = STATUS_E_FAIL; // SET THIS TO SOMETHING REASONABLE
goto AsyncUnlockError; } } Unlocked = UnlockLogon( pGlobals, SmartCardUnlock, UserName, Domain, &PasswordString, &Status, &IsAdmin, &IsLoggedOnUser, &ProfileBuffer, &ProfileBufferLength );
// Special handling for failed unlock 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 unlocks using
// the "display name".
if ((Status == STATUS_LOGON_FAILURE) && (IsOS(OS_PERSONAL) || IsOS(OS_PROFESSIONAL)) && !IsMachineDomainMember()) // using our version to optimize caching
{ if (ReplacedPossibleDisplayName(UserName)) { DifferentAccount = (lstrcmpi(UserName, pGlobals->UserName)) || (lstrcmpi(Domain, pGlobals->Domain)) ; Unlocked = UnlockLogon( pGlobals, SmartCardUnlock, UserName, Domain, &PasswordString, &Status, &IsAdmin, &IsLoggedOnUser, &ProfileBuffer, &ProfileBufferLength ); } }
//
// If this unlocked, and is the logged on user,
// then check to see if we should update all the in-memory passwords
//
if ( ( Unlocked ) && ( IsLoggedOnUser ) ) { //
// Could be a password update. Check:
//
if (RtlEqualMemory( PasswordHash, pGlobals->PasswordHash, PASSWORD_HASH_SIZE ) == FALSE ) {
// RevealPassword( &pGlobals->PasswordString );
UpdateWithChangedPassword( pGlobals, hDlg, TRUE, UserName, Domain, L"", Password, (PMSV1_0_INTERACTIVE_PROFILE)ProfileBuffer );
//
// Do not hide! Update will rehide the global copy of the password.
//
} }
//
// Free profile buffer
//
if ( ProfileBuffer ) { LsaFreeReturnBuffer(ProfileBuffer); }
if ( Unlocked ) { DifferentAccount = !IsLoggedOnUser ; } }
//
// Used to be just "else" here, ie:
// !PasswordExpiryWarning &&
// !( pGlobals->UnlockBehavior & UNLOCK_FORCE_AUTHENTICATION ) &&
// !SmartCardUnlock && !pGlobals->SmartCardLogon
// !DifferentAccount
// but that's not enough if the user ignored all expiry warnings to date
// and his password expired while locked (#404780)
//
// So the new logic is:
// If we didn't enter the previous block (tested by means of AlreadyLogged) or
// we entered it but it failed (and cached unlock is allowed and we didn't
// previously unlocked/logged on with a SC)
//
if ( ( AlreadyLogged == FALSE ) || ( ( Unlocked == FALSE ) && !( pGlobals->UnlockBehavior & UNLOCK_FORCE_AUTHENTICATION ) && !( pGlobals->SmartCardLogon ) ) ) { //
// un-hide the original password text so that we can
// do the compare.
//
// WARNING: We originally tried doing this comparison
// with old and new passwords hidden. This is
// not a good idea because the hide routine
// will allow matches that shouldn't match.
//
// RevealPassword( &pGlobals->PasswordString );
Unlocked = ( (lstrcmp(Domain, pGlobals->Domain) == 0) && (lstrcmpi(UserName, pGlobals->UserName) == 0) && (RtlEqualMemory( PasswordHash, pGlobals->PasswordHash, PASSWORD_HASH_SIZE ) == TRUE ) );
//
// re-hide the original password - use the same seed
//
// HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
if ( ( !Unlocked ) && ( AlreadyLogged == FALSE ) ) // We already tried UnlockLogon otherwise
{ //
// The password doesn't match what we have cached. User
// could have changed the password from another machine.
// Let's do the logon, and it if works, we update everything.
//
//
// Init profile buffer
//
ProfileBuffer = NULL;
AlreadyLogged = TRUE ;
Unlocked = UnlockLogon( pGlobals, FALSE, UserName, Domain, &PasswordString, &Status, &IsAdmin, &IsLoggedOnUser, &ProfileBuffer, &ProfileBufferLength );
if ( ( Unlocked ) && ( IsLoggedOnUser ) ) { //
// This logon worked. Must be a new password.
//
// RevealPassword( &pGlobals->PasswordString );
UpdateWithChangedPassword( pGlobals, hDlg, TRUE, UserName, Domain, L"", Password, (PMSV1_0_INTERACTIVE_PROFILE)ProfileBuffer );
//
// Do not hide! Update will rehide the global copy of the password.
//
}
//
// Free profile buffer
//
if ( ProfileBuffer ) { LsaFreeReturnBuffer(ProfileBuffer); }
if ( Unlocked ) { DifferentAccount = !IsLoggedOnUser ; } } }
if (Unlocked && !DifferentAccount ) {
if ( (!AlreadyLogged) && ( ( pGlobals->UnlockBehavior & UNLOCK_NO_NETWORK) == 0 ) ) { UnlockLogonAsync( pGlobals, NULL, UserName, Domain, &PasswordString, NULL, FALSE ); }
//
// Hide the new password to prevent it being paged cleartext.
//
HidePassword( &IgnoreSeed, &PasswordString );
pGlobals->SmartCardLogon = SmartCardUnlock;
return(MSGINA_DLG_SUCCESS); }
//
// Check for an admin logon and force the user off
//
if ( DifferentAccount ) { if ( !AlreadyLogged ) { // PJM... Unreachable.
IsAdmin = TestUserForAdmin( pGlobals, UserName, Domain, &PasswordString ); }
if ( IsAdmin ) {
//
// Hide the new password to prevent it being paged cleartext.
//
HidePassword( &IgnoreSeed, &PasswordString );
Result = TimeoutMessageBox(hDlg, pGlobals, IDS_FORCE_LOGOFF_WARNING, IDS_WINDOWS_MESSAGE, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2, TIMEOUT_CURRENT); if (Result == MSGINA_DLG_SUCCESS) {
return(MSGINA_DLG_FORCE_LOGOFF); }
return(Result); } } else {
//
// Cheap way to force a logon attempt, and hit the lockout yada yada
//
if ( !AlreadyLogged ) { // PJM... Unreachable.
UnlockLogon( pGlobals, SmartCardUnlock, UserName, Domain, &PasswordString, &Status, &IsAdmin, &IsLoggedOnUser, NULL, NULL );
}
}
AsyncUnlockError: //
// Hide the password to prevent it being paged cleartext.
//
HidePassword( &IgnoreSeed, &PasswordString );
if ( !DifferentAccount ) { int i ; UINT Resource = 0 ;
for ( i = 0 ; i < sizeof( UnlockMessages ) / sizeof( UNLOCK_MESSAGE ) ; i++ ) { if ( UnlockMessages[i].Status == Status ) { Resource = UnlockMessages[i].Resource ; break; } }
if ( Resource == 0 ) { Resource = IDS_UNLOCK_FAILED_BAD_PWD ; }
if(Resource == IDS_LOGON_NO_DOMAIN) { // Need to build the domain name into the string.
LoadString(hDllInstance, Resource, Buffer1, MAX_STRING_BYTES); _snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain); } else { LoadString(hDllInstance, Resource, Buffer2, MAX_STRING_BYTES); } fStringFound = TRUE; } else { //
// They're not the logged on user and they're not an admin.
// Tell them they failed to unlock the workstation.
//
if ( lstrlen(pGlobals->UserFullName) == 0 ) {
//
// No full name.
//
if ( pGlobals->Domain[0] == L'\0' ) { //
// UPN logon:
//
LoadString(hDllInstance, IDS_UNLOCK_FAILED_EMAIL_NFN, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName );
} else { LoadString(hDllInstance, IDS_UNLOCK_FAILED_NFN, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName );
}
} else {
if ( pGlobals->Domain[0] == L'\0' ) { //
// UPN Logon:
//
LoadString(hDllInstance, IDS_UNLOCK_FAILED_EMAIL, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->UserName, pGlobals->UserFullName );
} else {
LoadString(hDllInstance, IDS_UNLOCK_FAILED, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain, pGlobals->UserName, pGlobals->UserFullName ); } } }
LoadString(hDllInstance, IDS_WORKSTATION_LOCKED, Buffer1, MAX_STRING_BYTES);
Result = TimeoutMessageBoxlpstr(hDlg, pGlobals, Buffer2, Buffer1, MB_OK | MB_ICONSTOP, TIMEOUT_CURRENT); if (DLG_INTERRUPTED(Result)) { return( SetInterruptFlag( MSGINA_DLG_FAILURE ) ); }
return(MSGINA_DLG_FAILURE); }
/****************************************************************************\
* * FUNCTION: UnlockShowOptions * * PURPOSE: Hide the options part of the unlock dialog * * RETURNS: Nothing * * HISTORY: * * 15-dec-97 daviddv - Created * \****************************************************************************/
VOID UnlockShowOptions(PGLOBALS pGlobals, HWND hDlg, BOOL fShow) { RECT rc, rc2; INT dy; TCHAR szBuffer[32];
if ( pGlobals->UnlockOptionsShown != fShow ) { //
// Show hide optional fields in the dialog
//
if (pGlobals->ShowDomainBox) { GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_PASSWORD), &rc); GetWindowRect(GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), &rc2); dy = rc2.bottom-rc.bottom;
MoveControls(hDlg, ctrlNoDomain, sizeof(ctrlNoDomain)/sizeof(ctrlNoDomain[0]), 0, fShow ? dy:-dy, TRUE);
ShowDlgItem(hDlg, IDD_UNLOCK_DOMAIN_LABEL, fShow); ShowDlgItem(hDlg, IDD_UNLOCK_DOMAIN, fShow); }
ShowDlgItem(hDlg, IDD_KBLAYOUT_ICON, fShow); //
// 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_UNLOCK_OPTIONS, szBuffer); }
pGlobals->UnlockOptionsShown = fShow;
// Enable or disable the domain box depending on whether a UPN name has been typed
EnableDomainForUPN(GetDlgItem(hDlg, IDD_UNLOCK_NAME), GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN)); }
|