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.
 
 
 
 
 
 

1476 lines
41 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
Logon.cpp
Abstract:
Author:
Biao Wang (biaow) 01-Oct-2000
John Hawkins (Johnhaw) 01-Oct-2000
--*/
#include "PPdefs.h"
#include "session.h"
#include "logon.h"
#ifndef CRYPT_UNPROTECT_DATA_FN_DEFINE
#define CRYPT_UNPROTECT_DATA_FN_DEFINE
typedef BOOL
(WINAPI *CRYPT_UNPROTECT_DATA_FN)
(IN DATA_BLOB *pDataIn,
OUT OPTIONAL LPWSTR *ppszDataDescr,
IN DATA_BLOB *pOptionalEntropy,
IN PVOID pvReserved,
IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
IN DWORD dwFlags,
OUT DATA_BLOB *pDataOut
);
#endif
extern CRYPT_UNPROTECT_DATA_FN g_pfnCryptUnprotectData;
#define SIZE_OF_SALT 37
#define SALT_SHIFT 2
WCHAR g_szSalt[] = L"82BD0E67-9FEA-4748-8672-D5EFE5B779B0";
// #include "logon.tmh"
LOGON::LOGON(SESSION* pSession, DWORD dwParentFlags, PCWSTR pwszProxyUser, PCWSTR pwszProxyPass)
: m_pSession(pSession)
{
m_pwszProxyUser = pwszProxyUser;
m_pwszProxyPass = pwszProxyPass;
m_pSession->AddRef();
m_hConnect = NULL;
m_fCredsPresent = FALSE;
m_pwszSignIn = NULL;
m_pwszPassword = NULL;
m_pwszTicketRequest = NULL;
m_pwszAuthInfo = NULL;
m_pwszReturnUrl = NULL;
m_pBitmap = NULL;
m_fPrompt = FALSE;
m_wTimeSkew[0] = L'\0';
m_wNewDAUrl[0] = 0;
m_dwParentFlags = dwParentFlags;
m_p401Content = NULL;
m_pwszCbtxt = NULL;
m_pwszCbUrl = NULL;
}
LOGON::~LOGON(void)
{
if (m_pwszAuthInfo)
{
delete [] m_pwszAuthInfo;
}
if (m_pwszSignIn)
{
SecureZeroMemory(m_pwszSignIn, ::wcslen(m_pwszSignIn) * sizeof(WCHAR));
delete [] m_pwszSignIn;
}
if (m_pwszPassword)
{
SecureZeroMemory(m_pwszPassword, ::wcslen(m_pwszPassword) * sizeof(WCHAR));
delete [] m_pwszPassword;
}
if (m_pwszTicketRequest)
{
delete [] m_pwszTicketRequest;
}
if (m_pwszAuthHeader)
{
delete [] m_pwszAuthHeader;
}
m_pSession->RemoveRef();
if (m_p401Content)
{
m_p401Content->Release();
}
if (m_pwszCbtxt)
{
delete [] m_pwszCbtxt;
}
if (m_pwszCbUrl)
{
delete [] m_pwszCbUrl;
}
if (m_pwszProxyUser)
{
SecureZeroMemory((void*)m_pwszProxyUser, sizeof(m_pwszProxyUser[0]) * wcslen(m_pwszProxyUser));
delete [] m_pwszProxyUser;
}
if (m_pwszProxyPass)
{
SecureZeroMemory((void*)m_pwszProxyPass, sizeof(m_pwszProxyPass[0]) * wcslen(m_pwszProxyPass));
delete [] m_pwszProxyPass;
}
}
// -----------------------------------------------------------------------------
BOOL LOGON::Open(
PCWSTR pwszPartnerInfo // in the form of "WWW-Authenticate: Passport1.4 ..."
)
{
PP_ASSERT(pwszPartnerInfo != NULL);
// locate the auth scheme name, i.e. Passport1.4
PCWSTR pwszTicketRequest = ::wcsstr(pwszPartnerInfo, L"Passport1.4");
if (pwszTicketRequest == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Open() failed; Passport1.4 scheme not found");
return FALSE;
}
pwszTicketRequest += ::wcslen(L"Passport1.4");
// skip white spaces between the scheme name and the Ticket Request (TR)
while (*pwszTicketRequest == (L" ")[0]) { ++pwszTicketRequest; }
if (*pwszTicketRequest == L'\0')
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Open() failed; Ticket Request missing");
return FALSE;
}
// save the TR
DWORD dwTrLen = ::wcslen(pwszTicketRequest);
m_pwszTicketRequest = new WCHAR[dwTrLen + 1];
if (m_pwszTicketRequest == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Open() failed; not enough memory");
return FALSE;
}
::wcscpy(m_pwszTicketRequest, pwszTicketRequest);
m_pwszAuthHeader = new WCHAR[dwTrLen +
MAX_PASSPORT_USERNAME_LENGTH +
MAX_PASSPORT_PASSWORD_LENGTH +
MAX_PASSPORT_TIME_SKEW_LENGTH +
256 + // some buffer for the worst case
1];
if (m_pwszAuthHeader == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Open() failed; not enough memory");
return FALSE;
}
DoTraceMessage(PP_LOG_INFO, "LOGON::Open() succeed");
return TRUE;
}
void LOGON::Close(void)
{
PP_ASSERT(m_hConnect != NULL);
PP_ASSERT(m_pSession != NULL);
m_pSession->CloseHandle(m_hConnect);
m_hConnect = NULL;
}
DWORD
LoadSecurity(
VOID
);
// pClearPassword is assumed to be at least 256 chars
void DecryptPassword ( WCHAR* pClearPassword, PVOID pPassword, DWORD cbSize )
{
BOOL bOrigEncrypted = FALSE;
DATA_BLOB InBlob;
DATA_BLOB OutBlob;
LPWSTR pszDesc;
if ( pClearPassword == NULL )
return;
if ( cbSize == 0 )
{
// CryptUnprotectData doesn't like to be sent a zero-length buffer
pClearPassword[0] = L'\0';
return;
}
InBlob.pbData = (BYTE*)pPassword;
InBlob.cbData = cbSize;
DATA_BLOB EntropyBlob;
WCHAR szSalt[SIZE_OF_SALT];
wcscpy ( szSalt, g_szSalt);
for ( int i = 0; i < SIZE_OF_SALT; i++ )
szSalt[i] <<= SALT_SHIFT;
EntropyBlob.pbData = (BYTE*)szSalt;
EntropyBlob.cbData = sizeof(WCHAR)*(wcslen(szSalt)+1);
// Guaranteed to have a logon context if we've gotten this far.
// Consequently, a previously successful call to LoadSecurity can
// be assumed.
LoadSecurity();
PP_ASSERT(g_pfnCryptUnprotectData);
if ( (*g_pfnCryptUnprotectData) ( &InBlob,
&pszDesc,
&EntropyBlob,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&OutBlob ) )
{
if ( wcscmp (L"SSOCred", pszDesc) == 0 )
{
DWORD dwOutChars = OutBlob.cbData/sizeof(WCHAR);
if ( dwOutChars < 256 )
{
wcsncpy ( pClearPassword, (WCHAR*)OutBlob.pbData, dwOutChars );
pClearPassword[dwOutChars] = L'\0';
}
bOrigEncrypted = TRUE;
}
LocalFree ( pszDesc );
LocalFree ( OutBlob.pbData );
}
SecureZeroMemory ( szSalt, SIZE_OF_SALT);
if ( !bOrigEncrypted )
{
// copy the plain text
wcsncpy ( pClearPassword, (WCHAR*)pPassword, MAX_PASSPORT_PASSWORD_LENGTH );
pClearPassword[MAX_PASSPORT_PASSWORD_LENGTH] = 0;
pClearPassword[cbSize/sizeof(WCHAR)] = L'\0';
}
return;
}
void LOGON::GetCachedCreds(
PCWSTR pwszRealm,
PCWSTR pwszTarget,
PCREDENTIALW** pppCreds,
DWORD* pdwCreds
)
{
if (m_pSession->GetCachedCreds(pwszRealm,pwszTarget,pppCreds,pdwCreds) != FALSE)
{
PCREDENTIALW pCredToUse = *pppCreds[0];
::FileTimeToSystemTime(&(pCredToUse->LastWritten), &m_TimeCredsEntered);
}
}
// -----------------------------------------------------------------------------
BOOL LOGON::SetCredentials(
PCWSTR pwszRealm,
PCWSTR pwszTarget,
PCWSTR pwszSignIn,
PCWSTR pwszPassword,
PSYSTEMTIME pTimeCredsEntered
)
{
WCHAR wPass[MAX_PASSPORT_PASSWORD_LENGTH + 1];
wPass[0] = 0;
PCREDENTIALW* ppCred = NULL;
DWORD dwCreds = 0;
PCREDENTIALW pCredToUse = NULL;
if ((!pwszSignIn) && (!pwszPassword))
{
pTimeCredsEntered = NULL; // invalidate this parameter if cached creds are to be used
GetCachedCreds(pwszRealm, pwszTarget, &ppCred, &dwCreds);
if (dwCreds > 0 && ppCred[0] != NULL )
{
for ( DWORD idx = 0; idx < dwCreds; idx++ )
{
if ( ppCred[idx]->Type == CRED_TYPE_DOMAIN_VISIBLE_PASSWORD )
{
// check to see if prompt bit is set. If set, keep looking, only use if
// the prompt bit isn't set.
if ( !(ppCred[idx]->Flags & CRED_FLAGS_PROMPT_NOW) )
{
pCredToUse = ppCred[idx];
break;
}
}
}
}
if (pCredToUse == NULL)
{
return FALSE;
}
DecryptPassword(wPass,
PVOID(pCredToUse->CredentialBlob),
pCredToUse->CredentialBlobSize);
pwszSignIn = pCredToUse->UserName;
pwszPassword = wPass;
}
else
{
m_pSession->ResetLogoutFlag();
if (pTimeCredsEntered == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::SetCredentials() failed; Timestamp not specified");
return FALSE;
}
}
if (m_pwszSignIn)
{
SecureZeroMemory(m_pwszSignIn, ::wcslen(m_pwszSignIn) * sizeof(WCHAR));
delete [] m_pwszSignIn;
}
DWORD dwSignInLen = ::wcslen(pwszSignIn);
m_pwszSignIn = new WCHAR[dwSignInLen + 1];
if (m_pwszSignIn == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::SetCredentials() failed; not enough memory");
return FALSE;
}
::wcscpy(m_pwszSignIn, pwszSignIn);
if (m_pwszPassword)
{
SecureZeroMemory(m_pwszPassword, ::wcslen(m_pwszPassword) * sizeof(WCHAR));
delete [] m_pwszPassword;
}
DWORD dwPasswordLen = ::wcslen(pwszPassword);
m_pwszPassword = new WCHAR[dwPasswordLen + 1];
if (m_pwszPassword == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::SetCredentials() failed; not enough memory");
SecureZeroMemory(m_pwszSignIn, ::wcslen(m_pwszSignIn) * sizeof(WCHAR));
delete [] m_pwszSignIn;
m_pwszSignIn = NULL;
return FALSE;
}
::wcscpy(m_pwszPassword, pwszPassword);
SecureZeroMemory(wPass, ::wcslen(wPass) * sizeof(WCHAR));
if (pTimeCredsEntered)
{
m_TimeCredsEntered = *pTimeCredsEntered;
}
m_fCredsPresent = TRUE;
if (ppCred)
{
if (m_pSession->m_pfnCredFree)
{
m_pSession->m_pfnCredFree(ppCred);
}
}
return TRUE;
}
// -----------------------------------------------------------------------------
BOOL LOGON::ParseChallengeInfo(
PWSTR pwszChallenge
)
{
PP_ASSERT(pwszChallenge != NULL);
BOOL fRet = FALSE;
WCHAR Delimiters[] = L",";
PWSTR Token = ::wcstok(pwszChallenge, Delimiters);
while (Token != NULL)
{
// skip leading white spaces
while (*Token == (L" ")[0]) { ++Token; }
if (*Token == L'\0')
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::DownLoadCoBrandBitmap() : no text in between commas");
goto next_token;
}
// find cburl
if (!::_wcsnicmp(Token, L"cburl", ::wcslen(L"cburl")))
{
PWSTR CbUrl = ::wcsstr(Token, L"=");
if (CbUrl == NULL)
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::DownLoadCoBrandBitmap() : no = after cburl");
goto next_token;
}
CbUrl++; // skip "="
while (*CbUrl == (L" ")[0]) { ++CbUrl; } // skip leading white spaces
if (*CbUrl == L'\0')
{
goto next_token;
}
m_pwszCbUrl = new WCHAR[::wcslen(CbUrl)+1];
if (m_pwszCbUrl == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::DownLoadCoBrandBitmap() failed; not enough memory");
goto exit;
}
::wcscpy(m_pwszCbUrl, CbUrl);
DoTraceMessage(PP_LOG_INFO, "CoBrand URL %ws found", m_pwszCbUrl);
}
else if (!::_wcsnicmp(Token, L"ts", ::wcslen(L"ts")))
{
::wcsncpy(m_wTimeSkew, Token, MAX_PASSPORT_TIME_SKEW_LENGTH);
m_wTimeSkew[MAX_PASSPORT_TIME_SKEW_LENGTH] = 0;
}
else if (!::_wcsnicmp(Token, L"srealm", ::wcslen(L"srealm")))
{
PWSTR pwszRealm = ::wcsstr(Token, L"=");
if (pwszRealm == NULL)
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::DownLoadCoBrandBitmap() : no = after cburl");
goto next_token;
}
pwszRealm++; // skip "="
while (*pwszRealm == (L" ")[0]) { ++pwszRealm; } // skip leading white spaces
if (*pwszRealm == L'\0')
{
goto next_token;
}
::wcsncpy(m_wRealm, pwszRealm, MAX_PASSPORT_REALM_LENGTH);
m_wRealm[MAX_PASSPORT_REALM_LENGTH] = 0;
DoTraceMessage(PP_LOG_INFO, "sRealm URL %ws found", pwszRealm);
}
else if (!::_wcsnicmp(Token, L"cbtxt", ::wcslen(L"cbtxt")))
{
PWSTR pwszCbTxt = ::wcsstr(Token, L"=");
if (pwszCbTxt == NULL)
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::DownLoadCoBrandBitmap() : no = after cbtxt");
goto next_token;
}
pwszCbTxt++; // skip "="
while (*pwszCbTxt == (L" ")[0]) { ++pwszCbTxt; } // skip leading white spaces
if (*pwszCbTxt == L'\0')
{
goto next_token;
}
if (m_pwszCbtxt)
{
delete [] m_pwszCbtxt;
}
m_pwszCbtxt = new WCHAR[wcslen(pwszCbTxt)+1];
if (m_pwszCbtxt)
{
::wcscpy( m_pwszCbtxt, pwszCbTxt);
DoTraceMessage(PP_LOG_INFO, "cbtxt %ws found", m_pwszCbtxt);
}
}
next_token:
Token = ::wcstok(NULL, Delimiters);
}
exit:
return fRet;
}
// -----------------------------------------------------------------------------
DWORD LOGON::Handle401FromDA(
HINTERNET hRequest,
BOOL fTicketRequest
)
{
UNREFERENCED_PARAMETER(fTicketRequest);
PP_ASSERT(hRequest != NULL);
DWORD dwRetVal = (DWORD)PP_GENERIC_ERROR;
PWSTR pwszRawHeaders = NULL;
PSTR pszRawHeaders = NULL;
PWSTR pwszChallenge = NULL;
PWSTR pwszChallengeEnd = NULL;
DWORD ChallengeLength = 0;
if(!DelayLoad( &g_moduleOle32))
goto exit;
if(m_pSession->QueryHeaders(hRequest,
WINHTTP_QUERY_RAW_HEADERS_CRLF,
0,
&ChallengeLength) == FALSE)
{
if ((::GetLastError() != ERROR_INSUFFICIENT_BUFFER) || (ChallengeLength == 0))
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "Handle401FromDA() failed; QueryHeaders() failed; Error Code = %d",
dwErrorCode);
goto exit;
}
}
else
{
PP_ASSERT(FALSE); // control should not reach here
}
pwszRawHeaders = new WCHAR[ChallengeLength];
if (pwszRawHeaders == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "Handle401FromDA() failed; out of memory");
goto exit;
}
if(m_pSession->QueryHeaders(hRequest,
WINHTTP_QUERY_RAW_HEADERS_CRLF,
pwszRawHeaders,
&ChallengeLength) == FALSE)
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "Handle401FromDA() failed; QueryHeaders() failed; Error Code = %d",
dwErrorCode);
goto exit;
}
if ((pwszChallenge = ::wcsstr(pwszRawHeaders, L"Passport1.4")) == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "Handle401FromDA() failed; Passport1.4 auth header not found");
goto exit;
}
if ((pwszChallengeEnd = ::wcsstr(pwszChallenge, L"\r\n")) != NULL)
{
*pwszChallengeEnd = 0;
}
if (::wcsstr(pwszChallenge, L"noretry"))
{
dwRetVal = PP_LOGON_FAILED; // Login Request Failed; bad news!
DoTraceMessage(PP_LOG_WARNING, "Handle401FromDA() : Logon failed");
}
else if (::wcsstr(pwszChallenge, L"retry"))
{
// biaow-todo: not yet implemented
// PP_ASSERT(FALSE); // shouldn't reach here
dwRetVal = PP_LOGON_REQUIRED;
}
else if (::wcsstr(pwszChallenge, L"failed"))
{
// if (fTicketRequest)
// {
dwRetVal = PP_LOGON_REQUIRED;
DoTraceMessage(PP_LOG_INFO, "Handle401FromDA() : Logon required by DA");
// }
// else
// {
// dwRetVal = PP_LOGON_FAILED; // Login Request Failed; bad news!
// DoTraceMessage(PP_LOG_WARNING, "Handle401FromDA() : Logon failed");
// }
}
else
{
DoTraceMessage(PP_LOG_ERROR, "Handle401FromDA() failed; no valid DA status");
goto exit;
}
if (dwRetVal == PP_LOGON_REQUIRED || dwRetVal == PP_LOGON_FAILED)
{
if (::wcsstr(pwszChallenge, L"prompt"))
{
m_fPrompt = TRUE;
}
else
{
m_fPrompt = FALSE;
}
if (DL(CreateStreamOnHGlobal)(NULL, TRUE, &m_p401Content) != S_OK)
{
DoTraceMessage(PP_LOG_ERROR, "DL(CreateStreamOnHGlobal)() failed");
goto exit;
}
if (pwszChallengeEnd)
{
PP_ASSERT(*pwszChallengeEnd == 0);
*pwszChallengeEnd = L'\r';
}
pszRawHeaders = new CHAR[ChallengeLength * 2];
if (pszRawHeaders == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "DL(CreateStreamOnHGlobal)() failed, out of memory");
goto exit;
}
::WideCharToMultiByte(CP_ACP, 0, pwszRawHeaders, -1, pszRawHeaders, ChallengeLength * 2, NULL, NULL);
m_p401Content->Write(pszRawHeaders, strlen(pszRawHeaders), NULL);
{
DWORD cbRead = 0;
PBYTE bBuf = new BYTE [1024];
if (bBuf == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "DL(CreateStreamOnHGlobal)() failed, out of memory");
goto exit;
}
DWORD cbBuf = 1024;
while (m_pSession->ReadFile(hRequest, bBuf, cbBuf, &cbRead) && cbRead)
m_p401Content->Write(bBuf, cbRead, NULL);
delete [] bBuf;
}
LARGE_INTEGER Zero = {0};
m_p401Content->Seek(Zero, STREAM_SEEK_SET, NULL); // seek to the beginning of the stream
if (pwszChallengeEnd)
{
*pwszChallengeEnd = 0;
}
ParseChallengeInfo(pwszChallenge);
}
exit:
if (pwszRawHeaders)
{
delete [] pwszRawHeaders;
}
if (pszRawHeaders)
{
delete [] pszRawHeaders;
}
return dwRetVal;
}
// -----------------------------------------------------------------------------
DWORD LOGON::Handle200FromDA(
HINTERNET hRequest
)
{
PP_ASSERT(hRequest != NULL);
DWORD dwRetVal = (DWORD)PP_GENERIC_ERROR;
PWSTR pwszBuffer = NULL;
DWORD dwBuffer = 0;
if((!m_pSession->QueryHeaders(hRequest,
WINHTTP_QUERY_AUTHENTICATION_INFO,
pwszBuffer,
&dwBuffer))
&& (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
pwszBuffer = new WCHAR[dwBuffer];
if (pwszBuffer == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Handle200FromDA() failed; not enough memory");
goto exit;
}
if (!m_pSession->QueryHeaders(hRequest,
HTTP_QUERY_AUTHENTICATION_INFO,
pwszBuffer,
&dwBuffer))
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Handle200FromDA() failed; no Authenticate-Info header found");
goto exit;
}
WCHAR Delimiters[] = L",";
PWSTR Token = ::wcstok(pwszBuffer, Delimiters);
while (Token != NULL)
{
while (*Token == (L" ")[0]) { ++Token; }
if (*Token == L'\0')
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::Handle200FromDA() : no text in between commas");
goto next_token;
}
if (!::_wcsnicmp(Token, L"ru", ::wcslen(L"ru")))
{
PWSTR ReturnUrl = ::wcsstr(Token, L"=");
if (ReturnUrl == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Handle200FromDA() : no = after cburl");
goto exit;
}
ReturnUrl++; // skip =
while (*ReturnUrl == (L" ")[0]) { ++ReturnUrl; } // skip leading white spaces
if (*ReturnUrl == L'\0')
{
goto exit;
}
m_pwszReturnUrl = new WCHAR[::wcslen(ReturnUrl)+1];
if (m_pwszReturnUrl == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Handle200FromDA() failed; not enough memory");
goto exit;
}
::wcscpy(m_pwszReturnUrl, ReturnUrl);
}
else if (!::_wcsnicmp(Token, L"from-pp", ::wcslen(L"from-pp")))
{
m_pwszAuthInfo = new WCHAR[::wcslen(Token)+1];
if (m_pwszAuthInfo == NULL)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Handle200FromDA() failed; not enough memory");
goto exit;
}
::wcscpy(m_pwszAuthInfo, Token);
}
next_token:
Token = ::wcstok(NULL, Delimiters);
}
dwRetVal = PP_LOGON_SUCCESS;
}
else
{
PP_ASSERT(FALSE); // shouldn't reach here
goto exit;
}
exit:
if (pwszBuffer)
{
delete [] pwszBuffer;
}
return dwRetVal;
}
void LOGON::CheckForVersionChange(
HINTERNET hRequest
)
{
WCHAR wszBuffer[256];
DWORD dwBufferLen = sizeof(wszBuffer) / sizeof(WCHAR);
BOOL fDownloadNewNexusConfig = FALSE;
if (!m_pSession->QueryHeaders(hRequest,
WINHTTP_QUERY_PASSPORT_CONFIG,
wszBuffer,
&dwBufferLen))
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::CheckForVersionChange() failed; no PassportConfig header found");
goto exit;
}
WCHAR Delimiters[] = L",";
PWSTR Token = ::wcstok(wszBuffer, Delimiters);
while (Token != NULL)
{
// skip leading white spaces
while (*Token == (L" ")[0]) { ++Token; }
if (*Token == L'\0')
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::CheckForVersionChange() : no text in between commas");
goto next_token;
}
if (!::_wcsnicmp(Token, L"ConfigVersion", ::wcslen(L"ConfigVersion")))
{
PWSTR pwszConfigVersion = ::wcsstr(Token, L"=");
if (pwszConfigVersion == NULL)
{
DoTraceMessage(PP_LOG_WARNING, "LOGON::CheckForVersionChange() : no = after ConfigVersion");
goto next_token;
}
pwszConfigVersion++; // skip "="
while (*pwszConfigVersion == (L" ")[0]) { ++pwszConfigVersion; } // skip leading white spaces
if (*pwszConfigVersion == L'\0')
{
goto next_token;
}
if ((DWORD)_wtoi(pwszConfigVersion) > m_pSession->GetNexusVersion())
{
fDownloadNewNexusConfig = TRUE;
}
DoTraceMessage(PP_LOG_INFO, "ConfigVersion URL %ws found", pwszConfigVersion);
}
next_token:
Token = ::wcstok(NULL, Delimiters);
}
if (fDownloadNewNexusConfig)
{
m_pSession->PurgeAllDAInfo();
m_pSession->GetDAInfoFromPPNexus();
}
exit:
return;
}
VOID PrvLogonStatusCallback(
IN HINTERNET hInternet,
IN DWORD_PTR dwContext,
IN DWORD dwInternetStatus,
IN LPVOID lpvStatusInformation,
IN DWORD dwStatusInformationLength
)
{
LOGON* pLogon = reinterpret_cast<LOGON*>(dwContext);
pLogon->StatusCallback(hInternet,
dwInternetStatus,
lpvStatusInformation,
dwStatusInformationLength);
}
VOID LOGON::StatusCallback(
IN HINTERNET hInternet,
IN DWORD dwInternetStatus,
IN LPVOID lpvStatusInformation,
IN DWORD dwStatusInformationLength)
{
UNREFERENCED_PARAMETER(dwStatusInformationLength);
if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REDIRECT)
{
::wcsncpy(m_wNewDAUrl, (LPCWSTR)lpvStatusInformation, MAX_PASSPORT_URL_LENGTH);
m_wNewDAUrl[MAX_PASSPORT_URL_LENGTH] = 0;
#ifdef DBG
BOOL fRet =
#else
(VOID)
#endif
m_pSession->AddHeaders(hInternet,
m_pwszAuthHeader,
::wcslen(m_pwszAuthHeader),
WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE
);
PP_ASSERT(fRet == TRUE);
}
}
BOOL LOGON::GetLogonHost(
PWSTR pwszHostName,
OUT PDWORD pdwHostNameLen
) const
{
if (*pdwHostNameLen < DWORD(::wcslen(m_wDAHostName) + 1))
{
*pdwHostNameLen = ::wcslen(m_wDAHostName) + 1;
return FALSE;
}
PP_ASSERT(pwszHostName != NULL);
::wcscpy(pwszHostName, m_wDAHostName);
*pdwHostNameLen = ::wcslen(m_wDAHostName) + 1;
return TRUE;
}
//Determine if the character is unsafe under the URI RFC document
inline BOOL PPIsUnsafeUrlChar(TCHAR chIn) throw()
{
unsigned char ch = (unsigned char)chIn;
switch(ch)
{
case ';': case '\\': case '?': case '@': case '&':
case '=': case '+': case '$': case ',': case ' ':
case '<': case '>': case '#': case '%': case '\"':
case '{': case '}': case '|':
case '^': case '[': case ']': case '`':
return TRUE;
default:
{
if (ch < 32 || ch > 126)
return TRUE;
return FALSE;
}
}
}
BOOL PPEscapeUrl(LPCSTR lpszStringIn,
LPSTR lpszStringOut,
DWORD* pdwStrLen,
DWORD dwMaxLength,
DWORD dwFlags)
{
TCHAR ch;
DWORD dwLen = 0;
BOOL bRet = TRUE;
UNREFERENCED_PARAMETER(dwFlags);
while((ch = *lpszStringIn++) != '\0')
{
//if we are at the maximum length, set bRet to FALSE
//this ensures no more data is written to lpszStringOut, but
//the length of the string is still updated, so the user
//knows how much space to allocate
if (dwLen == dwMaxLength)
{
bRet = FALSE;
}
//if we are encoding and it is an unsafe character
if (PPIsUnsafeUrlChar(ch))
{
{
//if there is not enough space for the escape sequence
if (dwLen >= (dwMaxLength-3))
{
bRet = FALSE;
}
if (bRet)
{
//output the percent, followed by the hex value of the character
*lpszStringOut++ = '%';
sprintf(lpszStringOut, "%.2X", (unsigned char)(ch));
lpszStringOut+= 2;
}
dwLen += 2;
}
}
else //safe character
{
if (bRet)
*lpszStringOut++ = ch;
}
dwLen++;
}
if (bRet)
*lpszStringOut = '\0';
*pdwStrLen = dwLen;
return bRet;
}
// -----------------------------------------------------------------------------
DWORD LOGON::Logon(
BOOL fAnonymous
)
{
PP_ASSERT(m_pSession != NULL);
DWORD dwRetVal = (DWORD)PP_GENERIC_ERROR;
BOOL fTicketRequest;
HINTERNET hRequest = 0;
DWORD dwFlags = 0;
::wcscpy(m_pwszAuthHeader, L"Authorization: Passport1.4 ");
if (m_fCredsPresent && !fAnonymous)
{
if (m_pSession->GetNexusVersion() >= 10)
{
DWORD dwUTF8CredLen = max(::wcslen(m_pwszSignIn), ::wcslen(m_pwszPassword)) * 3;
DWORD dwEscCredLen = dwUTF8CredLen * 3;
DWORD dwActualEscCredLen;
PSTR pszUTF8Cred = NULL;
PSTR pszEscCred = NULL;
PWSTR pwszEscCred = NULL;
BOOL fExit = TRUE;
pszUTF8Cred = new CHAR[dwUTF8CredLen];
if (pszUTF8Cred == NULL)
{
goto local_cleanup;
}
pszUTF8Cred[0] = 0;
pszEscCred = new CHAR[dwEscCredLen];
if (pszEscCred == NULL)
{
goto local_cleanup;
}
pszEscCred[0] = 0;
pwszEscCred = new WCHAR[dwEscCredLen];
if (pwszEscCred == NULL)
{
goto local_cleanup;
}
pwszEscCred[0] = 0;
::WideCharToMultiByte(CP_UTF8, 0, m_pwszSignIn, -1, pszUTF8Cred, dwUTF8CredLen, NULL, NULL);
::PPEscapeUrl(pszUTF8Cred, pszEscCred, &dwActualEscCredLen, dwEscCredLen, 0);
int UsernameLength = ::MultiByteToWideChar(CP_ACP, 0, pszEscCred, -1, pwszEscCred, dwEscCredLen);
if (UsernameLength > MAX_PASSPORT_USERNAME_LENGTH)
{
goto local_cleanup;
}
::wcscat(m_pwszAuthHeader, L"sign-in=");
::wcscat(m_pwszAuthHeader, pwszEscCred);
::wcscat(m_pwszAuthHeader, L",");
::WideCharToMultiByte(CP_UTF8, 0, m_pwszPassword, -1, pszUTF8Cred, dwUTF8CredLen, NULL, NULL);
::PPEscapeUrl(pszUTF8Cred, pszEscCred, &dwActualEscCredLen, dwEscCredLen, 0);
int PasswordLength = ::MultiByteToWideChar(CP_ACP, 0, pszEscCred, -1, pwszEscCred, dwEscCredLen);
if (PasswordLength > MAX_PASSPORT_PASSWORD_LENGTH)
{
goto local_cleanup;
}
::wcscat(m_pwszAuthHeader, L"pwd=");
::wcscat(m_pwszAuthHeader, pwszEscCred);
::wcscat(m_pwszAuthHeader, L",");
fExit = FALSE;
local_cleanup:
if (pwszEscCred)
{
SecureZeroMemory(pwszEscCred, ::wcslen(pwszEscCred) * sizeof(WCHAR));
delete [] pwszEscCred;
}
if (pszEscCred)
{
SecureZeroMemory(pszEscCred, ::strlen(pszEscCred));
delete [] pszEscCred;
}
if (pszUTF8Cred)
{
SecureZeroMemory(pszUTF8Cred, ::strlen(pszUTF8Cred));
delete [] pszUTF8Cred;
}
if (fExit)
{
goto exit;
}
}
else
{
if (::wcslen(m_pwszSignIn) > MAX_PASSPORT_USERNAME_LENGTH)
{
goto exit;
}
::wcscat(m_pwszAuthHeader, L"sign-in=");
::wcscat(m_pwszAuthHeader, m_pwszSignIn);
::wcscat(m_pwszAuthHeader, L",");
if (::wcslen(m_pwszPassword) > MAX_PASSPORT_PASSWORD_LENGTH)
{
goto exit;
}
::wcscat(m_pwszAuthHeader, L"pwd=");
::wcscat(m_pwszAuthHeader, m_pwszPassword);
::wcscat(m_pwszAuthHeader, L",");
}
FILETIME ftCredsEntered;
::SystemTimeToFileTime(&m_TimeCredsEntered, &ftCredsEntered);
SYSTEMTIME stCurrent;
::GetSystemTime(&stCurrent);
FILETIME ftCurrent;
::SystemTimeToFileTime(&stCurrent, &ftCurrent);
LONGLONG llElapsedTime;
llElapsedTime = (*(LONGLONG *)&ftCurrent) - (*(LONGLONG *)&ftCredsEntered);
llElapsedTime /= (LONGLONG)10000000;
DWORD dwElapsedTime = (DWORD)llElapsedTime;
WCHAR wElapsedTime[16];
::wsprintfW(wElapsedTime, L"%d", dwElapsedTime);
::wcscat(m_pwszAuthHeader, L"elapsed-time=");
::wcscat(m_pwszAuthHeader, wElapsedTime);
::wcscat(m_pwszAuthHeader, L",");
if (m_wTimeSkew[0] && (::wcslen(m_wTimeSkew) <= MAX_PASSPORT_TIME_SKEW_LENGTH))
{
::wcscat(m_pwszAuthHeader, m_wTimeSkew);
::wcscat(m_pwszAuthHeader, L",");
}
fTicketRequest = FALSE; // this is a login request, since we've gather credentials
}
else
{
::wcscat(m_pwszAuthHeader, L"tname = , ");
fTicketRequest = TRUE;
}
::wcscat(m_pwszAuthHeader, m_pwszTicketRequest);
retry:
// attempt connecting to the Passport DA
if (m_hConnect)
{
m_pSession->CloseHandle(m_hConnect);
}
WCHAR wDATargetObj[256];
DWORD fStstus = m_pSession->GetDAInfo(m_pwszSignIn,
m_wDAHostName, MAX_PASSPORT_HOST_LENGTH,
wDATargetObj, 256);
if (fStstus == FALSE)
{
goto exit;
}
m_hConnect = m_pSession->Connect(m_wDAHostName/*m_pSession->GetLoginHost()*/,
INTERNET_DEFAULT_HTTPS_PORT);
if (m_hConnect == NULL)
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "LOGON::Open() failed; can not connect to %ws, Error = %d",
m_wDAHostName, dwErrorCode);
goto exit;
}
if (hRequest)
{
m_pSession->CloseHandle(hRequest);
}
dwFlags = m_dwParentFlags & ~INTERNET_FLAG_NO_COOKIES;
hRequest = m_pSession->OpenRequest(m_hConnect,
NULL, // "GET"
wDATargetObj/*m_pSession->GetLoginTarget()*/,
dwFlags | WINHTTP_FLAG_SECURE,
(DWORD_PTR)this
);
if (hRequest == NULL)
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "LOGON::Logon() failed; OpenRequest() to %ws failed, Error Code = %d",
wDATargetObj, dwErrorCode);
goto exit;
}
if (m_dwParentFlags & INTERNET_FLAG_NO_COOKIES)
{
ULONG ulParam = WINHTTP_DISABLE_COOKIES;
if (!WinHttpSetOption (hRequest, WINHTTP_OPTION_DISABLE_FEATURE , &ulParam, sizeof(ulParam)))
{
DWORD dwErrorCode = GetLastError();
DoTraceMessage(PP_LOG_ERROR, "LOGON::Logon() failed; WinHttpSetOption(WINHTTP_OPTION_DISABLE_FEATURE, NO_COOKIES), Error Code = %d", dwErrorCode);
goto exit;
}
}
if (m_pSession->m_pwszProxyUser && m_pSession->m_pwszProxyPass)
{
m_pSession->SetOption(hRequest, WINHTTP_OPTION_PROXY_USERNAME, (void*)m_pSession->m_pwszProxyUser, wcslen(m_pSession->m_pwszProxyUser) + 1);
m_pSession->SetOption(hRequest, WINHTTP_OPTION_PROXY_PASSWORD, (void*)m_pSession->m_pwszProxyPass, wcslen(m_pSession->m_pwszProxyPass) + 1);
}
m_wNewDAUrl[0] = 0;
m_pSession->SetStatusCallback(hRequest, PrvLogonStatusCallback);
if (!m_pSession->SendRequest(hRequest,
m_pwszAuthHeader,
::wcslen(m_pwszAuthHeader),
(DWORD_PTR)this))
{
DWORD dwErrorCode = ::GetLastError();
if (dwErrorCode != ERROR_SUCCESS)
{
DoTraceMessage(PP_LOG_ERROR, "LOGON::Logon() failed; SendRequest() failed, Error Code = %d",
dwErrorCode);
m_pSession->PurgeDAInfo(m_pwszSignIn);
if (m_pSession->GetDAInfoFromPPNexus() == TRUE)
{
goto retry;
}
goto exit;
}
}
if (m_pSession->ReceiveResponse(hRequest) == FALSE)
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "LOGON::Logon() failed; ReceiveResponse() failed, Error Code = %d",
dwErrorCode);
goto exit;
}
{
DWORD dwStatus, dwStatusLen;
dwStatusLen = sizeof(dwStatus);
if (!m_pSession->QueryHeaders(hRequest,
WINHTTP_QUERY_FLAG_NUMBER | WINHTTP_QUERY_STATUS_CODE,
&dwStatus,
&dwStatusLen))
{
DWORD dwErrorCode = ::GetLastError();
DoTraceMessage(PP_LOG_ERROR, "LOGON::Logon() failed; can not retrieve Status Code, Error Code = %d",
dwErrorCode);
goto exit;
}
if (dwStatus == HTTP_STATUS_DENIED)
{
dwRetVal = Handle401FromDA(hRequest, fTicketRequest);
}
else if (dwStatus == HTTP_STATUS_OK)
{
dwRetVal = Handle200FromDA(hRequest);
}
else
{
//PP_ASSERT(TRUE); // shouldn't reach here
//goto exit;
}
CheckForVersionChange(hRequest);
if (dwRetVal == PP_GENERIC_ERROR)
{
m_pSession->PurgeDAInfo(m_pwszSignIn);
if (m_pSession->GetDAInfoFromPPNexus() == TRUE)
{
goto retry;
}
}
else
{
if (m_wNewDAUrl[0])
{
m_pSession->UpdateDAInfo(m_pwszSignIn,
m_wNewDAUrl);
m_wNewDAUrl[0] = 0;
}
}
}
exit:
if (hRequest)
{
m_pSession->CloseHandle(hRequest);
}
return dwRetVal;
}
// -----------------------------------------------------------------------------
BOOL LOGON::GetChallengeInfo(
PBOOL pfPrompt,
PWSTR pwszCbUrl,
PDWORD pdwCbUrlLen,
PWSTR pwszCbText,
PDWORD pdwTextLen,
PWSTR pwszRealm,
DWORD dwMaxRealmLen
) const
{
if (pfPrompt)
{
*pfPrompt = m_fPrompt;
}
if (m_pwszCbtxt == NULL)
{
*pdwTextLen = 0;
}
else
{
if (*pdwTextLen < DWORD(::wcslen(m_pwszCbtxt) + 1))
{
*pdwTextLen = ::wcslen(m_pwszCbtxt) + 1;
}else
{
::wcscpy(pwszCbText, m_pwszCbtxt);
}
}
if (m_pwszCbUrl == NULL)
{
*pdwCbUrlLen = 0;
}
else
{
if (*pdwCbUrlLen < DWORD(::wcslen(m_pwszCbUrl) + 1))
{
*pdwCbUrlLen = ::wcslen(m_pwszCbUrl) + 1;
}
else
{
::wcscpy(pwszCbUrl, m_pwszCbUrl);
}
}
if (pwszRealm)
{
::wcsncpy(pwszRealm, m_wRealm, dwMaxRealmLen-1);
}
return TRUE;
}
BOOL LOGON::GetChallengeContent(
PBYTE pContent,
OUT PDWORD pdwContentLen
) const
{
if(!DelayLoad( &g_moduleOle32))
{
*pdwContentLen = 0;
return FALSE;
}
if (m_p401Content == NULL)
{
*pdwContentLen = 0;
return FALSE;
}
HGLOBAL hContent;
if (DL(GetHGlobalFromStream)(m_p401Content, &hContent) != S_OK)
{
*pdwContentLen = 0;
return FALSE;
}
DWORD dwContentLen = (DWORD)GlobalSize(hContent);
if (*pdwContentLen < dwContentLen)
{
*pdwContentLen = dwContentLen;
return FALSE;
}
LPVOID pvContent = GlobalLock(hContent);
memcpy(pContent, pvContent, dwContentLen);
GlobalUnlock(hContent);
*pdwContentLen = dwContentLen;
return TRUE;
}
// -----------------------------------------------------------------------------
BOOL LOGON::GetAuthorizationInfo(
PWSTR pwszTicket,
PDWORD pdwTicketLen,
PBOOL pfKeepVerb,
PWSTR pwszUrl,
PDWORD pdwUrlLen
) const
{
if (*pdwTicketLen < DWORD(::wcslen(m_pwszAuthInfo) + 1))
{
*pdwTicketLen = ::wcslen(m_pwszAuthInfo) + 1;
return FALSE;
}
PP_ASSERT(pwszTicket != NULL);
::wcscpy(pwszTicket, m_pwszAuthInfo);
*pdwTicketLen = ::wcslen(m_pwszAuthInfo) + 1;
if (m_pwszReturnUrl == NULL)
{
if (pfKeepVerb)
{
*pfKeepVerb = TRUE;
}
*pdwUrlLen = 0;
return TRUE;
}
if (*pdwUrlLen < DWORD(::wcslen(m_pwszReturnUrl) + 1))
{
*pdwUrlLen = ::wcslen(m_pwszReturnUrl) + 1;
return FALSE;
}
PP_ASSERT(pwszUrl != NULL);
::wcscpy(pwszUrl, m_pwszReturnUrl);
if (pfKeepVerb)
{
*pfKeepVerb = FALSE;
}
*pdwUrlLen = ::wcslen(m_pwszReturnUrl) + 1;
return TRUE;
}