2363 lines
69 KiB
C
2363 lines
69 KiB
C
//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));
|
|
}
|
|
|