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.
 
 
 
 
 
 

1746 lines
46 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: mslogon.c
//
// Contents: Microsoft Logon GUI DLL
//
// History: 7-14-94 RichardW Created
//
//----------------------------------------------------------------------------
#include "msgina.h"
#include <stdio.h>
#include <wchar.h>
//
// Constants for registry defaults for legal notices.
//
#define LEGAL_CAPTION_DEFAULT TEXT("")
#define LEGAL_TEXT_DEFAULT TEXT("")
//
// Number of seconds we will display the legal notices
// before timing out.
//
#define LEGAL_NOTICE_TIMEOUT 120
#define LOGON_SLEEP_PERIOD 750
#define WM_LOGONPROMPT WM_USER + 27
//
// Globals:
//
static WNDPROC OldCBWndProc;
HICON hSteadyFlag;
HICON hWavingFlag;
HICON hAuditFull;
//
// Prototypes:
//
int
DisplayLegalNotices(
PGLOBALS pGlobals
);
BOOL
GetLegalNotices(
LPTSTR *NoticeText,
LPTSTR *CaptionText
);
BOOL WINAPI
LogonDlgCBProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
BOOL WINAPI
LogonDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
BOOL
LogonDlgInit(
HWND hDlg
);
DLG_RETURN_TYPE
HandleFailedLogon(
HWND hDlg,
NTSTATUS Status,
NTSTATUS SubStatus,
PWCHAR UserName,
PWCHAR Domain
);
BOOL WINAPI
LogonHelpDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
BOOL WINAPI
LogonAuditHelpDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
);
VOID
ReportBootGood(
);
DLG_RETURN_TYPE
AttemptLogon(
HWND hDlg
);
DWORD
LogonThread(
PVOID p);
/***************************************************************************\
* FUNCTION: DisplayLegalNotices
*
* PURPOSE: Puts up a dialog box containing legal notices, if any.
*
* RETURNS: MSGINA_DLG_SUCCESS - the dialog was shown and dismissed successfully.
* MSGINA_DLG_FAILURE - the dialog could not be shown
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* HISTORY:
*
* Robertre 6-30-93 Created
*
\***************************************************************************/
int
DisplayLegalNotices(
PGLOBALS pGlobals
)
{
int Result = MSGINA_DLG_SUCCESS;
LPTSTR NoticeText;
LPTSTR CaptionText;
if (GetLegalNotices( &NoticeText, &CaptionText ))
{
Result = TimeoutMessageBoxlpstr( NULL,
NoticeText,
CaptionText,
MB_OK | MB_ICONEXCLAMATION,
LEGAL_NOTICE_TIMEOUT
);
Free( NoticeText );
Free( CaptionText );
}
return( Result );
}
/***************************************************************************\
* FUNCTION: GetLegalNotices
*
* PURPOSE: Get legal notice information out of the registry.
*
* RETURNS: TRUE - Output parameters contain valid data
* FALSE - No data returned.
*
* HISTORY:
*
* Robertre 6-30-93 Created
*
\***************************************************************************/
BOOL
GetLegalNotices(
LPTSTR *NoticeText,
LPTSTR *CaptionText
)
{
*CaptionText = AllocAndGetProfileString( APPLICATION_NAME,
LEGAL_NOTICE_CAPTION_KEY,
LEGAL_CAPTION_DEFAULT
);
*NoticeText = AllocAndGetProfileString( APPLICATION_NAME,
LEGAL_NOTICE_TEXT_KEY,
LEGAL_TEXT_DEFAULT
);
//
// There are several possiblities: either the strings aren't
// in the registry (in which case the above will return the
// passed default) or we failed trying to get them for some
// other reason (in which case the apis will have returned
// NULL).
//
// We want to put up the box if either string came back with
// something other than the default.
//
if (*CaptionText == NULL || *NoticeText == NULL) {
if (*CaptionText != NULL) {
Free(*CaptionText);
}
if (*NoticeText != NULL) {
Free(*NoticeText);
}
return( FALSE );
}
if ( (wcscmp(*CaptionText, LEGAL_CAPTION_DEFAULT) == 0) &&
(wcscmp(*NoticeText, LEGAL_TEXT_DEFAULT) == 0)) {
//
// Didn't get anything out of the registry.
//
Free(*CaptionText);
Free(*NoticeText);
return( FALSE );
}
return( TRUE );
}
/***************************************************************************\
* FUNCTION: LogonHelpDlgProc
*
* PURPOSE: Processes messages for logon help dialog
*
* RETURNS: DLG_SUCCESS - the dialog was shown and dismissed successfully.
* DLG_FAILURE - the dialog could not be shown
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* HISTORY:
*
* 12-15-92 Davidc Created.
*
\***************************************************************************/
BOOL WINAPI
LogonHelpDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, lParam);
CentreWindow(hDlg);
return(TRUE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hDlg, MSGINA_DLG_SUCCESS);
return(TRUE);
}
break;
}
// We didn't process this message
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: LogonAuditHelpDlgProc
//
// Synopsis: Handle the Help-during-audit-log-full dialog.
//
// Arguments: [hDlg] --
// [message] --
// [wParam] --
// [lParam] --
//
// History: 3-07-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL WINAPI
LogonAuditHelpDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, lParam);
CentreWindow(hDlg);
SendMessage( GetDlgItem( hDlg, IDD_AUDITHELP_ICON ),
STM_SETICON,
(WPARAM) hAuditFull,
0 );
return(TRUE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hDlg, IDOK );
return(TRUE);
case IDD_AUDITHELP_HELP:
EndDialog(hDlg, IDD_AUDITHELP_HELP );
return( TRUE );
}
break;
}
// We didn't process this message
return FALSE;
}
BOOL
WINAPI
SlowLogonDlgProc(
HWND hDlg,
UINT Message,
WPARAM wParam,
LPARAM lParam )
{
PGLOBALS pGlobals;
RECT myrect;
pGlobals = (PGLOBALS) GetWindowLong( hDlg, GWL_USERDATA );
switch ( Message )
{
case WM_INITDIALOG:
SetWindowLong( hDlg, GWL_USERDATA, lParam );
pGlobals = (PGLOBALS) lParam;
GetWindowRect( hDlg, &myrect );
SetWindowPos( hDlg,
HWND_TOPMOST,
pGlobals->OverlayPoint.left + 2,
pGlobals->OverlayPoint.top,
myrect.right - myrect.left,
myrect.bottom - myrect.top,
SWP_SHOWWINDOW );
pGlobals->hwndLogonInProgress = hDlg;
if ( !hWavingFlag )
{
hWavingFlag = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_WAVING_FLAG ),
IMAGE_ICON,
64, 64,
LR_DEFAULTCOLOR );
}
SendMessage( GetDlgItem( hDlg, IDD_PROGRESS_FRAME ),
STM_SETICON,
(WPARAM) hWavingFlag,
0 );
SetupCursor( TRUE );
RtlLeaveCriticalSection( &pGlobals->csGlobals );
SetForegroundWindow( hDlg );
return( TRUE );
case WM_LOGONPROMPT:
EndDialog( hDlg, 0 );
return( TRUE );
case WM_NCHITTEST:
return( TRUE );
case WM_LBUTTONDOWN:
SetCapture( hDlg );
return( TRUE );
case WM_LBUTTONUP:
ReleaseCapture();
return( TRUE );
case WM_MOUSEMOVE:
return( TRUE );
}
return( FALSE );
}
DWORD
SlowLogonThread(
PGLOBALS pGlobals)
{
DWORD SlowLogonWait;
int Result;
SlowLogonWait = LOGON_SLEEP_PERIOD;
Sleep( SlowLogonWait );
RtlEnterCriticalSection( &pGlobals->csGlobals );
if ( pGlobals->LogonInProgress )
{
//
// Start the dialog *with the critsec held* the Init case
// will free it.
//
Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx,
hDllInstance,
MAKEINTRESOURCE( IDD_PROGRESS_DIALOG ),
NULL,
SlowLogonDlgProc,
(LONG) pGlobals );
//
// If we failed, then assume we didn't successfully go through the
// initdialog case, and hence we still own the critsect.
//
if (Result < 0)
{
RtlLeaveCriticalSection( &pGlobals->csGlobals );
}
}
else
{
//
// Nope, main thread already done. Clean up and leave.
//
RtlLeaveCriticalSection( &pGlobals->csGlobals );
}
pGlobals->hwndLogonInProgress = NULL;
return( 0 );
}
int
Logon(
PGLOBALS pGlobals
)
{
int Result;
//
// Asynchronously update domain cache if necessary.
// We won't ask to wait so this routine will do no UI.
// i.e. we can ignore the result.
//
// Result = UpdateDomainCache(pGlobals, NULL, FALSE);
// ASSERT(!DLG_INTERRUPTED(Result));
//
// See if there are legal notices in the registry.
// If so, put them up in a message box
//
Result = DisplayLegalNotices( pGlobals );
if ( Result != MSGINA_DLG_SUCCESS ) {
return(WLX_SAS_ACTION_NONE);
}
//
// Get the latest audit log status and store in our globals
// If the audit log is full we show a different logon dialog.
//
GetAuditLogStatus(pGlobals);
//
// Take their username and password and try to log them on
//
pWlxFuncs->WlxSetTimeout(hGlobalWlx, LOGON_TIMEOUT);
Result = pWlxFuncs->WlxDialogBoxParam( hGlobalWlx,
hDllInstance,
(LPTSTR) IDD_LOGON_DIALOG,
NULL,
LogonDlgProc,
(LONG)pGlobals);
return(Result);
}
/***************************************************************************\
* FUNCTION: LogonDlgCBProc
*
* PURPOSE: Processes messages for Logon dialog combo box
*
* RETURNS: Return value depends on message being sent.
*
* HISTORY:
*
* 05-21-93 RobertRe Created.
*
\***************************************************************************/
BOOL WINAPI
LogonDlgCBProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
TCHAR KeyPressed;
// DbgPrint("message = %X\n",message);
switch (message) {
case WM_CHAR:
{
KeyPressed = (TCHAR) wParam;
SetWindowLong(hwnd, GWL_USERDATA, (LONG)KeyPressed);
//
// This fake CBN_SELCHANGE message will cause the
// "Please wait..." dialog box to appear even if
// the character pressed doesn't exist in the combobox yet.
//
PostMessage (GetParent(hwnd), WM_COMMAND,
MAKELONG(0, CBN_SELCHANGE), 0);
break;
}
}
return CallWindowProc(OldCBWndProc,hwnd,message,wParam,lParam);
}
/***************************************************************************\
* FUNCTION: LogonDlgProc
*
* PURPOSE: Processes messages for Logon dialog
*
* RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
* MSGINA_DLG_FAILURE - the logon failed,
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\***************************************************************************/
BOOL WINAPI
LogonDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
DLG_RETURN_TYPE Result;
HWND CBHandle;
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, (LPARAM)(pGlobals = (PGLOBALS)lParam));
//
// Subclass the domain list control so we can filter messages
//
CBHandle = GetDlgItem(hDlg,IDD_LOGON_DOMAIN);
SetWindowLong(CBHandle, GWL_USERDATA, 0);
OldCBWndProc = (WNDPROC)SetWindowLong(CBHandle, GWL_WNDPROC, (LONG)LogonDlgCBProc);
if (!LogonDlgInit(hDlg))
{
EndDialog(hDlg, MSGINA_DLG_FAILURE);
return(TRUE);
}
#ifdef AUTO_LOGON
//
// If not requesting auto logon or the shift key is held
// down, just return with the focus in the password field.
// Only look at the shift key if IgnoreShiftOverride is false (0).
//
if (GetProfileInt( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, 0 ) == 0 ||
((GetAsyncKeyState(VK_SHIFT) < 0) &&
(GetProfileInt( APPLICATION_NAME, IGNORE_SHIFT_OVERRIDE_KEY, 0 ) == 0))
)
#endif
return(SetPasswordFocus(hDlg));
#ifdef AUTO_LOGON
//
// Otherwise attempt to auto logon. If no default password
// specified, then this is a one shot attempt, which handles
// the case when auto logging on as Administrator.
//
{
TCHAR PasswordBuffer[ 32 ];
if (GetProfileString(APPLICATION_NAME, DEFAULT_PASSWORD_KEY, TEXT(""), PasswordBuffer, sizeof( PasswordBuffer )) != 0)
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, PasswordBuffer);
else
WriteProfileString( APPLICATION_NAME, AUTO_ADMIN_LOGON_KEY, TEXT("0") );
// Make sure domain list is valid before auto-logging in.
if (!pGlobals->DomainListComplete)
{
//
// Fill in the full domain list
//
LPTSTR String = AllocAndGetProfileString(
APPLICATION_NAME,
DEFAULT_DOMAIN_NAME_KEY, TEXT(""));
// Get trusted domain list and select appropriate default domain
Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_LOGON_DOMAIN,
String, TRUE);
Free(String);
if (DLG_INTERRUPTED(Result))
{
EndDialog(hDlg, Result);
}
pGlobals->DomainListComplete = TRUE;
}
// Drop through as if Enter had been pressed...
wParam = IDOK;
}
#endif
case WM_COMMAND:
switch (HIWORD(wParam))
{
case CBN_DROPDOWN:
case CBN_SELCHANGE:
DebugLog((DEB_TRACE, "Got CBN_DROPDOWN\n"));
if (!pGlobals->DomainListComplete)
{
//
// Fill in the full domain list
//
LPTSTR String = AllocAndGetProfileString(
APPLICATION_NAME,
DEFAULT_DOMAIN_NAME_KEY, TEXT(""));
pGlobals->DomainListComplete = TRUE;
// Get trusted domain list and select appropriate default domain
Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_LOGON_DOMAIN,
String, TRUE);
Free(String);
if (DLG_INTERRUPTED(Result))
{
EndDialog(hDlg, Result);
}
}
break;
default:
switch (LOWORD(wParam))
{
case IDOK:
//
// Deal with combo-box UI requirements
//
if (HandleComboBoxOK(hDlg, IDD_LOGON_DOMAIN))
{
return(TRUE);
}
Result = AttemptLogon( hDlg );
if (Result == MSGINA_DLG_FAILURE)
{
// Let the user try again
// Clear the password field and set focus to it
SetDlgItemText(hDlg, IDD_LOGON_PASSWORD, NULL);
SetPasswordFocus(hDlg);
return(TRUE);
}
EndDialog( hDlg, Result );
return(TRUE);
case IDCANCEL:
EndDialog(hDlg, MSGINA_DLG_FAILURE);
return(TRUE);
case IDD_LOGON_SHUTDOWN:
//
// This is a normal shutdown request
//
// Check they know what they're doing and find
// out if they want to reboot too.
//
Result = pWlxFuncs->WlxDialogBoxParam(
hGlobalWlx,
hDllInstance,
(LPTSTR)IDD_SHUTDOWN_QUERY,
hDlg,
ShutdownQueryDlgProc,
(LONG)pGlobals);
if (DLG_SHUTDOWN(Result))
{
EndDialog(hDlg, Result);
}
return(TRUE);
case IDD_LOGON_HELP_BUTTON:
if ( pGlobals->AuditLogFull )
{
Result = pWlxFuncs->WlxDialogBoxParam(
hGlobalWlx,
hDllInstance,
(LPTSTR)IDD_AUDITHELP_DIALOG,
hDlg,
LogonAuditHelpDlgProc,
(LONG)pGlobals);
}
else
{
Result = IDD_AUDITHELP_HELP;
}
if ( Result == IDD_AUDITHELP_HELP )
{
Result = pWlxFuncs->WlxDialogBoxParam(
hGlobalWlx,
hDllInstance,
(LPTSTR)IDD_LOGON_HELP,
hDlg,
LogonHelpDlgProc,
(LONG)pGlobals);
}
if (DLG_INTERRUPTED(Result))
{
EndDialog(hDlg, Result);
}
return(TRUE);
}
break;
}
break;
case WLX_WM_SAS:
if ((wParam == WLX_SAS_TYPE_TIMEOUT) ||
(wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) )
{
//
// If this was a timeout, return false, and let winlogon
// kill us later
//
return(FALSE);
}
return(TRUE);
}
return(FALSE);
}
/***************************************************************************\
* FUNCTION: LogonDlgInit
*
* PURPOSE: Handles initialization of logon dialog
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\***************************************************************************/
BOOL
LogonDlgInit(
HWND hDlg
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
DLG_RETURN_TYPE Result;
LPTSTR String;
BOOL bShutdownWithoutLogon = TRUE;
HICON hIcon;
TCHAR LogonMsg[MAX_PATH];
HKEY hKey;
int err;
DWORD RasDisable;
DWORD RasForce;
UNICODE_STRING s;
BOOL ShowRasBox;
// Centre the window on the screen and bring it to the front
CentreWindow(hDlg);
//
// Update the caption for certain banks
//
SetWelcomeCaption(hDlg);
if ( !hSteadyFlag )
{
hSteadyFlag = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_STEADY_FLAG ),
IMAGE_ICON,
64, 64,
LR_DEFAULTCOLOR );
}
SendMessage( GetDlgItem( hDlg, IDD_LOGON_ANI ),
STM_SETICON,
(WPARAM) hSteadyFlag,
0 );
//
// Get username and domain last used to login
//
String = AllocAndGetProfileString(APPLICATION_NAME,
DEFAULT_USER_NAME_KEY, TEXT(""));
if (String)
{
if (GetProfileInt( APPLICATION_NAME, DONT_DISPLAY_LAST_USER_KEY, 0 ) == 1)
{
String[0] = 0;
}
SetDlgItemText(hDlg, IDD_LOGON_NAME, String);
Free(String);
}
//
// Get trusted domain list and select appropriate default domain
//
String = AllocAndGetProfileString(APPLICATION_NAME,
DEFAULT_DOMAIN_NAME_KEY, TEXT(""));
if (String)
{
Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_LOGON_DOMAIN, String, FALSE);
Free(String);
}
else
{
Result = FillTrustedDomainCB(pGlobals, hDlg, IDD_LOGON_DOMAIN, TEXT(""), FALSE);
}
if (DLG_INTERRUPTED(Result)) {
EndDialog(hDlg, Result);
}
pGlobals->DomainListComplete = (Result == MSGINA_DLG_SUCCESS);
//
// if ShutdownWithoutLogon, use the proper 3 buttons: OK, Shutdown and Cancel
// instead of the 2 buttons OK and Cancel
//
bShutdownWithoutLogon = GetProfileInt(APPLICATION_NAME, SHUTDOWN_WITHOUT_LOGON_KEY, 1);
if (bShutdownWithoutLogon)
{
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_SHUTDOWN ), TRUE );
}
else
{
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_SHUTDOWN ), FALSE );
}
ShowRasBox = FALSE;
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
TEXT("Software\\Microsoft\\RAS"),
0,
KEY_READ,
& hKey );
if ( err == 0 )
{
RegCloseKey( hKey );
if ( GetRasDialOutProtocols() )
{
ShowRasBox = TRUE;
}
}
if ( ShowRasBox )
{
RasDisable = GetProfileInt( APPLICATION_NAME, RAS_DISABLE, 0 );
RasForce = GetProfileInt( APPLICATION_NAME, RAS_FORCE, 0 );
// pGlobals->RasForce = (BOOL) RasForce;
if (RasForce)
{
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 1 );
}
else
{
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
}
if (RasDisable || RasForce)
{
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX ), FALSE );
}
else
{
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX ), TRUE );
}
}
else
{
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX ), FALSE );
ShowWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX), SW_HIDE );
// pGlobals->RasForce = FALSE;
}
if ( pGlobals->AuditLogFull )
{
if ( !hAuditFull )
{
hAuditFull = LoadImage( hDllInstance,
MAKEINTRESOURCE( IDI_AUDIT_ICON ),
IMAGE_ICON,
64, 64,
LR_DEFAULTCOLOR );
}
LogonMsg[0] = TEXT('\0');
LoadString( hDllInstance, IDS_LOGON_LOG_FULL, LogonMsg, MAX_PATH );
SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, LogonMsg );
SendMessage( GetDlgItem( hDlg, IDD_LOGON_ANI ),
STM_SETICON,
(WPARAM) hAuditFull,
0 );
}
else
{
String = AllocAndGetProfileString( APPLICATION_NAME,
LOGON_MSG_KEY, TEXT("") );
if ( String )
{
if ( *String )
{
SetDlgItemText( hDlg, IDD_LOGON_ANNOUNCE, String );
}
Free( String );
}
}
if (!GetPrimaryDomain( NULL, NULL ))
{
//
// If we're not part of a domain, make sure to hide the domain field
//
ShowWindow( GetDlgItem( hDlg, IDD_LOGON_DOMAIN ), SW_HIDE );
ShowWindow( GetDlgItem( hDlg, IDD_LOGON_DOMAIN_LABEL ), SW_HIDE );
//
// And turn off RAS while we're at it.
//
CheckDlgButton( hDlg, IDD_LOGON_RASBOX, 0 );
EnableWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX ), FALSE );
ShowWindow( GetDlgItem( hDlg, IDD_LOGON_RASBOX), SW_HIDE );
}
// Success
return TRUE;
}
/***************************************************************************\
* FUNCTION: AttemptLogon
*
* PURPOSE: Tries to the log the user on using the current values in the
* logon dialog controls
*
* RETURNS: MSGINA_DLG_SUCCESS - the user was logged on successfully
* MSGINA_DLG_FAILURE - the logon failed,
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* NOTES: If the logon is successful, the global structure is filled in
* with the logon information.
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\***************************************************************************/
DLG_RETURN_TYPE
AttemptLogon(
HWND hDlg
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
PWCHAR UserName = pGlobals->UserName;
PWCHAR Domain = pGlobals->Domain;
PWCHAR Password = pGlobals->Password;
PTCHAR OldPassword = pGlobals->OldPassword;
UNICODE_STRING UserNameString;
UNICODE_STRING DomainString;
PSID LogonSid;
LUID LogonId;
HANDLE UserToken;
BOOL PasswordExpired;
NTSTATUS Status;
NTSTATUS SubStatus;
DLG_RETURN_TYPE Result;
DWORD RasBox;
BOOL timeout;
PUCHAR Dummy;
NET_API_STATUS NetStatus;
HANDLE hThread;
DWORD tid;
BOOL RasUsed;
//
// Hide the password so it doesn't make it to the pagefile in
// cleartext. Do this before getting the username and password
// so that it can't easily be identified (by association with
// the username and password) if we should crash or be rebooted
// before getting a chance to encode it.
//
GetDlgItemText(hDlg, IDD_LOGON_PASSWORD, Password, MAX_STRING_BYTES);
RtlInitUnicodeString(&pGlobals->PasswordString, Password);
pGlobals->Seed = 0; // Causes the encode routine to assign a seed
HidePassword( &pGlobals->Seed, &pGlobals->PasswordString );
//
// Now get the username and domain
//
GetDlgItemText(hDlg, IDD_LOGON_NAME, UserName, MAX_STRING_BYTES);
GetDlgItemText(hDlg, IDD_LOGON_DOMAIN, Domain, MAX_STRING_BYTES);
RtlInitUnicodeString(&UserNameString, UserName);
RtlInitUnicodeString(&DomainString, Domain);
//
// Ok, is the RASbox checked?
//
RasBox = IsDlgButtonChecked( hDlg, IDD_LOGON_RASBOX );
RasUsed = FALSE;
if ( RasBox == BST_CHECKED )
{
//
// Reset the current timeout so that they neatly clean up before
// winlogon up and blows them away.
//
pWlxFuncs->WlxSetTimeout( hGlobalWlx, 5 * 60 );
if ( !PopupRasPhonebookDlg( hDlg, pGlobals, &timeout) )
{
return( MSGINA_DLG_FAILURE );
}
RasUsed = TRUE;
//
// Reinitialize strings in case they've changed
//
RtlInitUnicodeString( &UserNameString, UserName );
//
// Ping Netlogon to allow us to go out on the net again...
//
NetStatus = I_NetLogonControl2(NULL,
NETLOGON_CONTROL_TRANSPORT_NOTIFY,
1, (LPBYTE)&Dummy, &Dummy );
if ( NetStatus == NO_ERROR ) {
NetApiBufferFree( Dummy );
}
}
//
// Store the logon time
// Do this before calling Lsa so we know if logon is successful that
// the password-must-change time will be greater than this time.
// If we grabbed this time after calling the lsa, this might not be true.
//
Status = NtQuerySystemTime(&pGlobals->LogonTime);
ASSERT(NT_SUCCESS(Status));
DebugLog((DEB_TRACE, "In Attempt Logon!\n"));
//
// Generate a unique sid for this logon
//
LogonSid = pGlobals->LogonSid;
//
// Kick off the feedback thread.
//
pGlobals->LogonInProgress = TRUE ;
GetWindowRect( GetDlgItem( hDlg, IDD_LOGON_ANI ), &pGlobals->OverlayPoint );
hThread = CreateThread( NULL, 0,
SlowLogonThread,
pGlobals,
0, &tid );
if (hThread)
{
CloseHandle( hThread );
}
SetupCursor( TRUE );
//
// Actually try to logon the user
//
Status = WinLogonUser(
pGlobals->LsaHandle,
pGlobals->AuthenticationPackage,
Interactive,
&UserNameString,
&DomainString,
&pGlobals->PasswordString,
LogonSid,
&LogonId,
&UserToken,
&pGlobals->UserProcessData.Quotas,
(PVOID *)&pGlobals->Profile,
&pGlobals->ProfileLength,
&SubStatus);
SetupCursor( FALSE );
RtlEnterCriticalSection( &pGlobals->csGlobals );
if ( pGlobals->hwndLogonInProgress )
{
SendMessage( pGlobals->hwndLogonInProgress,
WM_LOGONPROMPT,
0, 0 );
SetForegroundWindow( hDlg );
}
pGlobals->LogonInProgress = FALSE;
RtlLeaveCriticalSection( &pGlobals->csGlobals );
DebugLog((DEB_TRACE, "WinLogonUser returned %#x\n", Status));
PasswordExpired = (((Status == STATUS_ACCOUNT_RESTRICTION) &&
(SubStatus == STATUS_PASSWORD_EXPIRED)) ||
(Status == STATUS_PASSWORD_MUST_CHANGE));
//
// If the account has expired we let them change their password and
// automatically retry the logon with the new password.
//
if (PasswordExpired)
{
if (Status == STATUS_PASSWORD_MUST_CHANGE)
{
Result = TimeoutMessageBox(hDlg, IDS_PASSWORD_MUST_CHANGE,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONSTOP,
TIMEOUT_CURRENT);
}
else
{
Result = TimeoutMessageBox(hDlg, IDS_PASSWORD_EXPIRED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONSTOP,
TIMEOUT_CURRENT);
}
if (DLG_INTERRUPTED(Result))
{
return(Result);
}
//
// Copy the old password for mpr notification later
//
RevealPassword( &pGlobals->PasswordString );
wcsncpy(OldPassword, Password, MAX_STRING_BYTES);
pGlobals->OldSeed = 0;
RtlInitUnicodeString(&pGlobals->OldPasswordString, pGlobals->OldPassword);
HidePassword( &pGlobals->OldSeed, &pGlobals->OldPasswordString);
pGlobals->OldPasswordPresent = 1;
//
// Let the user change their password
//
Result = ChangePasswordLogon(hDlg, pGlobals, UserName, Domain,
Password);
if (DLG_INTERRUPTED(Result))
{
return(Result);
}
if (Result == MSGINA_DLG_FAILURE)
{
// The user doesn't want to, or failed to change their password.
return(Result);
}
//
// Retry the logon with the changed password
//
//
// Generate a unique sid for this logon
//
LogonSid = pGlobals->LogonSid;
Status = WinLogonUser(
pGlobals->LsaHandle,
pGlobals->AuthenticationPackage,
Interactive,
&UserNameString,
&DomainString,
&pGlobals->PasswordString,
LogonSid,
&LogonId,
&UserToken,
&pGlobals->UserProcessData.Quotas,
(PVOID *)&pGlobals->Profile,
&pGlobals->ProfileLength,
&SubStatus);
}
//
// Deal with a terminally failed logon attempt
//
if (!NT_SUCCESS(Status))
{
//
// Do lockout processing
//
LockoutHandleFailedLogon(pGlobals);
return (HandleFailedLogon(hDlg, Status, SubStatus, UserName, Domain));
}
//
// The user logged on successfully
//
//
// Do lockout processing
//
LockoutHandleSuccessfulLogon(pGlobals);
//
// If the audit log is full, check they're an admin
//
if (pGlobals->AuditLogFull)
{
//
// The audit log is full, so only administrators are allowed to logon.
//
if (!TestTokenForAdmin(UserToken))
{
//
// The user is not an administrator, boot 'em.
//
LsaFreeReturnBuffer(pGlobals->Profile);
NtClose(UserToken);
return (HandleFailedLogon(hDlg, STATUS_LOGON_FAILURE, 0, UserName, Domain));
}
}
//
// Hide ourselves before letting other credential managers put
// up dialogs
//
ShowWindow(hDlg, SW_HIDE);
//
// Notify credential managers of the successful logon
//
pGlobals->UserToken = UserToken;
pGlobals->UserProcessData.UserToken = UserToken;
pGlobals->UserProcessData.UserSid = LogonSid;
pGlobals->UserProcessData.NewThreadTokenSD = CreateUserThreadTokenSD(LogonSid, pGlobals->WinlogonSid);
pGlobals->MprLogonScripts = NULL;
if ( RasUsed )
{
pGlobals->ExtraApps = AllocAndGetProfileString(
WINLOGON, RASMON_KEY, RASMON_DEFAULT );
}
else
{
pGlobals->ExtraApps = NULL;
}
//
// If we get here, the system works well enough for the user to have
// actually logged on. Profile failures aren't fixable by last known
// good anyway. Therefore, declare the boot good.
//
ReportBootGood();
//
// Set up the system for the new user
//
pGlobals->LogonId = LogonId;
if ((pGlobals->Profile != NULL) && (pGlobals->Profile->FullName.Length > 0)) {
if (pGlobals->Profile->FullName.Length > MAX_STRING_LENGTH) {
wcsncpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer, MAX_STRING_LENGTH);
*(pGlobals->UserFullName + MAX_STRING_LENGTH) = UNICODE_NULL;
}
else {
lstrcpy(pGlobals->UserFullName, pGlobals->Profile->FullName.Buffer);
}
} else {
//
// No profile - set full name = NULL
pGlobals->UserFullName[0] = 0;
ASSERT( lstrlen(pGlobals->UserFullName) == 0);
}
//
// Update our default username and domain ready for the next logon
//
WriteProfileString(APPLICATION_NAME,
DEFAULT_USER_NAME_KEY, pGlobals->UserName);
WriteProfileString(APPLICATION_NAME,
DEFAULT_DOMAIN_NAME_KEY, pGlobals->Domain);
return(MSGINA_DLG_SUCCESS);
}
/****************************************************************************\
*
* FUNCTION: HandleFailedLogon
*
* PURPOSE: Tells the user why their logon attempt failed.
*
* RETURNS: MSGINA_DLG_FAILURE - we told them what the problem was successfully.
* DLG_INTERRUPTED() - a set of return values - see winlogon.h
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\****************************************************************************/
DLG_RETURN_TYPE
HandleFailedLogon(
HWND hDlg,
NTSTATUS Status,
NTSTATUS SubStatus,
PWCHAR UserName,
PWCHAR Domain
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
DLG_RETURN_TYPE Result;
TCHAR Buffer1[MAX_STRING_BYTES];
TCHAR Buffer2[MAX_STRING_BYTES];
switch (Status)
{
case STATUS_LOGON_FAILURE:
Result = TimeoutMessageBox(hDlg, IDS_INCORRECT_NAME_OR_PWD,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_ACCOUNT_RESTRICTION:
switch (SubStatus)
{
case STATUS_INVALID_LOGON_HOURS:
Result = TimeoutMessageBox(hDlg, IDS_INVALID_LOGON_HOURS,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_INVALID_WORKSTATION:
Result = TimeoutMessageBox(hDlg, IDS_INVALID_WORKSTATION,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_ACCOUNT_DISABLED:
Result = TimeoutMessageBox(hDlg, IDS_ACCOUNT_DISABLED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
default:
Result = TimeoutMessageBox(hDlg, IDS_ACCOUNT_RESTRICTION,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
}
break;
case STATUS_NO_LOGON_SERVERS:
LoadString(hDllInstance, IDS_LOGON_NO_DOMAIN, Buffer1, sizeof(Buffer1));
_snwprintf(Buffer2, sizeof(Buffer2), Buffer1, Domain);
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, sizeof(Buffer1));
Result = TimeoutMessageBoxlpstr(hDlg, Buffer2,
Buffer1,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_LOGON_TYPE_NOT_GRANTED:
Result = TimeoutMessageBox(hDlg, IDS_LOGON_TYPE_NOT_GRANTED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_NO_TRUST_LSA_SECRET:
Result = TimeoutMessageBox(hDlg, IDS_NO_TRUST_LSA_SECRET,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_TRUSTED_DOMAIN_FAILURE:
Result = TimeoutMessageBox(hDlg, IDS_TRUSTED_DOMAIN_FAILURE,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_TRUSTED_RELATIONSHIP_FAILURE:
Result = TimeoutMessageBox(hDlg, IDS_TRUSTED_RELATIONSHIP_FAILURE,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_ACCOUNT_EXPIRED:
Result = TimeoutMessageBox(hDlg, IDS_ACCOUNT_EXPIRED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_NETLOGON_NOT_STARTED:
Result = TimeoutMessageBox(hDlg, IDS_NETLOGON_NOT_STARTED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
case STATUS_ACCOUNT_LOCKED_OUT:
Result = TimeoutMessageBox(hDlg, IDS_ACCOUNT_LOCKED,
IDS_LOGON_MESSAGE,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
default:
WLPrint(("Logon failure status = 0x%lx, sub-status = 0x%lx", Status, SubStatus));
LoadString(hDllInstance, IDS_UNKNOWN_LOGON_FAILURE, Buffer1, sizeof(Buffer1));
_snwprintf(Buffer2, sizeof(Buffer2), Buffer1, Status);
LoadString(hDllInstance, IDS_LOGON_MESSAGE, Buffer1, sizeof(Buffer1));
Result = TimeoutMessageBoxlpstr(hDlg, Buffer2,
Buffer1,
MB_OK | MB_ICONEXCLAMATION,
TIMEOUT_CURRENT);
break;
}
if (!DLG_INTERRUPTED(Result))
{
Result = MSGINA_DLG_FAILURE;
}
return(Result);
UNREFERENCED_PARAMETER(UserName);
}
/****************************************************************************\
*
* FUNCTION: ReportBootGood
*
* PURPOSE: Discover if reporting boot success is responsibility of
* winlogon or not.
* If it is, report boot success.
* Otherwise, do nothing.
*
* RETURNS: Nothing
*
* HISTORY:
*
* 02-Feb-1993 bryanwi - created
*
\****************************************************************************/
VOID
ReportBootGood()
{
static DWORD fDoIt = (DWORD) -1; // -1 == uninited
// 0 == don't do it, or done
// 1 == do it
PWCH pchData;
DWORD cb, cbCopied;
if (fDoIt == -1) {
if ((pchData = Alloc(cb = sizeof(TCHAR)*128)) == NULL) {
return;
}
pchData[0] = TEXT('0');
cbCopied = GetProfileString(APPLICATION_NAME, REPORT_BOOT_OK_KEY, TEXT("0"),
(LPTSTR)pchData, 128);
fDoIt = 0;
if (pchData[0] != TEXT('0')) {
//
// "ReportBootGood" is present, and has some value other than
// '0', so report success.
//
fDoIt = 1;
}
Free((TCHAR *)pchData);
}
if (fDoIt == 1) {
NotifyBootConfigStatus(TRUE);
fDoIt = 0;
}
return;
}