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.

2886 lines
70 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. util.cxx
  5. Abstract:
  6. Contains utility functions
  7. Contents:
  8. new
  9. delete
  10. NewString
  11. CatString
  12. ResizeBuffer
  13. _memrchr
  14. strnistr
  15. PrivateStrChr
  16. PlatformType
  17. PlatformSupport
  18. GetTimeoutValue
  19. ProbeReadBuffer
  20. ProbeWriteBuffer
  21. ProbeAndSetDword
  22. ProbeString
  23. LoadDllEntryPoints
  24. UnloadDllEntryPoints
  25. MapInternetError
  26. CalculateHashValue
  27. GetCurrentGmtTime
  28. GetFileExtensionFromUrl
  29. CheckExpired
  30. FTtoString
  31. PrintFileTimeInInternetFormat
  32. InternetSettingsChanged
  33. RefreshSslState
  34. CertHashToStr
  35. ConvertSecurityInfoIntoCertInfoStruct
  36. FormatCertInfo
  37. UnicodeToUtf8
  38. CountUnicodeToUtf8
  39. ConvertUnicodeToUtf8
  40. StringContainsHighAnsi
  41. IsAddressValidIPString
  42. IsInGUIModeSetup
  43. Author:
  44. Richard L Firth (rfirth) 31-Oct-1994
  45. Revision History:
  46. 31-Oct-1994 rfirth
  47. Created
  48. --*/
  49. #include <wininetp.h>
  50. #if !defined(PAGE_SIZE)
  51. #define PAGE_SIZE 4096
  52. #endif
  53. #define DEFAULT_MAX_EXTENSION_LENGTH 8
  54. #pragma warning(disable: 4102)
  55. //
  56. // private prototypes
  57. //
  58. //
  59. // functions
  60. //
  61. void * __cdecl operator new(size_t Size) {
  62. return (void *)ALLOCATE_FIXED_MEMORY((UINT)Size);
  63. }
  64. void __cdecl operator delete(void * Pointer) {
  65. FREE_MEMORY((HLOCAL)Pointer);
  66. }
  67. LPSTR
  68. NewString(
  69. IN LPCSTR lpszIn,
  70. IN DWORD dwLen
  71. )
  72. /*++
  73. Routine Description:
  74. kind of version of strdup() but using LocalAlloc to allocate memory
  75. Arguments:
  76. String - pointer to string to make copy of
  77. Return Value:
  78. LPSTR
  79. Success - pointer to duplicated string
  80. Failure - NULL
  81. --*/
  82. {
  83. int len = (dwLen ? dwLen : strlen(lpszIn));
  84. LPSTR lpszOut;
  85. if (lpszOut = (LPSTR)ALLOCATE_FIXED_MEMORY(len+1)) {
  86. memcpy(lpszOut, lpszIn, len);
  87. *(lpszOut + len) = '\0';
  88. }
  89. return lpszOut;
  90. }
  91. LPWSTR
  92. NewStringW(
  93. IN LPCWSTR lpszIn,
  94. IN DWORD dwLen
  95. )
  96. /*++
  97. Routine Description:
  98. kind of version of strdup() but using LocalAlloc to allocate memory
  99. Arguments:
  100. String - pointer to string to make copy of
  101. Return Value:
  102. LPSTR
  103. Success - pointer to duplicated string
  104. Failure - NULL
  105. --*/
  106. {
  107. int len = (dwLen ? dwLen : lstrlenW(lpszIn));
  108. LPWSTR lpszOut;
  109. if (lpszOut = (LPWSTR)ALLOCATE_FIXED_MEMORY((sizeof(WCHAR)*(len+1)))) {
  110. memcpy(lpszOut, lpszIn, len*sizeof(WCHAR));
  111. *(lpszOut + len) = L'\0';
  112. }
  113. return lpszOut;
  114. }
  115. /*++
  116. Routine Description:
  117. kind of version of strcat() but using LocalAlloc to allocate memory
  118. Arguments:
  119. strings to concatenate
  120. Return Value:
  121. LPSTR
  122. Success - pointer to duplicated string
  123. Failure - NULL
  124. --*/
  125. LPSTR
  126. CatString (
  127. IN LPCSTR lpszLeft,
  128. IN LPCSTR lpszRight
  129. )
  130. {
  131. int cbLeft = strlen(lpszLeft);
  132. int cbRight = strlen(lpszRight) + 1; // include null termination
  133. LPSTR lpszOut;
  134. if (lpszOut = (LPSTR) ALLOCATE_FIXED_MEMORY (cbLeft + cbRight)) {
  135. memcpy (lpszOut, lpszLeft, cbLeft);
  136. memcpy (lpszOut + cbLeft, lpszRight, cbRight);
  137. }
  138. return lpszOut;
  139. }
  140. HLOCAL
  141. ResizeBuffer(
  142. IN HLOCAL BufferHandle,
  143. IN DWORD Size,
  144. IN BOOL Moveable
  145. )
  146. /*++
  147. Routine Description:
  148. Allocate, reallocate or free a buffer. If the buffer is moveable memory
  149. then it must be unlocked. If reallocating, the buffer can be grown or
  150. shrunk, depending on the current and required sizes
  151. Caveat Programmer:
  152. Regardless of whether a pre-existing buffer is moveable or fixed memory,
  153. it will be reallocated with the LMEM_MOVEABLE flag, possibly causing the
  154. output pointer to be different from the pre-existing pointer
  155. Arguments:
  156. BufferHandle - current handle of memory buffer. If NULL, a buffer will
  157. be allocated
  158. Size - size of buffer to allocate (or shrink to). If 0, the
  159. buffer will be freed
  160. Moveable - if TRUE and allocating memory then allocates a moveable
  161. memory buffer, else fixed
  162. Return Value:
  163. HLOCAL
  164. Success - handle of moveable memory buffer
  165. Failure - NULL;
  166. --*/
  167. {
  168. INET_ASSERT(!Moveable);
  169. if (BufferHandle == NULL) {
  170. //
  171. // don't allocate anything if no size - LocalAlloc() will return pointer
  172. // to memory object marked as discarded if we request a zero-length
  173. // moveable buffer. But I know that if Size is also 0, I don't want a
  174. // buffer at all, discarded or otherwise
  175. //
  176. if (Size != 0) {
  177. BufferHandle = ALLOCATE_MEMORY(Moveable ? LMEM_MOVEABLE : LMEM_FIXED, Size);
  178. }
  179. } else if (Size == 0) {
  180. BufferHandle = FREE_MEMORY(BufferHandle);
  181. INET_ASSERT(BufferHandle == NULL);
  182. } else {
  183. HLOCAL hNewBuff = REALLOCATE_MEMORY(BufferHandle, Size, LMEM_MOVEABLE);
  184. if(!hNewBuff)
  185. {
  186. FREE_MEMORY(BufferHandle);
  187. }
  188. BufferHandle = hNewBuff;
  189. }
  190. return BufferHandle;
  191. }
  192. LPSTR
  193. _memrchr(
  194. IN LPSTR lpString,
  195. IN CHAR cTarget,
  196. IN INT iLength
  197. )
  198. /*++
  199. Routine Description:
  200. Reverse find character in string
  201. Arguments:
  202. lpString - pointer to string in which to locate character
  203. cTarget - target character to find
  204. iLength - length of string
  205. Return Value:
  206. LPSTR - pointer to located character or NULL
  207. --*/
  208. {
  209. for (--iLength; (iLength >= 0) && (lpString[iLength] != cTarget); --iLength) {
  210. //
  211. // empty loop
  212. //
  213. }
  214. return (iLength < 0) ? NULL : &lpString[iLength];
  215. }
  216. LPSTR
  217. strnistr(
  218. IN LPSTR str1,
  219. IN LPSTR str2,
  220. IN DWORD Length
  221. )
  222. /*++
  223. Routine Description:
  224. Case-insensitive search for substring
  225. Arguments:
  226. str1 - string to search in
  227. str2 - substring to find
  228. Length - of str1
  229. Return Value:
  230. LPSTR - pointer to located str2 in str1 or NULL
  231. --*/
  232. {
  233. if (!*str2) {
  234. return str1;
  235. }
  236. for (LPSTR cp = str1; *cp && Length; ++cp, --Length) {
  237. LPSTR s1 = cp;
  238. LPSTR s2 = str2;
  239. DWORD l2 = Length;
  240. while (*s1 && *s2 && l2 && (toupper(*s1) == toupper(*s2))) {
  241. ++s1;
  242. ++s2;
  243. --l2;
  244. }
  245. if (!*s2) {
  246. return cp;
  247. }
  248. if (!l2) {
  249. break;
  250. }
  251. }
  252. return NULL;
  253. }
  254. LPSTR
  255. FASTCALL
  256. PrivateStrChr(
  257. IN LPCSTR lpStart,
  258. IN WORD wMatch
  259. )
  260. /*++
  261. Routine Description:
  262. Find first occurrence of character in string
  263. Private implimentation of StrChrA, this code is based on
  264. a code snipet from ShlWapi, but by placing it here,
  265. we can remove the extra NLS support that was needed
  266. in SHLWAPI. This piece of code is over twice as fast
  267. as the call into SHLWAPI.
  268. Arguments:
  269. lpStart - points to start of null terminated string
  270. wMatch - the character to match
  271. Return Value:
  272. LPSTR - ptr to the first occurrence of ch in str, NULL if not found.
  273. --*/
  274. {
  275. for ( ; *lpStart; lpStart++)
  276. {
  277. if ((BYTE)*lpStart == LOBYTE(wMatch)) {
  278. return((LPSTR)lpStart);
  279. }
  280. }
  281. return (NULL);
  282. }
  283. DWORD
  284. GetTickCountWrap()
  285. {
  286. #ifdef DEBUG_GETTICKCOUNT
  287. static BOOL fInit = FALSE;
  288. static DWORD dwDelta = 0;
  289. static DWORD dwBasis = 0;
  290. if (!fInit)
  291. {
  292. HKEY clientKey;
  293. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  294. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
  295. 0, // reserved
  296. KEY_QUERY_VALUE,
  297. &clientKey))
  298. {
  299. DWORD dwSize = sizeof(dwDelta);
  300. RegQueryValueEx(clientKey, "RollOverDelta", NULL, NULL, (LPBYTE)&dwDelta, &dwSize);
  301. }
  302. dwBasis = GetTickCount();
  303. fInit = TRUE;
  304. }
  305. DWORD dwResult = GetTickCount() - dwBasis + dwDelta;
  306. return dwResult;
  307. #else
  308. return GetTickCount();
  309. #endif
  310. }
  311. DWORD
  312. PlatformType(
  313. IN OUT LPDWORD lpdwVersion5os
  314. )
  315. /*++
  316. Routine Description:
  317. Returns the platform type based on the operating system information. We use
  318. our own platform types
  319. Arguments:
  320. lpdwVersion5os - optional pointer to value, set to TRUE if we on NT 5
  321. Return Value:
  322. DWORD
  323. Failure - PLATFORM_TYPE_UNKNOWN
  324. either GetVersionEx() failed, or we are running on an
  325. unrecognized operating system
  326. Success - PLATFORM_TYPE_WIN95
  327. The world's favourite desktop O/S
  328. PLATFORM_TYPE_WINNT
  329. The world's best O/S on top of anything
  330. --*/
  331. {
  332. #ifndef UNIX
  333. OSVERSIONINFO versionInfo;
  334. *lpdwVersion5os = FALSE;
  335. versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
  336. if (GetVersionEx(&versionInfo)) {
  337. switch (versionInfo.dwPlatformId) {
  338. case VER_PLATFORM_WIN32_WINDOWS:
  339. if(versionInfo.dwMinorVersion >= 90) {
  340. GlobalPlatformMillennium = TRUE;
  341. }
  342. return PLATFORM_TYPE_WIN95;
  343. case VER_PLATFORM_WIN32_NT:
  344. if ( lpdwVersion5os &&
  345. versionInfo.dwMajorVersion >= 5 ) {
  346. *lpdwVersion5os = TRUE;
  347. if (versionInfo.dwMinorVersion >= 1) {
  348. GlobalPlatformWhistler = TRUE;
  349. }
  350. }
  351. return PLATFORM_TYPE_WINNT;
  352. }
  353. }
  354. return PLATFORM_TYPE_UNKNOWN;
  355. #else
  356. return PLATFORM_TYPE_UNIX;
  357. #endif /* UNIX */
  358. }
  359. //
  360. //DWORD
  361. //PlatformSupport(
  362. // VOID
  363. // )
  364. //
  365. ///*++
  366. //
  367. //Routine Description:
  368. //
  369. // Returns a bitmap of capabilities supported by this operating system
  370. //
  371. //Arguments:
  372. //
  373. // None.
  374. //
  375. //Return Value:
  376. //
  377. // DWORD
  378. //
  379. //--*/
  380. //
  381. //{
  382. // switch (PlatformType()) {
  383. // case PLATFORM_TYPE_WINNT:
  384. // return PLATFORM_SUPPORTS_UNICODE;
  385. // }
  386. // return 0;
  387. //}
  388. DWORD
  389. GetTimeoutValue(
  390. IN DWORD TimeoutOption
  391. )
  392. /*++
  393. Routine Description:
  394. Gets a timeout value. The timeout is retrieved from the current handle. If
  395. it is not available in the current handle then the parent handle is checked
  396. (actually the current handle is derived from the parent, so this doesn't
  397. really do anything). If the value is still not available, then the global
  398. default is used
  399. Arguments:
  400. TimeoutOption - INTERNET_OPTION_ value used to specify the timeout value
  401. Return Value:
  402. DWORD
  403. Requested timeout value
  404. --*/
  405. {
  406. HINTERNET hInternet;
  407. DWORD timeout;
  408. DWORD error;
  409. hInternet = InternetGetMappedObjectHandle();
  410. if (hInternet != NULL) {
  411. error = RGetTimeout(hInternet, TimeoutOption, &timeout);
  412. }
  413. if ((hInternet == NULL) || (error != ERROR_SUCCESS)) {
  414. switch (TimeoutOption) {
  415. case INTERNET_OPTION_SEND_TIMEOUT:
  416. timeout = GlobalSendTimeout;
  417. break;
  418. case INTERNET_OPTION_RECEIVE_TIMEOUT:
  419. timeout = GlobalReceiveTimeout;
  420. break;
  421. case INTERNET_OPTION_DATA_SEND_TIMEOUT:
  422. timeout = GlobalDataSendTimeout;
  423. break;
  424. case INTERNET_OPTION_DATA_RECEIVE_TIMEOUT:
  425. timeout = GlobalDataReceiveTimeout;
  426. break;
  427. case INTERNET_OPTION_CONNECT_TIMEOUT:
  428. timeout = GlobalConnectTimeout;
  429. break;
  430. case INTERNET_OPTION_CONNECT_RETRIES:
  431. timeout = GlobalConnectRetries;
  432. break;
  433. case INTERNET_OPTION_FROM_CACHE_TIMEOUT:
  434. timeout = GlobalFromCacheTimeout;
  435. break;
  436. }
  437. }
  438. return timeout;
  439. }
  440. DWORD
  441. ProbeReadBuffer(
  442. IN LPVOID lpBuffer,
  443. IN DWORD dwBufferLength
  444. )
  445. /*++
  446. Routine Description:
  447. Probes a buffer for readability. Used as part of API parameter validation,
  448. this function tests the first and last locations in a buffer. This is not
  449. as strict as the IsBadXPtr() Windows APIs, but it means we don't have to
  450. test every location in the buffer
  451. Arguments:
  452. lpBuffer - pointer to buffer to test
  453. dwBufferLength - length of buffer
  454. Return Value:
  455. DWORD
  456. Success - ERROR_SUCCESS
  457. Failure - ERROR_INVALID_PARAMETER
  458. --*/
  459. {
  460. DWORD error;
  461. //
  462. // the buffer can be NULL if the probe length is 0. Otherwise, its an error
  463. //
  464. if (lpBuffer == NULL) {
  465. error = (dwBufferLength == 0) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
  466. } else if (dwBufferLength != 0) {
  467. __try {
  468. LPBYTE p;
  469. LPBYTE end;
  470. volatile BYTE b;
  471. p = (LPBYTE)lpBuffer;
  472. end = p + dwBufferLength - 1;
  473. b = *end;
  474. //
  475. // visit every page in the buffer - it doesn't matter that we may
  476. // test a character in the middle of a page
  477. //
  478. for (; p < end; p += PAGE_SIZE) {
  479. b = *p;
  480. }
  481. error = ERROR_SUCCESS;
  482. } __except(EXCEPTION_EXECUTE_HANDLER) {
  483. error = ERROR_INVALID_PARAMETER;
  484. }
  485. ENDEXCEPT
  486. } else {
  487. //
  488. // zero-length buffer
  489. //
  490. error = ERROR_INVALID_PARAMETER;
  491. }
  492. return error;
  493. }
  494. DWORD
  495. ProbeWriteBuffer(
  496. IN LPVOID lpBuffer,
  497. IN DWORD dwBufferLength
  498. )
  499. /*++
  500. Routine Description:
  501. Probes a buffer for writeability. Used as part of API parameter validation,
  502. this function tests the first and last locations in a buffer. This is not
  503. as strict as the IsBadXPtr() Windows APIs, but it means we don't have to
  504. test every location in the buffer
  505. Arguments:
  506. lpBuffer - pointer to buffer to test
  507. dwBufferLength - length of buffer
  508. Return Value:
  509. DWORD
  510. Success - ERROR_SUCCESS
  511. Failure - ERROR_INVALID_PARAMETER
  512. --*/
  513. {
  514. DWORD error;
  515. //
  516. // the buffer can be NULL if the probe length is 0. Otherwise, its an error
  517. //
  518. if (lpBuffer == NULL) {
  519. error = (dwBufferLength == 0) ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
  520. } else if (dwBufferLength != 0) {
  521. __try {
  522. LPBYTE p;
  523. LPBYTE end;
  524. volatile BYTE b;
  525. p = (LPBYTE)lpBuffer;
  526. end = p + dwBufferLength - 1;
  527. b = *end;
  528. *end = b;
  529. //
  530. // visit every page in the buffer - it doesn't matter that we may
  531. // test a character in the middle of a page
  532. //
  533. for (; p < end; p += PAGE_SIZE) {
  534. b = *p;
  535. *p = b;
  536. }
  537. error = ERROR_SUCCESS;
  538. } __except(EXCEPTION_EXECUTE_HANDLER) {
  539. error = ERROR_INVALID_PARAMETER;
  540. }
  541. ENDEXCEPT
  542. } else {
  543. //
  544. // zero-length buffer
  545. //
  546. error = ERROR_SUCCESS;
  547. }
  548. return error;
  549. }
  550. DWORD
  551. ProbeAndSetDword(
  552. IN LPDWORD lpDword,
  553. IN DWORD dwValue
  554. )
  555. /*++
  556. Routine Description:
  557. Probes a single DWORD buffer for writeability, and as a side-effect sets it
  558. to a default value. Used as part of API parameter validation
  559. Arguments:
  560. lpDword - pointer to DWORD buffer to test
  561. dwValue - default value to set
  562. Return Value:
  563. DWORD
  564. Success - ERROR_SUCCESS
  565. Failure - ERROR_INVALID_PARAMETER
  566. --*/
  567. {
  568. DWORD error;
  569. __try {
  570. *lpDword = dwValue;
  571. error = ERROR_SUCCESS;
  572. } __except(EXCEPTION_EXECUTE_HANDLER) {
  573. error = ERROR_INVALID_PARAMETER;
  574. }
  575. ENDEXCEPT
  576. return error;
  577. }
  578. DWORD
  579. ProbeString(
  580. IN LPSTR lpString,
  581. OUT LPDWORD lpdwStringLength
  582. )
  583. /*++
  584. Routine Description:
  585. Probes a string buffer for readability, and returns the length of the string
  586. Arguments:
  587. lpString - pointer to string to check
  588. lpdwStringLength - returned length of string
  589. Return Value:
  590. DWORD
  591. Success - ERROR_SUCCESS
  592. Failure - ERROR_INVALID_PARAMETER
  593. --*/
  594. {
  595. DWORD error;
  596. DWORD length;
  597. //
  598. // initialize string length and return code
  599. //
  600. length = 0;
  601. error = ERROR_SUCCESS;
  602. //
  603. // the buffer can be NULL
  604. //
  605. if (lpString != NULL) {
  606. __try {
  607. //
  608. // unfortunately, for a string, we have to visit every location in
  609. // the buffer to find the terminator
  610. //
  611. while (*lpString != '\0') {
  612. ++length;
  613. ++lpString;
  614. }
  615. } __except(EXCEPTION_EXECUTE_HANDLER) {
  616. error = ERROR_INVALID_PARAMETER;
  617. }
  618. ENDEXCEPT
  619. }
  620. *lpdwStringLength = length;
  621. return error;
  622. }
  623. DWORD
  624. ProbeStringW(
  625. IN LPWSTR lpString,
  626. OUT LPDWORD lpdwStringLength
  627. )
  628. /*++
  629. Routine Description:
  630. Probes a wide string buffer for readability, and returns the length of the string
  631. Arguments:
  632. lpString - pointer to string to check
  633. lpdwStringLength - returned length of string
  634. Return Value:
  635. DWORD
  636. Success - ERROR_SUCCESS
  637. Failure - ERROR_INVALID_PARAMETER
  638. --*/
  639. {
  640. DWORD error;
  641. DWORD length;
  642. //
  643. // initialize string length and return code
  644. //
  645. length = 0;
  646. error = ERROR_SUCCESS;
  647. //
  648. // the buffer can be NULL
  649. //
  650. if (lpString != NULL) {
  651. __try {
  652. //
  653. // unfortunately, for a string, we have to visit every location in
  654. // the buffer to find the terminator
  655. //
  656. while (*lpString != '\0') {
  657. ++length;
  658. ++lpString;
  659. }
  660. } __except(EXCEPTION_EXECUTE_HANDLER) {
  661. error = ERROR_INVALID_PARAMETER;
  662. }
  663. ENDEXCEPT
  664. }
  665. *lpdwStringLength = length;
  666. return error;
  667. }
  668. DWORD
  669. LoadDllEntryPoints(
  670. IN OUT LPDLL_INFO lpDllInfo,
  671. IN DWORD dwFlags
  672. )
  673. /*++
  674. Routine Description:
  675. Dynamically loads a DLL and the entry points described in lpDllEntryPoints
  676. Assumes: 1. Any thread serialization taken care of by caller
  677. 2. Module handle, entry point addresses and reference count
  678. already set to 0 if this is first time the DLL_INFO is
  679. being used to load the DLL
  680. Arguments:
  681. lpDllInfo - pointer to DLL_INFO structure containing all info about DLL
  682. and entry points to load
  683. dwFlags - flags controlling how this function operates:
  684. LDEP_PARTIAL_LOAD_OK
  685. - not fatal if we can't load all entry points
  686. Return Value:
  687. DWORD
  688. Success - ERROR_SUCCESS
  689. Failure - Win32 error
  690. --*/
  691. {
  692. DEBUG_ENTER((DBG_UTIL,
  693. Dword,
  694. "LoadDllEntryPoints",
  695. "%x [%q, %d], %#x",
  696. lpDllInfo,
  697. lpDllInfo->lpszDllName,
  698. lpDllInfo->dwNumberOfEntryPoints,
  699. dwFlags
  700. ));
  701. DWORD error = ERROR_SUCCESS;
  702. if (lpDllInfo->hModule == NULL) {
  703. DWORD dwMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  704. HMODULE hDll = LoadLibrary(lpDllInfo->lpszDllName);
  705. if (hDll != NULL) {
  706. lpDllInfo->hModule = hDll;
  707. lpDllInfo->LoadCount = 1;
  708. for (DWORD i = 0; i < lpDllInfo->dwNumberOfEntryPoints; ++i) {
  709. FARPROC proc = GetProcAddress(
  710. hDll,
  711. lpDllInfo->lpEntryPoints[i].lpszProcedureName
  712. );
  713. *lpDllInfo->lpEntryPoints[i].lplpfnProcedure = proc;
  714. if ((proc == NULL) && !(dwFlags & LDEP_PARTIAL_LOAD_OK)) {
  715. error = GetLastError();
  716. UnloadDllEntryPoints(lpDllInfo, TRUE);
  717. break;
  718. }
  719. }
  720. } else {
  721. error = GetLastError();
  722. }
  723. SetErrorMode(dwMode);
  724. } else {
  725. DEBUG_PRINT(UTIL,
  726. INFO,
  727. ("info for %q already loaded\n",
  728. lpDllInfo->lpszDllName
  729. ));
  730. InterlockedIncrement(&lpDllInfo->LoadCount);
  731. }
  732. DEBUG_LEAVE(error);
  733. return error;
  734. }
  735. DWORD
  736. UnloadDllEntryPoints(
  737. IN OUT LPDLL_INFO lpDllInfo,
  738. IN BOOL bForce
  739. )
  740. /*++
  741. Routine Description:
  742. Undoes the work of LoadDllEntryPoints()
  743. Assumes: 1. Any thread serialization taken care of by caller
  744. Arguments:
  745. lpDllInfo - pointer to DLL_INFO structure containing all info about DLL
  746. and (loaded) entry points
  747. bForce - TRUE if the DLL will be unloaded irrespective of the usage
  748. count
  749. Return Value:
  750. DWORD
  751. Success - ERROR_SUCCESS
  752. Failure - Win32 error
  753. --*/
  754. {
  755. DEBUG_ENTER((DBG_UTIL,
  756. Dword,
  757. "UnloadDllEntryPoints",
  758. "%x [%q, %d], %B",
  759. lpDllInfo,
  760. lpDllInfo->lpszDllName,
  761. lpDllInfo->dwNumberOfEntryPoints,
  762. bForce
  763. ));
  764. DWORD error = ERROR_SUCCESS;
  765. if (bForce) {
  766. lpDllInfo->LoadCount = 0;
  767. } else if (InterlockedDecrement(&lpDllInfo->LoadCount) == 0) {
  768. bForce = TRUE;
  769. }
  770. if (bForce && (lpDllInfo->hModule != NULL)) {
  771. if (!FreeLibrary(lpDllInfo->hModule)) {
  772. error = GetLastError();
  773. }
  774. //
  775. // even if FreeLibrary() failed we clear out the load info
  776. //
  777. lpDllInfo->hModule = NULL;
  778. for (DWORD i = 0; i < lpDllInfo->dwNumberOfEntryPoints; ++i) {
  779. *lpDllInfo->lpEntryPoints[i].lplpfnProcedure = NULL;
  780. }
  781. }
  782. DEBUG_LEAVE(error);
  783. return error;
  784. }
  785. #ifndef CERT_E_WRONG_USAGE
  786. # define CERT_E_WRONG_USAGE _HRESULT_TYPEDEF_(0x800B0110)
  787. #endif
  788. DWORD
  789. MapInternetError(
  790. IN DWORD dwErrorCode
  791. )
  792. /*++
  793. Routine Description:
  794. Maps a winsock/RPC/transport error into a more user-friendly WinInet error,
  795. and stores the original error in the per-thread context so that the app can
  796. retrieve it if it really cares
  797. N.B. We should no longer be receiving winsock errors directly at the WinInet
  798. interface. They are available via InternetGetLastResponseInfo()
  799. Arguments:
  800. dwErrorCode - original (winsock) error code to map
  801. Return Value:
  802. DWORD
  803. Mapped error code, or the orignal error if its not one that we handle
  804. --*/
  805. {
  806. LPINTERNET_THREAD_INFO lpThreadInfo;
  807. DEBUG_ENTER((DBG_UTIL,
  808. Dword,
  809. "MapInternetError",
  810. "%#x [%s]",
  811. dwErrorCode,
  812. InternetMapError(dwErrorCode)
  813. ));
  814. lpThreadInfo = InternetGetThreadInfo();
  815. if (lpThreadInfo) {
  816. lpThreadInfo->dwMappedErrorCode = dwErrorCode;
  817. }
  818. switch (dwErrorCode) {
  819. case SEC_E_INSUFFICIENT_MEMORY :
  820. dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  821. break;
  822. case SEC_E_INVALID_HANDLE :
  823. case SEC_E_UNSUPPORTED_FUNCTION :
  824. case SEC_E_TARGET_UNKNOWN :
  825. case SEC_E_INTERNAL_ERROR :
  826. case SEC_E_SECPKG_NOT_FOUND :
  827. case SEC_E_NOT_OWNER :
  828. case SEC_E_CANNOT_INSTALL :
  829. case SEC_E_INVALID_TOKEN :
  830. case SEC_E_CANNOT_PACK :
  831. case SEC_E_QOP_NOT_SUPPORTED :
  832. case SEC_E_NO_IMPERSONATION :
  833. case SEC_E_LOGON_DENIED :
  834. case SEC_E_UNKNOWN_CREDENTIALS :
  835. case SEC_E_NO_CREDENTIALS :
  836. case SEC_E_MESSAGE_ALTERED :
  837. case SEC_E_OUT_OF_SEQUENCE :
  838. case SEC_E_NO_AUTHENTICATING_AUTHORITY:
  839. case SEC_I_CONTINUE_NEEDED :
  840. case SEC_I_COMPLETE_NEEDED :
  841. case SEC_I_COMPLETE_AND_CONTINUE :
  842. case SEC_I_LOCAL_LOGON :
  843. case SEC_E_BAD_PKGID :
  844. case SEC_E_CONTEXT_EXPIRED :
  845. case SEC_E_INCOMPLETE_MESSAGE :
  846. dwErrorCode = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
  847. break;
  848. // Cert and Encryption errors
  849. case CERT_E_EXPIRED:
  850. case CERT_E_VALIDITYPERIODNESTING:
  851. dwErrorCode = ERROR_INTERNET_SEC_CERT_DATE_INVALID;
  852. break;
  853. case CERT_E_UNTRUSTEDROOT:
  854. dwErrorCode = ERROR_INTERNET_INVALID_CA;
  855. break;
  856. case CERT_E_CN_NO_MATCH:
  857. dwErrorCode = ERROR_INTERNET_SEC_CERT_CN_INVALID;
  858. break;
  859. case CRYPT_E_REVOKED:
  860. dwErrorCode = ERROR_INTERNET_SEC_CERT_REVOKED;
  861. break;
  862. // ignore revocation if the certificate does not have a CDP
  863. case CRYPT_E_NO_REVOCATION_CHECK:
  864. dwErrorCode = ERROR_SUCCESS;
  865. break;
  866. case CRYPT_E_REVOCATION_OFFLINE:
  867. dwErrorCode = ERROR_INTERNET_SEC_CERT_REV_FAILED;
  868. break;
  869. case CERT_E_ROLE:
  870. case CERT_E_PATHLENCONST:
  871. case CERT_E_CRITICAL:
  872. case CERT_E_PURPOSE:
  873. case CERT_E_ISSUERCHAINING:
  874. case CERT_E_MALFORMED:
  875. case CERT_E_CHAINING:
  876. // We can't allow connection if server doesn't have a server auth certificate.
  877. // To force CERT_E_WRONG_USAGE to error out we map it to the error below.
  878. // In the future we need to map it to it's own non-recoverable error, so we can
  879. // give the user a specific error message.
  880. case CERT_E_WRONG_USAGE:
  881. dwErrorCode = ERROR_INTERNET_SEC_INVALID_CERT;
  882. break;
  883. case WSAEINTR:
  884. case WSAEBADF:
  885. case WSAEACCES:
  886. case WSAEFAULT:
  887. case WSAEINVAL:
  888. case WSAEMFILE:
  889. case WSAEADDRINUSE:
  890. case WSAEADDRNOTAVAIL:
  891. dwErrorCode = ERROR_INTERNET_INTERNAL_ERROR;
  892. break;
  893. case WSAENOTSOCK:
  894. //
  895. // typically, if we see this error its because we tried to use a closed
  896. // socket handle
  897. //
  898. dwErrorCode = ERROR_INTERNET_OPERATION_CANCELLED;
  899. break;
  900. case WSAEWOULDBLOCK:
  901. case WSAEINPROGRESS:
  902. case WSAEALREADY:
  903. case WSAEDESTADDRREQ:
  904. case WSAEPROTOTYPE:
  905. case WSAENOPROTOOPT:
  906. case WSAEPROTONOSUPPORT:
  907. case WSAESOCKTNOSUPPORT:
  908. case WSAEOPNOTSUPP:
  909. case WSAEISCONN:
  910. case WSAETOOMANYREFS:
  911. case WSAELOOP:
  912. case WSAENAMETOOLONG:
  913. case WSAENOTEMPTY:
  914. case WSAEPROCLIM:
  915. case WSAEUSERS:
  916. case WSAEDQUOT:
  917. case WSAESTALE:
  918. case WSAEREMOTE:
  919. case WSAEDISCON:
  920. case WSASYSNOTREADY:
  921. case WSAVERNOTSUPPORTED:
  922. case WSANOTINITIALISED:
  923. //
  924. // currently unmapped errors
  925. //
  926. break;
  927. case WSAEMSGSIZE:
  928. dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
  929. break;
  930. case WSAEPFNOSUPPORT:
  931. case WSAEAFNOSUPPORT:
  932. dwErrorCode = ERROR_INTERNET_TCPIP_NOT_INSTALLED;
  933. break;
  934. case WSAECONNABORTED:
  935. case WSAESHUTDOWN:
  936. dwErrorCode = ERROR_INTERNET_CONNECTION_ABORTED;
  937. break;
  938. case WSAECONNRESET:
  939. case WSAENETRESET:
  940. dwErrorCode = ERROR_INTERNET_CONNECTION_RESET;
  941. break;
  942. case WSAENOBUFS:
  943. dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  944. break;
  945. case WSAETIMEDOUT:
  946. dwErrorCode = ERROR_INTERNET_TIMEOUT;
  947. break;
  948. case WSAENETDOWN:
  949. case WSAECONNREFUSED:
  950. case WSAENETUNREACH:
  951. case WSAENOTCONN:
  952. dwErrorCode = ERROR_INTERNET_CANNOT_CONNECT;
  953. break;
  954. case WSAEHOSTDOWN:
  955. case WSAEHOSTUNREACH:
  956. case WSAHOST_NOT_FOUND:
  957. case WSATRY_AGAIN:
  958. case WSANO_RECOVERY:
  959. case WSANO_DATA:
  960. dwErrorCode = ERROR_INTERNET_NAME_NOT_RESOLVED;
  961. break;
  962. default:
  963. DEBUG_PRINT(UTIL,
  964. WARNING,
  965. ("MapInternetError(): unmapped error code %d [%#x]\n",
  966. dwErrorCode,
  967. dwErrorCode
  968. ));
  969. break;
  970. }
  971. DEBUG_LEAVE(dwErrorCode);
  972. return dwErrorCode;
  973. }
  974. DWORD
  975. CalculateHashValue(
  976. IN LPSTR lpszString
  977. )
  978. /*++
  979. Routine Description:
  980. Calculate a hash number given a string
  981. Arguments:
  982. lpszString - string to hash
  983. Return Value:
  984. DWORD
  985. --*/
  986. {
  987. DWORD hashValue = 0;
  988. DWORD position = 1;
  989. while (*lpszString) {
  990. hashValue += *lpszString * position;
  991. ++lpszString;
  992. ++position;
  993. }
  994. return hashValue;
  995. }
  996. VOID GetCurrentGmtTime(
  997. LPFILETIME lpFt
  998. )
  999. /*++
  1000. Routine Description:
  1001. This routine returns the current GMT time
  1002. Arguments:
  1003. lpFt FILETIME strucutre in which this is returned
  1004. Returns:
  1005. Comments:
  1006. --*/
  1007. {
  1008. SYSTEMTIME sSysT;
  1009. GetSystemTime(&sSysT);
  1010. SystemTimeToFileTime(&sSysT, lpFt);
  1011. }
  1012. ///*** DwRemoveDots - Remove any dots from a path name
  1013. //**
  1014. //** Synopsis
  1015. //** DWORD DwRemoveDots (pchPath)
  1016. //** Lifted from win95 kernel.
  1017. //**
  1018. //** Input:
  1019. //** pchPath - A path string
  1020. //**
  1021. //**
  1022. //** Output:
  1023. //** returns the number of double dot levels removed from front
  1024. //**
  1025. //** Errors:
  1026. //** returns dwInvalid if invalid path
  1027. //**
  1028. //** Description:
  1029. //** Removes ..\ and .\ sequences from a path string. The path
  1030. //** string should not include the root drive or net name portion.
  1031. //** The return value of is the number of levels removed from the
  1032. //** start of the string. Levels removed from inside the string
  1033. //** will not be returned. For example:
  1034. //**
  1035. //** String Result Return
  1036. //**
  1037. //** ..\..\dir1 dir1 2
  1038. //** dir1\..\dir2 dir2 0
  1039. //** dir1\..\..\dir2 dir2 1
  1040. //** .\dir1 dir1 0
  1041. //** dir1\.\dir2 dir1\dir2 0
  1042. //**
  1043. //** A backslash at the start of the string will be ignored.
  1044. //*/
  1045. //
  1046. //// File and path definitions
  1047. //
  1048. //#define chExtSep '.'
  1049. //#define szExtSep "."
  1050. //#define chNetIni '\\'
  1051. //#define chDirSep '\\'
  1052. //#define szDirSep "\\"
  1053. //#define chDirSep2 '/'
  1054. //#define chDrvSep ':'
  1055. //#define chRelDir '.'
  1056. //#define chEnvSep ';'
  1057. //#define chWldChr '?'
  1058. //#define chWldSeq '*'
  1059. //#define chMinDrv 'A'
  1060. //#define chMaxDrv 'Z'
  1061. //#define chMinDrvLow 'a'
  1062. //#define chMaxDrvLow 'z'
  1063. //
  1064. //DWORD
  1065. //DwRemoveDots (
  1066. // char * pchPath
  1067. ///*++
  1068. //
  1069. //Routine Description:
  1070. // Removes ./ ../ etc from a path to normalize it
  1071. //
  1072. //Arguments:
  1073. //
  1074. // pchPath path string
  1075. //
  1076. //Returns:
  1077. //
  1078. // Count of levels dealt with
  1079. //
  1080. //Comments:
  1081. //
  1082. // Lifted from win95 kernel
  1083. //
  1084. //--*/
  1085. //)
  1086. // {
  1087. // BOOL fInside = FALSE;
  1088. // DWORD cLevel = 0;
  1089. // DWORD cBackup;
  1090. // register char * pchR;
  1091. // register char * pchL;
  1092. //
  1093. //#ifdef MAYBE
  1094. // // Check for invalid characters
  1095. // if (!FFixPathChars(pchPath)) {
  1096. // // No code required.
  1097. // return dwInvalid;
  1098. // }
  1099. //
  1100. //#endif //MAYBE
  1101. // // Skip slashes
  1102. // for (; *pchPath == chDirSep2; pchPath++)
  1103. // ;
  1104. // pchL = pchR = pchPath;
  1105. //
  1106. // // Loop through handling each directory part
  1107. // while (*pchR) {
  1108. // // This part starts with dot. Is it one or more?
  1109. // if (*pchR++ == chRelDir) {
  1110. // for (cBackup = 0; *pchR == chRelDir; cBackup++, pchR++)
  1111. // ;
  1112. // if (cBackup) {
  1113. // // More than one dot. Back up the left pointer.
  1114. // if ((*pchR != chDirSep2) && (*pchR != '\0')) {
  1115. // // we got a [.]+X (X != '\') might be an LFN
  1116. // // process this as a name
  1117. // goto name_processing;
  1118. // }
  1119. // // Doesn't advance for ending ..
  1120. // for (; *pchR == chDirSep2; pchR++)
  1121. // ;
  1122. // if (fInside) {
  1123. // for (; cBackup; cBackup--) {
  1124. // if (pchL <= pchPath) {
  1125. // cLevel += cBackup;
  1126. // fInside = FALSE;
  1127. // break;
  1128. // }
  1129. // // Remove the previous part
  1130. // for (pchL -= 2; *pchL != chDirSep2; pchL--) {
  1131. // if (pchL <= pchPath) {
  1132. // fInside = FALSE;
  1133. // pchL--;
  1134. // break;
  1135. // }
  1136. // }
  1137. // pchL++;
  1138. // }
  1139. // } else {
  1140. // cLevel += cBackup;
  1141. // }
  1142. // // Subtract ending backslash if not root
  1143. // if ((*pchR == '\0') && (pchL != pchPath))
  1144. // pchL--;
  1145. // strcpy(pchL, pchR);
  1146. // pchR = pchL;
  1147. // } else {
  1148. // // This part starts with one dot. Throw it away.
  1149. // if (*pchR != chDirSep2) {
  1150. // // Special case "\." by converting it to ""
  1151. // // unless it is a root, when it becomes "\".
  1152. // if (*pchR == '\0') {
  1153. // if (pchL == pchPath)
  1154. // *(pchR-1) = '\0'; // root
  1155. // else
  1156. // *(pchR-2) = '\0'; // not root
  1157. // return cLevel;
  1158. // }
  1159. // // we started with a '.' and then there was no '\'
  1160. // // might be an LFN name
  1161. // goto name_processing;
  1162. // }
  1163. // pchR++;
  1164. // strcpy(pchL, pchR);
  1165. // pchR = pchL;
  1166. // }
  1167. // } else {
  1168. //name_processing:
  1169. // // This part is a name. Skip it.
  1170. // fInside = TRUE;
  1171. // for (; TRUE; pchR++) {
  1172. // if (*pchR == chDirSep2) {
  1173. // if (*(pchR-1) == chRelDir) {
  1174. // // This name has one or more dots at the end.
  1175. // // Remove the last dot (NT3.5 does this).
  1176. // pchL = pchR-1;
  1177. // strcpy(pchL, pchR);
  1178. // pchR = pchL; // point to chDirSep2 again
  1179. // }
  1180. // for (; *pchR == chDirSep2; pchR++)
  1181. // ;
  1182. // break;
  1183. // } else if (*pchR == '\0') {
  1184. // // Remove trailing dots.
  1185. // // NB Can't fall off the beginning since the first char
  1186. // // of the current path element was not chRelDir.
  1187. // for (; *(pchR-1) == chRelDir; pchR--)
  1188. // ;
  1189. // // Overstore the first trailing dot, if there is one.
  1190. // *pchR = '\0';
  1191. // break;
  1192. // }
  1193. // }
  1194. // pchL = pchR;
  1195. // }
  1196. // }
  1197. // return cLevel;
  1198. //}
  1199. //#define OLD
  1200. #define EXE_EXTENSION TEXT(".exe")
  1201. #define DLL_EXTENSION TEXT(".dll")
  1202. #define CGI_EXTENSION TEXT(".cgi")
  1203. LPSTR GetFileExtensionFromUrl(
  1204. IN LPSTR lpszUrl,
  1205. IN OUT LPDWORD lpdwLength)
  1206. /*++
  1207. Routine Description:
  1208. This routine returns a possible file extension from a URL
  1209. It does this by walking back from the end till the first dot.
  1210. Arguments:
  1211. lpszUrl Url to derive the extension from
  1212. lpdwLength max length of the extension expected
  1213. Returns:
  1214. NULL if no dot within the passed in length or a forward slash or a
  1215. backward slash encountered before the dot. Otherwise returns a pointer
  1216. pointing past the dot in the url string
  1217. Comments:
  1218. --*/
  1219. {
  1220. INET_ASSERT(lpszUrl && lpdwLength);
  1221. #ifdef OLD
  1222. if (lpszUrl != NULL) {
  1223. LPSTR p;
  1224. DWORD len=0 , lenLimit= *lpdwLength;
  1225. p = lpszUrl + (strlen(lpszUrl) - 1);
  1226. while ((*p != '.') && (p != lpszUrl)) {
  1227. // if this contains a character that the filesystems
  1228. // don't like, then return NULL
  1229. if (strchr(vszInvalidFilenameChars, *p)) {
  1230. return(NULL);
  1231. }
  1232. if ((*p == '/') || (*p == '\\')) {
  1233. break;
  1234. }
  1235. --p;
  1236. ++len;
  1237. }
  1238. if ((*p == '.')
  1239. && (len != 0)
  1240. && (len < lenLimit)) {
  1241. *lpdwLength = len;
  1242. return p + 1;
  1243. }
  1244. }
  1245. return NULL;
  1246. #else
  1247. if (!lpszUrl)
  1248. {
  1249. *lpdwLength = 0;
  1250. return NULL;
  1251. }
  1252. LPSTR pszPeriod = NULL;
  1253. BOOL fContinue = TRUE;
  1254. // Scanning from left to right, note where we last saw a period.
  1255. // If we see a character that cannot be in an extension, and we've seen a period, forget
  1256. // about the period.
  1257. // Repeat this until we've reached the end of the url, a question mark (query) or hash (fragment)
  1258. // 1.6.98: _However_, if the file extension we've discovered is either .dll or .exe,
  1259. // we'll continue to scan beyond the query mark for a file extension.
  1260. // 1.20.98: And if we find no extension before the question mark, we'll look after it, then.
  1261. while (fContinue)
  1262. {
  1263. switch (*lpszUrl)
  1264. {
  1265. case TEXT('.'):
  1266. pszPeriod = lpszUrl;
  1267. break;
  1268. case TEXT('?'):
  1269. if (pszPeriod)
  1270. {
  1271. if ((!StrCmpNI(pszPeriod, EXE_EXTENSION, ARRAY_ELEMENTS(EXE_EXTENSION)-1))
  1272. || (!StrCmpNI(pszPeriod, DLL_EXTENSION, ARRAY_ELEMENTS(DLL_EXTENSION)-1))
  1273. || (!StrCmpNI(pszPeriod, CGI_EXTENSION, ARRAY_ELEMENTS(CGI_EXTENSION)-1)))
  1274. {
  1275. pszPeriod = NULL;
  1276. break;
  1277. }
  1278. }
  1279. else
  1280. {
  1281. break;
  1282. }
  1283. case TEXT('#'):
  1284. case TEXT('\0'):
  1285. fContinue = FALSE;
  1286. break;
  1287. default:
  1288. if (pszPeriod && strchr(vszInvalidFilenameChars, *lpszUrl))
  1289. {
  1290. pszPeriod = NULL;
  1291. }
  1292. }
  1293. lpszUrl++;
  1294. }
  1295. // This will be off by one
  1296. lpszUrl--;
  1297. if (pszPeriod)
  1298. {
  1299. if (*lpdwLength < (DWORD)(lpszUrl-pszPeriod))
  1300. {
  1301. pszPeriod = NULL;
  1302. }
  1303. else
  1304. {
  1305. pszPeriod++;
  1306. *lpdwLength = (DWORD)(lpszUrl-pszPeriod);
  1307. }
  1308. }
  1309. return pszPeriod;
  1310. #endif
  1311. }
  1312. DWORD
  1313. CheckExpired(
  1314. HINTERNET hRequestMapped,
  1315. BOOL* lpfIsExpired,
  1316. CACHE_ENTRY_INFO* pInfo,
  1317. LONGLONG DefaultExpiryDelta
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. This routine checks whether a cache entry has expired for ftp/gopher.
  1322. It uses the globally set synchronization modes to make that decision
  1323. Arguments:
  1324. hRequestMapped a mapped request handle
  1325. lpfIsExpired returns TRUE if expired, FALSE otherwise
  1326. lpCacheEntryInfo cache entry info containing all the timestamps
  1327. DefaultExpiryDelta time delta to use for default expiry calculation
  1328. Returns:
  1329. Windows error code
  1330. Comments:
  1331. --*/
  1332. {
  1333. switch (GlobalUrlCacheSyncMode)
  1334. {
  1335. case WININET_SYNC_MODE_NEVER:
  1336. // Never check, unless the page has expired
  1337. *lpfIsExpired = FALSE;
  1338. break;
  1339. case WININET_SYNC_MODE_ALWAYS:
  1340. *lpfIsExpired = TRUE;
  1341. break;
  1342. default:
  1343. if (FT2LL (pInfo->LastSyncTime) < dwdwSessionStartTime)
  1344. *lpfIsExpired = TRUE;
  1345. else
  1346. {
  1347. FILETIME ftCurrent;
  1348. GetCurrentGmtTime (&ftCurrent);
  1349. *lpfIsExpired = (FT2LL(ftCurrent) - FT2LL (pInfo->LastSyncTime)
  1350. > DefaultExpiryDelta);
  1351. }
  1352. break;
  1353. }
  1354. return ERROR_SUCCESS;
  1355. }
  1356. LPTSTR
  1357. FTtoString(
  1358. IN FILETIME *pftTime)
  1359. /*++
  1360. FTtoString:
  1361. This routine converts a given FILETIME structure to a string representing
  1362. the given date and time in the local format.
  1363. Arguments:
  1364. pftTime supplies the FILETIME structure to convert.
  1365. Return Value:
  1366. NULL - Memory allocation failure.
  1367. Otherwise, the address of the string, allocated via LocalAlloc.
  1368. Author:
  1369. Doug Barlow (dbarlow) 4/12/1996
  1370. --*/
  1371. {
  1372. LONG cchTotal, cchNeeded;
  1373. SYSTEMTIME stTime, stLocal;
  1374. LPTSTR szDateTime = NULL;
  1375. //
  1376. // Convert the FILETIME to a SYSTEMTIME.
  1377. //
  1378. if (!FileTimeToSystemTime(pftTime, &stTime))
  1379. goto ErrorExit;
  1380. //
  1381. // For now, leave it in GMT time, function not implimented in Win'95.
  1382. //
  1383. //if ( IsPlatformWinNT() )
  1384. //{
  1385. // if (!SystemTimeToTzSpecificLocalTime(NULL, &stTime, &stLocal))
  1386. // goto ErrorExit;
  1387. //}
  1388. //else
  1389. {
  1390. stLocal = stTime;
  1391. }
  1392. //
  1393. // Calculate how long the date string will be.
  1394. //
  1395. cchTotal =
  1396. GetDateFormat(
  1397. LOCALE_SYSTEM_DEFAULT,
  1398. DATE_SHORTDATE,
  1399. &stLocal,
  1400. NULL,
  1401. NULL,
  1402. 0);
  1403. if (0 >= cchTotal)
  1404. goto ErrorExit;
  1405. cchNeeded =
  1406. GetTimeFormat(
  1407. LOCALE_SYSTEM_DEFAULT,
  1408. 0,
  1409. &stLocal,
  1410. NULL,
  1411. NULL,
  1412. 0);
  1413. if (0 >= cchNeeded)
  1414. goto ErrorExit;
  1415. cchTotal += cchNeeded;
  1416. cchTotal += 4 * sizeof(TCHAR); // space, trailing NULL, and two extra.
  1417. szDateTime = (LPTSTR)ALLOCATE_MEMORY(LMEM_FIXED, cchTotal);
  1418. if (NULL == szDateTime)
  1419. goto ErrorExit;
  1420. //
  1421. // Fill in the time string.
  1422. //
  1423. cchNeeded =
  1424. GetDateFormat(
  1425. LOCALE_SYSTEM_DEFAULT,
  1426. DATE_SHORTDATE,
  1427. &stLocal,
  1428. NULL,
  1429. szDateTime,
  1430. cchTotal);
  1431. if (0 >= cchNeeded)
  1432. goto ErrorExit;
  1433. lstrcat(szDateTime, TEXT(" "));
  1434. cchNeeded = lstrlen(szDateTime);
  1435. cchNeeded =
  1436. GetTimeFormat(
  1437. LOCALE_SYSTEM_DEFAULT,
  1438. 0,
  1439. &stLocal,
  1440. NULL,
  1441. &szDateTime[cchNeeded],
  1442. cchTotal - cchNeeded);
  1443. if (0 >= cchNeeded)
  1444. goto ErrorExit;
  1445. return szDateTime;
  1446. ErrorExit:
  1447. if (NULL != szDateTime)
  1448. FREE_MEMORY(szDateTime);
  1449. return NULL;
  1450. }
  1451. BOOL
  1452. PrintFileTimeInInternetFormat(
  1453. FILETIME *lpft,
  1454. LPSTR lpszBuff,
  1455. DWORD dwSize
  1456. )
  1457. {
  1458. SYSTEMTIME sSysTime;
  1459. if (dwSize < INTERNET_RFC1123_BUFSIZE) {
  1460. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1461. return (FALSE);
  1462. }
  1463. if (!FileTimeToSystemTime(((CONST FILETIME *)lpft), &sSysTime)) {
  1464. return (FALSE);
  1465. }
  1466. return (InternetTimeFromSystemTime( &sSysTime,
  1467. INTERNET_RFC1123_FORMAT,
  1468. lpszBuff,
  1469. dwSize));
  1470. }
  1471. BOOL
  1472. InternetSettingsChanged(
  1473. VOID
  1474. )
  1475. /*++
  1476. Routine Description:
  1477. Determines if the global settings have been changed (inter-process)
  1478. Arguments:
  1479. None.
  1480. Return Value:
  1481. BOOL
  1482. --*/
  1483. {
  1484. DEBUG_ENTER((DBG_UTIL,
  1485. Bool,
  1486. "InternetSettingsChanged",
  1487. NULL
  1488. ));
  1489. DWORD dwVer;
  1490. BOOL bChanged = FALSE;
  1491. if (GetCurrentSettingsVersion(&dwVer)) {
  1492. DEBUG_PRINT(UTIL,
  1493. INFO,
  1494. ("current settings version = %d\n",
  1495. dwVer
  1496. ));
  1497. if (!GlobalSettingsLoaded || (dwVer != GlobalSettingsVersion)) {
  1498. GlobalSettingsLoaded = TRUE;
  1499. GlobalSettingsVersion = dwVer;
  1500. bChanged = TRUE;
  1501. }
  1502. }
  1503. DEBUG_LEAVE(bChanged);
  1504. return bChanged;
  1505. }
  1506. BOOL
  1507. RefreshSslState(
  1508. VOID
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. Starting with Whistler, client auth certificates are cached
  1513. for the logon session (not per process). Inetcpl now contains
  1514. a button that will clear on-demand the SSL state for the session.
  1515. If user cleared the SSL cache, then flush all cached
  1516. client auth certificates in the global cert cache for this process.
  1517. NOTE: This function leverages a cache header data value.
  1518. Clearing the state affects all processes, and
  1519. using one of these (which was never put into practice)
  1520. prevents the need for another shared registry value.
  1521. Arguments:
  1522. None.
  1523. Return Value:
  1524. BOOL If the client auth cert cache was cleared, this function will
  1525. return TRUE. Otherwise, this will return FALSE.
  1526. --*/
  1527. {
  1528. DWORD dwCount = 0;
  1529. BOOL bCleared = FALSE;
  1530. DEBUG_ENTER((DBG_UTIL,
  1531. Bool,
  1532. "RefreshSslState",
  1533. NULL
  1534. ));
  1535. if (GlobalPlatformWhistler &&
  1536. GetUrlCacheHeaderData(CACHE_HEADER_DATA_DOWNLOAD_PARTIAL, &dwCount) &&
  1537. dwCount != GlobalSslStateCount)
  1538. {
  1539. GlobalSslStateCount = dwCount;
  1540. PurgeKeepAlives(PKA_NOW);
  1541. GlobalCertCache.ClearClientAuthCertChains();
  1542. bCleared = TRUE;
  1543. }
  1544. DEBUG_LEAVE(bCleared);
  1545. return bCleared;
  1546. }
  1547. BOOL
  1548. CertHashToStr(
  1549. IN LPSTR lpMD5Hash,
  1550. IN DWORD dwMD5HashSize,
  1551. IN OUT LPSTR *lplpszHashStr
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. Converts a set of bytes into a neatly formated string of ':' (colon) seperated
  1556. hex digits that can be shown to the user.
  1557. Arguments:
  1558. lpMD5Hash - ptr to set of hash bytes
  1559. dwMD5HashSize - size of lpMD5Hash
  1560. lplpszHashStr - ptr to ptr where newly allocated return string will be stored.
  1561. Return Value:
  1562. BOOL
  1563. --*/
  1564. {
  1565. DWORD dwStrSize = (2*dwMD5HashSize) + dwMD5HashSize;
  1566. LPSTR lpszHashStr;
  1567. *lplpszHashStr = new CHAR[dwStrSize];
  1568. if ( *lplpszHashStr == NULL )
  1569. {
  1570. return FALSE;
  1571. }
  1572. lpszHashStr = *lplpszHashStr;
  1573. for ( DWORD i = 0 ; i < dwMD5HashSize; i++ )
  1574. {
  1575. unsigned char uHashByte;
  1576. if ( i != 0 )
  1577. {
  1578. *lpszHashStr = ':';
  1579. lpszHashStr++;
  1580. }
  1581. uHashByte = (unsigned char) * ( ((unsigned char * ) lpMD5Hash) + i);
  1582. wsprintf( lpszHashStr, "%02X", uHashByte);
  1583. lpszHashStr += 2;
  1584. }
  1585. INET_ASSERT( *lpszHashStr == '\0' );
  1586. return TRUE;
  1587. }
  1588. //
  1589. // private functions
  1590. //
  1591. DWORD
  1592. ConvertSecurityInfoIntoCertInfoStruct(
  1593. IN LPINTERNET_SECURITY_INFO pSecInfo,
  1594. OUT INTERNET_CERTIFICATE_INFO *pCertificate,
  1595. IN OUT DWORD *pcbCertificate
  1596. )
  1597. /*++
  1598. Routine Description:
  1599. Converts an X509 Certificate Structure into a WININET struct
  1600. used for storing the same info.
  1601. Arguments:
  1602. hContext - Context handle of the active SSPI session.
  1603. pCertInfo - Pointer to Structure where info is returned in.
  1604. Return Value:
  1605. DWORD
  1606. ERROR_SUCCESS - if cert cannot be converted
  1607. ERROR_NOT_ENOUGH_MEMORY
  1608. --*/
  1609. {
  1610. DWORD error = ERROR_SUCCESS;
  1611. PCERT_INFO pCertInfo = NULL;
  1612. DWORD cbCert = sizeof(INTERNET_CERTIFICATE_INFO),
  1613. cbSubject = 0,
  1614. cbIssuer = 0;
  1615. BOOL fCanAlloc = FALSE;
  1616. if(pSecInfo == NULL)
  1617. {
  1618. error = ERROR_INTERNET_INTERNAL_ERROR;
  1619. goto quit;
  1620. }
  1621. if(pCertificate == NULL || *pcbCertificate == 0)
  1622. {
  1623. *pcbCertificate = sizeof(INTERNET_CERTIFICATE_INFO);
  1624. goto quit;
  1625. }
  1626. if(*pcbCertificate < sizeof(INTERNET_CERTIFICATE_INFO) )
  1627. {
  1628. error = ERROR_INTERNET_INTERNAL_ERROR;
  1629. goto quit;
  1630. }
  1631. ZeroMemory(pCertificate, sizeof(INTERNET_CERTIFICATE_INFO));
  1632. fCanAlloc = TRUE;
  1633. if(pSecInfo->pCertificate &&
  1634. pSecInfo->pCertificate->pCertInfo )
  1635. {
  1636. pCertInfo = pSecInfo->pCertificate->pCertInfo;
  1637. //
  1638. // Now Convert Structures from SSPI format to WININET style.
  1639. // While in the process, we'll role them all into one
  1640. // big structure that we'll return to the user.
  1641. //
  1642. cbSubject = CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
  1643. &pCertInfo->Subject,
  1644. CERT_SIMPLE_NAME_STR |
  1645. CERT_NAME_STR_CRLF_FLAG |
  1646. CERT_NAME_STR_NO_PLUS_FLAG,
  1647. NULL,
  1648. 0);
  1649. if ( cbSubject > 0 )
  1650. {
  1651. // freed by caller outside of wininet
  1652. pCertificate->lpszSubjectInfo = (LPSTR) LocalAlloc(LPTR, cbSubject);
  1653. if ( pCertificate->lpszSubjectInfo == NULL )
  1654. {
  1655. error = ERROR_NOT_ENOUGH_MEMORY;
  1656. goto quit;
  1657. }
  1658. CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
  1659. &pCertInfo->Subject,
  1660. CERT_SIMPLE_NAME_STR |
  1661. CERT_NAME_STR_CRLF_FLAG |
  1662. CERT_NAME_STR_NO_PLUS_FLAG ,
  1663. pCertificate->lpszSubjectInfo,
  1664. cbSubject);
  1665. }
  1666. cbIssuer = CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
  1667. &pCertInfo->Issuer,
  1668. CERT_SIMPLE_NAME_STR |
  1669. CERT_NAME_STR_CRLF_FLAG |
  1670. CERT_NAME_STR_NO_PLUS_FLAG,
  1671. NULL,
  1672. 0);
  1673. if ( cbIssuer > 0 )
  1674. {
  1675. // freed by caller outside of wininet
  1676. pCertificate->lpszIssuerInfo = (LPSTR) LocalAlloc(LPTR, cbIssuer);
  1677. if ( pCertificate->lpszIssuerInfo == NULL )
  1678. {
  1679. error = ERROR_NOT_ENOUGH_MEMORY;
  1680. goto quit;
  1681. }
  1682. CertNameToStr(pSecInfo->pCertificate->dwCertEncodingType,
  1683. &pCertInfo->Issuer,
  1684. CERT_SIMPLE_NAME_STR |
  1685. CERT_NAME_STR_CRLF_FLAG |
  1686. CERT_NAME_STR_NO_PLUS_FLAG ,
  1687. pCertificate->lpszIssuerInfo,
  1688. cbIssuer);
  1689. }
  1690. CopyMemory(
  1691. (PVOID) &pCertificate->ftStart,
  1692. (PVOID) &pCertInfo->NotBefore,
  1693. sizeof(FILETIME)
  1694. );
  1695. CopyMemory(
  1696. (PVOID) &pCertificate->ftExpiry,
  1697. (PVOID) &pCertInfo->NotAfter,
  1698. sizeof(FILETIME)
  1699. );
  1700. }
  1701. /*if(pSecInfo->dwProtocol)
  1702. {
  1703. DWORD dwProtocolID;
  1704. TCHAR lpszProtocol[100];
  1705. ATTR_MAP ProtocolAttrMap[] =
  1706. {
  1707. {SP_PROT_SSL2_CLIENT, IDS_PROTOCOL_SSL2},
  1708. {SP_PROT_SSL3_CLIENT, IDS_PROTOCOL_SSL3},
  1709. {SP_PROT_PCT1_CLIENT, IDS_PROTOCOL_PCT1},
  1710. {SP_PROT_TLS1_CLIENT, IDS_PROTOCOL_TLS1}
  1711. };
  1712. for(j=0; j < sizeof(ProtocolAttrMap)/sizeof(ProtocolAttrMap[0]); j++)
  1713. {
  1714. if(ProtocolAttrMap[j].dwAttr == pSecInfo->dwProtocol)
  1715. {
  1716. dwProtocolID = ProtocolAttrMap[j].dwStringID;
  1717. break;
  1718. }
  1719. }
  1720. if(LoadString(GlobalDllHandle,
  1721. dwProtocolID,
  1722. lpszProtocol,
  1723. sizeof(lpszProtocol)/sizeof(lpszProtocol[0])))
  1724. {
  1725. pCertificate->lpszProtocolName = NewString(lpszProtocol);
  1726. }
  1727. } */
  1728. pCertificate->dwKeySize = pSecInfo->dwCipherStrength;
  1729. quit:
  1730. if ( error != ERROR_SUCCESS &&
  1731. fCanAlloc
  1732. )
  1733. {
  1734. if ( pCertificate->lpszSubjectInfo )
  1735. {
  1736. LocalFree(pCertificate->lpszSubjectInfo);
  1737. pCertificate->lpszSubjectInfo = NULL;
  1738. }
  1739. if ( pCertificate->lpszIssuerInfo )
  1740. {
  1741. LocalFree(pCertificate->lpszIssuerInfo);
  1742. pCertificate->lpszIssuerInfo = NULL;
  1743. }
  1744. }
  1745. return error;
  1746. }
  1747. /*++
  1748. FormatCertInfo:
  1749. This routine formats the information within a INTERNET_CERTIFICATE_INFO
  1750. structure suitable for display with localization.
  1751. Arguments:
  1752. pCertInfo supplies a pointer to the INTERNET_CERTIFICATE_INFO structure to
  1753. be formatted.
  1754. Return Value:
  1755. NULL - An error occurred. Otherwise, a pointer to the formatted string.
  1756. This string must be freed by the caller via LocalFree.
  1757. Author:
  1758. Doug Barlow (dbarlow) 4/30/1996
  1759. --*/
  1760. LPTSTR
  1761. FormatCertInfo(
  1762. IN INTERNET_CERTIFICATE_INFO *pCertInfo
  1763. )
  1764. {
  1765. LPVOID rgpvParams[9]; // Number of insertable elements in the
  1766. // plszStrings->szCertInfo resource
  1767. // string.
  1768. LPTSTR szResult = NULL;
  1769. int i = 0;
  1770. PLOCAL_STRINGSA plszStrings;
  1771. LPTSTR szFrom = NULL;
  1772. LPTSTR szUntil = NULL;
  1773. //
  1774. // Get the Certificate Information.
  1775. //
  1776. plszStrings = FetchLocalStringsA();
  1777. szFrom = FTtoString(&pCertInfo->ftStart);
  1778. szUntil = FTtoString(&pCertInfo->ftExpiry);
  1779. if ((NULL == szUntil) || (NULL == szFrom))
  1780. goto ErrorExit;
  1781. //ChangeCommaSpaceToCRLF(pCertInfo->lpszSubjectInfo);
  1782. //ChangeCommaSpaceToCRLF(pCertInfo->lpszIssuerInfo);
  1783. rgpvParams[i++] = (LPVOID)pCertInfo->lpszSubjectInfo;
  1784. rgpvParams[i++] = (LPVOID)pCertInfo->lpszIssuerInfo;
  1785. rgpvParams[i++] = (LPVOID)szFrom;
  1786. rgpvParams[i++] = (LPVOID)szUntil;
  1787. rgpvParams[i++] = (LPVOID)pCertInfo->lpszProtocolName;
  1788. rgpvParams[i++] = (LPVOID)pCertInfo->lpszSignatureAlgName;
  1789. rgpvParams[i++] = (LPVOID)pCertInfo->lpszEncryptionAlgName;
  1790. rgpvParams[i++] = (LPVOID)(DWORD_PTR)pCertInfo->dwKeySize;
  1791. if (96 <= pCertInfo->dwKeySize) // Recommended Key strength
  1792. rgpvParams[i++] = (LPVOID)plszStrings->szStrengthHigh;
  1793. else if (64 <= pCertInfo->dwKeySize) // Passable key strength
  1794. rgpvParams[i++] = (LPVOID)plszStrings->szStrengthMedium;
  1795. else // Ick! Low key strength.
  1796. rgpvParams[i++] = (LPVOID)plszStrings->szStrengthLow;
  1797. INET_ASSERT(i == sizeof(rgpvParams) / sizeof(LPVOID));
  1798. i = FormatMessage(
  1799. FORMAT_MESSAGE_ALLOCATE_BUFFER
  1800. | FORMAT_MESSAGE_FROM_STRING
  1801. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1802. plszStrings->szCertInfo,
  1803. 0, 0,
  1804. (LPTSTR)&szResult,
  1805. 0,
  1806. (va_list *)rgpvParams);
  1807. ErrorExit:
  1808. if (NULL != szFrom)
  1809. FREE_MEMORY(szFrom);
  1810. if (NULL != szUntil)
  1811. FREE_MEMORY(szUntil);
  1812. return szResult;
  1813. }
  1814. DWORD
  1815. ConvertUnicodeToUTF8(
  1816. IN LPCWSTR pwszIn,
  1817. IN DWORD dwInBufLen,
  1818. OUT LPSTR pszOut,
  1819. OUT DWORD* pdwOutStrLen,
  1820. IN BOOL bEncode
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. Convert a string of UNICODE characters to UTF-8:
  1825. 0000000000000000..0000000001111111: 0xxxxxxx
  1826. 0000000010000000..0000011111111111: 110xxxxx 10xxxxxx
  1827. 0000100000000000..1111111111111111: 1110xxxx 10xxxxxx 10xxxxxx
  1828. Arguments:
  1829. pwszIn - pointer to input wide-character string
  1830. dwInBufLen - number of CHARACTERS in pwszIn INCLUDING terminating NULL
  1831. pszOut - pointer to output narrow-character buffer
  1832. pdwOutStrLen - STRLEN of pszOut (excl. terminating NULL); IN value discarded.
  1833. bEncode - TRUE if we are to hex encode characters >= 0x80
  1834. Return Value:
  1835. DWORD
  1836. Success - ERROR_SUCCESS
  1837. Failure - NO ERROR checking done. Make sure large enuf buffer passed
  1838. in.
  1839. --*/
  1840. {
  1841. DEBUG_ENTER((DBG_HTTP,
  1842. Dword,
  1843. "ConvertUnicodeToUtf8",
  1844. "%.100wq, %#x, %#x, %#x, %B",
  1845. pwszIn, dwInBufLen, pszOut, pdwOutStrLen, bEncode
  1846. ));
  1847. INET_ASSERT(pwszIn);
  1848. INET_ASSERT((int)dwInBufLen > 0);
  1849. INET_ASSERT(pszOut);
  1850. LPSTR pszStart = pszOut;
  1851. static char hexArray[] = "0123456789ABCDEF";
  1852. while (dwInBufLen--) {
  1853. WORD wchar = *pwszIn++;
  1854. BYTE bchar;
  1855. if (wchar <= 0x007F) {
  1856. *pszOut++ = (BYTE)(wchar);
  1857. continue;
  1858. }
  1859. BYTE lead = ((wchar >= 0x0800) ? 0xE0 : 0xC0);
  1860. int shift = ((wchar >= 0x0800) ? 12 : 6);
  1861. bchar = lead | (BYTE)(wchar >> shift);
  1862. if (bEncode) {
  1863. *pszOut++ = '%';
  1864. *pszOut++ = hexArray[bchar >> 4];
  1865. bchar = hexArray[bchar & 0x0F];
  1866. }
  1867. *pszOut++ = bchar;
  1868. if (wchar >= 0x0800) {
  1869. bchar = 0x80 | (BYTE)((wchar >> 6) & 0x003F);
  1870. if (bEncode) {
  1871. *pszOut++ = '%';
  1872. *pszOut++ = hexArray[bchar >> 4];
  1873. bchar = hexArray[bchar & 0x0F];
  1874. }
  1875. *pszOut++ = bchar;
  1876. }
  1877. bchar = 0x80 | (BYTE)(wchar & 0x003F);
  1878. if (bEncode) {
  1879. *pszOut++ = '%';
  1880. *pszOut++ = hexArray[bchar >> 4];
  1881. bchar = hexArray[bchar & 0x0F];
  1882. }
  1883. *pszOut++ = bchar;
  1884. }
  1885. *pdwOutStrLen = PtrDiff32(pszOut, pszStart)-1;
  1886. DEBUG_LEAVE(ERROR_SUCCESS);
  1887. return ERROR_SUCCESS;
  1888. }
  1889. LPSTR
  1890. ConvertMBCSToUTF8(
  1891. IN LPCSTR lpszMBCSHostName,
  1892. IN DWORD dwMBCSHostNameLength,
  1893. IN DWORD dwCodePage,
  1894. OUT DWORD * pdwUTF8HostNameStrLen,
  1895. IN BOOL bLowerCase
  1896. )
  1897. {
  1898. DEBUG_ENTER((DBG_HTTP,
  1899. String,
  1900. "ConvertMBCSToUTF8",
  1901. "%.100q, %#x, %#x, %#x, %B",
  1902. lpszMBCSHostName, dwMBCSHostNameLength, dwCodePage, (pdwUTF8HostNameStrLen ? *pdwUTF8HostNameStrLen : NULL), bLowerCase
  1903. ));
  1904. DEBUG_DUMP(HTTP,
  1905. "lpszMBCSHostName: strlen+1byte\n",
  1906. lpszMBCSHostName,
  1907. (dwMBCSHostNameLength+1)
  1908. );
  1909. LPSTR lpszUTF8HostName = NULL;
  1910. LPWSTR lpwszWideHostName = NULL;
  1911. if (!lpszMBCSHostName || !dwMBCSHostNameLength)
  1912. goto quit;
  1913. DWORD dwWideLen = MultiByteToWideChar(dwCodePage, 0, lpszMBCSHostName, dwMBCSHostNameLength, NULL, 0);
  1914. //IMPORTANT! NULL terminator not included in dwWideLen
  1915. if (dwWideLen)
  1916. {
  1917. lpwszWideHostName = new WCHAR[dwWideLen+1];
  1918. if (lpwszWideHostName
  1919. && (dwWideLen = MultiByteToWideChar(dwCodePage, 0, lpszMBCSHostName, dwMBCSHostNameLength, lpwszWideHostName, dwWideLen))
  1920. && (lpszUTF8HostName = new CHAR[dwWideLen*3+1]))
  1921. {
  1922. // *pdwUTF8HostNameLength = dwWideLen*3+1;
  1923. // Fill in the terminating NULL character since dwMBCSHostNameLength doesn't include NULL.
  1924. lpwszWideHostName[dwWideLen] = L'\0';
  1925. DEBUG_DUMP(HTTP,
  1926. "Before CharLowerW - lpwszWideHostName: strlen*2+2\n",
  1927. lpwszWideHostName,
  1928. (dwWideLen*2+2)
  1929. );
  1930. if (bLowerCase)
  1931. {
  1932. CharLowerW(lpwszWideHostName);
  1933. DEBUG_DUMP(HTTP,
  1934. "After CharLowerW - lpwszWideHostName: strlen*2+2\n",
  1935. lpwszWideHostName,
  1936. (dwWideLen*2+2)
  1937. );
  1938. }
  1939. DWORD error = ConvertUnicodeToUTF8(lpwszWideHostName, dwWideLen+1, lpszUTF8HostName, pdwUTF8HostNameStrLen, FALSE);
  1940. DEBUG_DUMP(HTTP,
  1941. "ConvertUnicodeToUTF8 - lpszUTF8HostName: strlen+1\n",
  1942. lpszUTF8HostName,
  1943. (*pdwUTF8HostNameStrLen+1)
  1944. );
  1945. // no other error possible
  1946. INET_ASSERT(error == ERROR_SUCCESS);
  1947. }
  1948. }
  1949. quit:
  1950. if (lpwszWideHostName)
  1951. {
  1952. delete [] lpwszWideHostName;
  1953. }
  1954. DEBUG_LEAVE(lpszUTF8HostName);
  1955. return lpszUTF8HostName;
  1956. }
  1957. char *FindNamedValue(char *pszHeader, const char *pszFieldName, unsigned long *pdwValSize) {
  1958. const char ChDblQuote = '\"';
  1959. char *pszBegin, *pszValue;
  1960. BOOL fFound;
  1961. int cbName;
  1962. char *pch = pszHeader;
  1963. ExpectName:
  1964. while (*pch && isspace(*pch))
  1965. pch++;
  1966. ParseName:
  1967. pszBegin = pch;
  1968. while (*pch && isalnum(*pch))
  1969. pch++;
  1970. cbName = (int) (pch-pszBegin);
  1971. fFound = (cbName>0) && !strncmp(pszBegin, pszFieldName, cbName);
  1972. ExpectEqSign:
  1973. while (*pch && isspace(*pch))
  1974. pch++;
  1975. if (*pch=='=')
  1976. pch++;
  1977. ExpectValue:
  1978. while (*pch && isspace(*pch))
  1979. pch++;
  1980. if (*pch=='\"') {
  1981. pch++;
  1982. goto ParseQuotedValue;
  1983. }
  1984. ParseValue:
  1985. pszValue = pch;
  1986. while (*pch && *pch!=',')
  1987. pch++;
  1988. goto ExpectComma;
  1989. ParseQuotedValue:
  1990. pszValue = pch;
  1991. while (*pch && *pch!=ChDblQuote)
  1992. pch++;
  1993. ExpectComma:
  1994. if (fFound) {
  1995. int cbValue = (int) (pch-pszValue);
  1996. *pdwValSize = cbValue;
  1997. return pszValue;
  1998. }
  1999. while (*pch && *pch!=',')
  2000. pch++;
  2001. if (*pch==',') {
  2002. pch++;
  2003. goto ExpectName;
  2004. }
  2005. return NULL;
  2006. }
  2007. // Helper to determine if we're currently loaded during GUI mode setup
  2008. BOOL IsInGUIModeSetup()
  2009. {
  2010. // could be called multiple times in wininet
  2011. static DWORD s_dwSystemSetupInProgress = 42;
  2012. if (42 == s_dwSystemSetupInProgress)
  2013. {
  2014. // Rule is that this value will exist and be equal to 1 if in GUI mode setup.
  2015. // Default to NO, and only do this for upgrades because this is potentially
  2016. // needed for unattended clean installs.
  2017. s_dwSystemSetupInProgress = 0;
  2018. HKEY hKeySetup = NULL;
  2019. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2020. TEXT("System\\Setup"),
  2021. 0,
  2022. KEY_READ,
  2023. &hKeySetup))
  2024. {
  2025. DWORD dwSize = sizeof(s_dwSystemSetupInProgress);
  2026. if (ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
  2027. TEXT("SystemSetupInProgress"),
  2028. NULL,
  2029. NULL,
  2030. (LPBYTE) &s_dwSystemSetupInProgress,
  2031. &dwSize))
  2032. {
  2033. s_dwSystemSetupInProgress = 0;
  2034. }
  2035. else
  2036. {
  2037. dwSize = sizeof(s_dwSystemSetupInProgress);
  2038. if (s_dwSystemSetupInProgress &&
  2039. ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
  2040. TEXT("UpgradeInProgress"),
  2041. NULL,
  2042. NULL,
  2043. (LPBYTE) &s_dwSystemSetupInProgress,
  2044. &dwSize))
  2045. {
  2046. s_dwSystemSetupInProgress = 0;
  2047. }
  2048. }
  2049. RegCloseKey(hKeySetup);
  2050. }
  2051. }
  2052. return s_dwSystemSetupInProgress ? TRUE : FALSE;
  2053. }
  2054. #ifdef DONT_USE_IERT
  2055. /***
  2056. *char *StrTokEx(pstring, control) - tokenize string with delimiter in control
  2057. *
  2058. *Purpose:
  2059. * StrTokEx considers the string to consist of a sequence of zero or more
  2060. * text tokens separated by spans of one or more control chars. the first
  2061. * call, with string specified, returns a pointer to the first char of the
  2062. * first token, and will write a null char into pstring immediately
  2063. * following the returned token. when no tokens remain
  2064. * in pstring a NULL pointer is returned. remember the control chars with a
  2065. * bit map, one bit per ascii char. the null char is always a control char.
  2066. *
  2067. *Entry:
  2068. * char **pstring - ptr to ptr to string to tokenize
  2069. * char *control - string of characters to use as delimiters
  2070. *
  2071. *Exit:
  2072. * returns pointer to first token in string,
  2073. * returns NULL when no more tokens remain.
  2074. * pstring points to the beginning of the next token.
  2075. *
  2076. *WARNING!!!
  2077. * upon exit, the first delimiter in the input string will be replaced with '\0'
  2078. *
  2079. *******************************************************************************/
  2080. char * StrTokEx (char ** pstring, const char * control)
  2081. {
  2082. unsigned char *str;
  2083. const unsigned char *ctrl = (const unsigned char *)control;
  2084. unsigned char map[32];
  2085. int count;
  2086. char *tokenstr;
  2087. if(*pstring == NULL)
  2088. return NULL;
  2089. /* Clear control map */
  2090. for (count = 0; count < 32; count++)
  2091. map[count] = 0;
  2092. /* Set bits in delimiter table */
  2093. do
  2094. {
  2095. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  2096. } while (*ctrl++);
  2097. /* Initialize str. */
  2098. str = (unsigned char *)*pstring;
  2099. /* Find beginning of token (skip over leading delimiters). Note that
  2100. * there is no token if this loop sets str to point to the terminal
  2101. * null (*str == '\0') */
  2102. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  2103. str++;
  2104. tokenstr = (char *)str;
  2105. /* Find the end of the token. If it is not the end of the string,
  2106. * put a null there. */
  2107. for ( ; *str ; str++ )
  2108. {
  2109. if ( map[*str >> 3] & (1 << (*str & 7)) )
  2110. {
  2111. *str++ = '\0';
  2112. break;
  2113. }
  2114. }
  2115. /* string now points to beginning of next token */
  2116. *pstring = (char *)str;
  2117. /* Determine if a token has been found. */
  2118. if ( tokenstr == (char *)str )
  2119. return NULL;
  2120. else
  2121. return tokenstr;
  2122. }
  2123. /***
  2124. * double StrToDbl(const char *str, char **strStop) - convert string to double
  2125. *
  2126. * Purpose:
  2127. * To convert a string into a double. This function supports
  2128. * simple double representations like '1.234', '.5678'. It also support
  2129. * the a killobyte computaion by appending 'k' to the end of the string
  2130. * as in '1.5k' or '.5k'. The results would then become 1536 and 512.5.
  2131. *
  2132. * Return:
  2133. * The double representation of the string.
  2134. * strStop points to the character that caused the scan to stop.
  2135. *
  2136. *******************************************************************************/
  2137. double StrToDbl(const char *str, char **strStop)
  2138. {
  2139. double dbl = 0;
  2140. char *psz;
  2141. int iMult = 1;
  2142. int iKB = 1;
  2143. int iVal = 0;
  2144. BOOL bHaveDot = FALSE;
  2145. psz = (char*)str;
  2146. while(*psz)
  2147. {
  2148. if((*psz >= '0') && (*psz <= '9'))
  2149. {
  2150. iVal = (iVal * 10) + (*psz - '0');
  2151. if(bHaveDot)
  2152. iMult *= 10;
  2153. }
  2154. else if((*psz == '.') && !bHaveDot)
  2155. {
  2156. bHaveDot = TRUE;
  2157. }
  2158. else if((*psz == 'k') || (*psz == 'K'))
  2159. {
  2160. iKB = 1024;
  2161. psz++;
  2162. break;
  2163. }
  2164. else
  2165. {
  2166. break;
  2167. }
  2168. psz++;
  2169. }
  2170. *strStop = psz;
  2171. dbl = (double) (iVal * iKB) / iMult;
  2172. return(dbl);
  2173. }
  2174. #endif // DONT_USE_IERT
  2175. // We need a DBCS-safe version of StrTokEx.
  2176. char* StrTokEx2(char ** pstring, const char * control)
  2177. {
  2178. /*unsigned*/ char *str;
  2179. const /*unsigned*/ char *ctrl = control;
  2180. unsigned char map[32];
  2181. int count;
  2182. char *tokenstr;
  2183. if(*pstring == NULL)
  2184. return NULL;
  2185. /* Clear control map */
  2186. for (count = 0; count < 32; count++)
  2187. map[count] = 0;
  2188. /* Set bits in delimiter table */
  2189. do
  2190. {
  2191. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  2192. ctrl++;
  2193. } while (*ctrl);
  2194. /* Initialize str. */
  2195. str = *pstring;
  2196. /* Find beginning of token (skip over leading delimiters). Note that
  2197. * there is no token if this loop sets str to point to the terminal
  2198. * null (*str == '\0') */
  2199. while ((*str>0) && ((CharNext(str)-str)==1) && (map[*str >> 3] & (1 << (*str & 7))))
  2200. str = CharNext(str);
  2201. tokenstr = str;
  2202. /* Find the end of the token. If it is not the end of the string,
  2203. * put a null there. */
  2204. for ( ; *str ; str = CharNext(str))
  2205. {
  2206. if (((CharNext(str)-str)==1) && (*str>0) && (map[*str >> 3] & (1 << (*str & 7))))
  2207. {
  2208. *str++ = '\0';
  2209. break;
  2210. }
  2211. }
  2212. /* string now points to beginning of next token */
  2213. *pstring = str;
  2214. /* Determine if a token has been found. */
  2215. if ( tokenstr == str )
  2216. return NULL;
  2217. else
  2218. return tokenstr;
  2219. }