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.

921 lines
30 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: daclwrap.cxx
  4. //
  5. // Contents: class encapsulating file security.
  6. //
  7. // Classes: CDaclWrap
  8. //
  9. // History: Nov-93 Created DaveMont
  10. // Oct-96 Modified BrunoSc
  11. //
  12. //--------------------------------------------------------------------
  13. #include "pch.h"
  14. #include "t2.hxx"
  15. #include "daclwrap.hxx"
  16. #include "caclsmsg.h"
  17. ULONG printmessage (FILE* fp, DWORD messageID, ...);
  18. #if DBG
  19. extern ULONG Debug;
  20. #endif
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Member: CDaclWrap::CDaclWrap, public
  24. //
  25. // Synopsis: initialize data members, constructor will not throw
  26. //
  27. // Arguments: none
  28. //
  29. //----------------------------------------------------------------------------
  30. CDaclWrap::CDaclWrap()
  31. : _ccaa(0)
  32. {
  33. _powner = NULL;
  34. }
  35. //+---------------------------------------------------------------------------
  36. //
  37. // Member: Dtor, public
  38. //
  39. // Synopsis: cleanup allocated data
  40. //
  41. // Arguments: none
  42. //
  43. //----------------------------------------------------------------------------
  44. CDaclWrap::~CDaclWrap()
  45. {
  46. for (ULONG j = 0; j < _ccaa; j++)
  47. delete _aaa[j].pcaa;
  48. if (_powner) FreeSid( _powner );
  49. }
  50. //+---------------------------------------------------------------------------
  51. //
  52. // Member: CDaclWrap::SetAccess, public
  53. //
  54. // Synopsis: caches data for a new ACE
  55. //
  56. // Arguments: IN [option] - rePlace, Revoke, Grant, Deny
  57. // IN [Name] - principal (username)
  58. // IN [System] - server/machine where Name is defined
  59. // IN [access] - access mode (Read Change None All)
  60. // IN [dirmask] - access mode for directory (same as access)
  61. // IN [filespec] - if TRUE, no ACE for files will be written
  62. // (for directories only)
  63. //
  64. //----------------------------------------------------------------------------
  65. ULONG CDaclWrap::SetAccess(ULONG option, LPWSTR Name, LPWSTR System, ULONG access, ULONG dirmask, BOOL filespec)
  66. {
  67. ULONG ret;
  68. // static number of ACCESSes can be set at one time
  69. if (_ccaa >= CMAXACES)
  70. return(ERROR_BUFFER_OVERFLOW);
  71. // allocate a new account access class
  72. if (NULL == (_aaa[_ccaa].pcaa = new CAccountAccess(Name, System)))
  73. {
  74. return(ERROR_NOT_ENOUGH_MEMORY);
  75. }
  76. _aaa[_ccaa].option = option;
  77. SID *psid;
  78. if (ERROR_SUCCESS == ( ret = _aaa[_ccaa].pcaa->Init(access, dirmask, filespec))) // reads file security
  79. {
  80. // get the sid to make sure the username is valid
  81. if (ERROR_SUCCESS == ( ret =_aaa[_ccaa].pcaa->Sid(&psid)))
  82. {
  83. // loop thru the existing sids, making sure the new one is not a duplicate
  84. SID *poldsid;
  85. for (ULONG check = 0;check < _ccaa ; check++)
  86. {
  87. if (ERROR_SUCCESS == ( ret =_aaa[check].pcaa->Sid(&poldsid)))
  88. {
  89. if (EqualSid(psid,poldsid))
  90. {
  91. VERBOSE((stderr, L"SetAccess found matching new sids\n"))
  92. //NTRAID#NTBUG9-552419-2002/03/20-hiteshr
  93. delete _aaa[_ccaa].pcaa;
  94. return(ERROR_BAD_ARGUMENTS);
  95. }
  96. }
  97. }
  98. _ccaa++;
  99. }
  100. else
  101. {
  102. //NTRAID#NTBUG9-552419-2002/03/20-hiteshr
  103. delete _aaa[_ccaa].pcaa;
  104. }
  105. }
  106. else
  107. {
  108. //NTRAID#NTBUG9-552419-2002/03/20-hiteshr
  109. delete _aaa[_ccaa].pcaa;
  110. }
  111. return(ret);
  112. }
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Member: CDaclWrap:BuildAcl, public
  116. //
  117. // Synopsis: merges cached new aces with the input ACL
  118. //
  119. // Arguments: OUT [pnewdacl] - Address of new ACL to build
  120. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  121. // IN [revision] - ACL revision
  122. // IN [fdir] - True = directory
  123. //
  124. //----------------------------------------------------------------------------
  125. ULONG CDaclWrap::BuildAcl(ACL **pnewdacl, ACL *poldacl, WCHAR revision, BOOL fdir)
  126. {
  127. ULONG ret, caclsize;
  128. // get the size of the new ACL we are going to create
  129. if (ERROR_SUCCESS == (ret = _GetNewAclSize(&caclsize, poldacl, fdir)))
  130. {
  131. // allocate the new ACL
  132. if (ERROR_SUCCESS == (ret = _AllocateNewAcl(pnewdacl, caclsize, revision)))
  133. {
  134. // and fill it up
  135. if (ERROR_SUCCESS != (ret = _FillNewAcl(*pnewdacl, poldacl, fdir)))
  136. {
  137. // free the buffer if we failed
  138. LocalFree(*pnewdacl);
  139. }
  140. }
  141. }
  142. return(ret);
  143. }
  144. //+---------------------------------------------------------------------------
  145. //
  146. // Member: CDaclWrap:_GetNewAclSize, private
  147. //
  148. // Synopsis: returns the size need to merge the new ACEs with the old ACL,
  149. // this is an ugly algorithm:
  150. // (with integration of different rights for directory and files
  151. // much more uglier!! BSC )
  152. //
  153. // legend: a combined ACE is an ACE where the CONTAINER_INHERIT_ACE and the
  154. // OBJECT_INHERIT_ACE Flag in the ACE header is set.
  155. //
  156. //if (old aces exist)
  157. // for (new aces)
  158. // if (new ace option == GRANT)
  159. // for (old aces)
  160. // if (new ace SID == old ace SID)
  161. // do inheritance check
  162. // found = true
  163. // if (fdir) && (combined ACE)
  164. // fDirEntryFound = TRUE
  165. // if (old ace type == ALLOWED)
  166. // new ace mask |= old ace mask
  167. // old ace mask = 0
  168. // else
  169. // new ace mask &= ~old ace mask
  170. // old ace mask = 0
  171. // else
  172. // if (old ace type == ALLOWED)
  173. // old ace mask |= new ace mask
  174. // else
  175. // old ace mask &= ~new ace mask
  176. // if (!found)
  177. // if (fdir)
  178. // add 2 times size of new ace
  179. // else
  180. // add size of new ace
  181. // else
  182. // if (fDirEntryFound)
  183. // add size of new ace
  184. // else
  185. // new ace mask = 0
  186. // else
  187. // if (fdir)
  188. // add 2 times the size of new ace
  189. // else
  190. // add size of new ace
  191. //
  192. // for (old aces)
  193. // for (new aces)
  194. // if (new ace option == DENY, REPLACE, REVOKE)
  195. // if (new ace SID == old ace SID)
  196. // found = true
  197. // if (fdir) && (combined ACE)
  198. // bDirEntryFound = TRUE
  199. // break
  200. // if (!found)
  201. // if (fdir)
  202. // add 2 times the size of old ace
  203. // else
  204. // add size of old ace
  205. // else
  206. // old ace mask = 0
  207. // if (bDirEntryFound)
  208. // add size of old ace
  209. //else
  210. // for (new aces)
  211. // if (fdir)
  212. // add 2 times the size of new ace
  213. // else
  214. // add size of new ace
  215. //
  216. //
  217. // Arguments: OUT [caclsize] - returns size
  218. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  219. // IN [fdir] - True = directory
  220. //
  221. //----------------------------------------------------------------------------
  222. ULONG CDaclWrap::_GetNewAclSize(ULONG *caclsize, ACL *poldacl, BOOL fdir)
  223. {
  224. ULONG ret;
  225. BOOL bDirEntryFound = FALSE;
  226. // the size for the ACL header
  227. *caclsize = sizeof(ACL);
  228. // initialize the access requests
  229. for (ULONG j = 0; j < _ccaa; j++)
  230. _aaa[j].pcaa->ReInit();
  231. // if we are merging, calculate the merge size
  232. if (poldacl)
  233. {
  234. // first the grant options
  235. for (j = 0; j < _ccaa; j++)
  236. {
  237. SID *psid;
  238. if (OPTION_GRANT == _aaa[j].option)
  239. {
  240. BOOL ffound = FALSE;
  241. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  242. for (ULONG cace = 0; cace < poldacl->AceCount;
  243. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  244. {
  245. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  246. {
  247. if (EqualSid(psid,
  248. (SID *)&((ACCESS_ALLOWED_ACE *)pah)->SidStart) )
  249. {
  250. // if old and new types are the same, just and with the old
  251. if (fdir && (pah->AceType == _aaa[j].pcaa->AceType()))
  252. {
  253. // make sure that we can handle the inheritance
  254. _aaa[j].pcaa->AddInheritance(pah->AceFlags);
  255. ffound = TRUE;
  256. } else if (pah->AceType == _aaa[j].pcaa->AceType())
  257. {
  258. ffound = TRUE;
  259. }
  260. // if the ACE is a 'combined' entry, it has to be
  261. // broken into two entries: one for the directory itself,
  262. // one for the file inheritance. But merge the old settings
  263. // with the new ones!
  264. if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE) && (pah->AceFlags & OBJECT_INHERIT_ACE))
  265. { bDirEntryFound = TRUE;
  266. // die alte ACE wird gel�scht. -> vorher mit neuen mischen
  267. if (ACCESS_ALLOWED_ACE_TYPE == pah->AceType)
  268. { _aaa[j].pcaa->Init( _aaa[j].pcaa->AccessMask() | (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
  269. _aaa[j].pcaa->DirAccessMask() | (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
  270. _aaa[j].pcaa->FileSpecified()
  271. );
  272. // and do not copy the old entry
  273. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
  274. }
  275. else if (ACCESS_DENIED_ACE_TYPE == pah->AceType)
  276. { _aaa[j].pcaa->Init( _aaa[j].pcaa->AccessMask() & ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
  277. _aaa[j].pcaa->DirAccessMask() & ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask,
  278. _aaa[j].pcaa->FileSpecified()
  279. );
  280. //_aaa[j].pcaa->AccessMask() &= ~(ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask;
  281. // and do not copy the old entry
  282. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
  283. } else
  284. {
  285. VERBOSE((stderr, L"_GetNewAclSize found an ace that was not allowed or denied\n"))
  286. return(ERROR_INVALID_DATA);
  287. }
  288. }
  289. else
  290. { if (ACCESS_ALLOWED_ACE_TYPE == pah->AceType)
  291. { if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE))
  292. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask |= _aaa[j].pcaa->DirAccessMask();
  293. else
  294. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask |= _aaa[j].pcaa->AccessMask();
  295. } else if (ACCESS_DENIED_ACE_TYPE == pah->AceType)
  296. { if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE))
  297. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask &= ~_aaa[j].pcaa->DirAccessMask();
  298. else
  299. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask &= ~_aaa[j].pcaa->AccessMask();
  300. } else
  301. {
  302. VERBOSE((stderr, L"_GetNewAclSize found an ace that was not allowed or denied\n"))
  303. return(ERROR_INVALID_DATA);
  304. }
  305. }
  306. }
  307. } else
  308. {
  309. return(ret);
  310. }
  311. }
  312. if (!ffound)
  313. {
  314. // bugbug allowed/denied sizes currently the same
  315. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  316. sizeof(DWORD) +
  317. GetLengthSid(psid);
  318. // no old entry could be found. Therefore add two entries
  319. // as described above.
  320. if (fdir)
  321. { *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  322. sizeof(DWORD) +
  323. GetLengthSid(psid);
  324. }
  325. SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  326. } else
  327. {
  328. if (fdir && (ERROR_SUCCESS != (ret = _aaa[j].pcaa->TestInheritance())))
  329. { // if a 'combined' entry was found, a new one has to be added.
  330. // So adjust the size of the ACL for one entry.
  331. if (bDirEntryFound)
  332. { *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  333. sizeof(DWORD) +
  334. GetLengthSid(psid);
  335. }
  336. return(ret);
  337. }
  338. // if not needed, beceause of former 'combined' ACE,
  339. // the new ACE(s) had been modified and therefore is not being
  340. // copied.
  341. if (!bDirEntryFound) _aaa[j].pcaa->ClearAccessMask();
  342. }
  343. } else if ( (OPTION_REPLACE == _aaa[j].option) ||
  344. (OPTION_DENY == _aaa[j].option) )
  345. {
  346. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  347. {
  348. // bugbug allowed/denied sizes currently the same
  349. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  350. sizeof(DWORD) +
  351. GetLengthSid(psid);
  352. if (fdir)
  353. { *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  354. sizeof(DWORD) +
  355. GetLengthSid(psid);
  356. }
  357. SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  358. } else
  359. return(ret);
  360. }
  361. }
  362. // now for the deny, replace & revoke options
  363. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  364. SID *psid;
  365. // loop thru the old ACL
  366. for (ULONG cace = 0; cace < poldacl->AceCount;
  367. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  368. {
  369. BOOL ffound = FALSE;
  370. bDirEntryFound = FALSE;
  371. ULONG pos;
  372. // and thru the new ACEs looking for matching SIDs
  373. for (ULONG j = 0; j < _ccaa; j++)
  374. {
  375. if ( (_aaa[j].option & OPTION_DENY ) ||
  376. (_aaa[j].option & OPTION_REPLACE ) ||
  377. (_aaa[j].option & OPTION_REVOKE ) )
  378. {
  379. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  380. {
  381. if (EqualSid(psid,
  382. (SID *)&((ACCESS_ALLOWED_ACE *)
  383. pah)->SidStart) )
  384. {
  385. ffound = TRUE;
  386. pos = j;
  387. if ((fdir) && (pah->AceFlags & CONTAINER_INHERIT_ACE) && (pah->AceFlags & OBJECT_INHERIT_ACE))
  388. { // a 'combined' entry found. Take care that the old entry
  389. // don't get copied.
  390. bDirEntryFound = TRUE;
  391. }
  392. }
  393. } else
  394. return(ret);
  395. }
  396. }
  397. if (!ffound)
  398. {
  399. // if we did not find a match, add the size of the old ACE
  400. *caclsize += ((ACE_HEADER *)pah)->AceSize;
  401. if (fdir)
  402. {
  403. *caclsize += ((ACE_HEADER *)pah)->AceSize;
  404. }
  405. SIZE((stderr, L"adding on size of an old ACE (to the new ACL) = %d\n",*caclsize))
  406. }
  407. else
  408. {
  409. (ACCESS_MASK) ((ACCESS_ALLOWED_ACE *)pah)->Mask = 0;
  410. // if 'combined' entry found
  411. if (bDirEntryFound)
  412. { *caclsize += ((ACE_HEADER *)pah)->AceSize;
  413. }
  414. }
  415. }
  416. SIZE((stderr, L"final size for new ACL = %d\n",*caclsize))
  417. }
  418. else
  419. {
  420. // no old ACL, just add up the sizes of the new aces
  421. for (j = 0; j < _ccaa; j++)
  422. {
  423. // need to know the size of the sid
  424. SID *psid;
  425. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  426. {
  427. // bugbug allowed/denied sizes currently the same
  428. *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  429. sizeof(DWORD) +
  430. GetLengthSid(psid);
  431. // if directory, one entry for the directory itself, one for
  432. // file inheritence
  433. if (fdir)
  434. { *caclsize += sizeof(ACCESS_ALLOWED_ACE) -
  435. sizeof(DWORD) +
  436. GetLengthSid(psid);
  437. }
  438. SIZE((stderr, L"adding on size of an new ACE (to the new ACL) = %d\n",*caclsize))
  439. } else
  440. {
  441. return(ret);
  442. }
  443. }
  444. SIZE((stderr, L"final size for new ACL = %d\n",*caclsize))
  445. }
  446. // handle mode_exclusive a-henryw
  447. if (_EditMode == MODE_MODIFY_EXCLUSIVE)
  448. {
  449. if (poldacl == NULL)
  450. {
  451. return ERROR_NO_MORE_ITEMS;
  452. }
  453. else
  454. {
  455. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  456. SID *psid = NULL;
  457. for (ULONG j = 0; j < _ccaa; j++)
  458. {
  459. BOOL ffound = FALSE;
  460. bDirEntryFound = FALSE;
  461. for (ULONG cace = 0; cace < poldacl->AceCount;
  462. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  463. {
  464. if ( (_aaa[j].option & OPTION_DENY ) ||
  465. (_aaa[j].option & OPTION_REPLACE ) ||
  466. (_aaa[j].option & OPTION_REVOKE ) ||
  467. (_aaa[j].option & OPTION_GRANT))
  468. {
  469. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  470. {
  471. if (EqualSid(psid,
  472. (SID *)&((ACCESS_ALLOWED_ACE *)
  473. pah)->SidStart) )
  474. {
  475. ffound = TRUE;
  476. }
  477. }
  478. }
  479. }
  480. if (!ffound && psid)
  481. {
  482. *caclsize -= sizeof(ACCESS_ALLOWED_ACE) -
  483. sizeof(DWORD) +
  484. GetLengthSid(psid);
  485. _aaa[j].pcaa->ClearAccessMask();
  486. }
  487. }
  488. }
  489. }
  490. return(ERROR_SUCCESS);
  491. }
  492. //+---------------------------------------------------------------------------
  493. //
  494. // Member: CDaclWrap:_AllocateNewAcl, private
  495. //
  496. // Synopsis: allocates and initializes the new ACL
  497. //
  498. // Arguments: OUT [pnewdacl] - address of new ACL to allocate
  499. // IN [caclsize] - size to allocate for the new ACL
  500. // IN [revision] - revision of the new ACL
  501. //
  502. //----------------------------------------------------------------------------
  503. ULONG CDaclWrap::_AllocateNewAcl(ACL **pnewdacl, ULONG caclsize, ULONG revision)
  504. {
  505. if (NULL == (*pnewdacl = (ACL *) LocalAlloc(LMEM_FIXED, caclsize)))
  506. {
  507. return(ERROR_NOT_ENOUGH_MEMORY);
  508. }
  509. if (!InitializeAcl(*pnewdacl,caclsize, revision))
  510. {
  511. ULONG ret = GetLastError();
  512. LocalFree(*pnewdacl);
  513. return(ret);
  514. }
  515. return(ERROR_SUCCESS);
  516. }
  517. //+---------------------------------------------------------------------------
  518. //
  519. // Member: CDaclWrap:_SetAllowedAce, private
  520. //
  521. // Synopsis: appends an allowed ACE to the input ACL
  522. //
  523. // Arguments: IN [dacl] - ACL to add the ACE to
  524. // IN [mask] - access mask to add
  525. // IN [psid] - SID to add
  526. // IN [fdir] - if a Dir add inherit ACE as well
  527. // IN [filespec] - if TRUE, no ACE for file will be written
  528. // (directories only)
  529. //
  530. //----------------------------------------------------------------------------
  531. ULONG CDaclWrap::_SetAllowedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir, ACCESS_MASK dirmask, BOOL filespec)
  532. {
  533. ULONG ret = ERROR_SUCCESS;
  534. // compute the size of the ACE we are making
  535. USHORT acesize = (USHORT)(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(psid));
  536. SIZE((stderr, L"adding allowed ace, size = %d\n",fdir ? acesize*2 : acesize))
  537. // static buffer in the hopes we won't have to allocate memory
  538. BYTE buf[1024];
  539. // allocator either uses buf or allocates a new buffer if size is not enough
  540. FastAllocator fa(buf, 1024);
  541. // get the buffer for the ACE
  542. ACCESS_ALLOWED_ACE *paaa = (ACCESS_ALLOWED_ACE *)fa.GetBuf(acesize);
  543. // fill in the ACE
  544. memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
  545. paaa->Mask = mask;
  546. paaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  547. paaa->Header.AceSize = acesize;
  548. // put the ACE into the ACL
  549. if (!fdir)
  550. { paaa->Header.AceFlags = 0;
  551. if (!AddAce(dacl,
  552. dacl->AclRevision,
  553. 0xffffffff,
  554. paaa,
  555. paaa->Header.AceSize))
  556. { ret = GetLastError();
  557. return (ret);
  558. }
  559. }
  560. else
  561. { if (!filespec)
  562. { // if filespec is TRUE, the file inheritence is not specified
  563. paaa->Header.AceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
  564. if (!AddAce(dacl,
  565. dacl->AclRevision,
  566. 0xffffffff,
  567. paaa,
  568. paaa->Header.AceSize))
  569. { ret = GetLastError();
  570. return (ret);
  571. }
  572. }
  573. paaa->Mask = dirmask;
  574. paaa->Header.AceFlags = CONTAINER_INHERIT_ACE;
  575. if (!AddAce(dacl,
  576. dacl->AclRevision,
  577. 0xffffffff,
  578. paaa,
  579. paaa->Header.AceSize))
  580. ret = GetLastError();
  581. }
  582. return(ret);
  583. }
  584. //+---------------------------------------------------------------------------
  585. //
  586. // Member: CDaclWrap:_SetDeniedAce, private
  587. //
  588. // Synopsis: appends a denied ACE to the input ACL
  589. //
  590. // Arguments: IN [dacl] - ACL to add the ACE to
  591. // IN [mask] - access mask to add
  592. // IN [psid] - SID to add
  593. // IN [fdir] - if a Dir add inherit ACE as well
  594. //
  595. //----------------------------------------------------------------------------
  596. ULONG CDaclWrap::_SetDeniedAce(ACL *dacl, ACCESS_MASK mask, SID *psid, BOOL fdir)
  597. {
  598. ULONG ret = ERROR_SUCCESS;
  599. // compute the size of the ACE we are making
  600. USHORT acesize = (USHORT)( sizeof(ACCESS_DENIED_ACE) -
  601. sizeof(DWORD) +
  602. GetLengthSid(psid));
  603. SIZE((stderr, L"adding denied ace, size = %d\n",acesize))
  604. // static buffer in the hopes we won't have to allocate memory
  605. BYTE buf[1024];
  606. // allocator either uses buf or allocates a new buffer if size is not enough
  607. FastAllocator fa(buf, 1024);
  608. // get the buffer for the ACE
  609. ACCESS_DENIED_ACE *paaa = (ACCESS_DENIED_ACE *)fa.GetBuf(acesize);
  610. // fill in the ACE
  611. memcpy(&paaa->SidStart,psid,GetLengthSid(psid));
  612. paaa->Mask = mask;
  613. paaa->Header.AceType = ACCESS_DENIED_ACE_TYPE;
  614. paaa->Header.AceFlags = fdir ? CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE : 0;
  615. paaa->Header.AceSize = acesize;
  616. // put the ACE into the ACL
  617. if (!AddAce(dacl,
  618. dacl->AclRevision,
  619. 0xffffffff,
  620. paaa,
  621. paaa->Header.AceSize))
  622. ret = GetLastError();
  623. return(ret);
  624. }
  625. //+---------------------------------------------------------------------------
  626. //
  627. // Member: CDaclWrap:_FillNewAcl, private
  628. //
  629. // Synopsis: The worker routine that actually fills the ACL, it adds the
  630. // new denied ACEs, then if the new ACEs are being merged with
  631. // an existing ACL, the existing ACL's ACE's (that don't
  632. // conflict) are added, finally the new allowed ACEs are added.
  633. // another ugly algorithm:
  634. //
  635. //for (new aces)
  636. // if (new ace option == DENY)
  637. // add new ace
  638. //
  639. //if (old aces)
  640. // for (old aces)
  641. // if (old ace mask != 0)
  642. // add old ace
  643. //
  644. // for (new aces)
  645. // if (new ace option != DENY)
  646. // if ( new ace option != REVOKE)
  647. // if (new ace mask != 0
  648. // add new ace
  649. //
  650. //else
  651. // for (new aces)
  652. // if (new ace option != DENY)
  653. // add new ace
  654. //
  655. // Arguments: IN [pnewdacl] - the new ACL to be filled
  656. // IN [poldacl] - (OPTIONAL) old ACL that is to be merged
  657. // IN [fdir] - TRUE = directory
  658. //
  659. //----------------------------------------------------------------------------
  660. ULONG CDaclWrap::_FillNewAcl(ACL *pnewdacl, ACL *poldacl, BOOL fdir)
  661. {
  662. SID *psid;
  663. ULONG ret;
  664. // set new denied aces
  665. for (ULONG j = 0; j < _ccaa; j++)
  666. {
  667. if (_aaa[j].option & OPTION_DENY)
  668. {
  669. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  670. {
  671. if (ERROR_SUCCESS != (ret = _SetDeniedAce(pnewdacl,
  672. _aaa[j].pcaa->AccessMask(),
  673. psid,
  674. fdir )))
  675. return(ret);
  676. } else
  677. return(ret);
  678. }
  679. // should it be the new owner ?
  680. if (_aaa[j].option & OPTION_SET_OWNER)
  681. { // remember the SID. If it's not empty, more than one has been specified to be the owner!
  682. if (_powner)
  683. { // error, there can just be one...
  684. printmessage( stdout, MSG_TWO_OWNER, 0 );
  685. exit( -1 );
  686. }
  687. else
  688. { // get the descriptor and allocate the SID
  689. SID_IDENTIFIER_AUTHORITY *pSIDAuth;
  690. pSIDAuth = GetSidIdentifierAuthority( psid );
  691. if (!AllocateAndInitializeSid( pSIDAuth, 0, 0, 0, 0, 0, 0, 0, 0, 0, &_powner ))
  692. { ret = GetLastError();
  693. printmessage( stdout, ret, 0 );
  694. exit( -1 );
  695. }
  696. }
  697. }
  698. }
  699. // check and see if the ACL from from the file is in correct format
  700. if (poldacl)
  701. {
  702. SIZE((stderr, L"old ACL size = %d, acecount = %d\n",poldacl->AclSize,
  703. poldacl->AceCount))
  704. ACE_HEADER *pah = (ACE_HEADER *)Add2Ptr(poldacl, sizeof(ACL));
  705. // loop thru the old ACL, looking for matches with the new ACEs
  706. BOOL fallowedacefound = FALSE;
  707. for (ULONG cace = 0; cace < poldacl->AceCount;
  708. cace++, pah = (ACE_HEADER *)Add2Ptr(pah, pah->AceSize))
  709. {
  710. // error exit if the old ACL is incorrectly formated
  711. if (pah->AceType == ACCESS_DENIED_ACE_TYPE && fallowedacefound)
  712. {
  713. VERBOSE((stderr, L"_FillNewAcl found an denied ACE after an allowed ACE\n"))
  714. return(ERROR_INVALID_DATA);
  715. }
  716. else if (pah->AceType == ACCESS_ALLOWED_ACE_TYPE)
  717. fallowedacefound = TRUE;
  718. // add the old ace to the new ACL if the old ace's mask is not zero
  719. if ( 0 != (ACCESS_MASK)((ACCESS_ALLOWED_ACE *)pah)->Mask)
  720. {
  721. // add the old ace
  722. if (!AddAce(pnewdacl,
  723. pnewdacl->AclRevision,
  724. 0xffffffff,
  725. pah,
  726. pah->AceSize))
  727. return(GetLastError());
  728. }
  729. }
  730. // now for the new aces
  731. for (ULONG j = 0; j < _ccaa; j++)
  732. {
  733. if ( (_aaa[j].option != OPTION_DENY) &&
  734. (_aaa[j].option != OPTION_REVOKE) &&
  735. (_aaa[j].pcaa->AccessMask() != 0) )
  736. {
  737. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  738. {
  739. if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
  740. _aaa[j].pcaa->AccessMask(),
  741. psid,
  742. fdir,
  743. _aaa[j].pcaa->DirAccessMask(),
  744. _aaa[j].pcaa->FileSpecified())))
  745. return(ret);
  746. } else
  747. return(ret);
  748. }
  749. }
  750. } else
  751. {
  752. // no old acl, just add the (rest) of the new aces
  753. for (ULONG j = 0; j < _ccaa; j++)
  754. {
  755. if (_aaa[j].option != OPTION_DENY)
  756. {
  757. if (ERROR_SUCCESS == (ret = _aaa[j].pcaa->Sid(&psid)))
  758. {
  759. if (ERROR_SUCCESS != (ret = _SetAllowedAce(pnewdacl,
  760. _aaa[j].pcaa->AccessMask(),
  761. psid,
  762. fdir,
  763. _aaa[j].pcaa->DirAccessMask(),
  764. _aaa[j].pcaa->FileSpecified())))
  765. return(ret);
  766. } else
  767. return(ret);
  768. }
  769. }
  770. }
  771. return(ERROR_SUCCESS);
  772. }
  773. //----------------------------------------------------------------------------
  774. //
  775. // Function: printmessage
  776. //
  777. // Synopsis: prints a message, either from the local message file, or from the system
  778. //
  779. // Arguments: IN [fp] - stderr, stdio, etc.
  780. // IN [messageID] - variable argument list
  781. //
  782. // Returns: length of the output buffer
  783. //
  784. //----------------------------------------------------------------------------
  785. ULONG printmessage (FILE* fp, DWORD messageID, ...)
  786. {
  787. WCHAR messagebuffer[4096] = L"";
  788. va_list ap;
  789. va_start(ap, messageID);
  790. if (!FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE,
  791. NULL,
  792. messageID,
  793. 0,
  794. messagebuffer,
  795. sizeof(messagebuffer)/sizeof(messagebuffer[0]),
  796. &ap))
  797. {
  798. if(!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  799. NULL,
  800. messageID,
  801. 0,
  802. messagebuffer,
  803. sizeof(messagebuffer)/sizeof(messagebuffer[0]),
  804. &ap))
  805. {
  806. va_end(ap);
  807. return GetLastError();
  808. }
  809. }
  810. fputws(messagebuffer,fp);
  811. va_end(ap);
  812. return ERROR_SUCCESS;
  813. }