Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

842 lines
21 KiB

//+---------------------------------------------------------------------------
//
// 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>
//
// Define the structure used to pass data into the lock dialogs
//
typedef struct {
PGLOBALS pGlobals;
TIME LockTime;
} LOCK_DATA;
typedef LOCK_DATA *PLOCK_DATA;
typedef struct _ASYNC_UNLOCK_DATA {
PGLOBALS pGlobals;
UNICODE_STRING UserName;
UNICODE_STRING Domain;
UNICODE_STRING Password;
DWORD Reserved;
} ASYNC_UNLOCK_DATA, * PASYNC_UNLOCK_DATA;
//
// Private prototypes
//
BOOL LockedDlgInit(HWND, PGLOBALS);
BOOL UnlockDlgInit(HWND, PGLOBALS);
DLG_RETURN_TYPE AttemptUnlock(HWND, PGLOBALS);
BOOL WINAPI LogoffWaitDlgProc(HWND, UINT, DWORD, LONG);
HICON hLockedIcon = NULL;
HICON hUnlockIcon = NULL;
HWND
CreateBitmapControl(
HWND hDlg,
DWORD ControlId,
LPCTSTR ResourceId)
{
RECT rect;
HWND hFrame;
HWND hAni;
hFrame = GetDlgItem( hDlg, ControlId );
GetClientRect( hFrame, &rect );
MapWindowPoints( hFrame, hDlg, (LPPOINT) &rect, 1 );
hAni = CreateWindowEx(0,
TEXT("Static"),
NULL,
SS_BITMAP |
SS_CENTERIMAGE |
WS_VISIBLE |
WS_CHILD,
rect.left, rect.top,
rect.right, rect.bottom,
hDlg,
(HMENU) 1799,
hDllInstance,
NULL );
if (hAni)
{
SendMessage( hAni,
STM_SETIMAGE,
IMAGE_BITMAP,
(LPARAM) LoadImage( hDllInstance, ResourceId,
IMAGE_BITMAP, 0, 0,
LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS ) );
}
else
{
DebugLog((DEB_ERROR, "Couldn't create bitmap control, %d\n", GetLastError() ));
}
return( hAni );
}
SetLockedInfo(
PGLOBALS pGlobals,
HWND hDlg,
UINT ControlId)
{
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
//
// Set the locked message
//
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.
*
\***************************************************************************/
BOOL
CALLBACK
LockedDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS) GetWindowLong( hDlg, GWL_USERDATA);
HBITMAP hbm;
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, lParam);
pGlobals = (PGLOBALS) lParam ;
if (!LockedDlgInit(hDlg, pGlobals)) {
EndDialog(hDlg, DLG_FAILURE);
}
return(TRUE);
case WLX_WM_SAS:
EndDialog(hDlg, MSGINA_DLG_SUCCESS);
return(TRUE);
case WM_CLOSE:
hbm = (HBITMAP) SendMessage( GetDlgItem( hDlg, IDD_LOCKED_FRAME ),
STM_GETIMAGE,
IMAGE_BITMAP,
0 );
if (hbm)
{
DeleteObject( hbm );
}
break;
}
// 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
)
{
HBITMAP hbm;
SetWelcomeCaption( hDlg );
SetLockedInfo( pGlobals, hDlg, IDD_LOCKED_NAME_INFO );
SetupSystemMenu(hDlg);
CentreWindow(hDlg);
if ( !hLockedIcon )
{
hLockedIcon = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_LOCKED_ICON ),
IMAGE_ICON,
64, 64,
LR_DEFAULTCOLOR );
}
SendMessage( GetDlgItem( hDlg, IDD_LOCKED_FRAME),
STM_SETICON,
(WPARAM) hLockedIcon,
0 );
return TRUE;
}
VOID
WINAPI
WlxDisplayLockedNotice(PVOID pWlxContext)
{
int Result;
NTSTATUS Status;
PGLOBALS pGlobals;
pGlobals = (PGLOBALS) pWlxContext;
Status = NtQuerySystemTime(&pGlobals->LockTime);
if (!NT_SUCCESS(Status))
{
WLPrint(("LockWorkstation - failed to get system time"));
return;
}
pWlxFuncs->WlxSetTimeout(hGlobalWlx, 120);
Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx,
hDllInstance,
(LPWSTR) MAKEINTRESOURCE(IDD_LOCKED_DIALOG),
NULL,
LockedDlgProc,
(LONG) pGlobals );
}
int
WINAPI
WlxWkstaLockedSAS(
PVOID pWlxContext,
DWORD dwSasType
)
{
PGLOBALS pGlobals;
DWORD Result;
pGlobals = (PGLOBALS) pWlxContext;
Result = pWlxFuncs->WlxDialogBoxParam(
hGlobalWlx,
hDllInstance,
MAKEINTRESOURCE(IDD_UNLOCK_DIALOG),
NULL,
(DLGPROC) UnlockDlgProc,
(LONG) pGlobals);
switch (Result)
{
case MSGINA_DLG_SUCCESS:
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 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);
}
return(0);
}
/***************************************************************************\
* 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.
*
\***************************************************************************/
BOOL
CALLBACK
UnlockDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS) GetWindowLong(hDlg, GWL_USERDATA);
DLG_RETURN_TYPE Result;
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, lParam);
if (!UnlockDlgInit(hDlg, (PGLOBALS) lParam))
{
EndDialog(hDlg, DLG_FAILURE);
}
return(SetPasswordFocus(hDlg));
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
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);
//
// 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);
return TRUE;
}
break;
case WLX_WM_SAS:
// Ignore it
if ( wParam == WLX_SAS_TYPE_CTRL_ALT_DEL )
{
return( TRUE );
}
return( FALSE );
case WM_CLOSE:
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.
*
\***************************************************************************/
BOOL
UnlockDlgInit(
HWND hDlg,
PGLOBALS pGlobals
)
{
DLG_RETURN_TYPE Result;
HBITMAP hbm;
BOOL Success;
SetWelcomeCaption( hDlg );
SetLockedInfo( pGlobals, hDlg, IDD_UNLOCK_NAME_INFO );
if ( !hUnlockIcon )
{
hUnlockIcon = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_UNLOCK_ICON ),
IMAGE_ICON,
64, 72,
LR_DEFAULTCOLOR );
}
SendMessage( GetDlgItem( hDlg, IDD_UNLOCK_FRAME),
STM_SETICON,
(WPARAM) hUnlockIcon,
0 );
//
// Fill in the username
//
SetDlgItemText(hDlg, IDD_UNLOCK_NAME, pGlobals->UserName);
//
// Get trusted domain list and select appropriate domain
//
Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_UNLOCK_DOMAIN, pGlobals->Domain, TRUE);
if (DLG_INTERRUPTED(Result)) {
EndDialog(hDlg, Result);
}
//
// 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.
//
if (SendMessage(GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), CB_FINDSTRINGEXACT,
(WPARAM)-1, (LONG)pGlobals->Domain) == CB_ERR) {
DebugLog((DEB_ERROR, "Domain combo-box doesn't contain logged on domain, adding it manually for unlock\n"));
SendMessage(GetDlgItem(hDlg, IDD_UNLOCK_DOMAIN), CB_ADDSTRING,
0, (LONG)pGlobals->Domain);
}
if (!GetPrimaryDomain( NULL, NULL ))
{
//
// If we're not part of a domain, make sure to hide the domain field
//
ShowWindow( GetDlgItem( hDlg, IDD_UNLOCK_DOMAIN ), SW_HIDE );
ShowWindow( GetDlgItem( hDlg, IDD_UNLOCK_DOMAIN_LABEL ), SW_HIDE );
}
//
// Position window on screen
//
CentreWindow(hDlg);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// 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)
{
//
// Give everything a moment to switch back, restart, etc.
//
Sleep( 500 );
//
// Kick off the call to the LSA
//
UnlockLogon(
pData->pGlobals,
pData->UserName.Buffer,
pData->Domain.Buffer,
&pData->Password );
//
// 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:
//
//----------------------------------------------------------------------------
VOID
UnlockLogonAsync(
PGLOBALS pGlobals,
IN PWCHAR UserName,
IN PWCHAR Domain,
IN PUNICODE_STRING PasswordString
)
{
DWORD UserLength;
DWORD DomainLength;
PASYNC_UNLOCK_DATA pData;
HANDLE Thread;
DWORD Tid;
UserLength = wcslen( UserName ) * sizeof(WCHAR);
DomainLength = wcslen( Domain ) * sizeof(WCHAR);
pData = LocalAlloc( LMEM_FIXED, sizeof( ASYNC_UNLOCK_DATA ) +
UserLength + DomainLength +
PasswordString->Length + 3 * sizeof(WCHAR) );
if ( !pData )
{
return;
}
pData->pGlobals = pGlobals;
pData->UserName.Length = UserLength;
pData->UserName.MaximumLength = UserLength + sizeof(WCHAR);
pData->UserName.Buffer = (PWSTR) (pData + 1);
CopyMemory( pData->UserName.Buffer, UserName, UserLength + sizeof(WCHAR) );
pData->Domain.Length = DomainLength;
pData->Domain.MaximumLength = 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,
UnlockLogonThread, pData,
0, &Tid );
if ( Thread )
{
CloseHandle( Thread );
}
else
{
ZeroMemory( pData->Password.Buffer, pData->Password.Length );
LocalFree( pData );
}
}
/***************************************************************************\
* 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.
*
\***************************************************************************/
DLG_RETURN_TYPE
AttemptUnlock(
HWND hDlg,
PGLOBALS pGlobals)
{
TCHAR UserName[MAX_STRING_BYTES];
TCHAR Domain[MAX_STRING_BYTES];
TCHAR Password[MAX_STRING_BYTES];
BOOL Unlocked;
BOOL WrongPassword;
DLG_RETURN_TYPE Result;
UNICODE_STRING PasswordString;
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
UCHAR IgnoreSeed;
DWORD StringSize;
StringSize = GetDlgItemText(hDlg, IDD_UNLOCK_NAME, UserName, MAX_STRING_BYTES);
if (StringSize == MAX_STRING_BYTES)
{
UserName[MAX_STRING_BYTES-1] = TEXT('\0');
}
StringSize = GetDlgItemText(hDlg, IDD_UNLOCK_DOMAIN, Domain, MAX_STRING_BYTES);
if (StringSize == MAX_STRING_BYTES)
{
Domain[MAX_STRING_BYTES-1] = TEXT('\0');
}
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 );
//
// 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 );
//
// Check if this is the logged-on user
//
Unlocked = ( (lstrcmp(Password, pGlobals->Password) == 0) &&
(lstrcmpi(UserName, pGlobals->UserName) == 0) &&
(lstrcmp(Domain, pGlobals->Domain) == 0) );
//
// This may be needed later.
// It is easiest to do the compare now, while the password
// is in cleartext.
//
WrongPassword = ((wcscmp(Password, pGlobals->Password) != 0) &&
(_wcsicmp(UserName, pGlobals->UserName) == 0) &&
(wcscmp(Domain, pGlobals->Domain) == 0) );
//
// re-hide the original password - use the same seed
//
HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
if (Unlocked) {
UnlockLogonAsync( pGlobals, UserName, Domain, &PasswordString );
//
// Hide the new password to prevent it being paged cleartext.
//
HidePassword( &IgnoreSeed, &PasswordString );
//
// Need to do the unlock logon here.
//
return(MSGINA_DLG_SUCCESS);
}
//
// Check for an admin logon and force the user off
//
if (!WrongPassword)
{
if (TestUserForAdmin(pGlobals, UserName, Domain, &PasswordString)) {
//
// Hide the new password to prevent it being paged cleartext.
//
HidePassword( &IgnoreSeed, &PasswordString );
Result = TimeoutMessageBox(hDlg,
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
//
TestUserForAdmin(pGlobals, UserName, Domain, &PasswordString);
}
if ( WrongPassword ) {
LoadString(hDllInstance, IDS_UNLOCK_FAILED_BAD_PWD, Buffer2, MAX_STRING_BYTES);
} 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.
//
LoadString(hDllInstance, IDS_UNLOCK_FAILED_NFN, Buffer1, MAX_STRING_BYTES);
_snwprintf(Buffer2, sizeof(Buffer2)/sizeof(TCHAR), Buffer1, pGlobals->Domain,
pGlobals->UserName
);
} 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, Buffer2, Buffer1,
MB_OK | MB_ICONSTOP,
TIMEOUT_CURRENT);
if (DLG_INTERRUPTED(Result)) {
return( SetInterruptFlag( MSGINA_DLG_FAILURE ) );
}
return(MSGINA_DLG_FAILURE);
}