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.

670 lines
17 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. cachglob.cxx
  5. Abstract:
  6. contains global variables and functions of urlcache
  7. Author:
  8. Madan Appiah (madana) 12-Dec-1994
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include <wininetp.h>
  14. #include <cache.hxx>
  15. // Typedef for GetFileAttributeEx function
  16. typedef BOOL (WINAPI *PFNGETFILEATTREX)(LPCTSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
  17. #ifdef unix
  18. #include <flock.hxx>
  19. #endif /* unix */
  20. //
  21. // global variables definition.
  22. //
  23. // from wininet\dll\globals.cxx
  24. GLOBAL LONGLONG dwdwHttpDefaultExpiryDelta = 12 * 60 * 60 * (LONGLONG)10000000; // 12 hours in 100ns units
  25. GLOBAL LONGLONG dwdwSessionStartTime; // initialized in InitGlob() in urlcache
  26. GLOBAL LONGLONG dwdwSessionStartTimeDefaultDelta = 0;
  27. // from wininet\dll\Dllentry.cxx
  28. CRITICAL_SECTION GlobalCacheCritSect;
  29. BOOL GlobalCacheInitialized = FALSE;
  30. CConMgr *GlobalUrlContainers = NULL;
  31. LONG GlobalScavengerRunning = -1;
  32. DWORD GlobalRetrieveUrlCacheEntryFileCount = 0;
  33. PFNGETFILEATTREX gpfnGetFileAttributesEx = 0;
  34. char g_szFixup[sizeof(DWORD)];
  35. HINSTANCE g_hFixup;
  36. PFN_FIXUP g_pfnFixup;
  37. MEMORY *CacheHeap = NULL;
  38. HNDLMGR HandleMgr;
  39. GLOBAL DWORD GlobalDiskUsageLowerBound = (4*1024*1024);
  40. GLOBAL DWORD GlobalScavengeFileLifeTime = (10*60);
  41. GLOBAL BOOL GlobalPleaseQuitWhatYouAreDoing = FALSE;
  42. // Identity-related globals
  43. GLOBAL DWORD GlobalIdentity = 0;
  44. GLOBAL GUID GlobalIdentityGuid = { 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  45. GLOBAL BOOL GlobalSuppressCookiesPolicy = FALSE;
  46. #ifdef WININET6
  47. GLOBAL HKEY GlobalCacheHKey = HKEY_CURRENT_USER;
  48. #endif
  49. // shfolder.dll hmod handle
  50. HMODULE g_HMODSHFolder = NULL;
  51. // Shell32.dll hmod handle
  52. HMODULE g_HMODShell32 = NULL;
  53. // GLOBAL SECURITY_CACHE_LIST GlobalCertCache;
  54. GLOBAL DWORD GlobalSettingsVersion=0; // crossprocess settings versionstamp
  55. GLOBAL BOOL GlobalSettingsLoaded = FALSE;
  56. GLOBAL const char vszDisableSslCaching[] = "DisableCachingOfSSLPages";
  57. GLOBAL char vszCurrentUser[MAX_PATH];
  58. GLOBAL DWORD vdwCurrentUserLen = 0;
  59. // cookies info
  60. GLOBAL BOOL vfPerUserCookies = TRUE;
  61. const char vszAnyUserName[]="anyuser";
  62. const char vszPerUserCookies[] = "PerUserCookies";
  63. const char vszInvalidFilenameChars[] = "<>\\\"/:|?*";
  64. #ifdef unix
  65. /***********************
  66. * ReadOnlyCache on Unix
  67. * *********************
  68. * When the cache resides on a file system which is shared over NFS
  69. * and the user can access the same cache from different work-stations,
  70. * it causes a problem. The fix is made so that, the first process has
  71. * write access to the cache and any subsequent browser process which
  72. * is started from a different host will receive a read-only version
  73. * of the cache and will not be able to get cookies etc. A symbolic
  74. * link is created in $HOME/.microsoft named ielock. Creation and
  75. * deletion of this symbolic link should be atomic. The functions
  76. * CreateAtomicCacheLockFile and DeleteAtomicCacheLockFile implement
  77. * this behavior. When a readonly cache is used, cache deletion is
  78. * not allowed (Scavenger thread need not be launched).
  79. *
  80. * g_ReadOnlyCaches denotes if a readonly cache is being used.
  81. * gszLockingHost denotes the host that holds the cache lock.
  82. */
  83. BOOL g_ReadOnlyCaches = FALSE;
  84. char *gszLockingHost = 0;
  85. extern "C" void unixGetWininetCacheLockStatus(BOOL *pBool, char **pszLockingHost)
  86. {
  87. if(pBool)
  88. *pBool = g_ReadOnlyCaches;
  89. if(pszLockingHost)
  90. *pszLockingHost = gszLockingHost;
  91. }
  92. #endif /* unix */
  93. #ifdef CHECKLOCK_PARANOID
  94. // Code to enforce strict ordering on resources to prevent deadlock
  95. // One cannot attempt to take the critical section for the first time
  96. // if one holds a container lock
  97. DWORD dwThreadLocked;
  98. DWORD dwLockLevel;
  99. void CheckEnterCritical(CRITICAL_SECTION *_cs)
  100. {
  101. EnterCriticalSection(_cs);
  102. if (_cs == &GlobalCacheCritSect && dwLockLevel++ == 0)
  103. {
  104. dwThreadLocked = GetCurrentThreadId();
  105. if (GlobalUrlContainers) GlobalUrlContainers->CheckNoLocks(dwThreadLocked);
  106. }
  107. }
  108. void CheckLeaveCritical(CRITICAL_SECTION *_cs)
  109. {
  110. if (_cs == &GlobalCacheCritSect)
  111. {
  112. INET_ASSERT(dwLockLevel);
  113. if (dwLockLevel == 1)
  114. {
  115. if (GlobalUrlContainers) GlobalUrlContainers->CheckNoLocks(dwThreadLocked);
  116. dwThreadLocked = 0;
  117. }
  118. dwLockLevel--;
  119. }
  120. LeaveCriticalSection(_cs);
  121. }
  122. #endif
  123. //
  124. /*++
  125. --*/
  126. BOOL InitGlobals (void)
  127. {
  128. if (GlobalCacheInitialized)
  129. return TRUE;
  130. LOCK_CACHE();
  131. if (GlobalCacheInitialized)
  132. goto done;
  133. GetWininetUserName();
  134. // Read registry settings.
  135. OpenInternetSettingsKey();
  136. { // Detect a fixup handler. Open scope to avoid compiler complaint.
  137. REGISTRY_OBJ roCache (HKEY_LOCAL_MACHINE, OLD_CACHE_KEY);
  138. if (ERROR_SUCCESS == roCache.GetStatus())
  139. {
  140. DWORD cbFixup = sizeof(g_szFixup);
  141. if (ERROR_SUCCESS != roCache.GetValue
  142. ("FixupKey", (LPBYTE) g_szFixup, &cbFixup))
  143. {
  144. g_szFixup[0] = 0;
  145. }
  146. if (g_szFixup[0] != 'V' || g_szFixup[3] != 0)
  147. {
  148. g_szFixup[0] = 0;
  149. }
  150. }
  151. }
  152. /*
  153. {
  154. REGISTRY_OBJ roCache (HKEY_LOCAL_MACHINE, CACHE5_KEY);
  155. if (ERROR_SUCCESS == roCache.GetStatus())
  156. {
  157. DWORD dwDefTime;
  158. if (ERROR_SUCCESS == roCache.GetValue("SessionStartTimeDefaultDeltaSecs", &dwDefTime))
  159. {
  160. dwdwSessionStartTimeDefaultDelta = dwDefTime * (LONGLONG)10000000;
  161. dwdwSessionStartTime -= dwdwSessionStartTimeDefaultDelta;
  162. }
  163. }
  164. }
  165. */
  166. // Seed the random number generator for random file name generation.
  167. srand(GetTickCount());
  168. GetCurrentGmtTime((LPFILETIME)&dwdwSessionStartTime);
  169. GlobalUrlContainers = new CConMgr();
  170. GlobalCacheInitialized =
  171. GlobalUrlContainers && (GlobalUrlContainers->GetStatus() == ERROR_SUCCESS);
  172. if( GlobalCacheInitialized )
  173. {
  174. DWORD dwError = GlobalUrlContainers->CreateDefaultGroups();
  175. INET_ASSERT(dwError == ERROR_SUCCESS);
  176. }
  177. else
  178. {
  179. delete GlobalUrlContainers;
  180. GlobalUrlContainers = NULL;
  181. }
  182. done:
  183. UNLOCK_CACHE();
  184. return GlobalCacheInitialized;
  185. }
  186. URLCACHEAPI
  187. BOOL
  188. WINAPI
  189. DLLUrlCacheEntry(
  190. IN DWORD Reason
  191. )
  192. /*++
  193. Routine Description:
  194. Performs global initialization and termination for all protocol modules.
  195. This function only handles process attach and detach which are required for
  196. global initialization and termination, respectively. We disable thread
  197. attach and detach. New threads calling Wininet APIs will get an
  198. INTERNET_THREAD_INFO structure created for them by the first API requiring
  199. this structure
  200. Arguments:
  201. DllHandle - handle of this DLL. Unused
  202. Reason - process attach/detach or thread attach/detach
  203. Reserved - if DLL_PROCESS_ATTACH, NULL means DLL is being dynamically
  204. loaded, else static. For DLL_PROCESS_DETACH, NULL means DLL
  205. is being freed as a consequence of call to FreeLibrary()
  206. else the DLL is being freed as part of process termination
  207. Return Value:
  208. BOOL
  209. Success - TRUE
  210. Failure - FALSE. Failed to initialize
  211. --*/
  212. {
  213. HMODULE ModuleHandleKernel;
  214. switch (Reason)
  215. {
  216. case DLL_PROCESS_ATTACH:
  217. #ifdef CHECKLOCK_PARANOID
  218. dwThreadLocked = 0;
  219. dwLockLevel = 0;
  220. #endif
  221. ModuleHandleKernel = GetModuleHandle("KERNEL32");
  222. if (ModuleHandleKernel)
  223. {
  224. gpfnGetFileAttributesEx = (PFNGETFILEATTREX)
  225. GetProcAddress(ModuleHandleKernel, "GetFileAttributesExA");
  226. }
  227. InitializeCriticalSection (&GlobalCacheCritSect);
  228. // RunOnceUrlCache (NULL, NULL, NULL, 0); // test stub
  229. #ifdef unix
  230. if(CreateAtomicCacheLockFile(&g_ReadOnlyCaches,&gszLockingHost) == FALSE)
  231. return FALSE;
  232. #endif /* unix */
  233. break;
  234. case DLL_PROCESS_DETACH:
  235. // Clean up containers list.
  236. if (GlobalUrlContainers != NULL)
  237. {
  238. delete GlobalUrlContainers;
  239. GlobalUrlContainers = NULL;
  240. }
  241. // Unload fixup handler.
  242. if (g_hFixup)
  243. FreeLibrary (g_hFixup);
  244. HandleMgr.Destroy();
  245. #ifdef unix
  246. DeleteAtomicCacheLockFile();
  247. #endif /* unix */
  248. DeleteCriticalSection (&GlobalCacheCritSect);
  249. break;
  250. }
  251. return TRUE;
  252. }
  253. //
  254. // proxy info
  255. //
  256. // GLOBAL PROXY_INFO_GLOBAL GlobalProxyInfo;
  257. //
  258. // DLL version info
  259. //
  260. /*
  261. GLOBAL INTERNET_VERSION_INFO InternetVersionInfo = {
  262. WININET_MAJOR_VERSION,
  263. WININET_MINOR_VERSION
  264. };
  265. */
  266. //
  267. // HTTP version info - default 1.0
  268. //
  269. // GLOBAL HTTP_VERSION_INFO HttpVersionInfo = {1, 0};
  270. BOOL
  271. PrintFileTimeInInternetFormat(
  272. FILETIME *lpft,
  273. LPSTR lpszBuff,
  274. DWORD dwSize
  275. )
  276. {
  277. SYSTEMTIME sSysTime;
  278. if (dwSize < INTERNET_RFC1123_BUFSIZE) {
  279. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  280. return (FALSE);
  281. }
  282. if (!FileTimeToSystemTime(((CONST FILETIME *)lpft), &sSysTime)) {
  283. return (FALSE);
  284. }
  285. return (InternetTimeFromSystemTime( &sSysTime,
  286. lpszBuff));
  287. }
  288. BOOL
  289. GetWininetUserName(
  290. VOID
  291. )
  292. {
  293. BOOL fRet = FALSE;
  294. DWORD dwT;
  295. CHAR *ptr;
  296. // Note this critsect could be blocked for a while if RPC gets involved...
  297. // EnterCriticalSection(&GeneralInitCritSec);
  298. if (vdwCurrentUserLen) {
  299. fRet = TRUE;
  300. goto Done;
  301. }
  302. dwT = sizeof(vszCurrentUser);
  303. if (vfPerUserCookies) {
  304. fRet = GetUserName(vszCurrentUser, &dwT);
  305. if (!fRet) {
  306. DEBUG_PRINT(HTTP,
  307. ERROR,
  308. ("GetUsername returns %d\n",
  309. GetLastError()
  310. ));
  311. }
  312. }
  313. if (fRet == FALSE){
  314. strcpy(vszCurrentUser, vszAnyUserName);
  315. fRet = TRUE;
  316. }
  317. // Downcase the username.
  318. ptr = vszCurrentUser;
  319. while (*ptr)
  320. {
  321. *ptr = tolower(*ptr);
  322. ptr++;
  323. }
  324. INET_ASSERT(fRet == TRUE);
  325. vdwCurrentUserLen = (DWORD) (ptr - vszCurrentUser);
  326. Done:
  327. // LeaveCriticalSection(&GeneralInitCritSec);
  328. return (fRet);
  329. }
  330. /***
  331. *char *StrTokEx(pstring, control) - tokenize string with delimiter in control
  332. *
  333. *Purpose:
  334. * StrTokEx considers the string to consist of a sequence of zero or more
  335. * text tokens separated by spans of one or more control chars. the first
  336. * call, with string specified, returns a pointer to the first char of the
  337. * first token, and will write a null char into pstring immediately
  338. * following the returned token. when no tokens remain
  339. * in pstring a NULL pointer is returned. remember the control chars with a
  340. * bit map, one bit per ascii char. the null char is always a control char.
  341. *
  342. *Entry:
  343. * char **pstring - ptr to ptr to string to tokenize
  344. * char *control - string of characters to use as delimiters
  345. *
  346. *Exit:
  347. * returns pointer to first token in string,
  348. * returns NULL when no more tokens remain.
  349. * pstring points to the beginning of the next token.
  350. *
  351. *WARNING!!!
  352. * upon exit, the first delimiter in the input string will be replaced with '\0'
  353. *
  354. *******************************************************************************/
  355. char * StrTokExA (char ** pstring, const char * control)
  356. {
  357. unsigned char *str;
  358. const unsigned char *ctrl = (const unsigned char *)control;
  359. unsigned char map[32];
  360. int count;
  361. char *tokenstr;
  362. if(*pstring == NULL)
  363. return NULL;
  364. /* Clear control map */
  365. for (count = 0; count < 32; count++)
  366. map[count] = 0;
  367. /* Set bits in delimiter table */
  368. do
  369. {
  370. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  371. } while (*ctrl++);
  372. /* Initialize str. */
  373. str = (unsigned char *)*pstring;
  374. /* Find beginning of token (skip over leading delimiters). Note that
  375. * there is no token if this loop sets str to point to the terminal
  376. * null (*str == '\0') */
  377. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  378. str++;
  379. tokenstr = (char *)str;
  380. /* Find the end of the token. If it is not the end of the string,
  381. * put a null there. */
  382. for ( ; *str ; str++ )
  383. {
  384. if ( map[*str >> 3] & (1 << (*str & 7)) )
  385. {
  386. *str++ = '\0';
  387. break;
  388. }
  389. }
  390. /* string now points to beginning of next token */
  391. *pstring = (char *)str;
  392. /* Determine if a token has been found. */
  393. if ( tokenstr == (char *)str )
  394. return NULL;
  395. else
  396. return tokenstr;
  397. }
  398. const char vszUserNameHeader[4] = "~U:";
  399. // ---- from wininet\http\httptime.cxx
  400. //
  401. // external prototypes
  402. //
  403. /********************* Local data *******************************************/
  404. /******************** HTTP date format strings ******************************/
  405. // Month
  406. static const char cszJan[]="Jan";
  407. static const char cszFeb[]="Feb";
  408. static const char cszMar[]="Mar";
  409. static const char cszApr[]="Apr";
  410. static const char cszMay[]="May";
  411. static const char cszJun[]="Jun";
  412. static const char cszJul[]="Jul";
  413. static const char cszAug[]="Aug";
  414. static const char cszSep[]="Sep";
  415. static const char cszOct[]="Oct";
  416. static const char cszNov[]="Nov";
  417. static const char cszDec[]="Dec";
  418. // DayOfWeek in rfc1123 or asctime format
  419. static const char cszSun[]="Sun";
  420. static const char cszMon[]="Mon";
  421. static const char cszTue[]="Tue";
  422. static const char cszWed[]="Wed";
  423. static const char cszThu[]="Thu";
  424. static const char cszFri[]="Fri";
  425. static const char cszSat[]="Sat";
  426. // List of weekdays for rfc1123 or asctime style date
  427. static const char *rgszWkDay[7] =
  428. {
  429. cszSun,cszMon,cszTue,cszWed,cszThu,cszFri,cszSat
  430. };
  431. // list of month strings for all date formats
  432. static const char *rgszMon[12] =
  433. {
  434. cszJan,cszFeb,cszMar,cszApr,cszMay,cszJun,
  435. cszJul,cszAug,cszSep,cszOct,cszNov,cszDec
  436. };
  437. /******************** HTTP date format strings ******************************/
  438. /* Http date format: Sat, 29 Oct 1994 19:43:00 GMT */
  439. const char cszHttpDateFmt[]="%s, %02i %s %02i %02i:%02i:%02i GMT";
  440. /****************************************************************************/
  441. INTERNETAPI
  442. BOOL
  443. WINAPI
  444. InternetTimeFromSystemTimeA(
  445. IN CONST SYSTEMTIME *pst, // input GMT time
  446. IN DWORD dwRFC, // RFC format: must be FORMAT_RFC1123
  447. OUT LPSTR lpszTime, // output string buffer
  448. IN DWORD cbTime // output buffer size
  449. )
  450. /*++
  451. Routine Description:
  452. Converts system time to a time string fromatted in the specified RFC format
  453. Arguments:
  454. pst: points to the SYSTEMTIME to be converted
  455. dwRFC: RFC number of the format in which the result string should be returned
  456. lpszTime: buffer to return the string in
  457. cbTime: size of lpszTime buffer
  458. Return Value:
  459. BOOL
  460. TRUE - string converted
  461. FALSE - couldn't convert string, GetLastError returns windows error code
  462. --*/
  463. {
  464. DEBUG_ENTER_API((DBG_API,
  465. Handle,
  466. "InternetTimeFromSystemTimeA",
  467. "%#x, %d, %#x, %d",
  468. pst,
  469. dwRFC,
  470. lpszTime,
  471. cbTime
  472. ));
  473. DWORD dwErr;
  474. BOOL fResult = FALSE;
  475. FILETIME ft;
  476. if ( dwRFC != INTERNET_RFC1123_FORMAT
  477. || IsBadReadPtr (pst, sizeof(*pst))
  478. || IsBadWritePtr (lpszTime, cbTime)
  479. || !SystemTimeToFileTime(pst, &ft)
  480. )
  481. {
  482. dwErr = ERROR_INVALID_PARAMETER;
  483. }
  484. else if (cbTime < INTERNET_RFC1123_BUFSIZE)
  485. {
  486. dwErr = ERROR_INSUFFICIENT_BUFFER;
  487. }
  488. else
  489. {
  490. SYSTEMTIME st;
  491. if ((pst->wDay < 0)
  492. || (pst->wDay > 6))
  493. {
  494. // ST2FT ignores the week of the day; so if we round trip back,
  495. // it should place the correct week of the day.
  496. FileTimeToSystemTime(&ft, &st);
  497. pst = &st;
  498. }
  499. wsprintf (lpszTime, cszHttpDateFmt,
  500. rgszWkDay[pst->wDayOfWeek],
  501. pst->wDay,
  502. rgszMon[pst->wMonth-1],
  503. pst->wYear,
  504. pst->wHour,
  505. pst->wMinute,
  506. pst->wSecond);
  507. fResult = TRUE;
  508. }
  509. if (!fResult)
  510. {
  511. SetLastError(dwErr);
  512. DEBUG_ERROR(INET, dwErr);
  513. }
  514. DEBUG_LEAVE_API(fResult);
  515. return fResult;
  516. }