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.

689 lines
22 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1995, Microsoft Corporation.
  4. //
  5. // File: daclwrap.cxx
  6. //
  7. // Contents: class encapsulating file security.
  8. //
  9. // Classes: CDaclWrap
  10. //
  11. // History: Nov-93 Created DaveMont
  12. //
  13. //--------------------------------------------------------------------
  14. #include <t2.hxx>
  15. #include <daclwrap.hxx>
  16. #if DBG
  17. extern ULONG Debug;
  18. #endif
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CDaclWrap::CDaclWrap, public
  22. //
  23. // Synopsis: initialize data members, constructor will not throw
  24. //
  25. // Arguments: none
  26. //
  27. //----------------------------------------------------------------------------
  28. CDaclWrap::CDaclWrap()
  29. : _ccaa(0)
  30. {
  31. }
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Member: Dtor, public
  35. //
  36. // Synopsis: cleanup allocated data
  37. //
  38. // Arguments: none
  39. //
  40. //----------------------------------------------------------------------------
  41. CDaclWrap::~CDaclWrap()
  42. {
  43. for (ULONG j = 0; j < _ccaa; j++)
  44. delete _aaa[j].pcaa;
  45. }
  46. //+---------------------------------------------------------------------------
  47. //
  48. // Member: CDaclWrap::SetAccess, public
  49. //
  50. // Synopsis: caches data for a new ACE
  51. //
  52. // Arguments: IN [option] - rePlace, Revoke, Grant, Deny
  53. // IN [Name] - principal (username)
  54. // IN [System] - server/machine where Name is defined
  55. // IN [access] - access mode (Read Change None All)
  56. //
  57. //----------------------------------------------------------------------------
  58. ULONG CDaclWrap::SetAccess(ULONG option, WCHAR *Name, WCHAR *System, ULONG access)
  59. {
  60. ULONG ret;
  61. // sorry, static number of ACCESSes can be set at one time
  62. if (_ccaa >= CMAXACES)
  63. return(ERROR_BUFFER_OVERFLOW);
  64. // allocate a new account access class
  65. if (NULL == (_aaa[_ccaa].pcaa = new CAccountAccess(Name, System)))
  66. {
  67. return(ERROR_NOT_ENOUGH_MEMORY);
  68. }
  69. // to fix the bug where someone asks to both grant and deny under
  70. // the /p option (the deny is thru access = N)
  71. if ((GENERIC_NONE == access) && (OPTION_REPLACE == option))
  72. {
  73. _aaa[_ccaa].option = OPTION_DENY;
  74. } else
  75. {
  76. _aaa[_ccaa].option = option;
  77. }
  78. SID *psid;
  79. if (ERROR_SUCCESS == ( ret = _aaa[_ccaa].pcaa->Init(access)))
  80. {
  81. // get the sid to make sure the username is valid
  82. if (ERROR_SUCCESS == ( ret =_aaa[_ccaa].pcaa->Sid(&psid)))
  83. {
  84. // loop thru the existing sids, making sure the new one is not a duplicate
  85. SID *poldsid;
  86. for (ULONG check = 0;check < _ccaa ; check++)
  87. {
  88. if (ERROR_SUCCESS == ( ret =_aaa[check].pcaa->Sid(&poldsid)))
  89. {
  90. if (EqualSid(psid,poldsid))
  91. {
  92. VERBOSE((stderr, "SetAccess found matching new sids\n"))
  93. return(ERROR_BAD_ARGUMENTS);
  94. }
  95. }
  96. }
  97. _ccaa++;
  98. }
  99. }
  100. return(ret);
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Member: CDaclWrap:BuildAcl, public
  105. //
  106. // Synopsis: merges cached new aces with the input ACL
  107. //
  108. // Arguments: OUT [pnewdacl] - Address of new ACL to build
  109. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  110. // IN [revision] - ACL revision
  111. // IN [fdir] - True = directory
  112. //
  113. //----------------------------------------------------------------------------
  114. ULONG CDaclWrap::BuildAcl(ACL **pnewdacl, ACL *poldacl, UCHAR revision, BOOL fdir)
  115. {
  116. ULONG ret, caclsize;
  117. // get the size of the new ACL we are going to create
  118. if (ERROR_SUCCESS == (ret = _GetNewAclSize(&caclsize, poldacl, fdir)))
  119. {
  120. // allocate the new ACL
  121. if (ERROR_SUCCESS == (ret = _AllocateNewAcl(pnewdacl, caclsize, revision)))
  122. {
  123. // and fill it up
  124. if (ERROR_SUCCESS != (ret = _FillNewAcl(*pnewdacl, poldacl, fdir)))
  125. {
  126. // free the buffer if we failed
  127. LocalFree(*pnewdacl);
  128. }
  129. }
  130. }
  131. return(ret);
  132. }
  133. //+---------------------------------------------------------------------------
  134. //
  135. // Member: CDaclWrap:_GetNewAclSize, private
  136. //
  137. // Synopsis: returns the size need to merge the new ACEs with the old ACL,
  138. // this is an ugly algorithm:
  139. //
  140. //if (old aces exist)
  141. // for (new aces)
  142. // if (new ace option == GRANT)
  143. // for (old aces)
  144. // if (new ace SID == old ace SID)
  145. // do inheritance check
  146. // found = true
  147. // if (old ace type == ALLOWED)
  148. // old ace mask |= new ace mask
  149. // else
  150. // old ace mask &= ~new ace mask
  151. // if (!found)
  152. // add size of new ace
  153. // else
  154. // new ace mask = 0
  155. // else
  156. // add size of new ace
  157. //
  158. // for (old aces)
  159. // for (new aces)
  160. // if (new ace option == DENY, REPLACE, REVOKE)
  161. // if (new ace SID == old ace SID)
  162. // found = true
  163. // break
  164. // if (!found)
  165. // add size of old ace
  166. // else
  167. // old ace mask = 0
  168. //else
  169. // for (new aces)
  170. // add size of new ace
  171. //
  172. //
  173. // Arguments: OUT [caclsize] - returns size
  174. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  175. // IN [fdir] - True = directory
  176. //
  177. //----------------------------------------------------------------------------
  178. ULONG CDaclWrap::_GetNewAclSize(ULONG *caclsize, ACL *poldacl, BOOL fdir)
  179. {
  180. ULONG ret;
  181. // the size for the ACL header
  182. *caclsize = sizeof(ACL);
  183. // initialize the access requests
  184. for (ULONG j = 0; j < _ccaa; j++)
  185. _aaa[j].pcaa->ReInit();
  186. // if we are merging, calculate the merge size
  187. if (poldacl && (poldacl->AceCount != 0))
  188. {
  189. // first the grant options
  190. for (j = 0; j < _ccaa; j++)
  191. {
  192. SID *psid;
  193. if (OPTION_GRANT == _aaa[j].option)
  194. {
  195. BOOL ffound = FALSE;
  196. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  197. for (ULONG cace = 0; cace < poldacl->AceCount;
  198. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  199. {
  200. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  201. {
  202. if (EqualSid(psid,
  203. (SID *)&((ACCESS_ALLOWED_ACE *)
  204. pah)->SidStart) )
  205. {
  206. // if old and new types are the same, just and with the old
  207. if (fdir && (pah->AceType == _aaa[j].pcaa->AceType()))
  208. {
  209. // make sure that we can handle the inheritance
  210. _aaa[j].pcaa->AddInheritance(pah->AceFlags);
  211. ffound = TRUE;
  212. } else if (pah->AceType == _aaa[j].pcaa->AceType())
  213. {
  214. ffound = TRUE;
  215. }
  216. if (ACCESS_ALLOWED_ACE_TYPE == pah->AceType)
  217. {
  218. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)
  219. pah)->Mask |= _aaa[j].pcaa->AccessMask();
  220. } else if (ACCESS_DENIED_ACE_TYPE == pah->AceType)
  221. {
  222. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)
  223. pah)->Mask &= ~_aaa[j].pcaa->AccessMask();
  224. } else
  225. {
  226. VERBOSE((stderr, "_GetNewAclSize found an ace that was not allowed or denied\n"))
  227. return(ERROR_INVALID_DATA);
  228. }
  229. }
  230. } else
  231. {
  232. return(ret);
  233. }
  234. }
  235. if (!ffound)
  236. {
  237. // bugbug allowed/denied sizes currently the same
  238. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  239. sizeof(DWORD) +
  240. GetLengthSid(psid);
  241. SIZE((stderr, "adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  242. } else
  243. {
  244. if (fdir && (ERROR_SUCCESS != (ret = _aaa[j].pcaa->TestInheritance())))
  245. return(ret);
  246. _aaa[j].pcaa->ClearAccessMask();
  247. }
  248. } else if ( (OPTION_REPLACE == _aaa[j].option) ||
  249. (OPTION_DENY == _aaa[j].option) )
  250. {
  251. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  252. {
  253. // bugbug allowed/denied sizes currently the same
  254. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  255. sizeof(DWORD) +
  256. GetLengthSid(psid);
  257. SIZE((stderr, "adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  258. } else
  259. return(ret);
  260. }
  261. }
  262. // now for the deny, replace & revoke options
  263. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  264. SID *psid;
  265. // loop thru the old ACL
  266. for (ULONG cace = 0; cace < poldacl->AceCount;
  267. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  268. {
  269. BOOL ffound = FALSE;
  270. // and thru the new ACEs looking for matching SIDs
  271. for (ULONG j = 0; j < _ccaa; j++)
  272. {
  273. if ( (_aaa[j].option & OPTION_DENY ) ||
  274. (_aaa[j].option & OPTION_REPLACE ) ||
  275. (_aaa[j].option & OPTION_REVOKE ) )
  276. {
  277. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  278. {
  279. if (EqualSid(psid,
  280. (SID *)&((ACCESS_ALLOWED_ACE *)
  281. pah)->SidStart) )
  282. {
  283. ffound = TRUE;
  284. }
  285. } else
  286. return(ret);
  287. }
  288. }
  289. if (!ffound)
  290. {
  291. // if we did not find a match, add the size of the old ACE
  292. *caclsize += ((ACE_HEADER *)pah)->AceSize;
  293. SIZE((stderr, "adding on size of an old ACE (to the new ACL) = %d\n",*caclsize))
  294. } else
  295. {
  296. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
  297. }
  298. }
  299. SIZE((stderr, "final size for new ACL = %d\n",*caclsize))
  300. } else
  301. {
  302. // no old ACL, just add up the sizes of the new aces
  303. for (j = 0; j < _ccaa; j++)
  304. {
  305. // need to know the size of the sid
  306. SID *psid;
  307. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  308. {
  309. // bugbug allowed/denied sizes currently the same
  310. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  311. sizeof(DWORD) +
  312. GetLengthSid(psid);
  313. SIZE((stderr, "adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  314. } else
  315. {
  316. return(ret);
  317. }
  318. }
  319. SIZE((stderr, "final size for new ACL = %d\n",*caclsize))
  320. }
  321. return(ERROR_SUCCESS);
  322. }
  323. //+---------------------------------------------------------------------------
  324. //
  325. // Member: CDaclWrap:_AllocateNewAcl, private
  326. //
  327. // Synopsis: allocates and initializes the new ACL
  328. //
  329. // Arguments: OUT [pnewdacl] - address of new ACL to allocate
  330. // IN [caclsize] - size to allocate for the new ACL
  331. // IN [revision] - revision of the new ACL
  332. //
  333. //----------------------------------------------------------------------------
  334. ULONG CDaclWrap::_AllocateNewAcl(ACL **pnewdacl, ULONG caclsize, ULONG revision)
  335. {
  336. if (NULL == (*pnewdacl = (ACL *) LocalAlloc(LMEM_FIXED, caclsize)))
  337. {
  338. return(ERROR_NOT_ENOUGH_MEMORY);
  339. }
  340. if (!InitializeAcl(*pnewdacl,caclsize, revision))
  341. {
  342. ULONG ret = GetLastError();
  343. LocalFree(*pnewdacl);
  344. return(ret);
  345. }
  346. return(ERROR_SUCCESS);
  347. }
  348. //+---------------------------------------------------------------------------
  349. //
  350. // Member: CDaclWrap:_SetAllowedAce, private
  351. //
  352. // Synopsis: appends an allowed ACE to the input ACL
  353. //
  354. // Arguments: IN [dacl] - ACL to add the ACE to
  355. // IN [mask] - access mask to add
  356. // IN [psid] - SID to add
  357. // IN [fdir] - if a Dir add inherit ACE as well
  358. //
  359. //----------------------------------------------------------------------------
  360. ULONG CDaclWrap::_SetAllowedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir)
  361. {
  362. ULONG ret = ERROR_SUCCESS;
  363. // compute the size of the ACE we are making
  364. USHORT acesize = (USHORT)(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(psid));
  365. SIZE((stderr, "adding allowed ace, size = %d\n",fdir ? acesize*2 : acesize))
  366. // static buffer in the hopes we won't have to allocate memory
  367. BYTE buf[1024];
  368. // allocator either uses buf or allocates a new buffer if size is not enough
  369. FastAllocator fa(buf, 1024);
  370. // get the buffer for the ACE
  371. ACCESS_ALLOWED_ACE *paaa = (ACCESS_ALLOWED_ACE *)fa.GetBuf(acesize);
  372. if (!paaa) {
  373. return (ERROR_NOT_ENOUGH_MEMORY);
  374. }
  375. // fill in the ACE
  376. memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
  377. paaa->Mask = mask;
  378. paaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  379. paaa->Header.AceFlags = fdir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE : 0;
  380. paaa->Header.AceSize = acesize;
  381. // put the ACE into the ACL
  382. if (!AddAce(dacl,
  383. dacl->AclRevision,
  384. 0xffffffff,
  385. paaa,
  386. paaa->Header.AceSize))
  387. ret = GetLastError();
  388. return(ret);
  389. }
  390. //+---------------------------------------------------------------------------
  391. //
  392. // Member: CDaclWrap:_SetDeniedAce, private
  393. //
  394. // Synopsis: appends a denied ACE to the input ACL
  395. //
  396. // Arguments: IN [dacl] - ACL to add the ACE to
  397. // IN [mask] - access mask to add
  398. // IN [psid] - SID to add
  399. // IN [fdir] - if a Dir add inherit ACE as well
  400. //
  401. //----------------------------------------------------------------------------
  402. ULONG CDaclWrap::_SetDeniedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir)
  403. {
  404. ULONG ret = ERROR_SUCCESS;
  405. // compute the size of the ACE we are making
  406. USHORT acesize = (USHORT)(sizeof(ACCESS_DENIED_ACE) -
  407. sizeof(DWORD) +
  408. GetLengthSid(psid));
  409. SIZE((stderr, "adding denied ace, size = %d\n",acesize))
  410. // static buffer in the hopes we won't have to allocate memory
  411. BYTE buf[1024];
  412. // allocator either uses buf or allocates a new buffer if size is not enough
  413. FastAllocator fa(buf, 1024);
  414. // get the buffer for the ACE
  415. ACCESS_DENIED_ACE *paaa = (ACCESS_DENIED_ACE *)fa.GetBuf(acesize);
  416. if (!paaa)
  417. return (ERROR_NOT_ENOUGH_MEMORY);
  418. // fill in the ACE
  419. memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
  420. paaa->Mask = mask;
  421. paaa->Header.AceType = ACCESS_DENIED_ACE_TYPE;
  422. paaa->Header.AceFlags = fdir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE : 0;
  423. paaa->Header.AceSize = acesize;
  424. // put the ACE into the ACL
  425. if (!AddAce(dacl,
  426. dacl->AclRevision,
  427. 0xffffffff,
  428. paaa,
  429. paaa->Header.AceSize))
  430. ret = GetLastError();
  431. return(ret);
  432. }
  433. //+---------------------------------------------------------------------------
  434. //
  435. // Member: CDaclWrap:_FillNewAcl, private
  436. //
  437. // Synopsis: The worker routine that actually fills the ACL, it adds the
  438. // new denied ACEs, then if the new ACEs are being merged with
  439. // an existing ACL, the existing ACL's ACE's (that don't
  440. // conflict) are added, finally the new allowed ACEs are added.
  441. // another ugly algorithm:
  442. //
  443. //for (new aces)
  444. // if (new ace option == DENY)
  445. // add new ace
  446. //
  447. //if (old aces)
  448. // for (old aces)
  449. // if (old ace mask != 0)
  450. // add old ace
  451. //
  452. // for (new aces)
  453. // if (new ace option != DENY)
  454. // if ( new ace option != REVOKE)
  455. // if (new ace mask != 0
  456. // add new ace
  457. //
  458. //else
  459. // for (new aces)
  460. // if (new ace option != DENY)
  461. // add new ace
  462. //
  463. // Arguments: IN [pnewdacl] - the new ACL to be filled
  464. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  465. // IN [fdir] - TRUE = directory
  466. //
  467. //----------------------------------------------------------------------------
  468. ULONG CDaclWrap::_FillNewAcl(ACL *pnewdacl, ACL *poldacl, BOOL fdir)
  469. {
  470. SID *psid = NULL;
  471. ULONG ret;
  472. // set new denied aces
  473. VERBOSE((stderr, "start addr of new ACL %p\n",pnewdacl))
  474. for (ULONG j = 0; j < _ccaa; j++)
  475. {
  476. if (_aaa[j].option & OPTION_DENY)
  477. {
  478. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  479. {
  480. if (!psid) {
  481. return (ERROR_INVALID_DATA);
  482. }
  483. if (ERROR_SUCCESS != (ret = _SetDeniedAce(pnewdacl,
  484. _aaa[j].pcaa->AccessMask(),
  485. psid,
  486. fdir )))
  487. return(ret);
  488. } else
  489. return(ret);
  490. }
  491. }
  492. // check and see if the ACL from from the file is in correct format
  493. if (poldacl)
  494. {
  495. SIZE((stderr, "old ACL size = %d, acecount = %d\n",poldacl->AclSize,
  496. poldacl->AceCount))
  497. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  498. //
  499. // loop thru the old ACL, and add all explicit aces
  500. //
  501. BOOL fallowedacefound = FALSE;
  502. for (ULONG cace = 0; cace < poldacl->AceCount;
  503. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  504. {
  505. // error exit if the old ACL is incorrectly formated
  506. if(pah->AceFlags & INHERITED_ACE)
  507. continue;
  508. if (pah->AceType == ACCESS_DENIED_ACE_TYPE && fallowedacefound)
  509. {
  510. VERBOSE((stderr, "_FillNewAcl found an denied ACE after an allowed ACE\n"))
  511. return(ERROR_INVALID_DATA);
  512. }
  513. else if (pah->AceType == ACCESS_ALLOWED_ACE_TYPE)
  514. fallowedacefound = TRUE;
  515. // add the old ace to the new ACL if the old ace's mask is not zero
  516. if ( 0 != (ACCESS_MASK)((ACCESS_ALLOWED_ACE *)pah)->Mask)
  517. {
  518. // add the old ace
  519. if (!AddAce(pnewdacl,
  520. pnewdacl->AclRevision,
  521. 0xffffffff,
  522. pah,
  523. pah->AceSize))
  524. return(GetLastError());
  525. }
  526. }
  527. // now for the new aces
  528. for (ULONG j = 0; j < _ccaa; j++)
  529. {
  530. if ( (_aaa[j].option != OPTION_DENY) &&
  531. (_aaa[j].option != OPTION_REVOKE) &&
  532. (_aaa[j].pcaa->AccessMask() != 0) )
  533. {
  534. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  535. {
  536. if (!psid) {
  537. return (ERROR_INVALID_DATA);
  538. }
  539. if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
  540. _aaa[j].pcaa->AccessMask(),
  541. psid,
  542. fdir )))
  543. return(ret);
  544. } else
  545. return(ret);
  546. }
  547. }
  548. //
  549. // loop thru the old ACL, and add all the inherited aces
  550. //
  551. pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  552. for (ULONG cace = 0; cace < poldacl->AceCount;
  553. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  554. {
  555. if(pah->AceFlags & INHERITED_ACE)
  556. {
  557. // add the old ace to the new ACL if the old ace's mask is not zero
  558. if ( 0 != (ACCESS_MASK)((ACCESS_ALLOWED_ACE *)pah)->Mask)
  559. {
  560. // add the old ace
  561. if (!AddAce(pnewdacl,
  562. pnewdacl->AclRevision,
  563. 0xffffffff,
  564. pah,
  565. pah->AceSize))
  566. return(GetLastError());
  567. }
  568. }
  569. }
  570. } else
  571. {
  572. // no old acl, just add the (rest) of the new aces
  573. for (ULONG j = 0; j < _ccaa; j++)
  574. {
  575. if (_aaa[j].option != OPTION_DENY)
  576. {
  577. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  578. {
  579. if (!psid) {
  580. return (ERROR_INVALID_DATA);
  581. }
  582. if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
  583. _aaa[j].pcaa->AccessMask(),
  584. psid,
  585. fdir )))
  586. return(ret);
  587. } else
  588. return(ret);
  589. }
  590. }
  591. }
  592. return(ERROR_SUCCESS);
  593. }