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.

2489 lines
63 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. adlconvert.cpp
  5. Abstract:
  6. The routines to convert between AdlStatement, string in the ADL
  7. language, and a DACL.
  8. Author:
  9. t-eugenz - August 2000
  10. Environment:
  11. User mode only.
  12. Revision History:
  13. Created - August 2000
  14. Semantics finalized - September 2000
  15. --*/
  16. #include "adl.h"
  17. #include "adlconvert.h"
  18. void AdlStatement::ConvertFromDacl(IN const PACL pDacl)
  19. /*++
  20. Routine Description:
  21. Traverses the given ACL, and creates an AdlStatement structure
  22. representative of the DACL.
  23. Algorithm:
  24. First, break up the ACL into 32 stacks, by access mask bits, keeping
  25. track of the inheritance and SID.
  26. Then use the heuristic algorithm in ConvertStacksToPops to get a 'good'
  27. (though not necessarily optimal) sequence of stack pops to perform so as
  28. to produce the optimal set of ADL statements for the DACL.
  29. Finally, perform the sequence of pops and create the ADL statement.
  30. Arguments:
  31. pDacl - The DACL to convert to an AdlStatement
  32. Return Value:
  33. none
  34. --*/
  35. {
  36. DWORD dwIdx;
  37. DWORD dwIdxElems;
  38. AdlToken *pTok = NULL;
  39. AdlStatement::ADL_ERROR_TYPE adlErr = AdlStatement::ERROR_NO_ERROR;
  40. //
  41. // The stack representation of a DACL
  42. //
  43. DWORD pdwStackTop[32];
  44. DWORD pdwStackSize[32];
  45. PBIT_STACK_ELEM pStacks[32];
  46. //
  47. // Mappings from PSID to AdlToken of the name string and from
  48. // pointer into the user-specified language def to the appropriate
  49. // permission token. This allows reuse of name and permission tokens
  50. //
  51. map<const PSID, const AdlToken *> mapSidName;
  52. map<const WCHAR *, const AdlToken *> mapStringTok;
  53. //
  54. // list of pairs <Stack mask, Block Size>, which define the set of pops
  55. // to perform. This is filled in by the decision algorithm. For every
  56. // bit set in the stack mask, a block of the given size will be popped
  57. // into ADL from the stack.
  58. //
  59. list<pair<DWORD, DWORD> > listPops;
  60. list<pair<DWORD, DWORD> >::iterator iterPops;
  61. list<pair<DWORD, DWORD> >::iterator iterPopsEnd;
  62. //
  63. // List of permissions for a given access mask, used as output
  64. // by the access mask -> set of names lookup
  65. //
  66. list<WCHAR *> lPermissions;
  67. list<WCHAR *>::iterator iterPerm;
  68. list<WCHAR *>::iterator iterPermEnd;
  69. //
  70. // Initialize the stacks
  71. //
  72. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  73. {
  74. pdwStackSize[dwIdx] = 0;
  75. pdwStackTop[dwIdx] = 0;
  76. pStacks[dwIdx] = NULL;
  77. }
  78. //
  79. // First look up all names. If some names don't exist, save time
  80. // by not doing the rest of the conversion below
  81. //
  82. ConvertSidsToNames(pDacl, &mapSidName);
  83. //
  84. // Now convert the ACL to the set of 32 stacks (this needs to be freed
  85. // later)
  86. //
  87. ConvertDaclToStacks(pDacl, _pControl, pdwStackSize, pStacks);
  88. //
  89. // A bit of pre-processing: we will need a map from WCHAR * to
  90. // AdlToken *, so as to reuse AdlTokens for the same permission
  91. // name. The tokens will be garbage-collected later.
  92. //
  93. try
  94. {
  95. for( dwIdx = 0; _pControl->pPermissions[dwIdx].str != NULL; dwIdx++ )
  96. {
  97. pTok = new AdlToken(_pControl->pPermissions[dwIdx].str, 0, 0);
  98. try
  99. {
  100. AddToken(pTok);
  101. }
  102. catch(exception)
  103. {
  104. delete pTok;
  105. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  106. }
  107. mapStringTok[_pControl->pPermissions[dwIdx].str] = pTok;
  108. }
  109. }
  110. catch(exception)
  111. {
  112. adlErr = AdlStatement::ERROR_OUT_OF_MEMORY;
  113. goto error;
  114. }
  115. //
  116. // Now we are ready to actually convert the stacks into an ADL statement
  117. // First we run the recursive algorithm to determine the sequence of
  118. // pop operations on the stacks
  119. //
  120. try
  121. {
  122. ConvertStacksToPops(_pControl,
  123. pStacks,
  124. pdwStackSize,
  125. pdwStackTop,
  126. &listPops);
  127. }
  128. catch(exception)
  129. {
  130. adlErr = AdlStatement::ERROR_OUT_OF_MEMORY;
  131. goto error;
  132. }
  133. catch(AdlStatement::ADL_ERROR_TYPE err)
  134. {
  135. adlErr = err;
  136. goto error;
  137. }
  138. //
  139. // Now we perform the calculated pops
  140. //
  141. try
  142. {
  143. //
  144. // Go through the pops in order, and perform them
  145. //
  146. DWORD dwStacksPopped;
  147. DWORD dwBlockSize;
  148. for( iterPops = listPops.begin(), iterPopsEnd = listPops.end();
  149. iterPops != iterPopsEnd;
  150. iterPops++ )
  151. {
  152. dwStacksPopped = (*iterPops).first;
  153. dwBlockSize = (*iterPops).second;
  154. ASSERT( dwStacksPopped > 0 );
  155. ASSERT( dwBlockSize > 0 );
  156. //
  157. // Create new ADL statement
  158. //
  159. Next();
  160. //
  161. // Set permissions once, mask is same as stacks popped
  162. //
  163. lPermissions.erase(lPermissions.begin(), lPermissions.end());
  164. MapMaskToStrings(dwStacksPopped, &lPermissions);
  165. for( iterPerm = lPermissions.begin(),
  166. iterPermEnd = lPermissions.end();
  167. iterPerm != iterPermEnd;
  168. iterPerm++ )
  169. {
  170. Cur()->AddPermission(mapStringTok[*iterPerm]);
  171. }
  172. //
  173. // Now find the first stack with the block in question
  174. //
  175. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  176. {
  177. if( dwStacksPopped & ( 0x00000001 << dwIdx ) )
  178. {
  179. break;
  180. }
  181. }
  182. //
  183. // Add the Principals, ExPrincipals, and inheritance flags
  184. // to the ADL statement. The blocks should all be the same,
  185. // so first block is sufficient
  186. //
  187. //
  188. // First the inheritance flags
  189. //
  190. Cur()->OverwriteFlags(pStacks[dwIdx][pdwStackTop[dwIdx]].dwFlags);
  191. //
  192. // Now the principals and exprincipals
  193. //
  194. for( dwIdxElems = 0; dwIdxElems < dwBlockSize; dwIdxElems++ )
  195. {
  196. if( pStacks[dwIdx][pdwStackTop[dwIdx]+dwIdxElems].bAllow
  197. == FALSE )
  198. {
  199. Cur()->AddExPrincipal(
  200. mapSidName[
  201. pStacks[dwIdx][pdwStackTop[dwIdx] + dwIdxElems
  202. ].pSid]);
  203. }
  204. else
  205. {
  206. Cur()->AddPrincipal(
  207. mapSidName[
  208. pStacks[dwIdx][pdwStackTop[dwIdx] + dwIdxElems
  209. ].pSid]);
  210. }
  211. }
  212. //
  213. // Finally, move the tops of the stacks down to get rid of the
  214. // popped items
  215. //
  216. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  217. {
  218. if( dwStacksPopped & ( 0x00000001 << dwIdx ) )
  219. {
  220. pdwStackTop[dwIdx] += dwBlockSize;
  221. ASSERT(pdwStackTop[dwIdx] <= pdwStackSize[dwIdx]);
  222. }
  223. }
  224. }
  225. }
  226. catch(exception)
  227. {
  228. adlErr = AdlStatement::ERROR_OUT_OF_MEMORY;
  229. goto error;
  230. }
  231. catch(AdlStatement::ADL_ERROR_TYPE err)
  232. {
  233. adlErr = err;
  234. goto error;
  235. }
  236. error:;
  237. if( pStacks[0] != NULL )
  238. {
  239. //
  240. // Free the chunk of memory allocated by the converion
  241. //
  242. FreeMemory(pStacks[0]);
  243. }
  244. if( adlErr != AdlStatement::ERROR_NO_ERROR )
  245. {
  246. throw adlErr;
  247. }
  248. }
  249. ////////////////////////////////////////////////////////////////////////////////
  250. /////////////
  251. ///////////// DACL -> ADL conversion algorithm
  252. /////////////
  253. ////////////////////////////////////////////////////////////////////////////////
  254. void ConvertStacksToPops(
  255. IN const PADL_PARSER_CONTROL pControl,
  256. IN const PBIT_STACK_ELEM pStacks[32],
  257. IN const DWORD pdwStackSize[32],
  258. IN const DWORD pdwStackTop[32],
  259. OUT list< pair<DWORD, DWORD> > * pListPops
  260. )
  261. /*++
  262. Routine Description:
  263. Recursive heuristic to determine the 'good' conversion from ACL to ADL.
  264. Not necessarily optimal, but computationally feasible.
  265. This finds a sequence of pops which will empty the 32 per-bit stacks
  266. while trying to reduce the number of ADL statements output.
  267. Stacks are empty when the stack tops reach the stack ends.
  268. Algorithm:
  269. ---------
  270. While stacks are not empty:
  271. FindOptimalPop with given stack ends
  272. Set temporary stack sizes to the offsets for the optimal pop
  273. ConvertStacksToPops on the temporary stack ends
  274. Store the calculated optimal pop in pListPops
  275. Perform the optimal pops off the stacks
  276. Endwhile
  277. ---------
  278. For empty stacks, this just returns.
  279. The output offsets from FindOptimalPop work as temporary stack sizes,
  280. since everything ebove that must be popped off.
  281. WARNING: This is recursive, and uses 268 bytes of stack for locals.
  282. Therefore, a large worst-case ACL will blow the stack (if the recursion
  283. is near the bottom of the stack at every step). Once ADL goes into OS,
  284. this recursion can be rewritten as iteration by keeping a stack of the
  285. StackTop and StackSize in the heap instead of locals, as a finite-state
  286. stack machine.
  287. Arguments:
  288. pControl - The ADL parser spec, used for determining the number
  289. of strings it will take to express a permission
  290. pStacks - The stack representation of the DACL
  291. pdwStackSize - These are offsets to 1 past the last element in the
  292. stacks which should be considered
  293. pdwStackTop - These are offsets to the tops of the stacks to be
  294. considered
  295. pListPops - The STL list containing the sequence of pop operations
  296. to be performed, new pops are appended to this
  297. Return Value:
  298. none
  299. --*/
  300. {
  301. DWORD pdwTmpStackTop[32];
  302. DWORD pdwTmpStackSize[32];
  303. DWORD dwIdx;
  304. DWORD dwStacksPopped;
  305. DWORD dwBlockSize;
  306. //
  307. // Start with top of given stack
  308. //
  309. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  310. {
  311. pdwTmpStackTop[dwIdx] = pdwStackTop[dwIdx];
  312. }
  313. //
  314. // Stacks are empty when the top of each stack points to 1 past the end
  315. // Therefore, we can just use a memory compare on the tops array and
  316. // the stack sizes to check. Empty stacks have 0 size and top offset.
  317. //
  318. while( memcmp(pdwStackSize, pdwTmpStackTop, sizeof(DWORD) * 32) )
  319. {
  320. //
  321. // The loop should end on empty stacks. Therefore, if this fails,
  322. // we have an internal error. Otherwise, we have our optimal pop.
  323. //
  324. if( FALSE == FindOptimalPop(
  325. pControl,
  326. pStacks,
  327. pdwStackSize,
  328. pdwTmpStackTop,
  329. &dwStacksPopped,
  330. &dwBlockSize,
  331. pdwTmpStackSize
  332. ) )
  333. {
  334. throw AdlStatement::ERROR_FATAL_ACL_CONVERT_ERROR;
  335. }
  336. //
  337. // Now recurse, and pop off everything ABOVE the optimal pop
  338. //
  339. ConvertStacksToPops(
  340. pControl,
  341. pStacks,
  342. pdwTmpStackSize,
  343. pdwTmpStackTop,
  344. pListPops
  345. );
  346. //
  347. // Add the optimal pop to the list
  348. //
  349. pListPops->push_back(pair<DWORD, DWORD>(dwStacksPopped, dwBlockSize));
  350. //
  351. // Now update the tops of the stacks by lowering the tops by
  352. // the block size
  353. //
  354. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  355. {
  356. if( (0x00000001 << dwIdx) & dwStacksPopped )
  357. {
  358. //
  359. // By now we have removed everything ebove the optimal pop, and
  360. // the optimal pop itself. Therefore, go dwBlockSize past the
  361. // beginning of the optimal pop. Stacks other than those
  362. // involved in the optimal pop cannot be effected.
  363. //
  364. pdwTmpStackTop[dwIdx] = pdwTmpStackSize[dwIdx] + dwBlockSize;
  365. }
  366. }
  367. }
  368. }
  369. BOOL FindBlockInStack(
  370. IN const PBIT_STACK_ELEM pBlock,
  371. IN const DWORD dwBlockSize,
  372. IN const PBIT_STACK_ELEM pStack,
  373. IN const DWORD dwStackSize,
  374. IN const DWORD dwStackTop,
  375. OUT PDWORD pdwBlockStart
  376. )
  377. /*++
  378. Routine Description:
  379. Attempts to locate the first block of dwBlockSize which matches a block
  380. of the same size at pBlock in the given stack pStack, between dwStackTop
  381. and dwStackSize - 1. If successful, start offset of the block is stored in
  382. pdwBlockStart.
  383. Arguments:
  384. pBlock - A single block (see GetBlockSize for definition)
  385. for which to look for in pStack
  386. dwBlockSize - The number of elements composing this block
  387. pStack - The stack in which to look for pBlock
  388. dwStackSize - Offset to 1 past the last element in the stack to
  389. consider
  390. dwStackTop - Offset to the effective beginning of the stack
  391. pdwBlockStart - If successful, offset to the beginning of the
  392. found block is returned in this.
  393. Return Value:
  394. TRUE if block found
  395. FALSE otherwise, in which case *pdwBlockStart is undefined
  396. --*/
  397. {
  398. //
  399. // States used by this function
  400. //
  401. #define TMP2_NO_MATCH_STATE 0
  402. #define TMP2_MATCH_STATE 1
  403. DWORD dwState = TMP2_NO_MATCH_STATE;
  404. DWORD dwMatchStartIdx;
  405. DWORD dwIdxStack;
  406. DWORD dwIdxBlock;
  407. ASSERT( dwBlockSize > 0 );
  408. ASSERT( dwStackTop <= dwStackSize );
  409. for( dwIdxStack = dwStackTop, dwIdxBlock = 0;
  410. dwIdxStack < dwStackSize;
  411. dwIdxStack++ )
  412. {
  413. switch(dwState)
  414. {
  415. case TMP2_NO_MATCH_STATE:
  416. //
  417. // If the remaining stack is smaller than the block, no need to
  418. // check further
  419. //
  420. if( dwStackSize - dwIdxStack < dwBlockSize )
  421. {
  422. return FALSE;
  423. }
  424. //
  425. // Check for match start
  426. //
  427. if( pStack[dwIdxStack].bAllow == pBlock[dwIdxBlock].bAllow
  428. && pStack[dwIdxStack].dwFlags == pBlock[dwIdxBlock].dwFlags
  429. && EqualSid(pStack[dwIdxStack].pSid, pBlock[dwIdxBlock].pSid) )
  430. {
  431. //
  432. // Special case: block size 1
  433. //
  434. if( dwBlockSize == 1 )
  435. {
  436. *pdwBlockStart = dwIdxStack;
  437. return TRUE;
  438. }
  439. else
  440. {
  441. dwState = TMP2_MATCH_STATE;
  442. dwMatchStartIdx = dwIdxStack;
  443. dwIdxBlock++;
  444. }
  445. }
  446. break;
  447. case TMP2_MATCH_STATE:
  448. //
  449. // If still matched
  450. //
  451. if( pStack[dwIdxStack].bAllow == pBlock[dwIdxBlock].bAllow
  452. && pStack[dwIdxStack].dwFlags == pBlock[dwIdxBlock].dwFlags
  453. && EqualSid(pStack[dwIdxStack].pSid, pBlock[dwIdxBlock].pSid) )
  454. {
  455. dwIdxBlock++;
  456. //
  457. // Check for complete match
  458. //
  459. if( dwIdxBlock == dwBlockSize )
  460. {
  461. *pdwBlockStart = dwMatchStartIdx;
  462. return TRUE;
  463. }
  464. }
  465. else
  466. {
  467. //
  468. // Backtrack to the match start
  469. //
  470. dwState = TMP2_NO_MATCH_STATE;
  471. dwIdxBlock = 0;
  472. dwIdxStack = dwMatchStartIdx;
  473. }
  474. break;
  475. default:
  476. throw AdlStatement::ERROR_FATAL_ACL_CONVERT_ERROR;
  477. break;
  478. }
  479. }
  480. //
  481. // If never matched whole block, return FALSE
  482. //
  483. return FALSE;
  484. }
  485. BOOL FindOptimalPop(
  486. IN const PADL_PARSER_CONTROL pControl,
  487. IN const PBIT_STACK_ELEM pStacks[32],
  488. IN const DWORD pdwStackSize[32],
  489. IN const DWORD pdwStackTop[32],
  490. OUT PDWORD pdwStacksPopped,
  491. OUT PDWORD pdwBlockSize,
  492. OUT DWORD pdwPopOffsets[32]
  493. )
  494. /*++
  495. Routine Description:
  496. Attempts to locate the greedy-choice optimal set of blocks to pop off.
  497. Returns the optimal choice in the OUT values on success.
  498. The weight function can be tweaked, and may allow negative values, however
  499. the value of popping a single stack off the top MUST be positive.
  500. Uses this algorithm:
  501. -----------
  502. Start with weight 0
  503. For every non-empty stack:
  504. Get top block of stack
  505. Search all stacks for this block
  506. Compute the weight of this solution based on block size and # of stacks
  507. If the weight is greater than the current best weight:
  508. store the new weight as best weight
  509. store the new solution as best solution
  510. Endif
  511. Endfor
  512. If weight > 0
  513. Return the current best solution
  514. Else
  515. Report failure
  516. Endif
  517. -----------
  518. Arguments:
  519. pControl - The ADL parser spec, used for determining the number
  520. of strings it will take to express a permission
  521. pStacks - The stack representation of the DACL
  522. pdwStackSize - These are offsets to 1 past the last element in the
  523. stacks which should be considered
  524. pdwStackTop - These are offsets to the tops of the stacks to be
  525. considered
  526. pdwStacksPopped - Bitmask for which stacks will be popped, stacks which
  527. are effected by this pop have the appropriate bit set
  528. pdwBlockSize - The size of the block (same for all effected stacks) to
  529. be popped is returned through this.
  530. pdwPopOffsets - The start offsets of the blocks to pop are returned here
  531. Return Value:
  532. TRUE on success, if a pop with weight > 0 has been found
  533. FALSE otherwise, in which case OUT values are undefined
  534. --*/
  535. {
  536. DWORD dwIdxStacks1;
  537. DWORD dwIdxStacks2;
  538. //
  539. // Initial optimal solution
  540. //
  541. LONG iCurrentWeight = 0;
  542. //
  543. // Current solution
  544. //
  545. LONG iTempWeight;
  546. DWORD dwTempStacksPopped;
  547. DWORD dwTempBlockSize;
  548. DWORD pdwTempPops[32];
  549. DWORD dwBlockOffset;
  550. //
  551. // Try the block at the top of every stack
  552. //
  553. for( dwIdxStacks1 = 0; dwIdxStacks1 < 32; dwIdxStacks1++ )
  554. {
  555. //
  556. // Skip empty stacks
  557. //
  558. if( pdwStackSize[dwIdxStacks1] == pdwStackTop[dwIdxStacks1] )
  559. {
  560. continue;
  561. }
  562. dwTempBlockSize = GetStackBlockSize(pStacks[dwIdxStacks1],
  563. pdwStackTop[dwIdxStacks1],
  564. pdwStackSize[dwIdxStacks1]);
  565. //
  566. // If a block size of 0 is detected in a non-empty stack, then
  567. // this is not expressable in ADL, throw the error here
  568. //
  569. if( dwTempBlockSize == 0 )
  570. {
  571. throw AdlStatement::ERROR_INEXPRESSIBLE_ACL;
  572. }
  573. //
  574. // The initial weight is 0, since loop will account for top loop stack
  575. // Same with initial stacks popped
  576. //
  577. iTempWeight = 0;
  578. dwTempStacksPopped = 0;
  579. //
  580. // Now, try to find this block in all stacks
  581. //
  582. for( dwIdxStacks2 = 0; dwIdxStacks2 < 32; dwIdxStacks2++ )
  583. {
  584. //
  585. // Fist assume pop location is at the top (no pop),
  586. // even for empty stacks
  587. //
  588. pdwTempPops[dwIdxStacks2] = pdwStackTop[dwIdxStacks2];
  589. //
  590. // Skip empty stacks
  591. //
  592. if( ! (pdwStackSize[dwIdxStacks2] - pdwStackTop[dwIdxStacks2] > 0) )
  593. {
  594. continue;
  595. }
  596. if( TRUE == FindBlockInStack(
  597. &(pStacks[dwIdxStacks1][pdwStackTop[dwIdxStacks1]]),
  598. dwTempBlockSize,
  599. pStacks[dwIdxStacks2],
  600. pdwStackSize[dwIdxStacks2],
  601. pdwStackTop[dwIdxStacks2],
  602. &dwBlockOffset) )
  603. {
  604. //
  605. // Block was found in this stack
  606. //
  607. pdwTempPops[dwIdxStacks2] = dwBlockOffset;
  608. dwTempStacksPopped |= ( 0x00000001 << dwIdxStacks2);
  609. }
  610. }
  611. //
  612. // Calculate the weight of this solution
  613. //
  614. //
  615. // Weight for number of principals expressed
  616. //
  617. iTempWeight += (WEIGHT_STACK_HEIGHT) * dwTempBlockSize;
  618. //
  619. // Weights for each bit
  620. // also weights (or penalties) for having to pop things
  621. // off above the optimal pop
  622. //
  623. for( dwIdxStacks2 = 0; dwIdxStacks2 < 32; dwIdxStacks2++ )
  624. {
  625. if( dwTempStacksPopped & ( 0x00000001 << dwIdxStacks2 ) )
  626. {
  627. iTempWeight += (WEIGHT_PERM_BIT);
  628. iTempWeight += (WEIGHT_ITEM_ABOVE_POP)
  629. * ( pdwTempPops[dwIdxStacks2]
  630. - pdwStackTop[dwIdxStacks2] );
  631. }
  632. }
  633. //
  634. // Finally the weight/penalty for number of permission names
  635. // needed beyond the 1st one
  636. //
  637. iTempWeight += (WEIGHT_PERMISSION_NAME)
  638. * (NumStringsForMask(pControl, dwTempStacksPopped) - 1 );
  639. //
  640. // If this solution is better than the best so far, save it
  641. //
  642. if( iTempWeight > iCurrentWeight )
  643. {
  644. iCurrentWeight = iTempWeight;
  645. *pdwStacksPopped = dwTempStacksPopped;
  646. *pdwBlockSize = dwTempBlockSize;
  647. for( dwIdxStacks2 = 0; dwIdxStacks2 < 32; dwIdxStacks2++ )
  648. {
  649. pdwPopOffsets[dwIdxStacks2] = pdwTempPops[dwIdxStacks2];
  650. }
  651. }
  652. }
  653. //
  654. // If we have not found any solution, we were passed an empty set of stacks
  655. // Otherwise, the optimal solution is already in the OUT values
  656. //
  657. if( iCurrentWeight > 0 )
  658. {
  659. return TRUE;
  660. }
  661. else
  662. {
  663. return FALSE;
  664. }
  665. }
  666. void ConvertDaclToStacks(
  667. IN const PACL pDacl,
  668. IN const PADL_PARSER_CONTROL pControl,
  669. OUT DWORD pdwStackSize[32],
  670. OUT PBIT_STACK_ELEM pStacks[32]
  671. )
  672. /*++
  673. Routine Description:
  674. Traverses the given ACL, allocates the 32 per-bit stacks, and fills them
  675. with the ACL broken up per-bit. The allocated memory can be freed by
  676. a SINGLE call to AdlStatement::FreeMemory(pStacks[0]), since the block
  677. allocated is a single block.
  678. Arguments:
  679. pDacl - The DACL to convert
  680. pControl - The ADL_PARSER_CONTROL, for permission mapping
  681. pdwStackSize - The sizes of the stacks are returned here
  682. pStacks - The pointers to the per-bit stacks are returned here
  683. pStacks[0] should be freed later using
  684. AdlStatement::FreeMemory
  685. Return Value:
  686. none
  687. --*/
  688. {
  689. DWORD dwIdx;
  690. DWORD dwIdx2;
  691. DWORD dwTmp;
  692. DWORD dwNumBlocksTotal = 0;
  693. DWORD dwFlags;
  694. ACCESS_MASK amMask;
  695. BOOL bAllow;
  696. PVOID pAce;
  697. PSID pSid;
  698. DWORD pdwStackCur[32];
  699. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  700. {
  701. pdwStackSize[dwIdx] = 0;
  702. pdwStackCur[dwIdx] = 0;
  703. pStacks[dwIdx] = NULL;
  704. }
  705. //
  706. // Determine amount of stack space needed for each stack
  707. //
  708. for( dwIdx = 0; dwIdx < pDacl->AceCount; dwIdx++ )
  709. {
  710. GetAce(pDacl, dwIdx, &pAce);
  711. switch(((PACE_HEADER)pAce)->AceType)
  712. {
  713. case ACCESS_ALLOWED_ACE_TYPE:
  714. amMask = ((PACCESS_ALLOWED_ACE)pAce)->Mask
  715. & ~(pControl->amNeverSet | pControl->amSetAllow);
  716. break;
  717. case ACCESS_DENIED_ACE_TYPE:
  718. amMask = ((PACCESS_DENIED_ACE)pAce)->Mask
  719. & ~(pControl->amNeverSet | pControl->amSetAllow);
  720. break;
  721. default:
  722. throw AdlStatement::ERROR_UNKNOWN_ACE_TYPE;
  723. break;
  724. }
  725. for( dwIdx2 = 0, dwTmp = 0x00000001;
  726. dwIdx2 < 32 ;
  727. dwTmp <<= 1, dwIdx2++ )
  728. {
  729. if( dwTmp & amMask )
  730. {
  731. pdwStackSize[dwIdx2]++;
  732. dwNumBlocksTotal++;
  733. }
  734. }
  735. }
  736. //
  737. // Allocate the 32 stacks of pointers as a single memory chunk
  738. //
  739. pStacks[0] = (PBIT_STACK_ELEM)
  740. new BYTE[dwNumBlocksTotal * sizeof(BIT_STACK_ELEM)];
  741. if( pStacks[0] == NULL )
  742. {
  743. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  744. }
  745. //
  746. // Set the stack pointers to the proper locations in the single memory chunk
  747. //
  748. for( dwIdx = 1, dwTmp = pdwStackSize[0];
  749. dwIdx < 32;
  750. dwIdx++ )
  751. {
  752. if( pdwStackSize[dwIdx] > 0 )
  753. {
  754. pStacks[dwIdx] = &(pStacks[0][dwTmp]);
  755. dwTmp += pdwStackSize[dwIdx];
  756. }
  757. }
  758. ASSERT( dwTmp == dwNumBlocksTotal );
  759. //
  760. // Now go through the ACL again and fill in the stacks and advancing
  761. // the pStacksCur pointers
  762. // Stack sizes are known, so we treat the start of memory at TOP
  763. // of stack
  764. //
  765. // Make sure to strip out the INHERITED_ACE flag from the ACEs,
  766. // and handle the special access masks in the parser control
  767. //
  768. for( dwIdx = 0; dwIdx < pDacl->AceCount; dwIdx++ )
  769. {
  770. GetAce(pDacl, dwIdx, &pAce);
  771. switch(((PACE_HEADER)pAce)->AceType)
  772. {
  773. case ACCESS_ALLOWED_ACE_TYPE:
  774. dwFlags = ((PACCESS_ALLOWED_ACE)pAce)->Header.AceFlags
  775. & ( CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
  776. | NO_PROPAGATE_INHERIT_ACE | OBJECT_INHERIT_ACE );
  777. amMask = ((PACCESS_ALLOWED_ACE)pAce)->Mask
  778. & ~(pControl->amNeverSet | pControl->amSetAllow);
  779. bAllow = TRUE;
  780. pSid = &(((PACCESS_ALLOWED_ACE)pAce)->SidStart);
  781. break;
  782. case ACCESS_DENIED_ACE_TYPE:
  783. dwFlags = ((PACCESS_DENIED_ACE)pAce)->Header.AceFlags
  784. & ( CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
  785. | NO_PROPAGATE_INHERIT_ACE | OBJECT_INHERIT_ACE );
  786. amMask = ((PACCESS_DENIED_ACE)pAce)->Mask
  787. & ~(pControl->amNeverSet | pControl->amSetAllow);
  788. bAllow = FALSE;
  789. pSid = &(((PACCESS_DENIED_ACE)pAce)->SidStart);
  790. break;
  791. default:
  792. throw AdlStatement::ERROR_UNKNOWN_ACE_TYPE;
  793. break;
  794. }
  795. for( dwIdx2 = 0, dwTmp = 0x00000001;
  796. dwIdx2 < 32;
  797. dwIdx2++, dwTmp <<= 1 )
  798. {
  799. if( dwTmp & amMask )
  800. {
  801. //
  802. // Index should never reach size (1 past bottom) of the stack
  803. //
  804. ASSERT( pdwStackCur[dwIdx2] < pdwStackSize[dwIdx2] );
  805. //
  806. // Fill in the actual structure
  807. //
  808. pStacks[dwIdx2][pdwStackCur[dwIdx2]].bAllow = bAllow;
  809. pStacks[dwIdx2][pdwStackCur[dwIdx2]].pSid = pSid;
  810. pStacks[dwIdx2][pdwStackCur[dwIdx2]].dwFlags = dwFlags;
  811. //
  812. // Top of the stack is the top, but we fill the stack top-first
  813. // So advance toward bottom of stack
  814. //
  815. pdwStackCur[dwIdx2]++;
  816. }
  817. }
  818. }
  819. #if DBG
  820. //
  821. // Now perform an additional check in debug only that all stacks have
  822. // been filled as allocated
  823. //
  824. for( dwIdx = 0; dwIdx < 32; dwIdx++ )
  825. {
  826. ASSERT( pdwStackCur[dwIdx] == pdwStackSize[dwIdx] );
  827. }
  828. #endif
  829. }
  830. DWORD GetStackBlockSize(
  831. IN const PBIT_STACK_ELEM pStack,
  832. IN DWORD dwStartOffset,
  833. IN DWORD dwStackSize
  834. )
  835. /*++
  836. Routine Description:
  837. Finds the size of the maximum 'block' in the current per-bit stack, from
  838. the current position.
  839. A block is defined to be a set of 0 or more consecutive deny per-bit
  840. ACE entries immediately followed by 1 or more consecutive allow per-bit
  841. ACE entries such that the inheritance masks are the same.
  842. Therefore, a DENY without a matching allow is NOT a block. This is detected
  843. when we are in the TMP_READ_DENY_STATE (indicating we have already read at
  844. least one deny) and read either a deny or allow with a non-matching mask.
  845. On the other hand, even a single ALLOW is a valid block. Therefore this
  846. can only fail if dwStartOffset points to a deny.
  847. Arguments:
  848. pStack - The per-bit stack to check
  849. dwStartOffset - Position to begin at (using that ace, not the next one)
  850. dwStackSize - Maximum offset will be dwStackSize - 1, this should
  851. never get called with dwStackSize of 0.
  852. Return Value:
  853. Number of entries in the block if successful
  854. 0 if not successful
  855. --*/
  856. {
  857. //
  858. // States used by this function
  859. //
  860. #define TMP_START_STATE 0
  861. #define TMP_READ_DENY_STATE 1
  862. #define TMP_READ_ALLOW_STATE 2
  863. #define TMP_DONE_STATE 3
  864. DWORD dwCurState = TMP_START_STATE;
  865. DWORD dwCurOffset = dwStartOffset;
  866. DWORD dwFlags;
  867. ASSERT( dwStackSize > 0 );
  868. ASSERT( dwStartOffset < dwStackSize );
  869. //
  870. // Returns are inside the loop, they will terminate it
  871. //
  872. while( ( dwCurState != TMP_DONE_STATE ) && ( dwCurOffset < dwStackSize ) )
  873. {
  874. switch( dwCurState )
  875. {
  876. case TMP_START_STATE:
  877. dwFlags = pStack[dwCurOffset].dwFlags;
  878. if( pStack[dwCurOffset].bAllow == FALSE ) // DENY entry
  879. {
  880. dwCurState = TMP_READ_DENY_STATE;
  881. dwCurOffset++;
  882. }
  883. else // Otherwise an ALLOW entry
  884. {
  885. dwCurState = TMP_READ_ALLOW_STATE;
  886. dwCurOffset++;
  887. }
  888. break;
  889. case TMP_READ_DENY_STATE:
  890. //
  891. // If we are in this state, and find an entry with non-matching
  892. // flags, this means no valid block is possible, return 0
  893. //
  894. if( pStack[dwCurOffset].dwFlags != dwFlags )
  895. {
  896. //
  897. // Set end offset to indicate 0 block size and finish
  898. // This indicates there is no valid block
  899. //
  900. dwCurState = TMP_DONE_STATE;
  901. dwCurOffset = dwStartOffset;
  902. }
  903. else
  904. {
  905. if( pStack[dwCurOffset].bAllow == FALSE )
  906. {
  907. //
  908. // Another deny, stay in same state
  909. //
  910. dwCurOffset++;
  911. }
  912. else
  913. {
  914. //
  915. // Allow with matching flags, go into allow state
  916. //
  917. dwCurState = TMP_READ_ALLOW_STATE;
  918. dwCurOffset++;
  919. }
  920. }
  921. break;
  922. case TMP_READ_ALLOW_STATE:
  923. //
  924. // If we are in this state, we have read 0 or more denies and
  925. // at least 1 allow. Therefore, we already have a block, so we
  926. // just need to find its end and return.
  927. //
  928. if( (dwFlags == pStack[dwCurOffset].dwFlags)
  929. && (pStack[dwCurOffset].bAllow == TRUE) )
  930. {
  931. //
  932. // Another matching allow
  933. //
  934. dwCurOffset++;
  935. }
  936. else
  937. {
  938. //
  939. // End of block found
  940. //
  941. dwCurState = TMP_DONE_STATE;
  942. }
  943. break;
  944. }
  945. }
  946. //
  947. // Two ways to reach this point, hitting the bottom of the stack or
  948. // finding the end of the block (or lack thereof). In both cases, the
  949. // size of the block is dwCurOffset - dwStartOffset. In case of no
  950. // valid block, this will evaluate to 0.
  951. //
  952. return dwCurOffset - dwStartOffset;
  953. }
  954. DWORD NumStringsForMask(
  955. IN const PADL_PARSER_CONTROL pControl,
  956. IN ACCESS_MASK amMask
  957. )
  958. /*++
  959. Routine Description:
  960. Determines the number of permission names which would be required
  961. to express the access mask
  962. Arguments:
  963. pControl - This contains the mapping between permission names and masks
  964. amMask - The mask to represent
  965. Return Value:
  966. DWORD - The number of strings which would be required
  967. --*/
  968. {
  969. ACCESS_MASK amOptional = amMask;
  970. DWORD dwIdx = 0;
  971. DWORD dwNumStrings = 0;
  972. while( amMask != 0
  973. && (pControl->pPermissions )[dwIdx].str != NULL )
  974. {
  975. //
  976. // If all the bits representing the string are present in the whole mask
  977. // and at least some of the bits have not yet been represented
  978. // by another string, add this string to the list and remove the
  979. // bits from amMask (representing the still required bits)
  980. //
  981. if( ( (amOptional & (pControl->pPermissions )[dwIdx].mask)
  982. == (pControl->pPermissions )[dwIdx].mask )
  983. && (amMask & (pControl->pPermissions )[dwIdx].mask))
  984. {
  985. amMask &= ~(pControl->pPermissions )[dwIdx].mask;
  986. dwNumStrings++;
  987. }
  988. dwIdx++;
  989. }
  990. //
  991. // If any of the rights are not mapped, throw an exception
  992. //
  993. if( amMask != 0 )
  994. {
  995. throw AdlStatement::ERROR_UNKNOWN_ACCESS_MASK;
  996. }
  997. return dwNumStrings;
  998. }
  999. ////////////////////////////////////////////////////////////////////////////////
  1000. /////////////
  1001. ///////////// Conversion from ADL to DACL
  1002. /////////////
  1003. ////////////////////////////////////////////////////////////////////////////////
  1004. void AdlStatement::WriteToDacl(OUT PACL * ppDacl)
  1005. /*++
  1006. Routine Description:
  1007. Creates a DACL representative of the AdlStatement structure.
  1008. The PACL to the DACL is stored in ppDacl. It should be freed
  1009. with the AdlStatement::FreeMemory() function.
  1010. The algorithm is very straightforward, it's just a linear conversion
  1011. from ADL to a DACL, taking each ADL substatement and creating deny ACEs
  1012. for every ExPrincipal and allow ACEs for Principals.
  1013. Arguments:
  1014. ppDacl - A pointer to the allocated DACL is stored in *pDacl
  1015. Return Value:
  1016. none
  1017. --*/
  1018. {
  1019. //
  1020. // If not initialized, do not output
  1021. //
  1022. if( _bReady == FALSE )
  1023. {
  1024. throw AdlStatement::ERROR_NOT_INITIALIZED;
  1025. }
  1026. //
  1027. // Mapping from token *'s to SIDs
  1028. //
  1029. map<const AdlToken *, PSID> mapTokSid;
  1030. //
  1031. // Mapping from Adl substatements (AdlTree *'s) to their access mask
  1032. // This is before the special treatment masks are applied
  1033. //
  1034. map<const AdlTree *, ACCESS_MASK> mapTreeMask;
  1035. //
  1036. // Iterators which are reused
  1037. //
  1038. list<AdlTree *>::iterator iterTrees;
  1039. list<AdlTree *>::iterator iterTreesEnd;
  1040. list<const AdlToken *>::iterator iterTokens;
  1041. list<const AdlToken *>::iterator iterTokensEnd;
  1042. ACCESS_MASK amMask;
  1043. stack<PBYTE> stackToFree;
  1044. PBYTE pbLastAllocated;
  1045. DWORD dwAclSize = sizeof(ACL);
  1046. PACL pAcl = NULL;
  1047. try {
  1048. //
  1049. // Do a single LSA lookup, convert all at once
  1050. // SIDs will need to be deleted by retrieving them from the map
  1051. //
  1052. ConvertNamesToSids(&mapTokSid);
  1053. //
  1054. // Calculate the ACL size
  1055. //
  1056. for(iterTrees = _lTree.begin(), iterTreesEnd = _lTree.end();
  1057. iterTrees != iterTreesEnd;
  1058. iterTrees++)
  1059. {
  1060. //
  1061. // Now go through the Principals
  1062. //
  1063. for(iterTokens = (*iterTrees)->GetPrincipals()->begin(),
  1064. iterTokensEnd = (*iterTrees)->GetPrincipals()->end();
  1065. iterTokens != iterTokensEnd;
  1066. iterTokens ++)
  1067. {
  1068. dwAclSize += (
  1069. sizeof(ACCESS_ALLOWED_ACE)
  1070. - sizeof(DWORD)
  1071. + GetLengthSid((*(mapTokSid.find(*iterTokens))).second)
  1072. );
  1073. }
  1074. //
  1075. // And the ExPrincipals
  1076. //
  1077. for(iterTokens = (*iterTrees)->GetExPrincipals()->begin(),
  1078. iterTokensEnd = (*iterTrees)->GetExPrincipals()->end();
  1079. iterTokens != iterTokensEnd;
  1080. iterTokens ++)
  1081. {
  1082. dwAclSize += (
  1083. sizeof(ACCESS_DENIED_ACE)
  1084. - sizeof(DWORD)
  1085. + GetLengthSid((*(mapTokSid.find(*iterTokens))).second)
  1086. );
  1087. }
  1088. //
  1089. // Calculate the effective permissions ahead of time
  1090. //
  1091. amMask = 0;
  1092. for(iterTokens = (*iterTrees)->GetPermissions()->begin(),
  1093. iterTokensEnd = (*iterTrees)->GetPermissions()->end();
  1094. iterTokens != iterTokensEnd;
  1095. iterTokens ++)
  1096. {
  1097. amMask |= MapTokenToMask(*iterTokens);
  1098. }
  1099. //
  1100. // And enter the AdlTree *, Mask pair into the map
  1101. //
  1102. mapTreeMask[*iterTrees] = amMask;
  1103. }
  1104. //
  1105. // Allocate the ACL
  1106. //
  1107. pAcl = (PACL)new BYTE[dwAclSize];
  1108. if( pAcl == NULL )
  1109. {
  1110. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  1111. }
  1112. //
  1113. // Initialize the ACL
  1114. //
  1115. if( ! InitializeAcl(pAcl, dwAclSize, ACL_REVISION_DS))
  1116. {
  1117. throw AdlStatement::ERROR_ACL_API_FAILED;
  1118. }
  1119. //
  1120. // Now go through the substatements and create the ACEs
  1121. //
  1122. for(iterTrees = _lTree.begin(), iterTreesEnd = _lTree.end();
  1123. iterTrees != iterTreesEnd;
  1124. iterTrees++)
  1125. {
  1126. //
  1127. // First add the denies for this statement
  1128. //
  1129. for(iterTokens = (*iterTrees)->GetExPrincipals()->begin(),
  1130. iterTokensEnd = (*iterTrees)->GetExPrincipals()->end();
  1131. iterTokens != iterTokensEnd;
  1132. iterTokens ++)
  1133. {
  1134. if( ! AddAccessDeniedAceEx(
  1135. pAcl,
  1136. ACL_REVISION_DS,
  1137. (*iterTrees)->GetFlags(),
  1138. ( mapTreeMask[*iterTrees]
  1139. & ~_pControl->amSetAllow)
  1140. & ~_pControl->amNeverSet,
  1141. mapTokSid[*iterTokens] ))
  1142. {
  1143. throw AdlStatement::ERROR_ACL_API_FAILED;
  1144. }
  1145. }
  1146. //
  1147. // Now go through the Principals, add allows
  1148. //
  1149. for(iterTokens = (*iterTrees)->GetPrincipals()->begin(),
  1150. iterTokensEnd = (*iterTrees)->GetPrincipals()->end();
  1151. iterTokens != iterTokensEnd;
  1152. iterTokens ++)
  1153. {
  1154. if( ! AddAccessAllowedAceEx(
  1155. pAcl,
  1156. ACL_REVISION_DS,
  1157. (*iterTrees)->GetFlags(),
  1158. (mapTreeMask[*iterTrees]
  1159. | _pControl->amSetAllow)
  1160. & ~_pControl->amNeverSet,
  1161. mapTokSid[*iterTokens] ))
  1162. {
  1163. throw AdlStatement::ERROR_ACL_API_FAILED;
  1164. }
  1165. }
  1166. }
  1167. }
  1168. catch(...)
  1169. {
  1170. if( pAcl != NULL )
  1171. {
  1172. //
  1173. // Memory allocated for ACL
  1174. //
  1175. delete[] (PBYTE)pAcl;
  1176. }
  1177. //
  1178. // Memory allocated for the SIDs
  1179. //
  1180. while( !mapTokSid.empty() )
  1181. {
  1182. delete[] (PBYTE) (*(mapTokSid.begin())).second;
  1183. mapTokSid.erase(mapTokSid.begin());
  1184. }
  1185. //
  1186. // and pass the exception along
  1187. //
  1188. throw;
  1189. }
  1190. //
  1191. // Free the SIDs if done, since they are copied into the ACL
  1192. //
  1193. while( !mapTokSid.empty() )
  1194. {
  1195. delete[] (PBYTE) (*(mapTokSid.begin())).second;
  1196. mapTokSid.erase(mapTokSid.begin());
  1197. }
  1198. //
  1199. // The DACL is returned, so it should not be deallocated
  1200. //
  1201. *ppDacl = pAcl;
  1202. }
  1203. ////////////////////////////////////////////////////////////////////////////////
  1204. /////////////
  1205. ///////////// Utility functions
  1206. /////////////
  1207. ////////////////////////////////////////////////////////////////////////////////
  1208. bool AdlCompareStruct::operator()(IN const PSID pSid1,
  1209. IN const PSID pSid2 ) const
  1210. /*++
  1211. Routine Description:
  1212. This is a less-than function which places a complete ordering on
  1213. a set of PSIDs by value, NULL PSIDs are valid. This is used by the
  1214. STL map.
  1215. Since the number of subauthorities appears before the subauthorities
  1216. themselves, that difference will be noticed for two SIDs of different
  1217. size before the memcmp tries to access the nonexistant subauthority
  1218. in the shorter SID, therefore an access violation will not occur.
  1219. Arguments:
  1220. pSid1 - First PSID
  1221. pSid2 - Second PSID
  1222. Return Value:
  1223. Returns TRUE iff SID1 < SID2
  1224. FALSE otherwise
  1225. --*/
  1226. {
  1227. //
  1228. // If both are NULL, false should be returned for complete ordering
  1229. //
  1230. if(pSid2 == NULL)
  1231. {
  1232. return false;
  1233. }
  1234. if(pSid1 == NULL)
  1235. {
  1236. return true;
  1237. }
  1238. if( memcmp(pSid1, pSid2, GetLengthSid(pSid1)) < 0 )
  1239. {
  1240. return true;
  1241. }
  1242. else
  1243. {
  1244. return false;
  1245. }
  1246. }
  1247. bool AdlCompareStruct::operator()(IN const WCHAR * sz1,
  1248. IN const WCHAR * sz2 ) const
  1249. /*++
  1250. Routine Description:
  1251. operator() compares two null-terminated WCHAR* strings, case-INSENSITIVE.
  1252. Arguments:
  1253. sz1 - First string
  1254. sz2 - Second string
  1255. Return Value:
  1256. Returns TRUE iff sz1 < sz2
  1257. FALSE otherwise
  1258. --*/
  1259. {
  1260. return ( _wcsicmp(sz1, sz2) < 0 );
  1261. }
  1262. void AdlStatement::MapMaskToStrings(
  1263. IN ACCESS_MASK amMask,
  1264. IN OUT list<WCHAR *> *pList ) const
  1265. /*++
  1266. Routine Description:
  1267. Converts the given access mask into a list of const WCHAR *'s representing
  1268. the possibly overlapping permission strings which, when combined by a
  1269. bitwise OR, are equal to the access mask given. Throws exception if
  1270. a given access mask cannot be represented by the user-specified permissions.
  1271. The WCHAR * pointers are const, and should not be deallocated.
  1272. Arguments:
  1273. amMask - The mask to represent
  1274. pList - An allocated STL list in which to store the pointers
  1275. Return Value:
  1276. none
  1277. --*/
  1278. {
  1279. ACCESS_MASK amOptional = amMask;
  1280. DWORD dwIdx = 0;
  1281. while( amMask != 0
  1282. && (_pControl->pPermissions )[dwIdx].str != NULL )
  1283. {
  1284. //
  1285. // If all the bits representing the string are present in the whole mask
  1286. // and at least some of the bits have not yet been represented
  1287. // by another string, add this string to the list and remove the
  1288. // bits from amMask (representing the still required bits)
  1289. //
  1290. if( ( (amOptional & (_pControl->pPermissions )[dwIdx].mask)
  1291. == (_pControl->pPermissions )[dwIdx].mask )
  1292. && (amMask & (_pControl->pPermissions )[dwIdx].mask))
  1293. {
  1294. amMask &= ~(_pControl->pPermissions )[dwIdx].mask;
  1295. pList->push_back((_pControl->pPermissions )[dwIdx].str);
  1296. }
  1297. dwIdx++;
  1298. }
  1299. //
  1300. // If any of the rights are not mapped, throw an exception
  1301. //
  1302. if( amMask != 0 )
  1303. {
  1304. throw AdlStatement::ERROR_UNKNOWN_ACCESS_MASK;
  1305. }
  1306. }
  1307. void AdlStatement::ConvertSidsToNames(
  1308. IN const PACL pDacl,
  1309. IN OUT map<const PSID, const AdlToken *> * mapSidsNames
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. Traverses a DACL, and creates string representations of every SID
  1314. found in the DACL. Returns them in the provided map. The newly allocated
  1315. tokens will get garbage-collected by the AdlStatement later, no need
  1316. to free manually. Since the PSIDs used are the same as in the ACL itself,
  1317. we don't need to map by value, since pointer uniqueness is guaranteed here.
  1318. Arguments:
  1319. pDacl - DACL to traverse
  1320. mapSidNames - Where to store the resulting mapping
  1321. Return Value:
  1322. none
  1323. --*/
  1324. {
  1325. AdlStatement::ADL_ERROR_TYPE adlError = AdlStatement::ERROR_NO_ERROR;
  1326. DWORD dwIdx = 0;
  1327. LPVOID pAce = NULL;
  1328. AdlToken *pTok = NULL;
  1329. AdlToken *pTokLastAllocated = NULL;
  1330. wstring wsName, wsDomain;
  1331. NTSTATUS ntErr = STATUS_SUCCESS;
  1332. LSA_HANDLE LsaPolicy;
  1333. PLSA_REFERENCED_DOMAIN_LIST RefDomains = NULL;
  1334. PLSA_TRANSLATED_NAME Names = NULL;
  1335. LSA_OBJECT_ATTRIBUTES LsaObjectAttributes;
  1336. //
  1337. // Traverse the ACL to get the list of SIDs used
  1338. //
  1339. PSID *ppSids = NULL;
  1340. ppSids = (PSID *) new BYTE[sizeof(PSID) * pDacl->AceCount];
  1341. if( ppSids == NULL )
  1342. {
  1343. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1344. goto error;
  1345. }
  1346. for(dwIdx = 0; dwIdx < pDacl->AceCount; dwIdx++)
  1347. {
  1348. GetAce(pDacl, dwIdx, &pAce);
  1349. switch( ((ACE_HEADER *)pAce)->AceType )
  1350. {
  1351. case ACCESS_ALLOWED_ACE_TYPE:
  1352. ppSids[dwIdx] = &( ((ACCESS_ALLOWED_ACE *)pAce)->SidStart);
  1353. break;
  1354. case ACCESS_DENIED_ACE_TYPE:
  1355. ppSids[dwIdx] = &( ((ACCESS_DENIED_ACE *)pAce)->SidStart);
  1356. break;
  1357. default:
  1358. adlError = AdlStatement::ERROR_UNKNOWN_ACE_TYPE;
  1359. goto error;
  1360. break;
  1361. }
  1362. }
  1363. //
  1364. // Look up all SIDs, getting user and domain names, single LSA call
  1365. //
  1366. LsaObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
  1367. LsaObjectAttributes.RootDirectory = NULL;
  1368. LsaObjectAttributes.ObjectName = NULL;
  1369. LsaObjectAttributes.Attributes = 0;
  1370. LsaObjectAttributes.SecurityDescriptor = NULL;
  1371. LsaObjectAttributes.SecurityQualityOfService = NULL;
  1372. ntErr = LsaOpenPolicy(
  1373. NULL,
  1374. &LsaObjectAttributes,
  1375. POLICY_LOOKUP_NAMES,
  1376. &LsaPolicy);
  1377. if( ntErr != STATUS_SUCCESS )
  1378. {
  1379. adlError = AdlStatement::ERROR_LSA_FAILED;
  1380. goto error;
  1381. }
  1382. //
  1383. // Garbage collect later
  1384. //
  1385. ntErr = LsaLookupSids(LsaPolicy,
  1386. pDacl->AceCount,
  1387. ppSids,
  1388. &RefDomains,
  1389. &Names);
  1390. LsaClose(LsaPolicy);
  1391. if( ntErr != ERROR_SUCCESS )
  1392. {
  1393. if( (ntErr == STATUS_SOME_NOT_MAPPED) || (ntErr == STATUS_NONE_MAPPED) )
  1394. {
  1395. adlError = AdlStatement::ERROR_UNKNOWN_SID;
  1396. }
  1397. else
  1398. {
  1399. adlError = AdlStatement::ERROR_LSA_FAILED;
  1400. }
  1401. goto error;
  1402. }
  1403. //
  1404. // Now traverse the list ppSids, creating matching tokens for the
  1405. // SIDs in the ACL.
  1406. //
  1407. try
  1408. {
  1409. for(dwIdx = 0; dwIdx < pDacl->AceCount; dwIdx++)
  1410. {
  1411. pTok = NULL;
  1412. //
  1413. // LSA Strings not terminated, create terminated version
  1414. // LSA buffer sizes in bytes, not wchars
  1415. //
  1416. assert(Names[dwIdx].DomainIndex >= 0);
  1417. wsName.assign(Names[dwIdx].Name.Buffer,
  1418. Names[dwIdx].Name.Length / sizeof(WCHAR));
  1419. //
  1420. // If builtin, no need for domain info
  1421. //
  1422. if(Names[dwIdx].Use == SidTypeWellKnownGroup)
  1423. {
  1424. pTok = new AdlToken(wsName.c_str(), 0, 0);
  1425. }
  1426. else
  1427. {
  1428. wsDomain.assign(
  1429. RefDomains->Domains[Names[dwIdx].DomainIndex].Name.Buffer,
  1430. RefDomains->Domains[Names[dwIdx].DomainIndex].Name.Length
  1431. / sizeof(WCHAR));
  1432. pTok = new AdlToken(wsName.c_str(), wsDomain.c_str(), 0, 0);
  1433. }
  1434. if( pTok == NULL )
  1435. {
  1436. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1437. goto error;
  1438. }
  1439. else
  1440. {
  1441. //
  1442. // This will be deleted immediately if we cannot save the token
  1443. // for later deallocation
  1444. //
  1445. pTokLastAllocated = pTok;
  1446. }
  1447. AddToken(pTok); // For later garbage collection
  1448. //
  1449. // No need ot delete immedeately, since no exception thrown
  1450. //
  1451. pTokLastAllocated = NULL;
  1452. (*mapSidsNames)[(ppSids[dwIdx])] = pTok;
  1453. }
  1454. }
  1455. catch(exception)
  1456. {
  1457. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1458. goto error;
  1459. }
  1460. //
  1461. // Done with the SIDs and LSA info, deallocate
  1462. //
  1463. error:;
  1464. if( RefDomains != NULL )
  1465. {
  1466. LsaFreeMemory(RefDomains);
  1467. }
  1468. if( Names != NULL )
  1469. {
  1470. LsaFreeMemory(Names);
  1471. }
  1472. if( ppSids != NULL )
  1473. {
  1474. delete[] (PBYTE) ppSids;
  1475. }
  1476. if( adlError != AdlStatement::ERROR_NO_ERROR )
  1477. {
  1478. throw adlError;
  1479. }
  1480. }
  1481. ACCESS_MASK AdlStatement::MapTokenToMask(
  1482. IN const AdlToken * tokPermission
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. This routine maps a string represening a right to the matching access bits
  1487. using the user-supplied mapping.
  1488. This assumes that there are no pairs with ACCESS_MASK of 0 in the
  1489. user-supplied mapping.
  1490. Arguments:
  1491. tokPermission - The permission token to be looked up
  1492. Return Value:
  1493. ACCESS_MASK - The corresponding access mask
  1494. --*/
  1495. {
  1496. ACCESS_MASK amMask = 0;
  1497. DWORD dwIdx = 0;
  1498. //
  1499. // The token should never have a second value
  1500. //
  1501. if( tokPermission->GetOptValue() != NULL )
  1502. {
  1503. throw AdlStatement::ERROR_FATAL_PARSER_ERROR;
  1504. }
  1505. while(amMask == 0 && (_pControl->pPermissions)[dwIdx].str != NULL)
  1506. {
  1507. if(0 == _wcsicmp(tokPermission->GetValue(),
  1508. (_pControl->pPermissions)[dwIdx].str ))
  1509. {
  1510. amMask = (_pControl->pPermissions)[dwIdx].mask;
  1511. }
  1512. ++dwIdx;
  1513. }
  1514. //
  1515. // If mask was not matched, throw exception
  1516. //
  1517. if(amMask == 0)
  1518. {
  1519. SetErrorToken(tokPermission);
  1520. throw AdlStatement::ERROR_UNKNOWN_PERMISSION;
  1521. }
  1522. return amMask;
  1523. }
  1524. void AdlStatement::ConvertNamesToSids(
  1525. IN OUT map<const AdlToken *, PSID> * mapTokSid
  1526. )
  1527. /*++
  1528. Routine Description:
  1529. This routine traverses all AdlTree's in the AdlStatement, and creates a list
  1530. of all usernames used. It then makes a single LSA call, and creates a map
  1531. of name AdlToken*'s to PSIDs, for later use by the conversion function.
  1532. The newly allocated PSIDs are stored in the map. They should be freed
  1533. using the AdlStatement::FreeMemory() function.
  1534. On error, any PSIDs that have been added to the map are deleted.
  1535. Arguments:
  1536. mapTokSid - Allocated map to which the Token,PSID entries should
  1537. be added. This MUST be empty. Otherwise, on
  1538. error, externally allocated memory would get
  1539. freed here.
  1540. Return Value:
  1541. none
  1542. --*/
  1543. {
  1544. list<AdlTree *>::iterator iterTrees;
  1545. list<AdlTree *>::iterator iterTreesEnd;
  1546. list<const AdlToken *>::iterator iterTokens;
  1547. list<const AdlToken *>::iterator iterTokensEnd;
  1548. //
  1549. // List of all Principal tokens used, allows for a single tree traversal
  1550. //
  1551. list<const AdlToken *> listAllPrincipals;
  1552. //
  1553. // Mapping from PLSA_STRING to AdlToken, for detecting which
  1554. // username is invalid
  1555. //
  1556. map<DWORD, const AdlToken *> mapIdxToken;
  1557. //
  1558. // Delayed garbage collection
  1559. //
  1560. stack<PBYTE> stackToFree;
  1561. void * pLastAllocated = NULL;
  1562. AdlStatement::ADL_ERROR_TYPE adlError = AdlStatement::ERROR_NO_ERROR;
  1563. DWORD dwDomainSidSize;
  1564. DWORD numNames;
  1565. DWORD dwIdx;
  1566. PSID pSidTemp;
  1567. LSA_HANDLE LsaPolicy;
  1568. PLSA_UNICODE_STRING pLsaStrings;
  1569. PLSA_REFERENCED_DOMAIN_LIST RefDomains = NULL;
  1570. PLSA_TRANSLATED_SID TranslatedSids = NULL;
  1571. LSA_OBJECT_ATTRIBUTES LsaObjectAttributes;
  1572. LsaObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
  1573. LsaObjectAttributes.RootDirectory = NULL;
  1574. LsaObjectAttributes.ObjectName = NULL;
  1575. LsaObjectAttributes.Attributes = 0;
  1576. LsaObjectAttributes.SecurityDescriptor = NULL;
  1577. LsaObjectAttributes.SecurityQualityOfService = NULL;
  1578. //
  1579. // Verify that the input map is empty as required
  1580. //
  1581. if( !(*mapTokSid).empty() )
  1582. {
  1583. throw AdlStatement::ERROR_FATAL_PARSER_ERROR;
  1584. }
  1585. //
  1586. // STL throws exceptions, catch them here
  1587. //
  1588. try
  1589. {
  1590. //
  1591. // Determine total number of names and place them all in the list
  1592. //
  1593. for(numNames = 0, iterTrees = _lTree.begin(), iterTreesEnd = _lTree.end();
  1594. iterTrees != iterTreesEnd;
  1595. iterTrees++)
  1596. {
  1597. iterTokensEnd = (*iterTrees)->GetPrincipals()->end();
  1598. for(iterTokens = (*iterTrees)->GetPrincipals()->begin();
  1599. iterTokens != iterTokensEnd; iterTokens ++)
  1600. {
  1601. numNames++;
  1602. listAllPrincipals.push_back(*iterTokens);
  1603. }
  1604. iterTokensEnd = (*iterTrees)->GetExPrincipals()->end();
  1605. for(iterTokens = (*iterTrees)->GetExPrincipals()->begin();
  1606. iterTokens != iterTokensEnd; iterTokens ++)
  1607. {
  1608. numNames++;
  1609. listAllPrincipals.push_back(*iterTokens);
  1610. }
  1611. }
  1612. //
  1613. // Allocate the needed memory for the LSA name list
  1614. //
  1615. pLsaStrings = (PLSA_UNICODE_STRING)
  1616. new BYTE[numNames * sizeof(LSA_UNICODE_STRING)];
  1617. if( pLsaStrings == NULL )
  1618. {
  1619. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1620. goto error;
  1621. }
  1622. else
  1623. {
  1624. pLastAllocated = pLsaStrings;
  1625. stackToFree.push( (PBYTE)pLsaStrings );
  1626. pLastAllocated = NULL;
  1627. }
  1628. //
  1629. // Retrieve name strings here in proper format, DOMAIN\USER
  1630. //
  1631. for(iterTokens = listAllPrincipals.begin(),
  1632. dwIdx = 0,
  1633. iterTokensEnd = listAllPrincipals.end();
  1634. iterTokens != iterTokensEnd;
  1635. iterTokens ++, dwIdx++)
  1636. {
  1637. //
  1638. // Name may be with domain, or just username
  1639. //
  1640. if( (*iterTokens)->GetOptValue() != NULL )
  1641. {
  1642. //
  1643. // Extra 1 wchar for the '\' character, 2 bytes per wchar
  1644. //
  1645. pLsaStrings[dwIdx].Length = sizeof(WCHAR) *
  1646. ( wcslen((*iterTokens)->GetValue()) +
  1647. wcslen((*iterTokens)->GetOptValue()) + 1);
  1648. }
  1649. else
  1650. {
  1651. pLsaStrings[dwIdx].Length = sizeof(WCHAR) *
  1652. (wcslen((*iterTokens)->GetValue()) + 1);
  1653. }
  1654. pLsaStrings[dwIdx].MaximumLength = pLsaStrings[dwIdx].Length
  1655. + sizeof(WCHAR);
  1656. pLsaStrings[dwIdx].Buffer =
  1657. (LPTSTR)new BYTE[pLsaStrings[dwIdx].MaximumLength];
  1658. if( pLsaStrings[dwIdx].Buffer == NULL )
  1659. {
  1660. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1661. goto error;
  1662. }
  1663. else
  1664. {
  1665. pLastAllocated = pLsaStrings[dwIdx].Buffer;
  1666. stackToFree.push((PBYTE)(pLsaStrings[dwIdx].Buffer));
  1667. pLastAllocated = NULL;
  1668. mapIdxToken[dwIdx] = *iterTokens;
  1669. }
  1670. if( (*iterTokens)->GetOptValue != NULL )
  1671. {
  1672. wsprintf( (LPTSTR)(pLsaStrings[dwIdx].Buffer),
  1673. L"%s%c%s",
  1674. (*iterTokens)->GetOptValue(),
  1675. _pControl->pLang->CH_SLASH,
  1676. (*iterTokens)->GetValue() );
  1677. }
  1678. else
  1679. {
  1680. wsprintf( (LPTSTR)(pLsaStrings[dwIdx].Buffer),
  1681. L"%s",
  1682. (*iterTokens)->GetValue() );
  1683. }
  1684. }
  1685. //
  1686. // Open the LSA policy
  1687. //
  1688. NTSTATUS ntErr;
  1689. ntErr = LsaOpenPolicy(
  1690. NULL,
  1691. &LsaObjectAttributes,
  1692. POLICY_LOOKUP_NAMES,
  1693. &LsaPolicy);
  1694. if( ntErr != STATUS_SUCCESS )
  1695. {
  1696. adlError = AdlStatement::ERROR_LSA_FAILED;
  1697. goto error;
  1698. }
  1699. //
  1700. // Now perform the LsaLookupNames call
  1701. //
  1702. ntErr = LsaLookupNames(
  1703. LsaPolicy,
  1704. numNames,
  1705. pLsaStrings,
  1706. &RefDomains,
  1707. &TranslatedSids);
  1708. //
  1709. // Free the LSA handle
  1710. //
  1711. LsaClose(LsaPolicy);
  1712. //
  1713. // Check for any unknown names
  1714. //
  1715. if( ntErr != STATUS_SUCCESS )
  1716. {
  1717. adlError = AdlStatement::ERROR_LSA_FAILED;
  1718. if( ntErr == STATUS_SOME_NOT_MAPPED || ntErr == STATUS_NONE_MAPPED )
  1719. {
  1720. adlError = AdlStatement::ERROR_UNKNOWN_USER;
  1721. //
  1722. // Find first unknown name and return it to user
  1723. //
  1724. for( dwIdx = 0; dwIdx < numNames; dwIdx++ )
  1725. {
  1726. if( TranslatedSids[dwIdx].Use == SidTypeInvalid ||
  1727. TranslatedSids[dwIdx].Use == SidTypeUnknown )
  1728. {
  1729. SetErrorToken(mapIdxToken[dwIdx]);
  1730. adlError = AdlStatement::ERROR_UNKNOWN_USER;
  1731. }
  1732. }
  1733. }
  1734. goto error;
  1735. }
  1736. //
  1737. // Assume all names now mapped if this point is reached
  1738. // Traverse all tokens again, pairing them with SIDs
  1739. //
  1740. for(iterTokens = listAllPrincipals.begin(),
  1741. dwIdx = 0,
  1742. iterTokensEnd = listAllPrincipals.end();
  1743. iterTokens != iterTokensEnd;
  1744. iterTokens ++, dwIdx++)
  1745. {
  1746. //
  1747. // Make sure all domains were looked up successfuly
  1748. // Invalid SIDs caught earlier
  1749. //
  1750. assert(TranslatedSids[dwIdx].DomainIndex >= 0);
  1751. dwDomainSidSize = GetLengthSid(
  1752. RefDomains->Domains[TranslatedSids[dwIdx].DomainIndex].Sid);
  1753. //
  1754. // One more RID for the user
  1755. //
  1756. pSidTemp = new BYTE[dwDomainSidSize + sizeof(DWORD)];
  1757. if( pSidTemp == NULL )
  1758. {
  1759. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1760. goto error;
  1761. }
  1762. //
  1763. // Copy the domain SID
  1764. //
  1765. CopySid(dwDomainSidSize + sizeof(DWORD), pSidTemp,
  1766. RefDomains->Domains[TranslatedSids[dwIdx].DomainIndex].Sid);
  1767. //
  1768. // If the SID is not a domain SID, and is valid, then we need to add
  1769. // the last RID. If domain SID, then referenced domain is the only
  1770. // SID we need, and we already have copied it
  1771. //
  1772. if( TranslatedSids[dwIdx].Use != SidTypeDomain )
  1773. {
  1774. ((SID *)pSidTemp)->SubAuthority[
  1775. ((SID *)pSidTemp)->SubAuthorityCount
  1776. ] = TranslatedSids[dwIdx].RelativeId;
  1777. //
  1778. // Add 1 more subauthority
  1779. //
  1780. ((SID *)pSidTemp)->SubAuthorityCount++;
  1781. }
  1782. //
  1783. // If this fails, need to allocate the single uninserted SID
  1784. // Other SIDs will be deallocated externally
  1785. //
  1786. pLastAllocated = pSidTemp;
  1787. (*mapTokSid)[(*iterTokens)] = pSidTemp;
  1788. pLastAllocated = NULL;
  1789. }
  1790. }
  1791. //
  1792. // Catch STL exceptions here, if exception is thrown, either the above
  1793. // code is wrong, or out of memory. Assume out of memory.
  1794. //
  1795. catch(exception ex)
  1796. {
  1797. adlError = AdlStatement::ERROR_OUT_OF_MEMORY;
  1798. }
  1799. error:;
  1800. //
  1801. // Garbage collection
  1802. //
  1803. if( RefDomains != NULL)
  1804. {
  1805. LsaFreeMemory(RefDomains);
  1806. }
  1807. if( TranslatedSids != NULL)
  1808. {
  1809. LsaFreeMemory(TranslatedSids);
  1810. }
  1811. //
  1812. // If the grabage stack threw an exception, deallocate last allocated object
  1813. //
  1814. if( pLastAllocated != NULL )
  1815. {
  1816. delete[] (PBYTE)pLastAllocated;
  1817. }
  1818. while( ! stackToFree.empty() )
  1819. {
  1820. //
  1821. // If popping a stack causes an STL exception, we have bigger problems
  1822. // than memory leaks
  1823. //
  1824. delete[] stackToFree.top();
  1825. stackToFree.pop();
  1826. }
  1827. //
  1828. // If any other error code happened earlier, pass it on
  1829. //
  1830. if( adlError != AdlStatement::ERROR_NO_ERROR )
  1831. {
  1832. while( !(*mapTokSid).empty() )
  1833. {
  1834. delete[] (PBYTE) (*((*mapTokSid).begin())).second;
  1835. (*mapTokSid).erase( (*mapTokSid).begin() );
  1836. }
  1837. throw adlError;
  1838. }
  1839. }