|
|
#include <wininetp.h>
#include <urlmon.h>
#include <splugin.hxx>
#include "auth.h"
#include "sspspm.h"
#include "winctxt.h"
extern "C" { extern SspData *g_pSspData; } /*-----------------------------------------------------------------------------
PLUG_CTX -----------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Load ---------------------------------------------------------------------------*/ DWORD PLUG_CTX::Load() { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::Load", "this=%#x", this ));
INET_ASSERT(_pSPMData == _pPWC->pSPM);
DWORD_PTR dwAuthCode = 0;
DEBUG_ENTER (( DBG_HTTPAUTH, Pointer, "SSPI_InitScheme", "%s", GetScheme() ));
dwAuthCode = SSPI_InitScheme (GetScheme());
DEBUG_LEAVE(dwAuthCode);
if (!dwAuthCode) { _pSPMData->eState = STATE_ERROR; DEBUG_LEAVE(ERROR_INTERNET_INTERNAL_ERROR); return ERROR_INTERNET_INTERNAL_ERROR; }
_pSPMData->eState = STATE_LOADED; DEBUG_LEAVE(ERROR_SUCCESS); return ERROR_SUCCESS; }
/*---------------------------------------------------------------------------
ClearAuthUser ---------------------------------------------------------------------------*/ DWORD PLUG_CTX::ClearAuthUser(LPVOID *ppvContext, LPSTR szServer) { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::ClearAuthUser", "this=%#x ctx=%#x server=%.16s", this, *ppvContext, szServer ));
if (GetState() == AUTHCTX::STATE_LOADED) { AuthLock();
__try { DEBUG_ENTER (( DBG_HTTPAUTH, None, "UnloadAuthenticateUser", "ctx=%#x server=%s scheme=%s", *ppvContext, szServer, GetScheme() ));
UnloadAuthenticateUser(ppvContext, szServer, GetScheme());
DEBUG_LEAVE(0); } __except (EXCEPTION_EXECUTE_HANDLER) { DEBUG_PRINT( HTTPAUTH, ERROR, ("UnloadAuthenticateUser call down faulted\n") ); } ENDEXCEPT
AuthUnlock(); } *ppvContext = 0; DEBUG_LEAVE(ERROR_SUCCESS); return ERROR_SUCCESS; }
/*-----------------------------------------------------------------------------
wQueryHeadersAlloc
Routine Description:
Allocates a HTTP Header String, and queries the HTTP handle for it.
Arguments:
hRequestMapped - An open HTTP request handle where headers can be quiered dwQuery - The Query Type to pass to HttpQueryHeaders lpdwQueryIndex - The Index of the header to pass to HttpQueryHeaders, make sure to inialize to 0. lppszOutStr - On success, a pointer to Allocated string with header string, lpdwSize - size of the string returned in lppszOutStr
Return Value:
DWORD Success - ERROR_SUCCESS
Failure - One of Several Error codes defined in winerror.h or wininet.w
Comments:
On Error, lppszOutStr may still contain an allocated string that will need to be freed. -----------------------------------------------------------------------------*/ DWORD PLUG_CTX::wQueryHeadersAlloc ( IN HINTERNET hRequestMapped, IN DWORD dwQuery, OUT LPDWORD lpdwQueryIndex, OUT LPSTR *lppszOutStr, OUT LPDWORD lpdwSize ) { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::wQueryHeadersAlloc", "this=%#x request=%#x query=%d queryidx=%#x {%d} ppoutstr=%#x lpdwSize=%#x", this, hRequestMapped, dwQuery, lpdwQueryIndex, *lpdwQueryIndex, lppszOutStr, lpdwSize ));
LPSTR lpszRawHeaderBuf = NULL; DWORD dwcbRawHeaderBuf = 0; DWORD error; DWORD length; HTTP_REQUEST_HANDLE_OBJECT * pHttpRequest;
INET_ASSERT(lppszOutStr); INET_ASSERT(hRequestMapped); INET_ASSERT(lpdwSize);
*lppszOutStr = NULL; error = ERROR_SUCCESS; pHttpRequest = (HTTP_REQUEST_HANDLE_OBJECT *) hRequestMapped;
// Attempt to determine whether our header is there.
length = 0; if (pHttpRequest->QueryInfo(dwQuery, NULL, &length, lpdwQueryIndex) != ERROR_INSUFFICIENT_BUFFER) { // no authentication happening, we're done
error = ERROR_HTTP_HEADER_NOT_FOUND; goto quit; }
// Allocate a Fixed Size Buffer
lpszRawHeaderBuf = (LPSTR) ALLOCATE_MEMORY(LPTR, length); dwcbRawHeaderBuf = length;
if ( lpszRawHeaderBuf == NULL ) { error = ERROR_NOT_ENOUGH_MEMORY; goto quit; }
error = pHttpRequest->QueryInfo (dwQuery, lpszRawHeaderBuf, &dwcbRawHeaderBuf, lpdwQueryIndex);
INET_ASSERT(error != ERROR_INSUFFICIENT_BUFFER ); INET_ASSERT(error != ERROR_HTTP_HEADER_NOT_FOUND );
quit:
if ( error != ERROR_SUCCESS ) { dwcbRawHeaderBuf = 0;
if ( lpszRawHeaderBuf ) *lpszRawHeaderBuf = '\0'; }
*lppszOutStr = lpszRawHeaderBuf; *lpdwSize = dwcbRawHeaderBuf;
DEBUG_LEAVE(error); return error; }
/*-----------------------------------------------------------------------------
CrackAuthenticationHeader
Routine Description:
Attempts to decode a HTTP 1.1 Authentication header into its components.
Arguments:
hRequestMapped - Mapped Request handle fIsProxy - Whether proxy or server auth lpdwAuthenticationIndex - Index of current HTTP header. ( initally called with 0 ) lppszAuthHeader - allocated pointer which should be freed by client lppszAuthScheme - Pointer to Authentication scheme string. lppszRealm - Pointer to Realm string, lpExtra - Pointer to any Extra String data in the header that is not part of the Realm lpdwExtra - Pointer to Size of Extra data. lppszAuthScheme
Return Value:
DWORD Success - ERROR_SUCCESS
Failure - ERROR_NOT_ENOUGH_MEMORY, ERROR_HTTP_HEADER_NOT_FOUND
Comments: -----------------------------------------------------------------------------*/ DWORD PLUG_CTX::CrackAuthenticationHeader ( IN HINTERNET hRequestMapped, IN BOOL fIsProxy, IN DWORD dwAuthenticationIndex, IN OUT LPSTR *lppszAuthHeader, IN OUT LPSTR *lppszExtra, IN OUT DWORD *lpdwExtra, OUT LPSTR *lppszAuthScheme ) { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::CrackAuthenticationHeader", "this=%#x request=%#x isproxy=%B authidx=%d ppszAuthHeader=%#x ppszExtra=%#x pdwExtra=%#x ppszAuthScheme=%#x", this, hRequestMapped, fIsProxy, dwAuthenticationIndex, lppszAuthHeader, lppszExtra, lpdwExtra, lppszAuthScheme ));
DWORD error = ERROR_SUCCESS;
LPSTR lpszAuthHeader = NULL; DWORD cbAuthHeader = 0; LPSTR lpszExtra = NULL; LPSTR lpszAuthScheme = NULL;
LPDWORD lpdwAuthenticationIndex = &dwAuthenticationIndex; INET_ASSERT(lpdwExtra); INET_ASSERT(lppszExtra); INET_ASSERT(lpdwAuthenticationIndex);
DWORD dwQuery = fIsProxy? HTTP_QUERY_PROXY_AUTHENTICATE : HTTP_QUERY_WWW_AUTHENTICATE;
error = wQueryHeadersAlloc (hRequestMapped, dwQuery, lpdwAuthenticationIndex, &lpszAuthHeader, &cbAuthHeader);
if ( error != ERROR_SUCCESS ) { INET_ASSERT(*lpdwAuthenticationIndex || error == ERROR_HTTP_HEADER_NOT_FOUND ); goto quit; }
//
// Parse Header for Scheme type
//
lpszAuthScheme = lpszAuthHeader;
while ( *lpszAuthScheme == ' ' ) // strip spaces
lpszAuthScheme++;
lpszExtra = strchr(lpszAuthScheme, ' ');
if (lpszExtra) *lpszExtra++ = '\0';
if (lstrcmpi(GetScheme(), lpszAuthScheme)) { DEBUG_PRINT( HTTPAUTH, ERROR, ("Authentication: HTTP Scheme has changed!: Scheme=%q\n", lpszAuthScheme) );
goto quit;
}
DEBUG_PRINT( HTTPAUTH, INFO, ("Authentication: found in headers: Scheme=%q, Extra=%q\n", lpszAuthScheme, lpszExtra) );
quit: *lppszExtra = lpszExtra; *lpdwExtra = lpszExtra ? lstrlen(lpszExtra) : 0; *lppszAuthHeader = lpszAuthHeader; *lppszAuthScheme = lpszAuthScheme;
DEBUG_LEAVE(error); return error; }
/*---------------------------------------------------------------------------
ResolveProtocol ---------------------------------------------------------------------------*/ VOID PLUG_CTX::ResolveProtocol() { DEBUG_ENTER (( DBG_HTTPAUTH, None, "PLUG_CTX::ResolveProtocol", "this=%#x", this ));
SECURITY_STATUS ssResult; PWINCONTEXT pWinContext; SecPkgContext_NegotiationInfo SecPkgCtxtInfo;
INET_ASSERT(GetSchemeType() == SCHEME_NEGOTIATE);
SecPkgCtxtInfo.PackageInfo = NULL; // Call QueryContextAttributes on the context handle.
pWinContext = (PWINCONTEXT) (_pvContext); ssResult = (*(g_pSspData->pFuncTbl->QueryContextAttributes)) (pWinContext->pSspContextHandle, SECPKG_ATTR_NEGOTIATION_INFO, &SecPkgCtxtInfo);
if (ssResult == SEC_E_OK && (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_COMPLETE || (SecPkgCtxtInfo.NegotiationState == SECPKG_NEGOTIATION_OPTIMISTIC))) { // Resolve actual auth protocol from package name.
// update both the auth context and pwc entry.
if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "NTLM")) { _eSubScheme = SCHEME_NTLM; _dwSubFlags = PLUGIN_AUTH_FLAGS_NO_REALM; } else if (!lstrcmpi(SecPkgCtxtInfo.PackageInfo->Name, "Kerberos")) { _eSubScheme = SCHEME_KERBEROS; _dwSubFlags = PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED | PLUGIN_AUTH_FLAGS_NO_REALM; } DEBUG_PRINT( HTTPAUTH, INFO, ("Negotiate package is using %s\n", SecPkgCtxtInfo.PackageInfo->Name) );
}
if( SecPkgCtxtInfo.PackageInfo ) { (*(g_pSspData->pFuncTbl->FreeContextBuffer))(SecPkgCtxtInfo.PackageInfo); }
DEBUG_LEAVE(0); }
/*---------------------------------------------------------------------------
Constructor ---------------------------------------------------------------------------*/ PLUG_CTX::PLUG_CTX(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy, SPMData *pSPM, PWC* pPWC) : AUTHCTX(pSPM, pPWC) { DEBUG_ENTER (( DBG_HTTPAUTH, Pointer, "PLUG_CTX::PLUG_CTX", "this=%#x request=%#x isproxy=%B pSPM=%#x pPWC=%#x", this, pRequest, fIsProxy, pSPM, pPWC ));
_fIsProxy = fIsProxy; _pRequest = pRequest; _szAlloc = NULL; _szData = NULL; _cbData = 0; _pRequest->SetAuthState(AUTHSTATE_NONE); _fNTLMProxyAuth = _fIsProxy && (GetSchemeType() == SCHEME_NTLM );
_SecStatus = 0; _dwResolutionId = 0;
DEBUG_LEAVE(this); }
/*---------------------------------------------------------------------------
Destructor ---------------------------------------------------------------------------*/ PLUG_CTX::~PLUG_CTX() { DEBUG_ENTER (( DBG_HTTPAUTH, None, "PLUG_CTX::~PLUG_CTX", "this=%#x", this ));
if (GetState() == AUTHCTX::STATE_LOADED) { if (_pPWC) { ClearAuthUser(&_pvContext, _pPWC->lpszHost); } } if (_pRequest) { _pRequest->SetAuthState(AUTHSTATE_NONE); }
DEBUG_LEAVE(0); }
PCSTR PLUG_CTX::GetUrl(void) const { return _pRequest->GetURL(); }
/*---------------------------------------------------------------------------
PreAuthUser ---------------------------------------------------------------------------*/ DWORD PLUG_CTX::PreAuthUser(OUT LPSTR pBuf, IN OUT LPDWORD pcbBuf) { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::PreAuthUser", "this=%#x", this ));
INET_ASSERT(_pSPMData == _pPWC->pSPM);
AuthLock();
DWORD dwError; SECURITY_STATUS ssResult; PSTR lpszPass = _pPWC->GetPass();
// Make sure the auth provider is loaded.
if (GetState() != AUTHCTX::STATE_LOADED) { if (GetState() != AUTHCTX::STATE_ERROR ) Load(); if (GetState() != AUTHCTX::STATE_LOADED) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; } }
__try { ssResult = SEC_E_INTERNAL_ERROR;
DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PreAuthenticateUser", "ctx=%#x host=%s scheme=%s {buf=%x (%.16s...) cbbuf=%d} user=%s pass=%s", _pvContext, _pPWC->lpszHost, InternetMapAuthScheme(GetSchemeType()), pBuf, pBuf, *pcbBuf, _pPWC->lpszUser, lpszPass ));
LPSTR lpszFQDN = (LPSTR)GetFQDN((LPCSTR)_pPWC->lpszHost); LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pPWC->lpszHost; dwError = PreAuthenticateUser(&_pvContext, lpszHostName, GetScheme(), 0, // dwFlags
pBuf, pcbBuf, _pPWC->lpszUser, lpszPass, GetUrl(), &ssResult);
DEBUG_PRINT(HTTPAUTH, INFO, ("ssres: %#x [%s]\n", ssResult, InternetMapError(ssResult))); DEBUG_LEAVE(dwError);
// Transit to the correct auth state.
if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED) { if (GetSchemeType() == SCHEME_NEGOTIATE) ResolveProtocol();
// Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
// Negotiate does not transit to challenge.
// Any other protocol + SEC_E_OK only transits to challenge.
if ((GetSchemeType() == SCHEME_KERBEROS && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)) || (GetSchemeType() != SCHEME_NEGOTIATE && ssResult == SEC_E_OK)) { _pRequest->SetAuthState(AUTHSTATE_CHALLENGE); } } }
__except(EXCEPTION_EXECUTE_HANDLER) { DEBUG_PRINT (HTTPAUTH, ERROR, ("PreAuthenticateUser call down faulted\n")); _pSPMData->eState = STATE_ERROR; dwError = ERROR_INTERNET_INTERNAL_ERROR; }
ENDEXCEPT
DEBUG_PRINT( HTTPAUTH, INFO, ( "request %#x [%s] now in %s using %s\n", _pRequest, _pPWC->lpszHost, InternetMapAuthState(_pRequest->GetAuthState()), InternetMapAuthScheme(GetSchemeType()) ) );
exit: if (lpszPass) { memset(lpszPass, 0, strlen(lpszPass)); FREE_MEMORY(lpszPass); }
AuthUnlock(); DEBUG_LEAVE(dwError); return dwError; }
/*---------------------------------------------------------------------------
UpdateFromHeaders ---------------------------------------------------------------------------*/ DWORD PLUG_CTX::UpdateFromHeaders(HTTP_REQUEST_HANDLE_OBJECT *pRequest, BOOL fIsProxy) { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::UpdateFromHeaders", "this=%#x request=%#x isproxy=%B", this, pRequest, fIsProxy ));
DWORD dwError, cbExtra, dwAuthIdx; LPSTR szAuthHeader, szExtra, szScheme;
AuthLock();
// Get the auth header index corresponding to the scheme of this ctx.
if ((dwError = FindHdrIdxFromScheme(&dwAuthIdx)) != ERROR_SUCCESS) goto quit;
// Get the scheme and any extra data.
if ((dwError = CrackAuthenticationHeader(pRequest, fIsProxy, dwAuthIdx, &szAuthHeader, &szExtra, &cbExtra, &szScheme)) != ERROR_SUCCESS) goto quit; if (!cbExtra) _pRequest->SetAuthState(AUTHSTATE_NEGOTIATE);
// Check if auth scheme requires keep-alive.
if (!(GetFlags() & PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED)) { // if in negotiate phase check if we are going via proxy.
if (pRequest->GetAuthState() == AUTHSTATE_NEGOTIATE) { // BUGBUG: if via proxy, we are not going to get keep-alive
// connection to the server. It would be nice if we knew
// a priori the whether proxy would allow us to tunnel to
// http port on the server. Otherwise if we try and fail,
// we look bad vs. other browsers who are ignorant of ntlm
// and fall back to basic.
CHAR szBuffer[64]; DWORD dwBufferLength = sizeof(szBuffer); DWORD dwIndex = 0; BOOL fSessionBasedAuth = FALSE; if (pRequest->QueryResponseHeader(HTTP_QUERY_PROXY_SUPPORT, szBuffer, &dwBufferLength, 0, &dwIndex) == ERROR_SUCCESS) { if (!_stricmp(szBuffer, "Session-Based-Authentication")) { fSessionBasedAuth = TRUE; } } if (!fIsProxy && pRequest->IsRequestUsingProxy() && !pRequest->IsTalkingToSecureServerViaProxy() && !fSessionBasedAuth) { // Ignore NTLM via proxy since we won't get k-a to server.
dwError = ERROR_HTTP_HEADER_NOT_FOUND; goto quit; } }
// Else if in challenge phase, we require a persistent connection.
else { // If we don't have a keep-alive connection ...
if (!(pRequest->IsPersistentConnection (fIsProxy)) && !(pRequest->IsRequestUsingProxy())) { dwError = ERROR_HTTP_HEADER_NOT_FOUND; goto quit; } }
} // end if keep-alive required
quit:
if (dwError == ERROR_SUCCESS) { // If no password cache is set in the auth context,
// find or create one and set it in the handle.
if (!_pPWC) { _pPWC = FindOrCreatePWC(pRequest, fIsProxy, _pSPMData, NULL);
if (!_pPWC) { INET_ASSERT(FALSE); dwError = ERROR_INTERNET_INTERNAL_ERROR; } else { INET_ASSERT(_pPWC->pSPM == _pSPMData); _pPWC->nLockCount++; } } }
if (dwError == ERROR_SUCCESS) { // Point to allocated data.
_szAlloc = szAuthHeader; _szData = szExtra; _cbData = cbExtra; } else { // Free allocated data.
if (_szAlloc) delete _szAlloc; _szAlloc = NULL; _szData = NULL; _cbData = 0; }
DEBUG_PRINT( HTTPAUTH, INFO, ( "request %#x [%s] now in %s using %s\n", _pRequest, _pPWC->lpszHost, InternetMapAuthState(_pRequest->GetAuthState()), InternetMapAuthScheme(GetSchemeType()) ) );
// Return of non-success will cancel auth session.
AuthUnlock(); DEBUG_LEAVE(dwError); return dwError; }
/*---------------------------------------------------------------------------
PostAuthUser ---------------------------------------------------------------------------*/ DWORD PLUG_CTX::PostAuthUser() { DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "PLUG_CTX::PostAuthUser", "this=%#x", this ));
INET_ASSERT(_pSPMData == _pPWC->pSPM);
AuthLock();
DWORD dwError; PSTR lpszPass = _pPWC->GetPass(); // Make sure the auth provider is loaded.
if (GetState() != AUTHCTX::STATE_LOADED) { if (GetState() != AUTHCTX::STATE_ERROR ) Load(); if (GetState() != AUTHCTX::STATE_LOADED) { dwError = ERROR_INTERNET_INTERNAL_ERROR; goto exit; } }
BOOL fCanUseLogon = _fIsProxy || _pRequest->GetCredPolicy() == URLPOLICY_CREDENTIALS_SILENT_LOGON_OK;
SECURITY_STATUS ssResult; __try { ssResult = SEC_E_INTERNAL_ERROR;
DEBUG_ENTER (( DBG_HTTPAUTH, Dword, "AuthenticateUser", "ctx=%#x host=%s scheme=%s {data=%#x (%.16s...) cbdata=%d} user=%s pass=%s", _pvContext, _pPWC->lpszHost, InternetMapAuthScheme(GetSchemeType()), _szData, _szData, _cbData, _pPWC->lpszUser, lpszPass ));
LPSTR lpszFQDN = (LPSTR)GetFQDN((LPCSTR)_pPWC->lpszHost); LPSTR lpszHostName = lpszFQDN ? lpszFQDN : _pPWC->lpszHost;
dwError = AuthenticateUser(&_pvContext, lpszHostName, GetScheme(), fCanUseLogon, _szData, _cbData, _pPWC->lpszUser, lpszPass, GetUrl(), &ssResult);
_SecStatus = ssResult;
DEBUG_PRINT(HTTPAUTH, INFO, ("ssres: %#x [%s]\n", ssResult, InternetMapError(ssResult))); DEBUG_LEAVE(dwError);
// Kerberos package can get into a bad state.
if (GetSchemeType() == SCHEME_KERBEROS && ssResult == SEC_E_WRONG_PRINCIPAL) dwError = ERROR_INTERNET_INCORRECT_PASSWORD; // Transit to the correct auth state.
if (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED) { if (GetSchemeType() == SCHEME_NEGOTIATE) ResolveProtocol();
// Kerberos + SEC_E_OK or SEC_I_CONTINUE_NEEDED transits to challenge.
// Negotiate does not transit to challenge.
// Any other protocol + SEC_E_OK only transits to challenge.
if ((GetSchemeType() == SCHEME_KERBEROS && (ssResult == SEC_E_OK || ssResult == SEC_I_CONTINUE_NEEDED)) || (GetSchemeType() != SCHEME_NEGOTIATE && ssResult == SEC_E_OK)) { _pRequest->SetAuthState(AUTHSTATE_CHALLENGE); } } } __except (EXCEPTION_EXECUTE_HANDLER) { DEBUG_PRINT (HTTPAUTH, ERROR, ("AuthenticateUser faulted!\n")); dwError = ERROR_BAD_FORMAT; _pSPMData->eState = STATE_ERROR; } ENDEXCEPT
if (_szAlloc) { delete _szAlloc; _szAlloc = NULL; _szData = NULL; }
_cbData = 0;
DEBUG_PRINT( HTTPAUTH, INFO, ( "request %#x [%s] now in %s using %s\n", _pRequest, _pPWC->lpszHost, InternetMapAuthState(_pRequest->GetAuthState()), InternetMapAuthScheme(GetSchemeType()) ) );
exit: if (lpszPass) { memset(lpszPass, 0, strlen(lpszPass)); FREE_MEMORY(lpszPass); }
AuthUnlock(); DEBUG_LEAVE(dwError); return dwError; }
LPCSTR PLUG_CTX::GetFQDN(LPCSTR lpszHostName) { if (lstrcmpi(GetScheme(), "Negotiate")) // only need to get FQDN for Kerberos
{ return NULL; }
if (_pszFQDN) { return _pszFQDN; }
LPRESOLVER_CACHE_ENTRY lpResolverCacheEntry; DWORD TTL; LPADDRINFO lpAddrInfo; if (lpResolverCacheEntry = QueryResolverCache((LPSTR)lpszHostName, NULL, &lpAddrInfo, &TTL)) { _pszFQDN = (lpAddrInfo->ai_canonname ? NewString(lpAddrInfo->ai_canonname) : NULL); ReleaseResolverCacheEntry(lpResolverCacheEntry); return _pszFQDN; }
/*
CAddressList TempAddressList; DWORD dwResolutionId; TempAddressList.ResolveHost((LPSTR)lpszHostName, &_dwResolutionId, SF_FORCE);
if (lpResolverCacheEntry = QueryResolverCache((LPSTR)lpszHostName, NULL, &lpAddrInfo, &TTL)) { _pszFQDN = (lpAddrInfo->ai_canonname ? NewString(lpAddrInfo->ai_canonname) : NULL); ReleaseResolverCacheEntry(lpResolverCacheEntry); return _pszFQDN; } */
return NULL; }
|