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.

623 lines
18 KiB

  1. #include <wininetp.h>
  2. #include "cookieprompt.h"
  3. // checks a string to see if its a domain
  4. BOOL IsStringADomain( LPCSTR pszString)
  5. {
  6. int iLength = 0;
  7. bool fLastCharWasDot = false;
  8. while( pszString[iLength] != '\0')
  9. {
  10. if( fLastCharWasDot && pszString[iLength] == '.')
  11. return FALSE;
  12. fLastCharWasDot = pszString[iLength] == '.';
  13. if( !(IsCharAlphaNumericA( pszString[iLength])
  14. || pszString[iLength] == '.'
  15. || pszString[iLength] == '-'))
  16. {
  17. return FALSE;
  18. }
  19. iLength++;
  20. }
  21. return iLength > 0 ? TRUE : FALSE;
  22. }
  23. LPCSTR FindMinimizedCookieDomainInDomain( LPCSTR pszDomain)
  24. {
  25. LPCSTR pMinimizedDomain = pszDomain + strlen( pszDomain);
  26. do
  27. {
  28. pMinimizedDomain--;
  29. while( pszDomain < pMinimizedDomain
  30. && *(pMinimizedDomain-1) != L'.')
  31. {
  32. pMinimizedDomain--;
  33. }
  34. } while( !IsDomainLegalCookieDomainA( pMinimizedDomain, pszDomain)
  35. && pszDomain < pMinimizedDomain);
  36. return pMinimizedDomain;
  37. }
  38. CCookiePromptHistory::CCookiePromptHistory(const char *pchRegistryPath, bool fUseHKLM) {
  39. _fUseHKLM = fUseHKLM;
  40. lstrcpyn(_szRootKeyName, pchRegistryPath, sizeof(_szRootKeyName)/sizeof(_szRootKeyName[0]));
  41. _hkHistoryRoot = NULL;
  42. }
  43. CCookiePromptHistory::~CCookiePromptHistory() {
  44. if (_hkHistoryRoot)
  45. {
  46. RegCloseKey(_hkHistoryRoot);
  47. _hkHistoryRoot = NULL;
  48. }
  49. }
  50. HKEY CCookiePromptHistory::OpenRootKey()
  51. {
  52. HKEY hkey;
  53. if (_hkHistoryRoot == NULL)
  54. {
  55. if (RegCreateKeyEx(_fUseHKLM ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  56. _szRootKeyName,
  57. 0,
  58. NULL,
  59. REG_OPTION_NON_VOLATILE,
  60. KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
  61. NULL,
  62. &hkey,
  63. NULL) == ERROR_SUCCESS)
  64. {
  65. // if we aren't running in a service, we can cache the key
  66. if (!GlobalIsProcessNtService)
  67. {
  68. if (InterlockedCompareExchangePointer((void**)&_hkHistoryRoot, (void*)hkey, NULL))
  69. {
  70. // someone beat us in the race to fill in _hkHistoryRoot, close ours since we
  71. // failed to set it into _hkHistoryRoot
  72. RegCloseKey(hkey);
  73. hkey = _hkHistoryRoot;
  74. }
  75. }
  76. }
  77. else
  78. {
  79. hkey = NULL;
  80. }
  81. }
  82. else
  83. {
  84. // use the cached value
  85. hkey = _hkHistoryRoot;
  86. }
  87. return hkey;
  88. }
  89. BOOL CCookiePromptHistory::CloseRootKey(HKEY hkeyRoot)
  90. {
  91. BOOL bClosedKey = FALSE;
  92. if (hkeyRoot)
  93. {
  94. if (GlobalIsProcessNtService)
  95. {
  96. // we never cache the key when runnint in a service!
  97. INET_ASSERT(_hkHistoryRoot == NULL);
  98. RegCloseKey(hkeyRoot);
  99. bClosedKey = TRUE;
  100. }
  101. else
  102. {
  103. INET_ASSERT(_hkHistoryRoot == hkeyRoot);
  104. }
  105. }
  106. return bClosedKey;
  107. }
  108. /*
  109. Lookup user-decision for given host+policy combination.
  110. If "pchPolicyID" is NULL the decision applies regardless of policy.
  111. */
  112. BOOL CCookiePromptHistory::lookupDecision(const char *pchHostName,
  113. const char *pchPolicyID,
  114. unsigned long *pdwDecision) {
  115. BOOL fRet = FALSE;
  116. HKEY hSiteKey;
  117. CHAR szBuffer[ INTERNET_MAX_URL_LENGTH];
  118. DWORD dwBufferSize = INTERNET_MAX_URL_LENGTH;
  119. if (SUCCEEDED( UrlUnescape( (LPSTR)pchHostName, szBuffer, &dwBufferSize, 0)) // forced LPSTR conv necessary because COULD be inplace unescape
  120. && IsStringADomain( szBuffer))
  121. {
  122. HKEY hkHistoryRoot = OpenRootKey();
  123. if (hSiteKey = lookupSiteKey(hkHistoryRoot, FindMinimizedCookieDomainInDomain(szBuffer)))
  124. {
  125. DWORD dwType, dwCookieState;
  126. DWORD dwSize = sizeof(dwCookieState);
  127. if (ERROR_SUCCESS == RegQueryValueEx(hSiteKey, pchPolicyID, 0, &dwType, (LPBYTE) &dwCookieState, &dwSize)
  128. && (dwType==REG_DWORD)) {
  129. *pdwDecision = dwCookieState;
  130. fRet = TRUE;
  131. }
  132. RegCloseKey(hSiteKey);
  133. }
  134. CloseRootKey(hkHistoryRoot);
  135. }
  136. //commented code - legacy design where we allowed rules on a non-minimized domain
  137. // while (pchHostName && !fRet)
  138. // {
  139. // if (hSiteKey=lookupSiteKey(pchHostName)) {
  140. //
  141. // DWORD dwType, dwCookieState;
  142. // DWORD dwSize = sizeof(dwCookieState);
  143. //
  144. // if (ERROR_SUCCESS == RegQueryValueEx(hSiteKey, pchPolicyID, 0, &dwType, (LPBYTE) &dwCookieState, &dwSize)
  145. // && (dwType==REG_DWORD)) {
  146. //
  147. // *pdwDecision = dwCookieState;
  148. // fRet = TRUE;
  149. // }
  150. //
  151. // RegCloseKey(hSiteKey);
  152. // }
  153. //
  154. // /* Find and skip over next dot if there is one */
  155. // if (pchHostName = strchr(pchHostName, '.'))
  156. // pchHostName++;
  157. // }
  158. return fRet;
  159. }
  160. /*
  161. Save user-decision for given host+policy combination.
  162. If "pchPolicyID" is NULL the decision applies to all policies
  163. */
  164. BOOL CCookiePromptHistory::saveDecision(const char *pchHostName,
  165. const char *pszPolicyID,
  166. unsigned long dwDecision) {
  167. BOOL fRet = FALSE;
  168. HKEY hSiteKey;
  169. CHAR szBuffer[ INTERNET_MAX_URL_LENGTH];
  170. DWORD dwBufferSize = INTERNET_MAX_URL_LENGTH;
  171. if (SUCCEEDED( UrlUnescape( (LPSTR)pchHostName, szBuffer, &dwBufferSize, 0)) // forced LPSTR conv necessary because COULD be inplace unescape
  172. && IsStringADomain( szBuffer))
  173. {
  174. HKEY hkHistoryRoot = OpenRootKey();
  175. if (hSiteKey = lookupSiteKey(hkHistoryRoot, FindMinimizedCookieDomainInDomain( szBuffer), true))
  176. {
  177. if (ERROR_SUCCESS == RegSetValueEx(hSiteKey, pszPolicyID, 0, REG_DWORD,
  178. (LPBYTE) &dwDecision, sizeof(dwDecision)))
  179. fRet = TRUE;
  180. RegCloseKey(hSiteKey);
  181. }
  182. CloseRootKey(hkHistoryRoot);
  183. }
  184. return fRet;
  185. }
  186. /*
  187. Clear previously saved decision for given hostname+policy combination.
  188. If the policy-ID is "*" all decisions about the site are cleared.
  189. */
  190. BOOL CCookiePromptHistory::clearDecision(const char *pchHostName, const char *pchPolicyID) {
  191. BOOL fRet = FALSE;
  192. int error = ERROR_SUCCESS;
  193. HKEY hkHistoryRoot = OpenRootKey();
  194. if ( pchPolicyID != NULL && !strcmp(pchPolicyID, "*")) {
  195. error = SHDeleteKey(hkHistoryRoot, pchHostName);
  196. }
  197. else if (HKEY hSiteKey = lookupSiteKey(hkHistoryRoot, pchHostName, false)) {
  198. error = RegDeleteValue(hSiteKey, pchPolicyID);
  199. RegCloseKey(hSiteKey);
  200. }
  201. CloseRootKey(hkHistoryRoot);
  202. /* If neither of the previous conditionals were TRUE, then there is
  203. no decision corresponding to that hostname */
  204. return (error==ERROR_SUCCESS);
  205. }
  206. HKEY CCookiePromptHistory::lookupSiteKey(HKEY hkHistoryRoot, const char *pchHostName, bool fCreate) {
  207. HKEY hSiteKey = NULL;
  208. if (hkHistoryRoot)
  209. {
  210. LONG error;
  211. if (fCreate)
  212. {
  213. RegCreateKeyEx(hkHistoryRoot,
  214. pchHostName,
  215. 0,
  216. NULL,
  217. 0,
  218. KEY_QUERY_VALUE | KEY_SET_VALUE,
  219. NULL,
  220. &hSiteKey,
  221. NULL);
  222. }
  223. else
  224. {
  225. RegOpenKeyEx(hkHistoryRoot,
  226. pchHostName,
  227. 0,
  228. KEY_QUERY_VALUE | KEY_SET_VALUE,
  229. &hSiteKey);
  230. }
  231. }
  232. return hSiteKey;
  233. }
  234. BOOL CCookiePromptHistory::clearAll() {
  235. DWORD dwIndex = 0;
  236. DWORD dwRet;
  237. HKEY hkHistoryRoot = OpenRootKey();
  238. do {
  239. FILETIME ft;
  240. char achHostName[INTERNET_MAX_HOST_NAME_LENGTH];
  241. DWORD dwNameLen = sizeof(achHostName);
  242. dwRet = RegEnumKeyEx(hkHistoryRoot,
  243. dwIndex,
  244. achHostName,
  245. & dwNameLen,
  246. NULL, NULL, NULL,
  247. &ft);
  248. if (dwRet == ERROR_SUCCESS)
  249. {
  250. if (SHDeleteKey(hkHistoryRoot, achHostName) != ERROR_SUCCESS)
  251. {
  252. dwIndex++;
  253. }
  254. }
  255. }
  256. while (dwRet == ERROR_SUCCESS);
  257. CloseRootKey(hkHistoryRoot);
  258. return TRUE;
  259. }
  260. unsigned long CCookiePromptHistory::enumerateDecisions(char *pchSiteName, unsigned long *pcbName,
  261. unsigned long *pdwDecision,
  262. unsigned long dwIndex) {
  263. FILETIME ft;
  264. HKEY hkHistoryRoot = OpenRootKey();
  265. DWORD dwRet = RegEnumKeyEx(hkHistoryRoot, dwIndex, pchSiteName, pcbName, NULL, NULL, NULL, &ft);
  266. if (dwRet==ERROR_SUCCESS) {
  267. if (HKEY hSiteKey = lookupSiteKey(hkHistoryRoot, pchSiteName, false)) {
  268. DWORD dwType;
  269. DWORD dwSize = sizeof(DWORD);
  270. dwRet = RegQueryValueEx(hSiteKey, NULL, 0, &dwType, (LPBYTE) pdwDecision, &dwSize);
  271. RegCloseKey(hSiteKey);
  272. }
  273. else
  274. {
  275. dwRet = ERROR_NO_DATA;
  276. }
  277. }
  278. CloseRootKey(hkHistoryRoot);
  279. return dwRet;
  280. }
  281. /*
  282. Exported APIs for manipulating per-site cookie settings
  283. */
  284. extern CCookiePromptHistory cookieUIhistory;
  285. BOOL DeletePersistentCookies(const char *pszDomainSuffix);
  286. INTERNETAPI_(BOOL) InternetSetPerSiteCookieDecisionA( IN LPCSTR pchHostName, DWORD dwDecision)
  287. {
  288. BOOL retVal = FALSE;
  289. if( !pchHostName
  290. || IsBadStringPtr(pchHostName, INTERNET_MAX_URL_LENGTH))
  291. {
  292. SetLastError( ERROR_INVALID_PARAMETER);
  293. return FALSE;
  294. }
  295. if( dwDecision == COOKIE_STATE_UNKNOWN)
  296. {
  297. retVal = cookieUIhistory.clearDecision( pchHostName, "*");
  298. }
  299. else if ( (dwDecision == COOKIE_STATE_ACCEPT) || (dwDecision == COOKIE_STATE_REJECT))
  300. {
  301. retVal = cookieUIhistory.saveDecision( pchHostName, NULL, dwDecision);
  302. /* side-effect: choosing to reject all future cookies for a given website
  303. implicitly deletes existing cache cookies from that site*/
  304. if (dwDecision==COOKIE_STATE_REJECT)
  305. DeletePersistentCookies(pchHostName);
  306. }
  307. return retVal;
  308. }
  309. INTERNETAPI_(BOOL) InternetSetPerSiteCookieDecisionW( IN LPCWSTR pwchHostName, DWORD dwDecision)
  310. {
  311. if( !pwchHostName || IsBadStringPtrW( pwchHostName, INTERNET_MAX_URL_LENGTH))
  312. {
  313. SetLastError( ERROR_INVALID_PARAMETER);
  314. return FALSE;
  315. }
  316. MEMORYPACKET mpHostName;
  317. ALLOC_MB(pwchHostName,0,mpHostName);
  318. if (!mpHostName.psStr)
  319. {
  320. return FALSE;
  321. }
  322. UNICODE_TO_ANSI(pwchHostName, mpHostName);
  323. return InternetSetPerSiteCookieDecisionA( mpHostName.psStr, dwDecision);
  324. }
  325. INTERNETAPI_(BOOL) InternetGetPerSiteCookieDecisionA( IN LPCSTR pchHostName, unsigned long* pResult)
  326. {
  327. if( IsBadWritePtr( pResult, sizeof(unsigned long))
  328. || !pchHostName
  329. || IsBadStringPtr(pchHostName, INTERNET_MAX_URL_LENGTH))
  330. {
  331. SetLastError( ERROR_INVALID_PARAMETER);
  332. return FALSE;
  333. }
  334. return cookieUIhistory.lookupDecision( pchHostName, NULL, pResult);
  335. }
  336. INTERNETAPI_(BOOL) InternetGetPerSiteCookieDecisionW( IN LPCWSTR pwchHostName, unsigned long* pResult)
  337. {
  338. if( IsBadWritePtr( pResult, sizeof(unsigned long))
  339. || !pwchHostName
  340. || IsBadStringPtrW(pwchHostName, INTERNET_MAX_URL_LENGTH))
  341. {
  342. SetLastError( ERROR_INVALID_PARAMETER);
  343. return FALSE;
  344. }
  345. MEMORYPACKET mpHostName;
  346. ALLOC_MB(pwchHostName,0,mpHostName);
  347. if (!mpHostName.psStr)
  348. {
  349. return FALSE;
  350. }
  351. UNICODE_TO_ANSI(pwchHostName, mpHostName);
  352. return InternetGetPerSiteCookieDecisionA( mpHostName.psStr, pResult);
  353. }
  354. INTERNETAPI_(BOOL) InternetEnumPerSiteCookieDecisionA(OUT LPSTR pszSiteName, IN OUT unsigned long *pcSiteNameSize, OUT unsigned long *pdwDecision, IN unsigned long dwIndex) {
  355. int error = ERROR_INVALID_PARAMETER;
  356. if( !pcSiteNameSize || IsBadWritePtr( pcSiteNameSize, sizeof(DWORD)))
  357. {
  358. goto doneInternetEnumPerSiteCookieDecisionA;
  359. }
  360. if( !pszSiteName || IsBadWritePtr( pszSiteName, *pcSiteNameSize))
  361. {
  362. goto doneInternetEnumPerSiteCookieDecisionA;
  363. }
  364. if( !pdwDecision || IsBadWritePtr(pdwDecision, sizeof(DWORD)))
  365. {
  366. goto doneInternetEnumPerSiteCookieDecisionA;
  367. }
  368. error = cookieUIhistory.enumerateDecisions(pszSiteName, pcSiteNameSize, pdwDecision, dwIndex);
  369. if( error == ERROR_SUCCESS)
  370. *pcSiteNameSize += 1; // reg function doesn't count null terminator in size, it should
  371. doneInternetEnumPerSiteCookieDecisionA:
  372. if (error!=ERROR_SUCCESS)
  373. SetLastError(error);
  374. return (error==ERROR_SUCCESS);
  375. }
  376. INTERNETAPI_(BOOL) InternetEnumPerSiteCookieDecisionW(LPWSTR pwszSiteName, unsigned long *pcSiteNameSize, unsigned long *pdwDecision, unsigned long dwIndex) {
  377. DWORD dwErr = ERROR_INVALID_PARAMETER;
  378. BOOL fRet = FALSE;
  379. LPSTR pszSiteName = NULL;
  380. if( !pcSiteNameSize || IsBadWritePtr( pcSiteNameSize, sizeof(DWORD)))
  381. goto cleanup;
  382. if( !pwszSiteName || IsBadWritePtr( pwszSiteName, *pcSiteNameSize * sizeof(WCHAR)))
  383. goto cleanup;
  384. if( !pdwDecision || IsBadWritePtr( pdwDecision, sizeof(DWORD)))
  385. goto cleanup;
  386. pszSiteName = new char[*pcSiteNameSize];
  387. if( !pszSiteName)
  388. {
  389. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  390. goto cleanup;
  391. }
  392. fRet = InternetEnumPerSiteCookieDecisionA( pszSiteName, pcSiteNameSize, pdwDecision, dwIndex);
  393. if (fRet)
  394. {
  395. SHAnsiToUnicode( pszSiteName, pwszSiteName, *pcSiteNameSize);
  396. }
  397. dwErr = ERROR_SUCCESS;
  398. cleanup:
  399. if (dwErr!=ERROR_SUCCESS)
  400. SetLastError(dwErr);
  401. if ( pszSiteName != NULL)
  402. delete [] pszSiteName;
  403. return fRet;
  404. }
  405. INTERNETAPI_(BOOL) InternetClearAllPerSiteCookieDecisions()
  406. {
  407. return cookieUIhistory.clearAll();
  408. }
  409. BOOL DeletePersistentCookies(const char *pszDomainSuffix)
  410. {
  411. BOOL bRetval = TRUE;
  412. DWORD dwEntrySize, dwLastEntrySize;
  413. LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry;
  414. HANDLE hCacheDir = NULL;
  415. dwEntrySize = dwLastEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
  416. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA) new BYTE[dwEntrySize];
  417. if( lpCacheEntry == NULL)
  418. {
  419. bRetval = FALSE;
  420. goto Exit;
  421. }
  422. lpCacheEntry->dwStructSize = dwEntrySize;
  423. Again:
  424. if (!(hCacheDir = FindFirstUrlCacheEntryA("cookie:",lpCacheEntry,&dwEntrySize)))
  425. {
  426. delete [] lpCacheEntry;
  427. switch(GetLastError())
  428. {
  429. case ERROR_NO_MORE_ITEMS:
  430. goto Exit;
  431. case ERROR_INSUFFICIENT_BUFFER:
  432. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)
  433. new BYTE[dwEntrySize];
  434. if( lpCacheEntry == NULL)
  435. {
  436. bRetval = FALSE;
  437. goto Exit;
  438. }
  439. lpCacheEntry->dwStructSize = dwLastEntrySize = dwEntrySize;
  440. goto Again;
  441. default:
  442. bRetval = FALSE;
  443. goto Exit;
  444. }
  445. }
  446. do
  447. {
  448. if (lpCacheEntry->CacheEntryType & COOKIE_CACHE_ENTRY) {
  449. const char achEmpty[] = "";
  450. const char *pszFind = NULL;
  451. const char *pszAtSign = strchr(lpCacheEntry->lpszSourceUrlName, '@');
  452. /*
  453. The source URL for a cookie has the format:
  454. cookie:username@domain/path
  455. The logic for determining whether to delete the cookie checks for
  456. the following conditions on source URL:
  457. 1. presence of the @ sign
  458. 2. presence of argument passed in "pszDomainSuffix" as substring
  459. 3. the substring must occur after a dot or the @ sign
  460. (this avoids partial name matching on domains)
  461. 4. substring must occur as suffix, eg only at the end
  462. this happens IFF the match is followed by forward slash
  463. */
  464. if (pszDomainSuffix==NULL || /* null argument means "delete all cookies" */
  465. (pszAtSign &&
  466. (pszFind=strstr(pszAtSign+1, pszDomainSuffix)) &&
  467. (pszFind[-1]=='.' || pszFind[-1]=='@') &&
  468. pszFind[strlen(pszDomainSuffix)]=='/'))
  469. DeleteUrlCacheEntryA(lpCacheEntry->lpszSourceUrlName);
  470. }
  471. dwEntrySize = dwLastEntrySize;
  472. Retry:
  473. if (!FindNextUrlCacheEntryA(hCacheDir,lpCacheEntry, &dwEntrySize))
  474. {
  475. delete [] lpCacheEntry;
  476. switch(GetLastError())
  477. {
  478. case ERROR_NO_MORE_ITEMS:
  479. goto Exit;
  480. case ERROR_INSUFFICIENT_BUFFER:
  481. lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)
  482. new BYTE[dwEntrySize];
  483. if( lpCacheEntry == NULL)
  484. {
  485. bRetval = FALSE;
  486. goto Exit;
  487. }
  488. lpCacheEntry->dwStructSize = dwLastEntrySize = dwEntrySize;
  489. goto Retry;
  490. default:
  491. bRetval = FALSE;
  492. goto Exit;
  493. }
  494. }
  495. }
  496. while (TRUE);
  497. Exit:
  498. if (hCacheDir)
  499. FindCloseUrlCache(hCacheDir);
  500. return bRetval;
  501. }