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.

2037 lines
61 KiB

  1. /*****************************************************************************\
  2. Author: Hiteshr
  3. Copyright (c) 1998-2000 Microsoft Corporation
  4. Change History:
  5. Adapted From Parser Implemenation of Corey Morgan
  6. \*****************************************************************************/
  7. #include "pch.h"
  8. #include "..\dsutil2.h" // GetEscapedElement
  9. #include "..\parserutil.h" // eCommUnicodeAll
  10. #include <io.h> // _setmode()
  11. #include <fcntl.h> // _O_BINARY
  12. #include <locale.h> // setlocale 569040-2002/04/10-JonN initialize locale
  13. BOOL ValidateCommands(IN LPCTSTR pszCommandName,
  14. IN ARG_RECORD *Commands,
  15. OUT PPARSE_ERROR pError);
  16. // void DisplayDebugInfo(IN ARG_RECORD *Commands);
  17. // JonN 4/26/01 256583
  18. BOOL AddDNEscaping_Commands( IN OUT ARG_RECORD *Commands, OUT PPARSE_ERROR pError );
  19. DWORD AddDNEscaping_DN( OUT LPWSTR* ppszOut, IN LPWSTR pszIn );
  20. BOOL StartBuffer( OUT LPTSTR* pbuffer,
  21. OUT LONG* pmaxSize,
  22. OUT LONG* pcurrentSize );
  23. DWORD AddToBuffer( IN LPCTSTR psz,
  24. IN OUT LPTSTR* pbuffer,
  25. IN OUT LONG* pmaxSize,
  26. IN OUT LONG* pcurrentSize,
  27. IN BOOL fMSZBuffer);
  28. #define FILL_ERROR(pError,source,error_code,rec_index,argv_index) \
  29. pError->ErrorSource = source; \
  30. pError->Error = error_code; \
  31. pError->ArgRecIndex = rec_index; \
  32. pError->ArgvIndex = argv_index;
  33. // Copied from JSchwart
  34. DWORD FileType( HANDLE fp )
  35. {
  36. DWORD htype = GetFileType(fp);
  37. htype &= ~FILE_TYPE_REMOTE;
  38. return htype;
  39. }
  40. // NOTE: this is only implemented to return the correct thing
  41. // for ARG_TYPE_BOOL, ARG_TYPE_STR, and ARG_TYPE_MSZ
  42. // All other types will return FALSE
  43. BOOL HasValue( PARG_RECORD arg)
  44. {
  45. if (!arg)
  46. {
  47. return FALSE;
  48. }
  49. BOOL hasValue = FALSE;
  50. switch (arg->fType)
  51. {
  52. case ARG_TYPE_BOOL:
  53. hasValue = arg->bDefined;
  54. break;
  55. case ARG_TYPE_STR:
  56. case ARG_TYPE_MSZ:
  57. if (arg->strValue && arg->strValue[0])
  58. {
  59. hasValue = TRUE;
  60. }
  61. break;
  62. case ARG_TYPE_INTSTR:
  63. case ARG_TYPE_INT:
  64. case ARG_TYPE_HELP:
  65. case ARG_TYPE_DEBUG:
  66. case ARG_TYPE_LAST:
  67. default:
  68. hasValue = FALSE;
  69. break;
  70. }
  71. return hasValue;
  72. }
  73. BOOL IsCmd( PARG_RECORD arg, LPTOKEN pToken)
  74. {
  75. if(!arg || !pToken)
  76. return FALSE;
  77. LPWSTR str = pToken->GetToken();
  78. if(!str)
  79. return FALSE;
  80. if(pToken->IsSwitch())
  81. {
  82. str++;
  83. }else
  84. {
  85. if( (arg->fFlag & ARG_FLAG_NOFLAG) && !arg->bDefined )
  86. {
  87. return TRUE;
  88. }
  89. if ((arg->fFlag & ARG_FLAG_STDIN) &&
  90. !HasValue(arg))
  91. {
  92. return TRUE;
  93. }
  94. if( !(arg->fFlag & ARG_FLAG_VERB) )
  95. {
  96. return FALSE;
  97. }
  98. }
  99. if( ( arg->strArg1 && !_tcsicmp( str, arg->strArg1 ) )
  100. ||(arg->strArg2 && !_tcsicmp( str, arg->strArg2 )) )
  101. {
  102. return TRUE;
  103. }
  104. return FALSE;
  105. }
  106. void FreeCmd(ARG_RECORD *Commands)
  107. {
  108. int i;
  109. for(i=0;Commands[i].fType != ARG_TYPE_LAST;i++)
  110. {
  111. if((Commands[i].fType == ARG_TYPE_STR ||
  112. Commands[i].fType == ARG_TYPE_MSZ ) &&
  113. Commands[i].bDefined )
  114. {
  115. LocalFree( Commands[i].strValue );
  116. Commands[i].strValue = NULL;
  117. }
  118. if((Commands[i].fType == ARG_TYPE_PASSWORD) &&
  119. Commands[i].bDefined &&
  120. Commands[i].encryptedDataBlob.pbData)
  121. {
  122. LocalFree( Commands[i].encryptedDataBlob.pbData );
  123. Commands[i].encryptedDataBlob.pbData = NULL;
  124. }
  125. if( Commands[i].idArg1 && Commands[i].strArg1 != NULL )
  126. {
  127. LocalFree(Commands[i].strArg1);
  128. }
  129. if( Commands[i].idArg2 && Commands[i].strArg2 != NULL )
  130. {
  131. LocalFree( Commands[i].strArg2 );
  132. }
  133. Commands[i].bDefined = FALSE;
  134. }
  135. }
  136. BOOL LoadCmd(ARG_RECORD *Commands)
  137. {
  138. int i;
  139. BOOL bRet = TRUE;
  140. for( i=0; Commands[i].fType!=ARG_TYPE_LAST; i++ )
  141. {
  142. if(Commands[i].idArg1 !=0)
  143. if(!LoadStringAlloc(&Commands[i].strArg1, NULL,Commands[i].idArg1))
  144. {
  145. bRet = FALSE;
  146. break;
  147. }
  148. if(Commands[i].idArg2 !=0 && Commands[i].idArg2 != ID_ARG2_NULL)
  149. if(!LoadStringAlloc(&Commands[i].strArg2, NULL,Commands[i].idArg2))
  150. {
  151. bRet = FALSE;
  152. break;
  153. }
  154. }
  155. return bRet;
  156. }
  157. BOOL
  158. ValidateCommands(LPCTSTR pszCommandName,
  159. ARG_RECORD *Commands,
  160. PPARSE_ERROR pError)
  161. {
  162. int i = 0;
  163. LONG cReadFromStdin = 0;
  164. int iFirstReadFromStdin = -1;
  165. ARG_RECORD *CommandsIn = NULL;
  166. LPWSTR pBuffer=NULL;
  167. LONG BufferLen = 0;
  168. LPTOKEN pToken = NULL;
  169. int argc=0;
  170. BOOL bRet = FALSE;
  171. bool bAtLeastOne = false;
  172. bool bAtLeastOneDefined = false;
  173. if(!Commands || !pError || !pszCommandName)
  174. goto exit_gracefully;
  175. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  176. {
  177. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined &&
  178. !(Commands[i].fFlag & ARG_FLAG_STDIN))
  179. {
  180. FILL_ERROR(pError,
  181. ERROR_FROM_PARSER,
  182. PARSE_ERROR_SWITCH_NOTDEFINED,
  183. i,
  184. -1);
  185. goto exit_gracefully;
  186. }
  187. // Mark for reading from STDIN if the following conditions apply
  188. // 1. Command is marked to be read from STDIN and it is not defined
  189. // and it is marked as NOFLAG (no switch)
  190. // or
  191. // 2. Command is marked to be read from STDIN and it is defined and
  192. // if is not marked as NOFLAG and there is no value specified
  193. if (Commands[i].fFlag & ARG_FLAG_STDIN &&
  194. (!Commands[i].bDefined && (Commands[i].fFlag & ARG_FLAG_NOFLAG) ||
  195. (Commands[i].bDefined && !(Commands[i].fFlag & ARG_FLAG_NOFLAG) &&
  196. !HasValue(&Commands[i]))))
  197. {
  198. cReadFromStdin++;
  199. if (-1 == iFirstReadFromStdin)
  200. iFirstReadFromStdin = i;
  201. }
  202. if (Commands[i].fFlag & ARG_FLAG_ATLEASTONE)
  203. {
  204. bAtLeastOne = true;
  205. if (Commands[i].bDefined)
  206. {
  207. bAtLeastOneDefined = true;
  208. }
  209. }
  210. }
  211. if (bAtLeastOne && !bAtLeastOneDefined)
  212. {
  213. pError->ErrorSource = ERROR_FROM_PARSER;
  214. pError->Error = PARSE_ERROR_ATLEASTONE_NOTDEFINED;
  215. pError->ArgRecIndex = -1;
  216. pError->ArgvIndex = -1;
  217. goto exit_gracefully;
  218. }
  219. if(!cReadFromStdin)
  220. {
  221. bRet = TRUE;
  222. goto exit_gracefully;
  223. }
  224. //Read From STDIN
  225. BufferLen = ReadFromIn(&pBuffer);
  226. if(BufferLen == -1)
  227. {
  228. FILL_ERROR(pError,
  229. ERROR_WIN32_ERROR,
  230. GetLastError(),
  231. -1,
  232. -1);
  233. goto exit_gracefully;
  234. }
  235. if(BufferLen == 0)
  236. {
  237. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  238. {
  239. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  240. {
  241. FILL_ERROR(pError,
  242. ERROR_FROM_PARSER,
  243. PARSE_ERROR_SWITCH_NOTDEFINED,
  244. i,
  245. -1);
  246. goto exit_gracefully;
  247. }
  248. }
  249. }
  250. if(BufferLen)
  251. {
  252. //
  253. // JonN 9/4/01 460583
  254. // Check for Unicode input with non-Unicode command, or vice-versa
  255. //
  256. if (BufferLen < 4)
  257. {
  258. // not able to determine Unicode-ness with such short input
  259. }
  260. else if (g_fUnicodeInput)
  261. {
  262. // If all the characters in the input have nonzero hiwords,
  263. // this is almost certainly ANSI.
  264. bool bFoundShortChar = false;
  265. for (int ich = 0; ich < BufferLen; ich++)
  266. {
  267. if (pBuffer[ich] <= 0xff)
  268. {
  269. bFoundShortChar = true;
  270. break;
  271. }
  272. }
  273. if (!bFoundShortChar)
  274. // if ( !IsTextUnicode( pBuffer, BufferLen, NULL ) )
  275. {
  276. FILL_ERROR(pError,
  277. ERROR_FROM_PARSER,
  278. PARSE_ERROR_UNICODE_DEFINED,
  279. iFirstReadFromStdin,
  280. -1);
  281. goto exit_gracefully;
  282. }
  283. }
  284. else
  285. {
  286. // If the signature is char 0000 char 0000, this looks like Unicode.
  287. // getwchar() has the behavior of padding 00xx to 000000xx.
  288. if ( BufferLen >= 4
  289. && pBuffer[0]
  290. && !pBuffer[1]
  291. && pBuffer[2]
  292. && !pBuffer[3] )
  293. // if ( IsTextUnicode( pBuffer, BufferLen, NULL ) ) false positives
  294. {
  295. FILL_ERROR(pError,
  296. ERROR_FROM_PARSER,
  297. PARSE_ERROR_UNICODE_NOTDEFINED,
  298. iFirstReadFromStdin,
  299. -1);
  300. goto exit_gracefully;
  301. }
  302. }
  303. //Tokenize what you have read from STDIN
  304. DWORD dwErr;
  305. WCHAR szDelimiters[] = L" \n\t";
  306. dwErr = Tokenize(pBuffer,
  307. BufferLen,
  308. szDelimiters,
  309. &pToken,
  310. &argc);
  311. if( dwErr != ERROR_SUCCESS )
  312. {
  313. FILL_ERROR(pError,
  314. ERROR_WIN32_ERROR,
  315. dwErr,
  316. -1,
  317. -1);
  318. goto exit_gracefully;
  319. }
  320. //Prepare a CommandArray for them
  321. CommandsIn = (ARG_RECORD*)LocalAlloc(LPTR,sizeof(ARG_RECORD)*(cReadFromStdin+1));
  322. if(!CommandsIn)
  323. {
  324. FILL_ERROR(pError,
  325. ERROR_WIN32_ERROR,
  326. ERROR_NOT_ENOUGH_MEMORY,
  327. -1,
  328. -1);
  329. goto exit_gracefully;
  330. }
  331. int j;
  332. j = 0;
  333. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  334. {
  335. if (Commands[i].fFlag & ARG_FLAG_STDIN &&
  336. (!Commands[i].bDefined && (Commands[i].fFlag & ARG_FLAG_NOFLAG) ||
  337. (Commands[i].bDefined && !(Commands[i].fFlag & ARG_FLAG_NOFLAG) &&
  338. !HasValue(&Commands[i]))))
  339. {
  340. CommandsIn[j++] = Commands[i];
  341. }
  342. }
  343. //Copy the Last One
  344. CommandsIn[j] = Commands[i];
  345. if(!ParseCmd(pszCommandName,
  346. CommandsIn,
  347. argc,
  348. pToken,
  349. 0,
  350. pError,
  351. FALSE))
  352. {
  353. // 603157-2002/04/32-JonN
  354. // The commands read from STDIN are invalid. We must not pass through
  355. // pError from the recursed call to ParseCmd since the token list
  356. // to which it refers will be deleted before the parsing error
  357. // is displayed.
  358. FILL_ERROR(pError,
  359. ERROR_FROM_PARSER,
  360. PARSE_ERROR_ALREADY_DISPLAYED,
  361. i,
  362. -1);
  363. goto exit_gracefully;
  364. }
  365. //Copy the values back to Commands
  366. j=0;
  367. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  368. {
  369. if(Commands[i].fFlag & ARG_FLAG_STDIN &&
  370. (!Commands[i].bDefined && (Commands[i].fFlag & ARG_FLAG_NOFLAG) ||
  371. (Commands[i].bDefined && !(Commands[i].fFlag & ARG_FLAG_NOFLAG) &&
  372. !HasValue(&Commands[i]))))
  373. {
  374. Commands[i] = CommandsIn[j++];
  375. }
  376. }
  377. //Validate Commands
  378. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  379. {
  380. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  381. {
  382. FILL_ERROR(pError,
  383. ERROR_FROM_PARSER,
  384. PARSE_ERROR_SWITCH_NOTDEFINED,
  385. i,
  386. -1);
  387. goto exit_gracefully;
  388. }
  389. }
  390. }
  391. bRet = TRUE;
  392. exit_gracefully:
  393. if(CommandsIn)
  394. LocalFree(CommandsIn);
  395. if(pBuffer)
  396. LocalFree(pBuffer);
  397. if(pToken)
  398. {
  399. delete []pToken;
  400. }
  401. return bRet;
  402. }
  403. BOOL g_fUnicodeInput = FALSE;
  404. BOOL g_fUnicodeOutput = FALSE;
  405. BOOL ParseCmd(IN LPCTSTR pszCommandName,
  406. IN ARG_RECORD *Commands,
  407. IN int argc,
  408. IN LPTOKEN pToken,
  409. IN UINT* pUsageMessageTable,
  410. OUT PPARSE_ERROR pError,
  411. IN BOOL bValidate )
  412. {
  413. int i;
  414. BOOL bFound;
  415. BOOL bDoDebug = FALSE;
  416. int argCount;
  417. DWORD dwErr = ERROR_SUCCESS;
  418. BOOL bReturn = TRUE;
  419. LPTOKEN pTokenCopy = pToken;
  420. if(!pError)
  421. {
  422. return FALSE;
  423. }
  424. pError->MessageShown = FALSE;
  425. if(!Commands || argc == 0 || !pToken )
  426. {
  427. bReturn = FALSE;
  428. FILL_ERROR(pError,
  429. ERROR_WIN32_ERROR,
  430. E_INVALIDARG,
  431. -1,
  432. -1);
  433. goto exit_gracefully;
  434. }
  435. if(!LoadCmd(Commands))
  436. {
  437. bReturn = FALSE;
  438. FILL_ERROR(pError,
  439. ERROR_WIN32_ERROR,
  440. E_INVALIDARG,
  441. -1,
  442. -1);
  443. goto exit_gracefully;
  444. }
  445. argCount = argc;
  446. while( argc > 0 )
  447. {
  448. bFound = FALSE;
  449. for(i=0; Commands[i].fType != ARG_TYPE_LAST && (!bFound);i++)
  450. {
  451. if( IsCmd( &Commands[i], pToken) )
  452. {
  453. if(Commands[i].bDefined &&
  454. (!(Commands[i].fFlag & ARG_FLAG_STDIN) && HasValue(&Commands[i])))
  455. {
  456. FILL_ERROR(pError,
  457. ERROR_FROM_PARSER,
  458. PARSE_ERROR_MULTIPLE_DEF,
  459. i,
  460. -1);
  461. bReturn = FALSE;
  462. goto exit_gracefully;
  463. }
  464. if( pToken->IsSwitch() || Commands[i].fFlag & ARG_FLAG_VERB ){
  465. pToken++;argc--;
  466. }
  467. bFound = TRUE;
  468. Commands[i].bDefined = TRUE;
  469. switch( Commands[i].fType ){
  470. case ARG_TYPE_HELP:
  471. {
  472. Commands[i].bValue = TRUE;
  473. if( Commands[i].fntValidation != NULL )
  474. {
  475. Commands[i].fntValidation( Commands + i );
  476. }
  477. FILL_ERROR(pError,
  478. ERROR_FROM_PARSER,
  479. PARSE_ERROR_HELP_SWITCH,
  480. i,
  481. -1);
  482. if(pUsageMessageTable)
  483. DisplayMessage(pUsageMessageTable,TRUE);
  484. bReturn = FALSE;
  485. goto exit_gracefully;
  486. }
  487. break;
  488. case ARG_TYPE_DEBUG:
  489. //
  490. // REVIEW_JEFFJON : removed for now because it was AVing for dsadd group -secgrp
  491. //
  492. // bDoDebug = TRUE;
  493. Commands[i].fFlag |= ARG_FLAG_DEFAULTABLE;
  494. case ARG_TYPE_INT:
  495. {
  496. if( argc > 0 && !pToken->IsSlash())
  497. {
  498. PWSTR pszToken = pToken->GetToken();
  499. if(!ConvertStringToInterger(pszToken,&Commands[i].nValue))
  500. {
  501. FILL_ERROR(pError,
  502. ERROR_FROM_PARSER,
  503. PARSE_ERROR_SWITCH_VALUE,
  504. i,
  505. argCount - argc);
  506. bReturn = FALSE;
  507. goto exit_gracefully;
  508. }
  509. pToken++;argc--;
  510. }
  511. else if( !(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE) )
  512. {
  513. FILL_ERROR(pError,
  514. ERROR_FROM_PARSER,
  515. PARSE_ERROR_SWICH_NO_VALUE,
  516. i,
  517. argCount - argc);
  518. bReturn = FALSE;
  519. goto exit_gracefully;
  520. }
  521. }
  522. break;
  523. case ARG_TYPE_BOOL:
  524. Commands[i].bValue = TRUE;
  525. break;
  526. case ARG_TYPE_MSZ:
  527. if( argc > 0 && !pToken->IsSwitch())
  528. {
  529. LPTSTR buffer = NULL;
  530. LONG maxSize = 0;
  531. LONG currentSize = 0;
  532. if (!StartBuffer(&buffer,&maxSize,&currentSize))
  533. {
  534. FILL_ERROR(pError,
  535. ERROR_WIN32_ERROR,
  536. ERROR_NOT_ENOUGH_MEMORY,
  537. -1,
  538. argCount - argc);
  539. bReturn = FALSE;
  540. goto exit_gracefully;
  541. }
  542. LPCTSTR pszTemp = pToken->GetToken();
  543. dwErr = AddToBuffer(pszTemp,&buffer,&maxSize,&currentSize,TRUE);
  544. if (NO_ERROR != dwErr)
  545. {
  546. FILL_ERROR(pError,
  547. ERROR_WIN32_ERROR,
  548. dwErr,
  549. i,
  550. -1);
  551. bReturn = FALSE;
  552. goto exit_gracefully;
  553. }
  554. pToken++;argc--;
  555. while( argc > 0 && !pToken->IsSwitch() )
  556. {
  557. pszTemp = pToken->GetToken();
  558. dwErr = AddToBuffer(pszTemp,&buffer,&maxSize,&currentSize,TRUE);
  559. if (NO_ERROR != dwErr)
  560. {
  561. FILL_ERROR(pError,
  562. ERROR_WIN32_ERROR,
  563. dwErr,
  564. i,
  565. -1);
  566. bReturn = FALSE;
  567. goto exit_gracefully;
  568. }
  569. pToken++;argc--;
  570. }
  571. Commands[i].strValue = buffer;
  572. }
  573. else if( Commands[i].fFlag & ARG_FLAG_DEFAULTABLE )
  574. {
  575. //Here we are allocating the string using localAlloc so that
  576. //free cmd can simply call LocalFree on all Commands.strValue
  577. LPTSTR strValue = Commands[i].strValue;
  578. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(strValue)+1) * sizeof(TCHAR) );
  579. if( Commands[i].strValue != NULL )
  580. {
  581. //Buffer is correctly allocated.
  582. _tcscpy( Commands[i].strValue, strValue );
  583. }
  584. }
  585. else if ( Commands[i].fFlag & ARG_FLAG_STDIN )
  586. {
  587. // Do nothing here. The data should be retrieved from STDIN
  588. }
  589. else
  590. {
  591. FILL_ERROR(pError,
  592. ERROR_FROM_PARSER,
  593. PARSE_ERROR_SWICH_NO_VALUE,
  594. i,
  595. -1);
  596. bReturn = FALSE;
  597. goto exit_gracefully;
  598. }
  599. break;
  600. case ARG_TYPE_STR:
  601. case ARG_TYPE_PASSWORD: //Password is input from commandline as string
  602. if( argc > 0 && !pToken->IsSwitch())
  603. {
  604. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(pToken->GetToken())+2) * sizeof(TCHAR) );
  605. if( Commands[i].strValue != NULL )
  606. {
  607. //Buffer is properly allocated.
  608. _tcscpy( Commands[i].strValue, pToken->GetToken() );
  609. }
  610. pToken++;argc--;
  611. }else if( Commands[i].fFlag & ARG_FLAG_DEFAULTABLE )
  612. {
  613. //Here we are allocating the string using localAlloc so that
  614. //free cmd can simply call LocalFree on all Commands.strValue
  615. LPTSTR strValue = Commands[i].strValue;
  616. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(strValue)+2) * sizeof(TCHAR) );
  617. if( Commands[i].strValue != NULL )
  618. {
  619. //Buffer is properly allocated. Actually one byte extra.
  620. _tcscpy( Commands[i].strValue, strValue );
  621. }
  622. }else
  623. {
  624. FILL_ERROR(pError,
  625. ERROR_FROM_PARSER,
  626. PARSE_ERROR_SWICH_NO_VALUE,
  627. i,
  628. -1);
  629. bReturn = FALSE;
  630. goto exit_gracefully;
  631. }
  632. break;
  633. case ARG_TYPE_INTSTR:
  634. //
  635. // We use IsSlash here instead of IsSwitch because we want to allow
  636. // negative numbers
  637. //
  638. if( argc > 0 && !pToken->IsSlash())
  639. {
  640. PWSTR pszToken = pToken->GetToken();
  641. //Its fine.
  642. size_t strLen = wcslen(pszToken);
  643. Commands[i].nValue = _ttoi( pszToken);
  644. Commands[i].fType = ARG_TYPE_INT;
  645. if (Commands[i].nValue == 0 &&
  646. !iswdigit(pszToken[0]))
  647. {
  648. //
  649. // Then treat as a string
  650. //
  651. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(pToken->GetToken())+2) * sizeof(TCHAR) );
  652. if( Commands[i].strValue != NULL )
  653. {
  654. //proper buffer is allocated.
  655. _tcscpy( Commands[i].strValue, pToken->GetToken() );
  656. Commands[i].fType = ARG_TYPE_STR;
  657. }
  658. }
  659. pToken++;argc--;
  660. }
  661. else if( !(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE) )
  662. {
  663. FILL_ERROR(pError,
  664. ERROR_FROM_PARSER,
  665. PARSE_ERROR_SWICH_NO_VALUE,
  666. i,
  667. argCount - argc);
  668. bReturn = FALSE;
  669. goto exit_gracefully;
  670. }
  671. break;
  672. }
  673. if( Commands[i].bDefined && Commands[i].fntValidation != NULL )
  674. {
  675. dwErr = Commands[i].fntValidation(Commands + i);
  676. if( dwErr != ERROR_SUCCESS )
  677. {
  678. FILL_ERROR(pError,
  679. ERROR_FROM_VLDFN,
  680. dwErr,
  681. i,
  682. -1);
  683. bReturn = FALSE;
  684. goto exit_gracefully;
  685. }
  686. }
  687. }
  688. }
  689. if (!bFound)
  690. {
  691. pError->ErrorSource = ERROR_FROM_PARSER;
  692. pError->Error = PARSE_ERROR_UNKNOWN_INPUT_PARAMETER;
  693. pError->ArgRecIndex = -1;
  694. pError->ArgvIndex = argCount - argc;
  695. bReturn = FALSE;
  696. goto exit_gracefully;
  697. }
  698. }
  699. if( bDoDebug )
  700. {
  701. // DisplayDebugInfo(Commands);
  702. }
  703. if(bValidate)
  704. {
  705. //This should be done only in first parse when bValidate is set to true.
  706. //ValidateCommands recursively calls ParseCmd with different ARG_RECORD
  707. //array and that does not have eCommUnicodeInput etc switches.
  708. g_fUnicodeInput = Commands[eCommUnicodeInput].bDefined
  709. || ( Commands[eCommUnicodeAll].bDefined
  710. && (FILE_TYPE_PIPE == FileType(GetStdHandle(STD_INPUT_HANDLE))) );
  711. g_fUnicodeOutput = Commands[eCommUnicodeOutput].bDefined
  712. || ( Commands[eCommUnicodeAll].bDefined
  713. && (FILE_TYPE_PIPE == FileType(GetStdHandle(STD_OUTPUT_HANDLE))) );
  714. if (g_fUnicodeInput)
  715. {
  716. int dummy = _setmode( _fileno(stdin), _O_BINARY );
  717. }
  718. if (g_fUnicodeOutput)
  719. {
  720. WriteStandardOut( L"\xFEFF" );
  721. }
  722. }
  723. if(bValidate && !ValidateCommands(pszCommandName,Commands,pError))
  724. {
  725. bReturn = FALSE;
  726. goto exit_gracefully;
  727. }
  728. // JonN 4/26/01 256583
  729. // Note that this must be called after ValidateCommands, which completes
  730. // reading parameters from STDIN. If !bValidate, then we are in the
  731. // middle of a call to ValidateCommands.
  732. if (bValidate)
  733. {
  734. bReturn = AddDNEscaping_Commands(Commands,pError);
  735. }
  736. exit_gracefully:
  737. if(!bReturn)
  738. DisplayParseError(pszCommandName,pError, Commands, pTokenCopy);
  739. return bReturn;
  740. }
  741. /*
  742. void
  743. DisplayDebugInfo(ARG_RECORD *Commands)
  744. {
  745. int i;
  746. int nOut;
  747. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  748. {
  749. if( Commands[i].fType == ARG_TYPE_HELP ){
  750. continue;
  751. }
  752. nOut = _tprintf( _T("%s"), Commands[i].strArg1 );
  753. while( ++nOut < 10 )
  754. {
  755. _tprintf( _T(" ") );
  756. }
  757. _tprintf( _T("= ") );
  758. switch( Commands[i].fType )
  759. {
  760. case ARG_TYPE_DEBUG:
  761. case ARG_TYPE_INT:
  762. _tprintf( _T("%d"),
  763. Commands[i].nValue
  764. );
  765. break;
  766. case ARG_TYPE_BOOL:
  767. _tprintf( _T("%s"),
  768. Commands[i].bValue ? _T("TRUE") : _T("FALSE")
  769. );
  770. break;
  771. case ARG_TYPE_MSZ:
  772. if( NULL != Commands[i].strValue && _tcslen( Commands[i].strValue ) )
  773. {
  774. _tprintf( _T("%s ..."), Commands[i].strValue);
  775. }else
  776. {
  777. _tprintf( _T("%s"),_T("-") );
  778. }
  779. break;
  780. case ARG_TYPE_STR:
  781. _tprintf( _T("%s"),
  782. (Commands[i].strValue == NULL || !(_tcslen(Commands[i].strValue)) ) ?
  783. _T("-") : Commands[i].strValue
  784. );
  785. break;
  786. }
  787. _tprintf( _T("\n") );
  788. }
  789. _tprintf( _T("\n") );
  790. }
  791. */
  792. //This Function reads from the Command Line,
  793. //return it in tokenized format.
  794. DWORD GetCommandInput( OUT int *pargc, //Number of Tokens
  795. OUT LPTOKEN *ppToken) //Array of CToken
  796. {
  797. // 569040-2002/04/10-JonN initialize locale
  798. {
  799. UINT cp = GetConsoleCP();
  800. CHAR ach[256] = {0};
  801. HRESULT hr = StringCchPrintfA(ach, 256, ".%d", cp);
  802. assert( SUCCEEDED(hr) );
  803. char* pszOldLocale;
  804. #if 0
  805. pszOldLocale = setlocale(LC_ALL, NULL);
  806. _tprintf( _T("old locale was \"%hs\"\n"), pszOldLocale );
  807. _tprintf( _T("setting locale to \"%hs\"\n"), ach );
  808. #endif
  809. pszOldLocale = setlocale(LC_ALL, ach);
  810. assert( NULL != pszOldLocale );
  811. #if 0
  812. _tprintf( _T("new locale is \"%hs\"\n"), pszOldLocale );
  813. #endif
  814. }
  815. LPWSTR pBuffer = NULL;
  816. DWORD dwErr = ERROR_SUCCESS;
  817. WCHAR szDelimiters[] = L" \n\t";
  818. *pargc = 0;
  819. //Read the commandline input
  820. pBuffer = GetCommandLine();
  821. if(pBuffer)
  822. dwErr = Tokenize(pBuffer,
  823. wcslen(pBuffer),
  824. szDelimiters,
  825. ppToken,
  826. pargc);
  827. return dwErr;
  828. }
  829. BOOL IsDelimiter(WCHAR ch, LPWSTR pszDelimiters)
  830. {
  831. while(*pszDelimiters)
  832. if((WCHAR)*pszDelimiters++ == ch)
  833. return TRUE;
  834. return FALSE;
  835. }
  836. /*
  837. This Function Tokenize the input buffer. It needs to be called in two step.
  838. First time you call it, provide pBuf and Buflen. First Call will return
  839. the first token. To get next token, call the function with NULL for pBuf and
  840. 0 for Buflen.
  841. Output: pbQuote is true if this token was enclosed in a quote.
  842. ppToken: Token string. Call LocalFree to free it.
  843. Return Value:Length of Token if token found.
  844. 0 if no token found.
  845. -1 in case of error. Call GetLastError to get the error.
  846. */
  847. LONG GetToken(IN LPWSTR pBuf,
  848. IN LONG BufLen,
  849. IN LPWSTR pszDelimiters,
  850. OUT BOOL *pbQuote,
  851. OUT LPWSTR *ppToken)
  852. {
  853. static LPWSTR pBuffer;
  854. static LONG BufferLen;
  855. DWORD dwErr = ERROR_SUCCESS;
  856. if(pbQuote)
  857. *pbQuote = FALSE;
  858. if(ppToken)
  859. *ppToken = NULL;
  860. LONG MaxSize = INIT_SIZE;
  861. LONG pos = 0;
  862. if(pBuf)
  863. pBuffer = pBuf;
  864. if(BufLen)
  865. BufferLen = BufLen;
  866. if(!BufferLen)
  867. return pos;
  868. do
  869. {
  870. BOOL bQuoteBegin = FALSE;
  871. LPTSTR pItem = NULL;
  872. //Find the begining of Next Token
  873. // while( pBuffer[0] == L' ' ||
  874. // pBuffer[0] == L'\t' ||
  875. // pBuffer[0] == L'\n' && BufferLen)
  876. while(BufferLen && IsDelimiter(pBuffer[0],pszDelimiters) )
  877. {
  878. ++pBuffer;--BufferLen;
  879. }
  880. if(!BufferLen)
  881. break;
  882. //Does Token Start with '"'
  883. if( pBuffer[0] == L'"' )
  884. {
  885. if(pbQuote)
  886. *pbQuote = TRUE;
  887. bQuoteBegin = TRUE;
  888. pBuffer++; --BufferLen;
  889. }
  890. if(!BufferLen)
  891. break;
  892. if(ppToken)
  893. {
  894. pItem = (LPTSTR)LocalAlloc(LPTR,sizeof(WCHAR)*INIT_SIZE);
  895. if(!pItem)
  896. {
  897. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  898. return -1;
  899. }
  900. }
  901. //Now get the end
  902. WCHAR ch;
  903. while( BufferLen )
  904. {
  905. BOOL bChar = TRUE;
  906. if( BufferLen >= 2 && *pBuffer == L'\\' && *(pBuffer+1) == L'"')
  907. {
  908. ch = L'"';
  909. pBuffer +=2; BufferLen -=2;
  910. }
  911. else if(pBuffer[0] == L'"')
  912. {
  913. //A Matching Quote Found.
  914. if(bQuoteBegin)
  915. {
  916. ++pBuffer;
  917. --BufferLen;
  918. if(BufferLen)
  919. {
  920. //If next char is whitespace endof token
  921. //Ex "ABC" "xyz" . after C its endof token
  922. //if(pBuffer[0] == L' ' ||
  923. // pBuffer[0] == L'\t' ||
  924. // pBuffer[0] == L'\n')
  925. if(IsDelimiter(pBuffer[0],pszDelimiters) )
  926. break;
  927. else
  928. {
  929. //Ex "ABC"xyz
  930. if(pBuffer[0] != L'"')
  931. bQuoteBegin = FALSE;
  932. //"ABC""xyz"
  933. else
  934. {
  935. ++pBuffer;
  936. --BufferLen;
  937. }
  938. }
  939. }
  940. bChar = FALSE;
  941. //
  942. // Don't break because "" means that we want to clear the field out
  943. //
  944. // else
  945. // break;
  946. }
  947. //ABC" xyz" will get one token 'ABC xyz'
  948. else
  949. {
  950. bQuoteBegin = TRUE;
  951. ++pBuffer;
  952. --BufferLen;
  953. bChar = FALSE;
  954. }
  955. }
  956. // else if(!bQuoteBegin && (pBuffer[0] == L' ' ||
  957. // pBuffer[0] == L'\t' ||
  958. // pBuffer[0] == L'\n'))
  959. else if(!bQuoteBegin && IsDelimiter(pBuffer[0],pszDelimiters))
  960. {
  961. ++pBuffer;
  962. --BufferLen;
  963. break;
  964. }
  965. else
  966. {
  967. ch = pBuffer[0];
  968. ++pBuffer;
  969. --BufferLen;
  970. }
  971. if(bChar && ppToken)
  972. {
  973. if(pos == MaxSize -1)
  974. if(ERROR_SUCCESS != ResizeByTwo(&pItem,&MaxSize))
  975. {
  976. LocalFree(pItem);
  977. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  978. return -1;
  979. }
  980. pItem[pos] = ch;
  981. }
  982. if(bChar)
  983. ++pos;
  984. }
  985. if(pos ||
  986. (!pos && bQuoteBegin))
  987. {
  988. if(ppToken)
  989. {
  990. //Security review: Have checked the code very carefully to be sure that there
  991. //will always be space for terminating null. But this check is so cheap it won't
  992. //harm
  993. if( pos >= (LONG)MaxSize)
  994. {
  995. LocalFree(pItem);
  996. SetLastError(ERROR_INVALID_PARAMETER);
  997. return -1;
  998. }
  999. pItem[pos] = '\0';
  1000. *ppToken = pItem;
  1001. }
  1002. ++pos;
  1003. }
  1004. }while(0);
  1005. return pos;
  1006. }
  1007. /*
  1008. Function to convert string an array of CTokens.
  1009. INPUT: pBuf Input Buffer
  1010. BufLen Length of bBuf
  1011. OUTPUT:ppToken Gets Pointer to array of CToken
  1012. argc Lenght of array of CToken
  1013. Return Value: WIN32 Error
  1014. */
  1015. DWORD Tokenize(IN LPWSTR pBuf,
  1016. IN LONG BufLen,
  1017. LPWSTR szDelimiters,
  1018. OUT CToken **ppToken,
  1019. OUT int *argc)
  1020. {
  1021. *argc = 0;
  1022. CToken *pToken = NULL;
  1023. DWORD dwErr = ERROR_SUCCESS;
  1024. BOOL bQuote;
  1025. LPWSTR pszItem = NULL;
  1026. //Get First Token
  1027. LONG ret = GetToken(pBuf,
  1028. BufLen,
  1029. szDelimiters,
  1030. &bQuote,
  1031. NULL);
  1032. if(ret == -1)
  1033. {
  1034. dwErr = GetLastError();
  1035. goto exit_gracefully;
  1036. }
  1037. while(ret)
  1038. {
  1039. ++(*argc);
  1040. ret = GetToken(NULL,
  1041. NULL,
  1042. szDelimiters,
  1043. &bQuote,
  1044. NULL);
  1045. if(ret == -1)
  1046. {
  1047. dwErr = GetLastError();
  1048. goto exit_gracefully;
  1049. }
  1050. }
  1051. if(*argc)
  1052. {
  1053. int i =0;
  1054. pToken = new CToken[*argc];
  1055. if(!pToken)
  1056. {
  1057. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1058. goto exit_gracefully;
  1059. }
  1060. ret = GetToken(pBuf,
  1061. BufLen,
  1062. szDelimiters,
  1063. &bQuote,
  1064. &pszItem);
  1065. if(ret == -1)
  1066. {
  1067. dwErr = GetLastError();
  1068. goto exit_gracefully;
  1069. }
  1070. while(ret)
  1071. {
  1072. dwErr = pToken[i++].Init(pszItem,bQuote);
  1073. if(dwErr != ERROR_SUCCESS)
  1074. {
  1075. if(pszItem)
  1076. LocalFree(pszItem);
  1077. goto exit_gracefully;
  1078. }
  1079. if(pszItem)
  1080. LocalFree(pszItem);
  1081. pszItem = NULL;
  1082. ret = GetToken(NULL,
  1083. NULL,
  1084. szDelimiters,
  1085. &bQuote,
  1086. &pszItem);
  1087. if(ret == -1)
  1088. {
  1089. dwErr = GetLastError();
  1090. goto exit_gracefully;
  1091. }
  1092. }
  1093. }
  1094. exit_gracefully:
  1095. if(dwErr != ERROR_SUCCESS)
  1096. {
  1097. if(pToken)
  1098. {
  1099. delete [] pToken ;
  1100. }
  1101. return dwErr;
  1102. }
  1103. *ppToken = pToken;
  1104. return dwErr;
  1105. }
  1106. /*
  1107. Function to display the parsing errors. If function cannot
  1108. handle some error, it will return False (also sets
  1109. pError->MessageShown to false) and calling function
  1110. must handle that error.
  1111. Function will return false in following cases
  1112. 1)
  1113. if(pError->ErrorSource == ERROR_FROM_PARSER &&
  1114. pError->Error == PARSE_ERROR_ATLEASTONE_NOTDEFINED)
  1115. In this case error can be best displayed by the calling
  1116. routine.
  1117. 2)
  1118. if(pError->ErrorSource == ERROR_FROM_VLDFN &&
  1119. pError->Error != VLDFN_ERROR_NO_ERROR)
  1120. Error returned by custom validation functions
  1121. cannot be handled here.
  1122. 3)
  1123. if(pError->ErrorSource == ERROR_WIN32_ERROR) and
  1124. I cannot get any error message for the error code.
  1125. */
  1126. BOOL DisplayParseError(IN LPCTSTR pszCommandName,
  1127. IN PPARSE_ERROR pError,
  1128. IN ARG_RECORD *Commands,
  1129. IN CToken *pToken)
  1130. {
  1131. if(!pError || !pszCommandName)
  1132. return FALSE;
  1133. VOID *parg1 = NULL;
  1134. VOID *parg2 = NULL;
  1135. UINT idStr = 0;
  1136. BOOL bReturn = TRUE;
  1137. BOOL bDisplayUsageHelp = TRUE;
  1138. switch(pError->ErrorSource)
  1139. {
  1140. case ERROR_FROM_PARSER:
  1141. {
  1142. switch(pError->Error)
  1143. {
  1144. case PARSE_ERROR_SWITCH_VALUE:
  1145. {
  1146. idStr = IDS_PARSE_ERROR_SWITCH_VALUE;
  1147. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1148. }
  1149. break;
  1150. case PARSE_ERROR_SWICH_NO_VALUE:
  1151. {
  1152. idStr = IDS_PARSE_ERROR_SWICH_NO_VALUE;
  1153. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1154. }
  1155. break;
  1156. case PARSE_ERROR_UNKNOWN_INPUT_PARAMETER:
  1157. {
  1158. idStr = IDS_PARSE_ERROR_UNKNOWN_INPUT_PARAMETER;
  1159. parg1 = (pToken + pError->ArgvIndex)->GetToken();
  1160. }
  1161. break;
  1162. case PARSE_ERROR_SWITCH_NOTDEFINED:
  1163. {
  1164. idStr = IDS_PARSE_ERROR_SWITCH_NOTDEFINED;
  1165. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1166. }
  1167. break;
  1168. case PARSE_ERROR_MULTIPLE_DEF:
  1169. {
  1170. idStr = IDS_PARSE_ERROR_MULTIPLE_DEF;
  1171. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1172. }
  1173. break;
  1174. case PARSE_ERROR_UNICODE_NOTDEFINED:
  1175. {
  1176. idStr = IDS_PARSE_ERROR_UNICODE_NOTDEFINED;
  1177. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1178. }
  1179. break;
  1180. case PARSE_ERROR_UNICODE_DEFINED:
  1181. {
  1182. idStr = IDS_PARSE_ERROR_UNICODE_DEFINED;
  1183. parg1 = Commands[pError->ArgRecIndex].strArg1;
  1184. }
  1185. break;
  1186. // 603157-2002/04/23-JonN
  1187. case PARSE_ERROR_ALREADY_DISPLAYED:
  1188. {
  1189. return TRUE;
  1190. }
  1191. case PARSE_ERROR_HELP_SWITCH:
  1192. {
  1193. bDisplayUsageHelp = FALSE;
  1194. }
  1195. default:
  1196. bReturn = FALSE;
  1197. }
  1198. if(idStr)
  1199. {
  1200. //Format the string
  1201. LPWSTR pBuffer = NULL;
  1202. FormatStringID(&pBuffer,
  1203. NULL,
  1204. idStr,
  1205. parg1,
  1206. parg2);
  1207. //Display it
  1208. if(pBuffer)
  1209. {
  1210. LPWSTR pszFormat = NULL;
  1211. FormatStringID(&pszFormat,
  1212. NULL,
  1213. IDS_PARSER_FAILED,
  1214. pszCommandName,
  1215. pBuffer);
  1216. if(pszFormat)
  1217. {
  1218. DisplayError(pszFormat);
  1219. LocalFreeString(&pszFormat);
  1220. }
  1221. LocalFreeString(&pBuffer);
  1222. }
  1223. }
  1224. }
  1225. break;
  1226. case ERROR_FROM_VLDFN:
  1227. {
  1228. if(pError->Error != VLDFN_ERROR_NO_ERROR)
  1229. bReturn = FALSE;
  1230. }
  1231. break;
  1232. case ERROR_WIN32_ERROR:
  1233. {
  1234. LPWSTR pBuffer = NULL;
  1235. if(GetSystemErrorText(&pBuffer, pError->Error))
  1236. {
  1237. if(pBuffer)
  1238. {
  1239. LPWSTR pszFormat = NULL;
  1240. FormatStringID(&pszFormat,
  1241. NULL,
  1242. IDS_PARSER_FAILED,
  1243. pszCommandName,
  1244. pBuffer);
  1245. if(pszFormat)
  1246. {
  1247. DisplayError(pszFormat);
  1248. LocalFreeString(&pszFormat);
  1249. }
  1250. LocalFreeString(&pBuffer);
  1251. }
  1252. else
  1253. bReturn = FALSE;
  1254. }
  1255. else
  1256. bReturn = FALSE;
  1257. }
  1258. break;
  1259. default:
  1260. bReturn = FALSE;
  1261. break;
  1262. }
  1263. if(bReturn && bDisplayUsageHelp)
  1264. DisplayUsageHelp(pszCommandName);
  1265. pError->MessageShown = bReturn;
  1266. return bReturn;
  1267. }
  1268. VOID DisplayError(LPWSTR pszError)
  1269. {
  1270. if(pszError)
  1271. WriteStandardError(L"%s\r\n",pszError);
  1272. }
  1273. VOID DisplayOutput(LPWSTR pszOutput)
  1274. {
  1275. if(pszOutput)
  1276. WriteStandardOut(L"%s\r\n",pszOutput);
  1277. }
  1278. VOID DisplayOutputNoNewline(LPWSTR pszOutput)
  1279. {
  1280. if(pszOutput)
  1281. WriteStandardOut(L"%s",pszOutput);
  1282. }
  1283. /*******************************************************************
  1284. NAME: DisplayMessage
  1285. SYNOPSIS: Loads Message from Message Table and Formats its
  1286. IN Indent - Number of tabs to indent
  1287. MessageId - Id of the message to load
  1288. ... - Optional list of parameters
  1289. RETURNS: NONE
  1290. ********************************************************************/
  1291. VOID DisplayMessage(UINT *pUsageTable,
  1292. BOOL bUseStdOut)
  1293. {
  1294. if(!pUsageTable)
  1295. {
  1296. return;
  1297. }
  1298. while(*pUsageTable != USAGE_END)
  1299. {
  1300. PWSTR MessageDisplayString;
  1301. ULONG Length;
  1302. Length = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1303. NULL,
  1304. *pUsageTable,
  1305. 0,
  1306. (PWSTR)&MessageDisplayString,
  1307. 0,
  1308. NULL);
  1309. if ( Length != 0 )
  1310. {
  1311. if(bUseStdOut)
  1312. WriteStandardOut(L"%s",MessageDisplayString);
  1313. else
  1314. WriteStandardError(L"%s",MessageDisplayString);
  1315. LocalFree( MessageDisplayString );
  1316. }
  1317. ++pUsageTable;
  1318. }
  1319. }
  1320. /*
  1321. Class CToken
  1322. */
  1323. CToken::CToken():m_bInitQuote(FALSE),m_pszToken(NULL){}
  1324. CToken::~CToken()
  1325. {
  1326. LocalFree(m_pszToken);
  1327. }
  1328. //Changed to return DWORD
  1329. ////Added parameter validation NTRAID#NTBUG9-570360-2002/03/07-hiteshr
  1330. DWORD CToken::Init(LPWSTR psz, BOOL bQuote)
  1331. {
  1332. m_bInitQuote = bQuote;
  1333. if(!StringCopy(&m_pszToken,psz))
  1334. return ERROR_NOT_ENOUGH_MEMORY;
  1335. return
  1336. ERROR_SUCCESS;
  1337. }
  1338. //This function should be called only if
  1339. //CToken::Init has succeeded.
  1340. LPWSTR CToken::GetToken(){return m_pszToken;}
  1341. BOOL CToken::IsSwitch()
  1342. {
  1343. //Assert(m_pszToken);
  1344. if(!m_pszToken)
  1345. return FALSE;
  1346. if(m_bInitQuote)
  1347. return FALSE;
  1348. if(m_pszToken[0] == L'/' ||
  1349. m_pszToken[0] == L'-')
  1350. return TRUE;
  1351. return FALSE;
  1352. }
  1353. BOOL CToken::IsSlash()
  1354. {
  1355. if (!m_pszToken)
  1356. return FALSE;
  1357. if (m_bInitQuote)
  1358. return FALSE;
  1359. if (m_pszToken[0] == L'/')
  1360. return TRUE;
  1361. return FALSE;
  1362. }
  1363. void
  1364. MyWriteConsole(
  1365. HANDLE fp,
  1366. LPWSTR lpBuffer,
  1367. DWORD cchBuffer
  1368. )
  1369. {
  1370. if(!lpBuffer || !cchBuffer)
  1371. {
  1372. assert(false);
  1373. return;
  1374. }
  1375. //
  1376. // Jump through hoops for output because:
  1377. //
  1378. // 1. printf() family chokes on international output (stops
  1379. // printing when it hits an unrecognized character)
  1380. //
  1381. // 2. WriteConsole() works great on international output but
  1382. // fails if the handle has been redirected (i.e., when the
  1383. // output is piped to a file)
  1384. //
  1385. // 3. WriteFile() works great when output is piped to a file
  1386. // but only knows about bytes, so Unicode characters are
  1387. // printed as two Ansi characters.
  1388. //
  1389. if (FILE_TYPE_CHAR == FileType(fp))
  1390. {
  1391. WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
  1392. }
  1393. else if (g_fUnicodeOutput)
  1394. {
  1395. //Buffer bounds are passed correctly.
  1396. WriteFile(fp, lpBuffer, cchBuffer*sizeof(WCHAR), &cchBuffer, NULL);
  1397. }
  1398. else
  1399. {
  1400. int nSizeAnsiBuffer = WideCharToMultiByte(CP_OEMCP,
  1401. 0,
  1402. lpBuffer,
  1403. cchBuffer,
  1404. NULL,
  1405. 0,
  1406. NULL,
  1407. NULL);
  1408. if(nSizeAnsiBuffer > 0)
  1409. {
  1410. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LPTR, nSizeAnsiBuffer);
  1411. if (lpAnsiBuffer != NULL)
  1412. {
  1413. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  1414. 0,
  1415. lpBuffer,
  1416. cchBuffer,
  1417. lpAnsiBuffer,
  1418. nSizeAnsiBuffer,
  1419. NULL,
  1420. NULL);
  1421. if (cchBuffer != 0)
  1422. {
  1423. WriteFile(fp, lpAnsiBuffer, nSizeAnsiBuffer, &cchBuffer, NULL);
  1424. }
  1425. LocalFree(lpAnsiBuffer);
  1426. }
  1427. }
  1428. }
  1429. }
  1430. void
  1431. WriteStandardOut(PCWSTR pszFormat, ...)
  1432. {
  1433. static HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1434. //
  1435. // Verify parameters
  1436. //
  1437. if (!pszFormat)
  1438. {
  1439. return;
  1440. }
  1441. va_list args;
  1442. va_start(args, pszFormat);
  1443. int nBuf = -1;
  1444. size_t currentBufferSize = 0;
  1445. WCHAR* szBuffer = 0;
  1446. while (nBuf == -1)
  1447. {
  1448. if (szBuffer)
  1449. {
  1450. delete[] szBuffer;
  1451. szBuffer = 0;
  1452. }
  1453. currentBufferSize += 4 * MAX_PATH;
  1454. szBuffer = new WCHAR[currentBufferSize];
  1455. if (!szBuffer)
  1456. {
  1457. return;
  1458. }
  1459. //Security Review: Correct length is getting passed.
  1460. ZeroMemory(szBuffer, currentBufferSize * sizeof(WCHAR));
  1461. //Security Review: If retuned value is -1, buffer is getting expanded.
  1462. nBuf = _vsnwprintf(szBuffer, currentBufferSize, pszFormat, args);
  1463. }
  1464. //
  1465. // Output the results
  1466. //
  1467. if (nBuf > 0)
  1468. {
  1469. MyWriteConsole(standardOut,
  1470. szBuffer,
  1471. nBuf);
  1472. }
  1473. delete[] szBuffer;
  1474. szBuffer = 0;
  1475. va_end(args);
  1476. }
  1477. void
  1478. WriteStandardError(PCWSTR pszFormat, ...)
  1479. {
  1480. static HANDLE standardErr = GetStdHandle(STD_ERROR_HANDLE);
  1481. //
  1482. // Verify parameters
  1483. //
  1484. if (!pszFormat)
  1485. {
  1486. return;
  1487. }
  1488. va_list args;
  1489. va_start(args, pszFormat);
  1490. // JonN 9/3/01 This needs to be large enough to accomodate the usage text
  1491. //Security Review: This is huge. We should start with small buffer and
  1492. //increment if thats not sufficient. NTRAID#NTBUG9-569880-2002/03/07-hiteshr
  1493. size_t cchSize = MAX_PATH * 4;
  1494. const size_t cchGiveupSize = STRSAFE_MAX_CCH;
  1495. WCHAR* pszBuffer = NULL;
  1496. while(cchSize < cchGiveupSize)
  1497. {
  1498. pszBuffer = new WCHAR[cchSize];
  1499. if (!pszBuffer)
  1500. {
  1501. return;
  1502. }
  1503. //Security Review:Correct buffer size is passed.
  1504. ZeroMemory(pszBuffer, cchSize* sizeof(WCHAR));
  1505. //Security Review:This is fine since we check the nBuf below.
  1506. //if output is greated than 100*MAX_PATH, we won't print anything
  1507. //which is a bug and is covered in NTRAID#NTBUG9-569880-2002/03/07-hiteshr
  1508. HRESULT hr = StringCchVPrintf(pszBuffer, cchSize, pszFormat, args);
  1509. if(SUCCEEDED(hr))
  1510. {
  1511. break;
  1512. }
  1513. if(hr == STRSAFE_E_INSUFFICIENT_BUFFER)
  1514. {
  1515. //Buffer is small. Try with bigger buffer
  1516. delete[] pszBuffer;
  1517. pszBuffer = NULL;
  1518. cchSize = cchSize*2;
  1519. }
  1520. else
  1521. {
  1522. delete[] pszBuffer;
  1523. pszBuffer = NULL;
  1524. break;
  1525. }
  1526. }
  1527. //
  1528. // Output the results
  1529. //
  1530. if (pszBuffer)
  1531. {
  1532. MyWriteConsole(standardErr,
  1533. pszBuffer,
  1534. wcslen(pszBuffer));
  1535. delete[] pszBuffer;
  1536. }
  1537. va_end(args);
  1538. }
  1539. /*******************************************************************
  1540. NAME: AddDNEscaping_Commands
  1541. SYNOPSIS: Adds full ADSI escaping to DN arguments
  1542. ********************************************************************/
  1543. BOOL AddDNEscaping_Commands( IN OUT ARG_RECORD *Commands, OUT PPARSE_ERROR pError )
  1544. {
  1545. for( int i=0; ARG_TYPE_LAST != Commands[i].fType; i++ )
  1546. {
  1547. if (!(ARG_FLAG_DN & Commands[i].fFlag))
  1548. continue;
  1549. if (ARG_TYPE_STR == Commands[i].fType)
  1550. {
  1551. if (NULL == Commands[i].strValue)
  1552. continue;
  1553. LPWSTR pszEscaped = NULL;
  1554. DWORD dwErr = AddDNEscaping_DN(&pszEscaped, Commands[i].strValue);
  1555. if (ERROR_SUCCESS != dwErr)
  1556. {
  1557. FILL_ERROR(pError,
  1558. ERROR_FROM_PARSER,
  1559. PARSE_ERROR_SWITCH_VALUE,
  1560. i,
  1561. -1);
  1562. return FALSE;
  1563. }
  1564. LocalFree(Commands[i].strValue);
  1565. Commands[i].strValue = pszEscaped;
  1566. continue;
  1567. }
  1568. if (ARG_TYPE_MSZ != Commands[i].fType)
  1569. {
  1570. continue; // shouldn't happen
  1571. }
  1572. if (NULL == Commands[i].strValue)
  1573. continue;
  1574. // count through double-NULL-terminated string list
  1575. PWSTR pszDoubleNullObjectDN = Commands[i].strValue;
  1576. LPTSTR buffer = NULL;
  1577. LONG maxSize = 0;
  1578. LONG currentSize = 0;
  1579. if (!StartBuffer(&buffer,&maxSize,&currentSize))
  1580. {
  1581. FILL_ERROR(pError,
  1582. ERROR_WIN32_ERROR,
  1583. ERROR_NOT_ENOUGH_MEMORY,
  1584. -1,
  1585. -1);
  1586. return FALSE;
  1587. }
  1588. for ( ;
  1589. NULL != pszDoubleNullObjectDN &&
  1590. L'\0' != *pszDoubleNullObjectDN;
  1591. pszDoubleNullObjectDN += (wcslen(pszDoubleNullObjectDN)+1) ) //Security Review:
  1592. { //String is null terminated.
  1593. LPWSTR pszEscaped = NULL;
  1594. DWORD dwErr = AddDNEscaping_DN(&pszEscaped, pszDoubleNullObjectDN);
  1595. if (ERROR_SUCCESS != dwErr)
  1596. {
  1597. FILL_ERROR(pError,
  1598. ERROR_FROM_PARSER,
  1599. PARSE_ERROR_SWITCH_VALUE,
  1600. i,
  1601. -1);
  1602. return FALSE;
  1603. }
  1604. dwErr = AddToBuffer(pszEscaped,
  1605. &buffer,&maxSize,&currentSize,TRUE);
  1606. if (ERROR_SUCCESS != dwErr)
  1607. {
  1608. FILL_ERROR(pError,
  1609. ERROR_WIN32_ERROR,
  1610. dwErr,
  1611. -1,
  1612. -1);
  1613. return FALSE;
  1614. }
  1615. LocalFree(pszEscaped);
  1616. }
  1617. LocalFree(Commands[i].strValue);
  1618. Commands[i].strValue = buffer;
  1619. }
  1620. return TRUE;
  1621. } // AddDNEscaping_Commands
  1622. // JonN 10/17/01 476225 0x000A -> "\0A"
  1623. // returns hex value of character, or -1 on failure
  1624. int HexValue( WCHAR wch )
  1625. {
  1626. if ( L'0' <= wch && L'9' >= wch )
  1627. return wch - L'0';
  1628. else if ( L'A' <= wch && L'F' >= wch )
  1629. return 10 + wch - L'A';
  1630. else if ( L'a' <= wch && L'f' >= wch )
  1631. return 10 + wch - L'a';
  1632. else return -1;
  1633. }
  1634. DWORD AddDNEscaping_DN( OUT LPWSTR* ppszOut, IN LPWSTR pszIn )
  1635. {
  1636. //
  1637. // JonN 5/12/01 special-case "domainroot" and "forestroot" which can be
  1638. // parameters to "-startnode" but fail IADsPathname::GetEscapedElement().
  1639. //
  1640. if (!pszIn ||
  1641. !*pszIn ||
  1642. !_tcsicmp(L"domainroot",pszIn) ||
  1643. !_tcsicmp(L"forestroot",pszIn))
  1644. {
  1645. return (StringCopy(ppszOut,pszIn))
  1646. ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
  1647. }
  1648. LONG maxSize = 0;
  1649. LONG currentSize = 0;
  1650. if (!StartBuffer(ppszOut,&maxSize,&currentSize))
  1651. return ERROR_NOT_ENOUGH_MEMORY;
  1652. // copy pszIn into temporary buffer
  1653. LPWSTR pszCopy = NULL;
  1654. if (!StringCopy(&pszCopy,pszIn) || NULL == pszCopy)
  1655. return ERROR_NOT_ENOUGH_MEMORY;
  1656. WCHAR* pchElement = pszCopy;
  1657. WCHAR* pch = pszCopy;
  1658. do {
  1659. if (L'\\' == *pch && (L',' == *(pch+1)
  1660. || L'\\' == *(pch+1)))
  1661. {
  1662. //
  1663. // manual escaping on command line: "\," or "\\"
  1664. //
  1665. // also copies trailing L'\0'
  1666. //Security review:pch is null terminated
  1667. memmove(pch, pch+1, wcslen(pch)*sizeof(WCHAR));
  1668. }
  1669. // JonN 10/17/01 476225 0x000A -> "\0A"
  1670. else if (L'\\' == *pch &&
  1671. 0 <= HexValue(*(pch+1)) &&
  1672. 0 <= HexValue(*(pch+2)) )
  1673. {
  1674. //
  1675. // manual escaping on command line: "\0A" etc.
  1676. //
  1677. *pch = (WCHAR)( (16*HexValue(*(pch+1))) + HexValue(*(pch+2)));
  1678. // also copies trailing L'\0'
  1679. memmove(pch+1, pch+3, (wcslen(pch)-2)*sizeof(WCHAR));
  1680. }
  1681. // 613568-2002/05/03-JonN reject invalid escaping
  1682. else if (L'\\' == *pch)
  1683. {
  1684. return ERROR_INVALID_PARAMETER; // CODEWORK create detailed error message
  1685. }
  1686. else if (L',' == *pch || L'\0' == *pch)
  1687. {
  1688. //
  1689. // completes path element
  1690. //
  1691. WCHAR chTemp = *pch;
  1692. *pch = L'\0';
  1693. LPWSTR pszEscaped = NULL;
  1694. HRESULT hr = GetEscapedElement( &pszEscaped, pchElement );
  1695. if (FAILED(hr) || NULL == pszEscaped)
  1696. return ERROR_INVALID_PARAMETER; // cannot return HRESULTs
  1697. if (NULL != *ppszOut && L'\0' != **ppszOut)
  1698. {
  1699. // add seperator to DN
  1700. DWORD dwErr = AddToBuffer(L",",
  1701. ppszOut,&maxSize,&currentSize,
  1702. FALSE); // not MSZ output
  1703. if (ERROR_SUCCESS != dwErr)
  1704. return dwErr;
  1705. }
  1706. // add path element to DN
  1707. DWORD dwErr = AddToBuffer(pszEscaped,
  1708. ppszOut,&maxSize,&currentSize,
  1709. FALSE); // not MSZ output
  1710. if (ERROR_SUCCESS != dwErr)
  1711. return dwErr;
  1712. ::LocalFree(pszEscaped);
  1713. if (L'\0' == chTemp)
  1714. break;
  1715. *pch = chTemp;
  1716. pchElement = pch+1;
  1717. }
  1718. pch++;
  1719. } while (true);
  1720. LocalFree(pszCopy);
  1721. return ERROR_SUCCESS;
  1722. } // AddDNEscaping_DN
  1723. //Added parameter validation NTRAID#NTBUG9-570344-2002/03/07-hiteshr
  1724. BOOL StartBuffer( OUT LPTSTR* pbuffer,
  1725. OUT LONG* pmaxSize,
  1726. OUT LONG* pcurrentSize )
  1727. {
  1728. if(!pbuffer || !pmaxSize || !pcurrentSize)
  1729. return FALSE;
  1730. *pbuffer = (LPTSTR)LocalAlloc(LPTR,MAXSTR*sizeof(TCHAR)); // init to zero
  1731. *pmaxSize = MAXSTR;
  1732. *pcurrentSize = 0;
  1733. return (NULL != pbuffer);
  1734. }
  1735. //Added parameter validation NTRAID#NTBUG9-569880-2002/03/07-hiteshr
  1736. DWORD AddToBuffer( IN LPCTSTR psz,
  1737. IN OUT LPTSTR* pbuffer,
  1738. IN OUT LONG* pmaxSize,
  1739. IN OUT LONG* pcurrentSize,
  1740. BOOL fMSZBuffer)
  1741. {
  1742. if(!psz || !pbuffer || !pmaxSize || !pcurrentSize)
  1743. {
  1744. return ERROR_INVALID_PARAMETER;
  1745. }
  1746. //Security Review: psz is terminated by NULL
  1747. LONG len = (LONG)wcslen(psz);
  1748. //-2 as last string is delimited by two null
  1749. while(((*pcurrentSize) + len) > ((*pmaxSize) - 2))
  1750. {
  1751. DWORD dwErr = ResizeByTwo(pbuffer,pmaxSize);
  1752. if (dwErr != ERROR_SUCCESS)
  1753. return dwErr;
  1754. }
  1755. //Security Review:Buffer is correctly allocated above.
  1756. _tcscpy(((*pbuffer) + (*pcurrentSize)), psz);
  1757. (*pcurrentSize) += len;
  1758. //tail end of pbuffer is all NULLs
  1759. if (fMSZBuffer)
  1760. (*pcurrentSize)++;
  1761. return NO_ERROR;
  1762. }
  1763. BOOL
  1764. IsTokenHelpSwitch(LPTOKEN pToken)
  1765. {
  1766. if(!pToken)
  1767. {
  1768. return FALSE;
  1769. }
  1770. if(pToken->IsSwitch())
  1771. {
  1772. //Security Review:Right hand side string is constant.
  1773. if(!wcscmp(pToken->GetToken(),L"/?") ||
  1774. !wcscmp(pToken->GetToken(),L"/h") ||
  1775. !wcscmp(pToken->GetToken(),L"-?") ||
  1776. !wcscmp(pToken->GetToken(),L"-h"))
  1777. return TRUE;
  1778. }
  1779. return FALSE;
  1780. }
  1781. //+--------------------------------------------------------------------------
  1782. //
  1783. // Function: DisplayUsageHelp
  1784. //
  1785. // Synopsis: Displays "type dscmd /? for help"
  1786. //
  1787. // History: 11-Sep-2000 hiteshr Created
  1788. //---------------------------------------------------------------------------
  1789. void
  1790. DisplayUsageHelp( LPCWSTR pszCommand)
  1791. {
  1792. if(!pszCommand)
  1793. {
  1794. return;
  1795. }
  1796. LPWSTR pszFormat = NULL;
  1797. if(LoadStringAlloc(&pszFormat,NULL,IDS_DISPLAY_HELP))
  1798. {
  1799. WriteStandardError(pszFormat,
  1800. pszCommand);
  1801. }
  1802. LocalFreeString(&pszFormat);
  1803. }