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.
 
 
 
 
 
 

2126 lines
57 KiB

/****************************** Module Header ******************************\
* Module Name: wlx.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Winlogon main module
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#define WM_HIDEOURSELVES WM_USER + 600
#if DBG
char * SASTypes[] = { "Timeout", "Ctrl-Alt-Del", "ScreenSaver Timeout",
"ScreenSaver Activity", "User Logoff" };
#define SASName(x) (x < (sizeof(SASTypes) / sizeof(char *)) ? SASTypes[x] : "User Defined")
char * WlxRets[] = { "invalid", "Logon", "None", "LockWksta", "Logoff", "Shutdown",
"Pwd Changed", "TaskList", "UnlockWksta", "ForceLogoff",
"Shutdown-PowerOff", "Shutdown-Reboot" };
#define WlxName(x) (x < (sizeof(WlxRets) / sizeof(char *)) ? WlxRets[x] : "Invalid")
#endif
#define IsShutdown(x) ((x == WLX_SAS_ACTION_SHUTDOWN) || \
(x == WLX_SAS_ACTION_SHUTDOWN_REBOOT) || \
(x == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
#define RealFlagsFromStoredFlags(Flags) \
EWX_LOGOFF | \
((Flags & EWX_WINLOGON_OLD_SYSTEM) ? EWX_SYSTEM_CALLER : 0) | \
((Flags & EWX_WINLOGON_OLD_SHUTDOWN) ? EWX_SHUTDOWN : 0) | \
((Flags & EWX_WINLOGON_OLD_REBOOT) ? EWX_REBOOT : 0) | \
((Flags & EWX_WINLOGON_OLD_POWEROFF) ? EWX_POWEROFF : 0)
#define StoredFlagsFromRealFlags(Flags) \
EWX_LOGOFF | \
((Flags & EWX_SYSTEM_CALLER) ? EWX_WINLOGON_OLD_SYSTEM : 0) | \
((Flags & EWX_SHUTDOWN) ? EWX_WINLOGON_OLD_SHUTDOWN : 0) | \
((Flags & EWX_REBOOT) ? EWX_WINLOGON_OLD_REBOOT : 0) | \
((Flags & EWX_POWEROFF) ? EWX_WINLOGON_OLD_POWEROFF : 0)
BOOLEAN SasMessages = TRUE;
//
// For checking page file
//
extern TCHAR szMemMan[];
extern TCHAR szNoPageFile[];
//
// For migration
//
TCHAR szAdminName[ MAX_STRING_BYTES ];
//
// Local Prototypes
//
int
DoLockWksta(
PGLOBALS pGlobals,
BOOL ScreenSaverInvoked);
int
DoScreenSaver(
PGLOBALS pGlobals,
BOOL WkstaLocked);
void
WinsrvNotify(
PGLOBALS pGlobals,
DWORD SasType);
BOOL
LoggedonDlgInit(
HWND hDlg
);
//+---------------------------------------------------------------------------
//
// Function: DropWorkingSet
//
// Synopsis: Reduce working set when we're
//
// Arguments: (none)
//
// History: 11-04-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
DropWorkingSet(void)
{
NTSTATUS Status;
QUOTA_LIMITS Quota;
Status = NtQueryInformationProcess( NtCurrentProcess(),
ProcessQuotaLimits,
&Quota,
sizeof(QUOTA_LIMITS),
NULL );
if (NT_SUCCESS(Status))
{
Quota.MinimumWorkingSetSize = 0xFFFFFFFF;
Quota.MaximumWorkingSetSize = 0xFFFFFFFF;
NtSetInformationProcess(NtCurrentProcess(),
ProcessQuotaLimits,
&Quota,
sizeof(QUOTA_LIMITS) );
}
}
//+---------------------------------------------------------------------------
//
// Function: InitializeGinaDll
//
// Synopsis: Initializes the gina
//
// Arguments: [pGlobals] --
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
InitializeGinaDll(PGLOBALS pGlobals)
{
PGINASESSION pGina;
pGina = pGlobals->pGina;
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_INITIALIZE))
{
DebugLog((DEB_TRACE, "About to call WlxInitialize(%ws, 1, NULL, @%#x, @%#x)\n",
pGlobals->WindowStation.pszWinsta,
&WlxDispatchTable, &pGina->pGinaContext));
DebugBreak();
}
#endif
//
// Perversely, this may not return. The GINA may in fact call SASNotify
// immediately, so update the state before we go in:
//
pGlobals->WinlogonState = Winsta_NoOne;
DebugLog((DEB_TRACE_STATE, "InitGina: State is %d %s\n", Winsta_NoOne, GetState(Winsta_NoOne)));
if (!pGina->pWlxInitialize( pGlobals->WindowStation.pszWinsta,
pGlobals,
NULL,
(PVOID) &WlxDispatchTable,
&pGina->pGinaContext))
{
//
// If the GINA failed to init, we're dead. bugcheck time:
//
ExitProcess( EXIT_GINA_INIT_ERROR );
}
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: SASRouter
//
// Synopsis: Routes an SAS event to the appropriate recipient
//
// Arguments: [pGlobals] --
// [SasType] --
//
// History: 8-24-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
SASRouter( PGLOBALS pGlobals,
DWORD SasType )
{
if (!TestSasMessages())
{
QueueSasEvent(SasType);
return;
}
pGlobals->SasType = SasType;
if (!IsSASState(pGlobals->WinlogonState))
{
if (IsDisplayState(pGlobals->WinlogonState) ||
(pGlobals->WinlogonState == Winsta_WaitForShutdown) ||
(pGlobals->WinlogonState == Winsta_InShutdownDlg) ||
(pGlobals->WinlogonState == Winsta_Locked))
{
DebugLog((DEB_TRACE, "In state %s, sending kill message to window\n",
GetState(pGlobals->WinlogonState)));
if (!SendSasToTopWindow(pGlobals, SasType))
DebugLog((DEB_WARN, "No window to send SAS notice to?\n"));
}
//
// If this was a timeout message,
if ((SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) ||
(SasType == WLX_SAS_TYPE_TIMEOUT) )
{
//
// We do *not* change state on a timeout!
//
return;
}
ChangeStateForSAS(pGlobals);
if (!pGlobals->ScreenSaverActive)
{
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
}
//
// We should be in one of the three base states now:
//
DebugLog((DEB_TRACE_STATE, "SASRouter: In state %s\n", GetState(pGlobals->WinlogonState)));
switch (pGlobals->WinlogonState)
{
case Winsta_NoOne_SAS:
case Winsta_LoggedOn_SAS:
case Winsta_Locked_SAS:
case Winsta_WaitForLogoff:
case Winsta_WaitForShutdown:
case Winsta_InShutdownDlg:
DisableSasMessages();
break;
default:
DebugLog((DEB_ERROR, "SASRouter: Incorrect state %d, %s.\n",
pGlobals->WinlogonState, GetState(pGlobals->WinlogonState)));
break;
}
}
else
{
//
// We are already handling an SAS attempt.
//
// Note: This may fail. There may not be a window currently to
// receive the message. Life is tough that way. The SAS will be
// *dropped*.
//
DebugLog((DEB_TRACE, "Sending SAS %s to top window\n", SASName(SasType)));
SendSasToTopWindow(pGlobals, SasType);
}
}
//+---------------------------------------------------------------------------
//
// Function: CADNotify
//
// Synopsis: Called by sas.c, this is the entrypoint for a Ctrl-Alt-Del
// call. Expanded to handle all notification from winsrv.
//
// Arguments: [pGlobals] --
// [SasType] --
//
// Algorithm:
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
CADNotify(
PGLOBALS pGlobals,
DWORD SasType)
{
DebugLog((DEB_TRACE, "Received SAS from winsrv, code %d (%s)\n", SasType, SASName(SasType)));
if (SasType == WLX_SAS_TYPE_USER_LOGOFF)
{
WinsrvNotify(pGlobals, SasType);
}
else if (pGlobals->ForwardCAD)
{
SASRouter(pGlobals, SasType);
}
}
PWSTR
AllocAndDuplicateString(
PWSTR pszString)
{
int len;
PWSTR pszNewString;
if (!pszString)
{
return(NULL);
}
len = (wcslen(pszString) + 1) * sizeof(WCHAR);
pszNewString = LocalAlloc(LMEM_FIXED, len);
if (pszNewString)
{
CopyMemory(pszNewString, pszString, len);
}
return(pszNewString);
}
PWSTR
AllocAndDuplicateStrings(
PWSTR pszStrings)
{
DWORD len;
PWSTR pszNewStrings;
if (!pszStrings)
{
return(NULL);
}
len = LocalSize (pszStrings);
pszNewStrings = LocalAlloc(LPTR, len);
if (pszNewStrings)
{
CopyMemory(pszNewStrings, pszStrings, len);
}
return(pszNewStrings);
}
PVOID
CopyEnvironment(
PVOID pEnv)
{
MEMORY_BASIC_INFORMATION mbi;
PVOID pNew;
if (VirtualQueryEx(
GetCurrentProcess(),
pEnv,
&mbi,
sizeof(mbi) ) )
{
pNew = VirtualAlloc(NULL,
mbi.RegionSize,
MEM_COMMIT,
PAGE_READWRITE);
if (pNew)
{
CopyMemory(pNew, pEnv, mbi.RegionSize);
return(pNew);
}
}
return(NULL);
}
//+---------------------------------------------------------------------------
//
// Function: LogonAttempt
//
// Synopsis: Handles a logon attempt.
//
// Arguments: [pGlobals] --
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
int
LogonAttempt(
PGLOBALS pGlobals)
{
DWORD WlxResult;
PGINASESSION pGina;
WLX_MPR_NOTIFY_INFO MprInfo;
PWLX_PROFILE_V2_0 pProfileInfo;
PSID pLogonSid;
DWORD Options;
HANDLE hToken;
HANDLE uh;
int MprRet;
pGina = pGlobals->pGina;
pLogonSid = CreateLogonSid(NULL);
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_LOGGEDOUT))
{
DebugLog((DEB_TRACE, "About to call WlxLoggedOutSAS(%#x, %d, @%#x, @%x,\n",
pGina->pGinaContext, pGlobals->SasType, &pGlobals->LogonId, pLogonSid));
DebugLog((DEB_TRACE, " @%#x, @%#x, @%#x, @%#x)\n", &Options, &hToken,
&MprInfo, &pProfileInfo));
DebugBreak();
}
#endif
WlxSetTimeout(pGlobals, 120);
WlxResult = pGina->pWlxLoggedOutSAS(pGina->pGinaContext,
pGlobals->SasType,
&pGlobals->LogonId,
pLogonSid,
&Options,
&hToken,
&MprInfo,
&pProfileInfo );
DebugLog((DEB_TRACE, "WlxLoggedOutSAS returned %d, %s\n", WlxResult, WlxName(WlxResult)));
if (WlxResult != WLX_SAS_ACTION_LOGON )
{
DebugLog((DEB_TRACE_STATE, "LogonAttempt: Resetting state to %s\n", GetState(Winsta_NoOne)));
pGlobals->WinlogonState = Winsta_NoOne;
DeleteLogonSid(pLogonSid);
return(WlxResult);
}
//
// Okay, someone logged on. This, this is interesting.
//
if (MprInfo.pszUserName)
{
pGlobals->UserName = AllocAndDuplicateString(MprInfo.pszUserName);
}
MprRet = MprLogonNotify(
pGlobals,
NULL,
MprInfo.pszUserName,
MprInfo.pszDomain,
MprInfo.pszPassword,
MprInfo.pszOldPassword,
&pGlobals->LogonId,
&pGlobals->LogonScripts);
DestroyMprInfo(&MprInfo);
//
// Wait on the font loading thread here, so we don't inadvertantly re-enter
// the stuff in user that gets confused.
//
if ( hFontThread )
{
WaitForSingleObject( hFontThread, INFINITE );
CloseHandle( hFontThread );
hFontThread = NULL;
}
SecurityChangeUser(pGlobals, hToken, NULL, pLogonSid, TRUE);
if (!TEST_FLAG(Options, WLX_LOGON_OPT_NO_PROFILE))
{
if (pProfileInfo) {
if (pProfileInfo->pszProfile)
{
pGlobals->UserProfile.ProfilePath =
AllocAndExpandEnvironmentStrings(pProfileInfo->pszProfile);
LocalFree(pProfileInfo->pszProfile);
}
else
{
pGlobals->UserProfile.ProfilePath = NULL;
}
if (pProfileInfo->dwType >= WLX_PROFILE_TYPE_V2_0) {
if (pProfileInfo->pszPolicy)
{
pGlobals->UserProfile.PolicyPath =
AllocAndDuplicateString(pProfileInfo->pszPolicy);
LocalFree(pProfileInfo->pszPolicy);
}
else
{
pGlobals->UserProfile.PolicyPath = NULL;
}
if (pProfileInfo->pszNetworkDefaultUserProfile)
{
pGlobals->UserProfile.NetworkDefaultUserProfile =
AllocAndDuplicateString(pProfileInfo->pszNetworkDefaultUserProfile);
LocalFree(pProfileInfo->pszNetworkDefaultUserProfile);
}
else
{
pGlobals->UserProfile.NetworkDefaultUserProfile = NULL;
}
if (pProfileInfo->pszServerName)
{
pGlobals->UserProfile.ServerName =
AllocAndDuplicateString(pProfileInfo->pszServerName);
LocalFree(pProfileInfo->pszServerName);
}
else
{
pGlobals->UserProfile.ServerName = NULL;
}
if (pProfileInfo->pszEnvironment)
{
pGlobals->UserProfile.Environment =
AllocAndDuplicateStrings(pProfileInfo->pszEnvironment);
LocalFree(pProfileInfo->pszEnvironment);
}
else
{
pGlobals->UserProfile.Environment = NULL;
}
} else {
pGlobals->UserProfile.PolicyPath = NULL;
pGlobals->UserProfile.NetworkDefaultUserProfile = NULL;
pGlobals->UserProfile.ServerName = NULL;
pGlobals->UserProfile.Environment = NULL;
}
}
DebugLog((DEB_TRACE_PROFILE, "Using initial profile path of %ws\n", pGlobals->UserProfile.ProfilePath));
LocalFree(pProfileInfo);
//
// Load profile, set environment variables, etc.
//
if (SetupUserEnvironment(pGlobals))
{
OpenIniFileUserMapping(pGlobals);
uh = ImpersonateUser(&pGlobals->UserProcessData, NULL);
SetWindowStationUser(pGlobals->WindowStation.hwinsta, &pGlobals->LogonId,
pGlobals->UserProcessData.UserSid,
RtlLengthSid(pGlobals->UserProcessData.UserSid));
StopImpersonating(uh);
//
// Update the window station lock so that apps can start.
//
UnlockWindowStation(pGlobals->WindowStation.hwinsta);
LockWindowStation(pGlobals->WindowStation.hwinsta);
//
// allocate floppies and CDRoms (if so configured)
//
RmvAllocateRemovableMedia( pLogonSid );
}
else
{
//
// Whoops, something went wrong. we *must* log the user
// out. We do this by passing LOGOFF back to mainloop.
//
WlxResult = WLX_SAS_ACTION_LOGOFF;
}
}
return(WlxResult);
}
/****************************************************************************\
*
* FUNCTION: DisplayPreShellLogonMessages
*
* PURPOSE: Displays any security warnings to the user after a successful logon
* The messages are displayed before the shell starts
*
* RETURNS: DLG_SUCCESS - the dialogs were displayed successfully.
* DLG_INTERRUPTED() - a set defined in winlogon.h
*
* NOTE: Screen-saver timeouts are handled by our parent dialog so this
* routine should never return DLG_SCREEN_SAVER_TIMEOUT
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\****************************************************************************/
int
DisplayPreShellLogonMessages(
PGLOBALS pGlobals
)
{
int Result;
if (PageFilePopup) {
HKEY hkeyMM;
DWORD dwTempFile, cbTempFile, dwType;
//
// WinLogon created a temp page file. If a previous user has not
// created a real one already, then inform this user to do so.
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMemMan, 0, KEY_READ,
&hkeyMM) == ERROR_SUCCESS) {
cbTempFile = sizeof(dwTempFile);
if (RegQueryValueEx (hkeyMM, szNoPageFile, NULL, &dwType,
(LPBYTE) &dwTempFile, &cbTempFile) != ERROR_SUCCESS ||
dwType != REG_DWORD || cbTempFile != sizeof(dwTempFile)) {
dwTempFile = 0;
}
RegCloseKey(hkeyMM);
} else
dwTempFile = 0;
if (dwTempFile == 1) {
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
Result = TimeoutMessageBox(
pGlobals,
NULL,
IDS_NO_PAGING_FILE,
IDS_LIMITED_RESOURCES,
MB_OK | MB_ICONSTOP
);
if (Result == WLX_DLG_INPUT_TIMEOUT) {
return(Result);
}
}
}
return(DLG_SUCCESS);
}
//+---------------------------------------------------------------------------
//
// Function: DoStartShell
//
// Synopsis:
//
// Effects:
//
// Arguments: [pGlobals] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 9-30-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
DoStartShell(
PGLOBALS pGlobals
)
{
PGINASESSION pGina;
HANDLE hImp;
PVOID pNewEnvironment;
(void) DisplayPreShellLogonMessages(pGlobals);
//
// If not logging in as Guest, System or Administrator then check for
// migration of Windows 3.1 configuration inforation.
//
if (szAdminName[ 0 ] == TEXT('\0'))
{
LoadString(NULL, IDS_ADMIN_ACCOUNT_NAME, szAdminName, sizeof(szAdminName));
}
if (!IsUserAGuest(pGlobals) &&
_wcsicmp(pGlobals->UserName, szAdminName)
)
{
Windows31Migration(pGlobals);
}
pGina = pGlobals->pGina;
//
// Play the user's logon sound
//
if (pGlobals->PlaySound ||
pGlobals->MigrateSoundEvents ||
pGlobals->MigrateMidiUser)
{
BOOL fBeep;
if (OpenIniFileUserMapping(pGlobals))
{
hImp = ImpersonateUser(&pGlobals->UserProcessData, NULL);
//
// Migrate Users MIDI settings
//
if (pGlobals->MigrateMidiUser) {
(*(pGlobals->MigrateMidiUser))();
}
if (pGlobals->MigrateSoundEvents) {
(*(pGlobals->MigrateSoundEvents))();
}
if (pGlobals->PlaySound) {
//
// Whenever a user logs in, have WINMM.DLL check if there
// are any sound events within the [SOUNDS] section of
// CONTROL.INI that haven't been ported into HKCU/AppEvents.
// If there are, migrate those schemes to their new home.
// This must be done before the upcoming PlaySound() call,
// as PlaySound() uses the HKCU/AppEvents schemes-listing
// to resolve an SND_ALIAS_ID request.
//
if (!SystemParametersInfo(SPI_GETBEEP, 0, &fBeep, FALSE)) {
// Failed to get hold of beep setting. Should we be
// noisy or quiet? We have to choose one value...
fBeep = TRUE;
}
if (fBeep) {
(*(pGlobals->PlaySound))((LPCSTR)SND_ALIAS_SYSTEMSTART,
NULL,
SND_ALIAS_ID | SND_ASYNC | SND_NODEFAULT);
}
}
StopImpersonating(hImp);
CloseIniFileUserMapping(pGlobals);
}
}
WlxSetTimeout(pGlobals, 120);
pNewEnvironment = CopyEnvironment(pGlobals->UserProcessData.pEnvironment);
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_ACTIVATE))
{
DebugLog((DEB_TRACE, "About to call WlxActivateUserShell(%#x, %ws, %ws, %#x)\n",
pGina->pGinaContext, APPLICATION_DESKTOP_PATH,
pGlobals->LogonScripts, NULL));
DebugBreak();
}
#endif
return( pGina->pWlxActivateUserShell( pGina->pGinaContext,
APPLICATION_DESKTOP_PATH,
pGlobals->LogonScripts,
pNewEnvironment) );
}
//+---------------------------------------------------------------------------
//
// Function: HandleLoggedOn
//
// Synopsis:
//
// Effects:
//
// Arguments: [pGlobals] --
// [SasType] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 9-30-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
HandleLoggedOn(
PGLOBALS pGlobals,
DWORD SasType)
{
DWORD Result;
WLX_MPR_NOTIFY_INFO MprInfo;
PGINASESSION pGina;
int Flags;
int MprRet;
int LogoffResult;
pGina = pGlobals->pGina;
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
ZeroMemory(&MprInfo, sizeof(MprInfo));
WlxSetTimeout(pGlobals, 120);
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_LOGGEDON))
{
DebugLog((DEB_TRACE, "About to call WlxLoggedOnSAS( %#x, %d, NULL)\n",
pGina->pGinaContext, pGlobals->SasType));
DebugBreak();
}
#endif
Result = pGina->pWlxLoggedOnSAS( pGina->pGinaContext,
SasType,
NULL );
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
DebugLog((DEB_TRACE, "WlxLoggedOnSAS returned %d, %s\n", Result, WlxName(Result)));
pGlobals->LastGinaRet = Result;
//
// if a new SAS has come in while we were processing that one, repost it and
// pick it up in LoggedOnDlgProc.
//
if ( pGlobals->SasType != SasType )
{
DebugLog((DEB_TRACE, "New SAS (%d: %s) came in while handling (%d: %s). Routing it now\n",
pGlobals->SasType, SASName(pGlobals->SasType),
SasType, SASName(SasType) ));
SASRouter( pGlobals, pGlobals->SasType );
}
if (Result == WLX_SAS_ACTION_LOCK_WKSTA)
{
return (DoLockWksta(pGlobals, FALSE));
}
if ((Result == WLX_SAS_ACTION_TASKLIST) ||
(Result == WLX_SAS_ACTION_NONE))
{
if ((pGlobals->WinlogonState != Winsta_WaitForLogoff) &&
(pGlobals->WinlogonState != Winsta_WaitForShutdown) &&
(pGlobals->WinlogonState != Winsta_InShutdownDlg) )
{
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
}
if (Result == WLX_SAS_ACTION_TASKLIST)
{
WCHAR szTaskMgr[] = L"taskmgr.exe";
DebugLog((DEB_TRACE, "Starting taskmgr.exe.\n"));
if (pGlobals->UserLoggedOn ) {
pGina->pWlxStartApplication(pGina->pGinaContext,
APPLICATION_DESKTOP_PATH,
pGlobals->UserProcessData.pEnvironment,
szTaskMgr);
}
}
TickleMessenger();
return(Result);
}
switch (Result)
{
case WLX_SAS_ACTION_LOGOFF:
Flags = EWX_LOGOFF;
break;
case WLX_SAS_ACTION_FORCE_LOGOFF:
Flags = EWX_LOGOFF | EWX_FORCE;
break;
case WLX_SAS_ACTION_SHUTDOWN:
Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN;
break;
case WLX_SAS_ACTION_SHUTDOWN_REBOOT:
Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN | EWX_WINLOGON_OLD_REBOOT;
break;
case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF:
Flags = EWX_LOGOFF | EWX_WINLOGON_OLD_SHUTDOWN | EWX_WINLOGON_OLD_POWEROFF;
break;
default:
DebugLog((DEB_ERROR, "Incorrect result (%d) from WlxLoggedOnSAS\n", Result));
return(0);
}
LogoffResult = InitiateLogoff(pGlobals, Flags);
if (LogoffResult == DLG_FAILURE)
{
return(WLX_SAS_ACTION_NONE);
}
return(Result);
}
//+---------------------------------------------------------------------------
//
// Function: DoLockWksta
//
// Synopsis:
//
// Arguments: [pGlobals] --
//
// History: 9-16-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
int
DoLockWksta(
PGLOBALS pGlobals,
BOOL ScreenSaverInvoked)
{
int Result;
PGINASESSION pGina;
pGlobals->WinlogonState = Winsta_Locked;
DebugLog((DEB_TRACE_STATE, "DoLockWksta: Setting state to %s\n", GetState(Winsta_Locked)));
pGina = pGlobals->pGina;
LockWindowStation(pGlobals->WindowStation.hwinsta);
do
{
pGlobals->WinlogonState = Winsta_Locked_Display;
DebugLog((DEB_TRACE_STATE, "DoLockWksta: Setting state to %s\n",
GetState(Winsta_Locked_Display)));
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_DISPLAYLOCKED))
{
DebugLog((DEB_TRACE, "About to call WlxDisplayLockedNotice( %#x )\n",
pGina->pGinaContext ));
DebugBreak();
}
#endif
//
// No input timeout
//
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
pGina->pWlxDisplayLockedNotice( pGina->pGinaContext );
DebugLog((DEB_TRACE, "Out of DisplayLockedNotice, SAS = %s\n",
SASName(pGlobals->SasType)));
if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
{
//
// If we were invoked as part of a secure screen saver,
// then this timeout means that we should return to it
// and let it cycle.
//
if (ScreenSaverInvoked)
{
return(WLX_SAS_ACTION_NONE);
}
//
// Invoke the screen saver:
//
if (DoScreenSaver(pGlobals, TRUE) >= 0)
{
//
// Jump right back to the top.
//
Result = WLX_SAS_ACTION_NONE;
continue;
}
//
// A return of -1 indicates that some other SAS occurred,
// e.g. a Logoff, or a GINA specific SAS. Fall through to
// the default handling.
//
}
//
// An unfortunate label, but things get awfully convoluted switching
// between the screen saver and the locked state. The screen saver
// has stopped due to a SAS, and here is where we figure out what to
// do. This is jumped to from below, if the WkstaLocked dialog
// ended with a screen saver timeout.
//
ResetLockCall:
if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
{
if (pGlobals->LogoffFlags & EWX_WINLOGON_API_SHUTDOWN)
{
pGlobals->WinlogonState = Winsta_Shutdown;
}
return(WLX_SAS_ACTION_LOGOFF);
}
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_WKSTALOCKED))
{
DebugLog((DEB_TRACE, "About to call WlxWkstaLockedSAS( %#x, %d )\n",
pGina->pGinaContext, pGlobals->SasType ));
DebugBreak();
}
#endif
WlxSetTimeout(pGlobals, 120);
Result = pGina->pWlxWkstaLockedSAS( pGina->pGinaContext, pGlobals->SasType );
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
DebugLog((DEB_TRACE, "WlxWkstaLockedSAS returned %d, %s\n", Result, WlxName(Result)));
pGlobals->LastGinaRet = Result;
if ( (Result == WLX_SAS_ACTION_NONE) &&
(pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT ) )
{
//
// The GINA was interrupted by a screen saver timeout. If
// we were invoked by a screen saver, we should return immediately,
// otherwise, run the screen saver. Same as before when the display
// call timed out.
//
if (ScreenSaverInvoked)
{
return(WLX_SAS_ACTION_NONE);
}
//
// A return of -1 indicates that the screen saver terminated
// due to some other SAS. Jump back up to the point where we
// handle that, so that we have one point where we do things
// correctly.
//
if ( DoScreenSaver( pGlobals, TRUE ) < 0 )
{
goto ResetLockCall;
}
//
// Otherwise, fall through, and loop again.
//
}
} while (Result == WLX_SAS_ACTION_NONE);
if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
{
InitiateLogoff(pGlobals, EWX_LOGOFF | EWX_FORCE);
}
else
{
SetActiveDesktop( &pGlobals->WindowStation, Desktop_Application );
TickleMessenger();
}
return(Result);
}
//+---------------------------------------------------------------------------
//
// Function: DoScreenSaver
//
// Synopsis: Starts up the screen saver
//
// Effects:
//
// Arguments: [pGlobals] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 10-13-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
int
DoScreenSaver(
PGLOBALS pGlobals,
BOOL WkstaLocked)
{
int Result;
BOOL FastUnlock;
//
// WkstaLocked indicates that we were called by the DoLockWksta
// path. This means that we should not recursively call them, since
// there is no stopping case and we could chew up a lot of stack.
// So, we loop here, but we can break out if RunScreenSaver doesn't
// return Wksta locked.
//
//
// FastUnlock determines if we allow a grace period or not. If the
// wksta is locked coming in, then it is not allowed at all. If it is
// not locked on entry, then we allow it once.
//
FastUnlock = !WkstaLocked;
do
{
Result = RunScreenSaver(pGlobals, FALSE, FastUnlock);
FastUnlock = FALSE;
if (Result == WLX_SAS_ACTION_LOCK_WKSTA)
{
//
// Ok, it's a secure screen saver. If we are already locked,
// break and return
//
if (WkstaLocked)
{
break;
}
//
// Ok, it's not. Invoke the lock code ourselves, but tell it
// that it's being called from the screen saver path.
//
Result = DoLockWksta(pGlobals, TRUE);
}
else
{
break;
}
//
// Loop clause: we only get here if we have invoked DoLockWksta.
// Loop only if it return WLX_SAS_ACTION_NONE, not unlock or force
// logoff.
//
} while (Result == WLX_SAS_ACTION_NONE);
if ( (Result == -1) || (Result == WLX_SAS_ACTION_LOGOFF) )
{
return( Result );
}
else if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
{
return(Result);
}
return(0);
}
/***************************************************************************\
* FUNCTION: LogoffWaitDlgProc
*
* PURPOSE: Processes messages for the forced logoff wait dialog
*
* RETURNS:
* DLG_FAILURE - the dialog could not be displayed
* DLG_INTERRUPTED() - this is a set of possible interruptions (see winlogon.h)
*
* HISTORY:
*
* 05-09-92 Davidc Created.
*
\***************************************************************************/
BOOL
CALLBACK
LogoffWaitDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch (message) {
case WM_INITDIALOG:
EnableSasMessages(hDlg);
SetWindowLong(hDlg, GWL_USERDATA, lParam);
CentreWindow(hDlg);
return(TRUE);
}
// We didn't process this message
return FALSE;
}
BOOL
WaitForForceLogoff(
HWND hWnd,
PGLOBALS pGlobals)
{
int Result;
do
{
SetActiveDesktop( &pGlobals->WindowStation, Desktop_Winlogon );
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
Result = WlxDialogBoxParam( pGlobals,
pGlobals->hInstance,
MAKEINTRESOURCE(IDD_FORCED_LOGOFF_WAIT),
hWnd,
LogoffWaitDlgProc,
(LONG) pGlobals);
} while ( (Result == WLX_DLG_INPUT_TIMEOUT) ||
(Result == WLX_DLG_SCREEN_SAVER_TIMEOUT) );
return(TRUE);
}
/***************************************************************************\
* FUNCTION: LoggedOnDlgProc
*
* PURPOSE: Processes messages for the logged-on control dialog
*
* DIALOG RETURNS:
*
* DLG_FAILURE - Couldn't bring up the dialog
* DLG_LOGOFF() - The user logged off
*
* NOTES:
*
* On entry, it assumed that the winlogon desktop is switched to and the
* desktop lock is held. This same state exists on exit.
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\***************************************************************************/
BOOL WINAPI
LoggedonDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
int Result;
switch (message)
{
case WM_INITDIALOG:
SetWindowLong(hDlg, GWL_USERDATA, lParam);
pGlobals = (PGLOBALS)lParam;
if (!LoggedonDlgInit(hDlg)) {
EndDialog(hDlg, DLG_FAILURE);
return(TRUE);
}
// Send ourselves a message so we can hide ourselves without the
// dialog code trying to force us to be visible
PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
//
//
// Switch to app desktop and release lock
//
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
//
// Tickle the messenger so it will display any queue'd messages.
// (This call is a kind of NoOp).
//
TickleMessenger();
return(TRUE);
case WM_HIDEOURSELVES:
ShowWindow(hDlg, SW_HIDE);
DropWorkingSet();
return(TRUE);
case WLX_WM_SAS:
//
// Disable further SAS events until we decide what to do. If
// we start another window, they will automagically be forwarded
// to it. This lets us call right into the individual cases.
//
DisableSasMessages();
if (wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
{
Result = DoScreenSaver(pGlobals, FALSE);
if ( (Result < 0) || (Result == WLX_SAS_ACTION_LOGOFF) )
{
//
// Ugly case: the screen saver received a SAS event
// which has interrupted it. So, that SAS is now stored
// in the globals. We snag it, stuff it in wParam, and
// FALL THROUGH to the rest of this code.
//
wParam = pGlobals->SasType;
}
else if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
{
EndDialog(hDlg, WLX_SAS_ACTION_FORCE_LOGOFF);
return(TRUE);
}
else
{
EnableSasMessages(hDlg);
return(TRUE);
}
}
//
// Ok, more ugly cases. The user could asynchronously log off
// while we're in HandleLoggedOn(), in which case we would get
// the logoff notify in some other dialog, and returned to us
// here. But, we also have some logoff cases coming through
// here if we are waiting for the logoff, so if this is not
// winsrv telling us it's logged the guy off, ask the gina
// what to do.
//
if ((wParam != WLX_SAS_TYPE_USER_LOGOFF) &&
(wParam != WLX_SAS_TYPE_TIMEOUT) )
{
Result = HandleLoggedOn(pGlobals, (DWORD) wParam);
}
else
{
Result = -1;
}
if ((wParam == WLX_SAS_TYPE_USER_LOGOFF ) ||
(Result == WLX_SAS_ACTION_LOGOFF ) ||
(Result == WLX_SAS_ACTION_FORCE_LOGOFF ) )
{
//
// If we were shut down by the remote guy, handle that
//
if (pGlobals->WinlogonState == Winsta_Shutdown)
{
EndDialog(hDlg, pGlobals->LastGinaRet);
return(TRUE);
}
if ((pGlobals->WinlogonState == Winsta_WaitForLogoff) ||
(wParam == WLX_SAS_TYPE_USER_LOGOFF) )
{
if (IsShutdown(pGlobals->LastGinaRet))
{
pGlobals->WinlogonState = Winsta_WaitForShutdown;
}
else
pGlobals->WinlogonState = Winsta_NoOne;
DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to %s\n",
GetState(pGlobals->WinlogonState)));
EndDialog(hDlg, pGlobals->LastGinaRet);
return(TRUE);
}
else
{
DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to WaitForLogoff\n"));
pGlobals->WinlogonState = Winsta_WaitForLogoff;
//
// If this is a force-logoff, end now, so that we fall
// through to the special dialog (WaitForForceLogoff())
//
if (Result == WLX_SAS_ACTION_FORCE_LOGOFF)
{
EndDialog(hDlg, Result);
return(TRUE);
}
}
}
else
{
//
// Now it is perverse. If the user logged off *while the
// options dialog was up*, they will return NONE, expecting
// us to deal with it correctly.
//
if (pGlobals->WinlogonState == Winsta_WaitForLogoff)
{
if (IsShutdown(pGlobals->LastGinaRet))
{
pGlobals->WinlogonState = Winsta_WaitForShutdown;
}
else
pGlobals->WinlogonState = Winsta_NoOne;
DebugLog((DEB_TRACE_STATE, "LoggedOnDlg: setting state to %s\n",
GetState(pGlobals->WinlogonState)));
EndDialog(hDlg, pGlobals->LastGinaRet);
return(TRUE);
}
}
EnableSasMessages(hDlg);
DropWorkingSet();
return(TRUE);
}
// We didn't process this message
return(FALSE);
}
/***************************************************************************\
* FUNCTION: LoggedonDlgInit
*
* PURPOSE: Handles initialization of logged-on dialog
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 12-09-91 Davidc Created.
*
\***************************************************************************/
BOOL
LoggedonDlgInit(
HWND hDlg
)
{
PGLOBALS pGlobals = (PGLOBALS)GetWindowLong(hDlg, GWL_USERDATA);
// 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);
SetMapperFlag(hDlg, MAPPERFLAG_WINLOGON);
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: BlockWaitForUserAction
//
// Synopsis: Blocks, waiting for the interactive user to do something, or
// a SAS to come in from the gina.
//
// Effects:
//
// Arguments: [pGlobals] --
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
int
BlockWaitForUserAction(PGLOBALS pGlobals)
{
int res;
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Application);
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
res = WlxDialogBoxParam( pGlobals, pGlobals->hInstance,
MAKEINTRESOURCE(IDD_CONTROL),
NULL,
LoggedonDlgProc,
(LONG) pGlobals) ;
#if DBG
if (res == -1)
{
DebugLog((DEB_ERROR, "Failed to start LoggedOnDlgProc, %d\n", GetLastError()));
}
#endif
return(res);
}
//+---------------------------------------------------------------------------
//
// Function: MainLoop
//
// Synopsis: Main winlogon loop.
//
// Arguments: [pGlobals] --
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
MainLoop(PGLOBALS pGlobals)
{
DWORD WlxResult;
PGINASESSION pGina;
int ScreenSaverResult;
WlxResult = WLX_SAS_ACTION_NONE;
pGina = pGlobals->pGina;
//
// Initialize the gina dll
//
if (!InitializeGinaDll(pGlobals))
{
return;
}
//
// So long as action is none, loop here:
//
while (WlxResult == WLX_SAS_ACTION_NONE)
{
DealWithAutochkLogs();
//
// If no one is logged on, switch to the display state, and call
// the gina to display a message. This is structured this way so
// that a gina can call us immediately during Initialize, and we
// can fall into the loop in the correct state.
//
if (pGlobals->WinlogonState == Winsta_NoOne)
{
pGlobals->WinlogonState = Winsta_NoOne_Display;
DebugLog((DEB_TRACE_STATE, "Setting state to %s\n",
GetState(Winsta_NoOne_Display)));
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_DISPLAY))
{
DebugLog((DEB_TRACE, "About to call WlxDisplaySASNotice(%x)\n",
pGina->pGinaContext));
DebugBreak();
}
#endif
WlxSetTimeout(pGlobals, TIMEOUT_NONE);
pGina->pWlxDisplaySASNotice(pGina->pGinaContext);
//
// If we got a user logoff notify, that means that WE HAVE ALREADY
// SHUT DOWN. A remote shutdown has taken place, and it has been
// started by sysshut.c.
//
if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
{
//
// We are *done*
//
DebugLog(( DEB_TRACE_STATE, "Received Logoff, setting state to %s\n",
GetState(Winsta_Shutdown) ));
pGlobals->WinlogonState = Winsta_Shutdown;
break;
}
//
// If we got a time out,
//
if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
{
//
// run the screen saver
//
ScreenSaverResult = DoScreenSaver( pGlobals, FALSE );
if (ScreenSaverResult < 0)
{
//
// This means that a SAS other than activity cancelled
// the screen saver, such as a GINA specific one.
// In this case, drop on through to the logonattempt,
// since the current sas is in pGlobals.
//
NOTHING ;
}
else
{
if ( ( (ScreenSaverResult == 0) &&
(pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF) ) ||
(ScreenSaverResult == WLX_SAS_ACTION_LOGOFF) )
{
//
// Shutdown during the screen saver.
//
DebugLog(( DEB_TRACE_STATE, "Received Logoff during screensaver, setting state to %s\n",
GetState(Winsta_Shutdown) ));
pGlobals->WinlogonState = Winsta_Shutdown;
break;
}
//
// And start the loop over again.
//
WlxResult = WLX_SAS_ACTION_NONE;
//
// Remember, we're in Winsta_NoOne_Display right now, so we
// reset this so that we'll drop back into this at the top of
// the loop.
//
DebugLog((DEB_TRACE_STATE, "Resetting to %s\n",
GetState(Winsta_NoOne) ));
pGlobals->WinlogonState = Winsta_NoOne;
continue;
}
//
// If we got a user logoff notify, that means that WE HAVE ALREADY
// SHUT DOWN. A remote shutdown has taken place, and it has been
// started by sysshut.c.
//
if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
{
//
// We are *done*
//
DebugLog(( DEB_TRACE_STATE, "Received Logoff during no-one screensaver, setting state to %s\n",
GetState(Winsta_Shutdown) ));
pGlobals->WinlogonState = Winsta_Shutdown;
break;
}
}
}
WlxResult = LogonAttempt(pGlobals);
if (WlxResult == WLX_SAS_ACTION_NONE)
{
//
// If we got a user logoff notify, that means that WE HAVE ALREADY
// SHUT DOWN. A remote shutdown has taken place, and it has been
// started by sysshut.c.
//
if (pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF)
{
//
// We are *done*
//
DebugLog(( DEB_TRACE_STATE, "Got logoff during logon, setting to %s\n",
GetState(Winsta_Shutdown) ));
pGlobals->WinlogonState = Winsta_Shutdown;
break;
}
//
// If we got a time out (meaning a screensaver timeout
// occurred during the logon prompt, then the prompt should be dead,
// but we'll hit here
//
if (pGlobals->SasType == WLX_SAS_TYPE_SCRNSVR_TIMEOUT)
{
//
// run the screen saver
//
ScreenSaverResult = DoScreenSaver(pGlobals, FALSE);
if (ScreenSaverResult < 0)
{
//
// This means that a SAS other than activity cancelled
// the screen saver, such as a GINA specific one.
// In this case, drop on through to the logonattempt,
// since the current sas is in pGlobals.
//
NOTHING ;
}
else
{
if ( (ScreenSaverResult == 0) &&
(pGlobals->SasType == WLX_SAS_TYPE_USER_LOGOFF) )
{
//
// Shutdown during the screen saver.
//
DebugLog(( DEB_TRACE_STATE, "Received Logoff during screensaver, setting state to %s\n",
GetState(Winsta_Shutdown) ));
pGlobals->WinlogonState = Winsta_Shutdown;
break;
}
}
//
// We're already at WlxResult == NONE, and State == NoOne,
// so we can just continue
//
}
//
// Make sure that we're back to NoOne:
//
pGlobals->WinlogonState = Winsta_NoOne;
continue;
}
if (IsShutdownReturn(WlxResult))
{
pGlobals->LastGinaRet = WlxResult;
DebugLog((DEB_TRACE_STATE, "Setting state to %d (%s)\n",
Winsta_WaitForShutdown, GetState(Winsta_WaitForShutdown)));
pGlobals->WinlogonState = Winsta_WaitForShutdown;
break;
}
//
// Because profile or something else could have gone wrong, the gina
// could have returned LOGON, but it was changed to LOGOFF in
// LogonAttempt(). In that case, we don't try and start the shell,
// we just go straight to logoff processing.
//
if (WlxResult == WLX_SAS_ACTION_LOGON)
{
if (DoStartShell(pGlobals))
{
WlxResult = BlockWaitForUserAction(pGlobals);
if (WlxResult == WLX_SAS_ACTION_FORCE_LOGOFF)
{
WaitForForceLogoff(NULL, pGlobals);
WlxResult = WLX_SAS_ACTION_LOGOFF;
}
}
else
{
WlxResult = WLX_SAS_ACTION_LOGOFF;
}
}
EnableSasMessages(NULL);
SetActiveDesktop(&pGlobals->WindowStation, Desktop_Winlogon);
if (pGlobals->WinlogonState == Winsta_Shutdown)
{
break;
}
Logoff(pGlobals, WlxResult);
SecurityChangeUser(pGlobals, NULL, NULL, pGlobals->WinlogonSid, FALSE);
if (WlxResult == WLX_SAS_ACTION_LOGOFF)
{
pGlobals->WinlogonState = Winsta_NoOne;
DebugLog((DEB_TRACE, "WlxResult was logoff, so beginning loop again\n"));
DebugLog((DEB_TRACE_STATE, "State set to %s\n", GetState(Winsta_NoOne)));
WlxResult = WLX_SAS_ACTION_NONE;
}
//
// Notify the GINA that the user is logged off
//
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_LOGOFF))
{
DebugLog((DEB_TRACE, "About to call WlxLogoff(%x)\n", pGina->pGinaContext));
DebugBreak();
}
#endif
pGina->pWlxLogoff(pGina->pGinaContext);
//
// Toggle the winsta lock on and off. This clears the openlock, and
// sets the switchlock, allowing services to start, but no one can
// switch the active desktop.
//
UnlockWindowStation(pGlobals->WindowStation.hwinsta);
LockWindowStation(pGlobals->WindowStation.hwinsta);
#if DBG
if ((WlxResult == WLX_SAS_ACTION_NONE) ||
(WlxResult == WLX_SAS_ACTION_LOGON) ||
(WlxResult == WLX_SAS_ACTION_SHUTDOWN) ||
(WlxResult == WLX_SAS_ACTION_SHUTDOWN_REBOOT) ||
(WlxResult == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) )
{
continue;
}
DebugLog((DEB_TRACE, "WlxResult not acceptible value: %d\n", WlxResult));
DebugLog((DEB_TRACE, "Resetting to WLX_SAS_ACTION_NONE\n"));
WlxResult = WLX_SAS_ACTION_NONE;
#endif
}
}
//+---------------------------------------------------------------------------
//
// Function: LogoffFlagsToWlxCode
//
// Synopsis: Translates a winsrv USER_LOGOFF message flags to a
// wlx return code.
//
// Arguments: [Flags] --
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD
LogoffFlagsToWlxCode(DWORD Flags)
{
if (Flags & EWX_POWEROFF)
{
return(WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
}
if (Flags & EWX_REBOOT)
{
return(WLX_SAS_ACTION_SHUTDOWN_REBOOT);
}
if (Flags & EWX_SHUTDOWN)
{
return(WLX_SAS_ACTION_SHUTDOWN);
}
return(WLX_SAS_ACTION_LOGOFF);
}
//+---------------------------------------------------------------------------
//
// Function: WinsrvNotify
//
// Synopsis: Handles when winsrv talks to us
//
// Arguments: [pGlobals] --
// [SasType] --
//
// Algorithm:
//
// History: 10-17-94 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
WinsrvNotify(
PGLOBALS pGlobals,
DWORD SasType)
{
DWORD RealFlags;
DWORD LogoffResult;
WinstaState PriorState;
//
// If the caller isn't system, and no-one is logged on, discard this message.
//
if (!(pGlobals->LogoffFlags & EWX_SYSTEM_CALLER) && !pGlobals->UserLoggedOn)
{
DebugLog((DEB_TRACE, "Discarding notice from winsrv!\n"));
return;
}
//
// If this indicates that winlogon initiated this message (by calling
// InitiateLogoff() somewhere else, or we're in a wait state, then pass
// the message along. This is what will kill our LoggedOnDlg.
//
if ((pGlobals->LogoffFlags & EWX_WINLOGON_CALLER) ||
(pGlobals->WinlogonState == Winsta_WaitForLogoff) ||
(pGlobals->WinlogonState == Winsta_WaitForShutdown) ||
(pGlobals->WinlogonState == Winsta_InShutdownDlg) )
{
SASRouter(pGlobals, SasType);
RealFlags = RealFlagsFromStoredFlags(pGlobals->LogoffFlags);
pGlobals->LastGinaRet = LogoffFlagsToWlxCode(RealFlags);
return;
}
//
// Well, this means that the user has called ExitWindowsEx(), and winsrv
// has passed the ball to us. We have to turn around and ask the gina if
// logoff is ok. This is convenient for some security architectures. I
// guess.
//
#if DBG
if (TEST_FLAG(GinaBreakFlags, BREAK_ISLOGOFFOK))
{
DebugLog((DEB_TRACE, "About to call WlxIsLogoffOk(%#x)\n", pGlobals->pGina->pGinaContext));
DebugBreak();
}
#endif
if (!pGlobals->pGina->pWlxIsLogoffOk(pGlobals->pGina->pGinaContext))
{
DebugLog((DEB_TRACE, "Gina said no logoff...\n"));
return;
}
//
// Well, if we're not in a wait state, then initiate logoff and possibly
// shutdown. Convoluted, right?
//
if ((pGlobals->WinlogonState != Winsta_WaitForLogoff) &&
(pGlobals->WinlogonState != Winsta_WaitForShutdown) &&
(pGlobals->WinlogonState != Winsta_InShutdownDlg) )
{
PriorState = pGlobals->WinlogonState;
pGlobals->WinlogonState = Winsta_WaitForLogoff;
DebugLog((DEB_TRACE_STATE, "WinsrvNotify: Setting state to %s\n",
GetState(Winsta_WaitForLogoff)));
pGlobals->LastGinaRet = LogoffFlagsToWlxCode(pGlobals->LogoffFlags);
DebugLog((DEB_TRACE, "Setting lastginaret to %s\n",
WlxName(pGlobals->LastGinaRet)));
LogoffResult = InitiateLogoff( pGlobals,
(pGlobals->LogoffFlags & EWX_FORCE) |
StoredFlagsFromRealFlags(pGlobals->LogoffFlags)
);
if (LogoffResult == DLG_FAILURE)
{
DebugLog((DEB_TRACE, "Logoff refused, resetting\n"));
pGlobals->WinlogonState = PriorState;
DebugLog((DEB_TRACE_STATE, "WinsrvNotify: resetting state back to %s\n",
GetState(PriorState)));
}
}
}