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.

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