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.

916 lines
25 KiB

  1. #include <wininetp.h>
  2. #include <urlmon.h>
  3. #include <splugin.hxx>
  4. #include "auth.h"
  5. #include "sspspm.h"
  6. #include "winctxt.h"
  7. extern "C"
  8. {
  9. extern SspData *g_pSspData;
  10. }
  11. /*-----------------------------------------------------------------------------
  12. PLUG_CTX
  13. -----------------------------------------------------------------------------*/
  14. /*---------------------------------------------------------------------------
  15. Load
  16. ---------------------------------------------------------------------------*/
  17. DWORD PLUG_CTX::Load()
  18. {
  19. DEBUG_ENTER ((
  20. DBG_HTTPAUTH,
  21. Dword,
  22. "PLUG_CTX::Load",
  23. "this=%#x",
  24. this
  25. ));
  26. INET_ASSERT(_pSPMData == _pPWC->pSPM);
  27. DWORD_PTR dwAuthCode = 0;
  28. DEBUG_ENTER ((
  29. DBG_HTTPAUTH,
  30. Pointer,
  31. "SSPI_InitScheme",
  32. "%s",
  33. GetScheme()
  34. ));
  35. dwAuthCode = SSPI_InitScheme (GetScheme());
  36. DEBUG_LEAVE(dwAuthCode);
  37. if (!dwAuthCode)
  38. {
  39. _pSPMData->eState = STATE_ERROR;
  40. DEBUG_LEAVE(ERROR_INTERNET_INTERNAL_ERROR);
  41. return ERROR_INTERNET_INTERNAL_ERROR;
  42. }
  43. _pSPMData->eState = STATE_LOADED;
  44. DEBUG_LEAVE(ERROR_SUCCESS);
  45. return ERROR_SUCCESS;
  46. }
  47. /*---------------------------------------------------------------------------
  48. ClearAuthUser
  49. ---------------------------------------------------------------------------*/
  50. DWORD PLUG_CTX::ClearAuthUser(LPVOID *ppvContext, LPSTR szServer)
  51. {
  52. DEBUG_ENTER ((
  53. DBG_HTTPAUTH,
  54. Dword,
  55. "PLUG_CTX::ClearAuthUser",
  56. "this=%#x ctx=%#x server=%.16s",
  57. this,
  58. *ppvContext,
  59. szServer
  60. ));
  61. if (GetState() == AUTHCTX::STATE_LOADED)
  62. {
  63. AuthLock();
  64. __try
  65. {
  66. DEBUG_ENTER ((
  67. DBG_HTTPAUTH,
  68. None,
  69. "UnloadAuthenticateUser",
  70. "ctx=%#x server=%s scheme=%s",
  71. *ppvContext,
  72. szServer,
  73. GetScheme()
  74. ));
  75. UnloadAuthenticateUser(ppvContext, szServer, GetScheme());
  76. DEBUG_LEAVE(0);
  77. }
  78. __except (EXCEPTION_EXECUTE_HANDLER)
  79. {
  80. DEBUG_PRINT(
  81. HTTPAUTH,
  82. ERROR,
  83. ("UnloadAuthenticateUser call down faulted\n")
  84. );
  85. }
  86. ENDEXCEPT
  87. AuthUnlock();
  88. }
  89. *ppvContext = 0;
  90. DEBUG_LEAVE(ERROR_SUCCESS);
  91. return ERROR_SUCCESS;
  92. }
  93. /*-----------------------------------------------------------------------------
  94. wQueryHeadersAlloc
  95. Routine Description:
  96. Allocates a HTTP Header String, and queries the HTTP handle for it.
  97. Arguments:
  98. hRequestMapped - An open HTTP request handle
  99. where headers can be quiered
  100. dwQuery - The Query Type to pass to HttpQueryHeaders
  101. lpdwQueryIndex - The Index of the header to pass to HttpQueryHeaders,
  102. make sure to inialize to 0.
  103. lppszOutStr - On success, a pointer to Allocated string with header string,
  104. lpdwSize - size of the string returned in lppszOutStr
  105. Return Value:
  106. DWORD
  107. Success - ERROR_SUCCESS
  108. Failure - One of Several Error codes defined in winerror.h or wininet.w
  109. Comments:
  110. On Error, lppszOutStr may still contain an allocated string that will need to be
  111. freed.
  112. -----------------------------------------------------------------------------*/
  113. DWORD PLUG_CTX::wQueryHeadersAlloc
  114. (
  115. IN HINTERNET hRequestMapped,
  116. IN DWORD dwQuery,
  117. OUT LPDWORD lpdwQueryIndex,
  118. OUT LPSTR *lppszOutStr,
  119. OUT LPDWORD lpdwSize
  120. )
  121. {
  122. DEBUG_ENTER ((
  123. DBG_HTTPAUTH,
  124. Dword,
  125. "PLUG_CTX::wQueryHeadersAlloc",
  126. "this=%#x request=%#x query=%d queryidx=%#x {%d} ppoutstr=%#x lpdwSize=%#x",
  127. this,
  128. hRequestMapped,
  129. dwQuery,
  130. lpdwQueryIndex,
  131. *lpdwQueryIndex,
  132. lppszOutStr,
  133. lpdwSize
  134. ));
  135. LPSTR lpszRawHeaderBuf = NULL;
  136. DWORD dwcbRawHeaderBuf = 0;
  137. DWORD error;
  138. DWORD length;
  139. HTTP_REQUEST_HANDLE_OBJECT * pHttpRequest;
  140. INET_ASSERT(lppszOutStr);
  141. INET_ASSERT(hRequestMapped);
  142. INET_ASSERT(lpdwSize);
  143. *lppszOutStr = NULL;
  144. error = ERROR_SUCCESS;
  145. pHttpRequest = (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
  146. // Attempt to determine whether our header is there.
  147. length = 0;
  148. if (pHttpRequest->QueryInfo(dwQuery, NULL, &length, lpdwQueryIndex)
  149. != ERROR_INSUFFICIENT_BUFFER)
  150. {
  151. // no authentication happening, we're done
  152. error = ERROR_HTTP_HEADER_NOT_FOUND;
  153. goto quit;
  154. }
  155. // Allocate a Fixed Size Buffer
  156. lpszRawHeaderBuf = (LPSTR) ALLOCATE_MEMORY(LPTR, length);
  157. dwcbRawHeaderBuf = length;
  158. if ( lpszRawHeaderBuf == NULL )
  159. {
  160. error = ERROR_NOT_ENOUGH_MEMORY;
  161. goto quit;
  162. }
  163. error = pHttpRequest->QueryInfo
  164. (dwQuery, lpszRawHeaderBuf, &dwcbRawHeaderBuf, lpdwQueryIndex);
  165. INET_ASSERT(error != ERROR_INSUFFICIENT_BUFFER );
  166. INET_ASSERT(error != ERROR_HTTP_HEADER_NOT_FOUND );
  167. quit:
  168. if ( error != ERROR_SUCCESS )
  169. {
  170. dwcbRawHeaderBuf = 0;
  171. if ( lpszRawHeaderBuf )
  172. *lpszRawHeaderBuf = '\0';
  173. }
  174. *lppszOutStr = lpszRawHeaderBuf;
  175. *lpdwSize = dwcbRawHeaderBuf;
  176. DEBUG_LEAVE(error);
  177. return error;
  178. }
  179. /*-----------------------------------------------------------------------------
  180. CrackAuthenticationHeader
  181. Routine Description:
  182. Attempts to decode a HTTP 1.1 Authentication header into its
  183. components.
  184. Arguments:
  185. hRequestMapped - Mapped Request handle
  186. fIsProxy - Whether proxy or server auth
  187. lpdwAuthenticationIndex - Index of current HTTP header. ( initally called with 0 )
  188. lppszAuthHeader - allocated pointer which should be freed by client
  189. lppszAuthScheme - Pointer to Authentication scheme string.
  190. lppszRealm - Pointer to Realm string,
  191. lpExtra - Pointer to any Extra String data in the header that is not
  192. part of the Realm
  193. lpdwExtra - Pointer to Size of Extra data.
  194. lppszAuthScheme
  195. Return Value:
  196. DWORD
  197. Success - ERROR_SUCCESS
  198. Failure - ERROR_NOT_ENOUGH_MEMORY,
  199. ERROR_HTTP_HEADER_NOT_FOUND
  200. Comments:
  201. -----------------------------------------------------------------------------*/
  202. DWORD PLUG_CTX::CrackAuthenticationHeader
  203. (
  204. IN HINTERNET hRequestMapped,
  205. IN BOOL fIsProxy,
  206. IN DWORD dwAuthenticationIndex,
  207. IN OUT LPSTR *lppszAuthHeader,
  208. IN OUT LPSTR *lppszExtra,
  209. IN OUT DWORD *lpdwExtra,
  210. OUT LPSTR *lppszAuthScheme
  211. )
  212. {
  213. DEBUG_ENTER ((
  214. DBG_HTTPAUTH,
  215. Dword,
  216. "PLUG_CTX::CrackAuthenticationHeader",
  217. "this=%#x request=%#x isproxy=%B authidx=%d ppszAuthHeader=%#x ppszExtra=%#x pdwExtra=%#x ppszAuthScheme=%#x",
  218. this,
  219. hRequestMapped,
  220. fIsProxy,
  221. dwAuthenticationIndex,
  222. lppszAuthHeader,
  223. lppszExtra,
  224. lpdwExtra,
  225. lppszAuthScheme
  226. ));
  227. DWORD error = ERROR_SUCCESS;
  228. LPSTR lpszAuthHeader = NULL;
  229. DWORD cbAuthHeader = 0;
  230. LPSTR lpszExtra = NULL;
  231. LPSTR lpszAuthScheme = NULL;
  232. LPDWORD lpdwAuthenticationIndex = &dwAuthenticationIndex;
  233. INET_ASSERT(lpdwExtra);
  234. INET_ASSERT(lppszExtra);
  235. INET_ASSERT(lpdwAuthenticationIndex);
  236. DWORD dwQuery = fIsProxy?
  237. HTTP_QUERY_PROXY_AUTHENTICATE : HTTP_QUERY_WWW_AUTHENTICATE;
  238. error = wQueryHeadersAlloc (hRequestMapped, dwQuery,
  239. lpdwAuthenticationIndex, &lpszAuthHeader, &cbAuthHeader);
  240. if ( error != ERROR_SUCCESS )
  241. {
  242. INET_ASSERT(*lpdwAuthenticationIndex
  243. || error == ERROR_HTTP_HEADER_NOT_FOUND );
  244. goto quit;
  245. }
  246. //
  247. // Parse Header for Scheme type
  248. //
  249. lpszAuthScheme = lpszAuthHeader;
  250. while ( *lpszAuthScheme == ' ' ) // strip spaces
  251. lpszAuthScheme++;
  252. lpszExtra = strchr(lpszAuthScheme, ' ');
  253. if (lpszExtra)
  254. *lpszExtra++ = '\0';
  255. if (lstrcmpi(GetScheme(), lpszAuthScheme))
  256. {
  257. DEBUG_PRINT(
  258. HTTPAUTH,
  259. ERROR,
  260. ("Authentication: HTTP Scheme has changed!: Scheme=%q\n", lpszAuthScheme)
  261. );
  262. goto quit;
  263. }
  264. DEBUG_PRINT(
  265. HTTPAUTH,
  266. INFO,
  267. ("Authentication: found in headers: Scheme=%q, Extra=%q\n",
  268. lpszAuthScheme, lpszExtra)
  269. );
  270. quit:
  271. *lppszExtra = lpszExtra;
  272. *lpdwExtra = lpszExtra ? lstrlen(lpszExtra) : 0;
  273. *lppszAuthHeader = lpszAuthHeader;
  274. *lppszAuthScheme = lpszAuthScheme;
  275. DEBUG_LEAVE(error);
  276. return error;
  277. }
  278. /*---------------------------------------------------------------------------
  279. ResolveProtocol
  280. ---------------------------------------------------------------------------*/
  281. VOID PLUG_CTX::ResolveProtocol()
  282. {
  283. DEBUG_ENTER ((
  284. DBG_HTTPAUTH,
  285. None,
  286. "PLUG_CTX::ResolveProtocol",
  287. "this=%#x",
  288. this
  289. ));
  290. SECURITY_STATUS ssResult;
  291. PWINCONTEXT pWinContext;
  292. SecPkgContext_NegotiationInfo SecPkgCtxtInfo;
  293. INET_ASSERT(GetSchemeType() == SCHEME_NEGOTIATE);
  294. SecPkgCtxtInfo.PackageInfo = NULL;
  295. // Call QueryContextAttributes on the context handle.
  296. pWinContext = (PWINCONTEXT) (_pvContext);
  297. ssResult = (*(g_pSspData->pFuncTbl->QueryContextAttributes))
  298. (pWinContext->pSspContextHandle, SECPKG_ATTR_NEGOTIATION_INFO, &SecPkgCtxtInfo);
  299. if (ssResult == SEC_E_OK
  300. && (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_COMPLETE
  301. || (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_OPTIMISTIC)))
  302. {
  303. // Resolve actual auth protocol from package name.
  304. // update both the auth context and pwc entry.
  305. if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "NTLM"))
  306. {
  307. _eSubScheme = SCHEME_NTLM;
  308. _dwSubFlags = PLUGIN_AUTH_FLAGS_NO_REALM;
  309. }
  310. else if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "Kerberos"))
  311. {
  312. _eSubScheme = SCHEME_KERBEROS;
  313. _dwSubFlags = PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_NO_REALM;
  314. }
  315. DEBUG_PRINT(
  316. HTTPAUTH,
  317. INFO,
  318. ("Negotiate package is using %s\n", SecPkgCtxtInfo.PackageInfo->Name)
  319. );
  320. }
  321. if( SecPkgCtxtInfo.PackageInfo )
  322. {
  323. (*(g_pSspData->pFuncTbl->FreeContextBuffer))(SecPkgCtxtInfo.PackageInfo);
  324. }
  325. DEBUG_LEAVE(0);
  326. }
  327. /*---------------------------------------------------------------------------
  328. Constructor
  329. ---------------------------------------------------------------------------*/
  330. PLUG_CTX::PLUG_CTX(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy,
  331. SPMData *pSPM, PWC* pPWC)
  332. : AUTHCTX(pSPM, pPWC)
  333. {
  334. DEBUG_ENTER ((
  335. DBG_HTTPAUTH,
  336. Pointer,
  337. "PLUG_CTX::PLUG_CTX",
  338. "this=%#x request=%#x isproxy=%B pSPM=%#x pPWC=%#x",
  339. this,
  340. pRequest,
  341. fIsProxy,
  342. pSPM,
  343. pPWC
  344. ));
  345. _fIsProxy = fIsProxy;
  346. _pRequest = pRequest;
  347. _szAlloc = NULL;
  348. _szData = NULL;
  349. _cbData = 0;
  350. _pRequest->SetAuthState(AUTHSTATE_NONE);
  351. _fNTLMProxyAuth = _fIsProxy && (GetSchemeType() == SCHEME_NTLM );
  352. _SecStatus = 0;
  353. _dwResolutionId = 0;
  354. DEBUG_LEAVE(this);
  355. }
  356. /*---------------------------------------------------------------------------
  357. Destructor
  358. ---------------------------------------------------------------------------*/
  359. PLUG_CTX::~PLUG_CTX()
  360. {
  361. DEBUG_ENTER ((
  362. DBG_HTTPAUTH,
  363. None,
  364. "PLUG_CTX::~PLUG_CTX",
  365. "this=%#x",
  366. this
  367. ));
  368. if (GetState() == AUTHCTX::STATE_LOADED)
  369. {
  370. if (_pPWC)
  371. {
  372. ClearAuthUser(&_pvContext, _pPWC->lpszHost);
  373. }
  374. }
  375. if (_pRequest)
  376. {
  377. _pRequest->SetAuthState(AUTHSTATE_NONE);
  378. }
  379. DEBUG_LEAVE(0);
  380. }
  381. PCSTR PLUG_CTX::GetUrl(void) const
  382. {
  383. return _pRequest->GetURL();
  384. }
  385. /*---------------------------------------------------------------------------
  386. PreAuthUser
  387. ---------------------------------------------------------------------------*/
  388. DWORD PLUG_CTX::PreAuthUser(OUT LPSTR pBuf, IN OUT LPDWORD pcbBuf)
  389. {
  390. DEBUG_ENTER ((
  391. DBG_HTTPAUTH,
  392. Dword,
  393. "PLUG_CTX::PreAuthUser",
  394. "this=%#x",
  395. this
  396. ));
  397. INET_ASSERT(_pSPMData == _pPWC->pSPM);
  398. AuthLock();
  399. DWORD dwError;
  400. SECURITY_STATUS ssResult;
  401. PSTR lpszPass = _pPWC->GetPass();
  402. // Make sure the auth provider is loaded.
  403. if (GetState() != AUTHCTX::STATE_LOADED)
  404. {
  405. if (GetState() != AUTHCTX::STATE_ERROR )
  406. Load();
  407. if (GetState() != AUTHCTX::STATE_LOADED)
  408. {
  409. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  410. goto exit;
  411. }
  412. }
  413. __try
  414. {
  415. ssResult = SEC_E_INTERNAL_ERROR;
  416. DEBUG_ENTER ((
  417. DBG_HTTPAUTH,
  418. Dword,
  419. "PreAuthenticateUser",
  420. "ctx=%#x host=%s scheme=%s {buf=%x (%.16s...) cbbuf=%d} user=%s pass=%s",
  421. _pvContext,
  422. _pPWC->lpszHost,
  423. InternetMapAuthScheme(GetSchemeType()),
  424. pBuf,
  425. pBuf,
  426. *pcbBuf,
  427. _pPWC->lpszUser,
  428. lpszPass
  429. ));
  430. LPSTR lpszFQDN = (LPSTR)GetFQDN((LPCSTR)_pPWC->lpszHost);
  431. LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pPWC->lpszHost;
  432. dwError = PreAuthenticateUser(&_pvContext,
  433. lpszHostName,
  434. GetScheme(),
  435. 0, // dwFlags
  436. pBuf,
  437. pcbBuf,
  438. _pPWC->lpszUser,
  439. lpszPass,
  440. GetUrl(),
  441. &ssResult);
  442. DEBUG_PRINT(HTTPAUTH, INFO, ("ssres: %#x [%s]\n", ssResult, InternetMapError(ssResult)));
  443. DEBUG_LEAVE(dwError);
  444. // Transit to the correct auth state.
  445. if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)
  446. {
  447. if (GetSchemeType() == SCHEME_NEGOTIATE)
  448. ResolveProtocol();
  449. // Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
  450. // Negotiate does not transit to challenge.
  451. // Any other protocol + SEC_E_OK only transits to challenge.
  452. if ((GetSchemeType() == SCHEME_KERBEROS
  453. && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED))
  454. || (GetSchemeType() != SCHEME_NEGOTIATE && ssResult == SEC_E_OK))
  455. {
  456. _pRequest->SetAuthState(AUTHSTATE_CHALLENGE);
  457. }
  458. }
  459. }
  460. __except(EXCEPTION_EXECUTE_HANDLER)
  461. {
  462. DEBUG_PRINT (HTTPAUTH, ERROR, ("PreAuthenticateUser call down faulted\n"));
  463. _pSPMData->eState = STATE_ERROR;
  464. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  465. }
  466. ENDEXCEPT
  467. DEBUG_PRINT(
  468. HTTPAUTH,
  469. INFO,
  470. (
  471. "request %#x [%s] now in %s using %s\n",
  472. _pRequest,
  473. _pPWC->lpszHost,
  474. InternetMapAuthState(_pRequest->GetAuthState()),
  475. InternetMapAuthScheme(GetSchemeType())
  476. )
  477. );
  478. exit:
  479. if (lpszPass)
  480. {
  481. memset(lpszPass, 0, strlen(lpszPass));
  482. FREE_MEMORY(lpszPass);
  483. }
  484. AuthUnlock();
  485. DEBUG_LEAVE(dwError);
  486. return dwError;
  487. }
  488. /*---------------------------------------------------------------------------
  489. UpdateFromHeaders
  490. ---------------------------------------------------------------------------*/
  491. DWORD PLUG_CTX::UpdateFromHeaders(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy)
  492. {
  493. DEBUG_ENTER ((
  494. DBG_HTTPAUTH,
  495. Dword,
  496. "PLUG_CTX::UpdateFromHeaders",
  497. "this=%#x request=%#x isproxy=%B",
  498. this,
  499. pRequest,
  500. fIsProxy
  501. ));
  502. DWORD dwError, cbExtra, dwAuthIdx;
  503. LPSTR szAuthHeader, szExtra, szScheme;
  504. AuthLock();
  505. // Get the auth header index corresponding to the scheme of this ctx.
  506. if ((dwError = FindHdrIdxFromScheme(&dwAuthIdx)) != ERROR_SUCCESS)
  507. goto quit;
  508. // Get the scheme and any extra data.
  509. if ((dwError = CrackAuthenticationHeader(pRequest, fIsProxy, dwAuthIdx,
  510. &szAuthHeader, &szExtra, &cbExtra, &szScheme)) != ERROR_SUCCESS)
  511. goto quit;
  512. if (!cbExtra)
  513. _pRequest->SetAuthState(AUTHSTATE_NEGOTIATE);
  514. // Check if auth scheme requires keep-alive.
  515. if (!(GetFlags() & PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED))
  516. {
  517. // if in negotiate phase check if we are going via proxy.
  518. if (pRequest->GetAuthState() == AUTHSTATE_NEGOTIATE)
  519. {
  520. // BUGBUG: if via proxy, we are not going to get keep-alive
  521. // connection to the server. It would be nice if we knew
  522. // a priori the whether proxy would allow us to tunnel to
  523. // http port on the server. Otherwise if we try and fail,
  524. // we look bad vs. other browsers who are ignorant of ntlm
  525. // and fall back to basic.
  526. CHAR szBuffer[64];
  527. DWORD dwBufferLength = sizeof(szBuffer);
  528. DWORD dwIndex = 0;
  529. BOOL fSessionBasedAuth = FALSE;
  530. if (pRequest->QueryResponseHeader(HTTP_QUERY_PROXY_SUPPORT,
  531. szBuffer, &dwBufferLength,
  532. 0, &dwIndex) == ERROR_SUCCESS)
  533. {
  534. if (!_stricmp(szBuffer, "Session-Based-Authentication"))
  535. {
  536. fSessionBasedAuth = TRUE;
  537. }
  538. }
  539. if (!fIsProxy && pRequest->IsRequestUsingProxy()
  540. && !pRequest->IsTalkingToSecureServerViaProxy() && !fSessionBasedAuth)
  541. {
  542. // Ignore NTLM via proxy since we won't get k-a to server.
  543. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  544. goto quit;
  545. }
  546. }
  547. // Else if in challenge phase, we require a persistent connection.
  548. else
  549. {
  550. // If we don't have a keep-alive connection ...
  551. if (!(pRequest->IsPersistentConnection (fIsProxy)) && !(pRequest->IsRequestUsingProxy()))
  552. {
  553. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  554. goto quit;
  555. }
  556. }
  557. } // end if keep-alive required
  558. quit:
  559. if (dwError == ERROR_SUCCESS)
  560. {
  561. // If no password cache is set in the auth context,
  562. // find or create one and set it in the handle.
  563. if (!_pPWC)
  564. {
  565. _pPWC = FindOrCreatePWC(pRequest, fIsProxy, _pSPMData, NULL);
  566. if (!_pPWC)
  567. {
  568. INET_ASSERT(FALSE);
  569. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  570. }
  571. else
  572. {
  573. INET_ASSERT(_pPWC->pSPM == _pSPMData);
  574. _pPWC->nLockCount++;
  575. }
  576. }
  577. }
  578. if (dwError == ERROR_SUCCESS)
  579. {
  580. // Point to allocated data.
  581. _szAlloc = szAuthHeader;
  582. _szData = szExtra;
  583. _cbData = cbExtra;
  584. }
  585. else
  586. {
  587. // Free allocated data.
  588. if (_szAlloc)
  589. delete _szAlloc;
  590. _szAlloc = NULL;
  591. _szData = NULL;
  592. _cbData = 0;
  593. }
  594. DEBUG_PRINT(
  595. HTTPAUTH,
  596. INFO,
  597. (
  598. "request %#x [%s] now in %s using %s\n",
  599. _pRequest,
  600. _pPWC->lpszHost,
  601. InternetMapAuthState(_pRequest->GetAuthState()),
  602. InternetMapAuthScheme(GetSchemeType())
  603. )
  604. );
  605. // Return of non-success will cancel auth session.
  606. AuthUnlock();
  607. DEBUG_LEAVE(dwError);
  608. return dwError;
  609. }
  610. /*---------------------------------------------------------------------------
  611. PostAuthUser
  612. ---------------------------------------------------------------------------*/
  613. DWORD PLUG_CTX::PostAuthUser()
  614. {
  615. DEBUG_ENTER ((
  616. DBG_HTTPAUTH,
  617. Dword,
  618. "PLUG_CTX::PostAuthUser",
  619. "this=%#x",
  620. this
  621. ));
  622. INET_ASSERT(_pSPMData == _pPWC->pSPM);
  623. AuthLock();
  624. DWORD dwError;
  625. PSTR lpszPass = _pPWC->GetPass();
  626. // Make sure the auth provider is loaded.
  627. if (GetState() != AUTHCTX::STATE_LOADED)
  628. {
  629. if (GetState() != AUTHCTX::STATE_ERROR )
  630. Load();
  631. if (GetState() != AUTHCTX::STATE_LOADED)
  632. {
  633. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  634. goto exit;
  635. }
  636. }
  637. BOOL fCanUseLogon = _fIsProxy || _pRequest->GetCredPolicy()
  638. == URLPOLICY_CREDENTIALS_SILENT_LOGON_OK;
  639. SECURITY_STATUS ssResult;
  640. __try
  641. {
  642. ssResult = SEC_E_INTERNAL_ERROR;
  643. DEBUG_ENTER ((
  644. DBG_HTTPAUTH,
  645. Dword,
  646. "AuthenticateUser",
  647. "ctx=%#x host=%s scheme=%s {data=%#x (%.16s...) cbdata=%d} user=%s pass=%s",
  648. _pvContext,
  649. _pPWC->lpszHost,
  650. InternetMapAuthScheme(GetSchemeType()),
  651. _szData,
  652. _szData,
  653. _cbData,
  654. _pPWC->lpszUser,
  655. lpszPass
  656. ));
  657. LPSTR lpszFQDN = (LPSTR)GetFQDN((LPCSTR)_pPWC->lpszHost);
  658. LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pPWC->lpszHost;
  659. dwError = AuthenticateUser(&_pvContext,
  660. lpszHostName,
  661. GetScheme(),
  662. fCanUseLogon,
  663. _szData,
  664. _cbData,
  665. _pPWC->lpszUser,
  666. lpszPass,
  667. GetUrl(),
  668. &ssResult);
  669. _SecStatus = ssResult;
  670. DEBUG_PRINT(HTTPAUTH, INFO, ("ssres: %#x [%s]\n", ssResult, InternetMapError(ssResult)));
  671. DEBUG_LEAVE(dwError);
  672. // Kerberos package can get into a bad state.
  673. if (GetSchemeType() == SCHEME_KERBEROS && ssResult == SEC_E_WRONG_PRINCIPAL)
  674. dwError = ERROR_INTERNET_INCORRECT_PASSWORD;
  675. // Transit to the correct auth state.
  676. if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)
  677. {
  678. if (GetSchemeType() == SCHEME_NEGOTIATE)
  679. ResolveProtocol();
  680. // Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
  681. // Negotiate does not transit to challenge.
  682. // Any other protocol + SEC_E_OK only transits to challenge.
  683. if ((GetSchemeType() == SCHEME_KERBEROS
  684. && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED))
  685. || (GetSchemeType() != SCHEME_NEGOTIATE && ssResult == SEC_E_OK))
  686. {
  687. _pRequest->SetAuthState(AUTHSTATE_CHALLENGE);
  688. }
  689. }
  690. }
  691. __except (EXCEPTION_EXECUTE_HANDLER)
  692. {
  693. DEBUG_PRINT (HTTPAUTH, ERROR, ("AuthenticateUser faulted!\n"));
  694. dwError = ERROR_BAD_FORMAT;
  695. _pSPMData->eState = STATE_ERROR;
  696. }
  697. ENDEXCEPT
  698. if (_szAlloc)
  699. {
  700. delete _szAlloc;
  701. _szAlloc = NULL;
  702. _szData = NULL;
  703. }
  704. _cbData = 0;
  705. DEBUG_PRINT(
  706. HTTPAUTH,
  707. INFO,
  708. (
  709. "request %#x [%s] now in %s using %s\n",
  710. _pRequest,
  711. _pPWC->lpszHost,
  712. InternetMapAuthState(_pRequest->GetAuthState()),
  713. InternetMapAuthScheme(GetSchemeType())
  714. )
  715. );
  716. exit:
  717. if (lpszPass)
  718. {
  719. memset(lpszPass, 0, strlen(lpszPass));
  720. FREE_MEMORY(lpszPass);
  721. }
  722. AuthUnlock();
  723. DEBUG_LEAVE(dwError);
  724. return dwError;
  725. }
  726. LPCSTR PLUG_CTX::GetFQDN(LPCSTR lpszHostName)
  727. {
  728. if (lstrcmpi(GetScheme(), "Negotiate")) // only need to get FQDN for Kerberos
  729. {
  730. return NULL;
  731. }
  732. if (_pszFQDN)
  733. {
  734. return _pszFQDN;
  735. }
  736. LPRESOLVER_CACHE_ENTRY lpResolverCacheEntry;
  737. DWORD TTL;
  738. LPADDRINFO lpAddrInfo;
  739. if (lpResolverCacheEntry = QueryResolverCache((LPSTR)lpszHostName, NULL, &lpAddrInfo, &TTL))
  740. {
  741. _pszFQDN = (lpAddrInfo->ai_canonname ? NewString(lpAddrInfo->ai_canonname) : NULL);
  742. ReleaseResolverCacheEntry(lpResolverCacheEntry);
  743. return _pszFQDN;
  744. }
  745. /*
  746. CAddressList TempAddressList;
  747. DWORD dwResolutionId;
  748. TempAddressList.ResolveHost((LPSTR)lpszHostName, &_dwResolutionId, SF_FORCE);
  749. if (lpResolverCacheEntry = QueryResolverCache((LPSTR)lpszHostName, NULL, &lpAddrInfo, &TTL))
  750. {
  751. _pszFQDN = (lpAddrInfo->ai_canonname ? NewString(lpAddrInfo->ai_canonname) : NULL);
  752. ReleaseResolverCacheEntry(lpResolverCacheEntry);
  753. return _pszFQDN;
  754. }
  755. */
  756. return NULL;
  757. }