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.

2113 lines
49 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. cookieTypeData.Priority = PRIORITY_COOKIE;
  821. if (Platform != PLATFORM_SOURCE) {
  822. cookieTypeData.RemovePhysicalObject = RemoveCookie;
  823. cookieTypeData.CreatePhysicalObject = CreateCookie;
  824. }
  825. cookieTypeData.DoesPhysicalObjectExist = DoesCookieExist;
  826. cookieTypeData.EnumFirstPhysicalObject = EnumFirstCookie;
  827. cookieTypeData.EnumNextPhysicalObject = EnumNextCookie;
  828. cookieTypeData.AbortEnumPhysicalObject = AbortCookieEnum;
  829. cookieTypeData.ConvertObjectToMultiSz = ConvertCookieToMultiSz;
  830. cookieTypeData.ConvertMultiSzToObject = ConvertMultiSzToCookie;
  831. cookieTypeData.GetNativeObjectName = GetNativeCookieName;
  832. cookieTypeData.AcquirePhysicalObject = AcquireCookie;
  833. cookieTypeData.ReleasePhysicalObject = ReleaseCookie;
  834. cookieTypeData.ConvertObjectContentToUnicode = ConvertCookieContentToUnicode;
  835. cookieTypeData.ConvertObjectContentToAnsi = ConvertCookieContentToAnsi;
  836. cookieTypeData.FreeConvertedObjectContent = FreeConvertedCookieContent;
  837. g_CookieTypeId = IsmRegisterObjectType (
  838. S_COOKIES_NAME,
  839. TRUE,
  840. FALSE,
  841. &cookieTypeData
  842. );
  843. MYASSERT (g_CookieTypeId);
  844. return TRUE;
  845. }
  846. BOOL
  847. WINAPI
  848. CookiesSgmParse (
  849. IN PVOID Reserved
  850. )
  851. /*++
  852. Routine Description:
  853. CookiesSgmParse registers a component with the engine.
  854. Arguments:
  855. Reserved - Unused.
  856. Return Value:
  857. Always TRUE.
  858. --*/
  859. {
  860. TCHAR cookiesDir[MAX_PATH];
  861. IsmAddComponentAlias (
  862. TEXT("$Browser"),
  863. MASTERGROUP_SYSTEM,
  864. S_COOKIES_NAME,
  865. COMPONENT_SUBCOMPONENT,
  866. FALSE
  867. );
  868. if (pGetCookiesPath (cookiesDir)) {
  869. IsmAddComponentAlias (
  870. S_COOKIES_NAME,
  871. MASTERGROUP_SYSTEM,
  872. cookiesDir,
  873. COMPONENT_FOLDER,
  874. FALSE
  875. );
  876. }
  877. return TRUE;
  878. }
  879. BOOL
  880. WINAPI
  881. CookiesSgmQueueEnumeration (
  882. IN PVOID Reserved
  883. )
  884. /*++
  885. Routine Description:
  886. CookiesSgmQueueEnumeration queues all cookies to be processed if the
  887. cookies component is selected.
  888. Arguments:
  889. Reserved - Unused
  890. Return Value:
  891. Always TRUE.
  892. --*/
  893. {
  894. ENCODEDSTRHANDLE pattern;
  895. if (!IsmIsComponentSelected (S_COOKIES_NAME, COMPONENT_SUBCOMPONENT)) {
  896. return TRUE;
  897. }
  898. //
  899. // Use the ISM's build-in callback
  900. //
  901. pattern = IsmCreateSimpleObjectPattern (NULL, TRUE, NULL, TRUE);
  902. IsmQueueEnumeration (
  903. g_CookieTypeId,
  904. pattern,
  905. NULL,
  906. QUEUE_MAKE_APPLY|QUEUE_OVERWRITE_DEST|QUEUE_MAKE_NONCRITICAL,
  907. S_COOKIES_NAME
  908. );
  909. IsmDestroyObjectHandle (pattern);
  910. return TRUE;
  911. }
  912. BOOL
  913. WINAPI
  914. CookiesSourceInitialize (
  915. IN PMIG_LOGCALLBACK LogCallback,
  916. IN PVOID Reserved
  917. )
  918. /*++
  919. Routine Description:
  920. CookiesSourceInitialize initializes the SGM module.
  921. Arguments:
  922. LogCallback - Specifies the argument to pass to the log APIs
  923. Reserved - Unused
  924. Return Value:
  925. Always TRUE.
  926. --*/
  927. {
  928. LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
  929. return TRUE;
  930. }
  931. BOOL
  932. CookiesVcmQueueEnumeration (
  933. IN PVOID Reserved
  934. )
  935. /*++
  936. Routine Description:
  937. CookiesVcmQueueEnumeration is similar to the SGM queue enumeration, except
  938. that it only marks cookies as persistent. There is no need to set
  939. destination priority or apply here.
  940. Arguments:
  941. Reserved - Unused
  942. Return Value:
  943. Always TRUE.
  944. --*/
  945. {
  946. if (!IsmIsComponentSelected (S_COOKIES_NAME, COMPONENT_SUBCOMPONENT)) {
  947. return TRUE;
  948. }
  949. IsmQueueEnumeration (g_CookieTypeId, NULL, NULL, QUEUE_MAKE_PERSISTENT|QUEUE_MAKE_NONCRITICAL, NULL);
  950. return TRUE;
  951. }
  952. /*++
  953. The following enumeration routines are the ETM entry points. They rely
  954. on the enumeration routines above to access the physical machine.
  955. --*/
  956. BOOL
  957. pEnumCookieWorker (
  958. OUT PMIG_TYPEOBJECTENUM EnumPtr,
  959. IN PCOOKIES_ENUM CookieEnum
  960. )
  961. {
  962. PCTSTR expiresStr;
  963. //
  964. // Clean up previous enum resources
  965. //
  966. pDestroyCookieStrings (EnumPtr->ObjectNode, EnumPtr->ObjectLeaf);
  967. EnumPtr->ObjectNode = NULL;
  968. EnumPtr->ObjectLeaf = NULL;
  969. IsmReleaseMemory (EnumPtr->NativeObjectName);
  970. EnumPtr->NativeObjectName = NULL;
  971. //
  972. // Find the next match
  973. //
  974. for (;;) {
  975. EnumPtr->ObjectName = CookieEnum->HashData.String;
  976. if (ObsPatternMatch (CookieEnum->Pattern, EnumPtr->ObjectName)) {
  977. break;
  978. }
  979. if (!EnumNextHashTableString (&CookieEnum->HashData)) {
  980. AbortCookieEnum (EnumPtr);
  981. return FALSE;
  982. }
  983. }
  984. //
  985. // Fill the caller's structure and return success
  986. //
  987. if (!pCreateCookieStrings (EnumPtr->ObjectName, &EnumPtr->ObjectNode, &EnumPtr->ObjectLeaf)) {
  988. return FALSE;
  989. }
  990. EnumPtr->NativeObjectName = GetNativeCookieName (EnumPtr->ObjectName);
  991. EnumPtr->Level = 1;
  992. EnumPtr->SubLevel = 0;
  993. EnumPtr->IsLeaf = TRUE;
  994. EnumPtr->IsNode = TRUE;
  995. expiresStr = *((PCTSTR *) CookieEnum->HashData.ExtraData);
  996. expiresStr = GetEndOfString (expiresStr) + 1;
  997. EnumPtr->Details.DetailsSize = SizeOfString (expiresStr);
  998. EnumPtr->Details.DetailsData = (PCBYTE) expiresStr;
  999. return TRUE;
  1000. }
  1001. BOOL
  1002. EnumFirstCookie (
  1003. IN OUT PMIG_TYPEOBJECTENUM EnumPtr, CALLER_INITIALIZED
  1004. IN MIG_OBJECTSTRINGHANDLE Pattern,
  1005. IN UINT MaxLevel
  1006. )
  1007. {
  1008. PCOOKIES_ENUM cookieEnum = NULL;
  1009. if (!g_CookiesTable) {
  1010. return FALSE;
  1011. }
  1012. cookieEnum = (PCOOKIES_ENUM) PmGetMemory (g_CookiesPool, sizeof (COOKIES_ENUM));
  1013. cookieEnum->Pattern = PmDuplicateString (g_CookiesPool, Pattern);
  1014. EnumPtr->EtmHandle = (LONG_PTR) cookieEnum;
  1015. if (EnumFirstHashTableString (&cookieEnum->HashData, g_CookiesTable)) {
  1016. return pEnumCookieWorker (EnumPtr, cookieEnum);
  1017. } else {
  1018. AbortCookieEnum (EnumPtr);
  1019. return FALSE;
  1020. }
  1021. }
  1022. BOOL
  1023. EnumNextCookie (
  1024. IN OUT PMIG_TYPEOBJECTENUM EnumPtr
  1025. )
  1026. {
  1027. PCOOKIES_ENUM cookieEnum = NULL;
  1028. cookieEnum = (PCOOKIES_ENUM)(EnumPtr->EtmHandle);
  1029. if (!cookieEnum) {
  1030. return FALSE;
  1031. }
  1032. if (EnumNextHashTableString (&cookieEnum->HashData)) {
  1033. return pEnumCookieWorker (EnumPtr, cookieEnum);
  1034. } else {
  1035. AbortCookieEnum (EnumPtr);
  1036. return FALSE;
  1037. }
  1038. }
  1039. VOID
  1040. AbortCookieEnum (
  1041. IN PMIG_TYPEOBJECTENUM EnumPtr ZEROED
  1042. )
  1043. {
  1044. PCOOKIES_ENUM cookieEnum;
  1045. pDestroyCookieStrings (EnumPtr->ObjectNode, EnumPtr->ObjectLeaf);
  1046. IsmReleaseMemory (EnumPtr->NativeObjectName);
  1047. cookieEnum = (PCOOKIES_ENUM)(EnumPtr->EtmHandle);
  1048. if (cookieEnum) {
  1049. PmReleaseMemory (g_CookiesPool, cookieEnum->Pattern);
  1050. PmReleaseMemory (g_CookiesPool, cookieEnum);
  1051. }
  1052. ZeroMemory (EnumPtr, sizeof (MIG_TYPEOBJECTENUM));
  1053. }
  1054. /*++
  1055. The next set of functions implement the ETM entry points to acquire, test,
  1056. create and remove cookies. They rely on the cookie hash table being
  1057. accurate.
  1058. --*/
  1059. BOOL
  1060. AcquireCookie (
  1061. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1062. OUT PMIG_CONTENT ObjectContent, CALLER_INITIALIZED
  1063. IN MIG_CONTENTTYPE ContentType,
  1064. IN UINT MemoryContentLimit
  1065. )
  1066. {
  1067. PCTSTR cookieData = NULL;
  1068. MYASSERT (ObjectContent);
  1069. if (ContentType == CONTENTTYPE_FILE) {
  1070. // nobody should request this as a file
  1071. MYASSERT (FALSE);
  1072. return FALSE;
  1073. }
  1074. if (HtFindStringEx (g_CookiesTable, ObjectName, (PVOID) (&cookieData), FALSE)) {
  1075. ObjectContent->MemoryContent.ContentBytes = (PCBYTE) cookieData;
  1076. ObjectContent->MemoryContent.ContentSize = SizeOfString (cookieData);
  1077. cookieData = GetEndOfString (cookieData) + 1;
  1078. ObjectContent->Details.DetailsData = (PCBYTE) cookieData;
  1079. ObjectContent->Details.DetailsSize = SizeOfString (cookieData);
  1080. return TRUE;
  1081. }
  1082. return FALSE;
  1083. }
  1084. BOOL
  1085. ReleaseCookie (
  1086. IN PMIG_CONTENT ObjectContent ZEROED
  1087. )
  1088. {
  1089. if (ObjectContent) {
  1090. ZeroMemory (ObjectContent, sizeof (MIG_CONTENT));
  1091. }
  1092. return TRUE;
  1093. }
  1094. BOOL
  1095. DoesCookieExist (
  1096. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1097. )
  1098. {
  1099. if (g_DelayCookiesOp) {
  1100. return FALSE;
  1101. }
  1102. if (HtFindString (g_CookiesTable, ObjectName)) {
  1103. return TRUE;
  1104. }
  1105. return FALSE;
  1106. }
  1107. BOOL
  1108. pRemoveCookieWorker (
  1109. IN PCTSTR ObjectName,
  1110. IN PCTSTR Url,
  1111. IN PCTSTR CookieName
  1112. )
  1113. {
  1114. BOOL result = TRUE;
  1115. if (InternetSetCookie (
  1116. Url,
  1117. CookieName,
  1118. TEXT("foo; expires = Sat, 01-Jan-2000 00:00:00 GMT")
  1119. )) {
  1120. HtRemoveString (g_CookiesTable, ObjectName);
  1121. } else {
  1122. result = FALSE;
  1123. DEBUGMSG ((
  1124. DBG_ERROR,
  1125. "Unable to delete cookie %s for URL %s\n",
  1126. CookieName,
  1127. Url
  1128. ));
  1129. }
  1130. return result;
  1131. }
  1132. BOOL
  1133. RemoveCookie (
  1134. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1135. )
  1136. {
  1137. PCTSTR url;
  1138. PCTSTR cookieName;
  1139. BOOL result = FALSE;
  1140. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1141. if (url && cookieName) {
  1142. if (g_DelayCookiesOp) {
  1143. //
  1144. // delay this cookie create because wininet apis do not work
  1145. // for non-logged on users
  1146. //
  1147. IsmRecordDelayedOperation (
  1148. JRNOP_DELETE,
  1149. g_CookieTypeId,
  1150. ObjectName,
  1151. NULL
  1152. );
  1153. result = TRUE;
  1154. } else {
  1155. //
  1156. // add journal entry, then perform cookie deletion
  1157. //
  1158. IsmRecordOperation (
  1159. JRNOP_DELETE,
  1160. g_CookieTypeId,
  1161. ObjectName
  1162. );
  1163. result = pRemoveCookieWorker (ObjectName, url, cookieName);
  1164. }
  1165. }
  1166. pDestroyCookieStrings (url, cookieName);
  1167. }
  1168. return result;
  1169. }
  1170. BOOL
  1171. pCreateCookieWorker (
  1172. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1173. IN PMIG_CONTENT ObjectContent,
  1174. IN PCTSTR Url,
  1175. IN PCTSTR CookieName
  1176. )
  1177. {
  1178. PCTSTR fixedCookieData;
  1179. PCTSTR cookieData;
  1180. PCTSTR expires;
  1181. BOOL result = FALSE;
  1182. GROWBUFFER tempBuf = INIT_GROWBUFFER;
  1183. //
  1184. // write the object by joining the content with the details
  1185. //
  1186. cookieData = (PCTSTR) (ObjectContent->MemoryContent.ContentBytes);
  1187. expires = (PCTSTR) (ObjectContent->Details.DetailsData);
  1188. fixedCookieData = JoinTextEx (
  1189. NULL,
  1190. cookieData,
  1191. expires,
  1192. TEXT(";"),
  1193. 0,
  1194. NULL
  1195. );
  1196. if (InternetSetCookie (Url, CookieName, fixedCookieData)) {
  1197. pAddCookieToHashTable (
  1198. &tempBuf,
  1199. ObjectName,
  1200. Url,
  1201. CookieName,
  1202. cookieData,
  1203. expires
  1204. );
  1205. result = TRUE;
  1206. } else {
  1207. DEBUGMSG ((
  1208. DBG_COOKIES,
  1209. "Unable to set cookie %s for URL %s\n",
  1210. CookieName,
  1211. Url
  1212. ));
  1213. }
  1214. FreeText (fixedCookieData);
  1215. GbFree (&tempBuf);
  1216. return result;
  1217. }
  1218. BOOL
  1219. CreateCookie (
  1220. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1221. IN PMIG_CONTENT ObjectContent
  1222. )
  1223. {
  1224. PCTSTR url;
  1225. PCTSTR cookieName;
  1226. BOOL result = FALSE;
  1227. if (!ObjectContent->ContentInFile) {
  1228. if (ObjectContent->MemoryContent.ContentBytes &&
  1229. ObjectContent->MemoryContent.ContentSize &&
  1230. ObjectContent->Details.DetailsSize &&
  1231. ObjectContent->Details.DetailsData
  1232. ) {
  1233. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1234. if (url && cookieName) {
  1235. if (g_DelayCookiesOp) {
  1236. //
  1237. // delay this cookie create because wininet apis do not work
  1238. // for non-logged on users
  1239. //
  1240. IsmRecordDelayedOperation (
  1241. JRNOP_CREATE,
  1242. g_CookieTypeId,
  1243. ObjectName,
  1244. ObjectContent
  1245. );
  1246. result = TRUE;
  1247. } else {
  1248. //
  1249. // add journal entry, then create the cookie
  1250. //
  1251. IsmRecordOperation (
  1252. JRNOP_CREATE,
  1253. g_CookieTypeId,
  1254. ObjectName
  1255. );
  1256. if (DoesCookieExist (ObjectName)) {
  1257. //
  1258. // Fail because cookie cannot be overwritten
  1259. //
  1260. result = FALSE;
  1261. } else {
  1262. result = pCreateCookieWorker (
  1263. ObjectName,
  1264. ObjectContent,
  1265. url,
  1266. cookieName
  1267. );
  1268. }
  1269. }
  1270. }
  1271. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie node or leaf: %s", ObjectName));
  1272. pDestroyCookieStrings (url, cookieName);
  1273. }
  1274. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie object: %s", ObjectName));
  1275. }
  1276. ELSE_DEBUGMSG ((DBG_ERROR, "Can't write incomplete cookie object"));
  1277. }
  1278. return result;
  1279. }
  1280. /*++
  1281. The next group of functions converts a cookie object into a string format,
  1282. suitable for output to an INF file. The reverse conversion is also
  1283. implemented.
  1284. --*/
  1285. PCTSTR
  1286. ConvertCookieToMultiSz (
  1287. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1288. IN PMIG_CONTENT ObjectContent
  1289. )
  1290. {
  1291. PCTSTR url, cookieName;
  1292. PTSTR result = NULL;
  1293. PCTSTR data;
  1294. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1295. MYASSERT (url);
  1296. MYASSERT (cookieName);
  1297. //
  1298. // Build a multi-sz in the following format:
  1299. //
  1300. // <url>\0<cookie name>\0<cookie data>\0<expiration>\0\0
  1301. //
  1302. g_CookieConversionBuff.End = 0;
  1303. // <url>
  1304. GbCopyQuotedString (&g_CookieConversionBuff, url);
  1305. // <cookie name>
  1306. GbCopyQuotedString (&g_CookieConversionBuff, cookieName);
  1307. // <cookie data>
  1308. MYASSERT (!ObjectContent->ContentInFile);
  1309. if ((!ObjectContent->ContentInFile) &&
  1310. (ObjectContent->MemoryContent.ContentSize) &&
  1311. (ObjectContent->MemoryContent.ContentBytes)
  1312. ) {
  1313. data = (PCTSTR) ObjectContent->MemoryContent.ContentBytes;
  1314. GbCopyQuotedString (&g_CookieConversionBuff, data);
  1315. }
  1316. // <expiration>
  1317. MYASSERT (ObjectContent->Details.DetailsSize);
  1318. if (ObjectContent->Details.DetailsSize &&
  1319. ObjectContent->Details.DetailsData
  1320. ) {
  1321. data = (PCTSTR) ObjectContent->Details.DetailsData;
  1322. GbCopyQuotedString (&g_CookieConversionBuff, data);
  1323. }
  1324. // nul terminator
  1325. GbCopyString (&g_CookieConversionBuff, TEXT(""));
  1326. //
  1327. // Transfer multi-sz to ISM memory
  1328. //
  1329. result = IsmGetMemory (g_CookieConversionBuff.End);
  1330. CopyMemory (result, g_CookieConversionBuff.Buf, g_CookieConversionBuff.End);
  1331. //
  1332. // Clean up
  1333. //
  1334. pDestroyCookieStrings (url, cookieName);
  1335. }
  1336. ELSE_DEBUGMSG ((DBG_ERROR, "Invalid cookie object: %s", ObjectName));
  1337. return result;
  1338. }
  1339. BOOL
  1340. ConvertMultiSzToCookie (
  1341. IN PCTSTR ObjectMultiSz,
  1342. OUT MIG_OBJECTSTRINGHANDLE *ObjectName,
  1343. OUT PMIG_CONTENT ObjectContent OPTIONAL CALLER_INITIALIZED
  1344. )
  1345. {
  1346. MULTISZ_ENUM e;
  1347. PCTSTR strings[4];
  1348. UINT field;
  1349. g_CookieConversionBuff.End = 0;
  1350. //
  1351. // Fill the object content from the following multi-sz:
  1352. //
  1353. // <url>\0<cookie name>\0<cookie data>\0<expiration>\0\0
  1354. //
  1355. field = 0;
  1356. if (EnumFirstMultiSz (&e, ObjectMultiSz)) {
  1357. do {
  1358. strings[field] = e.CurrentString;
  1359. field++;
  1360. } while (field < 4 && EnumNextMultiSz (&e));
  1361. }
  1362. //
  1363. // Validate data (end-user can edit it!)
  1364. //
  1365. if (field != 4) {
  1366. return FALSE;
  1367. }
  1368. if (!strings[0] || !strings[1] || !strings[3]) {
  1369. return FALSE;
  1370. }
  1371. //
  1372. // Create the content struct
  1373. //
  1374. if (ObjectContent) {
  1375. ObjectContent->ContentInFile = FALSE;
  1376. ObjectContent->MemoryContent.ContentSize = SizeOfString (strings[2]);
  1377. if (ObjectContent->MemoryContent.ContentSize) {
  1378. ObjectContent->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize);
  1379. CopyMemory (
  1380. (PBYTE) ObjectContent->MemoryContent.ContentBytes,
  1381. strings[2],
  1382. ObjectContent->MemoryContent.ContentSize
  1383. );
  1384. }
  1385. ObjectContent->Details.DetailsSize = SizeOfString (strings[3]);
  1386. ObjectContent->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize);
  1387. CopyMemory (
  1388. (PBYTE) ObjectContent->Details.DetailsData,
  1389. strings[3],
  1390. ObjectContent->Details.DetailsSize
  1391. );
  1392. }
  1393. *ObjectName = pCreateCookieHandle (strings[0], strings[1]);
  1394. return TRUE;
  1395. }
  1396. PCTSTR
  1397. GetNativeCookieName (
  1398. IN MIG_OBJECTSTRINGHANDLE ObjectName
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. GetNativeCookieName converts the standard Cobra object into a more friendly
  1403. format. The Cobra object comes in the form of ^a<node>^b^c<leaf>, where
  1404. <node> is the URL, and <leaf> is the cookie name. The Cookies native name is
  1405. in the format of <CookieUrl>:<CookieName>.
  1406. Here is an example:
  1407. Cobra object: ^ahttp://foo.com/^b^c#my#cookie
  1408. Native object: cookie://foo.com/:MyCookie
  1409. (^a, ^b and ^c are placeholders for ISM-defined control characters.)
  1410. Arguments:
  1411. ObjectName - Specifies the encoded object name
  1412. Return Value:
  1413. A string that is equivalent to ObjectName, but is in a friendly format.
  1414. This string must be freed with IsmReleaseMemory.
  1415. --*/
  1416. {
  1417. PCTSTR cookieName;
  1418. UINT size;
  1419. PTSTR result = NULL;
  1420. PCTSTR url;
  1421. PCTSTR subUrl;
  1422. PCTSTR cookieUrl;
  1423. PCTSTR fullName;
  1424. if (pCreateCookieStrings (ObjectName, &url, &cookieName)) {
  1425. if (url && cookieName) {
  1426. //
  1427. // Skip beyond http:// prefix
  1428. //
  1429. subUrl = _tcschr (url, TEXT(':'));
  1430. if (subUrl) {
  1431. subUrl = _tcsinc (subUrl);
  1432. if (_tcsnextc (subUrl) == TEXT('/')) {
  1433. subUrl = _tcsinc (subUrl);
  1434. }
  1435. if (_tcsnextc (subUrl) == TEXT('/')) {
  1436. subUrl = _tcsinc (subUrl);
  1437. }
  1438. //
  1439. // Connect sub url with cookie:// prefix, then make full native name
  1440. //
  1441. cookieUrl = JoinText (TEXT("cookie://"), subUrl);
  1442. fullName = JoinTextEx (
  1443. NULL,
  1444. cookieUrl,
  1445. cookieName,
  1446. TEXT(":"),
  1447. 0,
  1448. NULL
  1449. );
  1450. FreeText (cookieUrl);
  1451. size = SizeOfString (fullName);
  1452. result = IsmGetMemory (size);
  1453. if (result) {
  1454. CopyMemory (result, fullName, size);
  1455. }
  1456. FreeText (fullName);
  1457. }
  1458. }
  1459. pDestroyCookieStrings (url, cookieName);
  1460. }
  1461. return result;
  1462. }
  1463. PMIG_CONTENT
  1464. ConvertCookieContentToUnicode (
  1465. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1466. IN PMIG_CONTENT ObjectContent
  1467. )
  1468. {
  1469. PMIG_CONTENT result = NULL;
  1470. if (!ObjectContent) {
  1471. return result;
  1472. }
  1473. if (ObjectContent->ContentInFile) {
  1474. return result;
  1475. }
  1476. result = IsmGetMemory (sizeof (MIG_CONTENT));
  1477. if (result) {
  1478. CopyMemory (result, ObjectContent, sizeof (MIG_CONTENT));
  1479. if ((ObjectContent->MemoryContent.ContentSize != 0) &&
  1480. (ObjectContent->MemoryContent.ContentBytes != NULL)
  1481. ) {
  1482. // convert cookie content
  1483. result->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize * 2);
  1484. if (result->MemoryContent.ContentBytes) {
  1485. DirectDbcsToUnicodeN (
  1486. (PWSTR)result->MemoryContent.ContentBytes,
  1487. (PSTR)ObjectContent->MemoryContent.ContentBytes,
  1488. ObjectContent->MemoryContent.ContentSize
  1489. );
  1490. result->MemoryContent.ContentSize = SizeOfStringW ((PWSTR)result->MemoryContent.ContentBytes);
  1491. }
  1492. }
  1493. if ((ObjectContent->Details.DetailsSize != 0) &&
  1494. (ObjectContent->Details.DetailsData != NULL)
  1495. ) {
  1496. // convert cookie details
  1497. result->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize * 2);
  1498. if (result->Details.DetailsData) {
  1499. DirectDbcsToUnicodeN (
  1500. (PWSTR)result->Details.DetailsData,
  1501. (PSTR)ObjectContent->Details.DetailsData,
  1502. ObjectContent->Details.DetailsSize
  1503. );
  1504. result->Details.DetailsSize = SizeOfStringW ((PWSTR)result->Details.DetailsData);
  1505. }
  1506. }
  1507. }
  1508. return result;
  1509. }
  1510. PMIG_CONTENT
  1511. ConvertCookieContentToAnsi (
  1512. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1513. IN PMIG_CONTENT ObjectContent
  1514. )
  1515. {
  1516. PMIG_CONTENT result = NULL;
  1517. if (!ObjectContent) {
  1518. return result;
  1519. }
  1520. if (ObjectContent->ContentInFile) {
  1521. return result;
  1522. }
  1523. result = IsmGetMemory (sizeof (MIG_CONTENT));
  1524. if (result) {
  1525. CopyMemory (result, ObjectContent, sizeof (MIG_CONTENT));
  1526. if ((ObjectContent->MemoryContent.ContentSize != 0) &&
  1527. (ObjectContent->MemoryContent.ContentBytes != NULL)
  1528. ) {
  1529. // convert cookie content
  1530. result->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize);
  1531. if (result->MemoryContent.ContentBytes) {
  1532. DirectUnicodeToDbcsN (
  1533. (PSTR)result->MemoryContent.ContentBytes,
  1534. (PWSTR)ObjectContent->MemoryContent.ContentBytes,
  1535. ObjectContent->MemoryContent.ContentSize
  1536. );
  1537. result->MemoryContent.ContentSize = SizeOfStringA ((PSTR)result->MemoryContent.ContentBytes);
  1538. }
  1539. }
  1540. if ((ObjectContent->Details.DetailsSize != 0) &&
  1541. (ObjectContent->Details.DetailsData != NULL)
  1542. ) {
  1543. // convert cookie details
  1544. result->Details.DetailsData = IsmGetMemory (ObjectContent->Details.DetailsSize);
  1545. if (result->Details.DetailsData) {
  1546. DirectUnicodeToDbcsN (
  1547. (PSTR)result->Details.DetailsData,
  1548. (PWSTR)ObjectContent->Details.DetailsData,
  1549. ObjectContent->Details.DetailsSize
  1550. );
  1551. result->Details.DetailsSize = SizeOfStringA ((PSTR)result->Details.DetailsData);
  1552. }
  1553. }
  1554. }
  1555. return result;
  1556. }
  1557. BOOL
  1558. FreeConvertedCookieContent (
  1559. IN PMIG_CONTENT ObjectContent
  1560. )
  1561. {
  1562. if (!ObjectContent) {
  1563. return TRUE;
  1564. }
  1565. if (ObjectContent->MemoryContent.ContentBytes) {
  1566. IsmReleaseMemory (ObjectContent->MemoryContent.ContentBytes);
  1567. }
  1568. if (ObjectContent->Details.DetailsData) {
  1569. IsmReleaseMemory (ObjectContent->Details.DetailsData);
  1570. }
  1571. IsmReleaseMemory (ObjectContent);
  1572. return TRUE;
  1573. }