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.

611 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: parserutil.cpp
  7. //
  8. // Contents: Helpful functions for manipulating and validating
  9. // generic command line arguments
  10. //
  11. // History: 07-Sep-2000 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "iostream.h"
  17. #include "cstrings.h"
  18. #include "commonstrings.h"
  19. //+--------------------------------------------------------------------------
  20. //
  21. // Function: GetPasswdStr
  22. //
  23. // Synopsis: Reads a password string from stdin without echoing the keystrokes
  24. //
  25. // Arguments: [buf - OUT] : buffer to put string in
  26. // [buflen - IN] : size of the buffer
  27. // [&len - OUT] : length of the string placed into the buffer
  28. //
  29. // Returns: DWORD : 0 or ERROR_INSUFFICIENT_BUFFER if user typed too much.
  30. // Buffer contents are only valid on 0 return.
  31. //
  32. // History: 07-Sep-2000 JeffJon Created
  33. //
  34. //---------------------------------------------------------------------------
  35. #define CR 0xD
  36. #define BACKSPACE 0x8
  37. DWORD GetPasswdStr(LPTSTR buf,
  38. DWORD buflen,
  39. PDWORD len)
  40. {
  41. TCHAR ch;
  42. TCHAR *bufPtr = buf;
  43. DWORD c;
  44. int err;
  45. DWORD mode;
  46. buflen -= 1; /* make space for null terminator */
  47. *len = 0; /* GP fault probe (a la API's) */
  48. GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
  49. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
  50. (~(ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT)) & mode);
  51. while (TRUE)
  52. {
  53. //Security Review:Correct buffer len is passed.
  54. err = ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &ch, 1, &c, 0);
  55. if (!err || c != 1)
  56. ch = 0xffff;
  57. if ((ch == CR) || (ch == 0xffff)) /* end of the line */
  58. break;
  59. if (ch == BACKSPACE)
  60. { /* back up one or two */
  61. /*
  62. * IF bufPtr == buf then the next two lines are
  63. * a no op.
  64. */
  65. if (bufPtr != buf)
  66. {
  67. bufPtr--;
  68. (*len)--;
  69. }
  70. }
  71. else
  72. {
  73. *bufPtr = ch;
  74. if (*len < buflen)
  75. bufPtr++ ; /* don't overflow buf */
  76. (*len)++; /* always increment len */
  77. }
  78. }
  79. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode);
  80. *bufPtr = TEXT('\0'); /* null terminate the string */
  81. putwchar(TEXT('\n'));
  82. return ((*len <= buflen) ? 0 : ERROR_INSUFFICIENT_BUFFER);
  83. }
  84. //+--------------------------------------------------------------------------
  85. //
  86. // Function: ValidatePassword
  87. //
  88. // Synopsis: Password validation function called by parser
  89. //
  90. // Arguments: [pArg - IN] : pointer argument structure which contains
  91. // the value to be validated
  92. //
  93. // Returns: DWORD : ERROR_INVALID_PARAMETER if the argument record or
  94. // the value it contains is not valid
  95. // ERROR_NOT_ENOUGH_MEMORY
  96. // ERROR_SUCCESS if everything succeeded and it is a
  97. // valid password
  98. // Otherwise it is an error condition returned from
  99. // GetPasswdStr
  100. //
  101. // History: 07-Sep-2000 JeffJon Created
  102. // 03-27-2002 hiteshr changed the function
  103. // //NTRAID#NTBUG9-571544-2000/11/13-hiteshr
  104. //---------------------------------------------------------------------------
  105. DWORD ValidatePassword(PVOID pArg,
  106. UINT IdStr,
  107. UINT IdPromptConfirm)
  108. {
  109. PARG_RECORD pRec = (PARG_RECORD)pArg;
  110. if(!pRec || !pRec->strValue)
  111. {
  112. return ERROR_INVALID_PARAMETER;
  113. }
  114. //Validate the length of password. Password length must be
  115. //less than MAX_PASSWORD_LENGTH
  116. size_t cchInputPassword = 0;
  117. HRESULT hr = StringCchLength(pRec->strValue,
  118. MAX_PASSWORD_LENGTH,
  119. &cchInputPassword);
  120. if(FAILED(hr))
  121. {
  122. DisplayErrorMessage(g_pszDSCommandName,NULL,E_INVALIDARG,IDS_ERROR_LONG_PASSWORD);
  123. return VLDFN_ERROR_NO_ERROR;
  124. }
  125. //If Password is *, store encrypted password
  126. if(wcscmp(pRec->strValue, L"*") != 0 )
  127. {
  128. DATA_BLOB EncryptedPasswordDataBlob;
  129. hr = EncryptPasswordString(pRec->strValue, &EncryptedPasswordDataBlob);
  130. //Clear the cleartext password
  131. SecureZeroMemory(pRec->strValue,cchInputPassword*sizeof(WCHAR));
  132. if(SUCCEEDED(hr))
  133. {
  134. LocalFree(pRec->strValue);
  135. pRec->encryptedDataBlob = EncryptedPasswordDataBlob;
  136. return ERROR_SUCCESS;
  137. }
  138. return hr;
  139. }
  140. //User entered * in commandline. Prompt for password.
  141. CComBSTR sbstrPrompt;
  142. if(sbstrPrompt.LoadString(::GetModuleHandle(NULL),IdStr))
  143. {
  144. DisplayOutput(sbstrPrompt);
  145. }
  146. else
  147. DisplayOutput(L"Enter Password\n");
  148. WCHAR buffer[MAX_PASSWORD_LENGTH];
  149. DWORD len = 0;
  150. DWORD dwErr = GetPasswdStr(buffer,MAX_PASSWORD_LENGTH,&len);
  151. if(dwErr != ERROR_SUCCESS)
  152. return dwErr;
  153. if(IdPromptConfirm)
  154. {
  155. if(sbstrPrompt.LoadString(::GetModuleHandle(NULL),IdPromptConfirm))
  156. {
  157. DisplayOutput(sbstrPrompt);
  158. }
  159. else
  160. DisplayOutput(L"Confirm Password\n");
  161. WCHAR buffer1[MAX_PASSWORD_LENGTH];
  162. DWORD len1 = 0;
  163. dwErr = GetPasswdStr(buffer1,MAX_PASSWORD_LENGTH,&len1);
  164. if(dwErr != ERROR_SUCCESS)
  165. return dwErr;
  166. //Security Review:This is fine.
  167. if(wcscmp(buffer,buffer1) != 0)
  168. {
  169. SecureZeroMemory(buffer,sizeof(buffer));
  170. SecureZeroMemory(buffer1,sizeof(buffer1));
  171. CComBSTR sbstrError;
  172. sbstrError.LoadString(::GetModuleHandle(NULL),IDS_ERROR_PASSWORD_MISSMATCH);
  173. DisplayErrorMessage(g_pszDSCommandName,NULL,S_OK,sbstrError);
  174. //Security Review:SecureZeroMemory buffer and buffer1 before returning
  175. return VLDFN_ERROR_NO_ERROR;
  176. }
  177. //Two passwords are same. Clear the buffer1
  178. SecureZeroMemory(buffer1,sizeof(buffer1));
  179. }
  180. //CryptProtectMemory strValue
  181. DATA_BLOB EncryptedPasswordDataBlob;
  182. hr = EncryptPasswordString(buffer, &EncryptedPasswordDataBlob);
  183. //Clear the cleartext password in buffer
  184. SecureZeroMemory(buffer,sizeof(buffer));
  185. if(SUCCEEDED(hr))
  186. {
  187. LocalFree(pRec->strValue);
  188. pRec->encryptedDataBlob = EncryptedPasswordDataBlob;
  189. return ERROR_SUCCESS;
  190. }
  191. return hr;
  192. }
  193. //+--------------------------------------------------------------------------
  194. //
  195. // Function: ValidateAdminPassword
  196. //
  197. // Synopsis: Password validation function called by parser for Admin
  198. //
  199. // Arguments: [pArg - IN] : pointer argument structure which contains
  200. // the value to be validated
  201. //
  202. // Returns: DWORD : ERROR_INVALID_PARAMETER if the argument record or
  203. // the value it contains is not valid
  204. // ERROR_SUCCESS if everything succeeded and it is a
  205. // valid password
  206. //
  207. // History: 07-Sep-2000 Hiteshr Created
  208. //
  209. //---------------------------------------------------------------------------
  210. DWORD ValidateAdminPassword(PVOID pArg)
  211. {
  212. return ValidatePassword(pArg,IDS_ADMIN_PASSWORD_PROMPT,0);
  213. }
  214. //+--------------------------------------------------------------------------
  215. //
  216. // Function: ValidateUserPassword
  217. //
  218. // Synopsis: Password validation function called by parser for Admin
  219. //
  220. // Arguments: [pArg - IN] : pointer argument structure which contains
  221. // the value to be validated
  222. //
  223. // Returns: DWORD : Same as ValidatePassword
  224. //
  225. // History: 07-Sep-2000 Hiteshr Created
  226. //
  227. //---------------------------------------------------------------------------
  228. DWORD ValidateUserPassword(PVOID pArg)
  229. {
  230. return ValidatePassword(pArg, IDS_USER_PASSWORD_PROMPT,IDS_USER_PASSWORD_CONFIRM);
  231. }
  232. //+--------------------------------------------------------------------------
  233. //
  234. // Function: ValidateYesNo
  235. //
  236. // Synopsis: Password validation function called by parser for Admin
  237. //
  238. // Arguments: [pArg - IN] : pointer argument structure which contains
  239. // the value to be validated
  240. //
  241. // Returns: DWORD : Same as ValidatePassword
  242. //
  243. // History: 07-Sep-2000 Hiteshr Created
  244. //
  245. //---------------------------------------------------------------------------
  246. DWORD ValidateYesNo(PVOID pArg)
  247. {
  248. PARG_RECORD pRec = (PARG_RECORD)pArg;
  249. if(!pRec || !pRec->strValue)
  250. return ERROR_INVALID_PARAMETER;
  251. CComBSTR sbstrInput;
  252. sbstrInput = pRec->strValue;
  253. sbstrInput.ToLower();
  254. if( sbstrInput == g_bstrYes )
  255. {
  256. LocalFree(pRec->strValue);
  257. pRec->bValue = TRUE;
  258. }
  259. else if( sbstrInput == g_bstrNo )
  260. {
  261. LocalFree(pRec->strValue);
  262. pRec->bValue = FALSE;
  263. }
  264. else
  265. return ERROR_INVALID_PARAMETER;
  266. //
  267. // Have to set this to bool or else
  268. // FreeCmd will try to free the string
  269. // which AVs when the bool is true
  270. //
  271. pRec->fType = ARG_TYPE_BOOL;
  272. return ERROR_SUCCESS;
  273. }
  274. //+--------------------------------------------------------------------------
  275. //
  276. // Function: ValidateNever
  277. //
  278. // Synopsis: Password validation function called by parser for Admin
  279. // Verifies the value contains digits or "NEVER"
  280. //
  281. // Arguments: [pArg - IN] : pointer argument structure which contains
  282. // the value to be validated
  283. //
  284. // Returns: DWORD : Same as ValidatePassword
  285. //
  286. // History: 07-Sep-2000 JeffJon Created
  287. //
  288. //---------------------------------------------------------------------------
  289. DWORD ValidateNever(PVOID pArg)
  290. {
  291. PARG_RECORD pRec = (PARG_RECORD)pArg;
  292. if(!pRec)
  293. return ERROR_INVALID_PARAMETER;
  294. if (pRec->fType == ARG_TYPE_STR)
  295. {
  296. CComBSTR sbstrInput;
  297. sbstrInput = pRec->strValue;
  298. //Security Review:This is fine, though we don't need
  299. //to copy it sbstrInput. A direct comparison should be
  300. //good enough.
  301. if( _wcsicmp(sbstrInput, g_bstrNever) )
  302. {
  303. return ERROR_INVALID_PARAMETER;
  304. }
  305. }
  306. return ERROR_SUCCESS;
  307. }
  308. //+--------------------------------------------------------------------------
  309. //
  310. // Function: ValidateGroupScope
  311. //
  312. // Synopsis: Makes sure that the value following the -scope switch is one
  313. // of (l/g/u)
  314. //
  315. // Arguments: [pArg - IN] : pointer argument structure which contains
  316. // the value to be validated
  317. //
  318. // Returns: DWORD : Same as ValidatePassword
  319. //
  320. // History: 18-Sep-2000 JeffJon Created
  321. //
  322. //---------------------------------------------------------------------------
  323. DWORD ValidateGroupScope(PVOID pArg)
  324. {
  325. DWORD dwReturn = ERROR_SUCCESS;
  326. PARG_RECORD pRec = (PARG_RECORD)pArg;
  327. if(!pRec || !pRec->strValue)
  328. return ERROR_INVALID_PARAMETER;
  329. CComBSTR sbstrInput;
  330. sbstrInput = pRec->strValue;
  331. sbstrInput.ToLower();
  332. if(sbstrInput == _T("l") ||
  333. sbstrInput == _T("g") ||
  334. sbstrInput == _T("u"))
  335. {
  336. dwReturn = ERROR_SUCCESS;
  337. }
  338. else
  339. {
  340. dwReturn = ERROR_INVALID_PARAMETER;
  341. }
  342. return dwReturn;
  343. }
  344. //+--------------------------------------------------------------------------
  345. //
  346. // Function: MergeArgCommand
  347. //
  348. // Synopsis: Combines two ARG_RECORD arrays into a single
  349. //
  350. // Arguments: [pCommand1 - IN] : first ARG_RECORD array to merge
  351. // [pCommand2 - IN] : second ARG_RECORD array to merge
  352. // [ppOutCommand - OUT] : the array that results from the merge
  353. //
  354. // Returns: HRESULT : S_OK on success
  355. // E_OUTOFMEMORY if failed to allocate memory for new array
  356. //
  357. // History: 08-Sep-2000 JeffJon Created
  358. //
  359. //---------------------------------------------------------------------------
  360. HRESULT MergeArgCommand(PARG_RECORD pCommand1,
  361. PARG_RECORD pCommand2,
  362. PARG_RECORD *ppOutCommand)
  363. {
  364. HRESULT hr = S_OK;
  365. //
  366. // Verify parameters
  367. //
  368. if (!pCommand1 && !pCommand2)
  369. {
  370. return E_INVALIDARG;
  371. }
  372. LONG nSize1 = 0;
  373. LONG nSize2 = 0;
  374. UINT i = 0;
  375. if (NULL != pCommand1)
  376. {
  377. for(i=0; pCommand1[i].fType != ARG_TYPE_LAST ;i++)
  378. {
  379. ++nSize1;
  380. }
  381. }
  382. if (NULL != pCommand2)
  383. {
  384. for(i=0; pCommand2[i].fType != ARG_TYPE_LAST ;i++)
  385. {
  386. ++nSize2;
  387. }
  388. }
  389. *ppOutCommand = (PARG_RECORD)LocalAlloc(LPTR, sizeof(ARG_RECORD)*(nSize1+nSize2+1));
  390. if(!*ppOutCommand)
  391. {
  392. return E_OUTOFMEMORY;
  393. }
  394. if (NULL != pCommand1)
  395. {
  396. //Security Review:This is fine.
  397. memcpy(*ppOutCommand,pCommand1,sizeof(ARG_RECORD)*(nSize1+1));
  398. }
  399. if (NULL != pCommand2)
  400. {
  401. //Security Review:This is fine.
  402. memcpy((*ppOutCommand+nSize1),pCommand2,sizeof(ARG_RECORD)*(nSize2+1));
  403. }
  404. return hr;
  405. }
  406. //+--------------------------------------------------------------------------
  407. //
  408. // Function: ParseStringByChar
  409. //
  410. // Synopsis: Parses a string into elements separated by the given character
  411. //
  412. // Arguments: [psz - IN] : string to be parsed
  413. // [tchar - IN] : character that is to be used as the separator
  414. // [pszArr - OUT] : the array to receive the parsed strings
  415. // [pnArrEntries - OUT] : the number of strings parsed from the list
  416. //
  417. // Returns:
  418. //
  419. // History: 18-Sep-2000 JeffJon Created
  420. // 14-Apr-2001 JeffJon Modified to separate on a generic character
  421. //
  422. //---------------------------------------------------------------------------
  423. void ParseStringByChar(PTSTR psz,
  424. TCHAR tchar,
  425. PTSTR** ppszArr,
  426. UINT* pnArrEntries)
  427. {
  428. //
  429. // Verify parameters
  430. //
  431. if (!psz ||
  432. !ppszArr ||
  433. !pnArrEntries)
  434. {
  435. ASSERT(psz);
  436. ASSERT(ppszArr);
  437. ASSERT(pnArrEntries);
  438. return;
  439. }
  440. //
  441. // Count the number of strings
  442. //
  443. UINT nCount = 0;
  444. PTSTR pszTemp = psz;
  445. while (true)
  446. {
  447. if (pszTemp[0] == tchar &&
  448. pszTemp[1] == tchar)
  449. {
  450. nCount++;
  451. break;
  452. }
  453. else if (pszTemp[0] == tchar &&
  454. pszTemp[1] != tchar)
  455. {
  456. nCount++;
  457. pszTemp++;
  458. }
  459. else
  460. {
  461. pszTemp++;
  462. }
  463. }
  464. *pnArrEntries = nCount;
  465. //
  466. // Allocate the array
  467. //
  468. *ppszArr = (PTSTR*)LocalAlloc(LPTR, nCount * sizeof(PTSTR));
  469. if (*ppszArr)
  470. {
  471. //
  472. // Copy the string pointers into the array
  473. //
  474. UINT nIdx = 0;
  475. pszTemp = psz;
  476. (*ppszArr)[nIdx] = pszTemp;
  477. nIdx++;
  478. while (true)
  479. {
  480. if (pszTemp[0] == tchar &&
  481. pszTemp[1] == tchar)
  482. {
  483. break;
  484. }
  485. else if (pszTemp[0] == tchar &&
  486. pszTemp[1] != tchar)
  487. {
  488. (*ppszArr)[nIdx] = &(pszTemp[1]);
  489. nIdx++;
  490. pszTemp++;
  491. }
  492. else
  493. {
  494. pszTemp++;
  495. }
  496. }
  497. }
  498. }
  499. //+--------------------------------------------------------------------------
  500. //
  501. // Function: ParseNullSeparatedString
  502. //
  503. // Synopsis: Parses a '\0' separated list that ends in "\0\0" into a string
  504. // array
  505. //
  506. // Arguments: [psz - IN] : '\0' separated string to be parsed
  507. // [pszArr - OUT] : the array to receive the parsed strings
  508. // [pnArrEntries - OUT] : the number of strings parsed from the list
  509. //
  510. // Returns:
  511. //
  512. // History: 14-Apr-2001 JeffJon Created
  513. //
  514. //---------------------------------------------------------------------------
  515. void ParseNullSeparatedString(PTSTR psz,
  516. PTSTR** ppszArr,
  517. UINT* pnArrEntries)
  518. {
  519. ParseStringByChar(psz,
  520. L'\0',
  521. ppszArr,
  522. pnArrEntries);
  523. }
  524. //+--------------------------------------------------------------------------
  525. //
  526. // Function: ParseSemicolonSeparatedString
  527. //
  528. // Synopsis: Parses a ';' separated list
  529. //
  530. // Arguments: [psz - IN] : ';' separated string to be parsed
  531. // [pszArr - OUT] : the array to receive the parsed strings
  532. // [pnArrEntries - OUT] : the number of strings parsed from the list
  533. //
  534. // Returns:
  535. //
  536. // History: 14-Apr-2001 JeffJon Created
  537. //
  538. //---------------------------------------------------------------------------
  539. void ParseSemicolonSeparatedString(PTSTR psz,
  540. PTSTR** ppszArr,
  541. UINT* pnArrEntries)
  542. {
  543. ParseStringByChar(psz,
  544. L';',
  545. ppszArr,
  546. pnArrEntries);
  547. }