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.

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