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.

701 lines
21 KiB

  1. #include <wininetp.h>
  2. #include <splugin.hxx>
  3. #include "auth.h"
  4. #include "sspspm.h"
  5. #include "winctxt.h"
  6. extern SspData *g_pSspData;
  7. /*-----------------------------------------------------------------------------
  8. PLUG_CTX
  9. -----------------------------------------------------------------------------*/
  10. /*---------------------------------------------------------------------------
  11. Load
  12. ---------------------------------------------------------------------------*/
  13. DWORD PLUG_CTX::Load()
  14. {
  15. INET_ASSERT(_pSPMData == _pCreds->pSPM);
  16. DWORD_PTR dwAuthCode = 0;
  17. dwAuthCode = SSPI_InitScheme (GetScheme());
  18. if (!dwAuthCode)
  19. {
  20. _pSPMData->eState = STATE_ERROR;
  21. return ERROR_WINHTTP_INTERNAL_ERROR;
  22. }
  23. _pSPMData->eState = STATE_LOADED;
  24. return ERROR_SUCCESS;
  25. }
  26. /*---------------------------------------------------------------------------
  27. ClearAuthUser
  28. ---------------------------------------------------------------------------*/
  29. DWORD PLUG_CTX::ClearAuthUser(LPVOID *ppvContext, LPSTR szServer)
  30. {
  31. if (GetState() == AUTHCTX::STATE_LOADED)
  32. {
  33. __try
  34. {
  35. UnloadAuthenticateUser(ppvContext, szServer, GetScheme());
  36. }
  37. __except (EXCEPTION_EXECUTE_HANDLER)
  38. {
  39. DEBUG_PRINT(HTTP, ERROR,
  40. ("UnloadAuthenticateUser call down faulted\n"));
  41. }
  42. ENDEXCEPT
  43. }
  44. *ppvContext = 0;
  45. return ERROR_SUCCESS;
  46. }
  47. /*-----------------------------------------------------------------------------
  48. wQueryHeadersAlloc
  49. Routine Description:
  50. Allocates a HTTP Header String, and queries the HTTP handle for it.
  51. Arguments:
  52. hRequestMapped - An open HTTP request handle
  53. where headers can be quiered
  54. dwQuery - The Query Type to pass to HttpQueryHeaders
  55. lpdwQueryIndex - The Index of the header to pass to HttpQueryHeaders,
  56. make sure to inialize to 0.
  57. lppszOutStr - On success, a pointer to Allocated string with header string,
  58. lpdwSize - size of the string returned in lppszOutStr
  59. Return Value:
  60. DWORD
  61. Success - ERROR_SUCCESS
  62. Failure - One of Several Error codes defined in winerror.h or wininet.w
  63. Comments:
  64. On Error, lppszOutStr may still contain an allocated string that will need to be
  65. freed.
  66. -----------------------------------------------------------------------------*/
  67. DWORD PLUG_CTX::wQueryHeadersAlloc
  68. (
  69. IN HINTERNET hRequestMapped,
  70. IN DWORD dwQuery,
  71. OUT LPDWORD lpdwQueryIndex,
  72. OUT LPSTR *lppszOutStr,
  73. OUT LPDWORD lpdwSize
  74. )
  75. {
  76. LPSTR lpszRawHeaderBuf = NULL;
  77. DWORD dwcbRawHeaderBuf = 0;
  78. DWORD error;
  79. DWORD length;
  80. HTTP_REQUEST_HANDLE_OBJECT * pHttpRequest;
  81. INET_ASSERT(lppszOutStr);
  82. INET_ASSERT(hRequestMapped);
  83. INET_ASSERT(lpdwSize);
  84. INET_ASSERT((dwQuery & HTTP_QUERY_HEADER_MASK) != HTTP_QUERY_CUSTOM);
  85. *lppszOutStr = NULL;
  86. error = ERROR_SUCCESS;
  87. pHttpRequest = (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
  88. // Attempt to determine whether our header is there.
  89. length = 0;
  90. if (pHttpRequest->QueryInfo(dwQuery, NULL, NULL, &length, lpdwQueryIndex)
  91. != ERROR_INSUFFICIENT_BUFFER)
  92. {
  93. // no authentication happening, we're done
  94. error = ERROR_HTTP_HEADER_NOT_FOUND;
  95. goto quit;
  96. }
  97. // Allocate a Fixed Size Buffer
  98. lpszRawHeaderBuf = (LPSTR) ALLOCATE_ZERO_MEMORY(length);
  99. dwcbRawHeaderBuf = length;
  100. if ( lpszRawHeaderBuf == NULL )
  101. {
  102. error = ERROR_NOT_ENOUGH_MEMORY;
  103. goto quit;
  104. }
  105. error = pHttpRequest->QueryInfo
  106. (dwQuery, NULL, lpszRawHeaderBuf, &dwcbRawHeaderBuf, lpdwQueryIndex);
  107. INET_ASSERT(error != ERROR_INSUFFICIENT_BUFFER );
  108. INET_ASSERT(error != ERROR_HTTP_HEADER_NOT_FOUND );
  109. quit:
  110. if ( error != ERROR_SUCCESS )
  111. {
  112. dwcbRawHeaderBuf = 0;
  113. if ( lpszRawHeaderBuf )
  114. *lpszRawHeaderBuf = '\0';
  115. }
  116. *lppszOutStr = lpszRawHeaderBuf;
  117. *lpdwSize = dwcbRawHeaderBuf;
  118. return error;
  119. }
  120. /*-----------------------------------------------------------------------------
  121. CrackAuthenticationHeader
  122. Routine Description:
  123. Attempts to decode a HTTP 1.1 Authentication header into its
  124. components.
  125. Arguments:
  126. hRequestMapped - Mapped Request handle
  127. fIsProxy - Whether proxy or server auth
  128. lpdwAuthenticationIndex - Index of current HTTP header. ( initally called with 0 )
  129. lppszAuthHeader - allocated pointer which should be freed by client
  130. lppszAuthScheme - Pointer to Authentication scheme string.
  131. lppszRealm - Pointer to Realm string,
  132. lpExtra - Pointer to any Extra String data in the header that is not
  133. part of the Realm
  134. lpdwExtra - Pointer to Size of Extra data.
  135. lppszAuthScheme
  136. Return Value:
  137. DWORD
  138. Success - ERROR_SUCCESS
  139. Failure - ERROR_NOT_ENOUGH_MEMORY,
  140. ERROR_HTTP_HEADER_NOT_FOUND
  141. Comments:
  142. -----------------------------------------------------------------------------*/
  143. DWORD PLUG_CTX::CrackAuthenticationHeader
  144. (
  145. IN HINTERNET hRequestMapped,
  146. IN BOOL fIsProxy,
  147. IN DWORD dwAuthenticationIndex,
  148. IN OUT LPSTR *lppszAuthHeader,
  149. IN OUT LPSTR *lppszExtra,
  150. IN OUT DWORD *lpdwExtra,
  151. OUT LPSTR *lppszAuthScheme
  152. )
  153. {
  154. DWORD error = ERROR_SUCCESS;
  155. LPSTR lpszAuthHeader = NULL;
  156. DWORD cbAuthHeader = 0;
  157. LPSTR lpszExtra = NULL;
  158. LPSTR lpszAuthScheme = NULL;
  159. LPDWORD lpdwAuthenticationIndex = &dwAuthenticationIndex;
  160. INET_ASSERT(lpdwExtra);
  161. INET_ASSERT(lppszExtra);
  162. INET_ASSERT(lpdwAuthenticationIndex);
  163. DWORD dwQuery = fIsProxy?
  164. HTTP_QUERY_PROXY_AUTHENTICATE : HTTP_QUERY_WWW_AUTHENTICATE;
  165. error = wQueryHeadersAlloc (hRequestMapped, dwQuery,
  166. lpdwAuthenticationIndex, &lpszAuthHeader, &cbAuthHeader);
  167. if ( error != ERROR_SUCCESS )
  168. {
  169. INET_ASSERT(*lpdwAuthenticationIndex
  170. || error == ERROR_HTTP_HEADER_NOT_FOUND );
  171. goto quit;
  172. }
  173. //
  174. // Parse Header for Scheme type
  175. //
  176. lpszAuthScheme = lpszAuthHeader;
  177. while ( *lpszAuthScheme == ' ' ) // strip spaces
  178. lpszAuthScheme++;
  179. lpszExtra = strchr(lpszAuthScheme, ' ');
  180. if (lpszExtra)
  181. *lpszExtra++ = '\0';
  182. if (lstrcmpi(GetScheme(), lpszAuthScheme))
  183. {
  184. DEBUG_PRINT(HTTP, ERROR,
  185. ("Authentication: HTTP Scheme has changed!: Scheme=%q\n",
  186. lpszAuthScheme));
  187. goto quit;
  188. }
  189. DEBUG_PRINT (HTTP, INFO,
  190. ("Authentication: found in headers: Scheme=%q, Extra=%q\n",
  191. lpszAuthScheme, lpszExtra));
  192. quit:
  193. *lppszExtra = lpszExtra;
  194. *lpdwExtra = lpszExtra ? lstrlen(lpszExtra) : 0;
  195. *lppszAuthHeader = lpszAuthHeader;
  196. *lppszAuthScheme = lpszAuthScheme;
  197. return error;
  198. }
  199. /*---------------------------------------------------------------------------
  200. ResolveProtocol
  201. ---------------------------------------------------------------------------*/
  202. VOID PLUG_CTX::ResolveProtocol()
  203. {
  204. SECURITY_STATUS ssResult;
  205. PWINCONTEXT pWinContext;
  206. SecPkgContext_NegotiationInfo SecPkgCtxtInfo;
  207. INET_ASSERT(GetSchemeType() == WINHTTP_AUTH_SCHEME_NEGOTIATE);
  208. SecPkgCtxtInfo.PackageInfo = NULL;
  209. // Call QueryContextAttributes on the context handle.
  210. pWinContext = (PWINCONTEXT) (_pvContext);
  211. ssResult = (*(g_pSspData->pFuncTbl->QueryContextAttributes))
  212. (pWinContext->pSspContextHandle, SECPKG_ATTR_NEGOTIATION_INFO, &SecPkgCtxtInfo);
  213. if (ssResult == SEC_E_OK
  214. && (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_COMPLETE
  215. || (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_OPTIMISTIC)))
  216. {
  217. // Resolve actual auth protocol from package name.
  218. // update both the auth context and Creds entry.
  219. if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "NTLM"))
  220. {
  221. _eSubScheme = WINHTTP_AUTH_SCHEME_NTLM;
  222. _dwSubFlags = PLUGIN_AUTH_FLAGS_NO_REALM;
  223. }
  224. else if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "Kerberos"))
  225. {
  226. _eSubScheme = WINHTTP_AUTH_SCHEME_KERBEROS;
  227. _dwSubFlags = PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_NO_REALM;
  228. }
  229. // BUGBUG - This faults.
  230. //
  231. }
  232. if (SecPkgCtxtInfo.PackageInfo)
  233. {
  234. (*(g_pSspData->pFuncTbl->FreeContextBuffer))(SecPkgCtxtInfo.PackageInfo);
  235. }
  236. }
  237. /*---------------------------------------------------------------------------
  238. Constructor
  239. ---------------------------------------------------------------------------*/
  240. PLUG_CTX::PLUG_CTX(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy,
  241. SPMData *pSPM, AUTH_CREDS* pCreds)
  242. : AUTHCTX(pSPM, pCreds)
  243. {
  244. _fIsProxy = fIsProxy;
  245. _pRequest = pRequest;
  246. _szAlloc = NULL;
  247. _szData = NULL;
  248. _cbData = 0;
  249. _pRequest->SetAuthState(AUTHSTATE_NONE);
  250. _fNTLMProxyAuth = _fIsProxy && (GetSchemeType() == WINHTTP_AUTH_SCHEME_NTLM);
  251. _pszFQDN = NULL;
  252. _fChallengeSeen = FALSE;
  253. }
  254. /*---------------------------------------------------------------------------
  255. Destructor
  256. ---------------------------------------------------------------------------*/
  257. PLUG_CTX::~PLUG_CTX()
  258. {
  259. if (GetState() == AUTHCTX::STATE_LOADED)
  260. {
  261. if (_pCreds)
  262. {
  263. if (_CtxCriSec.Lock())
  264. {
  265. ClearAuthUser(&_pvContext, _pCreds->lpszHost);
  266. _CtxCriSec.Unlock();
  267. }
  268. }
  269. }
  270. if (_pRequest)
  271. {
  272. _pRequest->SetAuthState(AUTHSTATE_NONE);
  273. }
  274. if (_pszFQDN)
  275. {
  276. FREE_MEMORY(_pszFQDN);
  277. }
  278. }
  279. /*---------------------------------------------------------------------------
  280. PreAuthUser
  281. ---------------------------------------------------------------------------*/
  282. DWORD PLUG_CTX::PreAuthUser(OUT LPSTR pBuf, IN OUT LPDWORD pcbBuf)
  283. {
  284. if (!_CtxCriSec.Lock())
  285. {
  286. return ERROR_NOT_ENOUGH_MEMORY;
  287. }
  288. INET_ASSERT(_pSPMData == _pCreds->pSPM);
  289. DWORD dwError;
  290. SECURITY_STATUS ssResult;
  291. // Make sure the auth provider is loaded.
  292. if (GetState() != AUTHCTX::STATE_LOADED)
  293. {
  294. if (GetState() != AUTHCTX::STATE_ERROR )
  295. Load();
  296. if (GetState() != AUTHCTX::STATE_LOADED)
  297. {
  298. dwError = ERROR_WINHTTP_INTERNAL_ERROR;
  299. goto exit;
  300. }
  301. }
  302. BOOL fCanUseLogon = _fIsProxy
  303. ? _pRequest->SilentLogonToProxyOK()
  304. : _pRequest->SilentLogonOK(_pCreds->lpszHost);
  305. LPSTR lpszFQDN = GetFQDN(_pCreds->lpszHost);
  306. LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pCreds->lpszHost;
  307. LPSTR lpszPass = _pCreds->GetPass();
  308. __try
  309. {
  310. ssResult = SEC_E_INTERNAL_ERROR;
  311. dwError = PreAuthenticateUser(&_pvContext,
  312. lpszHostName,
  313. GetScheme(),
  314. fCanUseLogon,
  315. 0, // dwFlags
  316. pBuf,
  317. pcbBuf,
  318. _pCreds->lpszUser,
  319. lpszPass,
  320. &ssResult);
  321. // Transit to the correct auth state.
  322. if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)
  323. {
  324. if (GetSchemeType() == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  325. ResolveProtocol();
  326. // Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
  327. // Negotiate does not transit to challenge.
  328. // Any other protocol + SEC_E_OK only transits to challenge.
  329. if ((GetSchemeType() == WINHTTP_AUTH_SCHEME_KERBEROS
  330. && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED))
  331. || (GetSchemeType() != WINHTTP_AUTH_SCHEME_NEGOTIATE && ssResult == SEC_E_OK))
  332. {
  333. _pRequest->SetAuthState(AUTHSTATE_CHALLENGE);
  334. }
  335. }
  336. }
  337. __except(EXCEPTION_EXECUTE_HANDLER)
  338. {
  339. DEBUG_PRINT (HTTP, ERROR, ("preAuthenticateUser call down faulted\n"));
  340. _pSPMData->eState = STATE_ERROR;
  341. dwError = ERROR_WINHTTP_INTERNAL_ERROR;
  342. }
  343. ENDEXCEPT
  344. if (lpszPass)
  345. {
  346. SecureZeroMemory(lpszPass, strlen(lpszPass));
  347. FREE_MEMORY(lpszPass);
  348. }
  349. exit:
  350. _CtxCriSec.Unlock();
  351. return dwError;
  352. }
  353. /*---------------------------------------------------------------------------
  354. UpdateFromHeaders
  355. ---------------------------------------------------------------------------*/
  356. DWORD PLUG_CTX::UpdateFromHeaders(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy)
  357. {
  358. DWORD dwError, cbExtra = 0, dwAuthIdx;
  359. LPSTR szAuthHeader = NULL, szExtra = NULL, szScheme;
  360. // Get the auth header index corresponding to the scheme of this ctx.
  361. if ((dwError = FindHdrIdxFromScheme(&dwAuthIdx)) != ERROR_SUCCESS)
  362. goto quit;
  363. // Get the scheme and any extra data.
  364. if ((dwError = CrackAuthenticationHeader(pRequest, fIsProxy, dwAuthIdx,
  365. &szAuthHeader, &szExtra, &cbExtra, &szScheme)) != ERROR_SUCCESS)
  366. goto quit;
  367. if (!cbExtra)
  368. {
  369. if (_fChallengeSeen)
  370. {
  371. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  372. goto quit;
  373. }
  374. _pRequest->SetAuthState(AUTHSTATE_NEGOTIATE);
  375. }
  376. // Check if auth scheme requires keep-alive.
  377. if (!(GetFlags() & PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED))
  378. {
  379. // if in negotiate phase check if we are going via proxy.
  380. if (pRequest->GetAuthState() == AUTHSTATE_NEGOTIATE)
  381. {
  382. // BUGBUG: if via proxy, we are not going to get keep-alive
  383. // connection to the server. It would be nice if we knew
  384. // a priori the whether proxy would allow us to tunnel to
  385. // http port on the server. Otherwise if we try and fail,
  386. // we look bad vs. other browsers who are ignorant of ntlm
  387. // and fall back to basic.
  388. CHAR szBuffer[64];
  389. DWORD dwBufferLength = sizeof(szBuffer);
  390. DWORD dwIndex = 0;
  391. BOOL fSessionBasedAuth = FALSE;
  392. if (pRequest->QueryResponseHeader(HTTP_QUERY_PROXY_SUPPORT,
  393. szBuffer, &dwBufferLength,
  394. 0, &dwIndex) == ERROR_SUCCESS)
  395. {
  396. if (!_stricmp(szBuffer, "Session-Based-Authentication"))
  397. {
  398. fSessionBasedAuth = TRUE;
  399. }
  400. }
  401. if (!fIsProxy && pRequest->IsRequestUsingProxy()
  402. && !pRequest->IsTalkingToSecureServerViaProxy() && !fSessionBasedAuth)
  403. {
  404. // Ignore NTLM via proxy since we won't get k-a to server.
  405. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  406. goto quit;
  407. }
  408. }
  409. // Else if in challenge phase, we require a persistent connection.
  410. else
  411. {
  412. // If we don't have a keep-alive connection ...
  413. if (!(pRequest->IsPersistentConnection (fIsProxy)))
  414. {
  415. dwError = ERROR_HTTP_HEADER_NOT_FOUND;
  416. goto quit;
  417. }
  418. }
  419. } // end if keep-alive required
  420. _fChallengeSeen = TRUE;
  421. quit:
  422. if (dwError == ERROR_SUCCESS)
  423. {
  424. // If no password cache is set in the auth context,
  425. // find or create one and set it in the handle.
  426. if (!_pCreds)
  427. {
  428. _pCreds = CreateCreds(pRequest, fIsProxy, _pSPMData, NULL);
  429. if (!_pCreds)
  430. {
  431. INET_ASSERT(FALSE);
  432. dwError = ERROR_WINHTTP_INTERNAL_ERROR;
  433. }
  434. else
  435. {
  436. INET_ASSERT(_pCreds->pSPM == _pSPMData);
  437. }
  438. }
  439. }
  440. if (_szAlloc)
  441. {
  442. FREE_MEMORY(_szAlloc);
  443. _szAlloc = NULL;
  444. _szData = NULL;
  445. }
  446. if (dwError == ERROR_SUCCESS)
  447. {
  448. // Point to allocated data.
  449. _szAlloc = szAuthHeader;
  450. _szData = szExtra;
  451. _cbData = cbExtra;
  452. }
  453. else
  454. {
  455. // Free allocated data.
  456. _szAlloc = NULL;
  457. _szData = NULL;
  458. _cbData = 0;
  459. }
  460. // Return of non-success will cancel auth session.
  461. return dwError;
  462. }
  463. /*---------------------------------------------------------------------------
  464. PostAuthUser
  465. ---------------------------------------------------------------------------*/
  466. DWORD PLUG_CTX::PostAuthUser()
  467. {
  468. if (!_CtxCriSec.Lock())
  469. {
  470. return ERROR_NOT_ENOUGH_MEMORY;
  471. }
  472. INET_ASSERT(_pSPMData == _pCreds->pSPM);
  473. DWORD dwError;
  474. // Make sure the auth provider is loaded.
  475. if (GetState() != AUTHCTX::STATE_LOADED)
  476. {
  477. if (GetState() != AUTHCTX::STATE_ERROR )
  478. Load();
  479. if (GetState() != AUTHCTX::STATE_LOADED)
  480. {
  481. dwError = ERROR_WINHTTP_INTERNAL_ERROR;
  482. goto exit;
  483. }
  484. }
  485. BOOL fCanUseLogon = _fIsProxy
  486. ? _pRequest->SilentLogonToProxyOK()
  487. : _pRequest->SilentLogonOK(_pCreds->lpszHost);
  488. if (_fDisableAutoLogon)
  489. {
  490. fCanUseLogon = FALSE;
  491. }
  492. LPSTR lpszFQDN = GetFQDN(_pCreds->lpszHost);
  493. LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pCreds->lpszHost;
  494. LPSTR lpszPass = _pCreds->GetPass();
  495. SECURITY_STATUS ssResult;
  496. __try
  497. {
  498. ssResult = SEC_E_INTERNAL_ERROR;
  499. dwError = AuthenticateUser(&_pvContext,
  500. lpszHostName,
  501. GetScheme(),
  502. fCanUseLogon,
  503. _szData,
  504. _cbData,
  505. _pCreds->lpszUser,
  506. lpszPass,
  507. &ssResult);
  508. // Kerberos package can get into a bad state.
  509. if (GetSchemeType() == WINHTTP_AUTH_SCHEME_KERBEROS && ssResult == SEC_E_WRONG_PRINCIPAL)
  510. dwError = ERROR_WINHTTP_INCORRECT_PASSWORD;
  511. // Transit to the correct auth state.
  512. if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)
  513. {
  514. if (GetSchemeType() == WINHTTP_AUTH_SCHEME_NEGOTIATE)
  515. ResolveProtocol();
  516. // Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
  517. // Negotiate does not transit to challenge.
  518. // Any other protocol + SEC_E_OK only transits to challenge.
  519. if ((GetSchemeType() == WINHTTP_AUTH_SCHEME_KERBEROS
  520. && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED))
  521. || (GetSchemeType() != WINHTTP_AUTH_SCHEME_NEGOTIATE && ssResult == SEC_E_OK))
  522. {
  523. _pRequest->SetAuthState(AUTHSTATE_CHALLENGE);
  524. }
  525. }
  526. }
  527. __except (EXCEPTION_EXECUTE_HANDLER)
  528. {
  529. DEBUG_PRINT (HTTP, ERROR, ("AuthenticateUser faulted!\n"));
  530. dwError = ERROR_BAD_FORMAT;
  531. _pSPMData->eState = STATE_ERROR;
  532. }
  533. ENDEXCEPT
  534. if (_szAlloc)
  535. {
  536. FREE_MEMORY(_szAlloc);
  537. _szAlloc = NULL;
  538. _szData = NULL;
  539. }
  540. if (lpszPass)
  541. {
  542. SecureZeroMemory(lpszPass, strlen(lpszPass));
  543. FREE_MEMORY(lpszPass);
  544. }
  545. _cbData = 0;
  546. exit:
  547. _CtxCriSec.Unlock();
  548. return dwError;
  549. }
  550. LPSTR PLUG_CTX::GetFQDN(LPSTR lpszHostName)
  551. {
  552. if (lstrcmpi(GetScheme(), "Negotiate")) // only need to get FQDN for Kerberos
  553. {
  554. return NULL;
  555. }
  556. if (_pszFQDN)
  557. {
  558. return _pszFQDN;
  559. }
  560. SERIALIZED_LIST* pResolverCache = GetRootHandle(_pRequest)->GetResolverCache()->GetResolverCacheList();
  561. LPADDRINFO lpAddrInfo;
  562. DWORD TTL;
  563. LPRESOLVER_CACHE_ENTRY lpResolverCacheEntry;
  564. if ((lpResolverCacheEntry=QueryResolverCache(pResolverCache,
  565. (LPSTR)lpszHostName,
  566. NULL,
  567. &lpAddrInfo,
  568. &TTL)) != NULL)
  569. {
  570. _pszFQDN = (lpAddrInfo->ai_canonname ? NewString(lpAddrInfo->ai_canonname) : NULL);
  571. ReleaseResolverCacheEntry(pResolverCache, lpResolverCacheEntry);
  572. return _pszFQDN;
  573. }
  574. return NULL;
  575. }