Source code of Windows XP (NT5)
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.

475 lines
12 KiB

  1. //+--------------------------------------------------------------------------
  2. // File: officer.cpp
  3. // Contents: officer rights implementation
  4. //---------------------------------------------------------------------------
  5. #include <stdafx.h>
  6. #include "officer.h"
  7. #include "certsd.h"
  8. using namespace CertSrv;
  9. static const DEFAULT_USERNAME_SIZE = 256;
  10. CClientPermission::CClientPermission(BOOL fAllow, PSID pSid) :
  11. m_fAllow(fAllow),
  12. m_Sid(pSid)
  13. {}
  14. HRESULT COfficerRights::Add(PSID pSid, BOOL fAllow)
  15. {
  16. HRESULT hr = S_OK;
  17. CClientPermission* pClient = new CClientPermission(fAllow, pSid);
  18. if(!CClientPermission::IsInitialized(pClient) ||
  19. !m_List.AddTail(pClient))
  20. {
  21. hr = E_OUTOFMEMORY;
  22. _JumpError(hr, error, "");
  23. }
  24. error:
  25. if(S_OK!=hr)
  26. delete pClient;
  27. return hr;
  28. }
  29. HRESULT COfficerRights::Init(PACCESS_ALLOWED_CALLBACK_ACE pAce)
  30. {
  31. HRESULT hr = S_OK;
  32. // no object reuse
  33. CSASSERT(!m_pSid);
  34. CSASSERT(m_List.IsEmpty());
  35. CSASSERT(IsValidSid((PSID)(&pAce->SidStart)));
  36. m_pSid = new CSid((PSID)(&pAce->SidStart));
  37. if(!m_pSid)
  38. {
  39. hr = E_OUTOFMEMORY;
  40. _JumpError(hr, error, "new CSid");
  41. }
  42. hr = AddSidList(pAce);
  43. _JumpIfError(hr, error, "COfficerRights::AddSidList");
  44. error:
  45. if(S_OK!=hr)
  46. {
  47. Cleanup();
  48. }
  49. return hr;
  50. }
  51. HRESULT COfficerRights::AddSidList(PACCESS_ALLOWED_CALLBACK_ACE pAce)
  52. {
  53. HRESULT hr = S_OK;
  54. PSID pSid;
  55. DWORD cSids;
  56. PSID_LIST pSidList = (PSID_LIST) (((BYTE*)&pAce->SidStart)+
  57. GetLengthSid(&pAce->SidStart));
  58. CSASSERT(EqualSid((PSID)&pAce->SidStart, GetSid()));
  59. for(pSid=(PSID)&pSidList->SidListStart, cSids=0;
  60. cSids<pSidList->dwSidCount;
  61. cSids++, pSid = (PSID)(((BYTE*)pSid)+GetLengthSid(pSid)))
  62. {
  63. hr = Add(pSid, ACCESS_ALLOWED_CALLBACK_ACE_TYPE==pAce->Header.AceType);
  64. _JumpIfError(hr, error, "COfficerRights::Add");
  65. }
  66. error:
  67. return hr;
  68. }
  69. COfficerRightsList::~COfficerRightsList()
  70. {
  71. Cleanup();
  72. }
  73. HRESULT COfficerRightsList::Load(PSECURITY_DESCRIPTOR pSD)
  74. {
  75. HRESULT hr = S_OK;
  76. PACL pAcl; // no free
  77. ACL_SIZE_INFORMATION AclInfo;
  78. PACCESS_ALLOWED_CALLBACK_ACE pAce;
  79. DWORD cAce;
  80. COfficerRights *pOfficerRights = NULL;
  81. DWORD cList;
  82. COfficerRights* pExistingOfficer;
  83. CSASSERT(IsValidSecurityDescriptor(pSD));
  84. hr = myGetSecurityDescriptorDacl(pSD, &pAcl);
  85. _JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
  86. if(!GetAclInformation(pAcl,
  87. &AclInfo,
  88. sizeof(AclInfo),
  89. AclSizeInformation))
  90. {
  91. hr = myHLastError();
  92. _JumpError(hr, error, "GetAclInformation");
  93. }
  94. m_dwCountList = 0;
  95. m_List = (COfficerRights **)LocalAlloc(LMEM_FIXED,
  96. sizeof(COfficerRights*)*AclInfo.AceCount);
  97. if(!m_List)
  98. {
  99. hr = E_OUTOFMEMORY;
  100. _JumpError(hr, error, "LocalAlloc");
  101. }
  102. ZeroMemory(m_List, sizeof(COfficerRights*)*AclInfo.AceCount);
  103. for(cAce=0; cAce<AclInfo.AceCount; cAce++)
  104. {
  105. pExistingOfficer = NULL;
  106. if(!GetAce(pAcl, cAce, (PVOID*)&pAce))
  107. {
  108. hr = myHLastError();
  109. _JumpError(hr, error, "GetAce");
  110. }
  111. CSASSERT(
  112. ACCESS_ALLOWED_CALLBACK_ACE_TYPE == pAce->Header.AceType ||
  113. ACCESS_DENIED_CALLBACK_ACE_TYPE == pAce->Header.AceType);
  114. // Detect if another object already exists for this officer; if so, we
  115. // will add the client list to it instead of creating a new object
  116. // Assuming denied aces always come before allow aces, we can limit
  117. // the search to allow type
  118. if(ACCESS_ALLOWED_CALLBACK_ACE_TYPE==pAce->Header.AceType)
  119. {
  120. for(cList=0; cList<m_dwCountList; cList++)
  121. {
  122. if(EqualSid(m_List[cList]->GetSid(),
  123. (PSID)&pAce->SidStart))
  124. {
  125. pExistingOfficer = m_List[cList];
  126. break;
  127. }
  128. }
  129. }
  130. if(pExistingOfficer)
  131. {
  132. // add SID list stored in this ace to existing officer object
  133. hr = pExistingOfficer->AddSidList(pAce);
  134. _JumpIfError(hr, error, "COfficerRights::AddSidList");
  135. }
  136. else
  137. {
  138. // create new officer object
  139. pOfficerRights = new COfficerRights;
  140. if(!pOfficerRights)
  141. {
  142. hr = E_OUTOFMEMORY;
  143. _JumpError(hr, error, "new COfficerRights");
  144. }
  145. hr = pOfficerRights->Init(pAce);
  146. _JumpIfError(hr, error, "COfficerRights::Init");
  147. m_List[m_dwCountList] = pOfficerRights;
  148. pOfficerRights = NULL;
  149. m_dwCountList++;
  150. }
  151. }
  152. error:
  153. if(S_OK!=hr && m_List)
  154. {
  155. if(m_List)
  156. {
  157. LocalFree(m_List);
  158. m_List = NULL;
  159. }
  160. if(pOfficerRights)
  161. {
  162. delete pOfficerRights;
  163. }
  164. }
  165. return hr;
  166. }
  167. HRESULT COfficerRightsList::Save(PSECURITY_DESCRIPTOR &rpSD)
  168. {
  169. HRESULT hr = S_OK;
  170. PSECURITY_DESCRIPTOR pSD = NULL, pSDSelfRelative = NULL;
  171. DWORD dwSelfRelativeSize = 0;
  172. PSID pSidBuiltinAdministrators = NULL;
  173. PACL pAcl = NULL;
  174. rpSD = NULL;
  175. pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED,
  176. SECURITY_DESCRIPTOR_MIN_LENGTH);
  177. if (!pSD)
  178. {
  179. hr = E_OUTOFMEMORY;
  180. _JumpError(hr, error, "LocalAlloc");
  181. }
  182. #ifdef _DEBUG
  183. ZeroMemory(pSD, SECURITY_DESCRIPTOR_MIN_LENGTH);
  184. #endif
  185. if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
  186. {
  187. hr = myHLastError();
  188. _JumpError(hr, error, "InitializeSecurityDescriptor");
  189. }
  190. hr = GetBuiltinAdministratorsSID(&pSidBuiltinAdministrators);
  191. _JumpIfError(hr, error, "GetBuiltinAdministratorsSID");
  192. if(!SetSecurityDescriptorOwner(
  193. pSD,
  194. pSidBuiltinAdministrators,
  195. FALSE))
  196. {
  197. hr = myHLastError();
  198. _JumpError(hr, error, "SetSecurityDescriptorControl");
  199. }
  200. hr = BuildAcl(pAcl);
  201. _JumpIfError(hr, error, "BuildAcl");
  202. if(!SetSecurityDescriptorDacl(
  203. pSD,
  204. TRUE, // DACL present
  205. pAcl,
  206. FALSE)) // DACL defaulted
  207. {
  208. hr = myHLastError();
  209. _JumpError(hr, error, "SetSecurityDescriptorDacl");
  210. }
  211. CSASSERT(IsValidSecurityDescriptor(pSD));
  212. MakeSelfRelativeSD(pSD, NULL, &dwSelfRelativeSize);
  213. if(ERROR_INSUFFICIENT_BUFFER!=GetLastError())
  214. {
  215. hr = myHLastError();
  216. _JumpError(hr, error, "SetSecurityDescriptorDacl");
  217. }
  218. pSDSelfRelative = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, dwSelfRelativeSize);
  219. if(!pSDSelfRelative)
  220. {
  221. hr = E_OUTOFMEMORY;
  222. _JumpError(hr, error, "LocalAlloc");
  223. }
  224. if(!MakeSelfRelativeSD(pSD, pSDSelfRelative, &dwSelfRelativeSize))
  225. {
  226. hr = myHLastError();
  227. _JumpError(hr, error, "MakeSelfRelativeSD");
  228. }
  229. rpSD = pSDSelfRelative;
  230. error:
  231. if(pAcl)
  232. {
  233. LocalFree(pAcl);
  234. }
  235. if(pSD)
  236. {
  237. LocalFree(pSD);
  238. }
  239. if(pSidBuiltinAdministrators)
  240. {
  241. LocalFree(pSidBuiltinAdministrators);
  242. }
  243. return hr;
  244. }
  245. HRESULT COfficerRightsList::BuildAcl(PACL &rpAcl)
  246. {
  247. HRESULT hr = S_OK;
  248. DWORD dwAclSize = sizeof(ACL);
  249. DWORD cRights;
  250. PACL pAcl = NULL;
  251. rpAcl = NULL;
  252. // calculate total acl size by adding the space required
  253. // for the ACEs resulting from each COfficerRights
  254. for(cRights=0;cRights<m_dwCountList;cRights++)
  255. {
  256. dwAclSize += m_List[cRights]->GetAceSize(FALSE);
  257. dwAclSize += m_List[cRights]->GetAceSize(TRUE);
  258. }
  259. pAcl = (PACL)LocalAlloc(LMEM_FIXED, dwAclSize);
  260. if(!pAcl)
  261. {
  262. hr = E_OUTOFMEMORY;
  263. _JumpError(hr, error, "LocalAlloc");
  264. }
  265. #ifdef _DEBUG
  266. ZeroMemory(pAcl, dwAclSize);
  267. #endif
  268. if(!InitializeAcl(pAcl, dwAclSize, ACL_REVISION))
  269. {
  270. hr = myHLastError();
  271. _JumpError(hr, error, "InitializeAcl");
  272. }
  273. // add deny aces first
  274. for(cRights=0;cRights<m_dwCountList;cRights++)
  275. {
  276. hr = m_List[cRights]->AddAce(pAcl, FALSE);
  277. _JumpIfError(hr, error, "COfficerRights::AddAce");
  278. }
  279. // then add allow aces
  280. for(cRights=0;cRights<m_dwCountList;cRights++)
  281. {
  282. hr = m_List[cRights]->AddAce(pAcl, TRUE);
  283. _JumpIfError(hr, error, "COfficerRights::AddAce");
  284. }
  285. CSASSERT(IsValidAcl(pAcl));
  286. rpAcl = pAcl;
  287. error:
  288. if(S_OK!=hr)
  289. {
  290. if(pAcl)
  291. {
  292. LocalFree(pAcl);
  293. }
  294. }
  295. return hr;
  296. }
  297. DWORD COfficerRights::GetAceSize(BOOL fAllow)
  298. {
  299. DWORD dwAceSize = sizeof(ACCESS_ALLOWED_CALLBACK_ACE);
  300. dwAceSize += GetLengthSid(m_pSid->GetSid());
  301. BOOL fFound = FALSE;
  302. TPtrListEnum<CClientPermission> CPEnum(m_List);
  303. CClientPermission *pCP;
  304. for(pCP=CPEnum.Next();pCP;pCP=CPEnum.Next())
  305. {
  306. if(pCP->GetPermission()==fAllow)
  307. {
  308. dwAceSize += GetLengthSid(pCP->GetSid());
  309. fFound = TRUE;
  310. }
  311. }
  312. return fFound?dwAceSize:0;
  313. }
  314. HRESULT COfficerRights::AddAce(PACL pAcl, BOOL fAllow)
  315. {
  316. HRESULT hr = S_OK;
  317. PACCESS_ALLOWED_CALLBACK_ACE pAce = NULL;
  318. DWORD dwAceSize = GetAceSize(fAllow);
  319. DWORD dwSidSize = GetLengthSid(m_pSid->GetSid());
  320. DWORD dwClientSidSize;
  321. PSID_LIST pSidList;
  322. PSID pClientSid;
  323. TPtrListEnum<CClientPermission> CPEnum(m_List);
  324. CClientPermission *pCP;
  325. BOOL fFound = FALSE;
  326. DWORD dwSidCount = 0;
  327. if(dwAceSize)
  328. {
  329. pAce = (PACCESS_ALLOWED_CALLBACK_ACE) LocalAlloc(LMEM_FIXED, dwAceSize);
  330. if(!pAce)
  331. {
  332. hr = E_OUTOFMEMORY;
  333. _JumpError(hr, error, "LocalAlloc");
  334. }
  335. #ifdef _DEBUG
  336. ZeroMemory(pAce, dwAceSize);
  337. #endif
  338. pAce->Header.AceType = fAllow?ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
  339. ACCESS_DENIED_CALLBACK_ACE_TYPE;
  340. pAce->Header.AceFlags= 0;
  341. pAce->Header.AceSize = (USHORT)dwAceSize;
  342. pAce->Mask = DELETE;
  343. CopySid(dwSidSize,
  344. (PSID)&pAce->SidStart,
  345. m_pSid->GetSid());
  346. pSidList = (PSID_LIST)(((BYTE*)&pAce->SidStart)+dwSidSize);
  347. pSidList->dwSidCount = m_List.GetCount();
  348. pClientSid = (PSID)&pSidList->SidListStart;
  349. for(pCP=CPEnum.Next(); pCP; pCP=CPEnum.Next())
  350. {
  351. if(pCP->GetPermission()==fAllow)
  352. {
  353. dwClientSidSize = GetLengthSid(pCP->GetSid());
  354. CopySid(dwClientSidSize,
  355. pClientSid,
  356. pCP->GetSid());
  357. pClientSid = (((BYTE*)pClientSid)+dwClientSidSize);
  358. fFound = TRUE;
  359. dwSidCount++;
  360. }
  361. }
  362. pSidList->dwSidCount = dwSidCount;
  363. CSASSERT(pClientSid==((BYTE*)pAce)+dwAceSize);
  364. if(fFound)
  365. {
  366. if(!::AddAce(
  367. pAcl,
  368. ACL_REVISION,
  369. MAXDWORD,
  370. pAce,
  371. dwAceSize))
  372. {
  373. hr = myHLastError();
  374. _JumpError(hr, error, "AddAce");
  375. }
  376. }
  377. }
  378. error:
  379. if(pAce)
  380. {
  381. LocalFree(pAce);
  382. }
  383. return hr;
  384. }
  385. void COfficerRightsList::Dump()
  386. {
  387. DBGPRINT((DBG_SS_INFO, "Officers: %d\n", m_dwCountList));
  388. wprintf(L"Officers: %d\n", m_dwCountList);
  389. for(DWORD dwCount=0;dwCount<m_dwCountList;dwCount++)
  390. {
  391. COfficerRights *pOR = GetAt(dwCount);
  392. wprintf(L"Officer %s, %d clients\n", pOR->GetName(), pOR->GetCount());
  393. for(DWORD c=0;c<pOR->GetCount();c++)
  394. {
  395. CClientPermission *pCli = pOR->GetAt(c);
  396. wprintf(L"\tClient %s, %s\n", pCli->GetName(), pCli->GetPermission()?L"allow":L"deny");
  397. }
  398. }
  399. }
  400. // Searches the list for an object with this SID; if found returns
  401. // object index, if not found, returns DWORD_MAX
  402. DWORD COfficerRights::Find(PSID pSid)
  403. {
  404. CClientPermission perm(TRUE, pSid);
  405. return m_List.FindIndex(perm);
  406. }