Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1009 lines
34 KiB

// --------------------------------------------------------------------------
// Module Name: ReturnToWelcome.cpp
//
// Copyright (c) 2001, Microsoft Corporation
//
// File to handle return to welcome.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
#include "StandardHeader.h"
#include "ReturnToWelcome.h"
#include <ginaipc.h>
#include <ginarcid.h>
#include <msginaexports.h>
#include <winsta.h>
#include <winwlx.h>
#include "Access.h"
#include "Compatibility.h"
#include "CredentialTransfer.h"
#include "StatusCode.h"
#include "SystemSettings.h"
#include "TokenInformation.h"
// --------------------------------------------------------------------------
// CReturnToWelcome::s_pWlxContext
// CReturnToWelcome::s_hEventRequest
// CReturnToWelcome::s_hEventShown
// CReturnToWelcome::s_hWait
// CReturnToWelcome::s_szEventName
// CReturnToWelcome::s_dwSessionID
//
// Purpose: Static member variables.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
void* CReturnToWelcome::s_pWlxContext = NULL;
HANDLE CReturnToWelcome::s_hEventRequest = NULL;
HANDLE CReturnToWelcome::s_hEventShown = NULL;
HANDLE CReturnToWelcome::s_hWait = NULL;
const TCHAR CReturnToWelcome::s_szEventName[] = TEXT("msgina: ReturnToWelcome");
DWORD CReturnToWelcome::s_dwSessionID = static_cast<DWORD>(-1);
// --------------------------------------------------------------------------
// CReturnToWelcome::CReturnToWelcome
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Constructor for CReturnToWelcome.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
CReturnToWelcome::CReturnToWelcome (void) :
_hToken(NULL),
_pLogonIPCCredentials(NULL),
_fUnlock(false),
_fDialogEnded(false)
{
}
// --------------------------------------------------------------------------
// CReturnToWelcome::~CReturnToWelcome
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Destructor for CReturnToWelcome.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
CReturnToWelcome::~CReturnToWelcome (void)
{
ReleaseMemory(_pLogonIPCCredentials);
ReleaseHandle(_hToken);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::Show
//
// Arguments: fUnlock = Required to unlock logon mode or not?
//
// Returns: INT_PTR
//
// Purpose: Presents the welcome screen with a logged on user. This is a
// special case to increase performance by not performing
// needless console disconnects and reconnects.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
INT_PTR CReturnToWelcome::Show (bool fUnlock)
{
INT_PTR iResult;
_fUnlock = fUnlock;
// If there was a reconnect failure then show it before showing the UI host.
if (s_dwSessionID != static_cast<DWORD>(-1))
{
ShowReconnectFailure(s_dwSessionID);
s_dwSessionID = static_cast<DWORD>(-1);
}
// Start the status host.
_Shell_LogonStatus_Init(HOST_START_NORMAL);
// Disable input timeouts on this dialog.
TBOOL(_Gina_SetTimeout(s_pWlxContext, 0));
// Use the DS component of msgina to display the dialog. It's a stub
// dialog that pretends to be WlxLoggedOutSAS but really isn't.
iResult = _Gina_DialogBoxParam(s_pWlxContext,
hDllInstance,
MAKEINTRESOURCE(IDD_GINA_RETURNTOWELCOME),
NULL,
CB_DialogProc,
reinterpret_cast<LPARAM>(this));
// The dialog has been shown. Release the CB_Request thread to
// re-register the wait on the switch user event.
if (s_hEventShown != NULL)
{
TBOOL(SetEvent(s_hEventShown));
}
// Handle MSGINA_DLG_SWITCH_CONSOLE and map this to WLX_SAS_ACTION_LOGON.
// This is an authenticated logon from a different session causing
// this one to get disconnected.
if (iResult == MSGINA_DLG_SWITCH_CONSOLE)
{
iResult = WLX_SAS_ACTION_LOGON;
}
// Look at the return code and respond accordingly. Map power button
// actions to the appropriate WLX_SAS_ACTION_SHUTDOWN_xxx.
else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_REBOOT_FLAG))
{
iResult = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
}
else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SHUTDOWN_FLAG))
{
iResult = WLX_SAS_ACTION_SHUTDOWN;
}
else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_POWEROFF_FLAG))
{
iResult = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
}
else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_HIBERNATE_FLAG))
{
iResult = WLX_SAS_ACTION_SHUTDOWN_HIBERNATE;
}
else if (iResult == (MSGINA_DLG_SHUTDOWN | MSGINA_DLG_SLEEP_FLAG))
{
iResult = WLX_SAS_ACTION_SHUTDOWN_SLEEP;
}
else if (iResult == MSGINA_DLG_LOCK_WORKSTATION)
{
iResult = WLX_SAS_ACTION_LOCK_WKSTA;
}
else if (iResult == WLX_DLG_USER_LOGOFF)
{
iResult = WLX_SAS_ACTION_LOGOFF;
}
else if (iResult == MSGINA_DLG_SUCCESS)
{
PSID pSIDNew;
pSIDNew = NULL;
if (_hToken != NULL)
{
PSID pSID;
CTokenInformation tokenInformationNew(_hToken);
pSID = tokenInformationNew.GetUserSID();
if (pSID != NULL)
{
DWORD dwSIDSize;
dwSIDSize = GetLengthSid(pSID);
pSIDNew = LocalAlloc(LMEM_FIXED, dwSIDSize);
if (pSIDNew != NULL)
{
TBOOL(CopySid(dwSIDSize, pSIDNew, pSID));
}
}
}
if (pSIDNew == NULL)
{
DWORD dwSIDSize, dwDomainSize;
SID_NAME_USE sidNameUse;
WCHAR *pszDomain;
dwSIDSize = dwDomainSize = 0;
(BOOL)LookupAccountNameW(NULL,
_pLogonIPCCredentials->userID.wszUsername,
NULL,
&dwSIDSize,
NULL,
&dwDomainSize,
&sidNameUse);
pszDomain = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, dwDomainSize * sizeof(WCHAR)));
if (pszDomain != NULL)
{
pSIDNew = LocalAlloc(LMEM_FIXED, dwSIDSize);
if (pSIDNew != NULL)
{
if (LookupAccountNameW(NULL,
_pLogonIPCCredentials->userID.wszUsername,
pSIDNew,
&dwSIDSize,
pszDomain,
&dwDomainSize,
&sidNameUse) == FALSE)
{
(HLOCAL)LocalFree(pSIDNew);
pSIDNew = NULL;
}
}
(HLOCAL)LocalFree(pszDomain);
}
}
if (pSIDNew != NULL)
{
// If the dialog succeeded then a user was authenticated.
if (IsSameUser(pSIDNew, _Gina_GetUserToken(s_pWlxContext)))
{
// If it's the same user then there's no disconnect or reconnect
// required. We're done. Return back to the user's desktop.
iResult = WLX_SAS_ACTION_LOGON;
}
else
{
DWORD dwSessionID;
// Assume something will fail. The return code
// MSGINA_DLG_SWITCH_FAILURE is a special message back to
// winlogon!HandleSwitchUser to signal that a
// reconnect/disconnect of some kind failed and that the
// welcome screen needs to be re-displayed along with an
// appropriate error message.
iResult = MSGINA_DLG_SWITCH_FAILURE;
if (UserIsDisconnected(pSIDNew, &dwSessionID))
{
// If the user is a disconnected user then reconnect back to
// their session. If this succeeds then we're done.
if (WinStationConnect(SERVERNAME_CURRENT,
dwSessionID,
NtCurrentPeb()->SessionId,
L"",
TRUE) != FALSE)
{
CCompatibility::MinimizeWindowsOnDisconnect();
CCompatibility::DropSessionProcessesWorkingSets();
iResult = WLX_SAS_ACTION_LOGON;
}
else
{
// If it fails then stash this information globally.
// The return code MSGINA_DLG_SWITCH_FAILURE will cause
// us to get called again and this will be checked, used
// and reset.
s_dwSessionID = dwSessionID;
}
}
else
{
// Otherwise credentials need to be transferred across sessions to
// a newly created session. Start the credential transfer server.
if (NT_SUCCESS(CCredentialServer::Start(_pLogonIPCCredentials, 0)))
{
CCompatibility::MinimizeWindowsOnDisconnect();
CCompatibility::DropSessionProcessesWorkingSets();
iResult = WLX_SAS_ACTION_LOGON;
}
}
}
(HLOCAL)LocalFree(pSIDNew);
}
else
{
iResult = MSGINA_DLG_SWITCH_FAILURE;
s_dwSessionID = NtCurrentPeb()->SessionId;
}
}
else
{
// If the dialog failed then do nothing. This will force a loop back
// to the present the welcome screen again until authentication.
iResult = WLX_SAS_ACTION_NONE;
}
if ((iResult == WLX_SAS_ACTION_LOGON) || (iResult == WLX_SAS_ACTION_NONE) || (iResult == MSGINA_DLG_SWITCH_FAILURE))
{
_Shell_LogonStatus_Destroy(HOST_END_HIDE);
}
return(iResult);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::GetEventName
//
// Arguments: <none>
//
// Returns: const WCHAR*
//
// Purpose: Returns the name of the event to return to welcome. Signal
// this event and you'll get a return to welcome.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
const WCHAR* CReturnToWelcome::GetEventName (void)
{
return(s_szEventName);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::StaticInitialize
//
// Arguments: pWlxContext = PGLOBALS struct for msgina.
//
// Returns: NTSTATUS
//
// Purpose: Creates a named event and ACL's it so that anybody can signal
// it but only S-1-5-18 (NT AUTHORITY\SYSTEM) or S-1-5-32-544
// (local administrators) can synchronize to it. Then register a
// wait on this object.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
NTSTATUS CReturnToWelcome::StaticInitialize (void *pWlxContext)
{
NTSTATUS status;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
SECURITY_ATTRIBUTES securityAttributes;
ASSERTMSG(s_pWlxContext == NULL, "Non NULL pWlxContext in CReturnToWelcome::StaticInitialize");
ASSERTMSG(s_hEventRequest == NULL, "Non NULL request event in CReturnToWelcome::StaticInitialize");
s_pWlxContext = pWlxContext;
// Build a security descriptor for the event that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM EVENT_ALL_ACCESS
// S-1-5-32-544 <local administrators> READ_CONTROL | SYNCHRONIZE | EVENT_MODIFY_STATE
// S-1-1-0 <everybody> EVENT_MODIFY_STATE
static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
static SID_IDENTIFIER_AUTHORITY s_SecurityWorldSID = SECURITY_WORLD_SID_AUTHORITY;
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
{
{
&s_SecurityNTAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
EVENT_ALL_ACCESS
},
{
&s_SecurityNTAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
READ_CONTROL | SYNCHRONIZE | EVENT_MODIFY_STATE
},
{
&s_SecurityWorldSID,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
EVENT_MODIFY_STATE
}
};
// Build a security descriptor that allows the described access above.
pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
if (pSecurityDescriptor != NULL)
{
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
securityAttributes.bInheritHandle = FALSE;
s_hEventRequest = CreateEvent(&securityAttributes, TRUE, FALSE, GetEventName());
if (s_hEventRequest != NULL)
{
s_hEventShown = CreateEvent(NULL, FALSE, FALSE, NULL);
if (s_hEventShown != NULL)
{
status = RegisterWaitForRequest();
}
else
{
status = CStatusCode::StatusCodeOfLastError();
}
}
else
{
status = CStatusCode::StatusCodeOfLastError();
}
ReleaseMemory(pSecurityDescriptor);
}
else
{
status = STATUS_NO_MEMORY;
}
// Initialize the last failed connect session ID.
s_dwSessionID = static_cast<DWORD>(-1);
return(status);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::StaticTerminate
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Unregisters the wait on the named event and releases
// associated resources.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
NTSTATUS CReturnToWelcome::StaticTerminate (void)
{
HANDLE hWait;
hWait = InterlockedExchangePointer(&s_hWait, NULL);
if (hWait != NULL)
{
(BOOL)UnregisterWait(hWait);
}
ReleaseHandle(s_hEventShown);
ReleaseHandle(s_hEventRequest);
s_pWlxContext = NULL;
return(STATUS_SUCCESS);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::IsSameUser
//
// Arguments: hToken = Token of the user for the current session.
//
// Returns: bool
//
// Purpose: Compares the token of the user for the current session with
// the token of the user who just authenticated. If the user is
// the same (compared by user SID not logon SID) then this is
// effectively a re-authentication. This will switch back.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
bool CReturnToWelcome::IsSameUser (PSID pSIDUser, HANDLE hToken) const
{
bool fResult;
if (hToken != NULL)
{
PSID pSIDCompare;
CTokenInformation tokenInformationCompare(hToken);
pSIDCompare = tokenInformationCompare.GetUserSID();
fResult = ((pSIDUser != NULL) &&
(pSIDCompare != NULL) &&
(EqualSid(pSIDUser, pSIDCompare) != FALSE));
}
else
{
fResult = false;
}
return(fResult);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::UserIsDisconnected
//
// Arguments: pdwSessionID = Session ID returned of found user.
//
// Returns: bool
//
// Purpose: Searches the list of disconnected sessions for the given
// matching user SID. Retrieve the user token for each
// disconnected window station and when a match is found return
// that session ID and a result back to the caller.
//
// History: 2001-01-12 vtan created
// --------------------------------------------------------------------------
bool CReturnToWelcome::UserIsDisconnected (PSID pSIDUser, DWORD *pdwSessionID) const
{
bool fResult;
PLOGONID pLogonIDs;
ULONG ulEntries;
fResult = false;
if (WinStationEnumerate(SERVERNAME_CURRENT, &pLogonIDs, &ulEntries) != FALSE)
{
ULONG ulIndex;
PLOGONID pLogonID;
for (ulIndex = 0, pLogonID = pLogonIDs; !fResult && (ulIndex < ulEntries); ++ulIndex, ++pLogonID)
{
if (pLogonID->State == State_Disconnected)
{
ULONG ulReturnLength;
WINSTATIONUSERTOKEN winStationUserToken;
winStationUserToken.ProcessId = ULongToHandle(GetCurrentProcessId());
winStationUserToken.ThreadId = ULongToHandle(GetCurrentThreadId());
winStationUserToken.UserToken = NULL;
if (WinStationQueryInformation(SERVERNAME_CURRENT,
pLogonID->SessionId,
WinStationUserToken,
&winStationUserToken,
sizeof(winStationUserToken),
&ulReturnLength) != FALSE)
{
fResult = IsSameUser(pSIDUser, winStationUserToken.UserToken);
if (fResult)
{
*pdwSessionID = pLogonID->SessionId;
}
TBOOL(CloseHandle(winStationUserToken.UserToken));
}
}
}
// Free any resources used.
(BOOLEAN)WinStationFreeMemory(pLogonIDs);
}
return(fResult);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::GetSessionUserName
//
// Arguments: dwSessionID = Session ID of user name to get.
// pszBuffer = UNLEN character buffer to use.
//
// Returns: <none>
//
// Purpose: Retrieves the display name of the user for the given session.
// The buffer must be at least UNLEN + sizeof('\0') characters.
//
// History: 2001-03-02 vtan created
// --------------------------------------------------------------------------
void CReturnToWelcome::GetSessionUserName (DWORD dwSessionID, WCHAR *pszBuffer)
{
ULONG ulReturnLength;
WINSTATIONINFORMATIONW winStationInformation;
// Ask terminal server for the user name of the session.
if (WinStationQueryInformationW(SERVERNAME_CURRENT,
dwSessionID,
WinStationInformation,
&winStationInformation,
sizeof(winStationInformation),
&ulReturnLength) != FALSE)
{
USER_INFO_2 *pUI2;
// Convert the user name to a display name.
if (NERR_Success == NetUserGetInfo(NULL,
winStationInformation.UserName,
2,
reinterpret_cast<LPBYTE*>(&pUI2)))
{
const WCHAR *pszName;
// Use the display name if it exists and isn't empty.
// Otherwise use the logon name.
if ((pUI2->usri2_full_name != NULL) && (pUI2->usri2_full_name[0] != L'\0'))
{
pszName = pUI2->usri2_full_name;
}
else
{
pszName = winStationInformation.UserName;
}
(WCHAR*)lstrcpyW(pszBuffer, pszName);
(NET_API_STATUS)NetApiBufferFree(pUI2);
}
}
}
// --------------------------------------------------------------------------
// CReturnToWelcome::ShowReconnectFailure
//
// Arguments: dwSessionID = Session that failed reconnection.
//
// Returns: <none>
//
// Purpose: Shows a message box indicating that the reconnection failed.
// The message box times out in 120 seconds.
//
// History: 2001-03-02 vtan created
// --------------------------------------------------------------------------
void CReturnToWelcome::ShowReconnectFailure (DWORD dwSessionID)
{
static const int BUFFER_SIZE = 256;
WCHAR *pszText;
pszText = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(WCHAR)));
if (pszText != NULL)
{
WCHAR *pszCaption;
pszCaption = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, BUFFER_SIZE * sizeof(WCHAR)));
if (pszCaption != NULL)
{
WCHAR *pszUsername;
pszUsername = static_cast<WCHAR*>(LocalAlloc(LMEM_FIXED, (UNLEN + sizeof('\0')) * sizeof(WCHAR)));
if (pszUsername != NULL)
{
GetSessionUserName(dwSessionID, pszUsername);
if (LoadString(hDllInstance,
IDS_RECONNECT_FAILURE,
pszCaption,
BUFFER_SIZE) != 0)
{
wsprintf(pszText, pszCaption, pszUsername);
if (LoadString(hDllInstance,
IDS_GENERIC_CAPTION,
pszCaption,
BUFFER_SIZE) != 0)
{
TBOOL(_Gina_SetTimeout(s_pWlxContext, LOGON_TIMEOUT));
(int)_Gina_MessageBox(s_pWlxContext,
NULL,
pszText,
pszCaption,
MB_OK | MB_ICONHAND);
}
}
(HLOCAL)LocalFree(pszUsername);
}
(HLOCAL)LocalFree(pszCaption);
}
(HLOCAL)LocalFree(pszText);
}
}
// --------------------------------------------------------------------------
// CReturnToWelcome::EndDialog
//
// Arguments: hwnd = HWND of dialog.
// iResult = Result to end dialog with.
//
// Returns: <none>
//
// Purpose: Ends the dialog. Marks the member variable to prevent
// re-entrancy.
//
// History: 2001-03-04 vtan created
// --------------------------------------------------------------------------
void CReturnToWelcome::EndDialog (HWND hwnd, INT_PTR iResult)
{
_fDialogEnded = true;
TBOOL(::EndDialog(hwnd, iResult));
}
// --------------------------------------------------------------------------
// CReturnToWelcome::Handle_WM_INITDIALOG
//
// Arguments: hwndDialog = HWND of the dialog.
//
// Returns: <none>
//
// Purpose: Handles WM_INITDIALOG. Brings up the friendly logon screen.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
void CReturnToWelcome::Handle_WM_INITDIALOG (HWND hwndDialog)
{
switch (_Shell_LogonDialog_Init(hwndDialog, _fUnlock ? SHELL_LOGONDIALOG_RETURNTOWELCOME_UNLOCK : SHELL_LOGONDIALOG_RETURNTOWELCOME))
{
case SHELL_LOGONDIALOG_LOGON:
case SHELL_LOGONDIALOG_NONE:
default:
{
// If it's anything but external host then something went wrong.
// Return MSGINA_DLG_LOCK_WORKSTATION to use the old method.
EndDialog(hwndDialog, MSGINA_DLG_LOCK_WORKSTATION);
break;
}
case SHELL_LOGONDIALOG_EXTERNALHOST:
{
break;
}
}
}
// --------------------------------------------------------------------------
// CReturnToWelcome::Handle_WM_DESTROY
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Handles WM_DESTROY. Destroys the welcome logon screen.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
void CReturnToWelcome::Handle_WM_DESTROY (void)
{
_ShellReleaseLogonMutex(FALSE);
_Shell_LogonDialog_Destroy();
}
// --------------------------------------------------------------------------
// CReturnToWelcome::Handle_WM_COMMAND
//
// Arguments: See the platform SDK under DialogProc.
//
// Returns: bool
//
// Purpose: Handles WM_COMMAND. Handles IDOK and IDCANCEL. IDOK means a
// logon request is made. IDCANCEL is special cased to take the
// LPARAM and use it as a LOGONIPC_CREDENTIALS for IDOK.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
bool CReturnToWelcome::Handle_WM_COMMAND (HWND hwndDialog, WPARAM wParam, LPARAM lParam)
{
bool fResult;
switch (wParam)
{
case IDOK:
{
bool fSuccessfulLogon;
const WCHAR *pszUsername, *pszDomain, *pszPassword;
// If credentials were successfully allocated then
// use them. Attempt to log the user on.
if (_pLogonIPCCredentials != NULL)
{
pszUsername = _pLogonIPCCredentials->userID.wszUsername;
pszDomain = _pLogonIPCCredentials->userID.wszDomain;
pszPassword = _pLogonIPCCredentials->wszPassword;
fSuccessfulLogon = (CTokenInformation::LogonUser(_pLogonIPCCredentials->userID.wszUsername,
_pLogonIPCCredentials->userID.wszDomain,
_pLogonIPCCredentials->wszPassword,
&_hToken) == ERROR_SUCCESS);
}
else
{
// Otherwise - no credentials - no logon.
pszUsername = pszDomain = pszPassword = NULL;
fSuccessfulLogon = false;
}
// Tell the logon component the result.
_Shell_LogonDialog_LogonCompleted(fSuccessfulLogon ? MSGINA_DLG_SUCCESS : MSGINA_DLG_FAILURE,
pszUsername,
pszDomain);
// And if successful then end the dialog with success code.
if (fSuccessfulLogon)
{
EndDialog(hwndDialog, MSGINA_DLG_SUCCESS);
}
fResult = true;
break;
}
case IDCANCEL:
// IDCANCEL: Take the LPARAM and treat it as a LOGONIPC_CREDENTIALS struct.
// Allocate memory for this and copy the structure.
_pLogonIPCCredentials = static_cast<LOGONIPC_CREDENTIALS*>(LocalAlloc(LMEM_FIXED, sizeof(LOGONIPC_CREDENTIALS)));
if ((_pLogonIPCCredentials != NULL) && (lParam != NULL))
{
*_pLogonIPCCredentials = *reinterpret_cast<LOGONIPC_CREDENTIALS*>(lParam);
}
fResult = true;
break;
default:
fResult = false;
break;
}
return(fResult);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::CB_DialogProc
//
// Arguments: See the platform SDK under DialogProc.
//
// Returns: INT_PTR
//
// Purpose: DialogProc for the return to welcome stub dialog. This handles
// WM_INITDIALOG, WM_DESTROY, WM_COMMAND and WLX_WM_SAS.
// WM_COMMAND is a request from the logon host. WLX_WM_SAS is a
// SAS from the logon process.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
INT_PTR CReturnToWelcome::CB_DialogProc (HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR iResult;
CReturnToWelcome *pThis;
pThis = reinterpret_cast<CReturnToWelcome*>(GetWindowLongPtr(hwndDialog, GWLP_USERDATA));
switch (uMsg)
{
case WM_INITDIALOG:
pThis = reinterpret_cast<CReturnToWelcome*>(lParam);
(LONG_PTR)SetWindowLongPtr(hwndDialog, GWLP_USERDATA, lParam);
pThis->Handle_WM_INITDIALOG(hwndDialog);
iResult = FALSE;
break;
case WM_DESTROY:
pThis->Handle_WM_DESTROY();
(LONG_PTR)SetWindowLongPtr(hwndDialog, GWLP_USERDATA, 0);
iResult = TRUE;
break;
case WM_COMMAND:
iResult = pThis->Handle_WM_COMMAND(hwndDialog, wParam, lParam);
break;
case WLX_WM_SAS:
(BOOL)_Shell_LogonDialog_DlgProc(hwndDialog, uMsg, wParam, lParam);
// If the SAS type is authenticated then end the return to welcome
// dialog and return to the caller MSGINA_DLG_SWITCH_CONSOLE.
if (wParam == WLX_SAS_TYPE_AUTHENTICATED)
{
pThis->EndDialog(hwndDialog, MSGINA_DLG_SWITCH_CONSOLE);
}
iResult = ((wParam != WLX_SAS_TYPE_TIMEOUT) && (wParam != WLX_SAS_TYPE_SCRNSVR_TIMEOUT));
break;
default:
if ((pThis != NULL) && !pThis->_fDialogEnded && !CSystemSettings::IsActiveConsoleSession())
{
pThis->EndDialog(hwndDialog, MSGINA_DLG_SWITCH_CONSOLE);
iResult = TRUE;
}
else
{
iResult = _Shell_LogonDialog_DlgProc(hwndDialog, uMsg, wParam, lParam);
}
break;
}
return(iResult);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::RegisterWaitForRequest
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Register a wait for the named event being signaled.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
NTSTATUS CReturnToWelcome::RegisterWaitForRequest (void)
{
NTSTATUS status;
if (s_hEventRequest != NULL)
{
ASSERTMSG(s_hWait == NULL, "Non NULL wait in CReturnToWelcome::RegisterWaitForRequest");
if (RegisterWaitForSingleObject(&s_hWait,
s_hEventRequest,
CB_Request,
NULL,
INFINITE,
WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE) != FALSE)
{
status = STATUS_SUCCESS;
}
else
{
status = CStatusCode::StatusCodeOfLastError();
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
return(status);
}
// --------------------------------------------------------------------------
// CReturnToWelcome::CB_Request
//
// Arguments: pParameter = User parameter.
// TimerOrWaitFired = Timer or wait fired.
//
// Returns: <none>
//
// Purpose: Callback invoked when ShellSwitchUser signals the named event.
//
// History: 2001-01-11 vtan created
// --------------------------------------------------------------------------
void CALLBACK CReturnToWelcome::CB_Request (void *pParameter, BOOLEAN TimerOrWaitFired)
{
UNREFERENCED_PARAMETER(pParameter);
UNREFERENCED_PARAMETER(TimerOrWaitFired);
HANDLE hWait;
// Unregister the wait if we can grab the wait.
hWait = InterlockedExchangePointer(&s_hWait, NULL);
if (hWait != NULL)
{
(BOOL)UnregisterWait(hWait);
}
// Send the SAS type WLX_SAS_TYPE_SWITCHUSER only if the workstation
// is the active console session. This API won't be called on PTS.
if (CSystemSettings::IsActiveConsoleSession() && CSystemSettings::IsFriendlyUIActive())
{
// Reset the shown event. When CReturnToWelcome::Show has shown the
// dialog it will set this event which will allow us to re-register
// a wait on the switch user event. This prevents multiple SAS events
// of type WLX_SAS_TYPE_SWITCHUSER being posted to the SAS window.
TBOOL(ResetEvent(s_hEventShown));
_Gina_SasNotify(s_pWlxContext, WLX_SAS_TYPE_SWITCHUSER);
(DWORD)WaitForSingleObject(s_hEventShown, INFINITE);
}
// Reset the event.
TBOOL(ResetEvent(s_hEventRequest));
// Reregister the wait.
TSTATUS(RegisterWaitForRequest());
}