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.

892 lines
22 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. adlstat.cpp
  5. Abstract:
  6. Implementation of AdlStatement and AdlTree class methods
  7. Author:
  8. t-eugenz - August 2000
  9. Environment:
  10. User mode only.
  11. Revision History:
  12. Created - August 2000
  13. --*/
  14. #include "adl.h"
  15. #include <set>
  16. void AdlStatement::ReadFromDacl(IN const PACL pDacl)
  17. /*++
  18. Routine Description:
  19. Empties anything in the current ADL statement, and attempts to fill it with
  20. the ADL representation of the given DACL.
  21. Arguments:
  22. pDacl - The DACL from which to construct the statement
  23. Return Value:
  24. none
  25. --*/
  26. {
  27. //
  28. // Start with cleanup
  29. //
  30. Cleanup();
  31. try
  32. {
  33. ConvertFromDacl(pDacl);
  34. }
  35. catch(exception)
  36. {
  37. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  38. }
  39. _bReady = TRUE;
  40. }
  41. void AdlStatement::ReadFromString(IN const WCHAR *szInput)
  42. /*++
  43. Routine Description:
  44. Empties anything in the current ADL statement, and attempts to fill it with
  45. the parsed version of the ADL statement szInput.
  46. Arguments:
  47. szInput - Input string in the ADL language describing the
  48. permissions
  49. Return Value:
  50. none
  51. --*/
  52. {
  53. //
  54. // Start with cleanup
  55. //
  56. Cleanup();
  57. //
  58. // Manually create first AdlTree, since the parser only creates
  59. // new trees AFTER completing an ADL_STATEMENT. At the end, the
  60. // ParseAdl function itself removes the extra empty tree
  61. // pushed on
  62. //
  63. this->Next();
  64. try
  65. {
  66. ParseAdl(szInput);
  67. }
  68. catch(exception)
  69. {
  70. Cleanup();
  71. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  72. }
  73. //
  74. // If no exceptions thrown, the instance is ready for output
  75. //
  76. _bReady = TRUE;
  77. }
  78. AdlStatement::~AdlStatement()
  79. /*++
  80. Routine Description:
  81. Destructor for the AdlStatement
  82. Uses the private Cleanup() function to deallocate
  83. Arguments:
  84. none
  85. Return Value:
  86. none
  87. --*/
  88. {
  89. this->Cleanup();
  90. }
  91. void AdlStatement::Cleanup()
  92. /*++
  93. Routine Description:
  94. Cleans up any memory used by the parse tree and any allocated tokens
  95. Arguments:
  96. none
  97. Return Value:
  98. none
  99. --*/
  100. {
  101. _bReady = FALSE;
  102. this->_tokError = NULL;
  103. while( !_lTree.empty() )
  104. {
  105. delete _lTree.front();
  106. _lTree.pop_front();
  107. }
  108. while( !_AllocatedTokens.empty() )
  109. {
  110. delete _AllocatedTokens.top();
  111. _AllocatedTokens.pop();
  112. }
  113. }
  114. AdlTree * AdlStatement::Cur()
  115. /*++
  116. Routine Description:
  117. This protected method returns the current AdlTree being filled in by the
  118. parser. It is only used by the ParseAdl function when it fills in the
  119. AdlTree structures
  120. Arguments:
  121. none
  122. Return Value:
  123. AdlTree * - non-const pointer to the AdlTree
  124. --*/
  125. {
  126. return *_iter;
  127. }
  128. void AdlStatement::Next()
  129. /*++
  130. Routine Description:
  131. This protected method constructs a new AdlTree and pushes it on top of the
  132. list (to make it accessable by this->Cur())
  133. It is only used by the ParseAdl function after completing an ADL_STATEMENT
  134. production, and by the AdlStatement constructor (once).
  135. Arguments:
  136. none
  137. Return Value:
  138. none
  139. --*/
  140. {
  141. AdlTree *pAdlTree = new AdlTree();
  142. if( pAdlTree == NULL )
  143. {
  144. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  145. }
  146. try
  147. {
  148. _lTree.push_back(pAdlTree);
  149. _iter = --_lTree.end();
  150. }
  151. catch(...)
  152. {
  153. delete pAdlTree;
  154. throw;
  155. }
  156. }
  157. void AdlStatement::PopEmpty()
  158. /*++
  159. Routine Description:
  160. This protected method pops the extra empty AdlTree added by the ParseAdl
  161. function after completing the last ADL_STATEMENT.
  162. Arguments:
  163. none
  164. Return Value:
  165. none
  166. --*/
  167. {
  168. delete _lTree.back();
  169. _lTree.pop_back();
  170. _iter = -- _lTree.end();
  171. }
  172. void AdlStatement::AddToken(AdlToken *tok)
  173. /*++
  174. Routine Description:
  175. This protected method is used by AdlStatement and friend classes to keep
  176. track of tokens which need to be garbage collected later. Tokens need
  177. to be kept around because they are used in the AdlTrees, and in error
  178. handling.
  179. Arguments:
  180. tok - Pointer to the token to be deleted when ~this is called
  181. Return Value:
  182. none
  183. --*/
  184. {
  185. _AllocatedTokens.push(tok);
  186. }
  187. void AdlStatement::WriteToString(OUT wstring *pSz)
  188. /*++
  189. Routine Description:
  190. This routine prints the AdlStatement structure as a statement in the ADL
  191. language to stdout. This will be replaced when the ADL semantics are
  192. finalized.
  193. Arguments:
  194. none
  195. Return Value:
  196. none
  197. --*/
  198. {
  199. if( _bReady == FALSE )
  200. {
  201. throw AdlStatement::ERROR_NOT_INITIALIZED;
  202. }
  203. list<AdlTree *>::iterator iter, iterEnd;
  204. for(iter = _lTree.begin(), iterEnd = _lTree.end();
  205. iter != iterEnd;
  206. iter++)
  207. {
  208. (*iter)->PrintAdl(pSz, _pControl);
  209. pSz->append(&(_pControl->pLang->CH_NEWLINE), 1);
  210. }
  211. }
  212. void AdlStatement::ValidateParserControl()
  213. /*++
  214. Routine Description:
  215. This validates the ADL_PARSER_CONTROL structure referenced by this
  216. AdlStatement instance
  217. Arguments:
  218. none
  219. Return Value:
  220. none
  221. --*/
  222. {
  223. try
  224. {
  225. //
  226. // Test to verify that all characters are unique
  227. // set.insert returns a pair, with 2nd element being a bool, which
  228. // is true iff an insertion occured. Set cannot have duplicates.
  229. //
  230. set<WCHAR> sChars;
  231. if(
  232. !sChars.insert(_pControl->pLang->CH_NULL).second ||
  233. !sChars.insert(_pControl->pLang->CH_SPACE).second ||
  234. !sChars.insert(_pControl->pLang->CH_TAB).second ||
  235. !sChars.insert(_pControl->pLang->CH_NEWLINE).second ||
  236. !sChars.insert(_pControl->pLang->CH_RETURN).second ||
  237. !sChars.insert(_pControl->pLang->CH_QUOTE).second ||
  238. !sChars.insert(_pControl->pLang->CH_COMMA).second ||
  239. !sChars.insert(_pControl->pLang->CH_SEMICOLON).second ||
  240. !sChars.insert(_pControl->pLang->CH_OPENPAREN).second ||
  241. !sChars.insert(_pControl->pLang->CH_CLOSEPAREN).second ||
  242. !sChars.insert(_pControl->pLang->CH_AT).second ||
  243. !sChars.insert(_pControl->pLang->CH_SLASH).second ||
  244. !sChars.insert(_pControl->pLang->CH_PERIOD).second
  245. )
  246. {
  247. throw AdlStatement::ERROR_INVALID_PARSER_CONTROL;
  248. }
  249. //
  250. // Check all strings for null pointers
  251. //
  252. if(
  253. _pControl->pLang->SZ_TK_AND == NULL ||
  254. _pControl->pLang->SZ_TK_EXCEPT == NULL ||
  255. _pControl->pLang->SZ_TK_ON == NULL ||
  256. _pControl->pLang->SZ_TK_ALLOWED == NULL ||
  257. _pControl->pLang->SZ_TK_AS == NULL ||
  258. _pControl->pLang->SZ_TK_THIS_OBJECT == NULL ||
  259. _pControl->pLang->SZ_TK_CONTAINERS == NULL ||
  260. _pControl->pLang->SZ_TK_OBJECTS == NULL ||
  261. _pControl->pLang->SZ_TK_CONTAINERS_OBJECTS == NULL ||
  262. _pControl->pLang->SZ_TK_NO_PROPAGATE == NULL
  263. )
  264. {
  265. throw AdlStatement::ERROR_INVALID_PARSER_CONTROL;
  266. }
  267. }
  268. catch(exception)
  269. {
  270. throw AdlStatement::ERROR_OUT_OF_MEMORY;
  271. }
  272. }
  273. /******************************************************************************
  274. AdlTree Methods
  275. *****************************************************************************/
  276. //
  277. // An array of these is used to determine the order in which to print
  278. //
  279. #define PRINT_PRINCIPALS 0
  280. #define PRINT_EXPRINCIPALS 1
  281. #define PRINT_ALLOWED 2
  282. #define PRINT_ACCESS 3
  283. #define PRINT_ON 4
  284. #define PRINT_OBJECTS 5
  285. #define PRINT_DEF_SIZE 6
  286. DWORD pdwLangEnglish[6] =
  287. {
  288. PRINT_PRINCIPALS,
  289. PRINT_EXPRINCIPALS,
  290. PRINT_ALLOWED,
  291. PRINT_ACCESS,
  292. PRINT_ON,
  293. PRINT_OBJECTS
  294. };
  295. DWORD pdwLangReverse[6] =
  296. {
  297. PRINT_EXPRINCIPALS,
  298. PRINT_PRINCIPALS,
  299. PRINT_ALLOWED,
  300. PRINT_ACCESS,
  301. PRINT_ON,
  302. PRINT_OBJECTS
  303. };
  304. //
  305. // Append a wchar array to the STL string POUTSTLSTRING, add quotes
  306. // if the input string contains any characters in the wchar
  307. // array SPECIALCHARS
  308. //
  309. #define APPEND_QUOTED_STRING(POUTSTLSTRING, INSTRING, SPECIALCHARS, QUOTECHAR) \
  310. if( wcspbrk( (INSTRING), (SPECIALCHARS) ) ) { \
  311. (POUTSTLSTRING)->append(&(QUOTECHAR), 1); \
  312. (POUTSTLSTRING)->append(INSTRING); \
  313. (POUTSTLSTRING)->append(&(QUOTECHAR), 1); \
  314. } else { \
  315. (POUTSTLSTRING)->append(INSTRING); \
  316. }
  317. void AdlTree::PrintAdl(wstring *pSz, PADL_PARSER_CONTROL pControl)
  318. /*++
  319. Routine Description:
  320. This routine prints the AdlTree structure using one of the pre-defined
  321. language specifications, selected by checking the ADL_PARSER_CONTROL
  322. structure. To add new languages, simply add a new 6 int array as above,
  323. and add it into the switch statement below so it will be recognized.
  324. Arguments:
  325. pSz - An existing wstring to which the ADL statement output will
  326. be appended
  327. pControl - Pointer to the ADL_PARSER_CONTROL structure to define the
  328. printing
  329. Return Value:
  330. none
  331. --*/
  332. {
  333. //
  334. // Iterators for token lists in the AdlTree
  335. //
  336. list<const AdlToken *>::iterator iter;
  337. list<const AdlToken *>::iterator iter_end;
  338. list<const AdlToken *>::iterator iter_tmp;
  339. //
  340. // If a string contains these characters, use quotes
  341. //
  342. WCHAR szSpecialChars[] =
  343. {
  344. pControl->pLang->CH_SPACE,
  345. pControl->pLang->CH_NEWLINE,
  346. pControl->pLang->CH_TAB,
  347. pControl->pLang->CH_RETURN,
  348. pControl->pLang->CH_COMMA,
  349. pControl->pLang->CH_OPENPAREN,
  350. pControl->pLang->CH_CLOSEPAREN,
  351. pControl->pLang->CH_SEMICOLON,
  352. pControl->pLang->CH_AT,
  353. pControl->pLang->CH_SLASH,
  354. pControl->pLang->CH_PERIOD,
  355. pControl->pLang->CH_QUOTE,
  356. 0
  357. };
  358. DWORD dwIdx;
  359. DWORD dwTmp;
  360. PDWORD pdwPrintSpec;
  361. //
  362. // Determine which type of grammar to use.
  363. //
  364. switch( pControl->pLang->dwLanguageType )
  365. {
  366. case TK_LANG_ENGLISH:
  367. pdwPrintSpec = pdwLangEnglish;
  368. break;
  369. case TK_LANG_REVERSE:
  370. pdwPrintSpec = pdwLangReverse;
  371. break;
  372. default:
  373. throw AdlStatement::ERROR_INVALID_PARSER_CONTROL;
  374. break;
  375. }
  376. //
  377. // Using that grammar, print the appropriate parts of each
  378. // ADL_STATEMENT production
  379. //
  380. for( dwIdx = 0; dwIdx < PRINT_DEF_SIZE; dwIdx++ )
  381. {
  382. switch(pdwPrintSpec[dwIdx])
  383. {
  384. case PRINT_PRINCIPALS:
  385. for( iter = _lpTokPrincipals.begin(),
  386. iter_end = _lpTokPrincipals.end();
  387. iter != iter_end;
  388. iter++)
  389. {
  390. APPEND_QUOTED_STRING(pSz,
  391. (*iter)->GetValue(),
  392. szSpecialChars,
  393. pControl->pLang->CH_QUOTE);
  394. //
  395. // ISSUE-2000/8/31
  396. // Need to find a way to determine this instead of string comp
  397. //
  398. if( (*iter)->GetOptValue() != NULL &&
  399. _wcsicmp(L"BUILTIN", (*iter)->GetOptValue()))
  400. {
  401. pSz->append(&(pControl->pLang->CH_AT), 1);
  402. APPEND_QUOTED_STRING(pSz,
  403. (*iter)->GetOptValue(),
  404. szSpecialChars,
  405. pControl->pLang->CH_QUOTE);
  406. }
  407. //
  408. // Separate with commas except the last one, there use "and"
  409. //
  410. iter_tmp = iter;
  411. if( ++iter_tmp == iter_end )
  412. {
  413. //
  414. // Do nothing for the last principal
  415. //
  416. }
  417. else if( ++iter_tmp == iter_end )
  418. {
  419. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  420. pSz->append(pControl->pLang->SZ_TK_AND);
  421. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  422. }
  423. else
  424. {
  425. pSz->append(&(pControl->pLang->CH_COMMA), 1);
  426. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  427. }
  428. }
  429. //
  430. // And a trailing space
  431. //
  432. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  433. break;
  434. case PRINT_EXPRINCIPALS:
  435. if( ! _lpTokExPrincipals.empty())
  436. {
  437. pSz->append(&(pControl->pLang->CH_OPENPAREN), 1);
  438. pSz->append(pControl->pLang->SZ_TK_EXCEPT);
  439. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  440. for( iter = _lpTokExPrincipals.begin(),
  441. iter_end = _lpTokExPrincipals.end();
  442. iter != iter_end;
  443. iter++)
  444. {
  445. APPEND_QUOTED_STRING(pSz,
  446. (*iter)->GetValue(),
  447. szSpecialChars,
  448. pControl->pLang->CH_QUOTE);
  449. //
  450. // ISSUE-2000/8/31
  451. // Need to find a way to determine this instead of string comp
  452. //
  453. if( (*iter)->GetOptValue() != NULL &&
  454. _wcsicmp(L"BUILTIN", (*iter)->GetOptValue()))
  455. {
  456. pSz->append(&(pControl->pLang->CH_AT), 1);
  457. APPEND_QUOTED_STRING(pSz,
  458. (*iter)->GetOptValue(),
  459. szSpecialChars,
  460. pControl->pLang->CH_QUOTE);
  461. }
  462. //
  463. // Separate with commas except the last one, there use "and"
  464. //
  465. iter_tmp = iter;
  466. if( ++iter_tmp == iter_end )
  467. {
  468. //
  469. // Do nothing for the last principal
  470. //
  471. }
  472. else if( ++iter_tmp == iter_end )
  473. {
  474. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  475. pSz->append(pControl->pLang->SZ_TK_AND);
  476. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  477. }
  478. else
  479. {
  480. pSz->append(&(pControl->pLang->CH_COMMA), 1);
  481. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  482. }
  483. }
  484. pSz->append(&(pControl->pLang->CH_CLOSEPAREN), 1);
  485. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  486. }
  487. break;
  488. case PRINT_ALLOWED:
  489. pSz->append(pControl->pLang->SZ_TK_ALLOWED);
  490. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  491. break;
  492. case PRINT_ACCESS:
  493. for( iter = _lpTokPermissions.begin(),
  494. iter_end = _lpTokPermissions.end();
  495. iter != iter_end;
  496. iter++)
  497. {
  498. APPEND_QUOTED_STRING(pSz,
  499. (*iter)->GetValue(),
  500. szSpecialChars,
  501. pControl->pLang->CH_QUOTE);
  502. //
  503. // Separate with commas except the last one, there use "and"
  504. //
  505. iter_tmp = iter;
  506. if( ++iter_tmp == iter_end )
  507. {
  508. //
  509. // Do nothing for the last permission
  510. //
  511. }
  512. else if( ++iter_tmp == iter_end )
  513. {
  514. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  515. pSz->append(pControl->pLang->SZ_TK_AND);
  516. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  517. }
  518. else
  519. {
  520. pSz->append(&(pControl->pLang->CH_COMMA), 1);
  521. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  522. }
  523. }
  524. //
  525. // And a trailing space
  526. //
  527. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  528. break;
  529. case PRINT_ON:
  530. pSz->append(pControl->pLang->SZ_TK_ON);
  531. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  532. break;
  533. case PRINT_OBJECTS:
  534. //
  535. // Make sure all bits are defined
  536. //
  537. if( _dwInheritFlags & ~(CONTAINER_INHERIT_ACE |
  538. INHERIT_ONLY_ACE |
  539. NO_PROPAGATE_INHERIT_ACE |
  540. OBJECT_INHERIT_ACE) )
  541. {
  542. throw AdlStatement::ERROR_INVALID_OBJECT;
  543. }
  544. //
  545. // Count the number of object statements, for proper punctuation
  546. //
  547. dwTmp = 0;
  548. if( ! ( _dwInheritFlags & INHERIT_ONLY_ACE) )
  549. {
  550. dwTmp++;
  551. }
  552. if(_dwInheritFlags & ( CONTAINER_INHERIT_ACE || OBJECT_INHERIT_ACE))
  553. {
  554. dwTmp++;
  555. }
  556. if(_dwInheritFlags & NO_PROPAGATE_INHERIT_ACE)
  557. {
  558. dwTmp++;
  559. }
  560. //
  561. // First "this object"
  562. //
  563. if( ! ( _dwInheritFlags & INHERIT_ONLY_ACE) )
  564. {
  565. APPEND_QUOTED_STRING(pSz,
  566. pControl->pLang->SZ_TK_THIS_OBJECT,
  567. szSpecialChars,
  568. pControl->pLang->CH_QUOTE);
  569. //
  570. // Print "and" if 1 more left, "," if two
  571. //
  572. dwTmp--;
  573. if( dwTmp == 2 )
  574. {
  575. pSz->append(&(pControl->pLang->CH_COMMA), 1);
  576. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  577. }
  578. else if( dwTmp == 1)
  579. {
  580. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  581. pSz->append(pControl->pLang->SZ_TK_AND);
  582. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  583. }
  584. }
  585. //
  586. // Then container/object inheritance
  587. //
  588. if( _dwInheritFlags & ( CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))
  589. {
  590. if( (_dwInheritFlags & OBJECT_INHERIT_ACE)
  591. && (_dwInheritFlags & CONTAINER_INHERIT_ACE) )
  592. {
  593. APPEND_QUOTED_STRING(pSz,
  594. pControl->pLang->SZ_TK_CONTAINERS_OBJECTS,
  595. szSpecialChars,
  596. pControl->pLang->CH_QUOTE);
  597. }
  598. else if( _dwInheritFlags & CONTAINER_INHERIT_ACE )
  599. {
  600. APPEND_QUOTED_STRING(pSz,
  601. pControl->pLang->SZ_TK_CONTAINERS,
  602. szSpecialChars,
  603. pControl->pLang->CH_QUOTE);
  604. }
  605. else
  606. {
  607. APPEND_QUOTED_STRING(pSz,
  608. pControl->pLang->SZ_TK_OBJECTS,
  609. szSpecialChars,
  610. pControl->pLang->CH_QUOTE);
  611. }
  612. dwTmp--;
  613. //
  614. // Print "and" if 1 more left
  615. // nothing if 0
  616. //
  617. if( dwTmp == 1)
  618. {
  619. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  620. pSz->append(pControl->pLang->SZ_TK_AND);
  621. pSz->append(&(pControl->pLang->CH_SPACE), 1);
  622. }
  623. }
  624. //
  625. // Now no-propagate
  626. //
  627. if(_dwInheritFlags & NO_PROPAGATE_INHERIT_ACE)
  628. {
  629. APPEND_QUOTED_STRING(pSz,
  630. pControl->pLang->SZ_TK_NO_PROPAGATE,
  631. szSpecialChars,
  632. pControl->pLang->CH_QUOTE);
  633. }
  634. break;
  635. default:
  636. //
  637. // Should not get here unless language defs are wrong
  638. //
  639. throw AdlStatement::ERROR_FATAL_PARSER_ERROR;
  640. break;
  641. }
  642. }
  643. //
  644. // And terminate the statement with a semicolon, invariable per grammar
  645. //
  646. pSz->append(&(pControl->pLang->CH_SEMICOLON), 1);
  647. }