Source code of Windows XP (NT5)
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.

2112 lines
47 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. cookies.c
  5. Abstract:
  6. Implements the cookies type module, which abstracts physical access to
  7. cookies, and queues all cookies to be migrated when the cookies component
  8. is enabled.
  9. Author:
  10. Calin Negreanu (calinn) 11 July 2000
  11. Revision History:
  12. jimschm 12-Oct-2000 Substantial redesign to work around several limiations
  13. in wininet apis
  14. --*/
  15. //
  16. // Includes
  17. //
  18. #include "pch.h"
  19. #include "logmsg.h"
  20. #include <wininet.h>
  21. #define DBG_COOKIES "Cookies"
  22. //
  23. // Strings
  24. //
  25. #define S_COOKIES_POOL_NAME "Cookies"
  26. #define S_COOKIES_NAME TEXT("Cookies")
  27. #define S_COOKIES_SHELL_FOLDER TEXT("Cookies.CSIDL_COOKIES")
  28. //
  29. // Constants
  30. //
  31. #define MAX_COOKIE_FILE_SIZE 65536
  32. //
  33. // Macros
  34. //
  35. // None
  36. //
  37. // Types
  38. //
  39. typedef struct {
  40. PCTSTR Pattern;
  41. HASHTABLE_ENUM HashData;
  42. } COOKIES_ENUM, *PCOOKIES_ENUM;
  43. //
  44. // Globals
  45. //
  46. PMHANDLE g_CookiesPool = NULL;
  47. BOOL g_DelayCookiesOp;
  48. HASHTABLE g_CookiesTable;
  49. MIG_OBJECTTYPEID g_CookieTypeId = 0;
  50. GROWBUFFER g_CookieConversionBuff = INIT_GROWBUFFER;
  51. PCTSTR g_Days[] = {
  52. TEXT("SUN"),
  53. TEXT("MON"),
  54. TEXT("TUE"),
  55. TEXT("WED"),
  56. TEXT("THU"),
  57. TEXT("FRI"),
  58. TEXT("SAT")
  59. };
  60. PCTSTR g_Months[] = {
  61. TEXT("JAN"),
  62. TEXT("FEB"),
  63. TEXT("MAR"),
  64. TEXT("APR"),
  65. TEXT("MAY"),
  66. TEXT("JUN"),
  67. TEXT("JUL"),
  68. TEXT("AUG"),
  69. TEXT("SEP"),
  70. TEXT("OCT"),
  71. TEXT("NOV"),
  72. TEXT("DEC")
  73. };
  74. typedef struct {
  75. PCTSTR Url;
  76. PCTSTR CookieName;
  77. PCTSTR CookieData;
  78. PCTSTR ExpirationString;
  79. } COOKIE_ITEM, *PCOOKIE_ITEM;
  80. typedef struct {
  81. // return value
  82. PCOOKIE_ITEM Item;
  83. // private enum members
  84. PCOOKIE_ITEM Array;
  85. UINT ArrayCount;
  86. UINT ArrayPos;
  87. INTERNET_CACHE_ENTRY_INFO *CacheEntry;
  88. HANDLE EnumHandle;
  89. GROWBUFFER CacheBuf;
  90. PMHANDLE Pool;
  91. } COOKIE_ENUM, *PCOOKIE_ENUM;
  92. //
  93. // Macro expansion list
  94. //
  95. // None
  96. //
  97. // Private function prototypes
  98. //
  99. // None
  100. //
  101. // Macro expansion definition
  102. //
  103. // None
  104. //
  105. // Private prototypes
  106. //
  107. TYPE_ENUMFIRSTPHYSICALOBJECT EnumFirstCookie;
  108. TYPE_ENUMNEXTPHYSICALOBJECT EnumNextCookie;
  109. TYPE_ABORTENUMPHYSICALOBJECT AbortCookieEnum;
  110. TYPE_CONVERTOBJECTTOMULTISZ ConvertCookieToMultiSz;
  111. TYPE_CONVERTMULTISZTOOBJECT ConvertMultiSzToCookie;
  112. TYPE_GETNATIVEOBJECTNAME GetNativeCookieName;
  113. TYPE_ACQUIREPHYSICALOBJECT AcquireCookie;
  114. TYPE_RELEASEPHYSICALOBJECT ReleaseCookie;
  115. TYPE_DOESPHYSICALOBJECTEXIST DoesCookieExist;
  116. TYPE_REMOVEPHYSICALOBJECT RemoveCookie;
  117. TYPE_CREATEPHYSICALOBJECT CreateCookie;
  118. TYPE_CONVERTOBJECTCONTENTTOUNICODE ConvertCookieContentToUnicode;
  119. TYPE_CONVERTOBJECTCONTENTTOANSI ConvertCookieContentToAnsi;
  120. TYPE_FREECONVERTEDOBJECTCONTENT FreeConvertedCookieContent;
  121. BOOL
  122. pEnumNextCookie (
  123. IN OUT PCOOKIE_ENUM EnumPtr
  124. );
  125. VOID
  126. pAbortCookieEnum (
  127. IN PCOOKIE_ENUM EnumPtr ZEROED
  128. );
  129. //
  130. // Code
  131. //
  132. BOOL
  133. CookiesInitialize (
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. CookiesInitialize is the ModuleInitialize entry point for the cookies
  139. module.
  140. Arguments:
  141. None.
  142. Return Value:
  143. TRUE if init succeeded, FALSE otherwise.
  144. --*/
  145. {
  146. g_CookiesTable = HtAllocEx (
  147. CASE_SENSITIVE,
  148. sizeof (PCTSTR),
  149. DEFAULT_BUCKET_SIZE
  150. );
  151. if (!g_CookiesTable) {
  152. return FALSE;
  153. }
  154. g_CookiesPool = PmCreateNamedPool (S_COOKIES_POOL_NAME);
  155. return (g_CookiesPool != NULL);
  156. }
  157. VOID
  158. CookiesTerminate (
  159. VOID
  160. )
  161. /*++
  162. Routine Description:
  163. CookiesTerminate is the ModuleTerminate entry point for the cookies module.
  164. Arguments:
  165. None.
  166. Return Value:
  167. None.
  168. --*/
  169. {
  170. GbFree (&g_CookieConversionBuff);
  171. if (g_CookiesTable) {
  172. HtFree (g_CookiesTable);
  173. g_CookiesTable = NULL;
  174. }
  175. if (g_CookiesPool) {
  176. PmEmptyPool (g_CookiesPool);
  177. PmDestroyPool (g_CookiesPool);
  178. g_CookiesPool = NULL;
  179. }
  180. }
  181. VOID
  182. WINAPI
  183. CookiesEtmNewUserCreated (
  184. IN PCTSTR UserName,
  185. IN PCTSTR DomainName,
  186. IN PCTSTR UserProfileRoot,
  187. IN PSID UserSid
  188. )
  189. /*++
  190. Routine Description:
  191. CookiesEtmNewUserCreated is a callback that gets called when a new user
  192. account is created. In this case, we must delay the apply of cookies,
  193. because we can only apply to the current user.
  194. Arguments:
  195. UserName - Specifies the name of the user being created
  196. DomainName - Specifies the NT domain name for the user (or NULL for no
  197. domain)
  198. UserProfileRoot - Specifies the root path to the user profile directory
  199. UserSid - Specifies the user's SID
  200. Return Value:
  201. None.
  202. --*/
  203. {
  204. // a new user was created, the cookies operations need to be delayed
  205. CookiesTerminate ();
  206. g_DelayCookiesOp = TRUE;
  207. }
  208. BOOL
  209. pGetCookiesPath (
  210. OUT PTSTR Buffer
  211. )
  212. /*++
  213. Routine Description:
  214. pGetCookiesPath retreives the path to CSIDL_COOKIES. This path is needed
  215. for registration of a static exclusion (so that .txt files in CSIDL_COOKIES
  216. do not get processed).
  217. Arguments:
  218. Buffer - Receives the path
  219. Return Value:
  220. TRUE if the cookies directory was obtained, FALSE otherwise.
  221. --*/
  222. {
  223. HRESULT result;
  224. LPITEMIDLIST pidl;
  225. BOOL b;
  226. LPMALLOC malloc;
  227. result = SHGetMalloc (&malloc);
  228. if (result != S_OK) {
  229. return FALSE;
  230. }
  231. result = SHGetSpecialFolderLocation (NULL, CSIDL_COOKIES, &pidl);
  232. if (result != S_OK) {
  233. return FALSE;
  234. }
  235. b = SHGetPathFromIDList (pidl, Buffer);
  236. IMalloc_Free (malloc, pidl);
  237. return b;
  238. }
  239. /*++
  240. The following routines parse a cookie TXT file (specifically, the wininet
  241. form of a cookie file). They are fairly straight-forward.
  242. --*/
  243. BOOL
  244. pGetNextLineFromFile (
  245. IN OUT PCSTR *CurrentPos,
  246. OUT PCSTR *LineStart,
  247. OUT PCSTR *LineEnd,
  248. IN PCSTR FileEnd
  249. )
  250. {
  251. PCSTR pos;
  252. pos = *CurrentPos;
  253. *LineEnd = NULL;
  254. //
  255. // Find the first non-whitespace character
  256. //
  257. while (pos < FileEnd) {
  258. if (!_ismbcspace (_mbsnextc (pos))) {
  259. break;
  260. }
  261. pos = _mbsinc (pos);
  262. }
  263. *LineStart = pos;
  264. //
  265. // Find the end
  266. //
  267. if (pos < FileEnd) {
  268. pos = _mbsinc (pos);
  269. while (pos < FileEnd) {
  270. if (*pos == '\r' || *pos == '\n') {
  271. break;
  272. }
  273. pos = _mbsinc (pos);
  274. }
  275. *LineEnd = pos;
  276. }
  277. *CurrentPos = pos;
  278. return *LineEnd != NULL;
  279. }
  280. PCTSTR
  281. pConvertStrToTchar (
  282. IN PMHANDLE Pool, OPTIONAL
  283. IN PCSTR Start,
  284. IN PCSTR End
  285. )
  286. {
  287. #ifdef UNICODE
  288. return DbcsToUnicodeN (Pool, Start, CharCountABA (Start, End));
  289. #else
  290. PTSTR dupStr;
  291. dupStr = AllocTextEx (Pool, (HALF_PTR) ((PBYTE) End - (PBYTE) Start) + 1);
  292. StringCopyAB (dupStr, Start, End);
  293. return dupStr;
  294. #endif
  295. }
  296. VOID
  297. pFreeUtilString (
  298. IN PCTSTR String
  299. )
  300. {
  301. #ifdef UNICODE
  302. FreeConvertedStr (String);
  303. #else
  304. FreeText (String);
  305. #endif
  306. }
  307. PCOOKIE_ITEM
  308. pGetCookiesFromFile (
  309. IN PCTSTR LocalFileName,
  310. IN PMHANDLE CookiePool,
  311. OUT UINT *ItemCount
  312. )
  313. {
  314. LONGLONG fileSize;
  315. HANDLE file;
  316. HANDLE map;
  317. PCSTR cookieFile;
  318. PCSTR currentPos;
  319. PCSTR lineStart;
  320. PCSTR lineEnd;
  321. PCSTR endOfFile;
  322. PCTSTR convertedStr;
  323. PCTSTR cookieName;
  324. PCTSTR cookieData;
  325. PCTSTR cookieUrl;
  326. GROWBUFFER tempBuf = INIT_GROWBUFFER;
  327. PCOOKIE_ITEM cookieArray;
  328. BOOL b;
  329. FILETIME expireTime;
  330. SYSTEMTIME cookieSysTime;
  331. TCHAR dateBuf[64];
  332. PTSTR dateBufEnd;
  333. // Let's check the size of the file. We don't want a malformed cookie
  334. // file to force us to map a huge file into memory.
  335. fileSize = BfGetFileSize (LocalFileName);
  336. if (fileSize > MAX_COOKIE_FILE_SIZE) {
  337. return NULL;
  338. }
  339. cookieFile = MapFileIntoMemory (LocalFileName, &file, &map);
  340. if (!cookieFile) {
  341. return NULL;
  342. }
  343. //
  344. // Parse the file
  345. //
  346. endOfFile = cookieFile + GetFileSize (file, NULL);
  347. currentPos = cookieFile;
  348. do {
  349. //
  350. // Get the cookie name, cookie data, and url. Then skip a line. Then
  351. // get the expiration low and high values.
  352. //
  353. // cookie name
  354. b = pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  355. if (b) {
  356. cookieName = pConvertStrToTchar (CookiePool, lineStart, lineEnd);
  357. }
  358. // cookie data
  359. b = b && pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  360. if (b) {
  361. cookieData = pConvertStrToTchar (CookiePool, lineStart, lineEnd);
  362. }
  363. // url
  364. b = b && pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  365. if (b) {
  366. convertedStr = pConvertStrToTchar (NULL, lineStart, lineEnd);
  367. cookieUrl = JoinTextEx (CookiePool, TEXT("http://"), convertedStr, NULL, 0, NULL);
  368. pFreeUtilString (convertedStr);
  369. }
  370. // don't care about the next line
  371. b = b && pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  372. // low DWORD for expire time
  373. b = b && pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  374. if (b) {
  375. convertedStr = pConvertStrToTchar (NULL, lineStart, lineEnd);
  376. expireTime.dwLowDateTime = _tcstoul (convertedStr, NULL, 10);
  377. pFreeUtilString (convertedStr);
  378. }
  379. // high DWORD for expire time
  380. b = b && pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile);
  381. if (b) {
  382. convertedStr = pConvertStrToTchar (NULL, lineStart, lineEnd);
  383. expireTime.dwHighDateTime = _tcstoul (convertedStr, NULL, 10);
  384. pFreeUtilString (convertedStr);
  385. //
  386. // Got the cookie; now find a "*" line (the terminator for the cookie)
  387. //
  388. while (pGetNextLineFromFile (&currentPos, &lineStart, &lineEnd, endOfFile)) {
  389. if (StringMatchABA ("*", lineStart, lineEnd)) {
  390. break;
  391. }
  392. }
  393. //
  394. // Create an expiration string
  395. //
  396. if (FileTimeToSystemTime (&expireTime, &cookieSysTime)) {
  397. //
  398. // Need to make something like this: "expires = Sat, 01-Jan-2000 00:00:00 GMT"
  399. //
  400. dateBufEnd = StringCopy (dateBuf, TEXT("expires = "));
  401. dateBufEnd += wsprintf (
  402. dateBufEnd,
  403. TEXT("%s, %02u-%s-%04u %02u:%02u:%02u GMT"),
  404. g_Days[cookieSysTime.wDayOfWeek],
  405. (UINT) cookieSysTime.wDay,
  406. g_Months[cookieSysTime.wMonth - 1],
  407. (UINT) cookieSysTime.wYear,
  408. cookieSysTime.wHour,
  409. cookieSysTime.wMinute,
  410. cookieSysTime.wSecond
  411. );
  412. } else {
  413. *dateBuf = 0;
  414. }
  415. //
  416. // Add an entry to the array of cookie items
  417. //
  418. cookieArray = (PCOOKIE_ITEM) GbGrow (&tempBuf, sizeof (COOKIE_ITEM));
  419. cookieArray->Url = cookieUrl;
  420. cookieArray->CookieName = cookieName;
  421. cookieArray->CookieData = cookieData;
  422. cookieArray->ExpirationString = PmDuplicateString (CookiePool, dateBuf);
  423. }
  424. } while (b);
  425. //
  426. // Transfer array to caller's pool
  427. //
  428. *ItemCount = tempBuf.End / sizeof (COOKIE_ITEM);
  429. if (tempBuf.End) {
  430. cookieArray = (PCOOKIE_ITEM) PmDuplicateMemory (CookiePool, tempBuf.Buf, tempBuf.End);
  431. } else {
  432. cookieArray = NULL;
  433. }
  434. //
  435. // Clean up
  436. //
  437. GbFree (&tempBuf);
  438. UnmapFile (cookieFile, map, file);
  439. return cookieArray;
  440. }
  441. MIG_OBJECTSTRINGHANDLE
  442. pCreateCookieHandle (
  443. IN PCTSTR Url,
  444. IN PCTSTR CookieName
  445. )
  446. /*++
  447. Routine Description:
  448. pCreateCookieHandle generates a MIG_OBJECTSTRINGHANDLE for a cookie object.
  449. This routine decorates the CookieName leaf so that case is preserved.
  450. Arguments:
  451. Url - Specifies the node portion (the URL associated with the cookie)
  452. CookieName - Specifies the case-sensitive name of the cookie
  453. Return Value:
  454. A handle to the cookie object (which may be cast to a PCTSTR), or NULL if
  455. an error occurs.
  456. --*/
  457. {
  458. PTSTR buffer;
  459. PTSTR p;
  460. PCTSTR q;
  461. MIG_OBJECTSTRINGHANDLE result;
  462. CHARTYPE ch;
  463. //
  464. // Cobra object strings are case-insensitive, but CookieName is not. Here
  465. // we convert CookieName into all lower-case, decorating with a caret to
  466. // indicate uppercase
  467. //
  468. buffer = AllocText (TcharCount (CookieName) * 2 + 1);
  469. q = CookieName;
  470. p = buffer;
  471. while (*q) {
  472. ch = (CHARTYPE) _tcsnextc (q);
  473. if (_istupper (ch) || ch == TEXT('#')) {
  474. *p++ = TEXT('#');
  475. }
  476. #ifndef UNICODE
  477. if (IsLeadByte (q)) {
  478. *p++ = *q++;
  479. }
  480. #endif
  481. *p++ = *q++;
  482. }
  483. *p = 0;
  484. CharLower (buffer);
  485. result = IsmCreateObjectHandle (Url, buffer);
  486. FreeText (buffer);
  487. return result;
  488. }
  489. BOOL
  490. pCreateCookieStrings (
  491. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  492. OUT PCTSTR *Url,
  493. OUT PCTSTR *Cookie
  494. )
  495. /*++
  496. Routine Description:
  497. pCreateCookieStrings converts an object handle into the URL and cookie name
  498. strings. It performs decoding of the decoration needed to support
  499. case-sensitive cookie names.
  500. Arguments:
  501. ObjectName - Specifies the encoded object name
  502. Url - Receives the URL string, unencoded
  503. Cookie - Receives the cookie name, unencoded
  504. Return Value:
  505. TRUE of the object was converted to strings, FALSE otherwise. The caller
  506. must call pDestroyCookieStrings to clean up Url and Cookie.
  507. --*/
  508. {
  509. PCTSTR node;
  510. PCTSTR leaf;
  511. PTSTR buffer;
  512. PTSTR p;
  513. PCTSTR q;
  514. PTSTR p2;
  515. //
  516. // Cobra object strings are case-insensitive, but CookieName is not.
  517. // Therefore, we must convert the string from an encoded lowercase format
  518. // into the original form.
  519. //
  520. IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf);
  521. if (!node || !leaf) {
  522. IsmDestroyObjectString (node);
  523. IsmDestroyObjectString (leaf);
  524. return FALSE;
  525. }
  526. *Url = node;
  527. //
  528. // Decode Cookie
  529. //
  530. buffer = AllocText (TcharCount (leaf) + 1);
  531. CharLower ((PTSTR) leaf);
  532. q = leaf;
  533. p = buffer;
  534. while (*q) {
  535. if (_tcsnextc (q) == TEXT('#')) {
  536. q = _tcsinc (q);
  537. if (*q == 0) {
  538. break;
  539. }
  540. p2 = p;
  541. } else {
  542. p2 = NULL;
  543. }
  544. #ifndef UNICODE
  545. if (IsLeadByte (q)) {
  546. *p++ = *q++;
  547. }
  548. #endif
  549. *p++ = *q++;
  550. if (p2) {
  551. *p = 0;
  552. CharUpper (p2);
  553. }
  554. }
  555. *p = 0;
  556. *Cookie = buffer;
  557. IsmDestroyObjectString (leaf);
  558. return TRUE;
  559. }
  560. VOID
  561. pDestroyCookieStrings (
  562. IN PCTSTR Url,
  563. IN PCTSTR CookieName
  564. )
  565. {
  566. IsmDestroyObjectString (Url);
  567. FreeText (CookieName);
  568. }
  569. VOID
  570. pAbortCookieEnum (
  571. IN PCOOKIE_ENUM EnumPtr ZEROED
  572. )
  573. {
  574. if (EnumPtr->Pool) {
  575. GbFree (&EnumPtr->CacheBuf);
  576. if (EnumPtr->EnumHandle) {
  577. FindCloseUrlCache (EnumPtr->EnumHandle);
  578. }
  579. PmDestroyPool (EnumPtr->Pool);
  580. }
  581. ZeroMemory (EnumPtr, sizeof (COOKIE_ENUM));
  582. }
  583. /*++
  584. The following enumeration routines enumerate the current user's cookies on
  585. the physical machine. They use wininet apis as much as possible, but
  586. they have to parse cookie TXT files because of api limitations.
  587. --*/
  588. BOOL
  589. pEnumFirstCookie (
  590. OUT PCOOKIE_ENUM EnumPtr
  591. )
  592. {
  593. DWORD size;
  594. BOOL b = FALSE;
  595. ZeroMemory (EnumPtr, sizeof (COOKIE_ENUM));
  596. EnumPtr->Pool = PmCreatePoolEx (512);
  597. size = EnumPtr->CacheBuf.End;
  598. EnumPtr->EnumHandle = FindFirstUrlCacheEntry (TEXT("cookie:"), NULL, &size);
  599. if (!EnumPtr->EnumHandle) {
  600. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  601. EnumPtr->CacheEntry = (INTERNET_CACHE_ENTRY_INFO *) GbGrow (&EnumPtr->CacheBuf, size);
  602. MYASSERT (EnumPtr->CacheEntry);
  603. EnumPtr->EnumHandle = FindFirstUrlCacheEntry (
  604. TEXT("cookie:"),
  605. EnumPtr->CacheEntry,
  606. &size
  607. );
  608. if (EnumPtr->EnumHandle) {
  609. b = TRUE;
  610. }
  611. }
  612. }
  613. if (!b) {
  614. pAbortCookieEnum (EnumPtr);
  615. return FALSE;
  616. }
  617. return pEnumNextCookie (EnumPtr);
  618. }
  619. BOOL
  620. pEnumNextCookie (
  621. IN OUT PCOOKIE_ENUM EnumPtr
  622. )
  623. {
  624. DWORD size;
  625. BOOL b;
  626. INTERNET_CACHE_ENTRY_INFO *cacheEntry = EnumPtr->CacheEntry;
  627. for (;;) {
  628. //
  629. // Is the cookie array empty? If so, fill it now.
  630. //
  631. if (!EnumPtr->ArrayCount) {
  632. if (!cacheEntry) {
  633. return FALSE;
  634. }
  635. EnumPtr->Array = pGetCookiesFromFile (
  636. cacheEntry->lpszLocalFileName,
  637. EnumPtr->Pool,
  638. &EnumPtr->ArrayCount
  639. );
  640. if (EnumPtr->Array) {
  641. //
  642. // Array was filled. Return the first item.
  643. //
  644. EnumPtr->Item = EnumPtr->Array;
  645. EnumPtr->ArrayPos = 1;
  646. return TRUE;
  647. }
  648. DEBUGMSG ((DBG_ERROR, "Unable to get cookies from %s", cacheEntry->lpszLocalFileName));
  649. } else if (EnumPtr->ArrayPos < EnumPtr->ArrayCount) {
  650. //
  651. // Another element in the array is available. Return it.
  652. //
  653. EnumPtr->Item = &EnumPtr->Array[EnumPtr->ArrayPos];
  654. EnumPtr->ArrayPos++;
  655. return TRUE;
  656. }
  657. //
  658. // Current local file enumeration is done. Now get the next local file.
  659. //
  660. EnumPtr->ArrayCount = 0;
  661. PmEmptyPool (EnumPtr->Pool);
  662. size = EnumPtr->CacheBuf.End;
  663. b = FindNextUrlCacheEntry (
  664. EnumPtr->EnumHandle,
  665. (INTERNET_CACHE_ENTRY_INFO *) EnumPtr->CacheBuf.Buf,
  666. &size
  667. );
  668. if (!b) {
  669. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  670. EnumPtr->CacheBuf.End = 0;
  671. EnumPtr->CacheEntry = (INTERNET_CACHE_ENTRY_INFO *) GbGrow (&EnumPtr->CacheBuf, size);
  672. MYASSERT (EnumPtr->CacheEntry);
  673. b = FindNextUrlCacheEntry (
  674. EnumPtr->EnumHandle,
  675. (INTERNET_CACHE_ENTRY_INFO *) EnumPtr->CacheBuf.Buf,
  676. &size
  677. );
  678. }
  679. }
  680. if (!b) {
  681. //
  682. // Enumeration is complete
  683. //
  684. break;
  685. }
  686. }
  687. pAbortCookieEnum (EnumPtr);
  688. return FALSE;
  689. }
  690. VOID
  691. pAddCookieToHashTable (
  692. IN OUT PGROWBUFFER TempBuf,
  693. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  694. IN PCTSTR Url,
  695. IN PCTSTR CookieName,
  696. IN PCTSTR CookieData,
  697. IN PCTSTR ExpirationString
  698. )
  699. /*++
  700. Routine Description:
  701. pAddCookieToHashTable puts a cookie in a hash table that is used for cache
  702. purposes. Cookies cannot be read easily in a random order. Therefore, a
  703. hash table is used to store each cookie. This routine adds the cookie to
  704. the hash table, complete with its URL, cookie name, cookie data and
  705. expiration string.
  706. Arguments:
  707. TempBuf - Specifies an initialized grow buffer used for temporary
  708. memory allocations, receives undefined temporary data.
  709. ObjectName - Specifies the cookie URL and name
  710. Url - Specifies the cookie URL (unencoded)
  711. CookieName - Specifies the cookie name (unencoded)
  712. CookieData - Specifies the cookie data string
  713. ExpirationString - Specifies the cookie expiration date, in string format
  714. Return Value:
  715. None.
  716. --*/
  717. {
  718. PCTSTR dupData;
  719. //
  720. // Write the cookie to the hash table. The object string is stored in the
  721. // hash table, along with a pointer to the cookie data and expiration
  722. // string. The cookie data and expieration string are kept in a separate
  723. // pool.
  724. //
  725. if (!HtFindString (g_CookiesTable, ObjectName)) {
  726. TempBuf->End = 0;
  727. GbMultiSzAppend (TempBuf, CookieData);
  728. GbMultiSzAppend (TempBuf, ExpirationString);
  729. dupData = (PCTSTR) PmDuplicateMemory (g_CookiesPool, TempBuf->Buf, TempBuf->End);
  730. HtAddStringAndData (g_CookiesTable, ObjectName, &dupData);
  731. }
  732. ELSE_DEBUGMSG ((DBG_ERROR, "Cookie already in the hash table: %s:%s", Url, CookieName));
  733. }
  734. BOOL
  735. pLoadCookiesData (
  736. VOID
  737. )
  738. /*++
  739. Routine Description:
  740. pLoadCookieData fills the hash table with all of the current user's
  741. cookies. The hash table is later used to drive enumeration, to acquire the
  742. cookie, and to test its existence.
  743. Arguments:
  744. None.
  745. Return Value:
  746. TRUE if the cookie cache was filled, FALSE otherwise.
  747. --*/
  748. {
  749. COOKIE_ENUM e;
  750. GROWBUFFER tempBuf = INIT_GROWBUFFER;
  751. MIG_OBJECTSTRINGHANDLE objectName;
  752. if (pEnumFirstCookie (&e)) {
  753. do {
  754. //
  755. // Store the cookie in a hash table (used for caching)
  756. //
  757. objectName = pCreateCookieHandle (e.Item->Url, e.Item->CookieName);
  758. pAddCookieToHashTable (
  759. &tempBuf,
  760. objectName,
  761. e.Item->Url,
  762. e.Item->CookieName,
  763. e.Item->CookieData,
  764. e.Item->ExpirationString
  765. );
  766. IsmDestroyObjectHandle (objectName);
  767. } while (pEnumNextCookie (&e));
  768. }
  769. GbFree (&tempBuf);
  770. return TRUE;
  771. }
  772. BOOL
  773. WINAPI
  774. CookiesEtmInitialize (
  775. IN MIG_PLATFORMTYPEID Platform,
  776. IN PMIG_LOGCALLBACK LogCallback,
  777. IN PVOID Reserved
  778. )
  779. /*++
  780. Routine Description:
  781. CookiesEtmInitialize initializes the physical type module aspect of this
  782. code. The ETM module is responsible for abstracting all access to cookies.
  783. Arguments:
  784. Platform - Specifies the platform that the type is running on
  785. (PLATFORM_SOURCE or PLATFORM_DESTINATION)
  786. LogCallback - Specifies the arg to pass to the central logging mechanism
  787. Reserved - Unused
  788. Return Value:
  789. TRUE if initialization succeeded, FALSE otherwise.
  790. --*/
  791. {
  792. TYPE_REGISTER cookieTypeData;
  793. TCHAR cookiesDir[MAX_PATH];
  794. MIG_OBJECTSTRINGHANDLE handle;
  795. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  796. //
  797. // Initialize a hash table of all cookies
  798. //
  799. pLoadCookiesData ();
  800. //
  801. // Exclude the cookies .txt files from other processing
  802. //
  803. if (Platform == PLATFORM_SOURCE) {
  804. if (pGetCookiesPath (cookiesDir)) {
  805. handle = IsmCreateObjectHandle (cookiesDir, NULL);
  806. IsmRegisterStaticExclusion (MIG_FILE_TYPE, handle);
  807. IsmSetEnvironmentString (PLATFORM_SOURCE, NULL, S_COOKIES_SHELL_FOLDER, handle);
  808. IsmDestroyObjectHandle (handle);
  809. }
  810. ELSE_DEBUGMSG ((DBG_COOKIES, "Unable to get cookies path"));
  811. } else {
  812. if (IsmCopyEnvironmentString (PLATFORM_SOURCE, NULL, S_COOKIES_SHELL_FOLDER, cookiesDir)) {
  813. IsmRegisterStaticExclusion (MIG_FILE_TYPE, cookiesDir);
  814. }
  815. }
  816. //
  817. // Register the type module callbacks
  818. //
  819. ZeroMemory (&cookieTypeData, sizeof (TYPE_REGISTER));
  820. if (Platform != PLATFORM_SOURCE) {
  821. cookieTypeData.RemovePhysicalObject = RemoveCookie;
  822. cookieTypeData.CreatePhysicalObject = CreateCookie;
  823. }
  824. cookieTypeData.DoesPhysicalObjectExist = DoesCookieExist;
  825. cookieTypeData.EnumFirstPhysicalObject = EnumFirstCookie;
  826. cookieTypeData.EnumNextPhysicalObject = EnumNextCookie;
  827. cookieTypeData.AbortEnumPhysicalObject = AbortCookieEnum;
  828. cookieTypeData.ConvertObjectToMultiSz = ConvertCookieToMultiSz;
  829. cookieTypeData.ConvertMultiSzToObject = ConvertMultiSzToCookie;
  830. cookieTypeData.GetNativeObjectName = GetNativeCookieName;
  831. cookieTypeData.AcquirePhysicalObject = AcquireCookie;
  832. cookieTypeData.ReleasePhysicalObject = ReleaseCookie;
  833. cookieTypeData.ConvertObjectContentToUnicode = ConvertCookieContentToUnicode;
  834. cookieTypeData.ConvertObjectContentToAnsi = ConvertCookieContentToAnsi;
  835. cookieTypeData.FreeConvertedObjectContent = FreeConvertedCookieContent;
  836. g_CookieTypeId = IsmRegisterObjectType (
  837. S_COOKIES_NAME,
  838. TRUE,
  839. FALSE,
  840. &cookieTypeData
  841. );
  842. MYASSERT (g_CookieTypeId);
  843. return TRUE;
  844. }
  845. BOOL
  846. WINAPI
  847. CookiesSgmParse (
  848. IN PVOID Reserved
  849. )
  850. /*++
  851. Routine Description:
  852. CookiesSgmParse registers a component with the engine.
  853. Arguments:
  854. Reserved - Unused.
  855. Return Value:
  856. Always TRUE.
  857. --*/
  858. {
  859. TCHAR cookiesDir[MAX_PATH];
  860. IsmAddComponentAlias (
  861. TEXT("$Browser"),
  862. MASTERGROUP_SYSTEM,
  863. S_COOKIES_NAME,
  864. COMPONENT_SUBCOMPONENT,
  865. FALSE
  866. );
  867. if (pGetCookiesPath (cookiesDir)) {
  868. IsmAddComponentAlias (
  869. S_COOKIES_NAME,
  870. MASTERGROUP_SYSTEM,
  871. cookiesDir,
  872. COMPONENT_FOLDER,
  873. FALSE
  874. );
  875. }
  876. return TRUE;
  877. }
  878. BOOL
  879. WINAPI
  880. CookiesSgmQueueEnumeration (
  881. IN PVOID Reserved
  882. )
  883. /*++
  884. Routine Description:
  885. CookiesSgmQueueEnumeration queues all cookies to be processed if the
  886. cookies component is selected.
  887. Arguments:
  888. Reserved - Unused
  889. Return Value:
  890. Always TRUE.
  891. --*/
  892. {
  893. ENCODEDSTRHANDLE pattern;
  894. if (!IsmIsComponentSelected (S_COOKIES_NAME, COMPONENT_SUBCOMPONENT)) {
  895. return TRUE;
  896. }
  897. //
  898. // Use the ISM's build-in callback
  899. //
  900. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE);
  901. IsmQueueEnumeration (
  902. g_CookieTypeId,
  903. pattern,
  904. NULL,
  905. QUEUE_MAKE_APPLY|QUEUE_OVERWRITE_DEST|QUEUE_MAKE_NONCRITICAL,
  906. S_COOKIES_NAME
  907. );
  908. IsmDestroyObjectHandle (pattern);
  909. return TRUE;
  910. }
  911. BOOL
  912. WINAPI
  913. CookiesSourceInitialize (
  914. IN PMIG_LOGCALLBACK LogCallback,
  915. IN PVOID Reserved
  916. )
  917. /*++
  918. Routine Description:
  919. CookiesSourceInitialize initializes the SGM module.
  920. Arguments:
  921. LogCallback - Specifies the argument to pass to the log APIs
  922. Reserved - Unused
  923. Return Value:
  924. Always TRUE.
  925. --*/
  926. {
  927. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  928. return TRUE;
  929. }
  930. BOOL
  931. CookiesVcmQueueEnumeration (
  932. IN PVOID Reserved
  933. )
  934. /*++
  935. Routine Description:
  936. CookiesVcmQueueEnumeration is similar to the SGM queue enumeration, except
  937. that it only marks cookies as persistent. There is no need to set
  938. destination priority or apply here.
  939. Arguments:
  940. Reserved - Unused
  941. Return Value:
  942. Always TRUE.
  943. --*/
  944. {
  945. if (!IsmIsComponentSelected (S_COOKIES_NAME, COMPONENT_SUBCOMPONENT)) {
  946. return TRUE;
  947. }
  948. IsmQueueEnumeration (g_CookieTypeId, NULL, NULL, QUEUE_MAKE_PERSISTENT|QUEUE_MAKE_NONCRITICAL, NULL);
  949. return TRUE;
  950. }
  951. /*++
  952. The following enumeration routines are the ETM entry points. They rely
  953. on the enumeration routines above to access the physical machine.
  954. --*/
  955. BOOL
  956. pEnumCookieWorker (
  957. OUT PMIG_TYPEOBJECTENUM EnumPtr,
  958. IN PCOOKIES_ENUM CookieEnum
  959. )
  960. {
  961. PCTSTR expiresStr;
  962. //
  963. // Clean up previous enum resources
  964. //
  965. pDestroyCookieStrings (EnumPtr->ObjectNode, EnumPtr->ObjectLeaf);
  966. EnumPtr->ObjectNode = NULL;
  967. EnumPtr->ObjectLeaf = NULL;
  968. IsmReleaseMemory (EnumPtr->NativeObjectName);
  969. EnumPtr->NativeObjectName = NULL;
  970. //
  971. // Find the next match
  972. //
  973. for (;;) {
  974. EnumPtr->ObjectName = CookieEnum->HashData.String;
  975. if (ObsPatternMatch (CookieEnum->Pattern, EnumPtr->ObjectName)) {
  976. break;
  977. }
  978. if (!EnumNextHashTableString (&CookieEnum->HashData)) {
  979. AbortCookieEnum (EnumPtr);
  980. return FALSE;
  981. }
  982. }
  983. //
  984. // Fill the caller's structure and return success
  985. //
  986. if (!pCreateCookieStrings (EnumPtr->ObjectName, &EnumPtr->ObjectNode, &EnumPtr->ObjectLeaf)) {
  987. return FALSE;
  988. }
  989. EnumPtr->NativeObjectName = GetNativeCookieName (EnumPtr->ObjectName);
  990. EnumPtr->Level = 1;
  991. EnumPtr->SubLevel = 0;
  992. EnumPtr->IsLeaf = TRUE;
  993. EnumPtr->IsNode = TRUE;
  994. expiresStr = *((PCTSTR *) CookieEnum->HashData.ExtraData);
  995. expiresStr = GetEndOfString (expiresStr) + 1;
  996. EnumPtr->Details.DetailsSize = SizeOfString (expiresStr);
  997. EnumPtr->Details.DetailsData = (PCBYTE) expiresStr;
  998. return TRUE;
  999. }
  1000. BOOL
  1001. EnumFirstCookie (
  1002. IN OUT PMIG_TYPEOBJECTENUM EnumPtr, CALLER_INITIALIZED
  1003. IN MIG_OBJECTSTRINGHANDLE Pattern,
  1004. IN UINT MaxLevel
  1005. )
  1006. {
  1007. PCOOKIES_ENUM cookieEnum = NULL;
  1008. if (!g_CookiesTable) {
  1009. return FALSE;
  1010. }
  1011. cookieEnum = (PCOOKIES_ENUM) PmGetMemory (g_CookiesPool, sizeof (COOKIES_ENUM));
  1012. cookieEnum->Pattern = PmDuplicateString (g_CookiesPool, Pattern);
  1013. EnumPtr->EtmHandle = (LONG_PTR) cookieEnum;
  1014. if (EnumFirstHashTableString (&cookieEnum->HashData, g_CookiesTable)) {
  1015. return pEnumCookieWorker (EnumPtr, cookieEnum);
  1016. } else {
  1017. AbortCookieEnum (EnumPtr);
  1018. return FALSE;
  1019. }
  1020. }
  1021. BOOL
  1022. EnumNextCookie (
  1023. IN OUT PMIG_TYPEOBJECTENUM EnumPtr
  1024. )
  1025. {
  1026. PCOOKIES_ENUM cookieEnum = NULL;
  1027. cookieEnum = (PCOOKIES_ENUM)(EnumPtr->EtmHandle);
  1028. if (!cookieEnum) {
  1029. return FALSE;
  1030. }
  1031. if (EnumNextHashTableString (&cookieEnum->HashData)) {
  1032. return pEnumCookieWorker (EnumPtr, cookieEnum);
  1033. } else {
  1034. AbortCookieEnum (EnumPtr);
  1035. return FALSE;
  1036. }
  1037. }
  1038. VOID
  1039. AbortCookieEnum (
  1040. IN PMIG_TYPEOBJECTENUM EnumPtr ZEROED
  1041. )
  1042. {
  1043. PCOOKIES_ENUM cookieEnum;
  1044. pDestroyCookieStrings (EnumPtr->ObjectNode, EnumPtr->ObjectLeaf);
  1045. IsmReleaseMemory (EnumPtr->NativeObjectName);
  1046. cookieEnum = (PCOOKIES_ENUM)(EnumPtr->EtmHandle);
  1047. if (cookieEnum) {
  1048. PmReleaseMemory (g_CookiesPool, cookieEnum->Pattern);
  1049. PmReleaseMemory (g_CookiesPool, cookieEnum);
  1050. }
  1051. ZeroMemory (EnumPtr, sizeof (MIG_TYPEOBJECTENUM));
  1052. }
  1053. /*++
  1054. The next set of functions implement the ETM entry points to acquire, test,
  1055. create and remove cookies. They rely on the cookie hash table being
  1056. accurate.
  1057. --*/
  1058. BOOL
  1059. AcquireCookie (
  1060. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1061. OUT PMIG_CONTENT ObjectContent, CALLER_INITIALIZED
  1062. IN MIG_CONTENTTYPE ContentType,
  1063. IN UINT MemoryContentLimit
  1064. )
  1065. {
  1066. PCTSTR cookieData = NULL;
  1067. MYASSERT (ObjectContent);
  1068. if (ContentType == CONTENTTYPE_FILE) {
  1069. // nobody should request this as a file
  1070. MYASSERT (FALSE);
  1071. return FALSE;
  1072. }
  1073. if (HtFindStringEx (g_CookiesTable, ObjectName, (PVOID) (&cookieData), FALSE)) {
  1074. ObjectContent->MemoryContent.ContentBytes = (PCBYTE) cookieData;
  1075. ObjectContent->MemoryContent.ContentSize = SizeOfString (cookieData);
  1076. cookieData = GetEndOfString (cookieData) + 1;
  1077. ObjectContent->Details.DetailsData = (PCBYTE) cookieData;
  1078. ObjectContent->Details.DetailsSize = SizeOfString (cookieData);
  1079. return TRUE;
  1080. }
  1081. return FALSE;
  1082. }
  1083. BOOL
  1084. ReleaseCookie (
  1085. IN PMIG_CONTENT ObjectContent ZEROED
  1086. )
  1087. {
  1088. if (ObjectContent) {
  1089. ZeroMemory (ObjectContent, sizeof (MIG_CONTENT));
  1090. }
  1091. return TRUE;
  1092. }
  1093. BOOL
  1094. DoesCookieExist (
  1095. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1096. )
  1097. {
  1098. if (g_DelayCookiesOp) {
  1099. return FALSE;
  1100. }
  1101. if (HtFindString (g_CookiesTable, ObjectName)) {
  1102. return TRUE;
  1103. }
  1104. return FALSE;
  1105. }
  1106. BOOL
  1107. pRemoveCookieWorker (
  1108. IN PCTSTR ObjectName,
  1109. IN PCTSTR Url,
  1110. IN PCTSTR CookieName
  1111. )
  1112. {
  1113. BOOL result = TRUE;
  1114. if (InternetSetCookie (
  1115. Url,
  1116. CookieName,
  1117. TEXT("foo; expires = Sat, 01-Jan-2000 00:00:00 GMT")
  1118. )) {
  1119. HtRemoveString (g_CookiesTable, ObjectName);
  1120. } else {
  1121. result = FALSE;
  1122. DEBUGMSG ((
  1123. DBG_ERROR,
  1124. "Unable to delete cookie %s for URL %s\n",
  1125. CookieName,
  1126. Url
  1127. ));
  1128. }
  1129. return result;
  1130. }
  1131. BOOL
  1132. RemoveCookie (
  1133. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1134. )
  1135. {
  1136. PCTSTR url;
  1137. PCTSTR cookieName;
  1138. BOOL result = FALSE;
  1139. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1140. if (url && cookieName) {
  1141. if (g_DelayCookiesOp) {
  1142. //
  1143. // delay this cookie create because wininet apis do not work
  1144. // for non-logged on users
  1145. //
  1146. IsmRecordDelayedOperation (
  1147. JRNOP_DELETE,
  1148. g_CookieTypeId,
  1149. ObjectName,
  1150. NULL
  1151. );
  1152. result = TRUE;
  1153. } else {
  1154. //
  1155. // add journal entry, then perform cookie deletion
  1156. //
  1157. IsmRecordOperation (
  1158. JRNOP_DELETE,
  1159. g_CookieTypeId,
  1160. ObjectName
  1161. );
  1162. result = pRemoveCookieWorker (ObjectName, url, cookieName);
  1163. }
  1164. }
  1165. pDestroyCookieStrings (url, cookieName);
  1166. }
  1167. return result;
  1168. }
  1169. BOOL
  1170. pCreateCookieWorker (
  1171. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1172. IN PMIG_CONTENT ObjectContent,
  1173. IN PCTSTR Url,
  1174. IN PCTSTR CookieName
  1175. )
  1176. {
  1177. PCTSTR fixedCookieData;
  1178. PCTSTR cookieData;
  1179. PCTSTR expires;
  1180. BOOL result = FALSE;
  1181. GROWBUFFER tempBuf = INIT_GROWBUFFER;
  1182. //
  1183. // write the object by joining the content with the details
  1184. //
  1185. cookieData = (PCTSTR) (ObjectContent->MemoryContent.ContentBytes);
  1186. expires = (PCTSTR) (ObjectContent->Details.DetailsData);
  1187. fixedCookieData = JoinTextEx (
  1188. NULL,
  1189. cookieData,
  1190. expires,
  1191. TEXT(";"),
  1192. 0,
  1193. NULL
  1194. );
  1195. if (InternetSetCookie (Url, CookieName, fixedCookieData)) {
  1196. pAddCookieToHashTable (
  1197. &tempBuf,
  1198. ObjectName,
  1199. Url,
  1200. CookieName,
  1201. cookieData,
  1202. expires
  1203. );
  1204. result = TRUE;
  1205. } else {
  1206. DEBUGMSG ((
  1207. DBG_COOKIES,
  1208. "Unable to set cookie %s for URL %s\n",
  1209. CookieName,
  1210. Url
  1211. ));
  1212. }
  1213. FreeText (fixedCookieData);
  1214. GbFree (&tempBuf);
  1215. return result;
  1216. }
  1217. BOOL
  1218. CreateCookie (
  1219. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1220. IN PMIG_CONTENT ObjectContent
  1221. )
  1222. {
  1223. PCTSTR url;
  1224. PCTSTR cookieName;
  1225. BOOL result = FALSE;
  1226. if (!ObjectContent->ContentInFile) {
  1227. if (ObjectContent->MemoryContent.ContentBytes &&
  1228. ObjectContent->MemoryContent.ContentSize &&
  1229. ObjectContent->Details.DetailsSize &&
  1230. ObjectContent->Details.DetailsData
  1231. ) {
  1232. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1233. if (url && cookieName) {
  1234. if (g_DelayCookiesOp) {
  1235. //
  1236. // delay this cookie create because wininet apis do not work
  1237. // for non-logged on users
  1238. //
  1239. IsmRecordDelayedOperation (
  1240. JRNOP_CREATE,
  1241. g_CookieTypeId,
  1242. ObjectName,
  1243. ObjectContent
  1244. );
  1245. result = TRUE;
  1246. } else {
  1247. //
  1248. // add journal entry, then create the cookie
  1249. //
  1250. IsmRecordOperation (
  1251. JRNOP_CREATE,
  1252. g_CookieTypeId,
  1253. ObjectName
  1254. );
  1255. if (DoesCookieExist (ObjectName)) {
  1256. //
  1257. // Fail because cookie cannot be overwritten
  1258. //
  1259. result = FALSE;
  1260. } else {
  1261. result = pCreateCookieWorker (
  1262. ObjectName,
  1263. ObjectContent,
  1264. url,
  1265. cookieName
  1266. );
  1267. }
  1268. }
  1269. }
  1270. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie node or leaf: %s", ObjectName));
  1271. pDestroyCookieStrings (url, cookieName);
  1272. }
  1273. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie object: %s", ObjectName));
  1274. }
  1275. ELSE_DEBUGMSG ((DBG_ERROR, "Can't write incomplete cookie object"));
  1276. }
  1277. return result;
  1278. }
  1279. /*++
  1280. The next group of functions converts a cookie object into a string format,
  1281. suitable for output to an INF file. The reverse conversion is also
  1282. implemented.
  1283. --*/
  1284. PCTSTR
  1285. ConvertCookieToMultiSz (
  1286. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1287. IN PMIG_CONTENT ObjectContent
  1288. )
  1289. {
  1290. PCTSTR url, cookieName;
  1291. PTSTR result = NULL;
  1292. PCTSTR data;
  1293. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1294. MYASSERT (url);
  1295. MYASSERT (cookieName);
  1296. //
  1297. // Build a multi-sz in the following format:
  1298. //
  1299. // <url>\0<cookie name>\0<cookie data>\0<expiration>\0\0
  1300. //
  1301. g_CookieConversionBuff.End = 0;
  1302. // <url>
  1303. GbCopyQuotedString (&g_CookieConversionBuff, url);
  1304. // <cookie name>
  1305. GbCopyQuotedString (&g_CookieConversionBuff, cookieName);
  1306. // <cookie data>
  1307. MYASSERT (!ObjectContent->ContentInFile);
  1308. if ((!ObjectContent->ContentInFile) &&
  1309. (ObjectContent->MemoryContent.ContentSize) &&
  1310. (ObjectContent->MemoryContent.ContentBytes)
  1311. ) {
  1312. data = (PCTSTR) ObjectContent->MemoryContent.ContentBytes;
  1313. GbCopyQuotedString (&g_CookieConversionBuff, data);
  1314. }
  1315. // <expiration>
  1316. MYASSERT (ObjectContent->Details.DetailsSize);
  1317. if (ObjectContent->Details.DetailsSize &&
  1318. ObjectContent->Details.DetailsData
  1319. ) {
  1320. data = (PCTSTR) ObjectContent->Details.DetailsData;
  1321. GbCopyQuotedString (&g_CookieConversionBuff, data);
  1322. }
  1323. // nul terminator
  1324. GbCopyString (&g_CookieConversionBuff, TEXT(""));
  1325. //
  1326. // Transfer multi-sz to ISM memory
  1327. //
  1328. result = IsmGetMemory (g_CookieConversionBuff.End);
  1329. CopyMemory (result, g_CookieConversionBuff.Buf, g_CookieConversionBuff.End);
  1330. //
  1331. // Clean up
  1332. //
  1333. pDestroyCookieStrings (url, cookieName);
  1334. }
  1335. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie object: %s", ObjectName));
  1336. return result;
  1337. }
  1338. BOOL
  1339. ConvertMultiSzToCookie (
  1340. IN PCTSTR ObjectMultiSz,
  1341. OUT MIG_OBJECTSTRINGHANDLE *ObjectName,
  1342. OUT PMIG_CONTENT ObjectContent OPTIONAL CALLER_INITIALIZED
  1343. )
  1344. {
  1345. MULTISZ_ENUM e;
  1346. PCTSTR strings[4];
  1347. UINT field;
  1348. g_CookieConversionBuff.End = 0;
  1349. //
  1350. // Fill the object content from the following multi-sz:
  1351. //
  1352. // <url>\0<cookie name>\0<cookie data>\0<expiration>\0\0
  1353. //
  1354. field = 0;
  1355. if (EnumFirstMultiSz (&e, ObjectMultiSz)) {
  1356. do {
  1357. strings[field] = e.CurrentString;
  1358. field++;
  1359. } while (field < 4 && EnumNextMultiSz (&e));
  1360. }
  1361. //
  1362. // Validate data (end-user can edit it!)
  1363. //
  1364. if (field != 4) {
  1365. return FALSE;
  1366. }
  1367. if (!strings[0] || !strings[1] || !strings[3]) {
  1368. return FALSE;
  1369. }
  1370. //
  1371. // Create the content struct
  1372. //
  1373. if (ObjectContent) {
  1374. ObjectContent->ContentInFile = FALSE;
  1375. ObjectContent->MemoryContent.ContentSize = SizeOfString (strings[2]);
  1376. if (ObjectContent->MemoryContent.ContentSize) {
  1377. ObjectContent->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize);
  1378. CopyMemory (
  1379. (PBYTE) ObjectContent->MemoryContent.ContentBytes,
  1380. strings[2],
  1381. ObjectContent->MemoryContent.ContentSize
  1382. );
  1383. }
  1384. ObjectContent->Details.DetailsSize = SizeOfString (strings[3]);
  1385. ObjectContent->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize);
  1386. CopyMemory (
  1387. (PBYTE) ObjectContent->Details.DetailsData,
  1388. strings[3],
  1389. ObjectContent->Details.DetailsSize
  1390. );
  1391. }
  1392. *ObjectName = pCreateCookieHandle (strings[0], strings[1]);
  1393. return TRUE;
  1394. }
  1395. PCTSTR
  1396. GetNativeCookieName (
  1397. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. GetNativeCookieName converts the standard Cobra object into a more friendly
  1402. format. The Cobra object comes in the form of ^a<node>^b^c<leaf>, where
  1403. <node> is the URL, and <leaf> is the cookie name. The Cookies native name is
  1404. in the format of <CookieUrl>:<CookieName>.
  1405. Here is an example:
  1406. Cobra object: ^ahttp://foo.com/^b^c#my#cookie
  1407. Native object: cookie://foo.com/:MyCookie
  1408. (^a, ^b and ^c are placeholders for ISM-defined control characters.)
  1409. Arguments:
  1410. ObjectName - Specifies the encoded object name
  1411. Return Value:
  1412. A string that is equivalent to ObjectName, but is in a friendly format.
  1413. This string must be freed with IsmReleaseMemory.
  1414. --*/
  1415. {
  1416. PCTSTR cookieName;
  1417. UINT size;
  1418. PTSTR result = NULL;
  1419. PCTSTR url;
  1420. PCTSTR subUrl;
  1421. PCTSTR cookieUrl;
  1422. PCTSTR fullName;
  1423. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1424. if (url && cookieName) {
  1425. //
  1426. // Skip beyond http:// prefix
  1427. //
  1428. subUrl = _tcschr (url, TEXT(':'));
  1429. if (subUrl) {
  1430. subUrl = _tcsinc (subUrl);
  1431. if (_tcsnextc (subUrl) == TEXT('/')) {
  1432. subUrl = _tcsinc (subUrl);
  1433. }
  1434. if (_tcsnextc (subUrl) == TEXT('/')) {
  1435. subUrl = _tcsinc (subUrl);
  1436. }
  1437. //
  1438. // Connect sub url with cookie:// prefix, then make full native name
  1439. //
  1440. cookieUrl = JoinText (TEXT("cookie://"), subUrl);
  1441. fullName = JoinTextEx (
  1442. NULL,
  1443. cookieUrl,
  1444. cookieName,
  1445. TEXT(":"),
  1446. 0,
  1447. NULL
  1448. );
  1449. FreeText (cookieUrl);
  1450. size = SizeOfString (fullName);
  1451. result = IsmGetMemory (size);
  1452. if (result) {
  1453. CopyMemory (result, fullName, size);
  1454. }
  1455. FreeText (fullName);
  1456. }
  1457. }
  1458. pDestroyCookieStrings (url, cookieName);
  1459. }
  1460. return result;
  1461. }
  1462. PMIG_CONTENT
  1463. ConvertCookieContentToUnicode (
  1464. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1465. IN PMIG_CONTENT ObjectContent
  1466. )
  1467. {
  1468. PMIG_CONTENT result = NULL;
  1469. if (!ObjectContent) {
  1470. return result;
  1471. }
  1472. if (ObjectContent->ContentInFile) {
  1473. return result;
  1474. }
  1475. result = IsmGetMemory (sizeof (MIG_CONTENT));
  1476. if (result) {
  1477. CopyMemory (result, ObjectContent, sizeof (MIG_CONTENT));
  1478. if ((ObjectContent->MemoryContent.ContentSize != 0) &&
  1479. (ObjectContent->MemoryContent.ContentBytes != NULL)
  1480. ) {
  1481. // convert cookie content
  1482. result->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize * 2);
  1483. if (result->MemoryContent.ContentBytes) {
  1484. DirectDbcsToUnicodeN (
  1485. (PWSTR)result->MemoryContent.ContentBytes,
  1486. (PSTR)ObjectContent->MemoryContent.ContentBytes,
  1487. ObjectContent->MemoryContent.ContentSize
  1488. );
  1489. result->MemoryContent.ContentSize = SizeOfStringW ((PWSTR)result->MemoryContent.ContentBytes);
  1490. }
  1491. }
  1492. if ((ObjectContent->Details.DetailsSize != 0) &&
  1493. (ObjectContent->Details.DetailsData != NULL)
  1494. ) {
  1495. // convert cookie details
  1496. result->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize * 2);
  1497. if (result->Details.DetailsData) {
  1498. DirectDbcsToUnicodeN (
  1499. (PWSTR)result->Details.DetailsData,
  1500. (PSTR)ObjectContent->Details.DetailsData,
  1501. ObjectContent->Details.DetailsSize
  1502. );
  1503. result->Details.DetailsSize = SizeOfStringW ((PWSTR)result->Details.DetailsData);
  1504. }
  1505. }
  1506. }
  1507. return result;
  1508. }
  1509. PMIG_CONTENT
  1510. ConvertCookieContentToAnsi (
  1511. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1512. IN PMIG_CONTENT ObjectContent
  1513. )
  1514. {
  1515. PMIG_CONTENT result = NULL;
  1516. if (!ObjectContent) {
  1517. return result;
  1518. }
  1519. if (ObjectContent->ContentInFile) {
  1520. return result;
  1521. }
  1522. result = IsmGetMemory (sizeof (MIG_CONTENT));
  1523. if (result) {
  1524. CopyMemory (result, ObjectContent, sizeof (MIG_CONTENT));
  1525. if ((ObjectContent->MemoryContent.ContentSize != 0) &&
  1526. (ObjectContent->MemoryContent.ContentBytes != NULL)
  1527. ) {
  1528. // convert cookie content
  1529. result->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize);
  1530. if (result->MemoryContent.ContentBytes) {
  1531. DirectUnicodeToDbcsN (
  1532. (PSTR)result->MemoryContent.ContentBytes,
  1533. (PWSTR)ObjectContent->MemoryContent.ContentBytes,
  1534. ObjectContent->MemoryContent.ContentSize
  1535. );
  1536. result->MemoryContent.ContentSize = SizeOfStringA ((PSTR)result->MemoryContent.ContentBytes);
  1537. }
  1538. }
  1539. if ((ObjectContent->Details.DetailsSize != 0) &&
  1540. (ObjectContent->Details.DetailsData != NULL)
  1541. ) {
  1542. // convert cookie details
  1543. result->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize);
  1544. if (result->Details.DetailsData) {
  1545. DirectUnicodeToDbcsN (
  1546. (PSTR)result->Details.DetailsData,
  1547. (PWSTR)ObjectContent->Details.DetailsData,
  1548. ObjectContent->Details.DetailsSize
  1549. );
  1550. result->Details.DetailsSize = SizeOfStringA ((PSTR)result->Details.DetailsData);
  1551. }
  1552. }
  1553. }
  1554. return result;
  1555. }
  1556. BOOL
  1557. FreeConvertedCookieContent (
  1558. IN PMIG_CONTENT ObjectContent
  1559. )
  1560. {
  1561. if (!ObjectContent) {
  1562. return TRUE;
  1563. }
  1564. if (ObjectContent->MemoryContent.ContentBytes) {
  1565. IsmReleaseMemory (ObjectContent->MemoryContent.ContentBytes);
  1566. }
  1567. if (ObjectContent->Details.DetailsData) {
  1568. IsmReleaseMemory (ObjectContent->Details.DetailsData);
  1569. }
  1570. IsmReleaseMemory (ObjectContent);
  1571. return TRUE;
  1572. }