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.

2272 lines
64 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. splugin.cxx
  5. Abstract:
  6. This file contains the implementation for Plug In Authentication
  7. The following functions are exported by this module:
  8. AuthOnRequest
  9. AuthOnResponse
  10. AuthCtxClose
  11. AuthInDialog
  12. AuthNotify
  13. AuthUnload
  14. Author:
  15. Arthur Bierer (arthurbi) 25-Dec-1995
  16. Revision History:
  17. Rajeev Dujari (rajeevd) 01-Oct-1996 overhauled
  18. Adriaan Canter (adriaanc) 01-03-1998 :
  19. AUTHCTX now a virtual base class, from which derived classes
  20. inherit to implement the different authentication protocols:
  21. BASIC_CTX (Basic auth),
  22. PLUG_CTX (NTLM, Negotiate)
  23. DIGEST_CTX (Digest auth, new)
  24. --*/
  25. #include <wininetp.h>
  26. #include <splugin.hxx>
  27. #include "auth.h"
  28. #include "sspspm.h"
  29. //
  30. // constants
  31. //
  32. #define WILDCARD 0x05 // don't use '*' since it can appear in an URL
  33. #define AssertHaveLock() INET_ASSERT(g_dwOwnerId == GetCurrentThreadId())
  34. #define MAX_AUTH_HDR_SIZE (MAX_BLOB_SIZE + HTTP_PROXY_AUTHORIZATION_LEN + 2)
  35. //
  36. // globals
  37. //
  38. // Global authentication providers list and state.
  39. AUTHCTX::SPMState AUTHCTX::g_eState;
  40. AUTHCTX::SPMData *AUTHCTX::g_pSPMList = NULL;
  41. // Global auth crit sect.
  42. CCritSec g_crstAuth;
  43. #ifdef DBG
  44. DWORD g_dwOwnerId = 0;
  45. LONG g_nLockCount = 0;
  46. #endif
  47. //
  48. // private prototypes
  49. //
  50. //-----------------------------------------------------------------------------
  51. //
  52. // AUTH_CREDS class definition.
  53. //
  54. //
  55. PRIVATE AUTH_CREDS *Creds_Create
  56. (
  57. LPSTR lpszHost,
  58. LPSTR lpszRealm,
  59. AUTHCTX::SPMData* pSPM
  60. );
  61. void Creds_Free (AUTH_CREDS *Creds);
  62. //-----------------------------------------------------------------------------
  63. //
  64. // Utilities
  65. //
  66. //
  67. PRIVATE VOID SspiFlush (LPSTR pszDll);
  68. PRIVATE BOOL TemplateMatch(LPSTR lpszTemplate, LPSTR lpszFilename);
  69. PRIVATE LPSTR MakeTemplate (LPSTR docname);
  70. PRIVATE LPSTR GetProxyName (HTTP_REQUEST_HANDLE_OBJECT *pRequest);
  71. PRIVATE BOOL ReadRegKey(
  72. BYTE * pbRegValue,
  73. DWORD * pdwNumBytes,
  74. LPSTR pszRegKey,
  75. LPSTR pszRegValueName,
  76. DWORD dwRegTypeExpected);
  77. //-----------------------------------------------------------------------------
  78. //
  79. //
  80. // AUTH_CREDS functions
  81. //
  82. // Creds_CREATE
  83. // Creds_FREE
  84. // SetUser
  85. // SetPass
  86. // FlushCredsList
  87. //
  88. PRIVATE AUTH_CREDS *Creds_Create // AUTH_CREDS constructor
  89. (
  90. LPSTR lpszHost, // Host Name to place in structure.
  91. LPSTR lpszRealm, // Realm string to add.
  92. AUTHCTX::SPMData * pSPM
  93. )
  94. {
  95. AUTH_CREDS* Creds = (AUTH_CREDS *) ALLOCATE_ZERO_MEMORY(sizeof(*Creds));
  96. if (!Creds)
  97. return NULL;
  98. INET_ASSERT (!Creds->lpszHost);
  99. Creds->lpszHost = lpszHost ? NewString(lpszHost) : NULL;
  100. INET_ASSERT (!Creds->lpszRealm);
  101. Creds->lpszRealm = lpszRealm ? NewString(lpszRealm) : NULL;
  102. Creds->pSPM = pSPM;
  103. if ( (!Creds->lpszHost && lpszHost)
  104. || (!Creds->lpszRealm && lpszRealm)
  105. )
  106. {
  107. Creds_Free(Creds);
  108. return NULL;
  109. }
  110. return Creds;
  111. }
  112. PRIVATE VOID Creds_Free(AUTH_CREDS *Creds) // AUTH_CREDS destructor
  113. {
  114. if ( Creds )
  115. {
  116. if (Creds->lpszHost)
  117. FREE_MEMORY(Creds->lpszHost);
  118. if ( Creds->lpszUser )
  119. FREE_MEMORY(Creds->lpszUser);
  120. if ( Creds->lpszPass )
  121. FREE_MEMORY(Creds->lpszPass);
  122. if ( Creds->lpszRealm )
  123. FREE_MEMORY(Creds->lpszRealm);
  124. FREE_MEMORY(Creds);
  125. }
  126. }
  127. PUBLIC DWORD AUTH_CREDS::SetUser (LPSTR lpszInput)
  128. {
  129. //AssertHaveLock();
  130. if (!lpszInput)
  131. {
  132. if (lpszUser)
  133. FREE_MEMORY (lpszUser);
  134. lpszUser = NULL;
  135. return ERROR_SUCCESS;
  136. }
  137. if (lpszUser && !lstrcmp (lpszUser, lpszInput))
  138. return ERROR_SUCCESS; // didn't change
  139. LPSTR lpszTemp = NewString(lpszInput);
  140. if (!lpszTemp)
  141. return ERROR_NOT_ENOUGH_MEMORY;
  142. if (lpszUser)
  143. FREE_MEMORY (lpszUser);
  144. lpszUser = lpszTemp;
  145. return ERROR_SUCCESS;
  146. }
  147. PUBLIC DWORD AUTH_CREDS::SetPass (LPSTR lpszInput)
  148. {
  149. //AssertHaveLock();
  150. if (!lpszInput)
  151. {
  152. if (lpszPass)
  153. FREE_MEMORY (lpszPass);
  154. lpszPass = NULL;
  155. return ERROR_SUCCESS;
  156. }
  157. if (lpszPass && !lstrcmp (lpszPass, lpszInput))
  158. return ERROR_SUCCESS; // didn't change
  159. LPSTR lpszTemp = NewString(lpszInput);
  160. if (!lpszTemp)
  161. return ERROR_NOT_ENOUGH_MEMORY;
  162. if (lpszPass)
  163. FREE_MEMORY (lpszPass);
  164. lpszPass = lpszTemp;
  165. return ERROR_SUCCESS;
  166. }
  167. /*++
  168. Delete some entries from a singly linked list.
  169. --*/
  170. /*
  171. PRIVATE void FlushCredsList (AUTH_CREDS **ppList)
  172. {
  173. AssertHaveLock();
  174. AUTH_CREDS *Creds = *ppList;
  175. while (Creds)
  176. {
  177. AUTH_CREDS *CredsNext = Creds->pNext;
  178. if (!Creds->nLockCount)
  179. Creds_Free (Creds);
  180. else
  181. {
  182. *ppList = Creds;
  183. ppList = &(Creds->pNext);
  184. }
  185. Creds = CredsNext;
  186. }
  187. *ppList = NULL;
  188. }
  189. */
  190. //-----------------------------------------------------------------------------
  191. //
  192. //
  193. // Auth* functions
  194. //
  195. // AuthOpen
  196. // AuthClose
  197. // AuthLock
  198. // AuthUnlock
  199. // AuthInDialog
  200. // AuthNotify
  201. // AuthFlush
  202. //
  203. //
  204. BOOL AuthOpen (void)
  205. {
  206. INET_ASSERT (!g_dwOwnerId && !g_nLockCount);
  207. return g_crstAuth.Init();
  208. }
  209. void AuthClose (void)
  210. {
  211. g_crstAuth.FreeLock();
  212. INET_ASSERT (!g_dwOwnerId && !g_nLockCount);
  213. }
  214. BOOL AuthLock (void)
  215. {
  216. INET_ASSERT(g_crstAuth.IsInitialized() == TRUE);
  217. if (!g_crstAuth.Lock())
  218. {
  219. INET_ASSERT(FALSE);
  220. return FALSE;
  221. }
  222. DEBUG_ONLY (if (!g_nLockCount++) g_dwOwnerId = GetCurrentThreadId();)
  223. return TRUE;
  224. }
  225. void AuthUnlock (void)
  226. {
  227. INET_ASSERT(g_crstAuth.IsInitialized() == TRUE);
  228. INET_ASSERT (g_nLockCount > 0);
  229. DEBUG_ONLY (if (!--g_nLockCount) g_dwOwnerId = 0;)
  230. g_crstAuth.Unlock();
  231. }
  232. /*++
  233. Flush any server and proxy password cache entries not in use.
  234. --*/
  235. PUBLIC void AuthFlush (void)
  236. {
  237. // Serialize access to globals.
  238. if (AuthLock())
  239. {
  240. if (!g_cSspiContexts)
  241. AUTHCTX::UnloadAll();
  242. DIGEST_CTX::FlushCreds();
  243. AuthUnlock();
  244. }
  245. }
  246. PUBLIC void AuthUnload (void)
  247. /*++
  248. Routine Description:
  249. Frees all Cached URLs, and unloads any loaded DLL authentication modeles.
  250. --*/
  251. {
  252. if (g_crstAuth.IsInitialized())
  253. {
  254. AuthFlush();
  255. if (AuthLock())
  256. {
  257. AUTHCTX::UnloadAll();
  258. AuthUnlock();
  259. }
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. //
  264. //
  265. // Utility Functions:
  266. //
  267. // SspiFlush
  268. // TemplateMatch
  269. // MakeTemplate
  270. // GetProxyName
  271. // ReadRegKey
  272. // TrimQuotes
  273. // TrimWhiteSpace
  274. // GetDelimitedToken
  275. // GetKeyValuePair
  276. //
  277. //
  278. typedef BOOL (WINAPI * SSPI_FLUSH) (VOID) ;
  279. void SspiFlush (LPSTR pszDll)
  280. {
  281. __try
  282. {
  283. HINSTANCE hinst = GetModuleHandle (pszDll);
  284. if (hinst)
  285. {
  286. SSPI_FLUSH pfnFlush = (SSPI_FLUSH)
  287. GetProcAddress (hinst, "CleanupCredentialCache");
  288. if (pfnFlush)
  289. {
  290. (*pfnFlush) ();
  291. }
  292. }
  293. }
  294. __except (EXCEPTION_EXECUTE_HANDLER)
  295. {
  296. INET_ASSERT (FALSE);
  297. }
  298. ENDEXCEPT
  299. }
  300. PRIVATE BOOL TemplateMatch(LPSTR lpszTemplate, LPSTR lpszFilename)
  301. /*++
  302. Routine Description:
  303. Attempts to match a template URL string with a URL ( FileName )
  304. Arguments:
  305. lpszTemplate - Template to match against.
  306. lpszFilename - URL to match with the template
  307. Return Value:
  308. BOOL
  309. Success - TRUE - match
  310. Failure - FALSE - no match
  311. Comments:
  312. Note: This Legacy code from the SpyGlass IE 1.0 browser
  313. --*/
  314. {
  315. /* code for this routine cloned from HTAA_templateMatch() */
  316. CHAR *p = lpszTemplate;
  317. CHAR *q = lpszFilename;
  318. int m;
  319. if (!lpszTemplate || !lpszFilename)
  320. return 0;
  321. for (; *p && *q && *p == *q; p++, q++) /* Find first mismatch */
  322. ; /* do nothing else */
  323. if (!*p && !*q)
  324. return 1; /* Equally long equal strings */
  325. else if (WILDCARD == *p)
  326. { /* Wildcard */
  327. p++; /* Skip wildcard character */
  328. m = strlen(q) - strlen(p); /* Amount to match to wildcard */
  329. if (m < 0)
  330. return 0; /* No match, filename too short */
  331. else
  332. { /* Skip the matched characters and compare */
  333. if (lstrcmp(p, q + m))
  334. return 0; /* Tail mismatch */
  335. else
  336. return 1; /* Tail match */
  337. }
  338. } /* if wildcard */
  339. else
  340. return 0; /* Length or character mismatch */
  341. }
  342. PRIVATE LPSTR MakeTemplate (LPSTR docname)
  343. /*++
  344. Routine Description:
  345. Makes a Template String (from a URL) that can later be used to match a range of URLs.
  346. Arguments:
  347. ppszTemplate - pointer to pointer of where Template can be stored
  348. docname - URL to create a template with.
  349. Return Value: BOOL
  350. Success - TRUE - created
  351. Failure - FALSE - error
  352. Comments:
  353. Note: This Legacy code from the SpyGlass IE 1.0 browser
  354. --*/
  355. {
  356. CHAR *pszTemplate = NULL;
  357. unsigned long k;
  358. k = 0;
  359. if (docname)
  360. {
  361. CHAR *slash;
  362. CHAR *first_slash;
  363. //
  364. // Ignore everything after first reserved character.
  365. //
  366. BYTE chSave = 0;
  367. LPSTR lpszScan = docname;
  368. while (*lpszScan)
  369. {
  370. if (*lpszScan == '?' || *lpszScan == ';')
  371. {
  372. chSave = *lpszScan;
  373. *lpszScan = 0;
  374. break;
  375. }
  376. lpszScan++;
  377. }
  378. slash = strrchr(docname, '/');
  379. //
  380. // If there is a "//" and no other slashes,
  381. // then make sure not to chop the hostname off
  382. // the URL. ex: http://www.netscape.com
  383. // should be //www.netscape.com* not //*
  384. //
  385. if (slash)
  386. {
  387. first_slash = strchr(docname, '/' );
  388. if ((first_slash+1) == slash)
  389. k = lstrlen(docname);
  390. else
  391. k = (unsigned long)(slash-docname)+1;
  392. }
  393. // Restore any reserved character (or rewrite terminating null)
  394. *lpszScan = chSave;
  395. }
  396. pszTemplate = (CHAR *) ALLOCATE_FIXED_MEMORY(k+2);
  397. if (!pszTemplate)
  398. return 0;
  399. memcpy(pszTemplate, docname, k);
  400. pszTemplate[k]= WILDCARD;
  401. pszTemplate[k+1]=0;
  402. DEBUG_PRINT(HTTP, INFO, ("MakeTemplate: made template [%s] from [%s]\n",
  403. pszTemplate, docname ));
  404. return pszTemplate;
  405. }
  406. LPSTR GetProxyName (HTTP_REQUEST_HANDLE_OBJECT *pRequest)
  407. {
  408. // Get the proxy name.
  409. LPSTR lpszProxy;
  410. DWORD cbProxy;
  411. INTERNET_PORT port;
  412. pRequest->GetProxyName(
  413. &lpszProxy,
  414. &cbProxy,
  415. &port);
  416. return lpszProxy;
  417. }
  418. //++------------------------------------------------------------------------
  419. //
  420. // Function: ReadRegKey
  421. //
  422. // Synopsis: This function reads a registry key.
  423. //
  424. // Arguments:
  425. //
  426. // Returns: TRUE no error
  427. // FALSE a fatal error happened
  428. //
  429. // History: AshishS Created 5/22/96
  430. //------------------------------------------------------------------------
  431. BOOL ReadRegKey(
  432. BYTE * pbRegValue, // The value of the reg key will be
  433. // stored here
  434. DWORD * pdwNumBytes, // Pointer to DWORD conataining
  435. // the number of bytes in the above buffer - will be
  436. // set to actual bytes stored.
  437. LPSTR pszRegKey, // Reg Key to be opened
  438. LPSTR pszRegValueName, // Reg Value to query
  439. DWORD dwRegTypeExpected) // Expected type of Value
  440. {
  441. HKEY hRegKey;
  442. DWORD dwRegType;
  443. LONG lResult;
  444. //read registry to find out name of the file
  445. if ( (lResult = REGOPENKEYEX(HKEY_LOCAL_MACHINE,
  446. pszRegKey, // address of subkey name
  447. 0, // reserved
  448. KEY_READ, // samDesired
  449. &hRegKey
  450. // address of handle of open key
  451. )) != ERROR_SUCCESS )
  452. {
  453. goto cleanup;
  454. }
  455. if ( (lResult =RegQueryValueEx( hRegKey,
  456. pszRegValueName,
  457. 0, // reserved
  458. &dwRegType,// address of buffer
  459. // for value type
  460. pbRegValue,
  461. pdwNumBytes)) != ERROR_SUCCESS )
  462. {
  463. REGCLOSEKEY(hRegKey);
  464. goto cleanup;
  465. }
  466. REGCLOSEKEY(hRegKey);
  467. if ( dwRegType != dwRegTypeExpected )
  468. {
  469. goto cleanup;
  470. }
  471. return TRUE;
  472. cleanup:
  473. return FALSE;
  474. }
  475. /*-----------------------------------------------------------------------------
  476. Inplace trim of one leading and one trailing quote.
  477. -----------------------------------------------------------------------------*/
  478. VOID TrimQuotes(LPSTR *psz, LPDWORD pcb)
  479. {
  480. if (*pcb && (**psz == '"'))
  481. {
  482. (*psz)++;
  483. (*pcb)--;
  484. }
  485. if (*pcb && (*(*psz + *pcb - 1) == '"'))
  486. (*pcb)--;
  487. }
  488. /*-----------------------------------------------------------------------------
  489. Inplace trim of leading and trailing whitespace.
  490. -----------------------------------------------------------------------------*/
  491. VOID TrimWhiteSpace(LPSTR *psz, LPDWORD pcb)
  492. {
  493. DWORD cb = *pcb;
  494. CHAR* beg = *psz;
  495. CHAR* end = beg + cb - 1;
  496. while ((cb != 0) && ((*beg == ' ') || (*beg == '\t')))
  497. {
  498. beg++;
  499. cb--;
  500. }
  501. while ((cb != 0) && ((*end == ' ') || (*end == '\t')))
  502. {
  503. end--;
  504. cb--;
  505. }
  506. *psz = beg;
  507. *pcb = cb;
  508. }
  509. /*-----------------------------------------------------------------------------
  510. Inplace strtok based on one delimiter. Ignores delimiter scoped by quotes.
  511. -----------------------------------------------------------------------------*/
  512. BOOL GetDelimitedToken(LPSTR* pszBuf, LPDWORD pcbBuf,
  513. LPSTR* pszTok, LPDWORD pcbTok,
  514. CHAR cDelim)
  515. {
  516. CHAR *pEnd;
  517. BOOL fQuote = FALSE,
  518. fRet = FALSE;
  519. *pcbTok = 0;
  520. *pszTok = *pszBuf;
  521. pEnd = *pszBuf + *pcbBuf - 1;
  522. while (*pcbBuf)
  523. {
  524. if ( ((**pszBuf == cDelim) && !fQuote)
  525. || (*pszBuf == pEnd)
  526. || (**pszBuf =='\r')
  527. || (**pszBuf =='\n'))
  528. {
  529. fRet = TRUE;
  530. break;
  531. }
  532. if (**pszBuf == '"')
  533. fQuote = !fQuote;
  534. (*pszBuf)++;
  535. (*pcbBuf)--;
  536. }
  537. if (fRet)
  538. {
  539. *pcbBuf = (DWORD) (pEnd - *pszBuf);
  540. if (**pszBuf == cDelim)
  541. {
  542. *pcbTok = (DWORD)(*pszBuf - *pszTok);
  543. (*pszBuf)++;
  544. }
  545. else
  546. *pcbTok = (DWORD) (*pszBuf - *pszTok) + 1;
  547. }
  548. return fRet;
  549. }
  550. /*-----------------------------------------------------------------------------
  551. Inplace retrieval of key and value from a buffer of form key = <">value<">
  552. -----------------------------------------------------------------------------*/
  553. BOOL GetKeyValuePair(LPSTR szB, DWORD cbB,
  554. LPSTR* pszK, LPDWORD pcbK,
  555. LPSTR* pszV, LPDWORD pcbV)
  556. {
  557. if (GetDelimitedToken(&szB, &cbB, pszK, pcbK, '='))
  558. {
  559. TrimWhiteSpace(pszK, pcbK);
  560. if (cbB)
  561. {
  562. *pszV = szB;
  563. *pcbV = cbB;
  564. TrimWhiteSpace(pszV, pcbV);
  565. }
  566. else
  567. {
  568. *pszV = NULL;
  569. *pcbV = 0;
  570. }
  571. return TRUE;
  572. }
  573. else
  574. {
  575. *pszK = *pszV = NULL;
  576. *pcbK = *pcbV = 0;
  577. }
  578. return FALSE;
  579. }
  580. //-----------------------------------------------------------------------------
  581. //
  582. //
  583. // Main authentication functions:
  584. //
  585. // AddAuthorizationHeader
  586. // AuthOnRequest
  587. // ProcessResponseHeader
  588. // AuthOnRequest
  589. //
  590. //
  591. /*-----------------------------------------------------------------------------
  592. -----------------------------------------------------------------------------*/
  593. PRIVATE void AddAuthorizationHeader
  594. (
  595. HTTP_REQUEST_HANDLE_OBJECT *pRequest,
  596. AUTHCTX* pAuthCtx
  597. )
  598. {
  599. if (!pAuthCtx)
  600. return;
  601. INET_ASSERT(pAuthCtx->_pSPMData);
  602. // AssertHaveLock();
  603. // Call the auth package.
  604. // CHAR *szHeader;
  605. // DWORD dwFastHeaderSize = MAX_BLOB_SIZE + HTTP_PROXY_AUTHORIZATION_LEN + 2;
  606. // CHAR* pszFastHeader = NULL;
  607. CHAR *szSlowHeader = NULL;
  608. // ULONG cbHeader;
  609. LPSTR pBuf;
  610. DWORD cbBuf;
  611. DWORD dwPlugInError;
  612. // CHAR *pszHeader;
  613. /*
  614. pszFastHeader = (CHAR*)ALLOCATE_FIXED_MEMORY(dwFastHeaderSize);
  615. if (!pszFastHeader)
  616. {
  617. // Don't worry about reporting an error.
  618. // Since this is a low mem condition, the only failure resulting
  619. // from this is that the header won't be added, and this won't
  620. // directly cause any more harm than unexpectedly failing to
  621. // authenticate, which isn't bad, given the low mem state.
  622. return;
  623. }
  624. */
  625. INT PackageId;
  626. ULONG cbMaxToken;
  627. //
  628. // GetPkgMaxToken() will return 10000 if invalid pkg.
  629. //
  630. if( (pAuthCtx->_pSPMData) &&
  631. (pAuthCtx->_pSPMData->szScheme) &&
  632. ((PackageId = GetPkgId( pAuthCtx->_pSPMData->szScheme )) != -1)
  633. )
  634. {
  635. cbMaxToken = GetPkgMaxToken( PackageId );
  636. } else {
  637. cbMaxToken = MAX_AUTH_MSG_SIZE;
  638. }
  639. //
  640. // add space for base64 overhead (33%, but round up)
  641. //
  642. cbMaxToken += (cbMaxToken/2);
  643. // Prefix with the appropriate header.
  644. /*
  645. if( cbMaxToken < dwFastHeaderSize )
  646. {
  647. cbHeader = dwFastHeaderSize;
  648. szHeader = pszFastHeader;
  649. } else {
  650. cbHeader = cbMaxToken;
  651. */
  652. szSlowHeader = (CHAR*)ALLOCATE_FIXED_MEMORY(cbMaxToken);
  653. if( szSlowHeader == NULL )
  654. {
  655. //
  656. // no clean way to report an error here. just try with the stack
  657. // buffer.
  658. //
  659. /*
  660. cbHeader = dwFastHeaderSize;
  661. szHeader = pszFastHeader;
  662. } else {
  663. szHeader = szSlowHeader; */
  664. return;
  665. }
  666. //}
  667. if (pAuthCtx->_fIsProxy)
  668. {
  669. memcpy (szSlowHeader, HTTP_PROXY_AUTHORIZATION_SZ, HTTP_PROXY_AUTHORIZATION_LEN);
  670. pBuf = szSlowHeader + HTTP_PROXY_AUTHORIZATION_LEN;
  671. // Don't reuse this keep-alive socket after a password cache flush.
  672. pRequest->SetAuthorized();
  673. }
  674. else
  675. {
  676. memcpy (szSlowHeader, HTTP_AUTHORIZATION_SZ, HTTP_AUTHORIZATION_LEN);
  677. pBuf = szSlowHeader + HTTP_AUTHORIZATION_LEN;
  678. // Don't reuse a keep-alive socket after a password cache flush.
  679. if (!pRequest->IsViaProxy())
  680. pRequest->SetAuthorized();
  681. }
  682. *pBuf++ = ' ';
  683. cbBuf = cbMaxToken - HTTP_PROXY_AUTHORIZATION_LEN - 2;
  684. INET_ASSERT (HTTP_PROXY_AUTHORIZATION_LEN >= HTTP_AUTHORIZATION_LEN);
  685. dwPlugInError =
  686. pAuthCtx->PreAuthUser(pBuf, &cbBuf);
  687. // If the plug in did not fail, add its header to the outgoing header list
  688. if (dwPlugInError == ERROR_SUCCESS && pAuthCtx->GetState() != AUTHCTX::STATE_ERROR)
  689. {
  690. // Append CR-LF.
  691. pBuf += cbBuf;
  692. *pBuf++ = '\r';
  693. *pBuf++ = '\n';
  694. *pBuf = 0;
  695. cbBuf = (DWORD) (pBuf - szSlowHeader);
  696. // Add or replace the (proxy-)authorization header.
  697. wHttpAddRequestHeaders (pRequest, szSlowHeader, cbBuf,
  698. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE);
  699. }
  700. // delete [] pszHeader;
  701. if( szSlowHeader )
  702. {
  703. FREE_MEMORY( szSlowHeader );
  704. }
  705. /*
  706. if (pszFastHeader)
  707. {
  708. FREE_MEMORY( pszFastHeader );
  709. }
  710. */
  711. DEBUG_LEAVE(0);
  712. }
  713. // biaow: move this to a better place
  714. PSTR DwordSchemeToString(DWORD dwScheme)
  715. {
  716. switch (dwScheme)
  717. {
  718. case WINHTTP_AUTH_SCHEME_BASIC:
  719. return "Basic";
  720. case WINHTTP_AUTH_SCHEME_NTLM:
  721. return "NTLM";
  722. case WINHTTP_AUTH_SCHEME_PASSPORT:
  723. return "Passport1.4";
  724. case WINHTTP_AUTH_SCHEME_DIGEST:
  725. return "Digest";
  726. case WINHTTP_AUTH_SCHEME_NEGOTIATE:
  727. return "Negotiate";
  728. default:
  729. return "";
  730. }
  731. }
  732. DWORD DwordSchemeToFlags(DWORD dwScheme)
  733. {
  734. switch (dwScheme)
  735. {
  736. case WINHTTP_AUTH_SCHEME_BASIC:
  737. return PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED;
  738. case WINHTTP_AUTH_SCHEME_NTLM:
  739. return PLUGIN_AUTH_FLAGS_NO_REALM;
  740. case WINHTTP_AUTH_SCHEME_PASSPORT:
  741. return PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED;
  742. case WINHTTP_AUTH_SCHEME_DIGEST:
  743. return PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI;
  744. case WINHTTP_AUTH_SCHEME_NEGOTIATE:
  745. return PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_NO_REALM;
  746. default:
  747. return 0;
  748. }
  749. }
  750. /*-----------------------------------------------------------------------------
  751. -----------------------------------------------------------------------------*/
  752. PUBLIC DWORD AuthOnRequest (IN HINTERNET hRequestMapped)
  753. {
  754. DEBUG_ENTER ((DBG_HTTP, Dword, "AuthOnRequest", "%#x", hRequestMapped));
  755. DWORD dwError = ERROR_SUCCESS;
  756. LPSTR lpszUser, lpszPass;
  757. // Get username, password, url, and auth context from request handle.
  758. HTTP_REQUEST_HANDLE_OBJECT *pRequest =
  759. (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
  760. LPSTR lpszUrl = pRequest->GetURL();
  761. LPSTR lpszHost= pRequest->GetServerName();
  762. AUTHCTX *pAuthCtx = pRequest->GetAuthCtx();
  763. AUTH_CREDS *Creds;
  764. BOOL fCredsChanged = FALSE;
  765. // PROXY AUTHENTICATION
  766. //
  767. // CERN proxies should remove proxy-authorization headers before forwarding
  768. // requests to servers. Otherwise, don't add proxy authorization headers
  769. // that would be seen by servers on a direct connect or via SSL tunneling.
  770. if (pRequest->IsRequestUsingProxy()
  771. && !pRequest->IsTalkingToSecureServerViaProxy())
  772. {
  773. // if an app sets proxy creds, we want to make sure that the specified
  774. // auth scheme is the same as the auth scheme in progress. Otherwise, we
  775. // will delete the current auth context and build a new one based on the
  776. // new scheme.
  777. if (pRequest->_pProxyCreds
  778. && (pAuthCtx && pAuthCtx->_fIsProxy)
  779. && (pAuthCtx->GetRawSchemeType() != pRequest->_pProxyCreds->_AuthScheme))
  780. {
  781. delete pAuthCtx;
  782. pAuthCtx = NULL;
  783. pRequest->SetAuthCtx(NULL);
  784. }
  785. if (pAuthCtx && pAuthCtx->_fIsProxy)
  786. {
  787. // We have a proxy authentication in progress.
  788. // If a user/pass set on handle, transfer to AUTH_CREDS.
  789. // First check for proxy credentials and fallback to server
  790. // for legacy wininet apps. This will invalidate the credentials
  791. // on the handle they were found for any subsequent calls to
  792. // GetUserAndPass.
  793. // Serialize access to globals.
  794. if (AuthLock())
  795. {
  796. if (pRequest->_pProxyCreds)
  797. {
  798. pAuthCtx->_pCreds->SetUser(pRequest->_pProxyCreds->_pszUserName);
  799. pAuthCtx->_pCreds->SetPass(pRequest->_pProxyCreds->_pszPassword);
  800. }
  801. else if (pRequest->GetUserAndPass(IS_PROXY, &lpszUser, &lpszPass))
  802. {
  803. pAuthCtx->_pCreds->SetUser(lpszUser);
  804. pAuthCtx->_pCreds->SetPass(lpszPass);
  805. }
  806. AuthUnlock();
  807. // Add the authorization header.
  808. AddAuthorizationHeader (pRequest, pAuthCtx);
  809. }
  810. }
  811. // NO PROXY AUTHENTICATION CONTEXT -> SEE IF A AUTH_CREDS EXISTS.
  812. else // See if we have a cached proxy user/pass.
  813. {
  814. if (pRequest->_pProxyCreds)
  815. {
  816. AUTHCTX::SPMData* pSPMData =
  817. reinterpret_cast<AUTHCTX::SPMData*>(New AUTHCTX::SPMData(
  818. DwordSchemeToString(pRequest->_pProxyCreds->_AuthScheme),
  819. DwordSchemeToFlags(pRequest->_pProxyCreds->_AuthScheme)));
  820. if (pSPMData)
  821. {
  822. AUTH_CREDS *pCreds = AUTHCTX::CreateCreds(pRequest, TRUE,
  823. pSPMData, pRequest->_pProxyCreds->_pszRealm);
  824. if (pCreds)
  825. {
  826. pCreds->SetUser(pRequest->_pProxyCreds->_pszUserName);
  827. pCreds->SetPass(pRequest->_pProxyCreds->_pszPassword);
  828. pAuthCtx = AUTHCTX::CreateAuthCtx(pRequest, IS_PROXY, pCreds);
  829. if (pAuthCtx && pAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_BASIC)
  830. {
  831. AddAuthorizationHeader (pRequest, pAuthCtx);
  832. }
  833. delete pAuthCtx;
  834. pAuthCtx = NULL;
  835. }
  836. }
  837. }
  838. }
  839. }
  840. // SERVER AUTHENTICATION
  841. //
  842. // Don't send server authorization when initiating SSL tunneling with proxy.
  843. if (!pRequest->IsTunnel())
  844. {
  845. // if an app sets server creds, we want to make sure that the specified
  846. // auth scheme is the same as the auth scheme in progress. Otherwise, we
  847. // will delete the current auth context and build a new one based on the
  848. // new scheme.
  849. if (pRequest->_pServerCreds
  850. && (pAuthCtx && !pAuthCtx->_fIsProxy)
  851. && (pAuthCtx->GetRawSchemeType() != pRequest->_pServerCreds->_AuthScheme))
  852. {
  853. delete pAuthCtx;
  854. pAuthCtx = NULL;
  855. pRequest->SetAuthCtx(NULL);
  856. }
  857. // See if we have a server authentication in progress
  858. if (pAuthCtx && !pAuthCtx->_fIsProxy)
  859. {
  860. // Server authentication in progress.
  861. // If a user/pass set on handle, transfer to AUTH_CREDS.
  862. // This will invalidate the credentials on the handle they
  863. // were found for any subsequent calls to GetUserAndPass.
  864. if (AuthLock())
  865. {
  866. if (pRequest->_pServerCreds)
  867. {
  868. pAuthCtx->_pCreds->SetUser(pRequest->_pServerCreds->_pszUserName);
  869. pAuthCtx->_pCreds->SetPass(pRequest->_pServerCreds->_pszPassword);
  870. }
  871. else if (pRequest->GetUserAndPass(IS_SERVER, &lpszUser, &lpszPass))
  872. {
  873. pAuthCtx->_pCreds->SetUser(lpszUser);
  874. pAuthCtx->_pCreds->SetPass(lpszPass);
  875. }
  876. AuthUnlock();
  877. // Add the authorization header.
  878. AddAuthorizationHeader (pRequest, pAuthCtx);
  879. }
  880. }
  881. else // See if we have a cached server user/pass.
  882. {
  883. // NO PROXY AUTHENTICATION CONTEXT -> SEE IF A AUTH_CREDS EXISTS
  884. if (pRequest->_pServerCreds)
  885. {
  886. BOOL fPreauth = FALSE;
  887. AUTHCTX *pNewAuthCtx = NULL;
  888. AUTHCTX::SPMData* pSPMData =
  889. reinterpret_cast<AUTHCTX::SPMData*>(New AUTHCTX::SPMData(
  890. DwordSchemeToString(pRequest->_pServerCreds->_AuthScheme),
  891. DwordSchemeToFlags(pRequest->_pServerCreds->_AuthScheme)));
  892. INET_ASSERT(pSPMData);
  893. AUTH_CREDS *pCreds = AUTHCTX::CreateCreds(pRequest, FALSE,
  894. pSPMData, pRequest->_pServerCreds->_pszRealm);
  895. if (pCreds)
  896. {
  897. pCreds->SetUser(pRequest->_pServerCreds->_pszUserName);
  898. pCreds->SetPass(pRequest->_pServerCreds->_pszPassword);
  899. pNewAuthCtx = AUTHCTX::CreateAuthCtx(pRequest, IS_SERVER, pCreds);
  900. if(pNewAuthCtx)
  901. {
  902. if (pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_NTLM
  903. || pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  904. {
  905. // NTLM or Negotiate (in which case we don't really know the
  906. // protocol yet) - create the auth context, set it in the handle
  907. // and set state to AUTHSTATE_NEGOTIATE. Handle now has
  908. // a valid auth context and is in the correct auth state
  909. // for the remainder of the authorization sequence.
  910. // It's possible that the Creds entry was created when no proxy
  911. // was in use and the user set a proxy. Check that this is
  912. // not the case.
  913. if (!pRequest->IsMethodBody()
  914. || (pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_NTLM
  915. && pRequest->IsDisableNTLMPreauth())
  916. || (pRequest->IsRequestUsingProxy()
  917. && !pRequest->IsTalkingToSecureServerViaProxy()))
  918. {
  919. // NTLM preauth disabled or over proxy; no preauth.
  920. delete pNewAuthCtx;
  921. pNewAuthCtx = NULL;
  922. }
  923. else
  924. {
  925. // Set the auth context in the handle and
  926. // add the auth header.
  927. pRequest->SetAuthCtx(pNewAuthCtx);
  928. pRequest->SetAuthState(AUTHSTATE_NEGOTIATE);
  929. AddAuthorizationHeader (pRequest, pNewAuthCtx);
  930. fPreauth = TRUE;
  931. }
  932. }
  933. else
  934. {
  935. // For Basic and Digest add the header but do not set the
  936. // context in the handle since we will delete it next.
  937. // In this case we record that we have pre-authenticated which
  938. // is necessary state info if the server challenges with a 401
  939. // and we are forced to re-authenticate.
  940. if ((pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_DIGEST && !fCredsChanged)
  941. || (pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_BASIC))
  942. {
  943. AddAuthorizationHeader (pRequest, pNewAuthCtx);
  944. pRequest->SetCreds(pNewAuthCtx->_pCreds);
  945. fPreauth = TRUE;
  946. }
  947. if (pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_PASSPORT)
  948. {
  949. pRequest->SetAuthCtx(pNewAuthCtx);
  950. AddAuthorizationHeader (pRequest, pNewAuthCtx);
  951. }
  952. }
  953. if (fPreauth)
  954. {
  955. // Proceed to delete the context if basic or digest.
  956. if (pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_DIGEST
  957. || pNewAuthCtx->GetSchemeType() == WINHTTP_AUTH_SCHEME_BASIC)
  958. {
  959. delete pNewAuthCtx;
  960. pNewAuthCtx = NULL;
  961. }
  962. }
  963. }
  964. }
  965. }
  966. }
  967. }
  968. DEBUG_LEAVE(dwError);
  969. return dwError;
  970. }
  971. /*-----------------------------------------------------------------------------
  972. -----------------------------------------------------------------------------*/
  973. DWORD ProcessResponseHeaders
  974. (
  975. HINTERNET hRequestMapped,
  976. BOOL fIsProxy
  977. )
  978. {
  979. DEBUG_ENTER ((DBG_HTTP, Dword, "ProcessResponseHeaders", "%#x", hRequestMapped));
  980. DWORD dwError = ERROR_SUCCESS;
  981. // Get context from request handle.
  982. HTTP_REQUEST_HANDLE_OBJECT *pRequest
  983. = (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
  984. AUTHCTX* pAuthCtx = pRequest->GetAuthCtx();
  985. if (pAuthCtx)
  986. {
  987. if ((dwError = pAuthCtx->UpdateFromHeaders(pRequest, fIsProxy))
  988. != ERROR_SUCCESS)
  989. {
  990. // Delete the auth context and fail auth
  991. // immediately if any other error than
  992. // scheme has been changed.
  993. delete pAuthCtx;
  994. pRequest->SetAuthCtx(NULL);
  995. if (dwError != ERROR_HTTP_HEADER_NOT_FOUND)
  996. goto cleanup;
  997. // Attempt to create a new auth context using
  998. // the challenge received from the server.
  999. // If this fails, we follow logic as commented
  1000. // below.
  1001. pAuthCtx = AUTHCTX::CreateAuthCtx(pRequest, fIsProxy);
  1002. if (!pAuthCtx)
  1003. {
  1004. dwError = ERROR_SUCCESS;
  1005. goto cleanup;
  1006. }
  1007. }
  1008. }
  1009. else
  1010. {
  1011. // CreateAuthCtx returns NULL if auth scheme not
  1012. // supported (fall through from HttpFiltOnResponse
  1013. // in sendreq.cxx) or if scheme is NTLM and the
  1014. // socket is not keep-alive or via proxy.
  1015. // In these cases it is necessary to check for a NULL
  1016. // return value. The correct return code for these cases is
  1017. // ERROR_SUCCESS, which will be returned by AuthOnResponse.
  1018. pAuthCtx = AUTHCTX::CreateAuthCtx(pRequest, fIsProxy);
  1019. if (!pAuthCtx)
  1020. {
  1021. dwError = ERROR_SUCCESS;
  1022. goto cleanup;
  1023. }
  1024. }
  1025. LPSTR lpszUser, lpszPass;
  1026. // First check for proxy credentials and fallback to server
  1027. // for legacy wininet apps. This will invalidate the credentials
  1028. // on the handle they were found for any subsequent calls to
  1029. // GetUserAndPass.
  1030. // I believe we should be putting the credentials in the
  1031. // password cache at this time. The scenario is that a client
  1032. // sets credentials on a handle, after a successful authentication
  1033. // the Creds will have null credentials. Pre-auth will then pull up
  1034. // credentials for the default user!!!!!!!!!!!
  1035. // Serialize access to globals.
  1036. if (AuthLock())
  1037. {
  1038. if (pRequest->_pServerCreds && !fIsProxy)
  1039. {
  1040. lpszUser = pRequest->_pServerCreds->_pszUserName;
  1041. lpszPass = pRequest->_pServerCreds->_pszPassword;
  1042. }
  1043. else if (pRequest->_pProxyCreds && fIsProxy)
  1044. {
  1045. lpszUser = pRequest->_pProxyCreds->_pszUserName;
  1046. lpszPass = pRequest->_pProxyCreds->_pszPassword;
  1047. }
  1048. else if ((!pRequest->GetUserAndPass(fIsProxy, &lpszUser, &lpszPass)) && fIsProxy && !GlobalIsProcessExplorer)
  1049. {
  1050. pRequest->GetUserAndPass(IS_SERVER, &lpszUser, &lpszPass);
  1051. }
  1052. AuthUnlock();
  1053. }
  1054. else
  1055. {
  1056. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1057. goto cleanup;
  1058. }
  1059. // If we retrieved credentials from the handle set
  1060. // them in the Creds.
  1061. if (lpszUser && lpszPass)
  1062. {
  1063. pAuthCtx->_pCreds->SetUser(lpszUser);
  1064. pAuthCtx->_pCreds->SetPass(lpszPass);
  1065. }
  1066. // Post authenticate user.
  1067. dwError = pAuthCtx->PostAuthUser();
  1068. // Map all unexpected error codes to login failure.
  1069. if (dwError != ERROR_WINHTTP_FORCE_RETRY
  1070. && dwError != ERROR_WINHTTP_INCORRECT_PASSWORD)
  1071. {
  1072. dwError = ERROR_WINHTTP_LOGIN_FAILURE;
  1073. }
  1074. pRequest->SetAuthCtx(pAuthCtx);
  1075. cleanup:
  1076. return dwError;
  1077. }
  1078. extern CHAR g_szPassportDAHost[];
  1079. BOOL IsSameDomain(LPCSTR pszTarget, LPCSTR pszResponse)
  1080. {
  1081. LPCSTR pszTargetR = pszTarget + strlen(pszTarget);
  1082. DWORD dwDotsSeen = 0;
  1083. while (--pszTargetR > pszTarget)
  1084. {
  1085. if (*pszTargetR == '.')
  1086. {
  1087. if (++dwDotsSeen == 2)
  1088. {
  1089. break;
  1090. }
  1091. }
  1092. }
  1093. if (dwDotsSeen == 2)
  1094. {
  1095. ++pszTargetR;
  1096. DWORD dwOffsetR = strlen(pszTargetR);
  1097. if (strlen(pszResponse) < dwOffsetR)
  1098. {
  1099. return FALSE;
  1100. }
  1101. LPCSTR pszResponseR = pszResponse + strlen(pszResponse) - dwOffsetR;
  1102. return !strcmp(pszTargetR, pszResponseR);
  1103. }
  1104. else
  1105. {
  1106. return FALSE;
  1107. }
  1108. }
  1109. VOID CheckForTweenerLogout(HTTP_REQUEST_HANDLE_OBJECT *pRequest)
  1110. {
  1111. DWORD dwIndex = 0;
  1112. DWORD dwError;
  1113. do
  1114. {
  1115. LPSTR szData;
  1116. DWORD cbData;
  1117. dwError = pRequest->FastQueryResponseHeader(HTTP_QUERY_AUTHENTICATION_INFO,
  1118. (LPVOID*) &szData,
  1119. &cbData,
  1120. dwIndex);
  1121. if (dwError == ERROR_SUCCESS)
  1122. {
  1123. if (strstr(szData, "Passport1.4") && strstr(szData, "logout"))
  1124. {
  1125. if (IsSameDomain(pRequest->GetServerName(), g_szPassportDAHost))
  1126. {
  1127. // g_fIgnoreCachedCredsForPassport = TRUE;
  1128. // todo: call session->Logout
  1129. }
  1130. break;
  1131. }
  1132. }
  1133. ++dwIndex;
  1134. } while (dwError == ERROR_SUCCESS);
  1135. }
  1136. /*-----------------------------------------------------------------------------
  1137. Routine Description:
  1138. Validates, and Caches Authentication Request headers if needed. If a URL matches a
  1139. cached set of templates it is assumed to require specific authentication information.
  1140. Arguments:
  1141. hRequest - An open HTTP request handle
  1142. where headers will be added if needed.
  1143. Return Value:
  1144. DWORD
  1145. Success - ERROR_SUCCESS
  1146. Failure - One of Several Error codes defined in winerror.h or wininet.w
  1147. Comments:
  1148. Need to handle mutiple authentication pages.
  1149. -----------------------------------------------------------------------------*/
  1150. PUBLIC DWORD AuthOnResponse (HINTERNET hRequestMapped)
  1151. {
  1152. DEBUG_ENTER((DBG_HTTP,
  1153. Dword,
  1154. "AuthOnResponse",
  1155. "%#x [%#x]",
  1156. hRequestMapped,
  1157. ((INTERNET_HANDLE_OBJECT *)hRequestMapped)->GetPseudoHandle()
  1158. ));
  1159. // Get URL and password cache entry from request handle.
  1160. HTTP_REQUEST_HANDLE_OBJECT *pRequest =
  1161. (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
  1162. AUTHCTX *pAuthCtx = pRequest->GetAuthCtx();
  1163. DWORD dwStatus = pRequest->GetStatusCode();
  1164. if (pAuthCtx)
  1165. {
  1166. if (pAuthCtx->_fIsProxy && dwStatus != HTTP_STATUS_PROXY_AUTH_REQ)
  1167. {
  1168. // We are done with proxy authentication.
  1169. delete pAuthCtx;
  1170. pRequest->SetAuthCtx (NULL);
  1171. if (pRequest->_pProxyCreds)
  1172. {
  1173. delete pRequest->_pProxyCreds;
  1174. pRequest->_pProxyCreds = NULL;
  1175. }
  1176. }
  1177. else if (!pAuthCtx->_fIsProxy && dwStatus != HTTP_STATUS_DENIED)
  1178. {
  1179. if ((pAuthCtx->GetSchemeType() != WINHTTP_AUTH_SCHEME_PASSPORT) || dwStatus != HTTP_STATUS_REDIRECT)
  1180. {
  1181. // We are done with server authentication.
  1182. delete pAuthCtx;
  1183. pRequest->SetAuthCtx (NULL);
  1184. if (pRequest->_pServerCreds)
  1185. {
  1186. delete pRequest->_pServerCreds;
  1187. pRequest->_pServerCreds = NULL;
  1188. }
  1189. }
  1190. else
  1191. {
  1192. // in the case of Passport Auth, 302 is still not done yet,
  1193. // but this is quite strange since 302 came a second time
  1194. // biaow-todo: we could be in a loop here
  1195. }
  1196. }
  1197. }
  1198. // Remove any stale authorization headers in case wHttpSendRequest
  1199. // loops, for example, to handle a redirect. To ignore trailing colon,
  1200. // subtract 1 from header lengths passed to ReplaceRequestHeader.
  1201. pRequest->ReplaceRequestHeader
  1202. (HTTP_QUERY_AUTHORIZATION,
  1203. "", 0, 0, HTTP_ADDREQ_FLAG_REPLACE);
  1204. pRequest->ReplaceRequestHeader
  1205. (HTTP_QUERY_PROXY_AUTHORIZATION,
  1206. "", 0, 0, HTTP_ADDREQ_FLAG_REPLACE);
  1207. DWORD error;
  1208. DWORD dwZone, dwPolicy;
  1209. //
  1210. // note: Negotiate MUTUAL_AUTH can return dwStatus = 200 with a final
  1211. // WWW-Authenticate blob to process. logic below could be adjusted
  1212. // to ProcessResponseHeaders() in this situation, which allows MUTUAL_AUTH
  1213. // to be enforced.
  1214. //
  1215. switch (dwStatus)
  1216. {
  1217. case HTTP_STATUS_PROXY_AUTH_REQ: // 407
  1218. error = ProcessResponseHeaders(pRequest, IS_PROXY);
  1219. break;
  1220. case HTTP_STATUS_REDIRECT: // 302
  1221. // process the header to see whether this is a 302 passport1.4 challenge
  1222. case HTTP_STATUS_DENIED: // 401
  1223. error = ProcessResponseHeaders(pRequest, IS_SERVER);
  1224. break;
  1225. default:
  1226. pRequest->SetAuthState(AUTHSTATE_NONE);
  1227. error = ERROR_SUCCESS;
  1228. }
  1229. // creds set by WinHttpSetCredentials() is good for one "authentication attempt" only.
  1230. // Since we are done authentication here, we are deleting it.
  1231. // biaow: detect the "final" failure so that we can delete the creds.
  1232. CheckForTweenerLogout(pRequest);
  1233. DEBUG_LEAVE(error);
  1234. return error;
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. //
  1238. //
  1239. // AUTHCTX Base class definitions
  1240. //
  1241. //
  1242. //
  1243. // static funcs:
  1244. // Enumerate
  1245. // UnloadAll
  1246. // CreateAuthCtx
  1247. // CreateAuthCtx (using Creds*)
  1248. // GetSPMListState
  1249. // SearchCredsList
  1250. // FindOrCreateCreds
  1251. // GetAuthHeaderData
  1252. //
  1253. // base funcs:
  1254. // FindHdrIdxFromScheme
  1255. // GetScheme
  1256. // GetSchemeType - returns enum
  1257. // GetFlags - returns SPM flags
  1258. // GetState - returns state of SPM provider
  1259. //
  1260. //
  1261. // virtual overrides: defined in basic.cxx, plug.cxx and digest.cxx
  1262. // UpdateFromHeaders
  1263. // PreAuthUser
  1264. // PostAuthUser
  1265. //
  1266. //
  1267. //
  1268. /*---------------------------------------------------------------------------
  1269. AUTHCTX::SPMData constructor
  1270. ---------------------------------------------------------------------------*/
  1271. AUTHCTX::SPMData::SPMData(LPSTR _szScheme, DWORD _dwFlags)
  1272. {
  1273. if (_szScheme)
  1274. {
  1275. szScheme = NewString(_szScheme);
  1276. cbScheme = strlen(_szScheme);
  1277. }
  1278. else
  1279. {
  1280. szScheme = NULL;
  1281. cbScheme = 0;
  1282. }
  1283. if (szScheme)
  1284. {
  1285. if (!lstrcmpi(szScheme, "Basic"))
  1286. eScheme = WINHTTP_AUTH_SCHEME_BASIC;
  1287. else if (!lstrcmpi(szScheme, "NTLM"))
  1288. eScheme = WINHTTP_AUTH_SCHEME_NTLM;
  1289. else if (!lstrcmpi(szScheme, "Digest"))
  1290. eScheme = WINHTTP_AUTH_SCHEME_DIGEST;
  1291. else if (!lstrcmpi(szScheme, "Negotiate"))
  1292. eScheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
  1293. else if (!lstrcmpi(szScheme, "Passport1.4"))
  1294. eScheme = WINHTTP_AUTH_SCHEME_PASSPORT;
  1295. else
  1296. eScheme = 0;
  1297. dwFlags = _dwFlags;
  1298. eState = STATE_NOTLOADED;
  1299. }
  1300. else
  1301. {
  1302. dwFlags = 0;
  1303. eState = STATE_ERROR;
  1304. }
  1305. }
  1306. /*---------------------------------------------------------------------------
  1307. AUTHCTX::SPMData destructor
  1308. ---------------------------------------------------------------------------*/
  1309. AUTHCTX::SPMData::~SPMData()
  1310. { delete szScheme; }
  1311. /*---------------------------------------------------------------------------
  1312. AUTHCTX constructor
  1313. ---------------------------------------------------------------------------*/
  1314. AUTHCTX::AUTHCTX(SPMData *pData, AUTH_CREDS *pCreds)
  1315. {
  1316. _pSPMData = pData;
  1317. _pCreds = pCreds;
  1318. _pRequest = NULL;
  1319. _fIsProxy = FALSE;
  1320. _pvContext = NULL;
  1321. _eSubScheme = 0;
  1322. _dwSubFlags = 0;
  1323. _CtxCriSec.Init();
  1324. }
  1325. /*---------------------------------------------------------------------------
  1326. Destructor
  1327. ---------------------------------------------------------------------------*/
  1328. AUTHCTX::~AUTHCTX()
  1329. {
  1330. if (AuthLock())
  1331. {
  1332. if (_pCreds)
  1333. Creds_Free(_pCreds);
  1334. AuthUnlock();
  1335. }
  1336. _CtxCriSec.FreeLock();
  1337. }
  1338. // ------------------------ Static Functions ---------------------------------
  1339. /*---------------------------------------------------------------------------
  1340. Enumerate
  1341. ---------------------------------------------------------------------------*/
  1342. VOID AUTHCTX::Enumerate()
  1343. {
  1344. struct SchemeFlagsPair
  1345. {
  1346. LPSTR pszScheme;
  1347. DWORD Flags;
  1348. };
  1349. SchemeFlagsPair SchemeFlags[] = {
  1350. {"NTLM", PLUGIN_AUTH_FLAGS_NO_REALM},
  1351. {"Basic", PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED},
  1352. {"Digest", PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI},
  1353. {"Negotiate", PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_NO_REALM},
  1354. {"Passport1.4", PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED}
  1355. };
  1356. SPMData *pNew;
  1357. g_pSPMList = NULL;
  1358. g_eState = STATE_ERROR;
  1359. AssertHaveLock();
  1360. // Hard-wired Basic, NTLM and Digest
  1361. for (DWORD dwIndex = 0; dwIndex < sizeof(SchemeFlags) / sizeof(SchemeFlagsPair); dwIndex++)
  1362. {
  1363. if (!GlobalPlatformVersion5 // we don't support Negotiate on NT4 or Win9x
  1364. && !stricmp(SchemeFlags[dwIndex].pszScheme, "Negotiate"))
  1365. {
  1366. continue;
  1367. }
  1368. pNew = (AUTHCTX::SPMData*) New SPMData(SchemeFlags[dwIndex].pszScheme, SchemeFlags[dwIndex].Flags);
  1369. if (!pNew)
  1370. return;
  1371. // Add to head of list.
  1372. if (pNew->eState != STATE_ERROR)
  1373. {
  1374. pNew->pNext = g_pSPMList;
  1375. g_pSPMList = pNew;
  1376. }
  1377. }
  1378. // The list is now in the correct state.
  1379. g_eState = STATE_LOADED;
  1380. }
  1381. VOID AUTHCTX::UnloadAll()
  1382. {
  1383. // BUGBUG - AuthFlush is called when the last browser session
  1384. // is closed. First the global Creds lists are destructed, and
  1385. // then this func (UnloadAll) is called. However, the global
  1386. // Creds lists are not necessarily flushed (they may have out-
  1387. // standing ref counts) and may persist across browser sessions.
  1388. // when we destruct the SPM list in this func, SPMs reference
  1389. // by any surviving Creds entries are bogus and can be used
  1390. // for subsequent authentication, resulting in a fault.
  1391. //
  1392. // The temporary hack here is to not destruct the SPM
  1393. // list if any Creds list is not destructed. We leak the
  1394. // SPM list on process detach but don't fault. Put the
  1395. // SPM destruct code in DllProcessDetach.
  1396. SPMData *pData = g_pSPMList;
  1397. while (pData)
  1398. {
  1399. SPMData *pNext = pData->pNext;
  1400. delete pData;
  1401. pData = pNext;
  1402. }
  1403. SSPI_Unload();
  1404. g_eState = STATE_NOTLOADED;
  1405. g_pSPMList = NULL;
  1406. }
  1407. DWORD StringSchemeToDword(LPSTR szScheme)
  1408. {
  1409. if (!stricmp(szScheme, "Basic"))
  1410. {
  1411. return WINHTTP_AUTH_SCHEME_BASIC;
  1412. }
  1413. else if (!stricmp(szScheme, "Digest"))
  1414. {
  1415. return WINHTTP_AUTH_SCHEME_DIGEST;
  1416. }
  1417. else if (!stricmp(szScheme, "Passport1.4"))
  1418. {
  1419. return WINHTTP_AUTH_SCHEME_PASSPORT;
  1420. }
  1421. else if (!stricmp(szScheme, "NTLM"))
  1422. {
  1423. return WINHTTP_AUTH_SCHEME_NTLM;
  1424. }
  1425. else if (!stricmp(szScheme, "Negotiate"))
  1426. {
  1427. return WINHTTP_AUTH_SCHEME_NEGOTIATE;
  1428. }
  1429. else
  1430. {
  1431. return 0;
  1432. }
  1433. }
  1434. /*---------------------------------------------------------------------------
  1435. CreateAuthCtx
  1436. Create an AUTHCTX* from headers - initially the authentication context
  1437. is created without a AUTH_CREDS entry. The AUTH_CREDS entry will be found or created
  1438. and possibly updated in UpdateFromHeaders.
  1439. ---------------------------------------------------------------------------*/
  1440. AUTHCTX* AUTHCTX::CreateAuthCtx(HTTP_REQUEST_HANDLE_OBJECT * pRequest, BOOL fIsProxy)
  1441. {
  1442. LPSTR szScheme;
  1443. DWORD cbScheme, dwError, dwAuthIdx;
  1444. AUTHCTX *pAuthCtx = NULL;
  1445. dwAuthIdx = 0;
  1446. szScheme = NULL;
  1447. // Get scheme. This is assumed to be the first
  1448. // non-ws token in the auth header info.
  1449. do
  1450. {
  1451. // It is necessary to hold on to the auth index
  1452. // in this loop because we could have gone through
  1453. // more than one scheme.
  1454. dwError = GetAuthHeaderData(pRequest, fIsProxy, NULL,
  1455. &szScheme, &cbScheme, ALLOCATE_BUFFER | GET_SCHEME, dwAuthIdx);
  1456. if (dwError != ERROR_SUCCESS)
  1457. goto quit;
  1458. pRequest->_SupportedSchemes |= StringSchemeToDword(szScheme);
  1459. pRequest->_AuthTarget = fIsProxy ? WINHTTP_AUTH_TARGET_PROXY : WINHTTP_AUTH_TARGET_SERVER;
  1460. // This will create the appropriate authentication context
  1461. // with a NULL password cache. The password cache will be
  1462. // created in the call to UpdateFromHeaders.
  1463. if (pAuthCtx == NULL)
  1464. {
  1465. pAuthCtx = CreateAuthCtx(pRequest, fIsProxy, szScheme);
  1466. // If creation of an auth context is successful, update
  1467. // the context from any header info.
  1468. if (pAuthCtx)
  1469. {
  1470. if (pAuthCtx->UpdateFromHeaders(pRequest, fIsProxy) != ERROR_SUCCESS)
  1471. {
  1472. delete pAuthCtx;
  1473. pAuthCtx = NULL;
  1474. }
  1475. else
  1476. {
  1477. pRequest->_PreferredScheme = StringSchemeToDword(szScheme);
  1478. }
  1479. }
  1480. }
  1481. dwAuthIdx++;
  1482. delete szScheme;
  1483. szScheme = NULL;
  1484. } while (1);
  1485. quit:
  1486. if (szScheme)
  1487. delete szScheme;
  1488. return pAuthCtx;
  1489. }
  1490. /*---------------------------------------------------------------------------
  1491. CreateAuthCtx
  1492. Create an AUTHCTX without a AUTH_CREDS from scheme
  1493. ---------------------------------------------------------------------------*/
  1494. AUTHCTX* AUTHCTX::CreateAuthCtx(HTTP_REQUEST_HANDLE_OBJECT *pRequest,
  1495. BOOL fIsProxy, LPSTR szScheme)
  1496. {
  1497. if (!AuthLock())
  1498. {
  1499. return NULL;
  1500. }
  1501. AUTHCTX *pNewAuthCtx = NULL;
  1502. // we don't want to create a Passport1.4 context on 401 response (from DA)
  1503. if (!lstrcmpi("Passport1.4", szScheme))
  1504. {
  1505. if (pRequest->GetStatusCode() == HTTP_STATUS_DENIED)
  1506. {
  1507. goto quit;
  1508. }
  1509. }
  1510. // If necessary, enumerate auth providers from registry.
  1511. if (AUTHCTX::GetSPMListState() == AUTHCTX::STATE_NOTLOADED)
  1512. AUTHCTX::Enumerate();
  1513. if (AUTHCTX::GetSPMListState() != AUTHCTX::STATE_LOADED)
  1514. {
  1515. // not critical, just no authentication
  1516. goto quit;
  1517. }
  1518. SPMData *pSPM;
  1519. pSPM = g_pSPMList;
  1520. // Find SPMData to create from scheme.
  1521. while (pSPM)
  1522. {
  1523. if (!lstrcmpi(pSPM->szScheme, szScheme))
  1524. break;
  1525. pSPM = pSPM->pNext;
  1526. }
  1527. if (!pSPM)
  1528. {
  1529. // No matching auth scheme found.
  1530. // Not critical, just no auth.
  1531. goto quit;
  1532. }
  1533. // Create an auth context without Creds
  1534. switch(pSPM->eScheme)
  1535. {
  1536. // Create BASIC_CTX with NULL AUTH_CREDS.
  1537. case WINHTTP_AUTH_SCHEME_BASIC:
  1538. pNewAuthCtx = New BASIC_CTX(pRequest, fIsProxy, pSPM, NULL);
  1539. break;
  1540. // Create DIGEST_CTX with NULL AUTH_CREDS.
  1541. case WINHTTP_AUTH_SCHEME_DIGEST:
  1542. pNewAuthCtx = New DIGEST_CTX(pRequest, fIsProxy, pSPM, NULL);
  1543. break;
  1544. case WINHTTP_AUTH_SCHEME_PASSPORT:
  1545. pNewAuthCtx = new PASSPORT_CTX(pRequest, fIsProxy, pSPM, NULL);
  1546. if (pNewAuthCtx)
  1547. {
  1548. if (((PASSPORT_CTX*)pNewAuthCtx)->Init() == FALSE)
  1549. {
  1550. delete pNewAuthCtx;
  1551. pNewAuthCtx = NULL;
  1552. }
  1553. }
  1554. break;
  1555. // Create PLUG_CTX with NULL AUTH_CREDS.
  1556. case WINHTTP_AUTH_SCHEME_NTLM:
  1557. case WINHTTP_AUTH_SCHEME_NEGOTIATE:
  1558. default:
  1559. pNewAuthCtx = New PLUG_CTX(pRequest, fIsProxy, pSPM, NULL);
  1560. }
  1561. quit:
  1562. AuthUnlock();
  1563. return pNewAuthCtx;
  1564. }
  1565. /*---------------------------------------------------------------------------
  1566. CreateAuthCtx
  1567. Create an AUTHCTX from a AUTH_CREDS.
  1568. ---------------------------------------------------------------------------*/
  1569. AUTHCTX* AUTHCTX::CreateAuthCtx(HTTP_REQUEST_HANDLE_OBJECT *pRequest,
  1570. BOOL fIsProxy, AUTH_CREDS* pCreds)
  1571. {
  1572. if (!AuthLock())
  1573. {
  1574. return NULL;
  1575. }
  1576. AUTHCTX *pNewAuthCtx = NULL;
  1577. // If necessary, enumerate auth providers from registry.
  1578. if (AUTHCTX::GetSPMListState() == AUTHCTX::STATE_NOTLOADED)
  1579. AUTHCTX::Enumerate();
  1580. if (AUTHCTX::GetSPMListState() != AUTHCTX::STATE_LOADED)
  1581. {
  1582. // not critical, just no authentication
  1583. goto quit;
  1584. }
  1585. // Handle tests (via proxy, is keep-alive)
  1586. // will be done in UpdateFromHeaders. Here
  1587. // we just construct the AUTHCTX.
  1588. switch(pCreds->pSPM->eScheme)
  1589. {
  1590. // Create BASIC_CTX.
  1591. case WINHTTP_AUTH_SCHEME_BASIC:
  1592. pNewAuthCtx = New BASIC_CTX(pRequest, fIsProxy, pCreds->pSPM, pCreds);
  1593. break;
  1594. // Create DIGEST_CTX.
  1595. case WINHTTP_AUTH_SCHEME_DIGEST:
  1596. pNewAuthCtx = New DIGEST_CTX(pRequest, fIsProxy, pCreds->pSPM, pCreds);
  1597. break;
  1598. case WINHTTP_AUTH_SCHEME_PASSPORT:
  1599. pNewAuthCtx = new PASSPORT_CTX(pRequest, fIsProxy, pCreds->pSPM, pCreds);
  1600. if (pNewAuthCtx)
  1601. {
  1602. if (((PASSPORT_CTX*)pNewAuthCtx)->Init() == FALSE)
  1603. {
  1604. delete pNewAuthCtx;
  1605. pNewAuthCtx = NULL;
  1606. }
  1607. }
  1608. break;
  1609. // Create PLUG_CTX.
  1610. case WINHTTP_AUTH_SCHEME_NTLM:
  1611. case WINHTTP_AUTH_SCHEME_NEGOTIATE:
  1612. default:
  1613. pNewAuthCtx = New PLUG_CTX(pRequest, fIsProxy, pCreds->pSPM, pCreds);
  1614. }
  1615. quit:
  1616. AuthUnlock();
  1617. return pNewAuthCtx;
  1618. }
  1619. AUTHCTX::SPMState AUTHCTX::GetSPMListState()
  1620. { return g_eState; }
  1621. /*-----------------------------------------------------------------------------
  1622. SearchCredsList
  1623. -----------------------------------------------------------------------------*/
  1624. //AUTH_CREDS* AUTHCTX::SearchCredsList
  1625. // (AUTH_CREDS* Creds, LPSTR lpszHost, LPSTR lpszUri, LPSTR lpszRealm, SPMData *pSPM)
  1626. /*++
  1627. Routine Description:
  1628. Scans the Linked List Cache for URLs, Realms, and Servers. Also allows
  1629. filter fields, to narrow searches.
  1630. Arguments:
  1631. Creds - Pointer to first item to search from.
  1632. lpszHost - Host, or Server name to search on.
  1633. lpszUri - URL to search on.
  1634. lpszRealm - Security Realm to search on
  1635. lpszScheme - Authentication scheme to search on.
  1636. Return Value:
  1637. AUTH_CREDS *
  1638. Success - Pointer to found item.
  1639. Failure - NULL pointer.
  1640. Comments:
  1641. Note: This Legacy code from the SpyGlass IE 1.0 browser
  1642. The AUTH_CREDS lists are searched on every request. Could optimize by keeping
  1643. a hash value of the server/proxy name.
  1644. If an exact match isn't found on a 401 response, the list is walked again
  1645. to search for a realm match. Could add a parameter to do both at once.
  1646. --*/
  1647. /*
  1648. {
  1649. AssertHaveLock();
  1650. while (Creds)
  1651. {
  1652. if ( (!pSPM || pSPM == Creds->pSPM)
  1653. && (!lpszHost || !lstrcmpi(Creds->lpszHost,lpszHost))
  1654. && (!lpszRealm || !lstrcmpi(Creds->lpszRealm,lpszRealm))
  1655. && (!lpszUri || TemplateMatch (Creds->lpszUrl, lpszUri))
  1656. )
  1657. {
  1658. DEBUG_PRINT(HTTP, INFO, ("Lookup: Found template match [%q]\n",
  1659. Creds->lpszUser));
  1660. return Creds;
  1661. }
  1662. else
  1663. {
  1664. Creds = Creds->pNext;
  1665. }
  1666. }
  1667. return NULL;
  1668. }
  1669. */
  1670. /*-----------------------------------------------------------------------------
  1671. FindOrCreateCreds
  1672. -----------------------------------------------------------------------------*/
  1673. AUTH_CREDS* AUTHCTX::CreateCreds(
  1674. HTTP_REQUEST_HANDLE_OBJECT *pRequest,
  1675. BOOL fIsProxy,
  1676. SPMData *pSPM,
  1677. LPSTR lpszRealm
  1678. )
  1679. {
  1680. //AssertHaveLock();
  1681. // Create a AUTH_CREDS.
  1682. AUTH_CREDS *Creds;
  1683. Creds = NULL;
  1684. if (!pSPM)
  1685. {
  1686. INET_ASSERT(FALSE);
  1687. goto quit;
  1688. }
  1689. // Get host from request handle.
  1690. LPSTR lpszHost;
  1691. lpszHost = fIsProxy?
  1692. GetProxyName(pRequest) : pRequest->GetServerName();
  1693. // For NTLM, use the hostname analagously to basic realm.
  1694. if (pSPM->eScheme == WINHTTP_AUTH_SCHEME_NTLM || pSPM->eScheme == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  1695. {
  1696. INET_ASSERT (!lpszRealm);
  1697. lpszRealm = lpszHost;
  1698. }
  1699. Creds = Creds_Create (lpszHost, lpszRealm, pSPM);
  1700. quit:
  1701. return Creds;
  1702. }
  1703. /*-----------------------------------------------------------------------------
  1704. GetAuthHeaderData
  1705. -----------------------------------------------------------------------------*/
  1706. DWORD AUTHCTX::GetAuthHeaderData(
  1707. HTTP_REQUEST_HANDLE_OBJECT *pRequest,
  1708. BOOL fIsProxy,
  1709. LPSTR szItem,
  1710. LPSTR *pszData,
  1711. LPDWORD pcbData,
  1712. DWORD dwFlags,
  1713. DWORD dwIndex)
  1714. {
  1715. LPSTR szData;
  1716. DWORD cbData, cbItem, dwError = ERROR_SUCCESS;;
  1717. CHAR *szTok, *szKey, *szValue;
  1718. DWORD cbTok, cbKey, cbValue;
  1719. szTok = szKey = szValue = NULL;
  1720. cbTok = cbKey = cbValue = NULL;
  1721. cbItem = szItem ? strlen(szItem) : 0;
  1722. DWORD dwQuery = fIsProxy?
  1723. HTTP_QUERY_PROXY_AUTHENTICATE : HTTP_QUERY_WWW_AUTHENTICATE;
  1724. // NULL item passed in means get up to the first \r\n, or
  1725. // possibly only the scheme is desired depending on dwFlags.
  1726. if (!cbItem)
  1727. {
  1728. if ((dwError = pRequest->FastQueryResponseHeader(dwQuery,
  1729. (LPVOID*) &szData,
  1730. &cbData,
  1731. dwIndex)) != ERROR_SUCCESS)
  1732. {
  1733. goto quit;
  1734. }
  1735. // Only the scheme is desired.
  1736. if (dwFlags & GET_SCHEME)
  1737. {
  1738. CHAR* ptr;
  1739. ptr = szValue = szData;
  1740. cbValue = 0;
  1741. while (!(*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n'))
  1742. {
  1743. ptr++;
  1744. cbValue++;
  1745. }
  1746. }
  1747. else
  1748. {
  1749. // The entire header is desired.
  1750. szValue = szData;
  1751. cbValue = cbData;
  1752. }
  1753. }
  1754. else
  1755. {
  1756. // An item was passed in - attempt to parse this
  1757. // from the headers and return the corresponding
  1758. // value.
  1759. if ((dwError = pRequest->FastQueryResponseHeader(dwQuery,
  1760. (LPVOID*) &szData,
  1761. &cbData,
  1762. dwIndex)) != ERROR_SUCCESS)
  1763. {
  1764. goto quit;
  1765. }
  1766. // Successfully retrieved header. Parse for the desired item.
  1767. // Point past scheme
  1768. while (!(*szData == ' ' || *szData == '\t' || *szData == '\r' || *szData == '\n'))
  1769. {
  1770. szData++;
  1771. cbData--;
  1772. }
  1773. // Attempt to parse an item of the format 'key = <">value<">'
  1774. // from a comma delmited list of items.
  1775. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  1776. while (GetDelimitedToken(&szData, &cbData, &szTok, &cbTok, ','))
  1777. {
  1778. if (GetKeyValuePair(szTok, cbTok, &szKey, &cbKey, &szValue, &cbValue))
  1779. {
  1780. if ((cbItem == cbKey) && !strnicmp(szKey, szItem, cbItem))
  1781. {
  1782. TrimQuotes(&szValue, &cbValue);
  1783. dwError = ERROR_SUCCESS;
  1784. break;
  1785. }
  1786. }
  1787. }
  1788. }
  1789. if (dwError == ERROR_SUCCESS)
  1790. {
  1791. // Allocate buffer containing data
  1792. // or return reference.
  1793. if (dwFlags & ALLOCATE_BUFFER)
  1794. {
  1795. *pszData = New CHAR[cbValue+1];
  1796. if (!*pszData)
  1797. {
  1798. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1799. goto quit;
  1800. }
  1801. memcpy(*pszData, szValue, cbValue);
  1802. (*pszData)[cbValue] = '\0';
  1803. *pcbData = cbValue;
  1804. }
  1805. else
  1806. {
  1807. *pszData = szValue;
  1808. *pcbData = cbValue;
  1809. }
  1810. }
  1811. quit:
  1812. if (dwError != ERROR_SUCCESS)
  1813. {
  1814. INET_ASSERT(dwIndex || dwError == ERROR_HTTP_HEADER_NOT_FOUND);
  1815. }
  1816. return dwError;
  1817. }
  1818. // ------------------------ Base class funcs---------------------------------
  1819. /*-----------------------------------------------------------------------------
  1820. FindHdrIdxFromScheme
  1821. -----------------------------------------------------------------------------*/
  1822. DWORD AUTHCTX::FindHdrIdxFromScheme(LPDWORD pdwIndex)
  1823. {
  1824. LPSTR szHeader;
  1825. DWORD cbScheme, cbHeader, dwQuery, dwError;
  1826. dwQuery = _fIsProxy?
  1827. HTTP_QUERY_PROXY_AUTHENTICATE : HTTP_QUERY_WWW_AUTHENTICATE;
  1828. *pdwIndex = 0;
  1829. while ((dwError = _pRequest->FastQueryResponseHeader(dwQuery,
  1830. (LPVOID*) &szHeader,
  1831. &cbHeader,
  1832. *pdwIndex)) == ERROR_SUCCESS)
  1833. {
  1834. DWORD cb = 0;
  1835. CHAR *ptr = szHeader;
  1836. while (!(*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n'))
  1837. {
  1838. ptr++;
  1839. cb++;
  1840. }
  1841. if ((_pSPMData->cbScheme == cb)
  1842. && (!strnicmp(_pSPMData->szScheme, szHeader, cb)))
  1843. {
  1844. break;
  1845. }
  1846. (*pdwIndex)++;
  1847. }
  1848. return dwError;
  1849. }
  1850. /*-----------------------------------------------------------------------------
  1851. Get funcs.
  1852. -----------------------------------------------------------------------------*/
  1853. LPSTR AUTHCTX::GetScheme()
  1854. { return _pSPMData->szScheme; }
  1855. DWORD AUTHCTX::GetSchemeType()
  1856. {
  1857. if (_pSPMData->eScheme == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  1858. {
  1859. if (_eSubScheme == WINHTTP_AUTH_SCHEME_NTLM || _eSubScheme == WINHTTP_AUTH_SCHEME_KERBEROS)
  1860. {
  1861. return _eSubScheme;
  1862. }
  1863. }
  1864. return _pSPMData->eScheme;
  1865. }
  1866. DWORD AUTHCTX::GetRawSchemeType()
  1867. {
  1868. return _pSPMData->eScheme;
  1869. }
  1870. DWORD AUTHCTX::GetFlags()
  1871. {
  1872. if (_pSPMData->eScheme == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  1873. {
  1874. if (_eSubScheme == WINHTTP_AUTH_SCHEME_NTLM || _eSubScheme == WINHTTP_AUTH_SCHEME_KERBEROS)
  1875. {
  1876. return _dwSubFlags;
  1877. }
  1878. }
  1879. return _pSPMData->dwFlags;
  1880. }
  1881. AUTHCTX::SPMState AUTHCTX::GetState()
  1882. { return _pSPMData->eState; }