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.
352 lines
9.5 KiB
352 lines
9.5 KiB
//***************************************************************************
|
|
//
|
|
// Copyright © Microsoft Corporation. All rights reserved.
|
|
//
|
|
// CreateMutexAsProcess.CPP
|
|
//
|
|
// Purpose: Create a mutex NOT using impersonation
|
|
//
|
|
//***************************************************************************
|
|
|
|
#include "precomp.h"
|
|
#include <brodcast.h>
|
|
#include <CreateMutexAsProcess.h>
|
|
#include "MultiPlat.h"
|
|
|
|
#include <cominit.h>
|
|
|
|
//
|
|
//
|
|
// precompiled security descriptor
|
|
// System and NetworkService has full access
|
|
//
|
|
// since this is RELATIVE, it will work on both IA32 and Win64
|
|
//
|
|
DWORD g_PrecSD[] = {
|
|
0x80040001 , 0x00000044 , 0x00000050 , 0x00000000 ,
|
|
0x00000014 , 0x00300002 , 0x00000002 , 0x00140000 ,
|
|
0x001f0001 , 0x00000101 , 0x05000000 , 0x00000012 ,
|
|
0x00140000 , 0x001f0001 , 0x00000101 , 0x05000000 ,
|
|
0x00000014 , 0x00000101 , 0x05000000 , 0x00000014 ,
|
|
0x00000101 , 0x05000000 , 0x00000014
|
|
};
|
|
|
|
DWORD g_SizeSD = 0;
|
|
|
|
DWORD g_RuntimeSD [
|
|
(
|
|
sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
|
|
(2 * (sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD))) +
|
|
sizeof(ACL) +
|
|
(3 * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) +
|
|
(3 * (sizeof(SID)+SID_MAX_SUB_AUTHORITIES*sizeof(DWORD)))
|
|
)/sizeof(DWORD)
|
|
];
|
|
|
|
typedef
|
|
BOOLEAN ( * fnRtlValidRelativeSecurityDescriptor)(
|
|
IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
|
|
IN ULONG SecurityDescriptorLength,
|
|
IN SECURITY_INFORMATION RequiredInformation
|
|
);
|
|
|
|
fnRtlValidRelativeSecurityDescriptor RtlValidRelativeSecurityDescriptor;
|
|
|
|
//
|
|
// Build a SD with owner == This
|
|
// group == This
|
|
// DACL
|
|
// ACE[0] MUTEX_ALL_ACCESS Owner
|
|
// ACE[1] MUTEX_ALL_ACCESS System
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
BOOL
|
|
CreateSD( )
|
|
{
|
|
|
|
if (!RtlValidRelativeSecurityDescriptor)
|
|
{
|
|
HMODULE hModule = GetModuleHandleW(L"ntdll.dll");
|
|
if (hModule)
|
|
{
|
|
RtlValidRelativeSecurityDescriptor = (fnRtlValidRelativeSecurityDescriptor)GetProcAddress(hModule,"RtlValidRelativeSecurityDescriptor");
|
|
if (!RtlValidRelativeSecurityDescriptor)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
HANDLE hToken;
|
|
BOOL bRet;
|
|
|
|
bRet = OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken);
|
|
if (bRet)
|
|
{
|
|
TOKEN_USER * pToken_User;
|
|
DWORD dwSize = sizeof(TOKEN_USER)+sizeof(SID)+(SID_MAX_SUB_AUTHORITIES*sizeof(DWORD));
|
|
pToken_User = (TOKEN_USER *)_alloca(dwSize);
|
|
bRet = GetTokenInformation(hToken,TokenUser,pToken_User,dwSize,&dwSize);
|
|
if (bRet)
|
|
{
|
|
SID SystemSid = { SID_REVISION,
|
|
1,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_LOCAL_SYSTEM_RID
|
|
};
|
|
|
|
SID NetworkSid = { SID_REVISION,
|
|
1,
|
|
SECURITY_NT_AUTHORITY,
|
|
SECURITY_NETWORK_SERVICE_RID
|
|
};
|
|
|
|
PSID pSIDUser = pToken_User->User.Sid;
|
|
dwSize = GetLengthSid(pSIDUser);
|
|
DWORD dwSids = 3; // Owner and System and NetworkService
|
|
DWORD ACLLength = (ULONG) sizeof(ACL) +
|
|
(dwSids * ((ULONG) sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG))) + dwSize + sizeof(SystemSid) + sizeof(NetworkSid);
|
|
|
|
DWORD dwSizeSD = sizeof(SECURITY_DESCRIPTOR_RELATIVE) + dwSize + dwSize + ACLLength;
|
|
SECURITY_DESCRIPTOR_RELATIVE * pLocalSD = (SECURITY_DESCRIPTOR_RELATIVE *)_alloca(dwSizeSD);
|
|
|
|
memset(pLocalSD,0,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
|
pLocalSD->Revision = SECURITY_DESCRIPTOR_REVISION;
|
|
pLocalSD->Control = SE_DACL_PRESENT|SE_SELF_RELATIVE;
|
|
|
|
//SetSecurityDescriptorOwner(pLocalSD,pSIDUser,FALSE);
|
|
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE),pSIDUser,dwSize);
|
|
pLocalSD->Owner = (DWORD)sizeof(SECURITY_DESCRIPTOR_RELATIVE);
|
|
|
|
//SetSecurityDescriptorGroup(pLocalSD,pSIDUser,FALSE);
|
|
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize,pSIDUser,dwSize);
|
|
pLocalSD->Group = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize);
|
|
|
|
|
|
PACL pDacl = (PACL)_alloca(ACLLength);
|
|
|
|
bRet = InitializeAcl( pDacl,
|
|
ACLLength,
|
|
ACL_REVISION);
|
|
if (bRet)
|
|
{
|
|
bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&SystemSid);
|
|
if (bRet)
|
|
{
|
|
bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,&NetworkSid);
|
|
if (bRet)
|
|
{
|
|
bRet = AddAccessAllowedAceEx (pDacl,ACL_REVISION,0,MUTEX_ALL_ACCESS,pSIDUser);
|
|
|
|
if (bRet)
|
|
{
|
|
//bRet = SetSecurityDescriptorDacl(pLocalSD,TRUE,pDacl,FALSE);
|
|
memcpy((BYTE*)pLocalSD+sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize,pDacl,ACLLength);
|
|
pLocalSD->Dacl = (DWORD)(sizeof(SECURITY_DESCRIPTOR_RELATIVE)+dwSize+dwSize);
|
|
|
|
if (RtlValidRelativeSecurityDescriptor(pLocalSD,
|
|
dwSizeSD,
|
|
OWNER_SECURITY_INFORMATION|
|
|
GROUP_SECURITY_INFORMATION|
|
|
DACL_SECURITY_INFORMATION))
|
|
{
|
|
g_SizeSD = dwSizeSD;
|
|
memcpy(g_RuntimeSD,pLocalSD,dwSizeSD);
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bRet;
|
|
};
|
|
|
|
CreateMutexAsProcess::CreateMutexAsProcess(const WCHAR *cszMutexName) : m_hMutex ( NULL )
|
|
{
|
|
BOOL bCreatedAndWaited = FALSE;
|
|
BOOL bImpersonated = TRUE;
|
|
BOOL bReverted = FALSE;
|
|
BOOL bProceed = FALSE;
|
|
HANDLE hThreadToken = INVALID_HANDLE_VALUE;
|
|
|
|
// The mutex will need to be opened in the process's context. If two impersonated
|
|
// threads need the mutex, we can't have the second one get an access denied when
|
|
// opening the mutex.
|
|
|
|
if ( OpenThreadToken (
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hThreadToken
|
|
)
|
|
)
|
|
{
|
|
if ( RevertToSelf() )
|
|
{
|
|
bReverted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LogMessage2 ( L"Failed to revert to self: (%d)", GetLastError() );
|
|
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwError = ::GetLastError ();
|
|
|
|
LogMessage2 ( L"Failed to open thread token: (%d)", dwError );
|
|
|
|
if ( ERROR_ACCESS_DENIED == dwError )
|
|
{
|
|
// we failed to open thread token on behalf of process
|
|
// we are running as NETWORK SERVICE so it would be "by design"
|
|
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
else if ( ERROR_NO_TOKEN == dwError || ERROR_NO_IMPERSONATION_TOKEN == dwError )
|
|
{
|
|
bImpersonated = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( ( bImpersonated && bReverted ) || ! bImpersonated )
|
|
{
|
|
m_hMutex = OpenMutexW(MUTEX_ALL_ACCESS,FALSE,cszMutexName);
|
|
if (NULL == m_hMutex)
|
|
{
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
if (0 == g_SizeSD)
|
|
{
|
|
if (CreateSD())
|
|
{
|
|
sa.nLength = g_SizeSD;
|
|
sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
|
|
sa.bInheritHandle = FALSE;
|
|
}
|
|
else
|
|
{
|
|
sa.nLength = sizeof(g_PrecSD);
|
|
sa.lpSecurityDescriptor = (LPVOID)g_PrecSD;
|
|
sa.bInheritHandle = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sa.nLength = g_SizeSD;
|
|
sa.lpSecurityDescriptor = (LPVOID)g_RuntimeSD;
|
|
sa.bInheritHandle = FALSE;
|
|
}
|
|
|
|
m_hMutex = CreateMutexW(&sa, FALSE, cszMutexName);
|
|
}
|
|
|
|
if ( m_hMutex != NULL )
|
|
{
|
|
if ( bImpersonated )
|
|
{
|
|
if ( ImpersonateLoggedOnUser ( hThreadToken ) )
|
|
{
|
|
bProceed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2 ( L"Failed to return to impersonation (%d)", GetLastError() );
|
|
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bProceed = TRUE;
|
|
}
|
|
|
|
if ( bProceed )
|
|
{
|
|
DWORD dwWaitResult = WAIT_OBJECT_0;
|
|
dwWaitResult = WaitForSingleObject(m_hMutex, INFINITE);
|
|
|
|
if ( dwWaitResult == WAIT_OBJECT_0 )
|
|
{
|
|
bCreatedAndWaited = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogErrorMessage2 ( L"Failed to open mutex: %s", cszMutexName );
|
|
|
|
if ( bImpersonated )
|
|
{
|
|
if ( !ImpersonateLoggedOnUser ( hThreadToken ) )
|
|
{
|
|
LogErrorMessage2 ( L"Failed to return to impersonation (%d)", GetLastError() );
|
|
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if DBG == 1
|
|
// for testing purpose I will let process break
|
|
::DebugBreak();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( ! bCreatedAndWaited )
|
|
{
|
|
if ( hThreadToken != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle(hThreadToken);
|
|
hThreadToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (m_hMutex)
|
|
{
|
|
ReleaseMutex(m_hMutex);
|
|
CloseHandle(m_hMutex);
|
|
m_hMutex = NULL;
|
|
}
|
|
|
|
// we need to throw here to avoid concurrent access
|
|
throw CFramework_Exception( L"CreateMutexAsProcess failed", HRESULT_FROM_WIN32 ( ::GetLastError () ) ) ;
|
|
}
|
|
}
|
|
|
|
CreateMutexAsProcess::~CreateMutexAsProcess()
|
|
{
|
|
if (m_hMutex)
|
|
{
|
|
ReleaseMutex(m_hMutex);
|
|
CloseHandle(m_hMutex);
|
|
}
|
|
}
|