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.

1277 lines
39 KiB

  1. // File: util.cxx
  2. //
  3. // Contents: Utility classes.
  4. //
  5. // Classes: CRefCount, CRegKey
  6. //
  7. // Functions://
  8. // History:
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "zonepch.h"
  12. #include "advpub.h"
  13. #ifdef UNIX
  14. #include <platform.h>
  15. #endif /* UNIX */
  16. #include "shfolder.h"
  17. // Misc utility functions and declarations.
  18. #define DRIVE_UNINIT 0xFFFF // Indicates that we haven't called GetDriveType yet.
  19. DWORD rgdwDriveTypeCache[26]; // one for each drive letter.
  20. BOOL g_bInit = FALSE;
  21. BOOL g_bUseHKLMOnly = FALSE;
  22. static LPWSTR s_pwzCacheDir;
  23. static HRESULT GetCacheDirectory( );
  24. static LPWSTR s_pwzCookieDir = NULL;
  25. static CHAR *s_szMarkPrefix = "<!-- saved from url=(%04d)";
  26. static CHAR *s_szMarkSuffix = " -->\r\n";
  27. CSharedMem g_SharedMem;
  28. static CRITICAL_SECTION g_csect_GetCacheDir;
  29. BOOL IsZonesInitialized( )
  30. {
  31. return g_bInit;
  32. }
  33. BOOL ZonesInit( )
  34. {
  35. if (!g_bInit)
  36. {
  37. DWORD dwType;
  38. DWORD dwSize = sizeof(DWORD);
  39. DWORD dwDefault = FALSE ; // If no entry found default is use HKCU.
  40. g_bInit = TRUE;
  41. // Call the shlwapi wrapper function that directly reads in a value for us.
  42. // Note that if the call fails we have the right value in g_bHKLMOnly already.
  43. SHRegGetUSValue(SZPOLICIES, SZHKLMONLY, &dwType, &g_bUseHKLMOnly,
  44. &dwSize, TRUE, &dwDefault, sizeof(dwDefault));
  45. InitializeCriticalSection(&CUrlZoneManager::s_csect);
  46. CUrlZoneManager::s_bcsectInit = TRUE;
  47. CSecurityManager::GlobalInit();
  48. // Initialize the drive type cache.
  49. for ( int i = 0 ; i < ARRAYSIZE(rgdwDriveTypeCache) ; i++ )
  50. rgdwDriveTypeCache[i] = DRIVE_UNINIT;
  51. //initialize critical section for GetCacheDirectory()
  52. InitializeCriticalSection(&g_csect_GetCacheDir);
  53. }
  54. return TRUE;
  55. }
  56. VOID ZonesUnInit ( )
  57. {
  58. CUrlZoneManager::Cleanup( );
  59. CSecurityManager::GlobalCleanup( );
  60. g_SharedMem.Release();
  61. // Free any memory allocated for the cache directory.
  62. delete [] s_pwzCacheDir;
  63. if(s_pwzCookieDir)
  64. delete [] s_pwzCookieDir;
  65. // Destroy the GetCacheDirectory() critsec.
  66. DeleteCriticalSection(&g_csect_GetCacheDir);
  67. }
  68. // IEAK calls this function so force us to re-read the global settings for
  69. // HKLM vs HKCU.
  70. STDAPI ZonesReInit(DWORD /* dwReserved */)
  71. {
  72. DWORD dwType;
  73. DWORD dwDefault = g_bUseHKLMOnly;
  74. DWORD dwSize = sizeof(DWORD);
  75. DWORD dwError = SHRegGetUSValue(SZPOLICIES, SZHKLMONLY, &dwType, &g_bUseHKLMOnly,
  76. &dwSize, TRUE, &dwDefault, sizeof(dwDefault));
  77. return HRESULT_FROM_WIN32(dwError);
  78. }
  79. // SHDOCVW calls this during Thicket save to get the comment to flag the
  80. // saved file as
  81. STDAPI GetMarkOfTheWeb(LPCSTR pszURL, LPCSTR pszFile, DWORD dwFlags, LPSTR *ppszMark)
  82. {
  83. HRESULT hr = S_OK;
  84. int cchURL = lstrlenA(pszURL);
  85. // Note - the code assumes that lstrlen(IDS_MARK_PREFIX)
  86. // equals wsprintf(IDS_MARK_PREFIX, lstrlen(url)
  87. *ppszMark = (LPSTR)LocalAlloc( LMEM_FIXED, (lstrlenA(s_szMarkPrefix) +
  88. cchURL +
  89. lstrlenA(s_szMarkSuffix) +
  90. 1) * sizeof(CHAR) );
  91. if ( *ppszMark )
  92. {
  93. wsprintfA( *ppszMark, s_szMarkPrefix, cchURL );
  94. lstrcatA( *ppszMark, pszURL );
  95. lstrcatA( *ppszMark, s_szMarkSuffix );
  96. }
  97. else
  98. hr = E_OUTOFMEMORY;
  99. return hr;
  100. }
  101. // The security manager calls this to sniff a file: URL for the Mark of the Web
  102. BOOL FileBearsMarkOfTheWeb(LPCTSTR pszFile, LPWSTR *ppszURLMark)
  103. {
  104. BOOL fMarked = FALSE;
  105. HANDLE hFile;
  106. CHAR szMarkPrefix[MARK_PREFIX_SIZE];
  107. CHAR szMarkSuffix[MARK_SUFFIX_SIZE];
  108. WCHAR wzMarkPrefix[MARK_PREFIX_SIZE];
  109. WCHAR wzMarkSuffix[MARK_SUFFIX_SIZE];
  110. BOOL fIsInUnicode = FALSE;
  111. DWORD cchReadBufLen = 0;
  112. DWORD cchURL;
  113. CHAR *szMarkHead = NULL;
  114. WCHAR *wzMarkHead = NULL;
  115. CHAR *szMarkSuf = NULL;
  116. WCHAR *wzMarkSuf = NULL;
  117. CHAR *pszURLMark = NULL;
  118. DWORD cchReadLen = 0;
  119. char *pszTmp = NULL;
  120. char *szReadBuf = NULL;
  121. int iIteration = 1;
  122. lstrcpyA(szMarkPrefix, s_szMarkPrefix);
  123. lstrcpyA(szMarkSuffix, s_szMarkSuffix);
  124. hFile = CreateFile( pszFile, GENERIC_READ, FILE_SHARE_READ ,
  125. NULL, OPEN_EXISTING,
  126. FILE_ATTRIBUTE_NORMAL, NULL );
  127. if ( hFile != INVALID_HANDLE_VALUE )
  128. {
  129. DWORD cchPrefix = lstrlenA(szMarkPrefix);
  130. DWORD dwRead;
  131. CHAR szHeader[UNICODE_HEADER_SIZE];
  132. DWORD cchHeader = UNICODE_HEADER_SIZE;
  133. if (ReadFile(hFile, szHeader, cchHeader, &dwRead, NULL) &&
  134. cchHeader == dwRead)
  135. {
  136. if ((BYTE)szHeader[0] == (BYTE)0xFF && (BYTE)szHeader[1] == (BYTE)0xFE)
  137. {
  138. fIsInUnicode = TRUE;
  139. }
  140. else
  141. {
  142. fIsInUnicode = FALSE;
  143. SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
  144. TransAssert(GetLastError() == NO_ERROR);
  145. }
  146. }
  147. else
  148. {
  149. // Unable to sniff for header
  150. goto Exit;
  151. }
  152. // File pointer is not at "real" beginning of file, regardless of
  153. // whether we are reading a UNICODE or ANSI file.
  154. szReadBuf = NULL;
  155. cchReadBufLen = 0;
  156. iIteration = 1;
  157. // Anchor NULL to make szMarkPrefix: <!-- saved from url=
  158. szMarkPrefix[cchPrefix-6] = '\0';
  159. if (fIsInUnicode)
  160. {
  161. if (!MultiByteToWideChar(CP_ACP, 0, szMarkPrefix, -1,
  162. wzMarkPrefix, MARK_PREFIX_SIZE))
  163. {
  164. goto Exit;
  165. }
  166. if (!MultiByteToWideChar(CP_ACP, 0, szMarkSuffix, -1,
  167. wzMarkSuffix, MARK_SUFFIX_SIZE))
  168. {
  169. goto Exit;
  170. }
  171. }
  172. for (;;)
  173. {
  174. cchReadBufLen = INTERNET_MAX_URL_LENGTH +
  175. EXTRA_BUFFER_SIZE * iIteration + 1;
  176. if (fIsInUnicode)
  177. {
  178. cchReadBufLen *= 2;
  179. }
  180. szReadBuf = new char[cchReadBufLen];
  181. if (!szReadBuf)
  182. {
  183. goto Exit;
  184. }
  185. cchReadLen = (fIsInUnicode) ? (cchReadBufLen - 2) : (cchReadBufLen - 1);
  186. if (ReadFile(hFile, szReadBuf, cchReadLen, &dwRead, NULL))
  187. {
  188. // look for mark of the web
  189. if (fIsInUnicode)
  190. {
  191. szReadBuf[dwRead] = L'\0';
  192. wzMarkHead = StrStrW((WCHAR *)szReadBuf, wzMarkPrefix);
  193. if (wzMarkHead)
  194. {
  195. // Look for mark of the web suffix. If we don't
  196. // have it, that means that we didn't have enough
  197. // space for the buffer, and we need to try again
  198. // with more space.
  199. wzMarkSuf = StrStrW(wzMarkHead, wzMarkSuffix);
  200. if (wzMarkSuf)
  201. {
  202. // Found suffix. We're done.
  203. break;
  204. }
  205. else
  206. {
  207. if (dwRead < cchReadLen)
  208. {
  209. // We've already read everything, and
  210. // we didn't find the suffix!
  211. goto Exit;
  212. }
  213. // Didn't find suffix because buffer was too
  214. // small. Try it again
  215. delete [] szReadBuf;
  216. szReadBuf = NULL;
  217. iIteration++;
  218. SetFilePointer(hFile, 2, 0, FILE_BEGIN);
  219. TransAssert(GetLastError() == NO_ERROR);
  220. continue;
  221. }
  222. }
  223. else
  224. {
  225. // Can't find the mark head! Must find it on
  226. // first iteration, or we give up.
  227. goto Exit;
  228. }
  229. }
  230. else
  231. {
  232. // We are dealing with ANSI
  233. szReadBuf[dwRead] = '\0';
  234. szMarkHead = StrStrA(szReadBuf, szMarkPrefix);
  235. if (szMarkHead)
  236. {
  237. // Look for mark of the web suffix. If we don't
  238. // have it, that means that we didn't have enough
  239. // space for the buffer, and we need to try again
  240. // with more space.
  241. szMarkSuf = StrStrA(szMarkHead, szMarkSuffix);
  242. if (szMarkSuf)
  243. {
  244. // Found suffix. We're done.
  245. break;
  246. }
  247. else
  248. {
  249. if (dwRead < cchReadLen)
  250. {
  251. // We've already read everything, and
  252. // we didn't find the suffix!
  253. goto Exit;
  254. }
  255. // Didn't find suffix because buffer was too
  256. // small. Try it again
  257. delete [] szReadBuf;
  258. szReadBuf = NULL;
  259. iIteration++;
  260. SetFilePointer(hFile, 0, 0, FILE_BEGIN);
  261. TransAssert(GetLastError() == NO_ERROR);
  262. continue;
  263. }
  264. }
  265. else
  266. {
  267. // Can't find the mark head! Must find it on
  268. // first iteration, or we give up.
  269. goto Exit;
  270. }
  271. }
  272. }
  273. else
  274. {
  275. // Read failure!
  276. TransAssert(0);
  277. }
  278. }
  279. // now wzMarkHead or szMarkHead points to beginning of the mark
  280. // of the web, and wzMarkSuf or szMarkSuf point to the mark suffix
  281. if (fIsInUnicode)
  282. {
  283. DWORD cchURL = 0;
  284. LPWSTR wzPtr = StrStrW(wzMarkHead, L"=(");
  285. if (!wzPtr) goto Exit;
  286. wzPtr += 2; // skip to beginning of length
  287. TransAssert((wzMarkSuf >= wzPtr));
  288. wzPtr[4] = L'\0'; // anchor NULL
  289. cchURL = StrToIntW(wzPtr);
  290. if (cchURL > INTERNET_MAX_URL_LENGTH)
  291. {
  292. cchURL = INTERNET_MAX_URL_LENGTH;
  293. }
  294. //the string length of the url should be greater than or equal to cchURL.
  295. //else abort the allocation.
  296. if ((wzMarkSuf-(wzPtr+5)) < (INT)cchURL)
  297. goto Exit;
  298. *ppszURLMark = (WCHAR*)LocalAlloc(LMEM_FIXED, (cchURL+1) * sizeof(WCHAR));
  299. if (!*ppszURLMark)
  300. {
  301. goto Exit;
  302. }
  303. // StrCpyN length includes NULL terminator
  304. StrCpyNW(*ppszURLMark, wzPtr + 5, cchURL + 1);
  305. }
  306. else
  307. {
  308. DWORD cchURL = 0;
  309. LPSTR szPtr = StrStrA(szMarkHead, "=(");
  310. if (!szPtr) goto Exit;
  311. szPtr += 2; // skip to beginning of length
  312. TransAssert((szMarkSuf >= szPtr));
  313. szPtr[4] = '\0'; // anchor NULL
  314. cchURL = StrToIntA(szPtr);
  315. if (cchURL > INTERNET_MAX_URL_LENGTH)
  316. {
  317. cchURL = INTERNET_MAX_URL_LENGTH;
  318. }
  319. //the string length of the url should be greater than or equal to cchURL.
  320. //else abort the allocation.
  321. if ((szMarkSuf-(szPtr+5)) < (INT)cchURL)
  322. goto Exit;
  323. pszTmp = new char[cchURL + 1];
  324. if (!pszTmp)
  325. {
  326. goto Exit;
  327. }
  328. *ppszURLMark = (WCHAR*)LocalAlloc(LMEM_FIXED, (cchURL+1) * sizeof(WCHAR));
  329. if (!*ppszURLMark)
  330. {
  331. goto Exit;
  332. }
  333. // StrCpyN length includes NULL terminator
  334. StrCpyNA(pszTmp, szPtr + 5, cchURL + 1);
  335. MultiByteToWideChar(CP_ACP, 0, pszTmp, -1, *ppszURLMark, cchURL);
  336. (*ppszURLMark)[cchURL] = '\0';
  337. }
  338. if (szReadBuf)
  339. {
  340. delete [] szReadBuf;
  341. szReadBuf = NULL;
  342. }
  343. }
  344. else
  345. {
  346. // CreateFile failure
  347. goto Exit;
  348. }
  349. fMarked = TRUE;
  350. Exit:
  351. if (hFile != INVALID_HANDLE_VALUE)
  352. {
  353. CloseHandle(hFile);
  354. }
  355. if (szReadBuf)
  356. {
  357. delete [] szReadBuf;
  358. }
  359. if (pszURLMark)
  360. {
  361. delete [] pszURLMark;
  362. }
  363. if (pszTmp) {
  364. delete [] pszTmp;
  365. }
  366. return fMarked;
  367. }
  368. //This function may now be called by one or more threads from IsFileInCacheDir() ( since we've moved invocation out of
  369. //ZonesInit ( to prevent LoadLibrary() being called during DllMain execution ) ).
  370. //Hence, we need a critsec for mutual exclusion..
  371. //This also means that if for some reason, this function fails the first time, it may be called mutliple times by different
  372. //threads, whereas earlier if it failed during ZonesInit(), it was never tried again.
  373. HRESULT GetCacheDirectory( )
  374. {
  375. HRESULT hr = E_FAIL;
  376. HMODULE hModShell=NULL;
  377. HMODULE hModShfolder=NULL;
  378. PFNSHGETFOLDERPATH pfnGetFolderPath;
  379. EnterCriticalSection(&g_csect_GetCacheDir);
  380. // If another thread managed to get this while this thread was waiting, bail out with success.
  381. // Optionally, if we want this code to execute only once, we can use a static boolean check.
  382. if (s_pwzCacheDir != NULL && s_pwzCookieDir != NULL)
  383. {
  384. hr = S_OK;
  385. goto Cleanup;
  386. }
  387. hModShell = LoadLibrary(TEXT("shell32.dll"));
  388. if (NULL == hModShell)
  389. {
  390. hr = HRESULT_FROM_WIN32(GetLastError());
  391. goto Cleanup;
  392. }
  393. #ifdef UNICODE
  394. pfnGetFolderPath = (PFNSHGETFOLDERPATHW)GetProcAddress(hModShell, "SHGetFolderPathW");
  395. #else
  396. pfnGetFolderPath = (PFNSHGETFOLDERPATHA)GetProcAddress(hModShell, "SHGetFolderPathA");
  397. #endif
  398. if (pfnGetFolderPath == NULL)
  399. {
  400. hModShfolder = LoadLibrary(TEXT("shfolder.dll"));
  401. if (hModShfolder == NULL)
  402. {
  403. hr = HRESULT_FROM_WIN32(GetLastError());
  404. goto Cleanup;
  405. }
  406. #ifdef UNICODE
  407. pfnGetFolderPath = (PFNSHGETFOLDERPATHW)GetProcAddress(hModShfolder, "SHGetFolderPathW");
  408. #else
  409. pfnGetFolderPath = (PFNSHGETFOLDERPATHA)GetProcAddress(hModShfolder, "SHGetFolderPathA");
  410. #endif
  411. }
  412. if (pfnGetFolderPath == NULL)
  413. {
  414. hr = HRESULT_FROM_WIN32(GetLastError());
  415. }
  416. else
  417. {
  418. TCHAR rgchCachePath[MAX_PATH];
  419. hr = pfnGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL, 0, rgchCachePath);
  420. if (rgchCachePath[0] == TEXT('\0'))
  421. hr = E_FAIL;
  422. if (SUCCEEDED(hr))
  423. {
  424. if (s_pwzCacheDir != NULL)
  425. {
  426. delete [] s_pwzCacheDir;
  427. s_pwzCacheDir = NULL;
  428. }
  429. // Allocate memory for the new location.
  430. s_pwzCacheDir = new TCHAR[lstrlen(rgchCachePath) + 1];
  431. if (s_pwzCacheDir != NULL)
  432. {
  433. StrCpy(s_pwzCacheDir, rgchCachePath);
  434. hr = S_OK;
  435. }
  436. else
  437. {
  438. hr = E_OUTOFMEMORY;
  439. goto Cleanup;
  440. }
  441. }
  442. hr = pfnGetFolderPath(NULL, CSIDL_COOKIES, NULL, 0, rgchCachePath);
  443. if (rgchCachePath[0] == TEXT('\0'))
  444. hr = E_FAIL;
  445. if (SUCCEEDED(hr))
  446. {
  447. if (s_pwzCookieDir != NULL)
  448. {
  449. delete [] s_pwzCookieDir;
  450. s_pwzCookieDir = NULL;
  451. }
  452. // Allocate memory for the new location.
  453. s_pwzCookieDir = new TCHAR[lstrlen(rgchCachePath) + 1];
  454. if (s_pwzCookieDir != NULL)
  455. {
  456. StrCpy(s_pwzCookieDir, rgchCachePath);
  457. hr = S_OK;
  458. }
  459. else
  460. hr = E_OUTOFMEMORY;
  461. }
  462. }
  463. Cleanup:
  464. if (hModShfolder)
  465. FreeLibrary(hModShfolder);
  466. if (hModShell)
  467. FreeLibrary(hModShell);
  468. LeaveCriticalSection(&g_csect_GetCacheDir);
  469. return hr;
  470. }
  471. #if NOTUSED // Keep this code around in the unlikely event that we resurrect the Unix port.
  472. // This function gets the location of the cache directory.
  473. HRESULT GetCacheDirectory( )
  474. {
  475. DWORD dwType;
  476. // First figure out if we are using per-user cache or per-machine cache.
  477. // This decides which registry key to look at for the cache value.
  478. BOOL fPerUserCache = TRUE;
  479. #ifndef UNIX
  480. OSVERSIONINFOA osvi = {0};
  481. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  482. GetVersionExA(&osvi);
  483. if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
  484. {
  485. fPerUserCache = TRUE;
  486. }
  487. else
  488. {
  489. DWORD dwUserProfile = 0;
  490. DWORD dwSize = sizeof(dwUserProfile);
  491. // Determine if user profiles are enabled.
  492. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZLOGON, SZUSERPROFILES, &dwType, &dwUserProfile, &dwSize))
  493. && (dwUserProfile != 0 ))
  494. {
  495. fPerUserCache = TRUE;
  496. // Look for the exceptional case where User Profiles are enabled but the cache is still
  497. // global.
  498. dwSize = sizeof(dwUserProfile);
  499. if ((ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZCACHE, SZUSERPROFILES, &dwType, &dwUserProfile, &dwSize))
  500. && (dwUserProfile == 0))
  501. {
  502. fPerUserCache = FALSE;
  503. }
  504. }
  505. else
  506. {
  507. fPerUserCache = FALSE;
  508. }
  509. }
  510. #endif /* !UNIX */
  511. HRESULT hr = S_OK;
  512. #ifdef UNIX
  513. WCHAR wszIE5Dir[] = L"ie5/";
  514. DWORD cchPath = MAX_PATH + sizeof(wszIE5Dir)/sizeof(WCHAR);
  515. #else
  516. DWORD cchPath = MAX_PATH;
  517. #endif /* !UNIX */
  518. s_pwzCacheDir = new WCHAR[cchPath];
  519. DWORD dwError = NOERROR;
  520. // First figure out if we are using per-user cache or per-machine cache.
  521. // This decides which registry key to look at for the cache value.
  522. if (s_pwzCacheDir != NULL)
  523. {
  524. LPCWSTR pwzKey = fPerUserCache ? SZSHELLFOLDER : SZCACHECONTENT;
  525. LPCWSTR pwzValue = fPerUserCache ? SZTIFS : SZCACHEPATH ;
  526. HKEY hKey = fPerUserCache ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  527. dwError = SHGetValueW(hKey, pwzKey, pwzValue, &dwType, s_pwzCacheDir, &cchPath);
  528. }
  529. else
  530. {
  531. dwError = ERROR_NOT_ENOUGH_MEMORY;
  532. }
  533. if (dwError != NOERROR)
  534. {
  535. delete [] s_pwzCacheDir;
  536. s_pwzCacheDir = NULL;
  537. hr = HRESULT_FROM_WIN32(dwError);
  538. }
  539. else
  540. {
  541. TransAssert(s_pwzCacheDir != NULL);
  542. PathRemoveBackslashW(s_pwzCacheDir);
  543. #ifdef UNIX
  544. {
  545. int ccPath, index;
  546. int lenIE5Dir = lstrlen(wszIE5Dir);
  547. ccPath = lstrlen(s_pwzCacheDir);
  548. index = ccPath - 1;
  549. while(index >= 0 && s_pwzCacheDir[index] != FILENAME_SEPARATOR_W)
  550. index--;
  551. index++;
  552. memmove(&s_pwzCacheDir[index+lenIE5Dir],&s_pwzCacheDir[index],(ccPath-index+1)*sizeof(TCHAR));
  553. memcpy(&s_pwzCacheDir[index], wszIE5Dir, lenIE5Dir*sizeof(TCHAR));
  554. }
  555. #endif /* UNIX */
  556. hr = S_OK;
  557. }
  558. return hr;
  559. }
  560. #endif // NOTUSED
  561. BOOL IsFileInCacheDir(LPCWSTR pwzFile)
  562. {
  563. BOOL bReturn = FALSE;
  564. TCHAR szLongPath[MAX_PATH];
  565. if(!GetLongPathNameWrapW(pwzFile, szLongPath, sizeof(szLongPath)/sizeof(TCHAR)))
  566. {
  567. goto exit;
  568. }
  569. if (s_pwzCacheDir == NULL || s_pwzCookieDir == NULL)
  570. {
  571. if (! (SUCCEEDED(GetCacheDirectory())) )
  572. goto exit;
  573. }
  574. if(PathIsPrefixW(s_pwzCacheDir, szLongPath))
  575. {
  576. bReturn = TRUE;
  577. }
  578. exit:
  579. return bReturn;
  580. }
  581. BOOL IsFileInCookieDir(LPCWSTR pwzFile)
  582. {
  583. BOOL bReturn = FALSE;
  584. TCHAR szLongPath[MAX_PATH];
  585. if(!GetLongPathNameWrapW(pwzFile, szLongPath, sizeof(szLongPath)/sizeof(TCHAR)))
  586. {
  587. goto exit;
  588. }
  589. if (s_pwzCacheDir == NULL || s_pwzCookieDir == NULL)
  590. {
  591. if (! (SUCCEEDED(GetCacheDirectory())) )
  592. goto exit;
  593. }
  594. if(PathIsPrefixW(s_pwzCookieDir, szLongPath))
  595. {
  596. bReturn = TRUE;
  597. }
  598. exit:
  599. return bReturn;
  600. }
  601. // This function takes a DWORD and returns a wide char string
  602. // in hex. There is no leading 0x and the leading 0's are stripped off
  603. // This is to avoid pulling in the general wsprintfW into wininet which is
  604. // pretty big. You have to pass in enough memory to write the resulting string
  605. // into ( i.e >= 9 chars)
  606. BOOL DwToWchar(DWORD dw, LPWSTR pwz, int radix)
  607. {
  608. char sz[9];
  609. LPSTR psz = sz;
  610. LPSTR pszTemp = (LPSTR)pwz;
  611. char rgFormatHex[] = "%lX";
  612. char rgFormatDecimal[] = "%ld";
  613. char *pszFormat;
  614. if (radix == 16)
  615. pszFormat = rgFormatHex;
  616. else if (radix == 10)
  617. pszFormat = rgFormatDecimal;
  618. else
  619. {
  620. TransAssert(FALSE);
  621. return FALSE;
  622. }
  623. if (wsprintfA(sz, pszFormat, dw) == 0)
  624. {
  625. return FALSE;
  626. }
  627. #ifndef unix
  628. // Everything in the string sz is ANSI.
  629. while (*psz != 0)
  630. {
  631. *pszTemp++ = *psz++;
  632. *pszTemp++ = '\0';
  633. }
  634. // Put the trailing NULL to the wide-char string.
  635. *pszTemp++ = '\0';
  636. *pszTemp++ = '\0';
  637. #else
  638. while(*psz != 0)
  639. *pwz++ = (WCHAR)(DWORD)*psz++;
  640. *pwz++ = 0;
  641. #endif /* unix */
  642. return TRUE;
  643. }
  644. // Drive type caching function.
  645. //
  646. DWORD GetDriveTypeFromCacheA(LPCSTR lpsz)
  647. {
  648. // NOTE: The retail version doesn't do any paramater validation to determine if this path is
  649. // a valid one. So something like CTHISISGARBAGE will return the drive type for C:.
  650. // This is just meant to be used inside the security manager so we can bypass these
  651. // checks.
  652. TransAssert(lstrlenA(lpsz) >= 3); // c:\ for example
  653. TransAssert(lpsz[1] == ':' && lpsz[2] == '\\');
  654. #ifndef unix
  655. CHAR ch = (CHAR)CharLowerA((LPSTR)lpsz[0]);
  656. #else
  657. CHAR *pch = CharLowerA((LPSTR)lpsz);
  658. CHAR ch = *pch;
  659. #endif /* unix */
  660. #ifndef UNIX
  661. if (ch >= 'a' && ch <= 'z')
  662. {
  663. // First check the cache to see if the entry already exists.
  664. int index = ch - 'a';
  665. if (rgdwDriveTypeCache[index] == DRIVE_UNINIT)
  666. {
  667. rgdwDriveTypeCache[index] = GetDriveTypeA(lpsz);
  668. }
  669. TransAssert(rgdwDriveTypeCache[index] != DRIVE_UNINIT);
  670. return rgdwDriveTypeCache[index];
  671. }
  672. #else
  673. if (ch == '/')
  674. {
  675. // IEUNIX - On unix we have only one drive "/" which is of type fixed
  676. // This was causing a wrong zone to be calculated for unix paths.
  677. return DRIVE_FIXED;
  678. }
  679. #endif
  680. else
  681. {
  682. return DRIVE_UNKNOWN;
  683. }
  684. }
  685. // Helper to determine if we're currently loaded during GUI mode setup
  686. BOOL IsInGUIModeSetup()
  687. {
  688. static DWORD s_dwSystemSetupInProgress = 42;
  689. if (42 == s_dwSystemSetupInProgress)
  690. {
  691. // Rule is that this value will exist and be equal to 1 if in GUI mode setup.
  692. // Default to NO, and only do this for upgrades because this is potentially
  693. // needed for unattended clean installs.
  694. s_dwSystemSetupInProgress = 0;
  695. HKEY hKeySetup = NULL;
  696. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  697. TEXT("System\\Setup"),
  698. 0,
  699. KEY_READ,
  700. &hKeySetup))
  701. {
  702. DWORD dwSize = sizeof(s_dwSystemSetupInProgress);
  703. if (ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
  704. TEXT("SystemSetupInProgress"),
  705. NULL,
  706. NULL,
  707. (LPBYTE) &s_dwSystemSetupInProgress,
  708. &dwSize))
  709. {
  710. s_dwSystemSetupInProgress = 0;
  711. }
  712. else
  713. {
  714. dwSize = sizeof(s_dwSystemSetupInProgress);
  715. if (s_dwSystemSetupInProgress &&
  716. ERROR_SUCCESS != RegQueryValueEx (hKeySetup,
  717. TEXT("UpgradeInProgress"),
  718. NULL,
  719. NULL,
  720. (LPBYTE) &s_dwSystemSetupInProgress,
  721. &dwSize))
  722. {
  723. s_dwSystemSetupInProgress = 0;
  724. }
  725. }
  726. RegCloseKey(hKeySetup);
  727. }
  728. }
  729. return s_dwSystemSetupInProgress ? TRUE : FALSE;
  730. }
  731. /////////////////////////////////////////////////////////////////////////////
  732. // CRegKey
  733. LONG CRegKey::Close()
  734. {
  735. LONG lRes = ERROR_SUCCESS;
  736. if (m_hKey != NULL)
  737. {
  738. lRes = SHRegCloseUSKey(m_hKey);
  739. m_hKey = NULL;
  740. }
  741. return lRes;
  742. }
  743. LONG CRegKey::Create(HUSKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired)
  744. {
  745. HUSKEY hKey = NULL;
  746. // BUGBUG : Is this the correct flag to call this function with?
  747. DWORD dwFlags = m_bHKLMOnly ? SHREGSET_FORCE_HKLM : SHREGSET_FORCE_HKCU;
  748. LONG lRes = SHRegCreateUSKey(lpszKeyName, samDesired, hKeyParent, &hKey, dwFlags);
  749. if (lRes == ERROR_SUCCESS)
  750. {
  751. lRes = Close();
  752. m_hKey = hKey;
  753. }
  754. return lRes;
  755. }
  756. LONG CRegKey::Open(HUSKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired)
  757. {
  758. HUSKEY hKey = NULL;
  759. LONG lRes = SHRegOpenUSKey(lpszKeyName, samDesired, hKeyParent, &hKey, m_bHKLMOnly);
  760. if (lRes == ERROR_SUCCESS)
  761. {
  762. lRes = Close();
  763. TransAssert(lRes == ERROR_SUCCESS);
  764. m_hKey = hKey;
  765. }
  766. return lRes;
  767. }
  768. LONG CRegKey::QueryValue(DWORD* pdwValue, LPCTSTR lpszValueName)
  769. {
  770. DWORD dwType = NULL;
  771. DWORD dwCount = sizeof(DWORD);
  772. LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
  773. pdwValue, &dwCount, m_bHKLMOnly, NULL, 0);
  774. TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_DWORD));
  775. TransAssert((lRes!=ERROR_SUCCESS) || (dwCount == sizeof(DWORD)));
  776. return lRes;
  777. }
  778. LONG CRegKey::QueryValue(LPTSTR szValue, LPCTSTR lpszValueName, DWORD* pdwCount)
  779. {
  780. TransAssert(pdwCount != NULL);
  781. DWORD dwType = 0;
  782. LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
  783. szValue, pdwCount, m_bHKLMOnly, NULL, 0);
  784. TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_SZ) ||
  785. (dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ));
  786. return lRes;
  787. }
  788. LONG CRegKey::QueryBinaryValue(LPBYTE pb, LPCTSTR lpszValueName, DWORD* pdwCount)
  789. {
  790. TransAssert(pdwCount != NULL);
  791. DWORD dwType = NULL;
  792. LONG lRes = SHRegQueryUSValue(m_hKey, lpszValueName, &dwType,
  793. pb, pdwCount, m_bHKLMOnly, NULL, 0);
  794. TransAssert((lRes!=ERROR_SUCCESS) || (dwType == REG_BINARY));
  795. return lRes;
  796. }
  797. LONG WINAPI CRegKey::SetValue(HUSKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName, BOOL bHKLMOnly)
  798. {
  799. TransAssert(lpszValue != NULL);
  800. CRegKey key(bHKLMOnly);
  801. LONG lRes = key.Create(hKeyParent, lpszKeyName, KEY_WRITE);
  802. if (lRes == ERROR_SUCCESS)
  803. lRes = key.SetValue(lpszValue, lpszValueName);
  804. return lRes;
  805. }
  806. LONG CRegKey::SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName)
  807. {
  808. TransAssert(lpszValue != NULL);
  809. CRegKey key(m_bHKLMOnly);
  810. LONG lRes = key.Create(m_hKey, lpszKeyName, KEY_WRITE);
  811. if (lRes == ERROR_SUCCESS)
  812. lRes = key.SetValue(lpszValue, lpszValueName);
  813. return lRes;
  814. }
  815. //////////////////////////////////////////////////////////////////////////
  816. //
  817. // Autoregistration entry points
  818. //
  819. //////////////////////////////////////////////////////////////////////////
  820. HRESULT CallRegInstall(LPSTR szSection)
  821. {
  822. HRESULT hr = E_FAIL;
  823. HINSTANCE hinstAdvPack = LoadLibraryA("ADVPACK.DLL");
  824. if (hinstAdvPack)
  825. {
  826. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, achREGINSTALL);
  827. if (pfnri)
  828. {
  829. hr = pfnri(g_hInst, szSection, NULL);
  830. }
  831. FreeLibrary(hinstAdvPack);
  832. }
  833. return hr;
  834. }
  835. /*
  836. * We want to show the inetcpl settings as "Custom" in case of an upgrade only.
  837. *
  838. * We detect an upgrade using an HKCU key which only urlmon selfreg. code can set
  839. * Earlier we used the "Zones" key.
  840. *
  841. * In Whistler, the problem is some other module ( Office maybe ) registers this key,
  842. * so that even on a fresh install, we assume it's Custom.
  843. * Fix is to change the key we check for.
  844. *
  845. * On Millenium, there was a problem with double registration - in this case, the fix
  846. * would be to also put in the version key and check both for existence of a known key
  847. * and to match version to avoid slamming "Custom" in if there's a version match.
  848. */
  849. BOOL
  850. ShouldSetCustom()
  851. {
  852. #define SZPATH_ZONES_LOCAL_A "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\0\\"
  853. BOOL fUpgrade = FALSE;
  854. HKEY hKeyZones;
  855. LONG dwResult = RegOpenKeyExA(
  856. HKEY_CURRENT_USER,
  857. SZPATH_ZONES_LOCAL_A,
  858. 0,
  859. KEY_READ,
  860. &hKeyZones);
  861. if (dwResult == ERROR_SUCCESS)
  862. {
  863. //key exists, not an upgrade
  864. RegCloseKey(hKeyZones);
  865. fUpgrade = TRUE;
  866. }
  867. return fUpgrade;
  868. }
  869. STDAPI
  870. ZonesDllInstall
  871. (
  872. IN BOOL bInstall, // Install or Uninstall
  873. IN LPCWSTR pwStr
  874. )
  875. {
  876. TransAssert(pwStr != NULL);
  877. HRESULT hr = S_OK;
  878. BOOL bUseHKLM = TRUE;
  879. if (pwStr && (0 == StrCmpIW(pwStr, L"HKCU")))
  880. {
  881. // Don't write to HKCU during GUI mode setup. Otherwise,
  882. // the values may get slammed into all profiles during an upgrade.
  883. if (IsInGUIModeSetup())
  884. return hr;
  885. bUseHKLM = FALSE;
  886. }
  887. if (bInstall && pwStr)
  888. {
  889. if(!StrCmpIW(pwStr, L"HKCUSoft"))
  890. {
  891. return CallRegInstall("RegSoften.HKCU");
  892. }
  893. else if(!StrCmpIW(pwStr, L"HKCUHard"))
  894. {
  895. return CallRegInstall("RegHarden.HKCU");
  896. }
  897. else if(!StrCmpIW(pwStr, L"HKLMHard"))
  898. {
  899. return CallRegInstall("RegHarden.HKLM");
  900. }
  901. else if(!StrCmpIW(pwStr, L"HKLMSoft"))
  902. {
  903. return CallRegInstall("RegSoften.HKLM");
  904. }
  905. }
  906. if ( bInstall )
  907. {
  908. BOOL fSetHKCUToCustom = FALSE; //Default to no-upgrade to avoid overwriting default zone settings.
  909. if (!bUseHKLM)
  910. {
  911. fSetHKCUToCustom = ShouldSetCustom();
  912. }
  913. // Backup IE3 user agent string, but don't do ever do these during
  914. // GUI mode setup
  915. if (!IsInGUIModeSetup())
  916. {
  917. CallRegInstall("BackupUserAgent");
  918. CallRegInstall("BackupConnectionSettings");
  919. }
  920. CallRegInstall(bUseHKLM ? "Backup.HKLM" : "Backup.HKCU");
  921. hr = CallRegInstall(bUseHKLM ? "Reg.HKLM" : "Reg.HKCU");
  922. if (!bUseHKLM)
  923. {
  924. // Bug # 19514: To appease the press, we need to change the default for scripting unsafe activex
  925. // controls to "disable" instead of "prompt". But at install time we can't blindly overwrite
  926. // the existing value. We have to check if the users Intranet/Internet zones are at medium
  927. // security from the previous install. To avoid instantiating the zone manager at registration
  928. // time we also hardcode the registry values here.
  929. #define SZINTRANET SZZONES TEXT("1")
  930. #define SZTRUSTED SZZONES TEXT("2")
  931. #define SZINTERNET SZZONES TEXT("3")
  932. #define SZUNTRUSTED SZZONES TEXT("4")
  933. TransAssert(URLZONE_INTRANET == 1);
  934. TransAssert(URLZONE_TRUSTED == 2);
  935. TransAssert(URLZONE_INTERNET == 3);
  936. TransAssert(URLZONE_UNTRUSTED == 4);
  937. DWORD dwCurrentLevel ;
  938. CRegKey regKeyIntranet(FALSE);
  939. if ((regKeyIntranet.Open(NULL, SZINTRANET, KEY_READ) == ERROR_SUCCESS) &&
  940. (regKeyIntranet.QueryValue(&dwCurrentLevel, SZCURRLEVEL) == NOERROR) &&
  941. (dwCurrentLevel == URLTEMPLATE_MEDIUM)
  942. )
  943. {
  944. CallRegInstall("Intranet.HackActiveX");
  945. }
  946. CRegKey regKeyInternet(FALSE);
  947. if ((regKeyInternet.Open(NULL, SZINTERNET, KEY_READ) == ERROR_SUCCESS) &&
  948. (regKeyInternet.QueryValue(&dwCurrentLevel, SZCURRLEVEL) == NOERROR) &&
  949. (dwCurrentLevel == URLTEMPLATE_MEDIUM)
  950. )
  951. {
  952. CallRegInstall("Internet.HackActiveX");
  953. }
  954. if (fSetHKCUToCustom)
  955. {
  956. //108298/104506 We want to preserve the settings prior to an upgrade, but at
  957. // the same time, we dont want to show a security level inconsistent with the
  958. // actual policies ( which is what will happen if templates change or default
  959. // policy values change. So set all templates to CUSTOM on install.
  960. CRegKey regKeyIntranet(FALSE);
  961. if(regKeyIntranet.Open(NULL, SZINTRANET, KEY_WRITE) == ERROR_SUCCESS)
  962. regKeyIntranet.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
  963. CRegKey regKeyTrusted(FALSE);
  964. if(regKeyTrusted.Open(NULL, SZTRUSTED, KEY_WRITE) == ERROR_SUCCESS)
  965. regKeyTrusted.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
  966. CRegKey regKeyInternet(FALSE);
  967. if(regKeyInternet.Open(NULL, SZINTERNET, KEY_WRITE) == ERROR_SUCCESS)
  968. regKeyInternet.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
  969. CRegKey regKeyUntrusted(FALSE);
  970. if(regKeyUntrusted.Open(NULL, SZUNTRUSTED, KEY_WRITE) == ERROR_SUCCESS)
  971. regKeyUntrusted.SetValue(URLTEMPLATE_CUSTOM, SZCURRLEVEL);
  972. }
  973. }
  974. }
  975. else
  976. {
  977. // Restore IE3 user agent string.
  978. CallRegInstall("RestoreUserAgent");
  979. CallRegInstall("RestoreConnectionSettings");
  980. hr = CallRegInstall(bUseHKLM ? "Unreg.HKLM" : "UnReg.HKCU");
  981. if (bUseHKLM)
  982. hr = CallRegInstall("Restore.HKLM");
  983. }
  984. return hr;
  985. }
  986. // CSharedMem member functions.
  987. BOOL CSharedMem::Init(LPCSTR pszNamePrefix, DWORD dwSize)
  988. {
  989. // Note that this function is in ANSI, because we don't have Unicode wrappers
  990. // for the file-mapping functions on Win9x and these need to work on Win9x.
  991. // Create the name for the file mapping object.
  992. // We want this name to be unique per logged in user.
  993. // We will choose a name of the form ZonesSM_"UserName" for systems prior to NT5
  994. // BUGBUG: On Terminal server should we use Global\ in the name. If a user is logged on in multiple
  995. // sessions this seems desirable, but not sure if registry changes get reflected in the other
  996. // session anyway.
  997. DWORD cchPrefix = lstrlenA(pszNamePrefix);
  998. LPSTR pszHandleName = (LPSTR) _alloca(cchPrefix + MAX_PATH);
  999. if (pszHandleName == NULL)
  1000. return FALSE;
  1001. memcpy(pszHandleName, pszNamePrefix, cchPrefix);
  1002. // Move pointer to after the fixed part of the string.
  1003. LPSTR psz = pszHandleName + cchPrefix;
  1004. // Technically the max username possible is UNLEN which is less than MAX_PATH.
  1005. // We use MAX_PATH to not pull in another random header into the build.
  1006. DWORD dwMaxNameSize = MAX_PATH;
  1007. if (GetUserNameA(psz, &dwMaxNameSize))
  1008. {
  1009. // If succeeded, rgchHandleName now contains the exact same thing.
  1010. }
  1011. else
  1012. {
  1013. TransAssert(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
  1014. // if it fails, we will assume no logged on user and just use a global shared memory
  1015. // section of the base name
  1016. }
  1017. m_dwSize = dwSize ;
  1018. // First try to see if the shared memory section already exists.
  1019. m_hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE,
  1020. NULL,
  1021. PAGE_READWRITE,
  1022. 0,
  1023. m_dwSize,
  1024. pszHandleName) ;
  1025. if (m_hFileMapping != NULL)
  1026. {
  1027. m_lpVoidShared = MapViewOfFile(m_hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  1028. }
  1029. return (m_hFileMapping != NULL && m_lpVoidShared != NULL);
  1030. }
  1031. VOID CSharedMem::Release()
  1032. {
  1033. if (m_lpVoidShared != NULL)
  1034. {
  1035. UnmapViewOfFile(m_lpVoidShared);
  1036. m_lpVoidShared = NULL;
  1037. }
  1038. if (m_hFileMapping != NULL)
  1039. {
  1040. CloseHandle(m_hFileMapping);
  1041. m_hFileMapping = NULL;
  1042. }
  1043. m_dwSize = 0;
  1044. }
  1045. // This function will return NULL if either we couldn not initialize the shared memory
  1046. // for some reason or the offset specified is not in range. The offset should be specified
  1047. // in number of bytes.
  1048. LPVOID CSharedMem::GetPtr(DWORD dwOffset)
  1049. {
  1050. if (m_lpVoidShared == NULL)
  1051. return NULL;
  1052. if (dwOffset >= m_dwSize)
  1053. return NULL;
  1054. return (BYTE *)m_lpVoidShared + dwOffset;
  1055. }