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.

777 lines
20 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: Util.cpp
  7. //
  8. // Contents: Generic utility functions and classes for dscmd
  9. //
  10. // History: 01-Oct-2000 JeffJon Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.h"
  14. #include "util.h"
  15. #ifdef DBG
  16. //
  17. // Globals
  18. //
  19. CDebugSpew DebugSpew;
  20. //+--------------------------------------------------------------------------
  21. //
  22. // Member: CDebugSpew::EnterFunction
  23. //
  24. // Synopsis: Outputs "Enter " followed by the function name (or any passed
  25. // in string) and then calls Indent so that any output is indented
  26. //
  27. // Arguments: [nDebugLevel - IN] : the level at which this output should
  28. // be spewed
  29. // [pszFunction - IN] : a string to output to the console which
  30. // is proceeded by "Entering "
  31. //
  32. // Returns:
  33. //
  34. // History: 01-Oct-2000 JeffJon Created
  35. //
  36. //---------------------------------------------------------------------------
  37. void CDebugSpew::EnterFunction(UINT nDebugLevel, PCWSTR pszFunction)
  38. {
  39. //
  40. // Verify input parameter
  41. //
  42. if (!pszFunction)
  43. {
  44. ASSERT(pszFunction);
  45. return;
  46. }
  47. CComBSTR sbstrOutput(L"Entering ");
  48. sbstrOutput += pszFunction;
  49. //
  50. // Output the debug spew
  51. //
  52. Output(nDebugLevel, sbstrOutput);
  53. //
  54. // Indent
  55. //
  56. Indent();
  57. }
  58. //+--------------------------------------------------------------------------
  59. //
  60. // Member: CDebugSpew::LeaveFunction
  61. //
  62. // Synopsis: Outputs "Exit " followed by the function name (or any passed
  63. // in string) and then calls Outdent
  64. //
  65. // Arguments: [nDebugLevel - IN] : the level at which this output should
  66. // be spewed
  67. // [pszFunction - IN] : a string to output to the console which
  68. // is proceeded by "Leaving "
  69. //
  70. // Returns:
  71. //
  72. // History: 01-Oct-2000 JeffJon Created
  73. //
  74. //---------------------------------------------------------------------------
  75. void CDebugSpew::LeaveFunction(UINT nDebugLevel, PCWSTR pszFunction)
  76. {
  77. //
  78. // Verify input parameter
  79. //
  80. if (!pszFunction)
  81. {
  82. ASSERT(pszFunction);
  83. return;
  84. }
  85. //
  86. // Outdent
  87. //
  88. Outdent();
  89. CComBSTR sbstrOutput(L"Leaving ");
  90. sbstrOutput += pszFunction;
  91. //
  92. // Output the debug spew
  93. //
  94. Output(nDebugLevel, sbstrOutput);
  95. }
  96. //+--------------------------------------------------------------------------
  97. //
  98. // Member: CDebugSpew::LeaveFunctionHr
  99. //
  100. // Synopsis: Outputs "Exit " followed by the function name (or any passed
  101. // in string), the HRESULT return value, and then calls Outdent
  102. //
  103. // Arguments: [nDebugLevel - IN] : the level at which this output should
  104. // be spewed
  105. // [pszFunction - IN] : a string to output to the console which
  106. // is proceeded by "Leaving "
  107. // [hr - IN] : the HRESULT result value that is being
  108. // returned by the function
  109. //
  110. // Returns:
  111. //
  112. // History: 01-Oct-2000 JeffJon Created
  113. //
  114. //---------------------------------------------------------------------------
  115. void CDebugSpew::LeaveFunctionHr(UINT nDebugLevel, PCWSTR pszFunction, HRESULT hr)
  116. {
  117. //
  118. // Verify input parameter
  119. //
  120. if (!pszFunction)
  121. {
  122. ASSERT(pszFunction);
  123. return;
  124. }
  125. //
  126. // Outdent
  127. //
  128. Outdent();
  129. CComBSTR sbstrOutput(L"Leaving ");
  130. sbstrOutput += pszFunction;
  131. //
  132. // Append the return value
  133. //
  134. WCHAR pszReturn[30];
  135. //Security Review:Enough buffer is provided.
  136. wsprintf(pszReturn, L" returning 0x%x", hr);
  137. sbstrOutput += pszReturn;
  138. //
  139. // Output the debug spew
  140. //
  141. Output(nDebugLevel, sbstrOutput);
  142. }
  143. //+--------------------------------------------------------------------------
  144. //
  145. // Member: OsName
  146. //
  147. // Synopsis: Returns a readable string of the platform
  148. //
  149. // Arguments: [refInfo IN] : reference the OS version info structure
  150. // retrieved from GetVersionEx()
  151. //
  152. // Returns: PWSTR : returns a pointer to static text describing the
  153. // platform. The returned string does not have to
  154. // be freed.
  155. //
  156. // History: 20-Dec-2000 JeffJon Created
  157. //
  158. //---------------------------------------------------------------------------
  159. PWSTR OsName(const OSVERSIONINFO& refInfo)
  160. {
  161. switch (refInfo.dwPlatformId)
  162. {
  163. case VER_PLATFORM_WIN32s:
  164. {
  165. return L"Win32s on Windows 3.1";
  166. }
  167. case VER_PLATFORM_WIN32_WINDOWS:
  168. {
  169. switch (refInfo.dwMinorVersion)
  170. {
  171. case 0:
  172. {
  173. return L"Windows 95";
  174. }
  175. case 1:
  176. {
  177. return L"Windows 98";
  178. }
  179. default:
  180. {
  181. return L"Windows 9X";
  182. }
  183. }
  184. }
  185. case VER_PLATFORM_WIN32_NT:
  186. {
  187. return L"Windows NT";
  188. }
  189. default:
  190. {
  191. ASSERT(false);
  192. break;
  193. }
  194. }
  195. return L"Some Unknown Windows Version";
  196. }
  197. //+--------------------------------------------------------------------------
  198. //
  199. // Member: CDebugSpew::SpewHeader
  200. //
  201. // Synopsis: Outputs debug information like command line and build info
  202. //
  203. // Arguments:
  204. //
  205. // Returns:
  206. //
  207. // History: 20-Dec-2000 JeffJon Created
  208. //
  209. //---------------------------------------------------------------------------
  210. void CDebugSpew::SpewHeader()
  211. {
  212. //
  213. // First output the command line
  214. //
  215. PWSTR pszCommandLine = GetCommandLine();
  216. if (pszCommandLine)
  217. {
  218. Output(MINIMAL_LOGGING,
  219. L"Command line: %s",
  220. GetCommandLine());
  221. }
  222. //
  223. // Output the module being used
  224. //
  225. do // false loop
  226. {
  227. //
  228. // Get the file path
  229. //
  230. WCHAR pszFileName[MAX_PATH + 1];
  231. ::ZeroMemory(pszFileName, sizeof(pszFileName));
  232. //Security Review:If the path is MAX_PATH long, API will return MAX_PATH and won't
  233. //NULL terminate, but we are fine since we allocated buffer of size MAX_PATH + 1
  234. //and set it to Zero
  235. if (::GetModuleFileNameW(::GetModuleHandle(NULL), pszFileName, MAX_PATH) == 0)
  236. {
  237. break;
  238. }
  239. Output(MINIMAL_LOGGING,
  240. L"Module: %s",
  241. pszFileName);
  242. //
  243. // get the file attributes
  244. //
  245. WIN32_FILE_ATTRIBUTE_DATA attr;
  246. ::ZeroMemory(&attr, sizeof(attr));
  247. if (::GetFileAttributesEx(pszFileName, GetFileExInfoStandard, &attr) == 0)
  248. {
  249. break;
  250. }
  251. //
  252. // convert the filetime to a system time
  253. //
  254. FILETIME localtime;
  255. ::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &localtime);
  256. SYSTEMTIME systime;
  257. ::FileTimeToSystemTime(&localtime, &systime);
  258. //
  259. // output the timestamp
  260. //
  261. Output(MINIMAL_LOGGING,
  262. L"Timestamp: %2d/%2d/%4d %2d:%2d:%d.%d",
  263. systime.wMonth,
  264. systime.wDay,
  265. systime.wYear,
  266. systime.wHour,
  267. systime.wMinute,
  268. systime.wSecond,
  269. systime.wMilliseconds);
  270. } while (false);
  271. //
  272. // Get the system info
  273. //
  274. OSVERSIONINFO info;
  275. info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  276. BOOL success = ::GetVersionEx(&info);
  277. ASSERT(success);
  278. //
  279. // Get the Whistler build lab version
  280. //
  281. CComBSTR sbstrLabInfo;
  282. do // false loop
  283. {
  284. HKEY key = 0;
  285. LONG err = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  286. L"Software\\Microsoft\\Windows NT\\CurrentVersion",
  287. 0,
  288. KEY_READ,
  289. &key);
  290. if (err != ERROR_SUCCESS)
  291. {
  292. break;
  293. }
  294. WCHAR buf[MAX_PATH + 1];
  295. ::ZeroMemory(buf, sizeof(buf));
  296. DWORD type = 0;
  297. DWORD bufSize = sizeof(WCHAR)*MAX_PATH;
  298. //NTRAID#NTBUG9-573572-2002/05/24, yanggao, bufSize is the size in bytes according to RegQueryValueEx.
  299. //In order to terminate the returned value, give it value sizeof(WCHAR)*MAX_PATH.
  300. //Security Review: when buffers match the exact length of data
  301. //value data is not null terminated.
  302. //NTRAID#NTBUG9-573572-2002/03/12-hiteshr
  303. err = ::RegQueryValueEx(key,
  304. L"BuildLab",
  305. 0,
  306. &type,
  307. reinterpret_cast<BYTE*>(buf),
  308. &bufSize);
  309. if (err != ERROR_SUCCESS)
  310. {
  311. break;
  312. }
  313. sbstrLabInfo = buf;
  314. } while (false);
  315. Output(MINIMAL_LOGGING,
  316. L"Build: %s %d.%d build %d %s (BuildLab:%s)",
  317. OsName(info),
  318. info.dwMajorVersion,
  319. info.dwMinorVersion,
  320. info.dwBuildNumber,
  321. info.szCSDVersion,
  322. sbstrLabInfo);
  323. //
  324. // Output a blank line to separate the header from the rest of the output
  325. //
  326. Output(MINIMAL_LOGGING,
  327. L"\r\n");
  328. }
  329. //+--------------------------------------------------------------------------
  330. //
  331. // Member: CDebugSpew::Output
  332. //
  333. // Synopsis: Outputs the passed in string to stdout proceeded by the number
  334. // of spaces specified by GetIndent()
  335. //
  336. // Arguments: [nDebugLevel - IN] : the level at which this output should
  337. // be spewed
  338. // [pszOutput - IN] : a format string to output to the console
  339. // [... - IN] : a variable argument list to be formatted
  340. // into pszOutput similar to wprintf
  341. //
  342. // Returns:
  343. //
  344. // History: 01-Oct-2000 JeffJon Created
  345. //
  346. //---------------------------------------------------------------------------
  347. void CDebugSpew::Output(UINT nDebugLevel, PCWSTR pszOutput, ...)
  348. {
  349. if (nDebugLevel <= GetDebugLevel())
  350. {
  351. //
  352. // Verify parameters
  353. //
  354. if (!pszOutput)
  355. {
  356. ASSERT(pszOutput);
  357. return;
  358. }
  359. va_list args;
  360. va_start(args, pszOutput);
  361. WCHAR szBuffer[1024];
  362. //Security Review:Check for the return value of function and also
  363. //consider replacing it with strsafe api.
  364. //NTRAID#NTBUG9-573602-2002/03/12-hiteshr
  365. if(FAILED(StringCchVPrintf(szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]), pszOutput, args)))
  366. return;
  367. CComBSTR sbstrOutput;
  368. //
  369. // Insert the spaces for the indent
  370. //
  371. for (UINT nCount = 0; nCount < GetIndent(); nCount++)
  372. {
  373. sbstrOutput += L" ";
  374. }
  375. //
  376. // Append the output string
  377. //
  378. sbstrOutput += szBuffer;
  379. //
  380. // Output the results
  381. //
  382. WriteStandardOut(L"%s\r\n", sbstrOutput);
  383. va_end(args);
  384. }
  385. }
  386. #endif // DBG
  387. //+--------------------------------------------------------------------------
  388. //
  389. // Macro: MyA2WHelper
  390. //
  391. // Synopsis: Converts a string from Ansi to Unicode in the OEM codepage
  392. //
  393. // Arguments: [lpa - IN] : Ansi string to be converted
  394. // [acp - IN] : the codepage to use
  395. //
  396. // Returns: PWSTR : the Unicode string in the OEM codepage. Caller
  397. // must free the returned pointer using delete[]
  398. //
  399. // History: 04-Oct-2000 JeffJon Created
  400. //
  401. //---------------------------------------------------------------------------
  402. inline PWSTR WINAPI MyA2WHelper(LPCSTR lpa, UINT acp)
  403. {
  404. ASSERT(lpa != NULL);
  405. // Use MultiByteToWideChar without a buffer to find out the required
  406. // size
  407. PWSTR wideString = 0;
  408. int result = MultiByteToWideChar(acp, 0, lpa, -1, 0, 0);
  409. if (result)
  410. {
  411. wideString = new WCHAR[result];
  412. if (wideString)
  413. {
  414. result = MultiByteToWideChar(acp, 0, lpa, -1, wideString, result);
  415. }
  416. }
  417. return wideString;
  418. }
  419. //+--------------------------------------------------------------------------
  420. //
  421. // Function: _UnicodeToOemConvert
  422. //
  423. // Synopsis: takes the passed in string (pszUnicode) and converts it to
  424. // the OEM code page
  425. //
  426. // Arguments: [pszUnicode - IN] : the string to be converted
  427. // [sbstrOemUnicode - OUT] : the converted string
  428. //
  429. // Returns:
  430. //
  431. // History: 04-Oct-2000 JeffJon Created
  432. //
  433. //---------------------------------------------------------------------------
  434. void _UnicodeToOemConvert(PCWSTR pszUnicode, CComBSTR& sbstrOemUnicode)
  435. {
  436. if (!pszUnicode)
  437. {
  438. ASSERT(pszUnicode);
  439. return;
  440. }
  441. // Use WideCharToMultiByte without a buffer to find out
  442. // the required size
  443. int result =
  444. WideCharToMultiByte(
  445. CP_OEMCP,
  446. 0,
  447. pszUnicode,
  448. -1,
  449. 0,
  450. 0,
  451. 0,
  452. 0);
  453. if (result)
  454. {
  455. // Now allocate and convert the string
  456. PSTR pszOemAnsi = new CHAR[result];
  457. if (pszOemAnsi)
  458. {
  459. ZeroMemory(pszOemAnsi, result * sizeof(CHAR));
  460. result =
  461. WideCharToMultiByte(
  462. CP_OEMCP,
  463. 0,
  464. pszUnicode,
  465. -1,
  466. pszOemAnsi,
  467. result * sizeof(CHAR),
  468. 0,
  469. 0);
  470. ASSERT(result);
  471. //
  472. // convert it back to WCHAR on OEM CP
  473. //
  474. PWSTR oemUnicode = MyA2WHelper(pszOemAnsi, CP_OEMCP);
  475. if (oemUnicode)
  476. {
  477. sbstrOemUnicode = oemUnicode;
  478. delete[] oemUnicode;
  479. oemUnicode = 0;
  480. }
  481. delete[] pszOemAnsi;
  482. pszOemAnsi = 0;
  483. }
  484. }
  485. }
  486. //+--------------------------------------------------------------------------
  487. //
  488. // Function: SpewAttrs(ADS_ATTR_INFO* pCreateAttrs, DWORD dwNumAttrs);
  489. //
  490. // Synopsis: Uses the DEBUG_OUTPUT macro to output the attributes and the
  491. // values specified
  492. //
  493. // Arguments: [pAttrs - IN] : The ADS_ATTR_INFO
  494. // [dwNumAttrs - IN] : The number of attributes in pAttrs
  495. //
  496. // Returns:
  497. //
  498. // History: 04-Oct-2000 JeffJon Created
  499. //
  500. //---------------------------------------------------------------------------
  501. #ifdef DBG
  502. void SpewAttrs(ADS_ATTR_INFO* pAttrs, DWORD dwNumAttrs)
  503. {
  504. for (DWORD dwAttrIdx = 0; dwAttrIdx < dwNumAttrs; dwAttrIdx++)
  505. {
  506. if (pAttrs[dwAttrIdx].dwADsType == ADSTYPE_DN_STRING ||
  507. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_EXACT_STRING ||
  508. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_IGNORE_STRING ||
  509. pAttrs[dwAttrIdx].dwADsType == ADSTYPE_PRINTABLE_STRING)
  510. {
  511. for (DWORD dwValueIdx = 0; dwValueIdx < pAttrs[dwAttrIdx].dwNumValues; dwValueIdx++)
  512. {
  513. if (pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString)
  514. {
  515. DEBUG_OUTPUT(FULL_LOGGING, L" %s = %s",
  516. pAttrs[dwAttrIdx].pszAttrName,
  517. pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString);
  518. }
  519. else
  520. {
  521. DEBUG_OUTPUT(FULL_LOGGING, L" %s = value being cleared",
  522. pAttrs[dwAttrIdx].pszAttrName);
  523. }
  524. }
  525. }
  526. }
  527. }
  528. #endif // DBG
  529. //+--------------------------------------------------------------------------
  530. //
  531. // Function: litow
  532. //
  533. // Synopsis:
  534. //
  535. // Arguments: [li - IN] : reference to large integer to be converted to string
  536. // [sResult - OUT] : Gets the output string
  537. // Returns: void
  538. //
  539. // History: 25-Sep-2000 hiteshr Created
  540. // Copied from dsadmin code base, changed work with CComBSTR
  541. //---------------------------------------------------------------------------
  542. void litow(LARGE_INTEGER& li, CComBSTR& sResult)
  543. {
  544. LARGE_INTEGER n;
  545. n.QuadPart = li.QuadPart;
  546. if (n.QuadPart == 0)
  547. {
  548. sResult = L"0";
  549. }
  550. else
  551. {
  552. CComBSTR sNeg;
  553. sResult = L"";
  554. if (n.QuadPart < 0)
  555. {
  556. sNeg = CComBSTR(L'-');
  557. n.QuadPart *= -1;
  558. }
  559. while (n.QuadPart > 0)
  560. {
  561. WCHAR ch[2];
  562. ch[0] = static_cast<WCHAR>(L'0' + static_cast<WCHAR>(n.QuadPart % 10));
  563. ch[1] = L'\0';
  564. sResult += ch;
  565. n.QuadPart = n.QuadPart / 10;
  566. }
  567. sResult += sNeg;
  568. }
  569. //Reverse the string
  570. //Security Review:256 is good enough for largest LARGE_INTEGER.
  571. //But since limit of string is known, a good case for using strsafe api.
  572. //NTRAID#NTBUG9-577081-2002/03/12-hiteshr
  573. WCHAR szTemp[256];
  574. if(SUCCEEDED(StringCchCopy(szTemp, 256, sResult)))
  575. {
  576. LPWSTR pStart,pEnd;
  577. pStart = szTemp;
  578. //Security Review Done.
  579. pEnd = pStart + wcslen(pStart) -1;
  580. while(pStart < pEnd)
  581. {
  582. WCHAR ch = *pStart;
  583. *pStart++ = *pEnd;
  584. *pEnd-- = ch;
  585. }
  586. sResult = szTemp;
  587. }
  588. }
  589. //+--------------------------------------------------------------------------
  590. //
  591. // Function: EncryptPasswordString
  592. //
  593. // Synopsis:Encrypts a password.
  594. //
  595. // Arguments:[pszPassword - IN] : Input Password. Input password must be
  596. // smaller than MAX_PASSWORD_LENGTH chars in length. Function
  597. // doesnot modify this string.
  598. //
  599. // [pEncryptedDataBlob - OUT] : Gets the output encrypted
  600. // datablob.
  601. // Returns: HRESULT
  602. //
  603. // History: 27-March-2002 hiteshr Created
  604. //---------------------------------------------------------------------------
  605. HRESULT
  606. EncryptPasswordString(IN LPCWSTR pszPassword,
  607. OUT DATA_BLOB *pEncryptedDataBlob)
  608. {
  609. if(!pszPassword || !pEncryptedDataBlob)
  610. {
  611. ASSERT(pszPassword);
  612. ASSERT(pEncryptedDataBlob);
  613. return E_POINTER;
  614. }
  615. HRESULT hr = S_OK;
  616. do
  617. {
  618. //Vaidate the length of input password. MAX_PASSWORD_LENGTH includes terminating
  619. //NULL character.
  620. size_t len = 0;
  621. hr = StringCchLength(pszPassword,
  622. MAX_PASSWORD_LENGTH,
  623. &len);
  624. if(FAILED(hr))
  625. {
  626. hr = E_INVALIDARG;
  627. break;
  628. }
  629. DATA_BLOB inDataBlob;
  630. inDataBlob.pbData = (BYTE*)pszPassword;
  631. inDataBlob.cbData = (DWORD)(len + 1)*sizeof(WCHAR);
  632. //Encrypt data
  633. if(!CryptProtectData(&inDataBlob,
  634. NULL,
  635. NULL,
  636. NULL,
  637. NULL,
  638. CRYPTPROTECT_UI_FORBIDDEN,
  639. pEncryptedDataBlob))
  640. {
  641. pEncryptedDataBlob->pbData = NULL;
  642. DWORD dwErr = GetLastError();
  643. hr = HRESULT_FROM_WIN32(dwErr);
  644. break;
  645. }
  646. }while(0);
  647. return hr;
  648. }
  649. //+--------------------------------------------------------------------------
  650. //
  651. // Function: DecryptPasswordString
  652. //
  653. // Synopsis: Decrypt encrypted password data.
  654. //
  655. // Arguments: [pEncryptedDataBlob- IN] : Input encrypted password data.
  656. // [ppszPassword - OUT] :Gets the output decrypted password.
  657. // This must be freed using LocalFree
  658. // Returns: HRESULT
  659. //
  660. // History: 27-March-2002 hiteshr Created
  661. //---------------------------------------------------------------------------
  662. HRESULT
  663. DecryptPasswordString(IN const DATA_BLOB* pEncryptedDataBlob,
  664. OUT LPWSTR *ppszPassword)
  665. {
  666. if(!pEncryptedDataBlob || !ppszPassword)
  667. {
  668. ASSERT(pEncryptedDataBlob);
  669. ASSERT(ppszPassword);
  670. return E_POINTER;
  671. }
  672. HRESULT hr = S_OK;
  673. do
  674. {
  675. DATA_BLOB decryptedDataBlob;
  676. if(!CryptUnprotectData((DATA_BLOB*)pEncryptedDataBlob,
  677. NULL,
  678. NULL,
  679. NULL,
  680. NULL,
  681. CRYPTPROTECT_UI_FORBIDDEN,
  682. &decryptedDataBlob))
  683. {
  684. DWORD dwErr = GetLastError();
  685. hr = HRESULT_FROM_WIN32(dwErr);
  686. break;
  687. }
  688. *ppszPassword = (LPWSTR)decryptedDataBlob.pbData;
  689. }while(0);
  690. return hr;
  691. }