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.

1801 lines
52 KiB

  1. /**********************************************************************/
  2. /** Microsoft Passport **/
  3. /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/
  4. /**********************************************************************/
  5. /*
  6. HelperFuncs.cpp
  7. COM object for manager interface
  8. FILE HISTORY:
  9. */
  10. // HelperFuncs.cpp : Useful functions
  11. #include "stdafx.h"
  12. #include <time.h>
  13. #include "HelperFuncs.h"
  14. #include "Monitoring.h"
  15. #include "nsconst.h"
  16. #include <wininet.h>
  17. #include <commd5.h>
  18. using namespace ATL;
  19. LPWSTR GetVersionString(void);
  20. BOOL PPEscapeUrl(LPCTSTR lpszStringIn,
  21. LPTSTR lpszStringOut,
  22. DWORD* pdwStrLen,
  23. DWORD dwMaxLength,
  24. DWORD dwFlags);
  25. //===========================================================================
  26. //
  27. // @func Copy char string helper, and ADDs the length of the source string
  28. // to cb.
  29. //
  30. // @rdesc returns the pointer into the buffer of last char copied.
  31. //
  32. LPSTR
  33. CopyHelperA(
  34. LPSTR pszDest, //@parm start of buffer to copy INTO
  35. LPCSTR pszSrc, //@parm string to copy
  36. LPCSTR pszBufEnd, //@parm end of buffer to prevent overwrite
  37. DWORD &cb //@parm length of the source string will be ADDed to this value
  38. )
  39. {
  40. LPCSTR pszDestTemp = pszDest;
  41. if(!pszDest || !pszSrc)
  42. return pszDest;
  43. while( (pszDest < pszBufEnd) && (*pszDest = *pszSrc))
  44. {
  45. pszDest++;
  46. pszSrc++;
  47. }
  48. cb += (DWORD) (pszDest - pszDestTemp);
  49. while(*pszSrc++)
  50. cb++;
  51. return( pszDest );
  52. }
  53. //===========================================================================
  54. //
  55. // Copy wchar string helper
  56. //
  57. LPWSTR
  58. CopyHelperW(
  59. LPWSTR pszDest,
  60. LPCWSTR pszSrc,
  61. LPCWSTR pszBufEnd
  62. )
  63. {
  64. if(!pszDest || !pszSrc)
  65. return pszDest;
  66. while( (pszDest < pszBufEnd) && (*pszDest = *pszSrc))
  67. {
  68. pszDest++;
  69. pszSrc++;
  70. }
  71. return( pszDest );
  72. }
  73. //===========================================================================
  74. //
  75. // Copy wchar string helper
  76. //
  77. LPWSTR
  78. CopyNHelperW(
  79. LPWSTR pszDest,
  80. LPCWSTR pszSrc,
  81. ULONG ulCount,
  82. LPCWSTR pszBufEnd
  83. )
  84. {
  85. ULONG ulCur = 0;
  86. if(!pszDest || !pszSrc)
  87. return pszDest;
  88. while( (pszDest < pszBufEnd) && (*pszDest = *pszSrc))
  89. {
  90. pszDest++;
  91. pszSrc++;
  92. if(++ulCur == ulCount) break;
  93. }
  94. return pszDest;
  95. }
  96. //===========================================================================
  97. //
  98. // Format a logo tag HTML element
  99. //
  100. BSTR
  101. FormatNormalLogoTag(
  102. LPCWSTR pszLoginServerURL,
  103. ULONG ulSiteId,
  104. LPCWSTR pszReturnURL,
  105. ULONG ulTimeWindow,
  106. BOOL bForceLogin,
  107. ULONG ulCurrentCryptVersion,
  108. time_t tCurrentTime,
  109. LPCWSTR pszCoBrand,
  110. LPCWSTR pszImageURL,
  111. LPCWSTR pszNameSpace,
  112. int nKPP,
  113. PM_LOGOTYPE nLogoType,
  114. USHORT lang,
  115. ULONG ulSecureLevel,
  116. CRegistryConfig* pCRC,
  117. BOOL fRedirToSelf,
  118. BOOL bCreateTPF
  119. )
  120. /*
  121. The old sprintf for reference:
  122. _snwprintf(text, 2048, L"<A HREF=\"%s?id=%d&ru=%s&tw=%d&fs=%s&kv=%d&ct=%u%s%s\">%s</A>",
  123. url, crc->getSiteId(), returnUrl, TimeWindow, ForceLogin ? L"1" : L"0",
  124. crc->getCurrentCryptVersion(), ct, CBT?L"&cb=":L"", CBT?CBT:L"", iurl);
  125. */
  126. {
  127. WCHAR text[MAX_URL_LENGTH * 2];
  128. LPWSTR pszCurrent = text;
  129. LPCWSTR pszBufEnd = &(text[MAX_URL_LENGTH * 2 - 1]);
  130. // logotag specific format
  131. pszCurrent = CopyHelperW(pszCurrent, L"<A HREF=\"", pszBufEnd);
  132. // call the common formatting function
  133. // it is the same for AuthURL and LogoTag
  134. pszCurrent = FormatAuthURLParameters(pszLoginServerURL,
  135. ulSiteId,
  136. pszReturnURL,
  137. ulTimeWindow,
  138. bForceLogin,
  139. ulCurrentCryptVersion,
  140. tCurrentTime,
  141. pszCoBrand,
  142. pszNameSpace,
  143. nKPP,
  144. pszCurrent,
  145. MAX_URL_LENGTH,
  146. lang,
  147. ulSecureLevel,
  148. pCRC,
  149. fRedirToSelf &&
  150. nLogoType == PM_LOGOTYPE_SIGNIN,
  151. bCreateTPF
  152. );
  153. if (NULL == pszCurrent)
  154. {
  155. return NULL;
  156. }
  157. pszCurrent = CopyHelperW(pszCurrent, L"\">", pszBufEnd);
  158. pszCurrent = CopyHelperW(pszCurrent, pszImageURL, pszBufEnd);
  159. pszCurrent = CopyHelperW(pszCurrent, L"</A>", pszBufEnd);
  160. return ALLOC_AND_GIVEAWAY_BSTR(text);
  161. }
  162. //===========================================================================
  163. //
  164. // Format a update logo tag HTML element
  165. //
  166. BSTR
  167. FormatUpdateLogoTag(
  168. LPCWSTR pszLoginServerURL,
  169. ULONG ulSiteId,
  170. LPCWSTR pszReturnURL,
  171. ULONG ulTimeWindow,
  172. BOOL bForceLogin,
  173. ULONG ulCurrentKeyVersion,
  174. time_t tCurrentTime,
  175. LPCWSTR pszCoBrand,
  176. int nKPP,
  177. LPCWSTR pszUpdateServerURL,
  178. BOOL bSecure,
  179. LPCWSTR pszProfileUpdate,
  180. PM_LOGOTYPE nLogoType,
  181. ULONG ulSecureLevel,
  182. CRegistryConfig* pCRC,
  183. BOOL bCreateTPF
  184. )
  185. /*
  186. The old sprintf for reference:
  187. _snwprintf(text, 2048,
  188. L"<A HREF=\"%s?id=%d&ru=%s&tw=%d&fs=%s&kv=%d&ct=%u%s%s\">%.*s?id=%d&ct=%u&sec=%s&ru=%s&up=%s%s</A>",
  189. url, crc->getSiteId(), returnUrl, TimeWindow, ForceLogin ? L"1" : L"0",
  190. crc->getCurrentCryptVersion(), ct, CBT?L"&cb=":L"", CBT?CBT:L"",
  191. (ins-iurl), iurl, crc->getSiteId(), ct, (bSecure ? L"true" : L"false"),returnUrl,
  192. newCH, ins+2);
  193. */
  194. {
  195. WCHAR text[MAX_URL_LENGTH * 2];
  196. WCHAR temp[40];
  197. WCHAR siteid[40];
  198. WCHAR curtime[40];
  199. LPWSTR pszCurrent = text;
  200. LPCWSTR pszBufEnd = &(text[MAX_URL_LENGTH * 2 - 1]);
  201. LPWSTR pszFirstHalfEnd;
  202. HRESULT hr = S_OK;
  203. pszCurrent = CopyHelperW(pszCurrent, L"<A HREF=\"", pszBufEnd);
  204. LPWSTR signStart1 = pszCurrent;
  205. pszCurrent = CopyHelperW(pszCurrent, pszLoginServerURL, pszBufEnd);
  206. if(wcschr(text, L'?') == NULL)
  207. pszCurrent = CopyHelperW(pszCurrent, L"?id=", pszBufEnd);
  208. else
  209. pszCurrent = CopyHelperW(pszCurrent, L"&id=", pszBufEnd);
  210. _ultow(ulSiteId, siteid, 10);
  211. pszCurrent = CopyHelperW(pszCurrent, siteid, pszBufEnd);
  212. pszCurrent = CopyHelperW(pszCurrent, L"&ru=", pszBufEnd);
  213. pszCurrent = CopyHelperW(pszCurrent, pszReturnURL, pszBufEnd);
  214. pszCurrent = CopyHelperW(pszCurrent, L"&tw=", pszBufEnd);
  215. _ultow(ulTimeWindow, temp, 10);
  216. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  217. pszCurrent = CopyHelperW(pszCurrent, L"&fs=", pszBufEnd);
  218. pszCurrent = CopyHelperW(pszCurrent, bForceLogin ? L"1" : L"0", pszBufEnd);
  219. pszCurrent = CopyHelperW(pszCurrent, L"&kv=", pszBufEnd);
  220. _ultow(ulCurrentKeyVersion, temp, 10);
  221. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  222. pszCurrent = CopyHelperW(pszCurrent, L"&ct=", pszBufEnd);
  223. _ultow(tCurrentTime, curtime, 10);
  224. pszCurrent = CopyHelperW(pszCurrent, curtime, pszBufEnd);
  225. if(pszCoBrand)
  226. {
  227. pszCurrent = CopyHelperW(pszCurrent, L"&cb=", pszBufEnd);
  228. pszCurrent = CopyHelperW(pszCurrent, pszCoBrand, pszBufEnd);
  229. }
  230. if(nKPP != -1)
  231. {
  232. pszCurrent = CopyHelperW(pszCurrent, L"&kpp=", pszBufEnd);
  233. _ultow(nKPP, temp, 10);
  234. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  235. }
  236. if(ulSecureLevel != 0)
  237. {
  238. pszCurrent = CopyHelperW(pszCurrent, L"&seclog=", pszBufEnd);
  239. _ultow(ulSecureLevel, temp, 10);
  240. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  241. }
  242. pszCurrent = CopyHelperW(pszCurrent, L"&ver=", pszBufEnd);
  243. pszCurrent = CopyHelperW(pszCurrent, GetVersionString(), pszBufEnd);
  244. hr = SignQueryString(pCRC, ulCurrentKeyVersion, signStart1, pszCurrent, pszBufEnd, bCreateTPF);
  245. if (S_OK != hr)
  246. {
  247. return NULL;
  248. }
  249. pszCurrent = CopyHelperW(pszCurrent, L"\">", pszBufEnd);
  250. pszFirstHalfEnd = pszUpdateServerURL ? (wcsstr(pszUpdateServerURL, L"$1")) : NULL;
  251. pszCurrent = CopyNHelperW(pszCurrent, pszUpdateServerURL, (ULONG)(pszFirstHalfEnd - pszUpdateServerURL), pszBufEnd);
  252. pszCurrent = CopyHelperW(pszCurrent, L"?id=", pszBufEnd);
  253. pszCurrent = CopyHelperW(pszCurrent, siteid, pszBufEnd);
  254. pszCurrent = CopyHelperW(pszCurrent, L"&ct=", pszBufEnd);
  255. pszCurrent = CopyHelperW(pszCurrent, curtime, pszBufEnd);
  256. pszCurrent = CopyHelperW(pszCurrent, L"&sec=", pszBufEnd);
  257. pszCurrent = CopyHelperW(pszCurrent, bSecure ? L"true" : L"false", pszBufEnd);
  258. pszCurrent = CopyHelperW(pszCurrent, L"&ru=", pszBufEnd);
  259. pszCurrent = CopyHelperW(pszCurrent, pszReturnURL, pszBufEnd);
  260. pszCurrent = CopyHelperW(pszCurrent, L"&up=", pszBufEnd);
  261. pszCurrent = CopyHelperW(pszCurrent, pszProfileUpdate, pszBufEnd);
  262. pszCurrent = CopyHelperW(pszCurrent, pszFirstHalfEnd + 2, pszBufEnd);
  263. pszCurrent = CopyHelperW(pszCurrent, L"</A>", pszBufEnd);
  264. return ALLOC_AND_GIVEAWAY_BSTR(text);
  265. }
  266. //===========================================================================
  267. //
  268. // Sign a query string with partner's key
  269. //
  270. HRESULT SignQueryString(
  271. CRegistryConfig* pCRC,
  272. ULONG ulCurrentKeyVersion,
  273. LPWSTR pszBufStart,
  274. LPWSTR& pszCurrent,
  275. LPCWSTR pszBufEnd,
  276. BOOL bCreateTPF
  277. )
  278. {
  279. BSTR signature = NULL;
  280. HRESULT hr = S_OK;
  281. if (!bCreateTPF)
  282. return hr;
  283. if(pCRC)
  284. {
  285. LPWSTR signStart = wcschr(pszBufStart, L'?');
  286. // nothing to sign
  287. if (NULL == signStart)
  288. {
  289. goto Cleanup;
  290. }
  291. // if found before pszCurrent
  292. if(signStart < pszCurrent)
  293. {
  294. ++signStart;;
  295. }
  296. hr = PartnerHash(pCRC, ulCurrentKeyVersion, signStart, pszCurrent - signStart, &signature);
  297. if (hr == S_OK && signature != NULL)
  298. {
  299. pszCurrent = CopyHelperW(pszCurrent, L"&tpf=", pszBufEnd);
  300. pszCurrent = CopyHelperW(pszCurrent, signature, pszBufEnd);
  301. }
  302. if (!signature && g_pAlert)
  303. {
  304. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_URLSIGNATURE_NOTCREATED,
  305. 0, NULL);
  306. }
  307. }
  308. else if(g_pAlert)
  309. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_URLSIGNATURE_NOTCREATED,
  310. 0, NULL);
  311. Cleanup:
  312. if (signature)
  313. {
  314. SysFreeString(signature);
  315. }
  316. return hr;
  317. }
  318. //===========================================================================
  319. //
  320. // MD5 hash with partner's key
  321. //
  322. HRESULT PartnerHash(
  323. CRegistryConfig* pCRC,
  324. ULONG ulCurrentKeyVersion,
  325. LPCWSTR tobeSigned,
  326. ULONG nChars,
  327. BSTR* pbstrHash
  328. )
  329. {
  330. // MD5 hash the url and query strings + the key of the
  331. //
  332. if(!pCRC || !pbstrHash) return E_INVALIDARG;
  333. CCoCrypt* crypt = pCRC->getCrypt(ulCurrentKeyVersion, NULL);
  334. DWORD keyLen = 0;
  335. unsigned char* key = NULL;
  336. BSTR bstrHash = NULL;
  337. HRESULT hr = S_OK;
  338. BOOL bSigned = FALSE;
  339. BSTR binHexedKey = NULL;
  340. LPSTR lpToBeHashed = NULL;
  341. if (crypt && (key = crypt->getKeyMaterial(&keyLen)))
  342. {
  343. CBinHex BinHex;
  344. //encode the key
  345. hr = BinHex.ToBase64ASCII((BYTE*)key, keyLen, 0, NULL, &binHexedKey);
  346. if (hr != S_OK)
  347. {
  348. goto Cleanup;
  349. }
  350. // W2A conversion here -- we sign ascii version
  351. ULONG ulFullLen;
  352. ULONG ulKeyLen;
  353. ULONG ulWideLen = wcslen(tobeSigned);
  354. ULONG ulAnsiLen = WideCharToMultiByte(CP_ACP, 0, tobeSigned, ulWideLen, NULL, 0, NULL, NULL);
  355. if (ulAnsiLen == 0)
  356. {
  357. hr = HRESULT_FROM_WIN32(GetLastError());
  358. goto Cleanup;
  359. }
  360. ulKeyLen = strlen((LPCSTR)binHexedKey);
  361. ulFullLen = ulAnsiLen + ulKeyLen;
  362. // NOTE - the SysAllocStringByteLen allocs an additional WCHAR so we won't overflow
  363. // The MD5Hash function actually uses SysStringByteLen when doing the hashing so unless
  364. // we want to make a copy just allocate what we need
  365. lpToBeHashed = (LPSTR) ::SysAllocStringByteLen(NULL, ulFullLen * sizeof(CHAR));
  366. if (lpToBeHashed == NULL)
  367. {
  368. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  369. goto Cleanup;
  370. }
  371. WideCharToMultiByte(CP_ACP,
  372. 0,
  373. tobeSigned,
  374. ulWideLen,
  375. lpToBeHashed,
  376. ulAnsiLen,
  377. NULL,
  378. NULL);
  379. strcpy(lpToBeHashed + ulAnsiLen, (LPCSTR)binHexedKey);
  380. RtlSecureZeroMemory((PVOID)binHexedKey, ulKeyLen);
  381. {
  382. CComPtr<IMD5> md5;
  383. hr = GetGlobalCOMmd5(&md5);
  384. if (hr == S_OK)
  385. {
  386. hr = md5->MD5Hash((BSTR)lpToBeHashed, &bstrHash);
  387. RtlSecureZeroMemory(lpToBeHashed + ulAnsiLen, ulKeyLen);
  388. if( hr == S_OK && bstrHash != NULL)
  389. {
  390. *pbstrHash = bstrHash;
  391. bstrHash = NULL;
  392. bSigned = TRUE;
  393. }
  394. else
  395. {
  396. *pbstrHash = NULL;
  397. }
  398. }
  399. }
  400. }
  401. else
  402. {
  403. if (g_pAlert )
  404. {
  405. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CURRENTKEY_NOTDEFINED, 0, NULL);
  406. }
  407. }
  408. Cleanup:
  409. if (bstrHash)
  410. {
  411. SysFreeString(bstrHash);
  412. }
  413. if (lpToBeHashed)
  414. {
  415. SysFreeString((BSTR)lpToBeHashed);
  416. }
  417. if (binHexedKey)
  418. {
  419. SysFreeString(binHexedKey);
  420. }
  421. if (!bSigned && g_pAlert)
  422. {
  423. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_URLSIGNATURE_NOTCREATED, 0, NULL);
  424. }
  425. return hr;
  426. }
  427. //===========================================================================
  428. //
  429. // Construct AuthURL, returning BSTR
  430. //
  431. BSTR
  432. FormatAuthURL(
  433. LPCWSTR pszLoginServerURL,
  434. ULONG ulSiteId,
  435. LPCWSTR pszReturnURL,
  436. ULONG ulTimeWindow,
  437. BOOL bForceLogin,
  438. ULONG ulCurrentKeyVersion,
  439. time_t tCurrentTime,
  440. LPCWSTR pszCoBrand,
  441. LPCWSTR pszNameSpace,
  442. int nKPP,
  443. USHORT lang,
  444. ULONG ulSecureLevel,
  445. CRegistryConfig* pCRC,
  446. BOOL fRedirToSelf,
  447. BOOL bCreateTPF
  448. )
  449. /*
  450. The old sprintf for reference:
  451. _snwprintf(text, 2048, L"%s?id=%d&ru=%s&tw=%d&fs=%d&kv=%d&ct=%u%s%s",
  452. url, crc->getSiteId(), returnUrl, TimeWindow, ForceLogin ? 1 : 0,
  453. crc->getCurrentCryptVersion(), ct ,CBT?L"&cb=":L"", CBT?CBT:L"");
  454. */
  455. {
  456. WCHAR text[2048] = L"";
  457. if (NULL == FormatAuthURLParameters(pszLoginServerURL,
  458. ulSiteId,
  459. pszReturnURL,
  460. ulTimeWindow,
  461. bForceLogin,
  462. ulCurrentKeyVersion,
  463. tCurrentTime,
  464. pszCoBrand,
  465. pszNameSpace,
  466. nKPP,
  467. text,
  468. sizeof(text)/sizeof(WCHAR),
  469. lang,
  470. ulSecureLevel,
  471. pCRC,
  472. fRedirToSelf,
  473. bCreateTPF
  474. ))
  475. {
  476. return NULL;
  477. }
  478. return ALLOC_AND_GIVEAWAY_BSTR(text);
  479. }
  480. //===========================================================================
  481. //
  482. //
  483. // consolidate the code in FormatAuthUrl and NormalLogoTag -- with passed in buffer
  484. //
  485. PWSTR
  486. FormatAuthURLParameters(
  487. LPCWSTR pszLoginServerURL,
  488. ULONG ulSiteId,
  489. LPCWSTR pszReturnURL,
  490. ULONG ulTimeWindow,
  491. BOOL bForceLogin,
  492. ULONG ulCurrentKeyVersion,
  493. time_t tCurrentTime,
  494. LPCWSTR pszCoBrand,
  495. LPCWSTR pszNameSpace,
  496. int nKPP,
  497. PWSTR pszBufStart,
  498. ULONG cBufLen, // length of buffer in WCHAR
  499. USHORT lang,
  500. ULONG ulSecureLevel,
  501. CRegistryConfig* pCRC,
  502. BOOL fRedirectToSelf, // if true, this is URL for self redirect
  503. // otherwise the redirect is to the login server
  504. BOOL bCreateTPF
  505. )
  506. {
  507. WCHAR temp[40];
  508. LPWSTR pszCurrent = pszBufStart, pszLoginStart, pszSignURLStart = NULL;
  509. LPCWSTR pszBufEnd = pszBufStart + cBufLen - 1;
  510. HRESULT hr = S_OK;
  511. PWSTR pwszReturn = NULL;
  512. // helper BSTR ...
  513. BSTR bstrHelper = SysAllocStringLen(NULL, cBufLen);
  514. if (NULL == bstrHelper)
  515. {
  516. goto Cleanup;
  517. }
  518. if (fRedirectToSelf)
  519. {
  520. //
  521. // new authUrl is the return URL + indication a challenge - msppchlg=1 - has to be
  522. // done + the rest of the qs parameters as they are in the original
  523. // protocol
  524. //
  525. DWORD cchLen = cBufLen;
  526. if(!InternetCanonicalizeUrl(pszReturnURL,
  527. pszCurrent,
  528. &cchLen,
  529. ICU_DECODE | ICU_NO_ENCODE))
  530. {
  531. // this should not fail ...
  532. _ASSERT(FALSE);
  533. goto Cleanup;
  534. }
  535. // require at least 50 chars
  536. if (cchLen > cBufLen - 50 )
  537. {
  538. _ASSERT(FALSE);
  539. goto Cleanup;
  540. }
  541. PWSTR psz = pszCurrent;
  542. while(*psz && *psz != L'?') psz++;
  543. // see if URL already contains '?'
  544. // if so, the sequence will start with '&'
  545. if (*psz)
  546. pszCurrent[cchLen] = L'&';
  547. else
  548. pszCurrent[cchLen] = L'?';
  549. pszCurrent += cchLen + 1;
  550. // indicate challange
  551. pszCurrent = CopyHelperW(pszCurrent, PPSITE_CHALLENGE, pszBufEnd);
  552. // login server ....
  553. pszCurrent = CopyHelperW(pszCurrent, L"&", pszBufEnd);
  554. pszCurrent = CopyHelperW(pszCurrent, PPLOGIN_PARAM, pszBufEnd);
  555. //
  556. // remember the start of the login URL
  557. pszLoginStart = pszCurrent;
  558. // use the temp buffer for the rest
  559. pszCurrent = bstrHelper;
  560. pszSignURLStart = pszCurrent;
  561. pszBufEnd = pszCurrent + SysStringLen(bstrHelper) - 1;
  562. //
  563. // format loginserverUrl and qs params in a separate buffer, so
  564. // they can be escaped ...
  565. pszCurrent = CopyHelperW(pszCurrent, pszLoginServerURL, pszBufEnd);
  566. // start sequence
  567. if (wcschr(pszLoginServerURL, L'?'))
  568. {
  569. // login server already contains qs
  570. pszCurrent = CopyHelperW(pszCurrent, L"&", pszBufEnd);
  571. }
  572. else
  573. {
  574. // start qs sequence
  575. pszCurrent = CopyHelperW(pszCurrent, L"?", pszBufEnd);
  576. }
  577. pszCurrent = CopyHelperW(pszCurrent, L"id=", pszBufEnd);
  578. // common code will fill in id and the rest ....
  579. }
  580. else
  581. {
  582. // redirect directly to a login server
  583. pszSignURLStart = pszCurrent;
  584. pszCurrent = CopyHelperW(pszCurrent, pszLoginServerURL, pszBufEnd);
  585. // start sequence
  586. while(*pszLoginServerURL && *pszLoginServerURL != L'?') pszLoginServerURL++;
  587. if (*pszLoginServerURL)
  588. pszCurrent = CopyHelperW(pszCurrent, L"&id=", pszBufEnd);
  589. else
  590. pszCurrent = CopyHelperW(pszCurrent, L"?id=", pszBufEnd);
  591. }
  592. _ultow(ulSiteId, temp, 10);
  593. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  594. // keep the ru, so I don't have to reconstruct
  595. pszCurrent = CopyHelperW(pszCurrent, L"&ru=", pszBufEnd);
  596. pszCurrent = CopyHelperW(pszCurrent, pszReturnURL, pszBufEnd);
  597. pszCurrent = CopyHelperW(pszCurrent, L"&tw=", pszBufEnd);
  598. _ultow(ulTimeWindow, temp, 10);
  599. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  600. if(bForceLogin)
  601. {
  602. pszCurrent = CopyHelperW(pszCurrent, L"&fs=1", pszBufEnd);
  603. }
  604. pszCurrent = CopyHelperW(pszCurrent, L"&kv=", pszBufEnd);
  605. _ultow(ulCurrentKeyVersion, temp, 10);
  606. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  607. pszCurrent = CopyHelperW(pszCurrent, L"&ct=", pszBufEnd);
  608. _ultow(tCurrentTime, temp, 10);
  609. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  610. if(pszCoBrand)
  611. {
  612. pszCurrent = CopyHelperW(pszCurrent, L"&cb=", pszBufEnd);
  613. pszCurrent = CopyHelperW(pszCurrent, pszCoBrand, pszBufEnd);
  614. }
  615. if(pszNameSpace)
  616. {
  617. if (!_wcsicmp(pszNameSpace, L"email"))
  618. {
  619. // namespace == email -> ems=1
  620. pszCurrent = CopyHelperW(pszCurrent, L"&ems=1", pszBufEnd);
  621. }
  622. else if(*pszNameSpace)
  623. {
  624. // regular namespace logic
  625. pszCurrent = CopyHelperW(pszCurrent, L"&ns=", pszBufEnd);
  626. pszCurrent = CopyHelperW(pszCurrent, pszNameSpace, pszBufEnd);
  627. }
  628. }
  629. else
  630. {
  631. // namespace == null : default to email
  632. pszCurrent = CopyHelperW(pszCurrent, L"&ems=1", pszBufEnd);
  633. }
  634. if(nKPP != -1 && nKPP != 0)
  635. {
  636. pszCurrent = CopyHelperW(pszCurrent, L"&kpp=", pszBufEnd);
  637. _ultow(nKPP, temp, 10);
  638. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  639. }
  640. if(ulSecureLevel != 0)
  641. {
  642. pszCurrent = CopyHelperW(pszCurrent, L"&seclog=", pszBufEnd);
  643. _ultow(ulSecureLevel, temp, 10);
  644. pszCurrent = CopyHelperW(pszCurrent, temp, pszBufEnd);
  645. }
  646. pszCurrent = CopyHelperW(pszCurrent, L"&ver=", pszBufEnd);
  647. pszCurrent = CopyHelperW(pszCurrent, GetVersionString(), pszBufEnd);
  648. // MD5 hash the url and query strings + the key of the
  649. //
  650. hr = SignQueryString(pCRC, ulCurrentKeyVersion, pszSignURLStart, pszCurrent, pszBufEnd, bCreateTPF);
  651. *pszCurrent = L'\0';
  652. if (S_OK != hr)
  653. {
  654. goto Cleanup;
  655. }
  656. if (fRedirectToSelf)
  657. {
  658. // escape and put back in the original buffer.
  659. // adjust the length first
  660. cBufLen -= (ULONG) (pszLoginStart - pszBufStart);
  661. if (!PPEscapeUrl(bstrHelper,
  662. pszLoginStart,
  663. &cBufLen,
  664. cBufLen,
  665. 0))
  666. {
  667. _ASSERT(FALSE);
  668. // cut the return
  669. pszCurrent = pszLoginStart;
  670. }
  671. else
  672. {
  673. pszCurrent = pszLoginStart + cBufLen;
  674. }
  675. }
  676. pwszReturn = pszCurrent;
  677. Cleanup:
  678. if (bstrHelper)
  679. {
  680. SysFreeString(bstrHelper);
  681. }
  682. return pwszReturn;
  683. }
  684. //===========================================================================
  685. //
  686. // retrieve a query parameter from a query string
  687. //
  688. BOOL
  689. GetQueryParam(LPCSTR queryString, LPSTR param, BSTR* p)
  690. {
  691. LPSTR aLoc, aEnd;
  692. int aLen, i;
  693. // Find the first occurrence of the param in the queryString.
  694. aLoc = strstr(queryString, param);
  695. while(aLoc != NULL)
  696. {
  697. // If the string was found at the beginning of the string, or was
  698. // preceded by a '&' then we've found the correct param. Otherwise
  699. // we tail-matched some other query string param and should look again.
  700. if(aLoc == queryString ||
  701. *(aLoc - 1) == '&')
  702. {
  703. aLoc += strlen(param);
  704. aEnd = strchr(aLoc, '&');
  705. if(aEnd)
  706. aLen = aEnd - aLoc;
  707. else
  708. aLen = strlen(aLoc);
  709. BSTR aVal = ALLOC_BSTR_LEN(NULL, aLen);
  710. if (NULL == aVal)
  711. return FALSE;
  712. for (i = 0; i < aLen; i++)
  713. aVal[i] = aLoc[i];
  714. *p = aVal;
  715. GIVEAWAY_BSTR(aVal);
  716. return TRUE;
  717. }
  718. aLoc = strstr(aLoc + 1, param);
  719. }
  720. return FALSE;
  721. }
  722. //===========================================================================
  723. //
  724. // get t, p, and f from query string
  725. //
  726. BOOL
  727. GetQueryData(
  728. LPCSTR queryString,
  729. BSTR* a,
  730. BSTR* p,
  731. BSTR* f)
  732. {
  733. // This one is optional, don't error out if it isn't there.
  734. GetQueryParam(queryString, "f=", f);
  735. if(!GetQueryParam(queryString, "t=", a))
  736. return FALSE;
  737. // OK if we have ticket w/o profile.
  738. GetQueryParam(queryString, "p=", p);
  739. return TRUE;
  740. }
  741. #define ToHexDigit(x) (('0' <= x && x <= '9') ? (x - '0') : (tolower(x) - 'a' + 10))
  742. //===========================================================================
  743. //
  744. // Get a cookie from value of cookie header
  745. //
  746. BOOL
  747. GetCookie(
  748. LPCSTR pszCookieHeader,
  749. LPCSTR pszCookieName,
  750. BSTR* pbstrCookieVal
  751. )
  752. {
  753. LPSTR nLoc;
  754. LPCSTR pH = pszCookieHeader;
  755. LPSTR nEnd;
  756. int nLen, src, dst;
  757. if(pbstrCookieVal == NULL || pszCookieHeader == NULL)
  758. return FALSE;
  759. *pbstrCookieVal = NULL;
  760. _ASSERT(pszCookieName);
  761. // find begining
  762. while (nLoc = strstr(pH, pszCookieName))
  763. {
  764. nLen = strlen(pszCookieName);
  765. _ASSERT(nLen > 0);
  766. if ((nLoc == pszCookieHeader || *(nLoc - 1) == ' ' || *(nLoc - 1) == ';' || *(nLoc - 1) == ':') && *(nLoc + nLen) == '=')
  767. break;
  768. else
  769. pH = nLoc + nLen;
  770. }
  771. if (nLoc == NULL)
  772. {
  773. return FALSE;
  774. }
  775. else
  776. nLoc += nLen + 1;
  777. // find end
  778. nEnd = strchr(nLoc,';');
  779. if (nEnd)
  780. nLen = nEnd - nLoc;
  781. else
  782. nLen = strlen(nLoc);
  783. if (nLen == 0) // empty cookie
  784. return FALSE;
  785. BSTR nVal = ALLOC_BSTR_LEN(NULL, nLen);
  786. if(!nVal)
  787. return FALSE;
  788. for (src = 0, dst = 0; src < nLen;)
  789. {
  790. //handle any url encoded gunk
  791. if(nLoc[src] == '%')
  792. {
  793. nVal[dst++] = (ToHexDigit(nLoc[src+1]) << 4) + ToHexDigit(nLoc[src+2]);
  794. src+=3;
  795. }
  796. else
  797. {
  798. nVal[dst++] = nLoc[src++];
  799. }
  800. }
  801. nVal[dst] = 0;
  802. GIVEAWAY_BSTR(nVal);
  803. *pbstrCookieVal = nVal;
  804. return TRUE;
  805. }
  806. //===========================================================================
  807. //
  808. // @func Build passport cookies (MSPAuth, MSPProf, MSPConsent) -- into a buffer
  809. // If the buffer is not big enough, return EMPTY string in the buffer and
  810. // the required size (including the NULL terminator) is returned in pdwBufLen.
  811. //
  812. // Note that CopyHelperA must be used in the construction for the right buffer length.
  813. //
  814. // @rdesc Returns one of the following values
  815. // @flag TRUE | Always
  816. BOOL
  817. BuildCookieHeaders(
  818. LPCSTR pszTicket,
  819. LPCSTR pszProfile,
  820. LPCSTR pszConsent,
  821. LPCSTR pszSecure,
  822. LPCSTR pszTicketDomain,
  823. LPCSTR pszTicketPath,
  824. LPCSTR pszConsentDomain,
  825. LPCSTR pszConsentPath,
  826. LPCSTR pszSecureDomain,
  827. LPCSTR pszSecurePath,
  828. BOOL bSave,
  829. LPSTR pszBuf, //@parm buffer that will hold the output. Could be NULL.
  830. IN OUT LPDWORD pdwBufLen, //@parm size of buffer. Could be 0
  831. bool bHTTPOnly
  832. )
  833. /*
  834. Here is the old code for reference:
  835. if (domain)
  836. {
  837. *bufSize = _snprintf(pCookieHeader, *bufSize,
  838. "Set-Cookie: MSPAuth=%s; path=/; domain=%s; %s\r\n"
  839. "Set-Cookie: MSPProf=%s; path=/; domain=%s; %s\r\n",
  840. W2A(a), domain,
  841. persist ? "expires=Mon 1-Jan-2035 12:00:00 GMT;" : "",
  842. W2A(p), domain,
  843. persist ? "expires=Mon 1-Jan-2035 12:00:00 GMT;" : "");
  844. }
  845. else
  846. {
  847. *bufSize = _snprintf(pCookieHeader, *bufSize,
  848. "Set-Cookie: MSPAuth=%s; path=/; %s\r\n"
  849. "Set-Cookie: MSPProf=%s; path=/; %s\r\n",
  850. W2A(a),
  851. persist ? "expires=Mon 1-Jan-2035 12:00:00 GMT;" : "",
  852. W2A(p),
  853. persist ? "expires=Mon 1-Jan-2035 12:00:00 GMT;" : "");
  854. }
  855. */
  856. {
  857. LPSTR pszCurrent = pszBuf;
  858. LPCSTR pszBufEnd;
  859. DWORD cbBuf = 0;
  860. //
  861. // 12002: if pszBuf was NULL, then we dont care about the passed in length; the caller wants to know
  862. // the required length. In this case, set *pdwBufLen so that pszBufEnd is also NULL
  863. //
  864. if (NULL == pszBuf)
  865. *pdwBufLen = 0;
  866. pszBufEnd = pszBuf + ((*pdwBufLen > 0) ? *pdwBufLen - 1 : 0);
  867. //
  868. // 12002: cbBuf MUST be initialized before calling CopyHelperA since it accumulates the lengths
  869. //
  870. pszCurrent = CopyHelperA(pszCurrent, "Set-Cookie: MSPAuth=", pszBufEnd, cbBuf);
  871. pszCurrent = CopyHelperA(pszCurrent, pszTicket, pszBufEnd, cbBuf);
  872. if(bHTTPOnly)
  873. pszCurrent = CopyHelperA(pszCurrent, "; HTTPOnly", pszBufEnd, cbBuf);
  874. if(pszTicketPath)
  875. {
  876. pszCurrent = CopyHelperA(pszCurrent, "; path=", pszBufEnd, cbBuf);
  877. pszCurrent = CopyHelperA(pszCurrent, pszTicketPath, pszBufEnd, cbBuf);
  878. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  879. }
  880. else
  881. pszCurrent = CopyHelperA(pszCurrent, "; path=/; ", pszBufEnd, cbBuf);
  882. if(pszTicketDomain)
  883. {
  884. pszCurrent = CopyHelperA(pszCurrent, "domain=", pszBufEnd, cbBuf);
  885. pszCurrent = CopyHelperA(pszCurrent, pszTicketDomain, pszBufEnd, cbBuf);
  886. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  887. }
  888. if(bSave)
  889. {
  890. pszCurrent = CopyHelperA(pszCurrent, COOKIE_EXPIRES(EXPIRE_FUTURE), pszBufEnd, cbBuf);
  891. }
  892. pszCurrent = CopyHelperA(pszCurrent, "\r\n", pszBufEnd, cbBuf);
  893. if(pszProfile)
  894. {
  895. pszCurrent = CopyHelperA(pszCurrent, "Set-Cookie: MSPProf=", pszBufEnd, cbBuf);
  896. pszCurrent = CopyHelperA(pszCurrent, pszProfile, pszBufEnd, cbBuf);
  897. if(bHTTPOnly)
  898. pszCurrent = CopyHelperA(pszCurrent, "; HTTPOnly", pszBufEnd, cbBuf);
  899. if(pszTicketPath)
  900. {
  901. pszCurrent = CopyHelperA(pszCurrent, "; path=", pszBufEnd, cbBuf);
  902. pszCurrent = CopyHelperA(pszCurrent, pszTicketPath, pszBufEnd, cbBuf);
  903. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  904. }
  905. else
  906. pszCurrent = CopyHelperA(pszCurrent, "; path=/; ", pszBufEnd, cbBuf);
  907. if(pszTicketDomain)
  908. {
  909. pszCurrent = CopyHelperA(pszCurrent, "domain=", pszBufEnd, cbBuf);
  910. pszCurrent = CopyHelperA(pszCurrent, pszTicketDomain, pszBufEnd, cbBuf);
  911. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  912. }
  913. if(bSave)
  914. {
  915. pszCurrent = CopyHelperA(pszCurrent, COOKIE_EXPIRES(EXPIRE_FUTURE), pszBufEnd, cbBuf);
  916. }
  917. pszCurrent = CopyHelperA(pszCurrent, "\r\n", pszBufEnd, cbBuf);
  918. }
  919. if(pszSecure)
  920. {
  921. pszCurrent = CopyHelperA(pszCurrent, "Set-Cookie: MSPSecAuth=", pszBufEnd, cbBuf);
  922. pszCurrent = CopyHelperA(pszCurrent, pszSecure, pszBufEnd, cbBuf);
  923. if(bHTTPOnly)
  924. pszCurrent = CopyHelperA(pszCurrent, "; HTTPOnly", pszBufEnd, cbBuf);
  925. if(pszSecurePath)
  926. {
  927. pszCurrent = CopyHelperA(pszCurrent, "; path=", pszBufEnd, cbBuf);
  928. pszCurrent = CopyHelperA(pszCurrent, pszSecurePath, pszBufEnd, cbBuf);
  929. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  930. }
  931. else
  932. pszCurrent = CopyHelperA(pszCurrent, "; path=/; ", pszBufEnd, cbBuf);
  933. if(pszSecureDomain)
  934. {
  935. pszCurrent = CopyHelperA(pszCurrent, "domain=", pszBufEnd, cbBuf);
  936. pszCurrent = CopyHelperA(pszCurrent, pszSecureDomain, pszBufEnd, cbBuf);
  937. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  938. }
  939. pszCurrent = CopyHelperA(pszCurrent, "secure\r\n", pszBufEnd, cbBuf);
  940. }
  941. // Set MSPConsent cookie
  942. pszCurrent = CopyHelperA(pszCurrent, "Set-Cookie: MSPConsent=", pszBufEnd, cbBuf);
  943. if(pszConsent)
  944. {
  945. pszCurrent = CopyHelperA(pszCurrent, pszConsent, pszBufEnd, cbBuf);
  946. if(bHTTPOnly)
  947. pszCurrent = CopyHelperA(pszCurrent, "; HTTPOnly", pszBufEnd, cbBuf);
  948. }
  949. if(pszConsentPath)
  950. {
  951. pszCurrent = CopyHelperA(pszCurrent, "; path=", pszBufEnd, cbBuf);
  952. pszCurrent = CopyHelperA(pszCurrent, pszConsentPath, pszBufEnd, cbBuf);
  953. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  954. }
  955. else
  956. pszCurrent = CopyHelperA(pszCurrent, "; path=/; ", pszBufEnd, cbBuf);
  957. if(pszConsentDomain)
  958. {
  959. pszCurrent = CopyHelperA(pszCurrent, "domain=", pszBufEnd, cbBuf);
  960. pszCurrent = CopyHelperA(pszCurrent, pszConsentDomain, pszBufEnd, cbBuf);
  961. pszCurrent = CopyHelperA(pszCurrent, "; ", pszBufEnd, cbBuf);
  962. }
  963. if(pszConsent)
  964. {
  965. if(bSave)
  966. {
  967. pszCurrent = CopyHelperA(pszCurrent, COOKIE_EXPIRES(EXPIRE_FUTURE), pszBufEnd, cbBuf);
  968. }
  969. }
  970. else
  971. {
  972. pszCurrent = CopyHelperA(pszCurrent, COOKIE_EXPIRES(EXPIRE_PAST), pszBufEnd, cbBuf);
  973. }
  974. pszCurrent = CopyHelperA(pszCurrent, "\r\n", pszBufEnd, cbBuf);
  975. // finally put the Auth-Info header
  976. pszCurrent = CopyHelperA(pszCurrent,
  977. C_AUTH_INFO_HEADER_PASSPORT,
  978. pszBufEnd, cbBuf);
  979. if (*pdwBufLen > 0 && (NULL != pszCurrent))
  980. {
  981. *(pszCurrent++) = '\0';
  982. *pdwBufLen = pszCurrent - pszBuf;
  983. }
  984. //
  985. // The length that we report to the caller when the buffer is not big enough
  986. // includes room for the '\0'.
  987. //
  988. cbBuf++;
  989. //
  990. // 12002: return the required size of the buffer if it is not big enough.
  991. // Also clear the buffer
  992. //
  993. if (cbBuf > *pdwBufLen)
  994. {
  995. if (*pdwBufLen > 0)
  996. {
  997. *pszBuf = '\0';
  998. }
  999. *pdwBufLen = cbBuf;
  1000. }
  1001. return TRUE;
  1002. }
  1003. //===========================================================================
  1004. //
  1005. // Decrpt and set ticket andprofile
  1006. //
  1007. HRESULT
  1008. DecryptTicketAndProfile(
  1009. BSTR bstrTicket,
  1010. BSTR bstrProfile,
  1011. BOOL bCheckConsent,
  1012. BSTR bstrConsent,
  1013. CRegistryConfig* pRegistryConfig,
  1014. IPassportTicket* piTicket,
  1015. IPassportProfile* piProfile)
  1016. {
  1017. HRESULT hr;
  1018. BSTR ret = NULL;
  1019. CCoCrypt* crypt = NULL;
  1020. time_t tValidUntil;
  1021. time_t tNow = time(NULL);
  1022. int kv;
  1023. int nMemberIdHighT, nMemberIdLowT;
  1024. VARIANT vMemberIdHighP, vMemberIdLowP;
  1025. CComPtr<IPassportTicket2> spTicket2;
  1026. if (!g_config->isValid()) // Guarantees config is non-null
  1027. {
  1028. AtlReportError(CLSID_FastAuth, PP_E_NOT_CONFIGUREDSTR,
  1029. IID_IPassportFastAuth, PP_E_NOT_CONFIGURED);
  1030. hr = PP_E_NOT_CONFIGURED;
  1031. goto Cleanup;
  1032. }
  1033. // Make sure we have both ticket and profile first.
  1034. if (bstrTicket == NULL || SysStringLen(bstrTicket) == 0)
  1035. {
  1036. hr = E_INVALIDARG;
  1037. goto Cleanup;
  1038. }
  1039. // Get key version and crypt object.
  1040. kv = CCoCrypt::getKeyVersion(bstrTicket);
  1041. crypt = pRegistryConfig->getCrypt(kv, &tValidUntil);
  1042. if (crypt == NULL)
  1043. {
  1044. if (g_pAlert )
  1045. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_KEY,
  1046. 0, NULL, SysStringByteLen(bstrTicket), (LPVOID)bstrTicket);
  1047. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1048. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1049. hr = PP_E_INVALID_TICKET;
  1050. goto Cleanup;
  1051. }
  1052. // Is the key still valid?
  1053. if(tValidUntil && tValidUntil < tNow)
  1054. {
  1055. DWORD dwTimes[2] = { tValidUntil, tNow };
  1056. TCHAR *pszStrings[1];
  1057. TCHAR value[34]; // the _itot only takes upto 33 chars
  1058. pszStrings[0] = _itot(pRegistryConfig->getSiteId(), value, 10);
  1059. if(g_pAlert)
  1060. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_KEY_EXPIRED,
  1061. 1, (LPCTSTR*)pszStrings, sizeof(DWORD) << 1, (LPVOID)dwTimes);
  1062. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1063. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1064. hr = PP_E_INVALID_TICKET;
  1065. goto Cleanup;
  1066. }
  1067. // Decrypt the ticket and set it into the ticket object.
  1068. if(crypt->Decrypt(bstrTicket, SysStringByteLen(bstrTicket), &ret)==FALSE)
  1069. {
  1070. if(g_pAlert)
  1071. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_INVALID_TICKET_C,
  1072. 0, NULL, SysStringByteLen(bstrTicket), (LPVOID)bstrTicket);
  1073. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1074. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1075. hr = PP_E_INVALID_TICKET;
  1076. goto Cleanup;
  1077. }
  1078. TAKEOVER_BSTR(ret);
  1079. hr = piTicket->put_unencryptedTicket(ret);
  1080. if (S_OK != hr)
  1081. {
  1082. goto Cleanup;
  1083. }
  1084. piTicket->QueryInterface(_uuidof(IPassportTicket2), (void**)&spTicket2);
  1085. _ASSERT(spTicket2);
  1086. FREE_BSTR(ret);
  1087. ret = NULL;
  1088. // Decrypt the profile and set it into the profile object.
  1089. if(bstrProfile && SysStringLen(bstrProfile) != 0)
  1090. {
  1091. if(crypt->Decrypt(bstrProfile, SysStringByteLen(bstrProfile), &ret) == FALSE)
  1092. {
  1093. if(g_pAlert)
  1094. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_INVALID_PROFILE_C,
  1095. 0, NULL, SysStringByteLen(bstrProfile), (LPVOID)bstrProfile);
  1096. piProfile->put_unencryptedProfile(NULL);
  1097. }
  1098. else
  1099. {
  1100. TAKEOVER_BSTR(ret);
  1101. hr = piProfile->put_unencryptedProfile(ret);
  1102. if (S_OK != hr)
  1103. {
  1104. goto Cleanup;
  1105. }
  1106. //
  1107. // Member id in profile MUST match member id in ticket.
  1108. //
  1109. piTicket->get_MemberIdHigh(&nMemberIdHighT);
  1110. piTicket->get_MemberIdLow(&nMemberIdLowT);
  1111. VariantInit(&vMemberIdHighP);
  1112. VariantInit(&vMemberIdLowP);
  1113. // these could be missing for mobile case
  1114. HRESULT hr1 = piProfile->get_Attribute(L"memberidhigh", &vMemberIdHighP);
  1115. HRESULT hr2 = piProfile->get_Attribute(L"memberidlow", &vMemberIdLowP);
  1116. // these could be missing for mobile case
  1117. if(hr1 == S_OK && hr2 == S_OK &&
  1118. (nMemberIdHighT != vMemberIdHighP.lVal ||
  1119. nMemberIdLowT != vMemberIdLowP.lVal))
  1120. {
  1121. piProfile->put_unencryptedProfile(NULL);
  1122. }
  1123. }
  1124. }
  1125. else
  1126. piProfile->put_unencryptedProfile(NULL);
  1127. //
  1128. // consent stuff
  1129. if(bstrConsent)
  1130. {
  1131. FREE_BSTR(ret);
  1132. ret = NULL;
  1133. if(crypt->Decrypt(bstrConsent, SysStringByteLen(bstrConsent), &ret) == FALSE)
  1134. {
  1135. if(g_pAlert)
  1136. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_INVALID_CONSENT,
  1137. 0, NULL, SysStringByteLen(bstrProfile), (LPVOID)bstrProfile);
  1138. // we can continue
  1139. }
  1140. else
  1141. {
  1142. TAKEOVER_BSTR(ret);
  1143. spTicket2->SetTertiaryConsent(ret); // we ignore return value here
  1144. }
  1145. }
  1146. // If the caller wants us to check consent, then do it. If we don't have
  1147. // consent, then set the profile back to NULL.
  1148. if(bCheckConsent)
  1149. {
  1150. ConsentStatusEnum ConsentCode = ConsentStatus_Unknown;
  1151. VARIANT_BOOL bRequireConsentCookie = ((
  1152. lstrcmpA(pRegistryConfig->getTicketDomain(), pRegistryConfig->getProfileDomain())
  1153. || lstrcmpA(pRegistryConfig->getTicketPath(), pRegistryConfig->getProfilePath())
  1154. ) && !(pRegistryConfig->bInDA())) ? VARIANT_TRUE: VARIANT_FALSE;
  1155. spTicket2->ConsentStatus(bRequireConsentCookie, NULL, &ConsentCode);
  1156. switch(ConsentCode)
  1157. {
  1158. case ConsentStatus_Known :
  1159. case ConsentStatus_DoNotNeed :
  1160. break;
  1161. case ConsentStatus_NotDefinedInTicket : // mean 1.X ticket
  1162. {
  1163. CComVariant vFlags;
  1164. // mobile case, flags may not exist
  1165. if(S_OK == piProfile->get_Attribute(L"flags", &vFlags) &&
  1166. (V_I4(&vFlags)& k_ulFlagsConsentCookieNeeded))
  1167. {
  1168. piProfile->put_unencryptedProfile(NULL);
  1169. }
  1170. }
  1171. break;
  1172. case ConsentStatus_Unknown :
  1173. piProfile->put_unencryptedProfile(NULL);
  1174. break;
  1175. default:
  1176. _ASSERT(0); // should not be here
  1177. break;
  1178. }
  1179. }
  1180. hr = S_OK;
  1181. Cleanup:
  1182. if (ret) FREE_BSTR(ret);
  1183. if(g_pPerf)
  1184. {
  1185. switch(hr)
  1186. {
  1187. case PP_E_INVALID_TICKET:
  1188. case E_INVALIDARG:
  1189. g_pPerf->incrementCounter(PM_INVALIDREQUESTS_TOTAL);
  1190. g_pPerf->incrementCounter(PM_INVALIDREQUESTS_SEC);
  1191. break;
  1192. default:
  1193. g_pPerf->incrementCounter(PM_VALIDREQUESTS_TOTAL);
  1194. g_pPerf->incrementCounter(PM_VALIDREQUESTS_SEC);
  1195. break;
  1196. }
  1197. g_pPerf->incrementCounter(PM_REQUESTS_TOTAL);
  1198. g_pPerf->incrementCounter(PM_REQUESTS_SEC);
  1199. }
  1200. else
  1201. {
  1202. _ASSERT(g_pPerf);
  1203. }
  1204. return hr;
  1205. }
  1206. //===========================================================================
  1207. //
  1208. // check if the ticket is secure -- private function
  1209. //
  1210. HRESULT
  1211. DoSecureCheck(
  1212. BSTR bstrSecure,
  1213. CRegistryConfig* pRegistryConfig,
  1214. IPassportTicket* piTicket
  1215. )
  1216. {
  1217. HRESULT hr;
  1218. BSTR ret = NULL;
  1219. CCoCrypt* crypt = NULL;
  1220. time_t tValidUntil;
  1221. time_t tNow = time(NULL);
  1222. int kv;
  1223. if (!g_config->isValid()) // Guarantees config is non-null
  1224. {
  1225. AtlReportError(CLSID_FastAuth, PP_E_NOT_CONFIGUREDSTR,
  1226. IID_IPassportFastAuth, PP_E_NOT_CONFIGURED);
  1227. hr = PP_E_NOT_CONFIGURED;
  1228. goto Cleanup;
  1229. }
  1230. // Make sure we have both ticket and profile first.
  1231. if (bstrSecure == NULL || SysStringLen(bstrSecure) == 0)
  1232. {
  1233. hr = E_INVALIDARG;
  1234. goto Cleanup;
  1235. }
  1236. // Get key version and crypt object.
  1237. kv = CCoCrypt::getKeyVersion(bstrSecure);
  1238. crypt = pRegistryConfig->getCrypt(kv, &tValidUntil);
  1239. if (crypt == NULL)
  1240. {
  1241. if (g_pAlert)
  1242. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_KEY,
  1243. 0, NULL, sizeof(DWORD), (LPVOID)&kv);
  1244. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1245. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1246. hr = PP_E_INVALID_TICKET;
  1247. goto Cleanup;
  1248. }
  1249. // Is the key still valid?
  1250. if(tValidUntil && tValidUntil < tNow)
  1251. {
  1252. DWORD dwTimes[2] = { tValidUntil, tNow };
  1253. TCHAR *pszStrings[1];
  1254. TCHAR value[34]; // the _itot only takes upto 33 chars
  1255. pszStrings[0] = _itot(pRegistryConfig->getSiteId(), value, 10);
  1256. if(g_pAlert)
  1257. g_pAlert->report(PassportAlertInterface::WARNING_TYPE, PM_KEY_EXPIRED,
  1258. 1, (LPCTSTR*)pszStrings, sizeof(DWORD) << 1, (LPVOID)dwTimes);
  1259. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1260. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1261. hr = PP_E_INVALID_TICKET;
  1262. goto Cleanup;
  1263. }
  1264. // Decrypt the ticket and set it into the ticket object.
  1265. if(crypt->Decrypt(bstrSecure, SysStringByteLen(bstrSecure), &ret)==FALSE)
  1266. {
  1267. AtlReportError(CLSID_FastAuth, PP_E_INVALID_TICKETSTR,
  1268. IID_IPassportFastAuth, PP_E_INVALID_TICKET);
  1269. hr = PP_E_INVALID_TICKET;
  1270. goto Cleanup;
  1271. }
  1272. TAKEOVER_BSTR(ret);
  1273. piTicket->DoSecureCheck(ret);
  1274. FREE_BSTR(ret);
  1275. ret = NULL;
  1276. hr = S_OK;
  1277. Cleanup:
  1278. return hr;
  1279. }
  1280. //===========================================================================
  1281. //
  1282. // Get HTTP request info from ECB
  1283. //
  1284. LPSTR
  1285. GetServerVariableECB(
  1286. EXTENSION_CONTROL_BLOCK* pECB,
  1287. LPSTR pszHeader
  1288. )
  1289. {
  1290. DWORD dwSize = 0;
  1291. LPSTR lpBuf;
  1292. pECB->GetServerVariable(pECB->ConnID, pszHeader, NULL, &dwSize);
  1293. if(GetLastError() != ERROR_INSUFFICIENT_BUFFER || dwSize == 0)
  1294. {
  1295. lpBuf = NULL;
  1296. goto Cleanup;
  1297. }
  1298. lpBuf = new CHAR[dwSize];
  1299. if(!lpBuf)
  1300. goto Cleanup;
  1301. if(!pECB->GetServerVariable(pECB->ConnID, pszHeader, lpBuf, &dwSize))
  1302. {
  1303. delete [] lpBuf;
  1304. lpBuf = NULL;
  1305. }
  1306. Cleanup:
  1307. return lpBuf;
  1308. }
  1309. //===========================================================================
  1310. //
  1311. // Get HTTP request info from Filter context
  1312. //
  1313. LPSTR
  1314. GetServerVariablePFC(
  1315. PHTTP_FILTER_CONTEXT pPFC,
  1316. LPSTR pszHeader
  1317. )
  1318. {
  1319. DWORD dwSize;
  1320. LPSTR lpBuf;
  1321. CHAR cDummy;
  1322. dwSize = 1;
  1323. pPFC->GetServerVariable(pPFC, pszHeader, &cDummy, &dwSize);
  1324. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || dwSize == 0)
  1325. {
  1326. lpBuf = NULL;
  1327. goto Cleanup;
  1328. }
  1329. lpBuf = new CHAR[dwSize];
  1330. if(!lpBuf)
  1331. goto Cleanup;
  1332. if(!pPFC->GetServerVariable(pPFC, pszHeader, lpBuf, &dwSize))
  1333. {
  1334. delete [] lpBuf;
  1335. lpBuf = NULL;
  1336. }
  1337. Cleanup:
  1338. return lpBuf;
  1339. }
  1340. LONG
  1341. HexToNum(
  1342. WCHAR c
  1343. )
  1344. {
  1345. return ((c >= L'0' && c <= L'9') ? (c - L'0') : ((c >= 'A' && c <= 'F') ? (c - L'A' + 10) : -1));
  1346. }
  1347. LONG
  1348. FromHex(
  1349. LPCWSTR pszHexString
  1350. )
  1351. {
  1352. LONG lResult = 0;
  1353. LONG lCurrent;
  1354. LPWSTR pszCurrent;
  1355. for(pszCurrent = const_cast<LPWSTR>(pszHexString); *pszCurrent; pszCurrent++)
  1356. {
  1357. if((lCurrent = HexToNum(towupper(*pszCurrent))) == -1)
  1358. break; // illegal character, we're done
  1359. lResult = (lResult << 4) + lCurrent;
  1360. }
  1361. return lResult;
  1362. }
  1363. inline BOOL PPIsUnsafeUrlChar(TCHAR chIn) throw();
  1364. //===========================================================================
  1365. //
  1366. // PPEscapeUrl
  1367. //
  1368. BOOL PPEscapeUrl(LPCTSTR lpszStringIn,
  1369. LPTSTR lpszStringOut,
  1370. DWORD* pdwStrLen,
  1371. DWORD dwMaxLength,
  1372. DWORD dwFlags)
  1373. {
  1374. TCHAR ch;
  1375. DWORD dwLen = 0;
  1376. BOOL bRet = TRUE;
  1377. BOOL bSchemeFile = FALSE;
  1378. DWORD dwColonPos = 0;
  1379. DWORD dwFlagsInternal = dwFlags;
  1380. while((ch = *lpszStringIn++) != '\0')
  1381. {
  1382. //if we are at the maximum length, set bRet to FALSE
  1383. //this ensures no more data is written to lpszStringOut, but
  1384. //the length of the string is still updated, so the user
  1385. //knows how much space to allocate
  1386. if (dwLen == dwMaxLength)
  1387. {
  1388. bRet = FALSE;
  1389. }
  1390. //if we are encoding and it is an unsafe character
  1391. if (PPIsUnsafeUrlChar(ch))
  1392. {
  1393. {
  1394. //if there is not enough space for the escape sequence
  1395. if (dwLen >= (dwMaxLength-3))
  1396. {
  1397. bRet = FALSE;
  1398. }
  1399. if (bRet)
  1400. {
  1401. //output the percent, followed by the hex value of the character
  1402. *lpszStringOut++ = '%';
  1403. _stprintf(lpszStringOut, _T("%.2X"), (unsigned char)(ch));
  1404. lpszStringOut+= 2;
  1405. }
  1406. dwLen += 2;
  1407. }
  1408. }
  1409. else //safe character
  1410. {
  1411. if (bRet)
  1412. *lpszStringOut++ = ch;
  1413. }
  1414. dwLen++;
  1415. }
  1416. if (bRet)
  1417. *lpszStringOut = L'\0';
  1418. *pdwStrLen = dwLen;
  1419. return bRet;
  1420. }
  1421. //Determine if the character is unsafe under the URI RFC document
  1422. inline BOOL PPIsUnsafeUrlChar(TCHAR chIn) throw()
  1423. {
  1424. unsigned char ch = (unsigned char)chIn;
  1425. switch(ch)
  1426. {
  1427. case ';': case '\\': case '?': case '@': case '&':
  1428. case '=': case '+': case '$': case ',': case ' ':
  1429. case '<': case '>': case '#': case '%': case '\"':
  1430. case '{': case '}': case '|':
  1431. case '^': case '[': case ']': case '`':
  1432. return TRUE;
  1433. default:
  1434. {
  1435. if (ch < 32 || ch > 126)
  1436. return TRUE;
  1437. return FALSE;
  1438. }
  1439. }
  1440. }
  1441. //===========================================================================
  1442. //
  1443. // Get RAW headers in a parse -- a more efficient way of getting multiple headers back
  1444. // return value:
  1445. // -1: indicate failuer
  1446. // 0: or positive -- # of headers found
  1447. // input: headers, names, namescount
  1448. // output: values -- value of the corresponding header, dwSizes -- size of the value;
  1449. //
  1450. int GetRawHeaders(LPCSTR headers, LPCSTR* names, LPCSTR* values, DWORD* dwSizes, DWORD namescount)
  1451. {
  1452. if (!headers || !names || !values || !dwSizes) return -1;
  1453. if (IsBadReadPtr(names, namescount * sizeof(LPCSTR))
  1454. || IsBadWritePtr(values, namescount * sizeof(LPCSTR*))
  1455. || IsBadWritePtr(dwSizes, namescount * sizeof(DWORD*))
  1456. ) return -1;
  1457. int c = 0;
  1458. int i = 0;
  1459. // init output params
  1460. // loop through headers
  1461. LPCSTR header = headers;
  1462. LPCSTR T;
  1463. DWORD l;
  1464. ZeroMemory(values, sizeof(LPCSTR*) * namescount);
  1465. ZeroMemory(dwSizes, sizeof(DWORD*) * namescount);
  1466. do
  1467. {
  1468. // white spaces
  1469. while(*header == ' ') ++header;
  1470. // find if the header is intersted
  1471. T = strchr(header, ':');
  1472. i = namescount;
  1473. if(T && T != header)
  1474. {
  1475. l = T - header; // size of the header name string
  1476. TempSubStr ss(header, l);
  1477. ++T;
  1478. while( --i >= 0)
  1479. {
  1480. if(strcmp(*(names + i), header) == 0)
  1481. {
  1482. // white spaces
  1483. while(*T == ' ') ++T;
  1484. *(values + i) = T;
  1485. ++c;
  1486. break;
  1487. }
  1488. }
  1489. // move forward
  1490. header = T;
  1491. }
  1492. // not found
  1493. while(*header != 0 && !(*header == 0xd && *(header + 1)==0xa)) ++header;
  1494. // fillin the size of the header value
  1495. if (i >= 0 && i < (int)namescount)
  1496. *(dwSizes + i) = header - T;
  1497. // move to next header
  1498. if(*header == 0) header = 0;
  1499. else
  1500. header += 2; // skip 0x0D0A
  1501. } while(header);
  1502. return c;
  1503. }
  1504. //===========================================================================
  1505. //
  1506. // get QueryString from HTTP request_line
  1507. //
  1508. LPCSTR GetRawQueryString(LPCSTR request_line, DWORD* dwSize)
  1509. {
  1510. if (!request_line) return NULL;
  1511. LPCSTR URI = strchr(request_line, ' ');
  1512. if (!URI) return NULL;
  1513. LPCSTR QS = strchr(URI + 1, '?');
  1514. if (!QS) return NULL;
  1515. ++QS;
  1516. // make sure if not part of someother header
  1517. LPCSTR end = strchr(QS,' ');
  1518. DWORD size = 0;
  1519. if (!end)
  1520. size = strlen(QS);
  1521. else
  1522. size = end - QS;
  1523. if (size == 0)
  1524. return NULL;
  1525. if (dwSize)
  1526. *dwSize = size;
  1527. return QS;
  1528. }