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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: casec.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // casec.cpp
  12. //
  13. // ISecurityInformation implementation for CA objects
  14. // and the new acl editor
  15. //
  16. // PURPOSE
  17. //
  18. //
  19. // DYNALOADED LIBRARIES
  20. //
  21. // HISTORY
  22. // 5-Nov-1998 petesk Copied template from privobsi.cpp sample.
  23. //
  24. /////////////////////////////////////////////////////////////////////
  25. #include <stdafx.h>
  26. #include <accctrl.h>
  27. #include <certca.h>
  28. #include <sddl.h>
  29. #include "certsrvd.h"
  30. #include "certacl.h"
  31. #define __dwFILE__ __dwFILE_CERTMMC_CASEC_CPP__
  32. //
  33. // defined in Security.cpp
  34. //
  35. // // define our generic mapping structure for our private objects //
  36. #define INHERIT_FULL (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)
  37. GENERIC_MAPPING ObjMap =
  38. {
  39. ACTRL_CERTSRV_READ,
  40. DELETE | WRITE_DAC | WRITE_OWNER | ACTRL_DS_WRITE_PROP,
  41. 0,
  42. ACTRL_CERTSRV_MANAGE
  43. };
  44. //
  45. // DESCRIPTION OF ACCESS FLAG AFFECTS
  46. //
  47. // SI_ACCESS_GENERAL shows up on general properties page
  48. // SI_ACCESS_SPECIFIC shows up on advanced page
  49. // SI_ACCESS_CONTAINER shows on general page IF object is a container
  50. //
  51. SI_ACCESS g_siObjAccesses[] = {CERTSRV_SI_ACCESS_LIST};
  52. #define g_iObjDefAccess 3 // ENROLL enabled by default
  53. // The following array defines the inheritance types for my containers.
  54. SI_INHERIT_TYPE g_siObjInheritTypes[] =
  55. {
  56. &GUID_NULL, 0, MAKEINTRESOURCE(IDS_INH_NONE),
  57. };
  58. HRESULT
  59. LocalAllocString(LPWSTR* ppResult, LPCWSTR pString)
  60. {
  61. if (!ppResult || !pString)
  62. return E_INVALIDARG;
  63. *ppResult = (LPWSTR)LocalAlloc(LPTR, (lstrlen(pString) + 1) * sizeof(WCHAR));
  64. if (!*ppResult)
  65. return E_OUTOFMEMORY;
  66. lstrcpy(*ppResult, pString);
  67. return S_OK;
  68. }
  69. void
  70. LocalFreeString(LPWSTR* ppString)
  71. {
  72. if (ppString)
  73. {
  74. if (*ppString)
  75. LocalFree(*ppString);
  76. *ppString = NULL;
  77. }
  78. }
  79. class CCASecurityObject : public ISecurityInformation
  80. {
  81. protected:
  82. ULONG m_cRef;
  83. CertSvrCA * m_pSvrCA;
  84. // PSECURITY_DESCRIPTOR m_pSD;
  85. public:
  86. CCASecurityObject() : m_cRef(1)
  87. {
  88. m_pSvrCA = NULL;
  89. // m_pSD = NULL;
  90. }
  91. virtual ~CCASecurityObject();
  92. STDMETHOD(Initialize)(CertSvrCA *pCA);
  93. // IUnknown methods
  94. STDMETHOD(QueryInterface)(REFIID, LPVOID *);
  95. STDMETHOD_(ULONG, AddRef)();
  96. STDMETHOD_(ULONG, Release)();
  97. // ISecurityInformation methods
  98. STDMETHOD(GetObjectInformation)(PSI_OBJECT_INFO pObjectInfo);
  99. STDMETHOD(GetSecurity)(SECURITY_INFORMATION si,
  100. PSECURITY_DESCRIPTOR *ppSD,
  101. BOOL fDefault);
  102. STDMETHOD(SetSecurity)(SECURITY_INFORMATION si,
  103. PSECURITY_DESCRIPTOR pSD);
  104. STDMETHOD(GetAccessRights)(const GUID* pguidObjectType,
  105. DWORD dwFlags,
  106. PSI_ACCESS *ppAccess,
  107. ULONG *pcAccesses,
  108. ULONG *piDefaultAccess);
  109. STDMETHOD(MapGeneric)(const GUID *pguidObjectType,
  110. UCHAR *pAceFlags,
  111. ACCESS_MASK *pmask);
  112. STDMETHOD(GetInheritTypes)(PSI_INHERIT_TYPE *ppInheritTypes,
  113. ULONG *pcInheritTypes);
  114. STDMETHOD(PropertySheetPageCallback)(HWND hwnd,
  115. UINT uMsg,
  116. SI_PAGE_TYPE uPage);
  117. protected:
  118. HRESULT GetSecurityDCOM(PSECURITY_DESCRIPTOR *ppSD);
  119. HRESULT GetSecurityRegistry(PSECURITY_DESCRIPTOR *ppSD);
  120. HRESULT SetSecurityDCOM(PSECURITY_DESCRIPTOR pSD);
  121. HRESULT SetSecurityRegistry(PSECURITY_DESCRIPTOR pSD);
  122. };
  123. ///////////////////////////////////////////////////////////////////////////////
  124. //
  125. // This is the entry point function called from our code that establishes
  126. // what the ACLUI interface is going to need to know.
  127. //
  128. //
  129. ///////////////////////////////////////////////////////////////////////////////
  130. extern "C"
  131. HRESULT
  132. CreateCASecurityInfo( CertSvrCA *pCA,
  133. LPSECURITYINFO *ppObjSI)
  134. {
  135. HRESULT hr;
  136. CCASecurityObject *psi;
  137. *ppObjSI = NULL;
  138. psi = new CCASecurityObject;
  139. if (!psi)
  140. return E_OUTOFMEMORY;
  141. hr = psi->Initialize(pCA);
  142. if (SUCCEEDED(hr))
  143. *ppObjSI = psi;
  144. else
  145. delete psi;
  146. return hr;
  147. }
  148. CCASecurityObject::~CCASecurityObject()
  149. {
  150. }
  151. STDMETHODIMP
  152. CCASecurityObject::Initialize(CertSvrCA *pCA)
  153. {
  154. m_pSvrCA = pCA;
  155. return S_OK;
  156. }
  157. ///////////////////////////////////////////////////////////
  158. //
  159. // IUnknown methods
  160. //
  161. ///////////////////////////////////////////////////////////
  162. STDMETHODIMP_(ULONG)
  163. CCASecurityObject::AddRef()
  164. {
  165. return ++m_cRef;
  166. }
  167. STDMETHODIMP_(ULONG)
  168. CCASecurityObject::Release()
  169. {
  170. if (--m_cRef == 0)
  171. {
  172. delete this;
  173. return 0;
  174. }
  175. return m_cRef;
  176. }
  177. STDMETHODIMP
  178. CCASecurityObject::QueryInterface(REFIID riid, LPVOID FAR* ppv)
  179. {
  180. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
  181. {
  182. *ppv = (LPSECURITYINFO)this;
  183. m_cRef++;
  184. return S_OK;
  185. }
  186. else
  187. {
  188. *ppv = NULL;
  189. return E_NOINTERFACE;
  190. }
  191. }
  192. ///////////////////////////////////////////////////////////
  193. //
  194. // ISecurityInformation methods
  195. //
  196. ///////////////////////////////////////////////////////////
  197. STDMETHODIMP
  198. CCASecurityObject::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
  199. {
  200. if(pObjectInfo == NULL)
  201. {
  202. return E_POINTER;
  203. }
  204. if(m_pSvrCA == NULL)
  205. {
  206. return E_POINTER;
  207. }
  208. ZeroMemory(pObjectInfo, sizeof(SI_OBJECT_INFO));
  209. pObjectInfo->dwFlags = SI_EDIT_PERMS |
  210. SI_NO_TREE_APPLY |
  211. SI_EDIT_AUDITS |
  212. SI_NO_ACL_PROTECT |
  213. SI_NO_ADDITIONAL_PERMISSION;
  214. if(!m_pSvrCA->AccessAllowed(CA_ACCESS_ADMIN))
  215. pObjectInfo->dwFlags |= SI_READONLY;
  216. pObjectInfo->hInstance = g_hInstance;
  217. if(m_pSvrCA->m_pParentMachine)
  218. {
  219. pObjectInfo->pszServerName = const_cast<WCHAR *>((LPCTSTR)m_pSvrCA->m_pParentMachine->m_strMachineName);
  220. }
  221. pObjectInfo->pszObjectName = const_cast<WCHAR *>((LPCTSTR)m_pSvrCA->m_strCommonName);
  222. return S_OK;
  223. }
  224. HRESULT CCASecurityObject::GetSecurityDCOM(PSECURITY_DESCRIPTOR *ppSD)
  225. {
  226. HRESULT hr = S_OK;
  227. ICertAdminD2 *pICertAdminD = NULL;
  228. DWORD dwServerVersion = 0; // 0 required by myOpenAdminDComConnection
  229. WCHAR const *pwszAuthority;
  230. CERTTRANSBLOB ctbSD;
  231. ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB));
  232. CSASSERT(m_pSvrCA);
  233. hr = myOpenAdminDComConnection(
  234. m_pSvrCA->m_bstrConfig,
  235. &pwszAuthority,
  236. NULL,
  237. &dwServerVersion,
  238. &pICertAdminD);
  239. _JumpIfError(hr, error, "myOpenAdminDComConnection");
  240. if (2 > dwServerVersion)
  241. {
  242. hr = RPC_E_VERSION_MISMATCH;
  243. _JumpError(hr, error, "old server");
  244. }
  245. __try
  246. {
  247. hr = pICertAdminD->GetCASecurity(
  248. pwszAuthority,
  249. &ctbSD);
  250. }
  251. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  252. {
  253. }
  254. _JumpIfError(hr, error, "pICertAdminD->GetCASecurity");
  255. myRegisterMemAlloc(ctbSD.pb, ctbSD.cb, CSM_COTASKALLOC);
  256. // take the return
  257. *ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, ctbSD.cb);
  258. if (NULL == *ppSD)
  259. {
  260. hr = E_OUTOFMEMORY;
  261. _JumpError(hr, error, "LocalAlloc");
  262. }
  263. MoveMemory(*ppSD, ctbSD.pb, ctbSD.cb);
  264. error:
  265. myCloseDComConnection((IUnknown **) &pICertAdminD, NULL);
  266. if (NULL != ctbSD.pb)
  267. {
  268. CoTaskMemFree(ctbSD.pb);
  269. }
  270. return hr;
  271. }
  272. HRESULT CCASecurityObject::GetSecurityRegistry(PSECURITY_DESCRIPTOR *ppSD)
  273. {
  274. HRESULT hr = S_OK;
  275. variant_t var;
  276. DWORD dwType;
  277. DWORD dwSize;
  278. BYTE* pbTmp;
  279. hr = m_pSvrCA->GetConfigEntry(
  280. NULL,
  281. wszREGCASECURITY,
  282. &var);
  283. _JumpIfError(hr, error, "GetConfigEntry");
  284. hr = myVariantToRegValue(
  285. &var,
  286. &dwType,
  287. &dwSize,
  288. &pbTmp);
  289. _JumpIfError(hr, error, "myVariantToRegValue");
  290. *ppSD = pbTmp;
  291. error:
  292. return hr;
  293. }
  294. STDMETHODIMP
  295. CCASecurityObject::GetSecurity(
  296. SECURITY_INFORMATION, // si
  297. PSECURITY_DESCRIPTOR *ppSD,
  298. BOOL /* fDefault */ )
  299. {
  300. HRESULT hr = S_OK;
  301. SECURITY_DESCRIPTOR_CONTROL Control = SE_DACL_PROTECTED;
  302. DWORD dwRevision;
  303. hr = GetSecurityDCOM(ppSD);
  304. _PrintIfError(hr, "GetSecurityDCOM");
  305. if(S_OK!=hr)
  306. {
  307. hr = GetSecurityRegistry(ppSD);
  308. _JumpIfError(hr, error, "GetSecurityRegistry");
  309. }
  310. CSASSERT(*ppSD);
  311. if(GetSecurityDescriptorControl(*ppSD, &Control, &dwRevision))
  312. {
  313. Control &= SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED;
  314. SetSecurityDescriptorControl(*ppSD,
  315. SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED,
  316. Control);
  317. }
  318. error:
  319. return hr;
  320. }
  321. HRESULT CCASecurityObject::SetSecurityDCOM(PSECURITY_DESCRIPTOR pSD)
  322. {
  323. HRESULT hr = S_OK;
  324. HANDLE hClientToken = NULL;
  325. HANDLE hHandle = NULL;
  326. ICertAdminD2 *pICertAdminD = NULL;
  327. DWORD dwServerVersion = 0;
  328. CERTTRANSBLOB ctbSD;
  329. WCHAR const *pwszAuthority;
  330. hHandle = GetCurrentThread();
  331. if (NULL == hHandle)
  332. {
  333. hr = myHLastError();
  334. }
  335. else
  336. {
  337. if (!OpenThreadToken(hHandle,
  338. TOKEN_QUERY,
  339. TRUE, // open as self
  340. &hClientToken))
  341. {
  342. hr = myHLastError();
  343. CloseHandle(hHandle);
  344. hHandle = NULL;
  345. }
  346. }
  347. if(hr != S_OK)
  348. {
  349. hHandle = GetCurrentProcess();
  350. if (NULL == hHandle)
  351. {
  352. hr = myHLastError();
  353. }
  354. else
  355. {
  356. HANDLE hProcessToken = NULL;
  357. hr = S_OK;
  358. if (!OpenProcessToken(hHandle,
  359. TOKEN_DUPLICATE,
  360. &hProcessToken))
  361. {
  362. hr = myHLastError();
  363. CloseHandle(hHandle);
  364. hHandle = NULL;
  365. }
  366. else
  367. {
  368. if(!DuplicateToken(hProcessToken,
  369. SecurityImpersonation,
  370. &hClientToken))
  371. {
  372. hr = myHLastError();
  373. CloseHandle(hHandle);
  374. hHandle = NULL;
  375. }
  376. CloseHandle(hProcessToken);
  377. }
  378. }
  379. }
  380. if(hr != S_OK)
  381. {
  382. goto error;
  383. }
  384. hr = myOpenAdminDComConnection(
  385. m_pSvrCA->m_bstrConfig,
  386. &pwszAuthority,
  387. NULL,
  388. &dwServerVersion,
  389. &pICertAdminD);
  390. _JumpIfError(hr, error, "myOpenAdminDComConnection");
  391. if (2 > dwServerVersion)
  392. {
  393. hr = RPC_E_VERSION_MISMATCH;
  394. _JumpError(hr, error, "old server");
  395. }
  396. __try
  397. {
  398. ctbSD.cb = GetSecurityDescriptorLength(pSD);
  399. ctbSD.pb = (BYTE*)pSD;
  400. hr = pICertAdminD->SetCASecurity(
  401. pwszAuthority,
  402. &ctbSD);
  403. if(hr == HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE))
  404. {
  405. // Attempt to fix enrollment object, see bug# 193388
  406. m_pSvrCA->FixEnrollmentObject();
  407. // try again
  408. hr = pICertAdminD->SetCASecurity(
  409. pwszAuthority,
  410. &ctbSD);
  411. }
  412. }
  413. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  414. {
  415. }
  416. _JumpIfError(hr, error, "pICertAdminD->SetCASecurity");
  417. error:
  418. myCloseDComConnection((IUnknown **) &pICertAdminD, NULL);
  419. if(hClientToken)
  420. {
  421. CloseHandle(hClientToken);
  422. }
  423. if(hHandle)
  424. {
  425. CloseHandle(hHandle);
  426. }
  427. return hr;
  428. }
  429. HRESULT CCASecurityObject::SetSecurityRegistry(PSECURITY_DESCRIPTOR pSD)
  430. {
  431. HRESULT hr = S_OK;
  432. variant_t var;
  433. CertSrv::CCertificateAuthoritySD CASD;
  434. // SD passed in contains only a DACL. We need to fully construct the
  435. // CA SD as certsrv would do
  436. hr = CASD.InitializeFromTemplate(WSZ_EMPTY_CA_SECURITY, L"");
  437. _JumpIfError(hr, error, "CCertificateAuthoritySD::Initialize");
  438. hr = CASD.Set(pSD, false);
  439. _JumpIfError(hr, error, "CCertificateAuthoritySD::Set");
  440. hr = myRegValueToVariant(
  441. REG_BINARY,
  442. GetSecurityDescriptorLength(CASD.Get()),
  443. (BYTE const*)CASD.Get(),
  444. &var);
  445. _JumpIfError(hr, error, "myRegValueToVariant");
  446. hr = m_pSvrCA->SetConfigEntry(
  447. NULL,
  448. wszREGCASECURITY,
  449. &var);
  450. _JumpIfErrorStr(hr, error, "SetConfigEntry", wszREGCASECURITY);
  451. // set status bit to signal certsrv to pick up changes next
  452. // time it starts
  453. hr = m_pSvrCA->GetConfigEntry(
  454. NULL,
  455. wszREGSETUPSTATUS,
  456. &var);
  457. _JumpIfErrorStr(hr, error, "GetConfigEntry", wszREGSETUPSTATUS);
  458. V_I4(&var) |= SETUP_SECURITY_CHANGED;
  459. hr = m_pSvrCA->SetConfigEntry(
  460. NULL,
  461. wszREGSETUPSTATUS,
  462. &var);
  463. _JumpIfErrorStr(hr, error, "SetConfigEntry", wszREGSETUPSTATUS);
  464. error:
  465. return hr;
  466. }
  467. STDMETHODIMP
  468. CCASecurityObject::SetSecurity(SECURITY_INFORMATION si,
  469. PSECURITY_DESCRIPTOR pSD)
  470. {
  471. HRESULT hr = S_OK;
  472. SECURITY_DESCRIPTOR_CONTROL Control = SE_DACL_PROTECTED;
  473. DWORD dwSize;
  474. DWORD dwRevision;
  475. PSECURITY_DESCRIPTOR pSDSelfRel = NULL;
  476. if (DACL_SECURITY_INFORMATION!=si)
  477. return E_NOTIMPL;
  478. if(si & DACL_SECURITY_INFORMATION)
  479. {
  480. if(GetSecurityDescriptorControl(pSD, &Control, &dwRevision))
  481. {
  482. Control &= SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED;
  483. SetSecurityDescriptorControl(pSD,
  484. SE_DACL_PROTECTED | SE_DACL_AUTO_INHERIT_REQ | SE_DACL_AUTO_INHERITED,
  485. Control);
  486. }
  487. }
  488. dwSize = GetSecurityDescriptorLength(pSD);
  489. pSDSelfRel = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSize);
  490. if(NULL == pSDSelfRel)
  491. {
  492. hr = E_OUTOFMEMORY;
  493. _JumpError(hr, error, "LocalAlloc");
  494. }
  495. if(!MakeSelfRelativeSD(pSD, pSDSelfRel, &dwSize))
  496. {
  497. LocalFree(pSDSelfRel);
  498. pSDSelfRel = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSize);
  499. if(NULL == pSDSelfRel)
  500. {
  501. hr = E_OUTOFMEMORY;
  502. _JumpError(hr, error, "LocalAlloc");
  503. }
  504. if(!MakeSelfRelativeSD(pSD, pSDSelfRel, &dwSize))
  505. {
  506. hr = myHLastError();
  507. _JumpError(hr, error, "LocalAlloc");
  508. }
  509. }
  510. hr = SetSecurityDCOM(pSDSelfRel);
  511. if (S_OK != hr)
  512. {
  513. HRESULT hr2 = hr;
  514. _PrintError(hr, "SetSecurityDCOM");
  515. if (E_ACCESSDENIED == hr ||
  516. (HRESULT) RPC_S_SERVER_UNAVAILABLE == hr ||
  517. HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) == hr)
  518. {
  519. hr2 = SetSecurityRegistry(pSDSelfRel);
  520. _JumpIfError(hr2, error, "SetSecurityRegistry");
  521. }
  522. DisplayCertSrvErrorWithContext(NULL, hr, IDS_CANNOT_UPDATE_SECURITY_ON_CA);
  523. if (S_OK == hr2)
  524. {
  525. hr = S_OK;
  526. }
  527. }
  528. error:
  529. if(NULL != pSDSelfRel)
  530. {
  531. LocalFree(pSDSelfRel);
  532. }
  533. return hr;
  534. }
  535. STDMETHODIMP
  536. CCASecurityObject::GetAccessRights(const GUID* /*pguidObjectType*/,
  537. DWORD /*dwFlags*/,
  538. PSI_ACCESS *ppAccesses,
  539. ULONG *pcAccesses,
  540. ULONG *piDefaultAccess)
  541. {
  542. *ppAccesses = g_siObjAccesses;
  543. *pcAccesses = sizeof(g_siObjAccesses)/sizeof(g_siObjAccesses[0]);
  544. *piDefaultAccess = g_iObjDefAccess;
  545. return S_OK;
  546. }
  547. STDMETHODIMP
  548. CCASecurityObject::MapGeneric(const GUID* /*pguidObjectType*/,
  549. UCHAR * /*pAceFlags*/,
  550. ACCESS_MASK *pmask)
  551. {
  552. MapGenericMask(pmask, &ObjMap);
  553. return S_OK;
  554. }
  555. STDMETHODIMP
  556. CCASecurityObject::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  557. ULONG *pcInheritTypes)
  558. {
  559. *ppInheritTypes = g_siObjInheritTypes;
  560. *pcInheritTypes = sizeof(g_siObjInheritTypes)/sizeof(g_siObjInheritTypes[0]);
  561. return S_OK;
  562. }
  563. STDMETHODIMP
  564. CCASecurityObject::PropertySheetPageCallback(HWND /*hwnd*/,
  565. UINT /*uMsg*/,
  566. SI_PAGE_TYPE /*uPage*/)
  567. {
  568. return S_OK;
  569. }