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.
1542 lines
40 KiB
1542 lines
40 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1999 - 2000
|
|
//
|
|
// File: event.cpp
|
|
//
|
|
// Contents: Cert CAuditEvent class implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#include <pch.cpp>
|
|
#pragma hdrstop
|
|
#include <sid.h>
|
|
#include <authzi.h>
|
|
|
|
#define __dwFILE__ __dwFILE_CERTSRV_EVENT_CPP__
|
|
|
|
|
|
using namespace CertSrv;
|
|
|
|
CAuditEvent::AUDIT_CATEGORIES cat[] =
|
|
{ // event ID // event category no of check role separation
|
|
//args for this event
|
|
{SE_AUDITID_CERTSRV_SHUTDOWN, AUDIT_FILTER_STARTSTOP, 0, TRUE},
|
|
{SE_AUDITID_CERTSRV_SERVICESTART, AUDIT_FILTER_STARTSTOP, 4, FALSE},
|
|
{SE_AUDITID_CERTSRV_SERVICESTOP, AUDIT_FILTER_STARTSTOP, 4, FALSE},
|
|
|
|
{SE_AUDITID_CERTSRV_BACKUPSTART, AUDIT_FILTER_BACKUPRESTORE,1, TRUE},
|
|
{SE_AUDITID_CERTSRV_BACKUPEND, AUDIT_FILTER_BACKUPRESTORE,0, TRUE},
|
|
{SE_AUDITID_CERTSRV_RESTORESTART, AUDIT_FILTER_BACKUPRESTORE,0, FALSE},
|
|
{SE_AUDITID_CERTSRV_RESTOREEND, AUDIT_FILTER_BACKUPRESTORE,0, FALSE},
|
|
|
|
{SE_AUDITID_CERTSRV_DENYREQUEST, AUDIT_FILTER_CERTIFICATE, 1, TRUE},
|
|
{SE_AUDITID_CERTSRV_RESUBMITREQUEST, AUDIT_FILTER_CERTIFICATE, 1, TRUE},
|
|
{SE_AUDITID_CERTSRV_SETEXTENSION, AUDIT_FILTER_CERTIFICATE, 5, TRUE},
|
|
{SE_AUDITID_CERTSRV_SETATTRIBUTES, AUDIT_FILTER_CERTIFICATE, 2, TRUE},
|
|
{SE_AUDITID_CERTSRV_IMPORTCERT, AUDIT_FILTER_CERTIFICATE, 2, TRUE},
|
|
{SE_AUDITID_CERTSRV_NEWREQUEST, AUDIT_FILTER_CERTIFICATE, 3, FALSE},
|
|
{SE_AUDITID_CERTSRV_REQUESTAPPROVED, AUDIT_FILTER_CERTIFICATE, 6, FALSE},
|
|
{SE_AUDITID_CERTSRV_REQUESTDENIED, AUDIT_FILTER_CERTIFICATE, 6, FALSE},
|
|
{SE_AUDITID_CERTSRV_REQUESTPENDING, AUDIT_FILTER_CERTIFICATE, 6, FALSE},
|
|
{SE_AUDITID_CERTSRV_DELETEROW, AUDIT_FILTER_CERTIFICATE, 3, TRUE},
|
|
{SE_AUDITID_CERTSRV_PUBLISHCACERT, AUDIT_FILTER_CERTIFICATE, 3, FALSE},
|
|
|
|
{SE_AUDITID_CERTSRV_REVOKECERT, AUDIT_FILTER_CERTREVOCATION, 2, TRUE},
|
|
{SE_AUDITID_CERTSRV_PUBLISHCRL, AUDIT_FILTER_CERTREVOCATION, 3, TRUE},
|
|
{SE_AUDITID_CERTSRV_AUTOPUBLISHCRL, AUDIT_FILTER_CERTREVOCATION, 5, FALSE},
|
|
|
|
{SE_AUDITID_CERTSRV_SETSECURITY, AUDIT_FILTER_CASECURITY, 1, TRUE},
|
|
{SE_AUDITID_CERTSRV_SETAUDITFILTER, AUDIT_FILTER_CASECURITY, 1, TRUE},
|
|
{SE_AUDITID_CERTSRV_SETOFFICERRIGHTS, AUDIT_FILTER_CASECURITY, 2, TRUE},
|
|
{SE_AUDITID_CERTSRV_ROLESEPARATIONSTATE,AUDIT_FILTER_CASECURITY, 1, FALSE},
|
|
|
|
{SE_AUDITID_CERTSRV_GETARCHIVEDKEY, AUDIT_FILTER_KEYAARCHIVAL, 1, TRUE},
|
|
{SE_AUDITID_CERTSRV_KEYARCHIVED, AUDIT_FILTER_KEYAARCHIVAL, 3, FALSE},
|
|
{SE_AUDITID_CERTSRV_IMPORTKEY, AUDIT_FILTER_KEYAARCHIVAL, 1, TRUE},
|
|
|
|
{SE_AUDITID_CERTSRV_SETCONFIGENTRY, AUDIT_FILTER_CACONFIG, 3, TRUE},
|
|
{SE_AUDITID_CERTSRV_SETCAPROPERTY, AUDIT_FILTER_CACONFIG, 4, TRUE},
|
|
};
|
|
CAuditEvent::AUDIT_CATEGORIES *CAuditEvent::m_gAuditCategories = cat;
|
|
|
|
DWORD CAuditEvent::m_gdwAuditCategoriesSize = sizeof(cat)/sizeof(cat[0]);
|
|
|
|
bool CAuditEvent::m_gfRoleSeparationEnabled = false;
|
|
|
|
CAuditEvent::CAuditEvent(ULONG ulEventID, DWORD dwFilter) :
|
|
m_cEventData(0),
|
|
m_cRequiredEventData(0),
|
|
m_dwFilter(dwFilter),
|
|
m_fRoleSeparationEnabled(false),
|
|
m_pISS(NULL),
|
|
m_hClientToken(NULL),
|
|
m_pCASD(NULL),
|
|
m_ClientContext(NULL),
|
|
m_pSDPrivileges(NULL),
|
|
m_pDaclPrivileges(NULL),
|
|
m_hRpc(NULL),
|
|
m_Error(0),
|
|
m_MaskAllowed(0),
|
|
m_crtGUID(0),
|
|
m_pUserSid(NULL),
|
|
m_hAuditEventType(NULL)
|
|
{
|
|
m_AuthzHandle = NULL;
|
|
|
|
m_Request.ObjectTypeList = NULL;
|
|
m_Request.PrincipalSelfSid = NULL;
|
|
m_Request.ObjectTypeListLength = 0;
|
|
m_Request.OptionalArguments = NULL;
|
|
|
|
m_Reply.ResultListLength = 1;
|
|
m_Reply.GrantedAccessMask = &m_MaskAllowed;
|
|
m_Reply.Error = &m_Error;
|
|
m_Reply.SaclEvaluationResults = &m_SaclEval;
|
|
|
|
SetEventID(ulEventID);
|
|
};
|
|
|
|
// initializes internal data associated with a particular audit event
|
|
void CAuditEvent::SetEventID(ULONG ulEventID)
|
|
{
|
|
m_ulEventID = ulEventID;
|
|
|
|
for(DWORD c=0; c<m_gdwAuditCategoriesSize; c++)
|
|
{
|
|
if(((DWORD)m_ulEventID)==((DWORD)m_gAuditCategories[c].ulAuditID))
|
|
{
|
|
m_fRoleSeparationEnabled =
|
|
m_gAuditCategories[c].fRoleSeparationEnabled;
|
|
|
|
m_cRequiredEventData = m_gAuditCategories[c].dwParamCount;
|
|
|
|
CSASSERT(m_EventDataMaxSize>=m_cRequiredEventData);
|
|
|
|
if(!m_gAuditCategories[c].hAuditEventType)
|
|
{
|
|
AuthziInitializeAuditEventType(
|
|
0,
|
|
SE_CATEGID_OBJECT_ACCESS,
|
|
(USHORT)m_ulEventID,
|
|
(USHORT)m_gAuditCategories[c].dwParamCount,
|
|
&m_gAuditCategories[c].hAuditEventType);
|
|
|
|
}
|
|
m_hAuditEventType = m_gAuditCategories[c].hAuditEventType;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CAuditEvent::~CAuditEvent()
|
|
{
|
|
for(DWORD cData=0;cData<m_cEventData;cData++)
|
|
delete m_pEventDataList[cData];
|
|
|
|
FreeCachedHandles();
|
|
}
|
|
|
|
void CAuditEvent::CleanupAuditEventTypeHandles()
|
|
{
|
|
for(DWORD c=0; c<m_gdwAuditCategoriesSize; c++)
|
|
{
|
|
if(m_gAuditCategories[c].hAuditEventType)
|
|
{
|
|
AuthziFreeAuditEventType(m_gAuditCategories[c].hAuditEventType);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CAuditEvent::IsEventValid()
|
|
{
|
|
for(DWORD c=0; c<m_gdwAuditCategoriesSize; c++)
|
|
{
|
|
if(m_ulEventID==m_gAuditCategories[c].ulAuditID)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CAuditEvent::IsEventEnabled()
|
|
{
|
|
if(0==m_ulEventID) // event is used for access check only
|
|
return false;
|
|
|
|
for(DWORD c=0; c<m_gdwAuditCategoriesSize; c++)
|
|
{
|
|
if(((DWORD)m_ulEventID)==((DWORD)m_gAuditCategories[c].ulAuditID))
|
|
{
|
|
return (m_dwFilter&m_gAuditCategories[c].dwFilter)?true:false;
|
|
}
|
|
}
|
|
// if get here the event has an unknown ID
|
|
CSASSERT(CSExpr(!L"Invalid event found"));
|
|
return false;
|
|
}
|
|
|
|
inline bool CAuditEvent::IsEventRoleSeparationEnabled()
|
|
{
|
|
return RoleSeparationIsEnabled() && m_fRoleSeparationEnabled;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(DWORD dwValue)
|
|
{
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_UI4;
|
|
V_UI4(pvtData) = dwValue;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(PBYTE pData, DWORD dwDataLen)
|
|
{
|
|
CSASSERT(pData && dwDataLen);
|
|
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_BLOB;
|
|
pvtData->blob.cbSize = dwDataLen;
|
|
pvtData->blob.pBlobData = (BYTE*)CoTaskMemAlloc(dwDataLen);
|
|
if(!pvtData->blob.pBlobData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
memcpy(pvtData->blob.pBlobData, pData, dwDataLen);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(bool fData)
|
|
{
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_BOOL;
|
|
V_BOOL(pvtData) = fData?VARIANT_TRUE:VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(LPCWSTR pcwszData)
|
|
{
|
|
if(!pcwszData)
|
|
pcwszData = L"";
|
|
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_LPWSTR;
|
|
pvtData->pwszVal =
|
|
(LPWSTR)CoTaskMemAlloc((wcslen(pcwszData)+1)*sizeof(WCHAR));
|
|
if(!pvtData->pwszVal)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(pvtData->pwszVal, pcwszData);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(LPCWSTR *ppcwszData)
|
|
{
|
|
CSASSERT(ppcwszData);
|
|
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_LPWSTR;
|
|
|
|
DWORD dwTextLen = 1;
|
|
|
|
for(LPCWSTR *ppcwszStr=ppcwszData; *ppcwszStr; ppcwszStr++)
|
|
{
|
|
dwTextLen += wcslen(*ppcwszStr)+2;
|
|
}
|
|
|
|
pvtData->pwszVal =
|
|
(LPWSTR)CoTaskMemAlloc(dwTextLen*sizeof(WCHAR));
|
|
if(!pvtData->pwszVal)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(pvtData->pwszVal, L"");
|
|
for(ppcwszStr=ppcwszData; *ppcwszStr; ppcwszStr++)
|
|
{
|
|
wcscat(pvtData->pwszVal, *ppcwszStr);
|
|
wcscat(pvtData->pwszVal, L"; ");
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(FILETIME time)
|
|
{
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
FILETIME ftZero = {0,0};
|
|
#define wszTIMEZERO L"0"
|
|
|
|
if(0 == CompareFileTime(&time, &ftZero))
|
|
{
|
|
V_VT(pvtData) = VT_LPWSTR;
|
|
pvtData->pwszVal = (LPWSTR) CoTaskMemAlloc(sizeof(wszTIMEZERO));
|
|
if (NULL == pvtData->pwszVal)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(pvtData->pwszVal, wszTIMEZERO);
|
|
}
|
|
else
|
|
{
|
|
V_VT(pvtData) = VT_FILETIME;
|
|
pvtData->filetime = time;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::AddData(const VARIANT *pvar, bool fDoublePercentInStrings=false)
|
|
{
|
|
CSASSERT(pvar);
|
|
|
|
EventData *pData = CreateNewEventData1();
|
|
if(!pData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pData->m_fDoublePercentsInStrings = fDoublePercentInStrings;
|
|
|
|
HRESULT hr = VariantCopy((VARIANT*)&pData->m_vtData, (VARIANT*)pvar);
|
|
myRegisterMemAlloc((VARIANT *) &pData->m_vtData, 0, CSM_VARIANT);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CAuditEvent::AddData(ULARGE_INTEGER *puliValue)
|
|
{
|
|
PROPVARIANT *pvtData = CreateNewEventData();
|
|
DWORD dwDataLen = sizeof(*puliValue);
|
|
|
|
if(!pvtData)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
V_VT(pvtData) = VT_UI8;
|
|
memcpy(&pvtData->uhVal, puliValue, dwDataLen);
|
|
return S_OK;
|
|
}
|
|
|
|
PROPVARIANT *CAuditEvent::CreateNewEventData()
|
|
{
|
|
EventData *pData = CreateNewEventData1();
|
|
return &pData->m_vtData;
|
|
}
|
|
|
|
CAuditEvent::EventData *CAuditEvent::CreateNewEventData1()
|
|
{
|
|
EventData *pData = new EventData;
|
|
if(!pData)
|
|
{
|
|
return NULL;
|
|
}
|
|
m_pEventDataList[m_cEventData++] = pData;
|
|
return pData;
|
|
}
|
|
|
|
|
|
HRESULT ConvertToStringBOOL(
|
|
BOOL fVal,
|
|
LPWSTR *ppwszOut)
|
|
|
|
{
|
|
LPCWSTR pwszBoolVal =
|
|
fVal==VARIANT_TRUE?
|
|
g_pwszYes:
|
|
g_pwszNo;
|
|
|
|
*ppwszOut = (LPWSTR) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(WCHAR)*(wcslen(pwszBoolVal)+1));
|
|
|
|
if(!*ppwszOut)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(*ppwszOut, pwszBoolVal);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAuditEvent::EventData::ConvertToString(LPWSTR *ppwszValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
switch(V_VT(&m_vtData))
|
|
{
|
|
case VT_I2:
|
|
hr = ConvertToStringI2I4(V_I2(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_BYREF|VT_I2:
|
|
hr = ConvertToStringI2I4(*V_I2REF(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_I4:
|
|
hr = ConvertToStringI2I4(V_I4(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_BYREF|VT_I4:
|
|
hr = ConvertToStringI2I4(*V_I4REF(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_UI2:
|
|
hr = ConvertToStringUI2UI4(V_UI2(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_BYREF|VT_UI2:
|
|
hr = ConvertToStringUI2UI4(*V_UI2REF(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_UI4:
|
|
hr = ConvertToStringUI2UI4(V_UI4(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_BYREF|VT_UI4:
|
|
hr = ConvertToStringUI2UI4(*V_UI4REF(&m_vtData), ppwszValue);
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
// We don't call CryptBinaryToString directly anywhere in the CA tree.
|
|
// This avoids errors when linking in the CryptBinaryToString code
|
|
// for NT 4 reskit builds.
|
|
|
|
hr = myCryptBinaryToString(
|
|
m_vtData.blob.pBlobData,
|
|
m_vtData.blob.cbSize,
|
|
CRYPT_STRING_BASE64,
|
|
ppwszValue);
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
hr = ConvertToStringBOOL(V_BOOL(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_BOOL|VT_BYREF:
|
|
hr = ConvertToStringBOOL(*V_BOOLREF(&m_vtData), ppwszValue);
|
|
break;
|
|
|
|
case VT_LPWSTR:
|
|
hr = ConvertToStringWSZ(
|
|
m_vtData.pwszVal,
|
|
ppwszValue,
|
|
m_fDoublePercentsInStrings);
|
|
break;
|
|
case VT_BSTR:
|
|
hr = ConvertToStringWSZ(
|
|
V_BSTR(&m_vtData),
|
|
ppwszValue,
|
|
m_fDoublePercentsInStrings);
|
|
break;
|
|
case VT_BSTR|VT_BYREF:
|
|
hr = ConvertToStringWSZ(
|
|
*V_BSTRREF(&m_vtData),
|
|
ppwszValue,
|
|
m_fDoublePercentsInStrings);
|
|
break;
|
|
|
|
case VT_FILETIME:
|
|
hr = myFileTimeToWszTime(
|
|
&m_vtData.filetime,
|
|
TRUE,
|
|
ppwszValue);
|
|
break;
|
|
|
|
case VT_ARRAY|VT_UI1:
|
|
hr = ConvertToStringArrayUI1(V_ARRAY(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_ARRAY|VT_UI1|VT_BYREF:
|
|
hr = ConvertToStringArrayUI1(*V_ARRAYREF(&m_vtData), ppwszValue);
|
|
break;
|
|
case VT_ARRAY|VT_BSTR:
|
|
hr = ConvertToStringArrayBSTR(
|
|
V_ARRAY(&m_vtData),
|
|
ppwszValue,
|
|
m_fDoublePercentsInStrings);
|
|
break;
|
|
case VT_ARRAY|VT_BSTR|VT_BYREF:
|
|
hr = ConvertToStringArrayBSTR(
|
|
*V_ARRAYREF(&m_vtData),
|
|
ppwszValue,
|
|
m_fDoublePercentsInStrings);
|
|
break;
|
|
|
|
default:
|
|
{
|
|
LPCWSTR pwszValOut = cAuditString_UnknownDataType;
|
|
VARIANT varOut;
|
|
VariantInit(&varOut);
|
|
|
|
hr = VariantChangeType(&varOut, (VARIANT*)&m_vtData, 0, VT_BSTR);
|
|
if(S_OK==hr)
|
|
{
|
|
pwszValOut = V_BSTR(&varOut);
|
|
}
|
|
*ppwszValue = (LPWSTR) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(WCHAR)*(wcslen(pwszValOut)+1));
|
|
if(!*ppwszValue)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
wcscpy(*ppwszValue, pwszValOut);
|
|
VariantClear(&varOut);
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::Report(bool fSuccess /* = true */)
|
|
{
|
|
HRESULT hr;
|
|
AUTHZ_AUDIT_EVENT_HANDLE AuthzAIH = NULL;
|
|
PAUDIT_PARAMS pAuditParams = NULL;
|
|
PAUDIT_PARAM pParamArray = NULL;
|
|
|
|
if(!IsEventEnabled())
|
|
{
|
|
return S_OK;
|
|
}
|
|
hr = BuildAuditParamArray(pParamArray);
|
|
_JumpIfError(hr, error, "GetAuditText");
|
|
|
|
if(!AuthziAllocateAuditParams(
|
|
&pAuditParams,
|
|
(USHORT)(m_cEventData+2))) // authz adds 2
|
|
{ // extra params
|
|
hr = myHLastError(); // internally
|
|
_JumpError(hr, error, "AuthziAllocateAuditParams");
|
|
}
|
|
|
|
#ifndef _DISABLE_AUTHZ_
|
|
if(!AuthziInitializeAuditParamsFromArray(
|
|
fSuccess?APF_AuditSuccess:APF_AuditFailure,
|
|
g_AuthzCertSrvRM,
|
|
(USHORT)m_cEventData,
|
|
pParamArray,
|
|
pAuditParams))
|
|
#else
|
|
SetLastError(E_INVALIDARG);
|
|
#endif
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthziInitializeAuditParamsFromArray");
|
|
}
|
|
|
|
if (!AuthziInitializeAuditEvent(0,
|
|
g_AuthzCertSrvRM,
|
|
m_hAuditEventType,
|
|
pAuditParams,
|
|
NULL,
|
|
INFINITE,
|
|
L"",
|
|
L"",
|
|
L"",
|
|
L"",
|
|
&AuthzAIH))
|
|
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "AuthzInitializeAuditInfo");
|
|
}
|
|
|
|
if(!AuthziLogAuditEvent( 0, AuthzAIH, NULL ))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "AuthzGenAuditEvent");
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_AUDIT,
|
|
"Audit event ID=%d\n",
|
|
m_ulEventID));
|
|
|
|
error:
|
|
|
|
if(AuthzAIH)
|
|
{
|
|
AuthzFreeAuditEvent(AuthzAIH);
|
|
}
|
|
|
|
if(pAuditParams)
|
|
{
|
|
AuthziFreeAuditParams(pAuditParams);
|
|
}
|
|
|
|
FreeAuditParamArray(pParamArray);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::SaveFilter(LPCWSTR pcwszSanitizedName)
|
|
{
|
|
return mySetCertRegDWValue(
|
|
pcwszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGAUDITFILTER,
|
|
m_dwFilter);
|
|
}
|
|
|
|
HRESULT CAuditEvent::LoadFilter(LPCWSTR pcwszSanitizedName)
|
|
{
|
|
return myGetCertRegDWValue(
|
|
pcwszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGAUDITFILTER,
|
|
&m_dwFilter);
|
|
}
|
|
|
|
HRESULT CAuditEvent::Impersonate()
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hThread = NULL;
|
|
|
|
CSASSERT(NULL==m_pISS);
|
|
CSASSERT(NULL==m_hClientToken);
|
|
|
|
if (NULL == m_hRpc)
|
|
{
|
|
// dcom impersonate
|
|
hr = CoGetCallContext(IID_IServerSecurity, (void**)&m_pISS);
|
|
_JumpIfError(hr, error, "CoGetCallContext");
|
|
|
|
hr = m_pISS->ImpersonateClient();
|
|
_JumpIfError(hr, error, "ImpersonateClient");
|
|
}
|
|
else
|
|
{
|
|
// rpc impersonate
|
|
hr = RpcImpersonateClient((RPC_BINDING_HANDLE) m_hRpc);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "RpcImpersonateClient");
|
|
}
|
|
}
|
|
|
|
hThread = GetCurrentThread();
|
|
if (NULL == hThread)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "GetCurrentThread");
|
|
}
|
|
if (!OpenThreadToken(hThread,
|
|
TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
FALSE, // client impersonation
|
|
&m_hClientToken))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "OpenThreadToken");
|
|
}
|
|
|
|
error:
|
|
|
|
if(S_OK!=hr)
|
|
{
|
|
if(NULL!=m_pISS)
|
|
{
|
|
m_pISS->Release();
|
|
m_pISS = NULL;
|
|
}
|
|
}
|
|
if (NULL != hThread)
|
|
{
|
|
CloseHandle(hThread);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::RevertToSelf()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
// CSASSERT(m_pISS||m_hRpc);
|
|
|
|
if (NULL != m_hRpc) // rpc
|
|
{
|
|
hr = RpcRevertToSelf();
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "RpcRevertToSelf");
|
|
}
|
|
m_hRpc = NULL;
|
|
}
|
|
else if(m_pISS) // dcom
|
|
{
|
|
hr = m_pISS->RevertToSelf();
|
|
_JumpIfError(hr, error, "IServerSecurity::RpcRevertToSelf");
|
|
|
|
m_pISS->Release();
|
|
m_pISS = NULL;
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|
|
|
|
HANDLE CAuditEvent::GetClientToken()
|
|
{
|
|
CSASSERT(m_hClientToken);
|
|
HANDLE hSave = m_hClientToken;
|
|
m_hClientToken = NULL;
|
|
return hSave;
|
|
}
|
|
|
|
// dwAuditFlags - not asking for both success and failure implicitely
|
|
// means the handles will be cached for future audit
|
|
HRESULT
|
|
CAuditEvent::AccessCheck(
|
|
ACCESS_MASK Mask,
|
|
DWORD dwAuditFlags,
|
|
handle_t hRpc,
|
|
HANDLE *phToken)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LUID luid = {0,0};
|
|
bool fAccessAllowed = false;
|
|
DWORD dwRoles = 0;
|
|
bool fImpersonating = false;
|
|
|
|
FreeCachedHandles();
|
|
|
|
m_hRpc = hRpc;
|
|
|
|
if (!g_CASD.IsInitialized())
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
|
|
_JumpError(hr, error, "Security not enabled");
|
|
}
|
|
|
|
hr = g_CASD.LockGet(&m_pCASD);
|
|
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
|
|
|
|
hr = Impersonate();
|
|
_JumpIfError(hr, error, "CAuditEvent::Impersonate");
|
|
|
|
fImpersonating = true;
|
|
|
|
// fail if RPC/COM encryption is required but client auth level is not
|
|
// "privacy"
|
|
hr = EnforceEncryption(CA_ACCESS_ENROLL==Mask);
|
|
_JumpIfError(hr, error, "EnforceEncryption");
|
|
|
|
hr = EnforceLocalVsRemote(Mask);
|
|
_JumpIfError(hr, error, "EnforceLocalVsRemote");
|
|
|
|
if(!AuthzInitializeContextFromToken(
|
|
0,
|
|
m_hClientToken,
|
|
g_AuthzCertSrvRM,
|
|
NULL,
|
|
luid,
|
|
NULL,
|
|
&m_ClientContext))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "AuthzInitializeContextFromToken");
|
|
|
|
if (E_INVALIDARG == hr && (!IsWhistler() || 2 <= g_fAdvancedServer))
|
|
{
|
|
hr = S_OK;
|
|
fAccessAllowed = TRUE;
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
if(Mask & CA_ACCESS_LOCALADMIN)
|
|
{
|
|
bool fLocalAdmin;
|
|
|
|
hr = myIsCurrentUserBuiltinAdmin(&fLocalAdmin);
|
|
_JumpIfError(hr, error, "myIsCurrentUserBuiltinAdmin");
|
|
|
|
if(fLocalAdmin)
|
|
{
|
|
dwRoles |= CA_ACCESS_LOCALADMIN;
|
|
}
|
|
}
|
|
|
|
RevertToSelf();
|
|
fImpersonating = false;
|
|
|
|
// Get privilege based roles if checking access on a privilege role
|
|
// or if role separation is enabled when we have to know all roles
|
|
if(IsEventRoleSeparationEnabled() ||
|
|
Mask & (CA_ACCESS_OPERATOR|CA_ACCESS_AUDITOR|CA_ACCESS_LOCALADMIN))
|
|
{
|
|
hr = GetPrivilegeRoles(&dwRoles);
|
|
_JumpIfError(hr, error, "CAuditEvent::GetPrivilegeRolesCount");
|
|
|
|
hr = BuildPrivilegeSecurityDescriptor(dwRoles);
|
|
_JumpIfError(hr, error, "CAuditEvent::BuildPrivilegeSecurityDescriptor");
|
|
}
|
|
|
|
// Get security descriptor based roles
|
|
m_Request.DesiredAccess = MAXIMUM_ALLOWED;
|
|
CSASSERT(!m_AuthzHandle);
|
|
if(!AuthzAccessCheck(
|
|
0,
|
|
m_ClientContext,
|
|
&m_Request,
|
|
NULL, //no audit
|
|
m_pCASD,
|
|
m_pSDPrivileges?(&m_pSDPrivileges):NULL,
|
|
m_pSDPrivileges?1:0,
|
|
&m_Reply,
|
|
IsEventEnabled()?&m_AuthzHandle:NULL)) // no caching if no audit
|
|
// event will be generated
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzAccessCheck");
|
|
}
|
|
|
|
dwRoles |= m_Reply.GrantedAccessMask[0];
|
|
|
|
if(m_Reply.Error[0]==ERROR_SUCCESS &&
|
|
m_Reply.GrantedAccessMask[0]&Mask)
|
|
{
|
|
fAccessAllowed = true;
|
|
}
|
|
|
|
if(IsEventRoleSeparationEnabled() &&
|
|
GetBitCount(dwRoles&CA_ACCESS_MASKROLES)>1)
|
|
{
|
|
hr = CERTSRV_E_ROLECONFLICT;
|
|
fAccessAllowed = false;
|
|
// don't return yet, we need to generate an audit
|
|
}
|
|
|
|
// Next is a fake access check to generate an audit.
|
|
// Access is denied if:
|
|
// - role separation is enabled and user has more than one role
|
|
// - none of the roles requested is allowed
|
|
|
|
// Generate audit if event is enabled and
|
|
if(IsEventEnabled() &&
|
|
(!fAccessAllowed && !(dwAuditFlags&m_gcNoAuditFailure) ||
|
|
fAccessAllowed && !(dwAuditFlags&m_gcNoAuditSuccess)))
|
|
{
|
|
|
|
m_Request.DesiredAccess =
|
|
fAccessAllowed?
|
|
m_Reply.GrantedAccessMask[0]&Mask:
|
|
Mask;
|
|
|
|
if(CERTSRV_E_ROLECONFLICT==hr)
|
|
m_Request.DesiredAccess = 0x0000ffff; //force a failure audit
|
|
|
|
HRESULT hr2 = CachedGenerateAudit();
|
|
if(S_OK != hr2)
|
|
{
|
|
hr = hr2;
|
|
_JumpIfError(hr, error, "CAuditEvent::CachedGenerateAudit");
|
|
}
|
|
}
|
|
|
|
if(phToken)
|
|
{
|
|
*phToken = GetClientToken();
|
|
}
|
|
|
|
error:
|
|
|
|
if(fImpersonating)
|
|
{
|
|
RevertToSelf();
|
|
}
|
|
|
|
if(!IsEventEnabled())
|
|
{
|
|
FreeCachedHandles();
|
|
}
|
|
|
|
if(S_OK==hr)
|
|
{
|
|
hr = fAccessAllowed?S_OK:E_ACCESSDENIED;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CAuditEvent::CachedGenerateAudit()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
AUTHZ_AUDIT_EVENT_HANDLE AuditInfo = NULL;
|
|
PAUDIT_PARAMS pAuditParams = NULL;
|
|
PAUDIT_PARAM pParamArray = NULL;
|
|
|
|
if(!IsEventEnabled())
|
|
{
|
|
FreeCachedHandles();
|
|
return S_OK;
|
|
}
|
|
|
|
CSASSERT(m_AuthzHandle);
|
|
|
|
hr = BuildAuditParamArray(pParamArray);
|
|
_JumpIfError(hr, error, "GetAuditText");
|
|
|
|
if(!AuthziAllocateAuditParams(
|
|
&pAuditParams,
|
|
(USHORT)(m_cEventData+2))) // authz adds 2
|
|
{ // extra params
|
|
hr = myHLastError(); // internally
|
|
_JumpError(hr, error, "AuthziAllocateAuditParams");
|
|
}
|
|
|
|
#ifndef _DISABLE_AUTHZ_
|
|
if(!AuthziInitializeAuditParamsFromArray(
|
|
APF_AuditSuccess|APF_AuditFailure,
|
|
g_AuthzCertSrvRM,
|
|
(USHORT)m_cEventData,
|
|
pParamArray,
|
|
pAuditParams))
|
|
#else
|
|
SetLastError(E_INVALIDARG);
|
|
#endif
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzInitAuditParams");
|
|
}
|
|
|
|
if(!AuthziInitializeAuditEvent(
|
|
0,
|
|
g_AuthzCertSrvRM,
|
|
m_hAuditEventType,
|
|
pAuditParams,
|
|
NULL,
|
|
INFINITE,
|
|
L"",
|
|
L"",
|
|
L"",
|
|
L"",
|
|
&AuditInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzInitAuditInfoHandle");
|
|
}
|
|
|
|
if(!AuthzCachedAccessCheck(
|
|
0,
|
|
m_AuthzHandle,
|
|
&m_Request,
|
|
AuditInfo,
|
|
&m_Reply))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzCachedAccessCheck");
|
|
}
|
|
|
|
error:
|
|
|
|
if(AuditInfo)
|
|
{
|
|
AuthzFreeAuditEvent(AuditInfo);
|
|
}
|
|
|
|
if(pAuditParams)
|
|
{
|
|
AuthziFreeAuditParams(pAuditParams);
|
|
}
|
|
|
|
FreeCachedHandles();
|
|
FreeAuditParamArray(pParamArray);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
void CAuditEvent::FreeCachedHandles()
|
|
{
|
|
if(m_hClientToken)
|
|
{
|
|
CloseHandle(m_hClientToken);
|
|
m_hClientToken = NULL;
|
|
}
|
|
|
|
if(m_AuthzHandle)
|
|
{
|
|
AuthzFreeHandle(m_AuthzHandle);
|
|
m_AuthzHandle = NULL;
|
|
}
|
|
|
|
if(m_pCASD)
|
|
{
|
|
g_CASD.Unlock();
|
|
m_pCASD = NULL;
|
|
}
|
|
|
|
if(m_ClientContext)
|
|
{
|
|
AuthzFreeContext(m_ClientContext);
|
|
m_ClientContext = NULL;
|
|
}
|
|
|
|
if(m_pUserSid)
|
|
{
|
|
LocalFree(m_pUserSid);
|
|
m_pUserSid = NULL;
|
|
}
|
|
if(m_pSDPrivileges)
|
|
{
|
|
LocalFree(m_pSDPrivileges);
|
|
m_pSDPrivileges = NULL;
|
|
}
|
|
if(m_pDaclPrivileges)
|
|
{
|
|
LocalFree(m_pDaclPrivileges);
|
|
m_pDaclPrivileges = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT CAuditEvent::RoleSeparationFlagSave(LPCWSTR pcwszSanitizedName)
|
|
{
|
|
return mySetCertRegDWValue(
|
|
pcwszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGROLESEPARATIONENABLED,
|
|
RoleSeparationIsEnabled()?1:0);
|
|
}
|
|
|
|
HRESULT CAuditEvent::RoleSeparationFlagLoad(LPCWSTR pcwszSanitizedName)
|
|
{
|
|
DWORD dwFlags = 0;
|
|
HRESULT hr = myGetCertRegDWValue(
|
|
pcwszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGROLESEPARATIONENABLED,
|
|
&dwFlags);
|
|
if(S_OK==hr)
|
|
{
|
|
RoleSeparationEnable(dwFlags?true:false);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::GetPrivilegeRoles(PDWORD pdwRoles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PTOKEN_USER pTokenUser = NULL;
|
|
DWORD cbTokenUser = 0;
|
|
PTOKEN_GROUPS pTokenGroups = NULL;
|
|
DWORD cbTokenGroups = 0;
|
|
DWORD dwRoles = 0;
|
|
LSA_HANDLE lsahPolicyHandle = NULL;
|
|
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS NTStatus;
|
|
|
|
// first get roles for the user itself
|
|
AuthzGetInformationFromContext(
|
|
m_ClientContext,
|
|
AuthzContextInfoUserSid,
|
|
0,
|
|
&cbTokenUser,
|
|
NULL);
|
|
|
|
if(GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzGetContextInformation");
|
|
}
|
|
|
|
pTokenUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, cbTokenUser);
|
|
_JumpIfAllocFailed(pTokenUser, error);
|
|
|
|
if(!AuthzGetInformationFromContext(
|
|
m_ClientContext,
|
|
AuthzContextInfoUserSid,
|
|
cbTokenUser,
|
|
&cbTokenUser,
|
|
pTokenUser))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzGetContextInformation");
|
|
}
|
|
|
|
// Object attributes are reserved, so initalize to zeroes.
|
|
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
|
|
|
NTStatus = LsaOpenPolicy(
|
|
NULL,
|
|
&ObjectAttributes,
|
|
POLICY_LOOKUP_NAMES,
|
|
&lsahPolicyHandle);
|
|
if(STATUS_SUCCESS!=NTStatus)
|
|
{
|
|
hr = myHError(LsaNtStatusToWinError(NTStatus));
|
|
_JumpError(hr, error, "LsaOpenPolicy");
|
|
}
|
|
|
|
CSASSERT(!m_pUserSid);
|
|
m_pUserSid = (PSID)LocalAlloc(LMEM_FIXED, GetLengthSid(pTokenUser->User.Sid));
|
|
_JumpIfAllocFailed(m_pUserSid, error);
|
|
|
|
CopySid(
|
|
GetLengthSid(pTokenUser->User.Sid),
|
|
m_pUserSid,
|
|
pTokenUser->User.Sid);
|
|
|
|
hr = GetUserPrivilegeRoles(lsahPolicyHandle, &pTokenUser->User, &dwRoles);
|
|
if(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)==hr)
|
|
{
|
|
hr =S_OK;
|
|
}
|
|
_JumpIfError(hr, error, "CAuditEvent::GetUserPrivilegeRoles");
|
|
|
|
*pdwRoles |= dwRoles;
|
|
|
|
// then find the roles assigned to the groups the user is member of
|
|
|
|
AuthzGetInformationFromContext(
|
|
m_ClientContext,
|
|
AuthzContextInfoGroupsSids,
|
|
0,
|
|
&cbTokenGroups,
|
|
NULL);
|
|
|
|
if(GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzGetContextInformation");
|
|
}
|
|
|
|
pTokenGroups = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, cbTokenGroups);
|
|
_JumpIfAllocFailed(pTokenGroups, error);
|
|
|
|
if(!AuthzGetInformationFromContext(
|
|
m_ClientContext,
|
|
AuthzContextInfoGroupsSids,
|
|
cbTokenGroups,
|
|
&cbTokenGroups,
|
|
pTokenGroups))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzGetContextInformation");
|
|
}
|
|
|
|
for(DWORD cGroups = 0; cGroups<pTokenGroups->GroupCount; cGroups++)
|
|
{
|
|
dwRoles = 0;
|
|
hr = GetUserPrivilegeRoles(
|
|
lsahPolicyHandle,
|
|
&pTokenGroups->Groups[cGroups],
|
|
&dwRoles);
|
|
if(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)==hr)
|
|
{
|
|
hr =S_OK;
|
|
}
|
|
_JumpIfError(hr, error, "CAuditEvent::GetUserPrivilegeRoles");
|
|
|
|
*pdwRoles |= dwRoles;
|
|
}
|
|
|
|
error:
|
|
if(pTokenUser)
|
|
{
|
|
LocalFree(pTokenUser);
|
|
}
|
|
if(pTokenGroups)
|
|
{
|
|
LocalFree(pTokenGroups);
|
|
}
|
|
if(lsahPolicyHandle)
|
|
{
|
|
LsaClose(lsahPolicyHandle);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CAuditEvent::GetUserPrivilegeRoles(
|
|
LSA_HANDLE lsah,
|
|
PSID_AND_ATTRIBUTES pSA,
|
|
PDWORD pdwRoles)
|
|
{
|
|
NTSTATUS NTStatus;
|
|
PLSA_UNICODE_STRING pLSAString = NULL;
|
|
ULONG cRights, c;
|
|
|
|
NTStatus = LsaEnumerateAccountRights(
|
|
lsah,
|
|
pSA->Sid,
|
|
&pLSAString,
|
|
&cRights);
|
|
|
|
if(STATUS_SUCCESS!=NTStatus)
|
|
{
|
|
return(myHError(LsaNtStatusToWinError(NTStatus)));
|
|
}
|
|
|
|
for(c=0; c<cRights; c++)
|
|
{
|
|
if(0==_wcsicmp(SE_SECURITY_NAME, pLSAString[c].Buffer))
|
|
{
|
|
*pdwRoles |= CA_ACCESS_AUDITOR;
|
|
}
|
|
else if(0==_wcsicmp(SE_BACKUP_NAME, pLSAString[c].Buffer))
|
|
{
|
|
*pdwRoles |= CA_ACCESS_OPERATOR;
|
|
}
|
|
}
|
|
|
|
if(pLSAString)
|
|
{
|
|
LsaFreeMemory(pLSAString);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CAuditEvent::GetMyRoles(
|
|
DWORD *pdwRoles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LUID luid = {0,0};
|
|
DWORD dwRoles = 0;
|
|
bool fImpersonating = false;
|
|
|
|
if (!g_CASD.IsInitialized())
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
|
|
_JumpError(hr, error, "Security not enabled");
|
|
}
|
|
|
|
hr = g_CASD.LockGet(&m_pCASD);
|
|
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::LockGet");
|
|
|
|
hr = Impersonate();
|
|
_JumpIfError(hr, error, "CAuditEvent::Impersonate");
|
|
|
|
// fail if RPC/COM encryption is required but client auth level is not
|
|
// "privacy"
|
|
hr = EnforceEncryption(false); // false == admin interface
|
|
_JumpIfError(hr, error, "EnforceEncryption");
|
|
|
|
fImpersonating = true;
|
|
|
|
if(!AuthzInitializeContextFromToken(
|
|
0,
|
|
m_hClientToken,
|
|
g_AuthzCertSrvRM,
|
|
NULL,
|
|
luid,
|
|
NULL,
|
|
&m_ClientContext))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzInitializeContextFromToken");
|
|
}
|
|
|
|
RevertToSelf();
|
|
fImpersonating = false;
|
|
|
|
hr = GetPrivilegeRoles(&dwRoles);
|
|
_JumpIfError(hr, error, "CAuditEvent::GetPrivilegeRoles");
|
|
|
|
m_Request.DesiredAccess = MAXIMUM_ALLOWED;
|
|
m_Reply.GrantedAccessMask[0] = 0;
|
|
|
|
if(!AuthzAccessCheck(
|
|
0,
|
|
m_ClientContext,
|
|
&m_Request,
|
|
NULL, //no audit
|
|
m_pCASD,
|
|
NULL,
|
|
0,
|
|
&m_Reply,
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AuthzAccessCheck");
|
|
}
|
|
|
|
dwRoles |= (m_Reply.GrantedAccessMask[0] &
|
|
(CA_ACCESS_MASKROLES | // returned mask could also
|
|
CA_ACCESS_READ | // include generic rights (like
|
|
CA_ACCESS_ENROLL)); // read and write DACL) which
|
|
// we are not interested in
|
|
*pdwRoles = dwRoles;
|
|
|
|
error:
|
|
|
|
if(fImpersonating)
|
|
{
|
|
RevertToSelf();
|
|
}
|
|
|
|
FreeCachedHandles();
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Build a one ace DACL security descriptor with the roles
|
|
// passed in
|
|
HRESULT CAuditEvent::BuildPrivilegeSecurityDescriptor(DWORD dwRoles)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwDaclSize;
|
|
PSID pOwnerSid = NULL; // no free
|
|
PSID pGroupSid = NULL; // no free
|
|
BOOL fDefaulted;
|
|
|
|
CSASSERT(NULL == m_pSDPrivileges);
|
|
CSASSERT(NULL == m_pDaclPrivileges);
|
|
|
|
m_pSDPrivileges = (PSECURITY_DESCRIPTOR)LocalAlloc(
|
|
LMEM_FIXED,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
_JumpIfAllocFailed(m_pSDPrivileges, error);
|
|
|
|
if (!InitializeSecurityDescriptor(
|
|
m_pSDPrivileges,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "InitializeSecurityDescriptor");
|
|
}
|
|
|
|
CSASSERT(m_pUserSid && IsValidSid(m_pUserSid));
|
|
|
|
dwDaclSize = sizeof(ACL) +
|
|
sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+
|
|
GetLengthSid(m_pUserSid);
|
|
|
|
m_pDaclPrivileges = (PACL)LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, dwDaclSize);
|
|
_JumpIfAllocFailed(m_pDaclPrivileges, error);
|
|
|
|
if(!InitializeAcl(m_pDaclPrivileges, dwDaclSize, ACL_REVISION))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "InitializeAcl");
|
|
}
|
|
|
|
if(!AddAccessAllowedAce(
|
|
m_pDaclPrivileges,
|
|
ACL_REVISION,
|
|
dwRoles,
|
|
m_pUserSid))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "AddAccessAllowedAce");
|
|
}
|
|
|
|
if(!GetSecurityDescriptorOwner(m_pCASD,
|
|
&pOwnerSid,
|
|
&fDefaulted))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "GetSecurityDescriptorOwner");
|
|
}
|
|
|
|
if(!SetSecurityDescriptorOwner(m_pSDPrivileges,
|
|
pOwnerSid,
|
|
fDefaulted))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetSecurityDescriptorOwner");
|
|
}
|
|
|
|
if(!GetSecurityDescriptorGroup(m_pCASD,
|
|
&pGroupSid,
|
|
&fDefaulted))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "GetSecurityDescriptorGroup");
|
|
}
|
|
|
|
if(!SetSecurityDescriptorGroup(m_pSDPrivileges,
|
|
pGroupSid,
|
|
fDefaulted))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetSecurityDescriptorGroup");
|
|
}
|
|
|
|
if(!SetSecurityDescriptorDacl(m_pSDPrivileges,
|
|
TRUE,
|
|
m_pDaclPrivileges,
|
|
FALSE))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "SetSecurityDescriptorDacl");
|
|
}
|
|
|
|
CSASSERT(IsValidSecurityDescriptor(m_pSDPrivileges));
|
|
|
|
error:
|
|
|
|
if(S_OK != hr)
|
|
{
|
|
if(m_pDaclPrivileges)
|
|
{
|
|
LocalFree(m_pDaclPrivileges);
|
|
m_pDaclPrivileges = NULL;
|
|
}
|
|
|
|
if(m_pSDPrivileges)
|
|
{
|
|
LocalFree(m_pSDPrivileges);
|
|
m_pSDPrivileges = NULL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::BuildAuditParamArray(PAUDIT_PARAM& rpParamArray)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// number of parameters added should be the same as the number of
|
|
// params defined in the audit format string in msaudite.dll
|
|
CSASSERT(m_cEventData == m_cRequiredEventData);
|
|
|
|
rpParamArray = (PAUDIT_PARAM) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(AUDIT_PARAM)*m_cEventData);
|
|
_JumpIfAllocFailed(rpParamArray, error);
|
|
|
|
for(USHORT c=0;c<m_cEventData;c++)
|
|
{
|
|
rpParamArray[c].Type = APT_String;
|
|
|
|
hr = m_pEventDataList[c]->ConvertToString(
|
|
&rpParamArray[c].String);
|
|
_JumpIfError(hr, error, "ConvertToString");
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|
|
|
|
void CAuditEvent::FreeAuditParamArray(PAUDIT_PARAM pParamArray)
|
|
{
|
|
if(pParamArray)
|
|
{
|
|
for(USHORT c=0;c<m_cEventData;c++)
|
|
{
|
|
if(pParamArray[c].String)
|
|
LocalFree(pParamArray[c].String);
|
|
}
|
|
|
|
LocalFree(pParamArray);
|
|
}
|
|
}
|
|
|
|
HRESULT CAuditEvent::EnforceEncryption(bool fRequestInterface)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if((fRequestInterface?
|
|
IF_ENFORCEENCRYPTICERTREQUEST:
|
|
IF_ENFORCEENCRYPTICERTADMIN) &
|
|
g_InterfaceFlags)
|
|
{
|
|
if(m_pISS) // DCOM
|
|
{
|
|
DWORD dwAuthLevel;
|
|
hr = m_pISS->QueryBlanket(
|
|
NULL, NULL, NULL,
|
|
&dwAuthLevel,
|
|
NULL, NULL, NULL);
|
|
_JumpIfError(hr, error, "IServerSecurity::QueryBlanket");
|
|
|
|
if(RPC_C_AUTHN_LEVEL_PKT_PRIVACY != dwAuthLevel)
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
_JumpError(hr, error, "call not encrypted");
|
|
}
|
|
}
|
|
else // RPC
|
|
{
|
|
CSASSERT(m_hRpc);
|
|
|
|
unsigned long ulAuthLevel;
|
|
|
|
hr = RpcBindingInqAuthClient(
|
|
m_hRpc,
|
|
NULL, NULL,
|
|
&ulAuthLevel,
|
|
NULL, NULL);
|
|
_JumpIfError(hr, error, "RpcBindingInqAuthClient");
|
|
|
|
if(RPC_C_AUTHN_LEVEL_PKT_PRIVACY != ulAuthLevel)
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
_JumpError(hr, error, "call not encrypted");
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CAuditEvent::EnforceLocalVsRemote(ACCESS_MASK Mask)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwEnforceNoLocalFlag, dwEnforceNoRemoteFlag;
|
|
PSID psidNetwork = NULL;
|
|
BOOL fIsRemote;
|
|
|
|
hr = GetNetworkSID(&psidNetwork);
|
|
_JumpIfError(hr, error, "GetLocalSid");
|
|
|
|
if(!CheckTokenMembership(m_hClientToken, psidNetwork, &fIsRemote))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CheckTokenMembership");
|
|
}
|
|
|
|
switch(Mask)
|
|
{
|
|
case CA_ACCESS_OPERATOR:
|
|
dwEnforceNoRemoteFlag = IF_NOREMOTEICERTADMINBACKUP;
|
|
dwEnforceNoLocalFlag = IF_NOLOCALICERTADMINBACKUP;
|
|
break;
|
|
case CA_ACCESS_ENROLL:
|
|
dwEnforceNoRemoteFlag = IF_NOREMOTEICERTREQUEST;
|
|
dwEnforceNoLocalFlag = IF_NOLOCALICERTREQUEST;
|
|
break;
|
|
default:
|
|
dwEnforceNoRemoteFlag = IF_NOREMOTEICERTADMIN;
|
|
dwEnforceNoLocalFlag = IF_NOLOCALICERTADMIN;
|
|
break;
|
|
}
|
|
|
|
if((fIsRemote && (g_InterfaceFlags & dwEnforceNoRemoteFlag)) ||
|
|
(!fIsRemote && (g_InterfaceFlags & dwEnforceNoLocalFlag)))
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
}
|
|
|
|
error:
|
|
if (NULL != psidNetwork)
|
|
{
|
|
FreeSid(psidNetwork);
|
|
}
|
|
return hr;
|
|
}
|