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.

1477 lines
46 KiB

  1. /*****************************************************************************\
  2. Author: Hiteshr
  3. Copyright (c) 1998-2002 Microsoft Corporation
  4. Change History:
  5. Adapted From Parser Implemenation of Corey Morgan
  6. \*****************************************************************************/
  7. #include "pch.h"
  8. #pragma hdrstop
  9. #include <netdom.h>
  10. BOOL ValidateCommands(IN ARG_RECORD *Commands,OUT PPARSE_ERROR pError);
  11. //General Utility Functions
  12. DWORD ResizeByTwo(PTSTR *ppBuffer, size_t *pSize);
  13. BOOL StringCopy(PWSTR *ppDest, PCWSTR pSrc);
  14. #define INIT_SIZE 1024
  15. #define FILL_ERROR(pError,source,error_code,rec_index,argv_index) \
  16. pError->ErrorSource = source; \
  17. pError->Error = error_code; \
  18. pError->ArgRecIndex = rec_index; \
  19. pError->ArgvIndex = argv_index;
  20. BOOL IsCmd( PARG_RECORD arg, LPTOKEN pToken)
  21. {
  22. if (!arg || !pToken)
  23. return FALSE;
  24. LPWSTR str = pToken->GetToken();
  25. if (!str)
  26. return FALSE;
  27. if (pToken->IsSwitch())
  28. {
  29. if (arg->fFlag & ARG_FLAG_VERB)
  30. {
  31. // Verbs do not have a switch.
  32. //
  33. return FALSE;
  34. }
  35. str++;
  36. }
  37. else
  38. {
  39. if ((arg->fFlag & ARG_FLAG_OBJECT) && !arg->bDefined)
  40. {
  41. return TRUE;
  42. }
  43. if (!(arg->fFlag & ARG_FLAG_VERB))
  44. {
  45. // Non-verbs must have a switch except for the object arg.
  46. //
  47. return FALSE;
  48. }
  49. }
  50. // NOTICE-2002/02/26-ericb - SecurityPush: all strings internally generated
  51. // and previously checked for termination.
  52. if ( ( arg->strArg1 && !_wcsicmp( str, arg->strArg1 ) )
  53. ||(arg->strArg2 && !_wcsicmp( str, arg->strArg2 )) )
  54. {
  55. return TRUE;
  56. }
  57. return FALSE;
  58. }
  59. void FreeCmd(ARG_RECORD *Commands)
  60. {
  61. int i;
  62. for(i=0;Commands[i].fType != ARG_TYPE_LAST;i++)
  63. {
  64. if ((Commands[i].fType == ARG_TYPE_STR ||
  65. Commands[i].fType == ARG_TYPE_MSZ ) &&
  66. Commands[i].bDefined )
  67. {
  68. if ( Commands[i].strValue )
  69. {
  70. LocalFree( Commands[i].strValue );
  71. }
  72. Commands[i].strValue = NULL;
  73. }
  74. if ( Commands[i].idArg1 && Commands[i].strArg1 != NULL )
  75. {
  76. LocalFree(Commands[i].strArg1);
  77. }
  78. if ( Commands[i].idArg2 && Commands[i].strArg2 != NULL )
  79. {
  80. LocalFree( Commands[i].strArg2 );
  81. }
  82. Commands[i].bDefined = FALSE;
  83. }
  84. }
  85. BOOL LoadCmd(ARG_RECORD *Commands)
  86. {
  87. int i;
  88. BOOL bRet = TRUE;
  89. for (i=0; Commands[i].fType!=ARG_TYPE_LAST; i++)
  90. {
  91. if (Commands[i].idArg1 !=0)
  92. if (!LoadStringAlloc(&Commands[i].strArg1, NULL, Commands[i].idArg1))
  93. {
  94. bRet = FALSE;
  95. break;
  96. }
  97. if (Commands[i].idArg2 !=0 && Commands[i].idArg2 != ID_ARG2_NULL)
  98. if (!LoadStringAlloc(&Commands[i].strArg2, NULL, Commands[i].idArg2))
  99. {
  100. bRet = FALSE;
  101. break;
  102. }
  103. }
  104. return bRet;
  105. }
  106. BOOL
  107. ValidateCommands(ARG_RECORD *Commands, PPARSE_ERROR pError)
  108. {
  109. int i = 0;
  110. LONG cReadFromStdin = 0;
  111. ARG_RECORD *CommandsIn = NULL;
  112. LPWSTR pBuffer=NULL;
  113. LONG BufferLen = 0;
  114. LPTOKEN pToken = NULL;
  115. int argc=0;
  116. BOOL bRet = FALSE;
  117. bool bAtLeastOne = false;
  118. bool bAtLeastOneDefined = false;
  119. if (!Commands || !pError)
  120. goto exit_gracefully;
  121. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  122. {
  123. if ( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  124. {
  125. if (Commands[i].fFlag & ARG_FLAG_STDIN)
  126. {
  127. cReadFromStdin++;
  128. }
  129. else
  130. {
  131. FILL_ERROR(pError,
  132. ERROR_FROM_PARSER,
  133. PARSE_ERROR_SWITCH_NOTDEFINED,
  134. i,
  135. -1);
  136. goto exit_gracefully;
  137. }
  138. }
  139. if (Commands[i].fFlag & ARG_FLAG_ATLEASTONE)
  140. {
  141. bAtLeastOne = true;
  142. if (Commands[i].bDefined)
  143. {
  144. bAtLeastOneDefined = true;
  145. }
  146. }
  147. }
  148. if (bAtLeastOne && !bAtLeastOneDefined)
  149. {
  150. FILL_ERROR(pError, ERROR_FROM_PARSER,
  151. PARSE_ERROR_ATLEASTONE_NOTDEFINED, -1, -1)
  152. goto exit_gracefully;
  153. }
  154. if (!cReadFromStdin)
  155. {
  156. bRet = TRUE;
  157. goto exit_gracefully;
  158. }
  159. //Read From STDIN
  160. BufferLen = ReadFromIn(&pBuffer);
  161. if (BufferLen == -1)
  162. {
  163. FILL_ERROR(pError,
  164. ERROR_WIN32_ERROR,
  165. GetLastError(),
  166. -1,
  167. -1);
  168. goto exit_gracefully;
  169. }
  170. if (BufferLen == 0)
  171. {
  172. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  173. {
  174. if ( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  175. {
  176. FILL_ERROR(pError,
  177. ERROR_FROM_PARSER,
  178. PARSE_ERROR_SWITCH_NOTDEFINED,
  179. i,
  180. -1);
  181. goto exit_gracefully;
  182. }
  183. }
  184. }
  185. if (BufferLen)
  186. {
  187. //Tokenize what you have read from STDIN
  188. DWORD dwErr;
  189. WCHAR szDelimiters[] = L": \n\t";
  190. dwErr = Tokenize(pBuffer,
  191. BufferLen,
  192. szDelimiters,
  193. &pToken,
  194. &argc);
  195. if ( dwErr != ERROR_SUCCESS )
  196. {
  197. FILL_ERROR(pError,
  198. ERROR_WIN32_ERROR,
  199. dwErr,
  200. -1,
  201. -1);
  202. goto exit_gracefully;
  203. }
  204. //Prepare a CommandArray for them
  205. CommandsIn = (ARG_RECORD*)LocalAlloc(LPTR,sizeof(ARG_RECORD)*(cReadFromStdin+1));
  206. if (!CommandsIn)
  207. {
  208. FILL_ERROR(pError,
  209. ERROR_WIN32_ERROR,
  210. ERROR_NOT_ENOUGH_MEMORY,
  211. -1,
  212. -1);
  213. goto exit_gracefully;
  214. }
  215. int j;
  216. j = 0;
  217. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  218. {
  219. if ((Commands[i].fFlag & ARG_FLAG_REQUIRED) &&
  220. (Commands[i].fFlag & ARG_FLAG_STDIN) &&
  221. !Commands[i].bDefined)
  222. {
  223. CommandsIn[j++] = Commands[i];
  224. }
  225. }
  226. //Copy the Last One
  227. CommandsIn[j] = Commands[i];
  228. if (!ParseCmd(CommandsIn,
  229. argc,
  230. pToken,
  231. false,
  232. pError,
  233. FALSE))
  234. {
  235. goto exit_gracefully;
  236. }
  237. //Copy the values back to Commands
  238. j=0;
  239. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  240. {
  241. if ((Commands[i].fFlag & ARG_FLAG_REQUIRED) &&
  242. (Commands[i].fFlag & ARG_FLAG_STDIN) &&
  243. !Commands[i].bDefined)
  244. {
  245. Commands[i] = CommandsIn[j++];
  246. }
  247. }
  248. //Validate Commands
  249. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  250. {
  251. if ( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  252. {
  253. FILL_ERROR(pError,
  254. ERROR_FROM_PARSER,
  255. PARSE_ERROR_SWITCH_NOTDEFINED,
  256. i,
  257. -1);
  258. goto exit_gracefully;
  259. }
  260. }
  261. }
  262. bRet = TRUE;
  263. exit_gracefully:
  264. if (CommandsIn)
  265. LocalFree(CommandsIn);
  266. if (pBuffer)
  267. LocalFree(pBuffer);
  268. if (pToken)
  269. {
  270. delete []pToken;
  271. }
  272. return bRet;
  273. }
  274. BOOL ParseCmd(IN ARG_RECORD *Commands,
  275. IN int argc,
  276. IN LPTOKEN pToken,
  277. IN bool fSkipObject,
  278. OUT PPARSE_ERROR pError,
  279. IN BOOL bValidate)
  280. {
  281. int i = 0;
  282. BOOL bFound = FALSE;
  283. int argCount = 0;
  284. DWORD dwErr = ERROR_SUCCESS;
  285. HRESULT hr = S_OK;
  286. if (!Commands || argc == 0 || !pToken || !pError)
  287. return FALSE;
  288. argCount = argc;
  289. while (argc > 0)
  290. {
  291. bFound = FALSE;
  292. for (i = 0; Commands[i].fType != ARG_TYPE_LAST && (!bFound); i++)
  293. {
  294. if (fSkipObject && Commands[i].fFlag & ARG_FLAG_OBJECT)
  295. {
  296. continue;
  297. }
  298. if (IsCmd(&Commands[i], pToken))
  299. {
  300. if (Commands[i].bDefined)
  301. {
  302. FILL_ERROR(pError,
  303. ERROR_FROM_PARSER,
  304. PARSE_ERROR_MULTIPLE_DEF,
  305. i,
  306. -1);
  307. return FALSE;
  308. }
  309. if (pToken->IsSwitch())
  310. {
  311. pToken++;
  312. argc--;
  313. }
  314. bFound = TRUE;
  315. Commands[i].bDefined = TRUE;
  316. switch( Commands[i].fType )
  317. {
  318. case ARG_TYPE_HELP:
  319. Commands[i].bValue = TRUE;
  320. if ( Commands[i].fntValidation != NULL )
  321. {
  322. Commands[i].fntValidation( Commands + i );
  323. }
  324. if ( Commands[i].idArg1 == MSG_TAG_EXPERTHELP )
  325. {
  326. FILL_ERROR(pError,
  327. ERROR_FROM_PARSER,
  328. PARSE_ERROR_EXPERT_HELP_SWITCH,
  329. i,
  330. -1);
  331. }
  332. else
  333. {
  334. FILL_ERROR(pError,
  335. ERROR_FROM_PARSER,
  336. PARSE_ERROR_HELP_SWITCH,
  337. i,
  338. -1);
  339. }
  340. return FALSE;
  341. break;
  342. case ARG_TYPE_INT:
  343. if ( argc > 0 && !pToken->IsSwitch())
  344. {
  345. PCWSTR pszToken = pToken->GetToken();
  346. if (!pszToken)
  347. {
  348. FILL_ERROR(pError,
  349. ERROR_FROM_PARSER,
  350. PARSE_ERROR_SWITCH_VALUE,
  351. i,
  352. argCount - argc);
  353. return FALSE;
  354. }
  355. Commands[i].nValue = _wtoi( pszToken);
  356. if (Commands[i].nValue == 0 &&
  357. !iswdigit(pszToken[0]))
  358. {
  359. FILL_ERROR(pError,
  360. ERROR_FROM_PARSER,
  361. PARSE_ERROR_SWITCH_VALUE,
  362. i,
  363. argCount - argc);
  364. return FALSE;
  365. }
  366. pToken++;
  367. argc--;
  368. }
  369. else if ( !(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE) )
  370. {
  371. FILL_ERROR(pError,
  372. ERROR_FROM_PARSER,
  373. PARSE_ERROR_SWITCH_VALUE,
  374. i,
  375. argCount - argc);
  376. return FALSE;
  377. }
  378. break;
  379. case ARG_TYPE_VERB:
  380. //
  381. // Verbs are not proceeded by a switch character.
  382. //
  383. pToken++;
  384. argc--;
  385. // fall through.
  386. case ARG_TYPE_BOOL:
  387. //
  388. // Bools are proceeded by a switch char (and had the token
  389. // pointer advanced above).
  390. //
  391. Commands[i].bValue = TRUE;
  392. break;
  393. case ARG_TYPE_MSZ:
  394. if (argc > 0 && !pToken->IsSwitch())
  395. {
  396. PWSTR buffer = (PWSTR)LocalAlloc(LPTR, MAXSTR*sizeof(WCHAR));
  397. size_t maxSize = MAXSTR;
  398. size_t currentSize = 0;
  399. size_t len = 0;
  400. if (!buffer)
  401. {
  402. FILL_ERROR(pError,
  403. ERROR_WIN32_ERROR,
  404. ERROR_NOT_ENOUGH_MEMORY,
  405. -1,
  406. argCount - argc);
  407. return FALSE;
  408. }
  409. PCWSTR pszToken = pToken->GetToken();
  410. if (!pszToken)
  411. {
  412. ASSERT(FALSE);
  413. FILL_ERROR(pError,
  414. ERROR_FROM_PARSER,
  415. PARSE_ERROR_SWITCH_VALUE,
  416. i,
  417. argCount - argc);
  418. return FALSE;
  419. }
  420. hr = StringCchLength(pszToken, MAXSTR, &len);
  421. if (FAILED(hr))
  422. {
  423. ASSERT(FALSE);
  424. FILL_ERROR(pError,
  425. ERROR_WIN32_ERROR,
  426. HRESULT_CODE(hr),
  427. i,
  428. -1);
  429. return FALSE;
  430. }
  431. //-2 as last string is delimited by two null
  432. while (len > (maxSize - 2))
  433. {
  434. dwErr = ResizeByTwo(&buffer, &maxSize);
  435. if (dwErr != ERROR_SUCCESS)
  436. {
  437. FILL_ERROR(pError,
  438. ERROR_WIN32_ERROR,
  439. dwErr,
  440. i,
  441. -1);
  442. return FALSE;
  443. }
  444. }
  445. hr = StringCchCopy(buffer, maxSize, pszToken);
  446. if (FAILED(hr))
  447. {
  448. ASSERT(FALSE);
  449. FILL_ERROR(pError,
  450. ERROR_WIN32_ERROR,
  451. HRESULT_CODE(hr),
  452. i,
  453. -1);
  454. return FALSE;
  455. }
  456. currentSize += len;
  457. //Null Terminate, buffer is initialized to zero
  458. currentSize++;
  459. pToken++;
  460. argc--;
  461. while (argc > 0 && !pToken->IsSwitch())
  462. {
  463. pszToken = pToken->GetToken();
  464. if (!pszToken)
  465. {
  466. ASSERT(FALSE);
  467. FILL_ERROR(pError,
  468. ERROR_FROM_PARSER,
  469. PARSE_ERROR_SWITCH_VALUE,
  470. i,
  471. argCount - argc);
  472. return FALSE;
  473. }
  474. hr = StringCchLength(pszToken, MAXSTR, &len);
  475. if (FAILED(hr))
  476. {
  477. ASSERT(FALSE);
  478. FILL_ERROR(pError,
  479. ERROR_WIN32_ERROR,
  480. HRESULT_CODE(hr),
  481. i,
  482. -1);
  483. return FALSE;
  484. }
  485. while ((currentSize + len) > (maxSize - 2))
  486. {
  487. dwErr = ResizeByTwo(&buffer, &maxSize);
  488. if (dwErr != ERROR_SUCCESS)
  489. {
  490. FILL_ERROR(pError,
  491. ERROR_WIN32_ERROR,
  492. dwErr,
  493. i,
  494. -1);
  495. return FALSE;
  496. }
  497. }
  498. hr = StringCchCat((buffer + currentSize),
  499. maxSize - currentSize,
  500. pszToken);
  501. if (FAILED(hr))
  502. {
  503. ASSERT(FALSE);
  504. FILL_ERROR(pError,
  505. ERROR_WIN32_ERROR,
  506. HRESULT_CODE(hr),
  507. i,
  508. -1);
  509. return FALSE;
  510. }
  511. currentSize += len;
  512. //Null Terminate, buffer is initialized to zero
  513. currentSize++;
  514. pToken++;
  515. argc--;
  516. }
  517. Commands[i].strValue = buffer;
  518. }
  519. else if (Commands[i].fFlag & ARG_FLAG_DEFAULTABLE )
  520. {
  521. PWSTR strValue = Commands[i].strValue;
  522. // NOTICE-2002/02/26-ericb - SecurityPush: the command array
  523. // strings are all loaded from the resource fork.
  524. Commands[i].strValue = (PWSTR)LocalAlloc(LPTR, (wcslen(strValue)+1) * sizeof(WCHAR));
  525. if (Commands[i].strValue != NULL )
  526. {
  527. wcscpy(Commands[i].strValue, strValue);
  528. }
  529. else
  530. {
  531. FILL_ERROR(pError,
  532. ERROR_WIN32_ERROR,
  533. ERROR_NOT_ENOUGH_MEMORY,
  534. -1,
  535. argCount - argc);
  536. return FALSE;
  537. }
  538. }
  539. else
  540. {
  541. FILL_ERROR(pError,
  542. ERROR_FROM_PARSER,
  543. PARSE_ERROR_SWICH_NO_VALUE,
  544. i,
  545. -1);
  546. return FALSE;
  547. }
  548. break;
  549. case ARG_TYPE_STR:
  550. if (argc > 0)
  551. {
  552. if (!pToken->IsSwitch())
  553. {
  554. size_t len = 0;
  555. PCWSTR pwzToken = pToken->GetToken();
  556. if (!pwzToken)
  557. {
  558. ASSERT(FALSE);
  559. FILL_ERROR(pError,
  560. ERROR_FROM_PARSER,
  561. PARSE_ERROR_SWITCH_VALUE,
  562. i,
  563. argCount - argc);
  564. return FALSE;
  565. }
  566. hr = StringCchLength(pwzToken, MAXSTR, &len);
  567. if (FAILED(hr))
  568. {
  569. ASSERT(FALSE);
  570. FILL_ERROR(pError,
  571. ERROR_WIN32_ERROR,
  572. HRESULT_CODE(hr),
  573. i,
  574. -1);
  575. return FALSE;
  576. }
  577. len++; // make room for null.
  578. Commands[i].strValue = (PWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
  579. if (Commands[i].strValue == NULL)
  580. {
  581. ASSERT(FALSE);
  582. FILL_ERROR(pError,
  583. ERROR_WIN32_ERROR,
  584. ERROR_NOT_ENOUGH_MEMORY,
  585. i,
  586. -1);
  587. return FALSE;
  588. }
  589. hr = StringCchCopy(Commands[i].strValue, len, pwzToken);
  590. if (FAILED(hr))
  591. {
  592. ASSERT(FALSE);
  593. FILL_ERROR(pError,
  594. ERROR_WIN32_ERROR,
  595. HRESULT_CODE(hr),
  596. i,
  597. -1);
  598. return FALSE;
  599. }
  600. pToken++;
  601. argc--;
  602. }
  603. else if (ARG_FLAG_OPTIONAL & Commands[i].fFlag)
  604. {
  605. // The current switch doesn't have a value.
  606. // An arg value is optional, so parse the next switch
  607. // token.
  608. //
  609. break;
  610. }
  611. }
  612. else if (Commands[i].fFlag & ARG_FLAG_DEFAULTABLE)
  613. {
  614. // NOTICE-2002/02/26-ericb - SecurityPush: the command array
  615. // strings are all loaded from the resource fork.
  616. PWSTR strValue = Commands[i].strValue;
  617. Commands[i].strValue = (PWSTR)LocalAlloc(LPTR, (wcslen(strValue) + 1) * sizeof(WCHAR));
  618. if (Commands[i].strValue == NULL)
  619. {
  620. FILL_ERROR(pError,
  621. ERROR_WIN32_ERROR,
  622. ERROR_NOT_ENOUGH_MEMORY,
  623. -1,
  624. argCount - argc);
  625. return FALSE;
  626. }
  627. wcscpy(Commands[i].strValue, strValue);
  628. }
  629. else if (ARG_FLAG_OPTIONAL & Commands[i].fFlag)
  630. {
  631. // The current switch doesn't have a value and is the
  632. // last token, so we are done.
  633. //
  634. break;
  635. }
  636. else
  637. {
  638. FILL_ERROR(pError,
  639. ERROR_FROM_PARSER,
  640. PARSE_ERROR_SWICH_NO_VALUE,
  641. i,
  642. -1);
  643. return FALSE;
  644. }
  645. break;
  646. case ARG_TYPE_INTSTR:
  647. //
  648. // We use IsSlash here instead of IsSwitch because we want to allow
  649. // negative numbers
  650. //
  651. if (argc > 0 && !pToken->IsSlash())
  652. {
  653. PCWSTR pszToken = pToken->GetToken();
  654. if (!pszToken)
  655. {
  656. FILL_ERROR(pError,
  657. ERROR_FROM_PARSER,
  658. PARSE_ERROR_SWITCH_VALUE,
  659. i,
  660. argCount - argc);
  661. return FALSE;
  662. }
  663. Commands[i].nValue = _wtoi( pszToken);
  664. Commands[i].fType = ARG_TYPE_INT;
  665. if (Commands[i].nValue == 0 &&
  666. !iswdigit(pszToken[0]))
  667. {
  668. //
  669. // Then treat as a string
  670. //
  671. size_t len = 0;
  672. hr = StringCchLength(pszToken, MAXSTR, &len);
  673. if (FAILED(hr))
  674. {
  675. ASSERT(FALSE);
  676. FILL_ERROR(pError,
  677. ERROR_WIN32_ERROR,
  678. HRESULT_CODE(hr),
  679. i,
  680. -1);
  681. return FALSE;
  682. }
  683. len++; // make room for null.
  684. Commands[i].strValue = (PWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
  685. if (Commands[i].strValue == NULL )
  686. {
  687. FILL_ERROR(pError,
  688. ERROR_WIN32_ERROR,
  689. ERROR_NOT_ENOUGH_MEMORY,
  690. -1,
  691. argCount - argc);
  692. return FALSE;
  693. }
  694. hr = StringCchCopy(Commands[i].strValue, len, pszToken);
  695. if (FAILED(hr))
  696. {
  697. ASSERT(FALSE);
  698. FILL_ERROR(pError,
  699. ERROR_WIN32_ERROR,
  700. HRESULT_CODE(hr),
  701. i,
  702. -1);
  703. return FALSE;
  704. }
  705. Commands[i].fType = ARG_TYPE_STR;
  706. }
  707. pToken++;
  708. argc--;
  709. }
  710. else if (!(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE))
  711. {
  712. FILL_ERROR(pError,
  713. ERROR_FROM_PARSER,
  714. PARSE_ERROR_SWITCH_VALUE,
  715. i,
  716. argCount - argc);
  717. return FALSE;
  718. }
  719. break;
  720. }
  721. if (Commands[i].bDefined && Commands[i].fntValidation != NULL)
  722. {
  723. dwErr = Commands[i].fntValidation(Commands + i);
  724. if (dwErr != ERROR_SUCCESS)
  725. {
  726. FILL_ERROR(pError,
  727. ERROR_FROM_VLDFN,
  728. dwErr,
  729. i,
  730. -1);
  731. return FALSE;
  732. }
  733. }
  734. }
  735. }
  736. if (!bFound)
  737. {
  738. FILL_ERROR(pError,
  739. ERROR_FROM_PARSER,
  740. PARSE_ERROR_UNKNOWN_INPUT_PARAMETER,
  741. -1,
  742. argCount - argc);
  743. return FALSE;
  744. }
  745. }
  746. if (bValidate)
  747. return ValidateCommands(Commands, pError);
  748. return TRUE;
  749. }
  750. // This Function reads from the Command Line,
  751. // return it in tokenized format.
  752. DWORD GetCommandInput( OUT int *pargc, //Number of Tokens
  753. OUT LPTOKEN *ppToken) //Array of CToken
  754. {
  755. LPWSTR pBuffer = NULL;
  756. DWORD dwErr = ERROR_SUCCESS;
  757. WCHAR szDelimiters[] = L": \n\t";
  758. // Delimiters for first token, : omitted to prevent
  759. // parser getting confused by : in drive letter
  760. // if full path of netdom.exe is specified
  761. WCHAR szAltDelimiters[] = L" \n\t";
  762. *pargc = 0;
  763. // Read the commandline input
  764. pBuffer = GetCommandLine();
  765. if (!pBuffer)
  766. {
  767. return ERROR_INVALID_PARAMETER;
  768. }
  769. size_t cch = 0;
  770. // NOTICE-2002/02/20-ericb - SecurityPush: Set the max command line to
  771. // 2048 (NETDOM_MAX_CMDLINE) which should be more than enough for any netdom
  772. // command string.
  773. HRESULT hr = StringCchLength(pBuffer, NETDOM_MAX_CMDLINE, &cch);
  774. if (FAILED(hr))
  775. {
  776. return HRESULT_CODE(hr);
  777. }
  778. dwErr = Tokenize(pBuffer,
  779. cch,
  780. szDelimiters,
  781. ppToken,
  782. pargc,
  783. szAltDelimiters);
  784. return dwErr;
  785. }
  786. BOOL IsDelimiter(WCHAR ch, LPWSTR pszDelimiters)
  787. {
  788. while (*pszDelimiters)
  789. if ((WCHAR)*pszDelimiters++ == ch)
  790. return TRUE;
  791. return FALSE;
  792. }
  793. /*
  794. This function tokenizes the input buffer. It needs to be called in two steps.
  795. First time you call it, provide pBuf and Buflen. First Call will return
  796. the first token. To get next token, call the function with NULL for pBuf and
  797. 0 for Buflen.
  798. Output: pbQuote is true if this token was enclosed in a quote.
  799. ppToken: Token string. Call LocalFree to free it.
  800. Return Value:Length of Token if token found.
  801. 0 if no token found.
  802. -1 in case of error. Call GetLastError to get the error.
  803. */
  804. LONG GetToken(IN LPWSTR pBuf,
  805. IN LONG BufLen,
  806. IN LPWSTR pszDelimiters,
  807. OUT BOOL *pbQuote,
  808. OUT LPWSTR *ppToken)
  809. {
  810. static LPWSTR pBuffer;
  811. static LONG BufferLen;
  812. DWORD dwErr = ERROR_SUCCESS;
  813. if (pbQuote)
  814. *pbQuote = FALSE;
  815. if (ppToken)
  816. *ppToken = NULL;
  817. size_t MaxSize = INIT_SIZE;
  818. LONG pos = 0;
  819. if (pBuf)
  820. pBuffer = pBuf;
  821. if (BufLen)
  822. BufferLen = BufLen;
  823. if (!BufferLen || !pBuffer || !pBuffer[0])
  824. return pos;
  825. // NOTICE-2002/02/27-ericb - SecurityPush: multiple changes to reduce the
  826. // chance of buffer pointer errors.(done)
  827. do
  828. {
  829. BOOL bQuoteBegin = FALSE;
  830. PWSTR pItem = NULL;
  831. //Find the begining of Next Token
  832. while (BufferLen && pBuffer && IsDelimiter(pBuffer[0], pszDelimiters))
  833. {
  834. ++pBuffer; --BufferLen;
  835. }
  836. if (!BufferLen || !pBuffer || !pBuffer[0])
  837. break;
  838. //Does Token Start with '"'
  839. if (pBuffer[0] == L'"' )
  840. {
  841. if (pbQuote)
  842. *pbQuote = TRUE;
  843. bQuoteBegin = TRUE;
  844. pBuffer++; --BufferLen;
  845. }
  846. if (!BufferLen || !pBuffer || !pBuffer[0])
  847. break;
  848. if (ppToken)
  849. {
  850. pItem = (PWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*INIT_SIZE);
  851. if (!pItem)
  852. {
  853. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  854. return -1;
  855. }
  856. }
  857. //Now get the end
  858. WCHAR ch;
  859. while (BufferLen && pBuffer)
  860. {
  861. BOOL bChar = TRUE;
  862. if (BufferLen >= 2 && pBuffer && *pBuffer == L'\\' &&
  863. (pBuffer+1) && *(pBuffer+1) == L'"')
  864. {
  865. ch = L'"';
  866. pBuffer +=2; BufferLen -=2;
  867. }
  868. else if (pBuffer[0] == L'"')
  869. {
  870. //A Matching Quote Found.
  871. if (bQuoteBegin)
  872. {
  873. ++pBuffer;
  874. --BufferLen;
  875. if (BufferLen && pBuffer)
  876. {
  877. //If next char is whitespace endof token
  878. //Ex "ABC" "xyz" . after C its endof token
  879. if (IsDelimiter(pBuffer[0], pszDelimiters) )
  880. break;
  881. else
  882. {
  883. //Ex "ABC"xyz
  884. if (pBuffer[0] != L'"')
  885. bQuoteBegin = FALSE;
  886. //"ABC""xyz"
  887. else
  888. {
  889. ++pBuffer;
  890. --BufferLen;
  891. }
  892. }
  893. }
  894. bChar = FALSE;
  895. //
  896. // Don't break because "" means that we want to clear the field out
  897. //
  898. }
  899. //ABC" xyz" will get one token 'ABC xyz'
  900. else
  901. {
  902. bQuoteBegin = TRUE;
  903. ++pBuffer;
  904. --BufferLen;
  905. bChar = FALSE;
  906. }
  907. }
  908. else if (!bQuoteBegin && IsDelimiter(pBuffer[0], pszDelimiters))
  909. {
  910. ++pBuffer;
  911. --BufferLen;
  912. break;
  913. }
  914. else
  915. {
  916. ch = pBuffer[0];
  917. ++pBuffer;
  918. --BufferLen;
  919. }
  920. if (bChar && ppToken)
  921. {
  922. if (pos == MaxSize - 1)
  923. if (ERROR_SUCCESS != ResizeByTwo(&pItem, &MaxSize))
  924. {
  925. LocalFree(pItem);
  926. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  927. return -1;
  928. }
  929. pItem[pos] = ch;
  930. }
  931. if (bChar)
  932. ++pos;
  933. }
  934. if (pos ||
  935. (!pos && bQuoteBegin))
  936. {
  937. if (ppToken)
  938. {
  939. if (pos >= (LONG)MaxSize)
  940. {
  941. ASSERT(FALSE);
  942. LocalFree(pItem);
  943. SetLastError(ERROR_INVALID_PARAMETER);
  944. return -1;
  945. }
  946. pItem[pos] = '\0';
  947. *ppToken = pItem;
  948. }
  949. ++pos;
  950. }
  951. } while (0);
  952. return pos;
  953. }
  954. /*
  955. Function to convert string an array of CTokens.
  956. INPUT: pBuf Input Buffer
  957. BufLen Length of bBuf
  958. szDelimiters Chars to use as delimiters
  959. pszAltDelimiters If specified, use this set of delimiters for
  960. the first token and those specified by szDelimiter
  961. for subsequent tokens.
  962. OUTPUT:ppToken Gets Pointer to array of CToken
  963. argc Lenght of array of CToken
  964. Return Value: WIN32 Error
  965. */
  966. DWORD Tokenize(IN LPWSTR pBuf,
  967. IN LONG BufLen,
  968. LPWSTR szDelimiters,
  969. OUT CToken **ppToken,
  970. OUT int *argc,
  971. IN OPTIONAL LPWSTR pszAltDelimiters)
  972. {
  973. *argc = 0;
  974. CToken *pToken = NULL;
  975. DWORD dwErr = ERROR_SUCCESS;
  976. BOOL bQuote;
  977. LPWSTR pszItem = NULL;
  978. // Count the tokens. Get First Token.
  979. LONG ret = 0;
  980. if ( pszAltDelimiters )
  981. {
  982. //If alternate delimiters are specified
  983. // for the first token use them
  984. // this is put to avoid the parser getting
  985. // confused by the : in cmd line calls like
  986. // c:\dir\netdom
  987. ret = GetToken(pBuf,
  988. BufLen,
  989. pszAltDelimiters,
  990. &bQuote,
  991. NULL);
  992. }
  993. else
  994. {
  995. ret = GetToken(pBuf,
  996. BufLen,
  997. szDelimiters,
  998. &bQuote,
  999. NULL);
  1000. }
  1001. if (ret == -1)
  1002. {
  1003. dwErr = GetLastError();
  1004. goto exit_gracefully;
  1005. }
  1006. // Count the rest of the tokens.
  1007. while(ret)
  1008. {
  1009. ++(*argc);
  1010. ret = GetToken(NULL,
  1011. NULL,
  1012. szDelimiters,
  1013. &bQuote,
  1014. NULL);
  1015. if (ret == -1)
  1016. {
  1017. dwErr = GetLastError();
  1018. goto exit_gracefully;
  1019. }
  1020. }
  1021. if (*argc)
  1022. {
  1023. // Save the tokens.
  1024. int i =0;
  1025. pToken = new CToken[*argc];
  1026. if (!pToken)
  1027. {
  1028. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1029. goto exit_gracefully;
  1030. }
  1031. if ( pszAltDelimiters )
  1032. {
  1033. //If alternate delimiters are specified
  1034. // for the first token use them
  1035. // this is put to avoid the parser getting
  1036. // confused by the : in cmd line calls like
  1037. // c:\dir\netdom
  1038. ret = GetToken(pBuf,
  1039. BufLen,
  1040. pszAltDelimiters,
  1041. &bQuote,
  1042. &pszItem);
  1043. }
  1044. else
  1045. {
  1046. ret = GetToken(pBuf,
  1047. BufLen,
  1048. szDelimiters,
  1049. &bQuote,
  1050. &pszItem);
  1051. }
  1052. if (ret == -1)
  1053. {
  1054. dwErr = GetLastError();
  1055. goto exit_gracefully;
  1056. }
  1057. while(ret)
  1058. {
  1059. if (!pToken[i++].Init(pszItem, bQuote))
  1060. {
  1061. dwErr = ERROR_OUTOFMEMORY;
  1062. goto exit_gracefully;
  1063. }
  1064. if (pszItem)
  1065. LocalFree(pszItem);
  1066. pszItem = NULL;
  1067. ret = GetToken(NULL,
  1068. NULL,
  1069. szDelimiters,
  1070. &bQuote,
  1071. &pszItem);
  1072. if (ret == -1)
  1073. {
  1074. dwErr = GetLastError();
  1075. goto exit_gracefully;
  1076. }
  1077. }
  1078. }
  1079. exit_gracefully:
  1080. if (dwErr != ERROR_SUCCESS)
  1081. {
  1082. if (pToken)
  1083. {
  1084. delete [] pToken ;
  1085. }
  1086. return dwErr;
  1087. }
  1088. *ppToken = pToken;
  1089. return dwErr;
  1090. }
  1091. VOID DisplayOutput(LPWSTR pszOutput)
  1092. {
  1093. HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1094. if (pszOutput && standardOut )
  1095. {
  1096. MyWriteConsole ( standardOut, pszOutput, wcslen ( pszOutput ) );
  1097. MyWriteConsole ( standardOut, L"\n", 1 );
  1098. }
  1099. }
  1100. VOID DisplayOutputNoNewline(LPWSTR pszOutput)
  1101. {
  1102. HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1103. if (pszOutput && standardOut )
  1104. {
  1105. MyWriteConsole ( standardOut, pszOutput, wcslen ( pszOutput ) );
  1106. }
  1107. }
  1108. /*
  1109. Class CToken
  1110. */
  1111. CToken::CToken(PCWSTR psz, BOOL bQuote)
  1112. {
  1113. StringCopy(&m_pszToken,psz);
  1114. m_bInitQuote = bQuote;
  1115. }
  1116. CToken::CToken() : m_bInitQuote(FALSE), m_pszToken(NULL) {}
  1117. CToken::~CToken()
  1118. {
  1119. LocalFree(m_pszToken);
  1120. }
  1121. BOOL CToken::Init(PCWSTR psz, BOOL bQuote)
  1122. {
  1123. if (!StringCopy(&m_pszToken,psz))
  1124. {
  1125. return FALSE;
  1126. }
  1127. m_bInitQuote = bQuote;
  1128. return TRUE;
  1129. }
  1130. PWSTR CToken::GetToken() const {return m_pszToken;}
  1131. BOOL CToken::IsSwitch() const
  1132. {
  1133. //Assert(m_pszToken);
  1134. if (!m_pszToken)
  1135. return FALSE;
  1136. if (m_bInitQuote)
  1137. return FALSE;
  1138. if (m_pszToken[0] == L'/' ||
  1139. m_pszToken[0] == L'-')
  1140. return TRUE;
  1141. return FALSE;
  1142. }
  1143. BOOL CToken::IsSlash() const
  1144. {
  1145. if (!m_pszToken)
  1146. return FALSE;
  1147. if (m_bInitQuote)
  1148. return FALSE;
  1149. if (m_pszToken[0] == L'/')
  1150. return TRUE;
  1151. return FALSE;
  1152. }
  1153. // Copied from JSchwart
  1154. BOOL
  1155. FileIsConsole(
  1156. HANDLE fp
  1157. )
  1158. {
  1159. unsigned htype;
  1160. htype = GetFileType(fp);
  1161. htype &= ~FILE_TYPE_REMOTE;
  1162. return htype == FILE_TYPE_CHAR;
  1163. }
  1164. // Outputs the string in the lpBuffer
  1165. // fp is the handle for StdOut / StdErr
  1166. // lpBuffer string to be printed out
  1167. // cchBuffer - no of chars in lpBuffer excluding null termination
  1168. void
  1169. MyWriteConsole(
  1170. HANDLE fp,
  1171. LPWSTR lpBuffer,
  1172. DWORD cchBuffer
  1173. )
  1174. {
  1175. // NOTICE-2002/02/27-ericb - SecurityPush: validate output routine parameters.
  1176. // cchBuffer can be 0 for the case of empty string ""
  1177. if (!lpBuffer)
  1178. {
  1179. ASSERT(FALSE);
  1180. lpBuffer = L"MyWriteConsole null buffer!";
  1181. cchBuffer = wcslen(lpBuffer);
  1182. }
  1183. //
  1184. // Jump through hoops for output because:
  1185. //
  1186. // 1. printf() family chokes on international output (stops
  1187. // printing when it hits an unrecognized character)
  1188. //
  1189. // 2. WriteConsole() works great on international output but
  1190. // fails if the handle has been redirected (i.e., when the
  1191. // output is piped to a file)
  1192. //
  1193. // 3. WriteFile() works great when output is piped to a file
  1194. // but only knows about bytes, so Unicode characters are
  1195. // printed as two Ansi characters.
  1196. //
  1197. if (FileIsConsole(fp))
  1198. {
  1199. WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
  1200. }
  1201. else
  1202. {
  1203. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
  1204. if (lpAnsiBuffer != NULL)
  1205. {
  1206. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  1207. 0,
  1208. lpBuffer,
  1209. cchBuffer,
  1210. lpAnsiBuffer,
  1211. cchBuffer * sizeof(WCHAR),
  1212. NULL,
  1213. NULL);
  1214. if (cchBuffer != 0)
  1215. {
  1216. WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL);
  1217. }
  1218. LocalFree(lpAnsiBuffer);
  1219. }
  1220. }
  1221. }
  1222. void
  1223. WriteStandardOut(PCWSTR pszFormat, ...)
  1224. {
  1225. static HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1226. //
  1227. // Verify parameters
  1228. //
  1229. if (!pszFormat)
  1230. {
  1231. return;
  1232. }
  1233. va_list args;
  1234. va_start(args, pszFormat);
  1235. int nBuf;
  1236. WCHAR szBuffer[4 * MAX_PATH];
  1237. ZeroMemory(szBuffer, sizeof(szBuffer));
  1238. nBuf = _vsnwprintf(szBuffer, sizeof(szBuffer)/sizeof(WCHAR), pszFormat, args);
  1239. //
  1240. // Output the results
  1241. //
  1242. if (nBuf > 0)
  1243. {
  1244. MyWriteConsole(standardOut,
  1245. szBuffer,
  1246. nBuf);
  1247. }
  1248. va_end(args);
  1249. }
  1250. // Reads From Stdin, also works if StdIn has been redirected
  1251. //
  1252. // ppBuffer is allocated by this method, and filled with the null
  1253. // terminated string entered by the user.
  1254. // Caller must free the buffer using LocalFree
  1255. //
  1256. // Return Value:
  1257. // Number of WCHAR read if successful excluding the null termination
  1258. // -1 in case of Failure. Call GetLastError to get the error.
  1259. LONG ReadFromIn(OUT LPWSTR *ppBuffer)
  1260. {
  1261. LPWSTR pBuffer = NULL;
  1262. DWORD dwErr = ERROR_SUCCESS;
  1263. pBuffer = (LPWSTR)LocalAlloc(LPTR,INIT_SIZE*sizeof(WCHAR));
  1264. if (!pBuffer)
  1265. {
  1266. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1267. return -1;
  1268. }
  1269. LONG Pos = 0;
  1270. size_t MaxSize = INIT_SIZE;
  1271. wint_t ch = 0;
  1272. while( (ch = getwchar()) != L'\n' && ch != WEOF )
  1273. {
  1274. if (Pos == MaxSize -1 )
  1275. {
  1276. if (ERROR_SUCCESS != ResizeByTwo(&pBuffer, &MaxSize))
  1277. {
  1278. LocalFree(pBuffer);
  1279. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1280. return -1;
  1281. }
  1282. }
  1283. pBuffer[Pos++] = (WCHAR)ch;
  1284. }
  1285. pBuffer[Pos] = L'\0';
  1286. *ppBuffer = pBuffer;
  1287. return Pos;
  1288. }
  1289. //Helper function used by ReadFromIn
  1290. DWORD ResizeByTwo( PWSTR *ppBuffer, size_t *pSize )
  1291. {
  1292. if (!ppBuffer || !*ppBuffer || !pSize || !*pSize)
  1293. {
  1294. ASSERT(ppBuffer);
  1295. ASSERT(*ppBuffer);
  1296. ASSERT(pSize);
  1297. ASSERT(*pSize);
  1298. return ERROR_INVALID_PARAMETER;
  1299. }
  1300. LPWSTR pTempBuffer = (LPWSTR)LocalAlloc(LPTR, (*pSize) * 2 * sizeof(WCHAR));
  1301. if (!pTempBuffer)
  1302. return ERROR_NOT_ENOUGH_MEMORY;
  1303. memcpy(pTempBuffer, *ppBuffer, *pSize * sizeof(WCHAR));
  1304. LocalFree(*ppBuffer);
  1305. *ppBuffer = pTempBuffer;
  1306. *pSize *= 2;
  1307. return ERROR_SUCCESS;
  1308. }
  1309. BOOL StringCopy(PWSTR *ppDest, PCWSTR pSrc)
  1310. {
  1311. if (!ppDest)
  1312. {
  1313. ASSERT(FALSE);
  1314. return FALSE;
  1315. }
  1316. *ppDest = NULL;
  1317. if (!pSrc)
  1318. return TRUE;
  1319. size_t cch = 0;
  1320. HRESULT hr = StringCchLength(pSrc, MAXSTR, &cch);
  1321. if (FAILED(hr))
  1322. {
  1323. ASSERT(FALSE);
  1324. return FALSE;
  1325. }
  1326. cch++; // add space for the null.
  1327. *ppDest = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
  1328. if (!*ppDest)
  1329. return FALSE;
  1330. hr = StringCchCopy(*ppDest, cch, pSrc);
  1331. return SUCCEEDED(hr);
  1332. }