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.
 
 
 
 
 
 

689 lines
17 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: casec.cpp
//
//--------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////
// casec.cpp
//
// ISecurityInformation implementation for CA objects
// and the new acl editor
//
// PURPOSE
//
//
// DYNALOADED LIBRARIES
//
// HISTORY
// 5-Nov-1998 petesk Copied template from privobsi.cpp sample.
//
/////////////////////////////////////////////////////////////////////
#include <stdafx.h>
#include <accctrl.h>
#include <certca.h>
#include <sddl.h>
#include "certsrvd.h"
#include "certacl.h"
#define __dwFILE__ __dwFILE_CERTMMC_CASEC_CPP__
//
// defined in Security.cpp
//
// // define our generic mapping structure for our private objects //
#define INHERIT_FULL (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)
GENERIC_MAPPING ObjMap =
{
ACTRL_CERTSRV_READ,
DELETE | WRITE_DAC | WRITE_OWNER | ACTRL_DS_WRITE_PROP,
0,
ACTRL_CERTSRV_MANAGE
};
//
// DESCRIPTION OF ACCESS FLAG AFFECTS
//
// SI_ACCESS_GENERAL shows up on general properties page
// SI_ACCESS_SPECIFIC shows up on advanced page
// SI_ACCESS_CONTAINER shows on general page IF object is a container
//
SI_ACCESS g_siObjAccesses[] = {CERTSRV_SI_ACCESS_LIST};
#define g_iObjDefAccess 3 // ENROLL enabled by default
// The following array defines the inheritance types for my containers.
SI_INHERIT_TYPE g_siObjInheritTypes[] =
{
&GUID_NULL, 0, MAKEINTRESOURCE(IDS_INH_NONE),
};
HRESULT
LocalAllocString(LPWSTR* ppResult, LPCWSTR pString)
{
if (!ppResult || !pString)
return E_INVALIDARG;
*ppResult = (LPWSTR)LocalAlloc(LPTR, (lstrlen(pString) + 1) * sizeof(WCHAR));
if (!*ppResult)
return E_OUTOFMEMORY;
lstrcpy(*ppResult, pString);
return S_OK;
}
void
LocalFreeString(LPWSTR* ppString)
{
if (ppString)
{
if (*ppString)
LocalFree(*ppString);
*ppString = NULL;
}
}
class CCASecurityObject : public ISecurityInformation
{
protected:
ULONG m_cRef;
CertSvrCA * m_pSvrCA;
// PSECURITY_DESCRIPTOR m_pSD;
public:
CCASecurityObject() : m_cRef(1)
{
m_pSvrCA = NULL;
// m_pSD = NULL;
}
virtual ~CCASecurityObject();
STDMETHOD(Initialize)(CertSvrCA *pCA);
// IUnknown methods
STDMETHOD(QueryInterface)(REFIID, LPVOID *);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
// ISecurityInformation methods
STDMETHOD(GetObjectInformation)(PSI_OBJECT_INFO pObjectInfo);
STDMETHOD(GetSecurity)(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR *ppSD,
BOOL fDefault);
STDMETHOD(SetSecurity)(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD);
STDMETHOD(GetAccessRights)(const GUID* pguidObjectType,
DWORD dwFlags,
PSI_ACCESS *ppAccess,
ULONG *pcAccesses,
ULONG *piDefaultAccess);
STDMETHOD(MapGeneric)(const GUID *pguidObjectType,
UCHAR *pAceFlags,
ACCESS_MASK *pmask);
STDMETHOD(GetInheritTypes)(PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes);
STDMETHOD(PropertySheetPageCallback)(HWND hwnd,
UINT uMsg,
SI_PAGE_TYPE uPage);
protected:
HRESULT GetSecurityDCOM(PSECURITY_DESCRIPTOR *ppSD);
HRESULT GetSecurityRegistry(PSECURITY_DESCRIPTOR *ppSD);
HRESULT SetSecurityDCOM(PSECURITY_DESCRIPTOR pSD);
HRESULT SetSecurityRegistry(PSECURITY_DESCRIPTOR pSD);
};
///////////////////////////////////////////////////////////////////////////////
//
// This is the entry point function called from our code that establishes
// what the ACLUI interface is going to need to know.
//
//
///////////////////////////////////////////////////////////////////////////////
extern "C"
HRESULT
CreateCASecurityInfo( CertSvrCA *pCA,
LPSECURITYINFO *ppObjSI)
{
HRESULT hr;
CCASecurityObject *psi;
*ppObjSI = NULL;
psi = new CCASecurityObject;
if (!psi)
return E_OUTOFMEMORY;
hr = psi->Initialize(pCA);
if (SUCCEEDED(hr))
*ppObjSI = psi;
else
delete psi;
return hr;
}
CCASecurityObject::~CCASecurityObject()
{
}
STDMETHODIMP
CCASecurityObject::Initialize(CertSvrCA *pCA)
{
m_pSvrCA = pCA;
return S_OK;
}
///////////////////////////////////////////////////////////
//
// IUnknown methods
//
///////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CCASecurityObject::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG)
CCASecurityObject::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
STDMETHODIMP
CCASecurityObject::QueryInterface(REFIID riid, LPVOID FAR* ppv)
{
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
{
*ppv = (LPSECURITYINFO)this;
m_cRef++;
return S_OK;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
///////////////////////////////////////////////////////////
//
// ISecurityInformation methods
//
///////////////////////////////////////////////////////////
STDMETHODIMP
CCASecurityObject::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
{
if(pObjectInfo == NULL)
{
return E_POINTER;
}
if(m_pSvrCA == NULL)
{
return E_POINTER;
}
ZeroMemory(pObjectInfo, sizeof(SI_OBJECT_INFO));
pObjectInfo->dwFlags = SI_EDIT_PERMS |
SI_NO_TREE_APPLY |
SI_EDIT_AUDITS |
SI_NO_ACL_PROTECT |
SI_NO_ADDITIONAL_PERMISSION;
if(!m_pSvrCA->AccessAllowed(CA_ACCESS_ADMIN))
pObjectInfo->dwFlags |= SI_READONLY;
pObjectInfo->hInstance = g_hInstance;
if(m_pSvrCA->m_pParentMachine)
{
pObjectInfo->pszServerName = const_cast<WCHAR *>((LPCTSTR)m_pSvrCA->m_pParentMachine->m_strMachineName);
}
pObjectInfo->pszObjectName = const_cast<WCHAR *>((LPCTSTR)m_pSvrCA->m_strCommonName);
return S_OK;
}
HRESULT CCASecurityObject::GetSecurityDCOM(PSECURITY_DESCRIPTOR *ppSD)
{
HRESULT hr = S_OK;
ICertAdminD2 *pICertAdminD = NULL;
DWORD dwServerVersion = 0; // 0 required by myOpenAdminDComConnection
WCHAR const *pwszAuthority;
CERTTRANSBLOB ctbSD;
ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB));
CSASSERT(m_pSvrCA);
hr = myOpenAdminDComConnection(
m_pSvrCA->m_bstrConfig,
&pwszAuthority,
NULL,
&dwServerVersion,
&pICertAdminD);
_JumpIfError(hr, error, "myOpenAdminDComConnection");
if (2 > dwServerVersion)
{
hr = RPC_E_VERSION_MISMATCH;
_JumpError(hr, error, "old server");
}
__try
{
hr = pICertAdminD->GetCASecurity(
pwszAuthority,
&ctbSD);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
_JumpIfError(hr, error, "pICertAdminD->GetCASecurity");
myRegisterMemAlloc(ctbSD.pb, ctbSD.cb, CSM_COTASKALLOC);
// take the return
*ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, ctbSD.cb);
if (NULL == *ppSD)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
MoveMemory(*ppSD, ctbSD.pb, ctbSD.cb);
error:
myCloseDComConnection((IUnknown **) &pICertAdminD, NULL);
if (NULL != ctbSD.pb)
{
CoTaskMemFree(ctbSD.pb);
}
return hr;
}
HRESULT CCASecurityObject::GetSecurityRegistry(PSECURITY_DESCRIPTOR *ppSD)
{
HRESULT hr = S_OK;
variant_t var;
DWORD dwType;
DWORD dwSize;
BYTE* pbTmp;
hr = m_pSvrCA->GetConfigEntry(
NULL,
wszREGCASECURITY,
&var);
_JumpIfError(hr, error, "GetConfigEntry");
hr = myVariantToRegValue(
&var,
&dwType,
&dwSize,
&pbTmp);
_JumpIfError(hr, error, "myVariantToRegValue");
*ppSD = pbTmp;
error:
return hr;
}
STDMETHODIMP
CCASecurityObject::GetSecurity(
SECURITY_INFORMATION, // si
PSECURITY_DESCRIPTOR *ppSD,
BOOL /* fDefault */ )
{
HRESULT hr = S_OK;
SECURITY_DESCRIPTOR_CONTROL Control = SE_DACL_PROTECTED;
DWORD dwRevision;
hr = GetSecurityDCOM(ppSD);
_PrintIfError(hr, "GetSecurityDCOM");
if(S_OK!=hr)
{
hr = GetSecurityRegistry(ppSD);
_JumpIfError(hr, error, "GetSecurityRegistry");
}
CSASSERT(*ppSD);
if(GetSecurityDescriptorControl(*ppSD, &Control, &dwRevision))
{
Control &= SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED;
SetSecurityDescriptorControl(*ppSD,
SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED,
Control);
}
error:
return hr;
}
HRESULT CCASecurityObject::SetSecurityDCOM(PSECURITY_DESCRIPTOR pSD)
{
HRESULT hr = S_OK;
HANDLE hClientToken = NULL;
HANDLE hHandle = NULL;
ICertAdminD2 *pICertAdminD = NULL;
DWORD dwServerVersion = 0;
CERTTRANSBLOB ctbSD;
WCHAR const *pwszAuthority;
hHandle = GetCurrentThread();
if (NULL == hHandle)
{
hr = myHLastError();
}
else
{
if (!OpenThreadToken(hHandle,
TOKEN_QUERY,
TRUE, // open as self
&hClientToken))
{
hr = myHLastError();
CloseHandle(hHandle);
hHandle = NULL;
}
}
if(hr != S_OK)
{
hHandle = GetCurrentProcess();
if (NULL == hHandle)
{
hr = myHLastError();
}
else
{
HANDLE hProcessToken = NULL;
hr = S_OK;
if (!OpenProcessToken(hHandle,
TOKEN_DUPLICATE,
&hProcessToken))
{
hr = myHLastError();
CloseHandle(hHandle);
hHandle = NULL;
}
else
{
if(!DuplicateToken(hProcessToken,
SecurityImpersonation,
&hClientToken))
{
hr = myHLastError();
CloseHandle(hHandle);
hHandle = NULL;
}
CloseHandle(hProcessToken);
}
}
}
if(hr != S_OK)
{
goto error;
}
hr = myOpenAdminDComConnection(
m_pSvrCA->m_bstrConfig,
&pwszAuthority,
NULL,
&dwServerVersion,
&pICertAdminD);
_JumpIfError(hr, error, "myOpenAdminDComConnection");
if (2 > dwServerVersion)
{
hr = RPC_E_VERSION_MISMATCH;
_JumpError(hr, error, "old server");
}
__try
{
ctbSD.cb = GetSecurityDescriptorLength(pSD);
ctbSD.pb = (BYTE*)pSD;
hr = pICertAdminD->SetCASecurity(
pwszAuthority,
&ctbSD);
if(hr == HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE))
{
// Attempt to fix enrollment object, see bug# 193388
m_pSvrCA->FixEnrollmentObject();
// try again
hr = pICertAdminD->SetCASecurity(
pwszAuthority,
&ctbSD);
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
_JumpIfError(hr, error, "pICertAdminD->SetCASecurity");
error:
myCloseDComConnection((IUnknown **) &pICertAdminD, NULL);
if(hClientToken)
{
CloseHandle(hClientToken);
}
if(hHandle)
{
CloseHandle(hHandle);
}
return hr;
}
HRESULT CCASecurityObject::SetSecurityRegistry(PSECURITY_DESCRIPTOR pSD)
{
HRESULT hr = S_OK;
variant_t var;
CertSrv::CCertificateAuthoritySD CASD;
// SD passed in contains only a DACL. We need to fully construct the
// CA SD as certsrv would do
hr = CASD.InitializeFromTemplate(WSZ_EMPTY_CA_SECURITY, L"");
_JumpIfError(hr, error, "CCertificateAuthoritySD::Initialize");
hr = CASD.Set(pSD, false);
_JumpIfError(hr, error, "CCertificateAuthoritySD::Set");
hr = myRegValueToVariant(
REG_BINARY,
GetSecurityDescriptorLength(CASD.Get()),
(BYTE const*)CASD.Get(),
&var);
_JumpIfError(hr, error, "myRegValueToVariant");
hr = m_pSvrCA->SetConfigEntry(
NULL,
wszREGCASECURITY,
&var);
_JumpIfErrorStr(hr, error, "SetConfigEntry", wszREGCASECURITY);
// set status bit to signal certsrv to pick up changes next
// time it starts
hr = m_pSvrCA->GetConfigEntry(
NULL,
wszREGSETUPSTATUS,
&var);
_JumpIfErrorStr(hr, error, "GetConfigEntry", wszREGSETUPSTATUS);
V_I4(&var) |= SETUP_SECURITY_CHANGED;
hr = m_pSvrCA->SetConfigEntry(
NULL,
wszREGSETUPSTATUS,
&var);
_JumpIfErrorStr(hr, error, "SetConfigEntry", wszREGSETUPSTATUS);
error:
return hr;
}
STDMETHODIMP
CCASecurityObject::SetSecurity(SECURITY_INFORMATION si,
PSECURITY_DESCRIPTOR pSD)
{
HRESULT hr = S_OK;
SECURITY_DESCRIPTOR_CONTROL Control = SE_DACL_PROTECTED;
DWORD dwSize;
DWORD dwRevision;
PSECURITY_DESCRIPTOR pSDSelfRel = NULL;
if (DACL_SECURITY_INFORMATION!=si)
return E_NOTIMPL;
if(si & DACL_SECURITY_INFORMATION)
{
if(GetSecurityDescriptorControl(pSD, &Control, &dwRevision))
{
Control &= SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED;
SetSecurityDescriptorControl(pSD,
SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED,
Control);
}
}
dwSize = GetSecurityDescriptorLength(pSD);
pSDSelfRel = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSize);
if(NULL == pSDSelfRel)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!MakeSelfRelativeSD(pSD, pSDSelfRel, &dwSize))
{
LocalFree(pSDSelfRel);
pSDSelfRel = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSize);
if(NULL == pSDSelfRel)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if(!MakeSelfRelativeSD(pSD, pSDSelfRel, &dwSize))
{
hr = myHLastError();
_JumpError(hr, error, "LocalAlloc");
}
}
hr = SetSecurityDCOM(pSDSelfRel);
if (S_OK != hr)
{
HRESULT hr2 = hr;
_PrintError(hr, "SetSecurityDCOM");
if (E_ACCESSDENIED == hr ||
(HRESULT) RPC_S_SERVER_UNAVAILABLE == hr ||
HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) == hr)
{
hr2 = SetSecurityRegistry(pSDSelfRel);
_JumpIfError(hr2, error, "SetSecurityRegistry");
}
DisplayCertSrvErrorWithContext(NULL, hr, IDS_CANNOT_UPDATE_SECURITY_ON_CA);
if (S_OK == hr2)
{
hr = S_OK;
}
}
error:
if(NULL != pSDSelfRel)
{
LocalFree(pSDSelfRel);
}
return hr;
}
STDMETHODIMP
CCASecurityObject::GetAccessRights(const GUID* /*pguidObjectType*/,
DWORD /*dwFlags*/,
PSI_ACCESS *ppAccesses,
ULONG *pcAccesses,
ULONG *piDefaultAccess)
{
*ppAccesses = g_siObjAccesses;
*pcAccesses = sizeof(g_siObjAccesses)/sizeof(g_siObjAccesses[0]);
*piDefaultAccess = g_iObjDefAccess;
return S_OK;
}
STDMETHODIMP
CCASecurityObject::MapGeneric(const GUID* /*pguidObjectType*/,
UCHAR * /*pAceFlags*/,
ACCESS_MASK *pmask)
{
MapGenericMask(pmask, &ObjMap);
return S_OK;
}
STDMETHODIMP
CCASecurityObject::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
ULONG *pcInheritTypes)
{
*ppInheritTypes = g_siObjInheritTypes;
*pcInheritTypes = sizeof(g_siObjInheritTypes)/sizeof(g_siObjInheritTypes[0]);
return S_OK;
}
STDMETHODIMP
CCASecurityObject::PropertySheetPageCallback(HWND /*hwnd*/,
UINT /*uMsg*/,
SI_PAGE_TYPE /*uPage*/)
{
return S_OK;
}