windows-nt/Source/XPSP1/NT/shell/ext/gina/logonmutex.cpp
2020-09-26 16:20:57 +08:00

454 lines
14 KiB
C++

// --------------------------------------------------------------------------
// Module Name: LogonMutex.cpp
//
// Copyright (c) 2001, Microsoft Corporation
//
// File that implements a class that manages a single global logon mutex.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
#include "StandardHeader.h"
#include "LogonMutex.h"
#include <msginaexports.h>
#include "Access.h"
#include "SystemSettings.h"
DWORD CLogonMutex::s_dwThreadID = 0;
LONG CLogonMutex::s_lAcquireCount = 0;
HANDLE CLogonMutex::s_hMutex = NULL;
HANDLE CLogonMutex::s_hMutexRequest = NULL;
HANDLE CLogonMutex::s_hEvent = NULL;
const TCHAR CLogonMutex::s_szLogonMutexName[] = SZ_INTERACTIVE_LOGON_MUTEX_NAME;
const TCHAR CLogonMutex::s_szLogonRequestMutexName[] = SZ_INTERACTIVE_LOGON_REQUEST_MUTEX_NAME;
const TCHAR CLogonMutex::s_szLogonReplyEventName[] = SZ_INTERACTIVE_LOGON_REPLY_EVENT_NAME;
const TCHAR CLogonMutex::s_szShutdownEventName[] = SZ_SHUT_DOWN_EVENT_NAME;
SID_IDENTIFIER_AUTHORITY CLogonMutex::s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY CLogonMutex::s_SecurityWorldSID = SECURITY_WORLD_SID_AUTHORITY;
// --------------------------------------------------------------------------
// CLogonMutex::Acquire
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Acquires the mutex. Ensures that the mutex is only acquired
// on the main thread of winlogon by an assert. The mutex should
// never be abandoned within normal execution. However, a
// process termination can cause this to happen.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::Acquire (void)
{
DWORD dwWaitResult;
ASSERTMSG((s_dwThreadID == 0) || (s_dwThreadID == GetCurrentThreadId()), "Must acquire mutex on initializing thread in CLogonMutex::Acquire");
if ((s_hMutex != NULL) && (WAIT_TIMEOUT == WaitForSingleObject(s_hEvent, 0)))
{
ASSERTMSG(s_lAcquireCount == 0, "Mutex already owned in CLogonMutex::Acquire");
dwWaitResult = WaitForSingleObject(s_hMutex, INFINITE);
++s_lAcquireCount;
}
}
// --------------------------------------------------------------------------
// CLogonMutex::Release
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Releases the mutex. Again makes sure the caller is the main
// thread of winlogon. The acquisitions and releases are
// reference counted to allow unbalanced release calls to be
// made.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::Release (void)
{
ASSERTMSG((s_dwThreadID == 0) || (s_dwThreadID == GetCurrentThreadId()), "Must acquire mutex on initializing thread in CLogonMutex::Release");
if ((s_hMutex != NULL) && (s_lAcquireCount > 0))
{
TBOOL(ReleaseMutex(s_hMutex));
--s_lAcquireCount;
}
}
// --------------------------------------------------------------------------
// CLogonMutex::SignalReply
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Open the global logon reply event and signal it.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::SignalReply (void)
{
HANDLE hEvent;
hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, s_szLogonReplyEventName);
if (hEvent != NULL)
{
TBOOL(SetEvent(hEvent));
TBOOL(CloseHandle(hEvent));
}
}
// --------------------------------------------------------------------------
// CLogonMutex::SignalShutdown
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Signal the global shut down event. This will prevent further
// interactive requests from being processed.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::SignalShutdown (void)
{
if (s_hEvent != NULL)
{
TBOOL(SetEvent(s_hEvent));
}
}
// --------------------------------------------------------------------------
// CLogonMutex::StaticInitialize
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Initializes the logon mutex objects based on whether this is
// session 0 or higher and or what the product type is. Because
// the initialization for session is done only the once this
// requires a machine restart for the objects to be created.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::StaticInitialize (void)
{
// Check the machine settings. Must be friendly UI and PER/PRO (FUS).
if (CSystemSettings::IsFriendlyUIActive() && CSystemSettings::IsMultipleUsersEnabled() && CSystemSettings::IsWorkStationProduct())
{
DWORD dwErrorCode;
s_dwThreadID = GetCurrentThreadId();
s_lAcquireCount = 0;
// On session 0 create the objects and ACL them.
if (NtCurrentPeb()->SessionId == 0)
{
s_hEvent = CreateShutdownEvent();
if (s_hEvent != NULL)
{
s_hMutex = CreateLogonMutex();
if (s_hMutex != NULL)
{
s_hMutexRequest = CreateLogonRequestMutex();
if (s_hMutexRequest != NULL)
{
Acquire();
dwErrorCode = ERROR_SUCCESS;
}
else
{
dwErrorCode = GetLastError();
}
}
else
{
dwErrorCode = GetLastError();
}
}
else
{
dwErrorCode = GetLastError();
}
}
else
{
// For sessions other than 0 open the objects.
s_hEvent = OpenShutdownEvent();
if (s_hEvent != NULL)
{
if (WAIT_TIMEOUT == WaitForSingleObject(s_hEvent, 0))
{
s_hMutex = OpenLogonMutex();
if (s_hMutex != NULL)
{
Acquire();
dwErrorCode = ERROR_SUCCESS;
}
else
{
dwErrorCode = GetLastError();
}
}
else
{
dwErrorCode = ERROR_SHUTDOWN_IN_PROGRESS;
}
}
else
{
dwErrorCode = GetLastError();
}
}
if (ERROR_SUCCESS == dwErrorCode)
{
ASSERTMSG(s_hMutex != NULL, "NULL s_hMutex in CLogonMutex::StaticInitialize");
ASSERTMSG(s_hEvent != NULL, "NULL s_hEvent in CLogonMutex::StaticInitialize");
}
else
{
ReleaseHandle(s_hEvent);
ReleaseHandle(s_hMutex);
s_dwThreadID = 0;
}
}
else
{
s_dwThreadID = 0;
s_lAcquireCount = 0;
s_hMutex = NULL;
s_hEvent = NULL;
}
}
// --------------------------------------------------------------------------
// CLogonMutex::StaticTerminate
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Releases the mutex if held and closes the object handle.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
void CLogonMutex::StaticTerminate (void)
{
Release();
ASSERTMSG(s_lAcquireCount == 0, "Mutex not released in CLogonMutex::StaticTerminate");
ReleaseHandle(s_hMutex);
}
// --------------------------------------------------------------------------
// CLogonMutex::CreateShutdownEvent
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Creates the global shut down event. ACL'd so that anybody can
// synchronize against it and therefore listen but only SYSTEM
// can set it to indicate machine shut down has begun.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
HANDLE CLogonMutex::CreateShutdownEvent (void)
{
HANDLE hEvent;
SECURITY_ATTRIBUTES securityAttributes;
// 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
// S-1-1-0 <everybody> SYNCHRONIZE
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
},
{
&s_SecurityWorldSID,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
SYNCHRONIZE
}
};
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
securityAttributes.bInheritHandle = FALSE;
hEvent = CreateEvent(&securityAttributes, TRUE, FALSE, s_szShutdownEventName);
if (securityAttributes.lpSecurityDescriptor != NULL)
{
(HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
}
return(hEvent);
}
// --------------------------------------------------------------------------
// CLogonMutex::CreateLogonMutex
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Creates the global logon mutex. ACL'd so that only SYSTEM can
// acquire and release the mutex. This is not for user
// consumption.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
HANDLE CLogonMutex::CreateLogonMutex (void)
{
HANDLE hMutex;
SECURITY_ATTRIBUTES securityAttributes;
// Build a security descriptor for the mutex that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM MUTEX_ALL_ACCESS
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
{
{
&s_SecurityNTAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
MUTEX_ALL_ACCESS
}
};
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
securityAttributes.bInheritHandle = FALSE;
hMutex = CreateMutex(&securityAttributes, FALSE, s_szLogonMutexName);
if (securityAttributes.lpSecurityDescriptor != NULL)
{
(HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
}
return(hMutex);
}
// --------------------------------------------------------------------------
// CLogonMutex::CreateLogonRequestMutex
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Creates the logon request mutex for interactive logon
// requests. For a service to make this request it must acquire
// the mutex and therefore only a single request can be made at
// any one time. This is ACL'd so that only SYSTEM can gain
// access to this object.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
HANDLE CLogonMutex::CreateLogonRequestMutex (void)
{
HANDLE hMutex;
SECURITY_ATTRIBUTES securityAttributes;
// Build a security descriptor for the mutex that allows:
// S-1-5-18 NT AUTHORITY\SYSTEM MUTEX_ALL_ACCESS
static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
{
{
&s_SecurityNTAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
MUTEX_ALL_ACCESS
}
};
securityAttributes.nLength = sizeof(securityAttributes);
securityAttributes.lpSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
securityAttributes.bInheritHandle = FALSE;
hMutex = CreateMutex(&securityAttributes, FALSE, s_szLogonRequestMutexName);
if (securityAttributes.lpSecurityDescriptor != NULL)
{
(HLOCAL)LocalFree(securityAttributes.lpSecurityDescriptor);
}
return(hMutex);
}
// --------------------------------------------------------------------------
// CLogonMutex::OpenShutdownEvent
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Opens a handle to the global shut down event.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
HANDLE CLogonMutex::OpenShutdownEvent (void)
{
return(OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, s_szShutdownEventName));
}
// --------------------------------------------------------------------------
// CLogonMutex::OpenLogonMutex
//
// Arguments: <none>
//
// Returns: HANDLE
//
// Purpose: Opens a handle to the global logon mutex.
//
// History: 2001-04-06 vtan created
// --------------------------------------------------------------------------
HANDLE CLogonMutex::OpenLogonMutex (void)
{
return(OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, s_szLogonMutexName));
}