454 lines
14 KiB
C++
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));
|
||
|
}
|
||
|
|