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.
 
 
 
 
 
 

4859 lines
142 KiB

/**********************************************************************/
/** Microsoft Passport **/
/** Copyright(c) Microsoft Corporation, 1999 - 2001 **/
/**********************************************************************/
/*
manager.cpp
COM object for manager interface
FILE HISTORY:
*/
// Manager.cpp : Implementation of CManager
#include "stdafx.h"
#include <httpext.h>
#include "Manager.h"
#include <httpfilt.h>
#include <time.h>
#include <malloc.h>
#include <wininet.h>
#include <nsconst.h>
#include "VariantUtils.h"
#include "HelperFuncs.h"
#include "RegistryConfig.h"
#include "PassportService_i.c"
#include "atlbase.h"
PWSTR GetVersionString();
//using namespace ATL;
// gmarks
#include "Monitoring.h"
/////////////////////////////////////////////////////////////////////////////
// CManager
#include "passporttypes.h"
// static utility func
static VOID GetTicketAndProfileFromHeader(PWSTR pszAuthHeader,
PWSTR& pszTicket,
PWSTR& pszProfile,
PWSTR& pszF);
// Used for cookie expiration.
const DATE g_dtExpire = 365*137;
const DATE g_dtExpired = 365*81;
//===========================================================================
//
// CManager
//
CManager::CManager() :
m_fromQueryString(false), m_ticketValid(VARIANT_FALSE),
m_profileValid(VARIANT_FALSE), m_lNetworkError(0),
m_pRegistryConfig(NULL), m_pECB(NULL), m_pFC(NULL),
m_bIsTweenerCapable(FALSE),
m_bSecureTransported(false)
{
PPTraceFuncV func(PPTRACE_FUNC, "CManager");
// ticket object
m_pUnkMarshaler = NULL;
try
{
m_piTicket = new CComObject<CTicket>();
}
catch(...)
{
m_piTicket = NULL;
}
if(m_piTicket)
m_piTicket->AddRef();
// profile object
try
{
m_piProfile = new CComObject<CProfile>();
}
catch(...)
{
m_piProfile = NULL;
}
if(m_piProfile)
m_piProfile->AddRef();
m_bOnStartPageCalled = false;
}
//===========================================================================
//
// ~CManager
//
CManager::~CManager()
{
PPTraceFuncV func(PPTRACE_FUNC, "~CManager");
if(m_pRegistryConfig)
m_pRegistryConfig->Release();
if (m_piTicket) m_piTicket->Release();
if (m_piProfile) m_piProfile->Release();
}
//===========================================================================
//
// IfConsentCookie -- if a consent cookie should be sent back
// return value: S_OK -- has consent cookie; S_FALSE -- no consent cookie
// output param: The consent cookie
//
HRESULT CManager::IfConsentCookie(BSTR* pMSPConsent)
{
BSTR bstrRawConsent = NULL;
HRESULT hr = S_FALSE;
PPTraceFunc<HRESULT>
func(
PPTRACE_FUNC,
hr,
"IfConsentCookie"," <<<< %lx",
pMSPConsent
);
if (!m_piTicket || !m_piProfile || !m_pRegistryConfig)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
LPCSTR domain = m_pRegistryConfig->getTicketDomain();
LPCSTR path = m_pRegistryConfig->getTicketPath();
LPCSTR tertiaryDomain = m_pRegistryConfig->getProfileDomain();
LPCSTR tertiaryPath = m_pRegistryConfig->getProfilePath();
if (!tertiaryPath) tertiaryPath = "/";
if(!domain) domain = "";
if(!path) path = "";
if(!tertiaryDomain) tertiaryDomain = "";
if(!tertiaryPath) tertiaryPath = "";
//
// if a separate consent cookie is necessary
if((lstrcmpiA(domain, tertiaryDomain) || lstrcmpiA(path, tertiaryPath)) &&
(m_piTicket->GetPassportFlags() & k_ulFlagsConsentCookieNeeded) &&
!m_pRegistryConfig->bInDA() )
{
if (pMSPConsent == NULL) // no output param
hr = S_OK;
else
{
*pMSPConsent = NULL;
CCoCrypt* crypt = m_pRegistryConfig->getCurrentCrypt();
if (!crypt)
{
hr = E_FAIL;
goto Cleanup;
}
// get the consent cookie from ticket
hr = m_piTicket->get_unencryptedCookie(CTicket::MSPConsent, 0, &bstrRawConsent);
if (FAILED(hr))
goto Cleanup;
// encrypt it with partner's key
if (!crypt->Encrypt(m_pRegistryConfig->getCurrentCryptVersion(),
(LPSTR)bstrRawConsent,
SysStringByteLen(bstrRawConsent),
pMSPConsent))
{
hr = E_FAIL;
goto Cleanup;
}
}
}
Cleanup:
if (bstrRawConsent)
{
SysFreeString(bstrRawConsent);
}
if(pMSPConsent)
PPTracePrint(PPTRACE_RAW, ">>> pMSPConsent:%ws", PPF_WCHAR(*pMSPConsent));
return hr;
}
//===========================================================================
//
// IfAlterAuthCookie
//
// return S_OK -- when auth cookie is different from t (altered), should use
// the cookie and secAuth cookie returned
// S_FALSE -- not altered -- can use the t as auth cookie
// if MSPSecAuth != NULL, write the secure cookie
HRESULT CManager::IfAlterAuthCookie(BSTR* pMSPAuth, BSTR* pMSPSecAuth)
{
_ASSERT(pMSPAuth && pMSPSecAuth);
*pMSPAuth = NULL;
*pMSPSecAuth = NULL;
HRESULT hr = S_FALSE;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"IfAlterAuthCookie", "<<< %lx, %lx",
pMSPAuth, pMSPSecAuth);
if (!m_piTicket || !m_piProfile || !m_pRegistryConfig)
{
return E_OUTOFMEMORY;
}
if (!(m_piTicket->GetPassportFlags() & k_ulFlagsSecuredTransportedTicket)
|| !m_bSecureTransported)
{
return hr;
}
BSTR bstrRawAuth = NULL;
BSTR bstrRawSecAuth = NULL;
CCoCrypt* crypt = m_pRegistryConfig->getCurrentCrypt();
if (!crypt)
{
hr = PM_CANT_DECRYPT_CONFIG;
goto Cleanup;
}
hr = m_piTicket->get_unencryptedCookie(CTicket::MSPAuth, 0, &bstrRawAuth);
if (FAILED(hr))
goto Cleanup;
if (!crypt->Encrypt(m_pRegistryConfig->getCurrentCryptVersion(),
(LPSTR)bstrRawAuth,
SysStringByteLen(bstrRawAuth),
pMSPAuth))
{
hr = PM_CANT_DECRYPT_CONFIG;
goto Cleanup;
}
hr = m_piTicket->get_unencryptedCookie(CTicket::MSPSecAuth, 0, &bstrRawSecAuth);
if (FAILED(hr))
goto Cleanup;
if (!crypt->Encrypt(m_pRegistryConfig->getCurrentCryptVersion(),
(LPSTR)bstrRawSecAuth,
SysStringByteLen(bstrRawSecAuth),
pMSPSecAuth))
{
hr = PM_CANT_DECRYPT_CONFIG;
goto Cleanup;
}
Cleanup:
if (bstrRawAuth)
{
SysFreeString(bstrRawAuth);
}
if (bstrRawSecAuth)
{
SysFreeString(bstrRawSecAuth);
}
PPTracePrint(PPTRACE_RAW,
">>> pMSPAuth:%ws, pMSPSecAuth:%ws",
PPF_WCHAR(*pMSPAuth),
PPF_WCHAR(*pMSPSecAuth));
return hr;
}
//===========================================================================
//
// wipeState -- cleanup teh state of manager object
//
void
CManager::wipeState()
{
PPTraceFuncV func(PPTRACE_FUNC, "wipeState");
m_pECB = NULL;
m_pFC = NULL;
m_bIsTweenerCapable = FALSE;
m_bOnStartPageCalled = false;
m_fromQueryString = false;
m_lNetworkError = 0;
m_ticketValid = VARIANT_FALSE;
m_profileValid = VARIANT_FALSE;
m_piRequest = NULL;
m_piResponse = NULL;
// cleanup ticket content
if(m_piTicket) m_piTicket->put_unencryptedTicket(NULL);
// cleanup profile content
if(m_piProfile) m_piProfile->put_unencryptedProfile(NULL);
// cleanup buffered registry config
if(m_pRegistryConfig)
{
m_pRegistryConfig->Release();
m_pRegistryConfig = NULL;
}
}
//===========================================================================
//
// InterfaceSupportsErrorInfo
//
STDMETHODIMP CManager::InterfaceSupportsErrorInfo(REFIID riid)
{
PPTraceFuncV func(PPTRACE_FUNC, "InterfaceSupportsErrorInfo");
static const IID* arr[] =
{
&IID_IPassportManager,
&IID_IPassportManager2,
&IID_IPassportManager3,
&IID_IDomainMap,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
//===========================================================================
//
// OnStartPage -- called by ASP pages automatically by IIS when declared on the page
//
STDMETHODIMP CManager::OnStartPage (IUnknown* pUnk)
{
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPage"," <<< %lx",
pUnk);
if(!pUnk)
{
return hr = E_POINTER;
}
IScriptingContextPtr spContext;
spContext = pUnk;
// Get Request Object Pointer
hr = OnStartPageASP(spContext->Request, spContext->Response);
return hr;
}
BSTR
MyA2W(
char *src
)
{
if (src == NULL)
{
return NULL;
}
BSTR str = NULL;
int nConvertedLen = MultiByteToWideChar(GetACP(), 0, src, -1, NULL, NULL);
str = ::SysAllocStringLen(NULL, nConvertedLen - 1);
if (str != NULL)
{
if (!MultiByteToWideChar(GetACP(), 0, src, -1, str, nConvertedLen))
{
SysFreeString(str);
str = NULL;
}
}
return str;
}
//===========================================================================
//
// OnStartPageASP -- called by asp pages when created by using factory object
// FUTURE --- should change the OnStartPage function to use this function
//
STDMETHODIMP CManager::OnStartPageASP(
IDispatch* piRequest,
IDispatch* piResponse
)
{
HRESULT hr = S_OK;
char* spBuf = NULL;
BSTR bstrName=NULL;
BSTR bstrValue=NULL;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageASP",
" <<< %lx, %lx", piRequest, piResponse);
PassportLog("CManager::OnStartPageASP Enter:\r\n");
if(!piRequest || !piResponse)
return hr = E_INVALIDARG;
USES_CONVERSION;
try
{
IRequestDictionaryPtr piServerVariables;
_variant_t vtItemName;
_variant_t vtHTTPS;
_variant_t vtMethod;
_variant_t vtPath;
_variant_t vtQs;
_variant_t vtServerPort;
_variant_t vtHeaders;
CComQIPtr<IResponse> spResponse;
CComQIPtr<IRequest> spRequest;
// Get Request Object Pointer
spRequest = piRequest;
spResponse = piResponse;
//
// Get the server variables collection.
//
spRequest->get_ServerVariables(&piServerVariables);
//
// now see if that's a special redirect
// requiring challenge generation
// if so processing stops here ....
//
if (checkForPassportChallenge(piServerVariables))
{
PPTracePrint(PPTRACE_RAW, "special redirect for Challenge");
return S_OK;
}
//
// Might need this for multi-site, or secure ticket/profile
//
vtItemName = L"HTTPS";
piServerVariables->get_Item(vtItemName, &vtHTTPS);
if(vtHTTPS.vt != VT_BSTR)
vtHTTPS.ChangeType(VT_BSTR);
DWORD flags = 0;
if(vtHTTPS.bstrVal && lstrcmpiW(L"on", vtHTTPS.bstrVal) == 0)
flags |= PASSPORT_HEADER_FLAGS_HTTPS;
// headers
vtItemName.Clear();
vtItemName = L"ALL_RAW";
piServerVariables->get_Item(vtItemName, &vtHeaders);
if(vtHeaders.vt != VT_BSTR){
vtHeaders.ChangeType(VT_BSTR);
}
// path
vtItemName.Clear();
vtItemName = L"PATH_INFO";
piServerVariables->get_Item(vtItemName, &vtPath);
if(vtPath.vt != VT_BSTR)
vtPath.ChangeType(VT_BSTR);
// vtMethod
vtItemName.Clear();
vtItemName = L"REQUEST_METHOD";
piServerVariables->get_Item(vtItemName, &vtMethod);
if(vtMethod.vt != VT_BSTR)
vtMethod.ChangeType(VT_BSTR);
// QUERY_STRING
vtItemName.Clear();
vtItemName = L"QUERY_STRING";
piServerVariables->get_Item(vtItemName, &vtQs);
if(vtQs.vt != VT_BSTR)
vtQs.ChangeType(VT_BSTR);
DWORD bufSize = 0;
DWORD requiredBufSize = MAX_URL_LENGTH;
// make sure the size if sufficient
while(bufSize < requiredBufSize)
{
if (spBuf)
{
free(spBuf);
}
if(NULL == (spBuf = (char *)malloc(requiredBufSize)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
bufSize = requiredBufSize;
hr = OnStartPageHTTPRawEx(W2A(vtMethod.bstrVal),
W2A(vtPath.bstrVal),
W2A(vtQs.bstrVal),
NULL, // version
W2A(vtHeaders.bstrVal),
flags,
&requiredBufSize,
spBuf);
}
// write the cookies
if(hr == S_OK && requiredBufSize && *spBuf)
{
char* pNext = spBuf;
while(pNext != NULL)
{
char* pName = pNext;
char* pValue = strchr(pName, ':');
if(pValue)
{
// make temp sub string
TempSubStr tsN(pName, pValue - pName);
bstrName = MyA2W(pName);
if (bstrName) {
++pValue;
pNext = strstr(pValue, "\r\n"); // new line
if(pNext)
{
// make temp sub string
TempSubStr tsV(pValue, pNext - pValue);
pNext += 2;
bstrValue = MyA2W(pValue);
}
else
{
bstrValue = MyA2W(pValue);
}
if (bstrValue)
{
spResponse->raw_AddHeader(bstrName, bstrValue);
}
}
}
else
{
pNext = pValue;
}
if (bstrName) {
SysFreeString(bstrName);
bstrName = NULL;
}
if (bstrValue) {
SysFreeString(bstrValue);
bstrValue = NULL;
}
}
}
if (spBuf) {
free(spBuf);
spBuf = NULL;
}
// Get Request Object Pointer
m_piRequest = piRequest;
// Get Response Object Pointer
m_piResponse = piResponse;
}
catch (...)
{
if (m_piRequest.GetInterfacePtr() != NULL)
m_piRequest.Release();
if (m_piResponse.GetInterfacePtr() != NULL)
m_piResponse.Release();
m_bOnStartPageCalled = false;
if (spBuf) {
free(spBuf);
}
if (bstrName) {
SysFreeString(bstrName);
}
if (bstrValue) {
SysFreeString(bstrValue);
}
}
exit:
return hr = S_OK;
}
//===========================================================================
//
// OnStartPageManual -- authenticate with t, and p, MSPAuth, MSPProf, MSPConsent, MSPsecAuth
// not recommended to use, will be depracated
//
STDMETHODIMP CManager::OnStartPageManual(
BSTR qsT,
BSTR qsP,
BSTR mspauth,
BSTR mspprof,
BSTR mspconsent,
VARIANT mspsec,
VARIANT* pCookies
)
{
int hasSec;
BSTR bstrSec;
BSTR bstrConsent = NULL;
BSTR bstrNewAuth = NULL;
BSTR bstrNewSecAuth = NULL;
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageManual",
" <<< %ws, %ws, %ws, %ws, %ws", qsT, qsP, mspauth, mspprof, mspconsent);
PassportLog("CManager::OnStartPageManual Enter: T = %ws, P = %ws, A = %ws, PR = %ws\r\n",
qsT, qsP, mspauth, mspprof);
if (!g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_piTicket || !m_piProfile)
{
return E_OUTOFMEMORY;
}
wipeState();
if(m_pRegistryConfig)
m_pRegistryConfig->Release();
m_pRegistryConfig = g_config->checkoutRegistryConfig();
// Auth with Query String T & P first
if (handleQueryStringData(qsT, qsP))
{
VARIANT_BOOL persist;
_bstr_t domain;
_bstr_t path;
_bstr_t bstrAuth;
_bstr_t bstrProf;
bstrAuth.Assign(qsT);
bstrProf.Assign(qsP);
if (pCookies)
{
VariantInit(pCookies);
if (m_pRegistryConfig->getTicketPath())
path = m_pRegistryConfig->getTicketPath();
else
path = L"/";
m_piTicket->get_HasSavedPassword(&persist);
BOOL bSetConsent = (S_OK == IfConsentCookie(&bstrConsent));
SAFEARRAYBOUND rgsabound;
rgsabound.lLbound = 0;
rgsabound.cElements = 2;
// secure cookie
if (m_bSecureTransported)
rgsabound.cElements++;
if(bSetConsent)
rgsabound.cElements++;
SAFEARRAY *sa = SafeArrayCreate(VT_VARIANT, 1, &rgsabound);
if (!sa)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
pCookies->vt = VT_ARRAY | VT_VARIANT;
pCookies->parray = sa;
WCHAR buf[4096];
DWORD bufSize;
long spot = 0;
VARIANT *vArray;
SafeArrayAccessData(sa, (void**)&vArray);
// write Auth cookies
BSTR auth, secAuth; // do not call SysFreeString on them, they are skin level copy
if (S_OK == IfAlterAuthCookie(&bstrNewAuth, &bstrNewSecAuth))
{
auth = bstrNewAuth;
secAuth = bstrNewSecAuth;
}
else
{
auth = bstrAuth;
secAuth = NULL;
}
domain = m_pRegistryConfig->getTicketDomain();
// add MSPAuth
if (domain.length())
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPAuth=%s; path=%s; domain=%s; %s\r\n",
(LPWSTR)auth, (LPWSTR)path, (LPWSTR)domain,
persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"");
}
else
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPAuth=%s; path=%s; %s\r\n",
(LPWSTR)auth, (LPWSTR)path,
persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"");
}
buf[4095] = L'\0';
vArray[spot].vt = VT_BSTR;
vArray[spot].bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(buf, bufSize);
spot++;
// add MSPSecAuth
if (m_bSecureTransported)
{
_bstr_t secDomain = m_pRegistryConfig->getSecureDomain();
_bstr_t secPath;
if (m_pRegistryConfig->getSecurePath())
secPath = m_pRegistryConfig->getSecurePath();
else
secPath = L"/";
if (secDomain.length())
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPSecAuth=%s; path=%s; domain=%s; %s; secure\r\n",
((secAuth && *secAuth) ? (LPWSTR)secAuth : L""), (LPWSTR)secPath, (LPWSTR)secDomain,
((!secAuth || *secAuth == 0) ? W_COOKIE_EXPIRES(EXPIRE_PAST)
: L""));
}
else
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPSecAuth=%s; path=%s; %s; secure\r\n",
((secAuth && *secAuth) ? (LPWSTR)secAuth : L""), (LPWSTR)secPath,
((!secAuth || *secAuth == 0) ? W_COOKIE_EXPIRES(EXPIRE_PAST)
: L""));
}
buf[4095] = L'\0';
vArray[spot].vt = VT_BSTR;
vArray[spot].bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(buf, bufSize);
spot++;
}
if (domain.length())
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPProf=%s; path=%s; domain=%s; %s\r\n",
(LPWSTR)bstrProf, (LPWSTR)path, (LPWSTR)domain,
persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"");
}
else
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPProf=%s; path=%s; %s\r\n",
(LPWSTR)bstrProf, (LPWSTR)path,
persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"");
}
buf[4095] = L'\0';
vArray[spot].vt = VT_BSTR;
vArray[spot].bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(buf, bufSize);
spot++;
if(bSetConsent)
{
if (m_pRegistryConfig->getProfilePath())
path = m_pRegistryConfig->getProfilePath();
else
path = L"/";
domain = m_pRegistryConfig->getProfileDomain();
if (domain.length())
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPConsent=%s; path=%s; domain=%s; %s\r\n",
bSetConsent ? (LPWSTR)bstrConsent : L"", (LPWSTR)path, (LPWSTR)domain,
bSetConsent ? (persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"")
: W_COOKIE_EXPIRES(EXPIRE_PAST));
}
else
{
bufSize = _snwprintf(buf, 4096,
L"Set-Cookie: MSPConsent=%s; path=%s; %s\r\n",
bSetConsent ? (LPWSTR)bstrConsent : L"", (LPWSTR)path,
bSetConsent ? (persist ? W_COOKIE_EXPIRES(EXPIRE_FUTURE) : L"")
: W_COOKIE_EXPIRES(EXPIRE_PAST));
}
buf[4095] = L'\0';
vArray[spot].vt = VT_BSTR;
vArray[spot].bstrVal = ALLOC_AND_GIVEAWAY_BSTR_LEN(buf, bufSize);
spot++;
}
SafeArrayUnaccessData(sa);
}
}
// Now, check the cookies
if (!m_fromQueryString)
{
hasSec = GetBstrArg(mspsec, &bstrSec);
if(hasSec == CV_DEFAULT || hasSec == CV_BAD)
bstrSec = NULL;
handleCookieData(mspauth, mspprof, mspconsent, bstrSec);
if(hasSec == CV_FREE)
SysFreeString(bstrSec);
}
hr = S_OK;
Cleanup:
if (bstrNewAuth)
{
SysFreeString(bstrNewAuth);
}
if (bstrNewSecAuth)
{
SysFreeString(bstrNewSecAuth);
}
if (bstrConsent)
{
SysFreeString(bstrConsent);
}
PassportLog("CManager::OnStartPageManual Exit:\r\n");
return hr;
}
//===========================================================================
//
// OnStartPageECB -- Authenticate with ECB -- for ISAPI extensions
//
STDMETHODIMP CManager::OnStartPageECB(
LPBYTE pvECB,
DWORD* bufSize,
LPSTR pCookieHeader
)
{
if (!pvECB) return E_INVALIDARG;
EXTENSION_CONTROL_BLOCK* pECB = (EXTENSION_CONTROL_BLOCK*) pvECB;
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageECB",
" <<< %lx, %lx, %d, %lx", pvECB, bufSize, *bufSize, pCookieHeader);
ATL::CAutoVectorPtr<CHAR> spHTTPS;
ATL::CAutoVectorPtr<CHAR> spheaders;
spheaders.Attach(GetServerVariableECB(pECB, "ALL_RAW"));
spHTTPS.Attach(GetServerVariableECB(pECB, "HTTPS"));
DWORD flags = 0;
if((CHAR*)spHTTPS && lstrcmpiA("on", (CHAR*)spHTTPS) == 0)
flags |= PASSPORT_HEADER_FLAGS_HTTPS;
hr = OnStartPageHTTPRawEx(pECB->lpszMethod,
pECB->lpszPathInfo,
pECB->lpszQueryString,
NULL, // version
(CHAR*)spheaders,
flags, bufSize,
pCookieHeader);
m_pECB = pECB;
return hr;
}
//===========================================================================
//
// OnStartPageHTTPRaw -- Authenticate with HTTP request-line and headers
// returns response headers as output parameters
//
STDMETHODIMP CManager::OnStartPageHTTPRaw(
/* [string][in] */ LPCSTR request_line,
/* [string][in] */ LPCSTR headers,
/* [in] */ DWORD flags,
/* [out][in] */ DWORD *bufSize,
/* [size_is][out] */ LPSTR pCookieHeader)
{
// an old client, let's try the QS
DWORD dwSize;
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageHTTPRaw",
" <<< %s, %s, %lx, %lx, %d, %lx", request_line, headers, flags, bufSize, *bufSize, pCookieHeader);
LPCSTR pBuffer = GetRawQueryString(request_line, &dwSize);
if (pBuffer)
{
TempSubStr tss(pBuffer, dwSize);
hr = OnStartPageHTTPRawEx(NULL, NULL, pBuffer, NULL, headers, flags, bufSize, pCookieHeader);
}
else
hr = OnStartPageHTTPRawEx(NULL, NULL, NULL, NULL, headers, flags, bufSize, pCookieHeader);
return hr;
}
//===========================================================================
//
// @func OnStartPageHTTPRawEx -- Authenticate with HTTP request-line and headers
// returns response headers as output parameters. If *bufsize is not smaller
// the required length or pCookieHeader is NULL, the required length is returned
// in bufsize. In this case, an empty string is written into pCookieHeader if
// it is not NULL.
// method, path, HTTPVer are not being used in this version of the API
//
// @rdesc returns one of these values
// @flag E_POINTER | NULL bufSize
// @flag E_POINTER | not writable buffer given by pCookieHeader
// @flag PP_E_NOT_CONFIGURED | not valid state to call this method
// @flag S_OK
//
STDMETHODIMP CManager::OnStartPageHTTPRawEx(
/* [string][in] */ LPCSTR method,
/* [string][in] */ LPCSTR path,
/* [string][in] */ LPCSTR QS,
/* [string][in] */ LPCSTR HTTPVer,
/* [string][in] */ LPCSTR headers,
/* [in] */ DWORD flags,
/* [out][in] */ DWORD *bufSize, //@parm retuns the length of the headers. Could be 0 to ask for the req. len.
/* [size_is][out]*/ LPSTR pCookieHeader) //@parm buffer to hold the headers. Could be NULL to ask for the req. len
{
USES_CONVERSION;
if(bufSize == NULL)
return E_POINTER;
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageHTTPRawEx",
" <<< %s, %s, %s, %s, %s, %lx, %lx, %d, %lx", method, path, QS, HTTPVer, headers, flags, bufSize, *bufSize, pCookieHeader);
PassportLog("CManager::OnStartPageHTTPRawEx Enter:\r\n");
//
// 12002: if *bufSize is 0, we will not be writing into pCookieHeader
//
if(*bufSize == 0)
pCookieHeader = NULL;
if(pCookieHeader && IsBadWritePtr(pCookieHeader, *bufSize))
return E_POINTER;
if (!g_config || !g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_piTicket || !m_piProfile)
{
return E_OUTOFMEMORY;
}
wipeState();
DWORD dwSize;
LPCSTR pBuffer;
// used to convert to wide ...
WCHAR *pwszBuf = NULL;
enum {
header_Host,
header_Accept_Auth,
header_Authorization,
header_Cookie,
header_total
};
LPCSTR headerNames[header_total] = { "Host", "Accept-Auth", "Authorization", "Cookie"};
DWORD headerSizes[header_total];
LPCSTR headerValues[header_total] = {0};
GetRawHeaders(headers, headerNames, headerValues, headerSizes, header_total);
//
// Use the header to get the server name being requested
// so we can get the correct registry config. But only do this
// if we have some configured sites.
//
if(m_pRegistryConfig)
m_pRegistryConfig->Release();
pBuffer = headerValues[header_Host];
if(g_config->HasSites() && pBuffer)
{
TempSubStr tss(pBuffer, headerSizes[header_Host]);
TempSubStr tssRemovePort;
LPSTR pPort = strstr(pBuffer, ":");
if(pPort)
{
++pPort;
DWORD dwPort = atoi(pPort);
if(dwPort == 80 || dwPort == 443)
{
tssRemovePort.Set(pBuffer, pPort - pBuffer - 1);
}
}
// for port 80 and 443, this should be removed
PPTracePrint(PPTRACE_RAW, "SiteName %s", PPF_CHAR(pBuffer));
m_pRegistryConfig = g_config->checkoutRegistryConfig((LPSTR)pBuffer);
}
else
{
PPTracePrint(PPTRACE_RAW, "Default Site");
m_pRegistryConfig = g_config->checkoutRegistryConfig(NULL);
}
if (pCookieHeader)
*pCookieHeader = '\0';
//
// If we have a secure ticket/profile and the url is SSL,
// then tack on the MSPPuid cookie.
//
if(PASSPORT_HEADER_FLAGS_HTTPS & flags)
m_bSecureTransported = true;
else
m_bSecureTransported = false;
PPTracePrint(PPTRACE_RAW, "HTTPS:%d", m_bSecureTransported);
// see if client understands passport
pBuffer = headerValues[header_Accept_Auth];
if (pBuffer)
{
TempSubStr tss(pBuffer, headerSizes[header_Accept_Auth]);
if (strstr(pBuffer, PASSPORT_PROT14_A))
{
m_bIsTweenerCapable = TRUE;
PPTracePrint(PPTRACE_RAW, "PASSPORT_PROT14 capable");
}
}
BSTR ret = NULL;
CCoCrypt* crypt = NULL;
BOOL fParseSuccess = FALSE;
pBuffer = headerValues[header_Authorization];
PWSTR pwszTicket = NULL, pwszProfile = NULL, pwszF = NULL;
// use these when t&p come from qs
BSTR QSAuth = NULL, QSProf = NULL, QSErrflag = NULL;
BSTR bstrConsent = NULL;
BSTR bstrNewAuth = NULL;
BSTR bstrNewSecAuth = NULL;
if (pBuffer)
{
TempSubStr tss(pBuffer, headerSizes[header_Authorization]);
// has passport auth header
if(strstr(pBuffer, PASSPORT_PROT14_A))
{
// convert to wide ...
int cch = MultiByteToWideChar(GetACP(), 0, pBuffer, -1, NULL, NULL);
pwszBuf = (WCHAR*)LocalAlloc(LMEM_FIXED, (cch + 1) * sizeof (WCHAR));
if (NULL != pwszBuf)
{
if (0 != MultiByteToWideChar(GetACP(), 0, pBuffer, -1, pwszBuf, cch))
{
BSTR bstrT = NULL;
BSTR bstrP = NULL;
GetTicketAndProfileFromHeader(pwszBuf, pwszTicket, pwszProfile, pwszF);
// due to the fact that handleQueryStringData wants BSTRs we can't use
// the direct pointers we just got, so we have to make copies.
if( pwszTicket == NULL )
{
bstrT = NULL;
}
else
{
bstrT = SysAllocString(pwszTicket);
if (NULL == bstrT)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
if( pwszProfile == NULL )
{
bstrP = NULL;
}
else
{
bstrP = SysAllocString(pwszProfile);
if (NULL == bstrP)
{
SysFreeString(bstrT);
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
// make ticket and profile BSTRs
PPTracePrint(PPTRACE_RAW,
"PASSPORT_PROT14 Authorization <<< header:%ws, t:%ws, p:%ws, f:%ws",
pwszBuf, pwszTicket, pwszProfile, pwszF);
fParseSuccess = handleQueryStringData(bstrT, bstrP);
if (pwszF)
m_lNetworkError = _wtol(pwszF);
SysFreeString(bstrT);
SysFreeString(bstrP);
}
}
}
else
{
// not our header. BUGBUG could there be multiple headers ???
pBuffer = NULL;
}
}
if (!pBuffer)
{
// an old client, let's try the QS
if (QS)
{
// get ticket and profile ...
// BUGBUG This could be optimized to avoid wide/short conversions, but later...
GetQueryData(QS, &QSAuth, &QSProf, &QSErrflag);
fParseSuccess = handleQueryStringData(QSAuth,QSProf);
if(QSErrflag != NULL)
m_lNetworkError = _wtol(QSErrflag);
PPTracePrint(PPTRACE_RAW,
"QueryString <<< t:%ws, p:%ws, f:%ws",
QSAuth, QSProf, QSErrflag);
}
}
if (fParseSuccess)
{
//
// If we got secure ticket or profile, then
// we need to re-encrypt the insecure version
// before setting the cookie headers.
//
PPTracePrint(PPTRACE_RAW, "Authenticated");
// Set the cookies
LPSTR ticketDomain = m_pRegistryConfig->getTicketDomain();
LPSTR profileDomain = m_pRegistryConfig->getProfileDomain();
LPSTR secureDomain = m_pRegistryConfig->getSecureDomain();
LPSTR ticketPath = m_pRegistryConfig->getTicketPath();
LPSTR profilePath = m_pRegistryConfig->getProfilePath();
LPSTR securePath = m_pRegistryConfig->getSecurePath();
VARIANT_BOOL persist;
m_piTicket->get_HasSavedPassword(&persist);
// MSPConsent cookie
BOOL bSetConsent = (S_OK == IfConsentCookie(&bstrConsent));
// Build the cookie headers.
// the authentication cookies
BSTR auth, secAuth; // do not call SysFreeString on them, they are skin level copy
if (S_OK == IfAlterAuthCookie(&bstrNewAuth, &bstrNewSecAuth))
{
auth = bstrNewAuth;
secAuth = bstrNewSecAuth;
}
else
{
if (pwszTicket)
{
auth = pwszTicket;
}
else
{
auth = QSAuth;
}
secAuth = NULL;
}
// build cookies for output
BuildCookieHeaders(W2A(auth),
(pwszProfile ? W2A(pwszProfile) : (QSProf ? W2A(QSProf) : NULL)),
(bSetConsent ? W2A(bstrConsent) : NULL),
(secAuth ? W2A(secAuth) : NULL),
ticketDomain,
ticketPath,
profileDomain,
profilePath,
secureDomain,
securePath,
persist,
pCookieHeader,
bufSize,
!m_pRegistryConfig->getNotUseHTTPOnly());
PPTracePrint(PPTRACE_RAW,
"Cookie headers >>> %s",PPF_CHAR(pCookieHeader));
}
if (QSAuth) FREE_BSTR(QSAuth);
if (QSProf) FREE_BSTR(QSProf);
if (QSErrflag) FREE_BSTR(QSErrflag);
if (bstrNewAuth)
{
SysFreeString(bstrNewAuth);
}
if (bstrNewSecAuth)
{
SysFreeString(bstrNewSecAuth);
}
if (bstrConsent)
{
SysFreeString(bstrConsent);
}
// Now, check the cookies
if (!m_fromQueryString)
{
BSTR CookieAuth = NULL, CookieProf = NULL, CookieConsent = NULL, CookieSecure = NULL;
pBuffer = headerValues[header_Cookie];
if(pBuffer)
{
TempSubStr tss(pBuffer, headerSizes[header_Cookie]);
GetCookie(pBuffer, "MSPAuth", &CookieAuth); // GetCookie has URLDecode in it
GetCookie(pBuffer, "MSPProf", &CookieProf);
GetCookie(pBuffer, "MSPConsent", &CookieConsent);
GetCookie(pBuffer, "MSPSecAuth", &CookieSecure);
handleCookieData(CookieAuth,CookieProf,CookieConsent,CookieSecure);
PPTracePrint(PPTRACE_RAW,
"Cookies <<< t:%ws, p:%ws, c:%ws, s:%ws",
CookieAuth, CookieProf, CookieConsent, CookieSecure);
if (CookieAuth) FREE_BSTR(CookieAuth);
if (CookieProf) FREE_BSTR(CookieProf);
if (CookieConsent) FREE_BSTR(CookieConsent);
if (CookieSecure) FREE_BSTR(CookieSecure);
}
// we are not returning cookie info back
if (pCookieHeader)
*pCookieHeader = 0;
*bufSize = 0;
}
PassportLog("CManager::OnStartPageHTTPRawEx Exit:\r\n");
hr = S_OK;
Cleanup:
if (NULL != pwszBuf)
{
// free the memory since we no longer need it
LocalFree(pwszBuf);
}
return hr;
}
//===========================================================================
//
// ContinueStartPageBody
// -- when OnStartPageHTTPRaw returns PP_E_HTTP_BODY_REQUIRED, this func is expected to call
// not doing anything for 2.0 release
STDMETHODIMP CManager::ContinueStartPageHTTPRaw(
/* [in] */ DWORD bodyLen,
/* [size_is][in] */ byte *body,
/* [out][in] */ DWORD *pBufSize,
/* [size_is][out] */ LPSTR pRespHeaders,
/* [out][in] */ DWORD *pRespBodyLen,
/* [size_is][out] */ byte *pRespBody)
{
return E_NOTIMPL;
}
//===========================================================================
//
// OnStartPageFilter -- for ISAPI filters
//
STDMETHODIMP CManager::OnStartPageFilter(
LPBYTE pvPFC,
DWORD* bufSize,
LPSTR pCookieHeader
)
{
if (!pvPFC) return E_INVALIDARG;
PHTTP_FILTER_CONTEXT pfc = (PHTTP_FILTER_CONTEXT) pvPFC;
HRESULT hr = S_OK;
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"OnStartPageFilter",
" <<< %lx, %lx, %d, %lx", pvPFC, bufSize, *bufSize, pCookieHeader);
ATL::CAutoVectorPtr<CHAR> spheaders;
ATL::CAutoVectorPtr<CHAR> spHTTPS;
ATL::CAutoVectorPtr<CHAR> spQS;
spheaders.Attach(GetServerVariablePFC(pfc, "ALL_RAW"));
spHTTPS.Attach(GetServerVariablePFC(pfc, "HTTPS"));
spQS.Attach(GetServerVariablePFC(pfc, "QUERY_STRING"));
DWORD flags = 0;
if((CHAR*)spHTTPS && lstrcmpiA("on", (CHAR*)spHTTPS) == 0)
flags |= PASSPORT_HEADER_FLAGS_HTTPS;
hr = OnStartPageHTTPRawEx(NULL, NULL, (CHAR*)spQS, NULL, (CHAR*)spheaders, flags, bufSize, pCookieHeader);
m_pFC = pfc;
return hr;
}
//===========================================================================
//
// OnEndPage
//
STDMETHODIMP CManager::OnEndPage ()
{
PassportLog("CManager::OnEndPage Enter:\r\n");
if (m_bOnStartPageCalled)
{
m_bOnStartPageCalled = false;
// Release all interfaces
m_piRequest.Release();
m_piResponse.Release();
}
if (!m_piTicket || !m_piProfile)
{
return E_OUTOFMEMORY;
}
// Just in case...
m_piTicket->put_unencryptedTicket(NULL);
m_piProfile->put_unencryptedProfile(NULL);
m_profileValid = m_ticketValid = VARIANT_FALSE;
m_fromQueryString = false;
if(m_pRegistryConfig)
{
m_pRegistryConfig->Release();
m_pRegistryConfig = NULL;
}
PassportLog("CManager::OnEndPage Exit:\r\n");
return S_OK;
}
//===========================================================================
//
// AuthURL
//
//
// Old API. Auth URL is pointing to the login server
//
STDMETHODIMP
CManager::AuthURL(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BSTR *pAuthUrl)
{
CComVariant vEmpty(_T(""));
return CommonAuthURL(vRU, vTimeWindow, vForceLogin,
vCoBrand, vLCID, vNameSpace,
vKPP, vSecureLevel,
FALSE, vEmpty, pAuthUrl);
}
//===========================================================================
//
// AuthURL2
//
//
// new API. return URL is to the login server
//
STDMETHODIMP
CManager::AuthURL2(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BSTR *pAuthUrl)
{
CComVariant vEmpty(_T(""));
return CommonAuthURL(vRU, vTimeWindow, vForceLogin,
vCoBrand, vLCID, vNameSpace,
vKPP, vSecureLevel,
TRUE, vEmpty, pAuthUrl);
}
//===========================================================================
//
// CommonAuthURL
//
//
// AuthURL implementation
//
STDMETHODIMP
CManager::CommonAuthURL(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BOOL fRedirToSelf,
VARIANT vFunctionArea, // BSTR: e.g. Wireless
BSTR *pAuthUrl)
{
USES_CONVERSION;
time_t ct;
WCHAR url[MAX_URL_LENGTH] = L"";
VARIANT freeMe;
UINT TimeWindow;
int nKPP;
VARIANT_BOOL ForceLogin = VARIANT_FALSE;
ULONG ulSecureLevel = 0;
BSTR CBT = NULL, returnUrl = NULL, bstrNameSpace = NULL;
int hasCB, hasRU, hasLCID, hasTW, hasFL, hasNameSpace, hasKPP, hasUseSec;
USHORT Lang;
HRESULT hr = S_OK;
BSTR bstrFunctionArea = NULL;
int hasFunctionArea;
CNexusConfig* cnc = NULL;
PassportLog("CManager::CommonAuthURL Enter:\r\n");
if (!g_config) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!g_config->isValid() || !m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
// Make sure args are of the right type
if ((hasTW = GetIntArg(vTimeWindow, (int*) &TimeWindow)) == CV_BAD)
return E_INVALIDARG;
if ((hasFL = GetBoolArg(vForceLogin, &ForceLogin)) == CV_BAD)
return E_INVALIDARG;
if ((hasUseSec = GetIntArg(vSecureLevel, (int*)&ulSecureLevel)) == CV_BAD)
return E_INVALIDARG;
if ((hasLCID = GetShortArg(vLCID,&Lang)) == CV_BAD)
return E_INVALIDARG;
if ((hasKPP = GetIntArg(vKPP, &nKPP)) == CV_BAD)
return E_INVALIDARG;
hasCB = GetBstrArg(vCoBrand, &CBT);
if (hasCB == CV_BAD)
return E_INVALIDARG;
if (hasCB == CV_FREE)
{
TAKEOVER_BSTR(CBT);
}
hasRU = GetBstrArg(vRU, &returnUrl);
if (hasRU == CV_BAD)
{
if (hasCB == CV_FREE && CBT)
FREE_BSTR(CBT);
return E_INVALIDARG;
}
if (hasRU == CV_FREE)
{
TAKEOVER_BSTR(returnUrl);
}
hasNameSpace = GetBstrArg(vNameSpace, &bstrNameSpace);
if (hasNameSpace == CV_BAD)
{
if (hasCB == CV_FREE && CBT)
SysFreeString(CBT);
if (hasRU == CV_FREE && returnUrl)
SysFreeString(returnUrl);
return E_INVALIDARG;
}
if (hasNameSpace == CV_FREE)
{
TAKEOVER_BSTR(bstrNameSpace);
}
if (hasNameSpace == CV_DEFAULT)
{
bstrNameSpace = m_pRegistryConfig->getNameSpace();
}
// **************************************************
// Logging
if (NULL != returnUrl)
{
PassportLog(" RU = %ws\n", returnUrl);
}
PassportLog(" TW = %X, SL = %X, L = %d, KPP = %X\r\n", TimeWindow, ulSecureLevel, Lang, nKPP);
if (NULL != bstrNameSpace)
{
PassportLog(" NS = %ws\r\n", bstrNameSpace);
}
if (NULL != CBT)
{
PassportLog(" CBT = %ws\r\n", CBT);
}
// **************************************************
hasFunctionArea = GetBstrArg(vFunctionArea, &bstrFunctionArea);
if (hasFunctionArea == CV_FREE)
{
TAKEOVER_BSTR(bstrFunctionArea);
}
if(hasUseSec == CV_DEFAULT)
ulSecureLevel = m_pRegistryConfig->getSecureLevel();
WCHAR *szAUAttrName;
if (SECURELEVEL_USE_HTTPS(ulSecureLevel))
szAUAttrName = L"AuthSecure";
else
szAUAttrName = L"Auth";
BSTR szAttrName_FuncArea = NULL;
if (bstrFunctionArea != NULL)
{
szAttrName_FuncArea = SysAllocStringLen(NULL, wcslen(bstrFunctionArea) + wcslen(szAUAttrName));
if (NULL == szAttrName_FuncArea)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
wcscpy(szAttrName_FuncArea, bstrFunctionArea);
wcscat(szAttrName_FuncArea, szAUAttrName);
}
cnc = g_config->checkoutNexusConfig();
if (hasLCID == CV_DEFAULT)
Lang = m_pRegistryConfig->getDefaultLCID();
if (hasKPP == CV_DEFAULT)
nKPP = m_pRegistryConfig->getKPP();
VariantInit(&freeMe);
if (!m_pRegistryConfig->DisasterModeP())
{
// If I'm authenticated, get my domain specific url
if (m_ticketValid && m_profileValid)
{
HRESULT hr = m_piProfile->get_ByIndex(MEMBERNAME_INDEX, &freeMe);
if (hr != S_OK || freeMe.vt != VT_BSTR)
{
if (bstrFunctionArea)
{
cnc->getDomainAttribute(L"Default",
szAttrName_FuncArea,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
if (*url == 0) // nothing is in URL string
{
cnc->getDomainAttribute(L"Default",
szAUAttrName,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
}
else
{
LPCWSTR psz = wcsrchr(freeMe.bstrVal, L'@');
if (bstrFunctionArea)
{
cnc->getDomainAttribute(psz ? psz+1 : L"Default",
szAttrName_FuncArea,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
if (*url == 0) // nothing is in URL string
{
cnc->getDomainAttribute(psz ? psz+1 : L"Default",
szAUAttrName,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
}
}
else
{
if (bstrFunctionArea)
{
cnc->getDomainAttribute(L"Default",
szAttrName_FuncArea,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
}
if(*url == 0) // nothing in URL string
{
cnc->getDomainAttribute(L"Default",
szAUAttrName,
sizeof(url) / sizeof(WCHAR),
url,
Lang);
}
}
else
lstrcpynW(url, m_pRegistryConfig->getDisasterUrl(), sizeof(url) / sizeof(WCHAR));
time(&ct);
if (*url == L'\0')
{
hr = S_OK;
goto Cleanup;
}
if (hasTW == CV_DEFAULT)
TimeWindow = m_pRegistryConfig->getDefaultTicketAge();
if (hasFL == CV_DEFAULT)
ForceLogin = m_pRegistryConfig->forceLoginP() ? VARIANT_TRUE : VARIANT_FALSE;
if (hasCB == CV_DEFAULT)
CBT = m_pRegistryConfig->getDefaultCoBrand();
if (hasRU == CV_DEFAULT)
returnUrl = m_pRegistryConfig->getDefaultRU();
if (returnUrl == NULL)
returnUrl = L"";
if(ulSecureLevel == VARIANT_TRUE) // special case for backward compatible
ulSecureLevel = k_iSeclevelSecureChannel;
if ((TimeWindow != 0 && TimeWindow < PPM_TIMEWINDOW_MIN) || TimeWindow > PPM_TIMEWINDOW_MAX)
{
WCHAR buf[20];
_itow(TimeWindow,buf,10);
AtlReportError(CLSID_Manager, (LPCOLESTR) PP_E_INVALID_TIMEWINDOWSTR,
IID_IPassportManager, PP_E_INVALID_TIMEWINDOW);
hr = PP_E_INVALID_TIMEWINDOW;
goto Cleanup;
}
if (NULL == pAuthUrl)
{
hr = E_INVALIDARG;
goto Cleanup;
}
*pAuthUrl = FormatAuthURL(
url,
m_pRegistryConfig->getSiteId(),
returnUrl,
TimeWindow,
ForceLogin,
m_pRegistryConfig->getCurrentCryptVersion(),
ct,
CBT,
bstrNameSpace,
nKPP,
Lang,
ulSecureLevel,
m_pRegistryConfig,
fRedirToSelf,
IfCreateTPF()
);
if (NULL == *pAuthUrl)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = S_OK;
Cleanup:
if (szAttrName_FuncArea)
{
SysFreeString(szAttrName_FuncArea);
}
if (NULL != cnc)
{
cnc->Release();
}
if (hasFunctionArea== CV_FREE && bstrFunctionArea)
FREE_BSTR(bstrFunctionArea);
if (hasRU == CV_FREE && returnUrl)
FREE_BSTR(returnUrl);
if (hasCB == CV_FREE && CBT)
FREE_BSTR(CBT);
// !!! need to confirmation
if (hasNameSpace == CV_FREE && bstrNameSpace)
FREE_BSTR(bstrNameSpace);
VariantClear(&freeMe);
PassportLog("CManager::CommonAuthURL Exit: %X\r\n", hr);
return hr;
}
//===========================================================================
//
// GetLoginChallenge
// return AuthURL,
// output parameter: tweener authHeader
//
// get AuthURL and AuthHeaders
//
STDMETHODIMP CManager::GetLoginChallenge(VARIANT vReturnUrl,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrandTemplate,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
VARIANT vExtraParams,
BSTR* pAuthHeader
)
{
if (!pAuthHeader) return E_INVALIDARG;
VARIANT vHeader;
VariantInit(&vHeader);
HRESULT hr = GetLoginChallengeInternal(
vReturnUrl,
vTimeWindow,
vForceLogin,
vCoBrandTemplate,
vLCID,
vNameSpace,
vKPP,
vSecureLevel,
vExtraParams,
&vHeader,
NULL);
if(S_OK == hr && V_VT(&vHeader) == VT_BSTR && V_BSTR(&vHeader))
{
*pAuthHeader = V_BSTR(&vHeader);
VariantInit(&vHeader);
}
else
VariantClear(&vHeader);
return hr;
}
//===========================================================================
//
// GetLoginChallengeInternal
// return AuthURL,
// output parameter: tweener authHeader
//
// get AuthURL and AuthHeaders
//
STDMETHODIMP CManager::GetLoginChallengeInternal(VARIANT vReturnUrl,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrandTemplate,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
VARIANT vExtraParams,
VARIANT *pAuthHeader,
BSTR* pAuthVal
)
{
HRESULT hr = S_OK;
if (pAuthVal)
{
*pAuthVal = NULL;
}
if (pAuthHeader)
{
V_BSTR(pAuthHeader) = NULL;
}
_bstr_t strAuthHeader;
try
{
// format qs and WWW-Authenticate header ....
_bstr_t strUrl, strRetUrl, strCBT, strNameSpace;
UINT TimeWindow;
int nKPP;
time_t ct;
VARIANT_BOOL ForceLogin;
ULONG ulSecureLevel;
WCHAR rgLCID[10];
hr = GetLoginParams(vReturnUrl,
vTimeWindow,
vForceLogin,
vCoBrandTemplate,
vLCID,
vNameSpace,
vKPP,
vSecureLevel,
strUrl,
strRetUrl,
TimeWindow,
ForceLogin,
ct,
strCBT,
strNameSpace,
nKPP,
ulSecureLevel,
rgLCID);
if (S_OK == hr && strUrl.length() != 0)
{
WCHAR szBuf[MAX_QS_LENGTH] = L"";
// prepare redirect URL to the login server for
// downlevel clients
if (NULL == FormatAuthURLParameters(strUrl,
m_pRegistryConfig->getSiteId(),
strRetUrl,
TimeWindow,
ForceLogin,
m_pRegistryConfig->getCurrentCryptVersion(),
ct,
strCBT,
strNameSpace,
nKPP,
szBuf,
sizeof(szBuf)/sizeof(WCHAR),
0, // lang does not matter ....
ulSecureLevel,
m_pRegistryConfig,
FALSE,
IfCreateTPF()
)) // do not redirect to self!
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// insert the WWW-Authenticate header ...
hr = FormatAuthHeaderFromParams(strUrl,
strRetUrl,
TimeWindow,
ForceLogin,
ct,
strCBT,
strNameSpace,
nKPP,
rgLCID,
ulSecureLevel,
strAuthHeader);
if (S_OK != hr)
{
goto Cleanup;
}
// and add the extra ....
BSTR strExtra = NULL;
int res = GetBstrArg(vExtraParams, &strExtra);
if (res != CV_BAD)
{
if (res == CV_DEFAULT)
{
strExtra = m_pRegistryConfig->getExtraParams();
}
if (NULL != strExtra)
{
strAuthHeader += _bstr_t(L",") + strExtra;
}
}
if (res == CV_FREE)
::SysFreeString(strExtra);
// set return values
if (pAuthHeader && (WCHAR*)strAuthHeader != NULL)
{
V_VT(pAuthHeader) = VT_BSTR;
// TODO: should avoid this SysAllocString
V_BSTR(pAuthHeader) = ::SysAllocString((WCHAR*)strAuthHeader);
if (NULL == V_BSTR(pAuthHeader))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
if (pAuthVal)
{
*pAuthVal = ::SysAllocString(szBuf);
if (NULL == *pAuthVal)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
}
}
catch(...)
{
hr = E_OUTOFMEMORY;
}
Cleanup:
return hr;
}
//===========================================================================
//
// LoginUser
//
//
// client logon method
// vExtraParams: coBranding text is passed as cbtxt=cobrandingtext
// the content of the input parameter should be UTF8 encoded, and
// properly URL escapted before passing into this function
//
STDMETHODIMP CManager::LoginUser(VARIANT vReturnUrl,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrandTemplate,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
VARIANT vExtraParams)
{
// format qs and WWW-Authenticate header ....
BSTR authURL = NULL;
CComVariant authHeader;
PassportLog("CManager::LoginUser Enter:\r\n");
HRESULT hr = GetLoginChallengeInternal( vReturnUrl,
vTimeWindow,
vForceLogin,
vCoBrandTemplate,
vLCID,
vNameSpace,
vKPP,
vSecureLevel,
vExtraParams,
&authHeader,
&authURL);
if (S_OK == hr)
{
_ASSERT(V_VT(&authHeader) == VT_BSTR);
_ASSERT(authURL);
_ASSERT(V_BSTR(&authHeader));
// TODO: _bstr_t should be removed globaly in ppm
if (m_piResponse)
{
m_piResponse->AddHeader(L"WWW-Authenticate", V_BSTR(&authHeader));
_bstr_t authURL1 = authURL;
// and redirect!
if (!m_bIsTweenerCapable)
m_piResponse->Redirect(authURL1);
else
{
// send a 401
m_piResponse->put_Status(L"401 Unauthorized");
m_piResponse->End();
}
}
else if (m_pECB || m_pFC)
{
// use ECB of Filter interfaces
// 4k whould be enough ....
char buffer[4096],
status[25] = "302 Object moved",
*psz=buffer,
rgszTemplate[] = "Content-Type: text/html\r\nLocation: %ws\r\n"
"Content-Length: 0\r\n"
"WWW-Authenticate: %ws\r\n\r\n";
DWORD cbTotalLength = strlen(rgszTemplate);
//
// This is a hack fix, unfortunately we can succeed the call to GetChallengeInternal but
// have a NULL authHeader, it seemed a bit risky to try and fix GetLoginParams which
// seems to be the function which returns success when allocations are failing.
//
if ((NULL == V_BSTR(&authHeader)) || (NULL == (BSTR)authURL))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
cbTotalLength += wcslen(V_BSTR(&authHeader)) + wcslen(authURL);
if (m_bIsTweenerCapable)
strcpy(status, "401 Unauthorized");
if (cbTotalLength >= sizeof(buffer))
{
// if not ...
// need to alloc
psz = new CHAR[cbTotalLength];
_ASSERT(psz);
}
if (psz)
{
sprintf(psz,
rgszTemplate,
authURL,
V_BSTR(&authHeader));
if (m_pECB)
{
// extension
HSE_SEND_HEADER_EX_INFO Headers =
{
status,
psz,
strlen(status),
strlen(psz),
TRUE
};
if (!m_pECB->ServerSupportFunction(m_pECB->ConnID,
HSE_REQ_SEND_RESPONSE_HEADER_EX,
&Headers,
NULL,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
// filter
if (!m_pFC->ServerSupportFunction(m_pFC,
SF_REQ_SEND_RESPONSE_HEADER,
status,
(ULONG_PTR) psz,
NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (psz != buffer)
// if we had to allocate
delete[] psz;
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
Cleanup:
if (authURL)
{
SysFreeString(authURL);
}
PassportLog("CManager::LoginUser Exit: %X\r\n", hr);
return hr;
}
//===========================================================================
//
// IsAuthenticated -- determine if authenticated with specified SecureLevel
//
STDMETHODIMP CManager::IsAuthenticated(
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT SecureLevel,
VARIANT_BOOL *pVal)
{
HRESULT hr;
ULONG TimeWindow;
VARIANT_BOOL ForceLogin;
ATL::CComVariant vSecureLevel;
ULONG ulSecureLevel;
int hasTW, hasFL, hasSecureLevel;
PassportLog("CManager::IsAuthenticated Enter:\r\n");
PPTraceFunc<HRESULT> func(PPTRACE_FUNC, hr,
"IsAuthenticated", "<<< %lx, %lx, %1x, %1x",
V_I4(&vTimeWindow), V_I4(&vForceLogin), V_I4(&SecureLevel), pVal);
if (!m_piTicket || !m_piProfile)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
if (!g_config) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!g_config->isValid() || !m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
if ((hasTW = GetIntArg(vTimeWindow,(int*)&TimeWindow)) == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasTW == CV_DEFAULT)
TimeWindow = m_pRegistryConfig->getDefaultTicketAge();
if ((hasFL = GetBoolArg(vForceLogin, &ForceLogin)) == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasFL == CV_DEFAULT)
ForceLogin = m_pRegistryConfig->forceLoginP() ? VARIANT_TRUE : VARIANT_FALSE;
hasSecureLevel = GetIntArg(SecureLevel, (int*)&ulSecureLevel);
if(hasSecureLevel == CV_BAD) // try the legacy type VT_BOOL, map VARIANT_TRUE to SecureChannel
{
hr = E_INVALIDARG;
goto Cleanup;
}
else if (hasSecureLevel == CV_DEFAULT)
{
ulSecureLevel = m_pRegistryConfig->getSecureLevel();
}
if(ulSecureLevel == VARIANT_TRUE)// backward compatible with 1.3X
{
ulSecureLevel = k_iSeclevelSecureChannel;
}
vSecureLevel = ulSecureLevel;
// Logging
PassportLog(" TW = %X, SL = %X\r\n", TimeWindow, ulSecureLevel);
hr = m_piTicket->get_IsAuthenticated(TimeWindow, ForceLogin, vSecureLevel, pVal);
PPTracePrint(PPTRACE_RAW, "IsAuthenticated Params: %d, %d, %d, %lx", TimeWindow, ForceLogin, ulSecureLevel, *pVal);
Cleanup:
if(g_pPerf)
{
if (*pVal)
{
g_pPerf->incrementCounter(PM_AUTHSUCCESS_TOTAL);
g_pPerf->incrementCounter(PM_AUTHSUCCESS_SEC);
}
else
{
g_pPerf->incrementCounter(PM_AUTHFAILURE_TOTAL);
g_pPerf->incrementCounter(PM_AUTHFAILURE_SEC);
}
}
else
{
_ASSERT(g_pPerf);
}
PassportLog("CManager::IsAuthenticated Exit: %X\r\n", hr);
return hr;
}
//===========================================================================
//
// LogoTag
//
//
// old PM API. The URL is pointing to login server
//
STDMETHODIMP
CManager::LogoTag(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vSecure,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BSTR *pVal)
{
return CommonLogoTag(vRU, vTimeWindow, vForceLogin,
vCoBrand, vLCID, vSecure,
vNameSpace, vKPP, vSecureLevel,
FALSE, pVal);
}
//===========================================================================
//
// LogoTag2
//
//
// new PM API. The URL is pointing to the partner site
//
STDMETHODIMP
CManager::LogoTag2(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vSecure,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BSTR *pVal)
{
return CommonLogoTag(vRU, vTimeWindow, vForceLogin,
vCoBrand, vLCID, vSecure,
vNameSpace, vKPP, vSecureLevel,
TRUE, pVal);
}
//===========================================================================
//
// CommonLogoTag
//
STDMETHODIMP
CManager::CommonLogoTag(
VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vSecure,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
BOOL fRedirToSelf,
BSTR *pVal)
{
time_t ct;
ULONG TimeWindow;
int nKPP;
VARIANT_BOOL ForceLogin, bSecure = VARIANT_FALSE;
ULONG ulSecureLevel = 0;
BSTR CBT = NULL, returnUrl = NULL, NameSpace = NULL;
int hasCB = -1, hasRU = -1, hasLCID, hasTW, hasFL, hasSec, hasUseSec, hasNameSpace = -1, hasKPP;
USHORT Lang;
LPWSTR pszNewURL = NULL;
BSTR upd = NULL;
CNexusConfig* cnc = NULL;
HRESULT hr = S_OK;
USES_CONVERSION;
PassportLog("CManager::CommonLogoTag Enter:\r\n");
time(&ct);
if (NULL == pVal)
{
hr = E_INVALIDARG;
goto Cleanup;
}
*pVal = NULL;
if (!g_config) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!g_config->isValid() || !m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
//
// parameters parsing ...
// Make sure args are of the right type
if ( ((hasTW = GetIntArg(vTimeWindow, (int*) &TimeWindow)) == CV_BAD) ||
((hasFL = GetBoolArg(vForceLogin, &ForceLogin)) == CV_BAD) ||
((hasSec = GetBoolArg(vSecure,&bSecure)) == CV_BAD) ||
// FUTURE: should introduce a new func: GetLongArg ...
((hasUseSec = GetIntArg(vSecureLevel,(int*)&ulSecureLevel)) == CV_BAD) ||
((hasLCID = GetShortArg(vLCID,&Lang)) == CV_BAD) ||
((hasKPP = GetIntArg(vKPP, &nKPP)) == CV_BAD) )
{
hr = E_INVALIDARG;
goto Cleanup;
}
hasCB = GetBstrArg(vCoBrand, &CBT);
if (hasCB == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasCB == CV_FREE)
{
TAKEOVER_BSTR(CBT);
}
hasRU = GetBstrArg(vRU, &returnUrl);
if (hasRU == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasRU == CV_FREE)
{
TAKEOVER_BSTR(returnUrl);
}
hasNameSpace = GetBstrArg(vNameSpace, &NameSpace);
if (hasNameSpace == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasNameSpace == CV_FREE)
{
TAKEOVER_BSTR(NameSpace);
}
if (hasNameSpace == CV_DEFAULT)
{
NameSpace = m_pRegistryConfig->getNameSpace();
}
WCHAR *szSIAttrName, *szSOAttrName;
if (hasSec == CV_OK && bSecure == VARIANT_TRUE)
{
szSIAttrName = L"SecureSigninLogo";
szSOAttrName = L"SecureSignoutLogo";
}
else
{
szSIAttrName = L"SigninLogo";
szSOAttrName = L"SignoutLogo";
}
if(hasUseSec == CV_DEFAULT)
ulSecureLevel = m_pRegistryConfig->getSecureLevel();
if(ulSecureLevel == VARIANT_TRUE) // special case for backward compatible
ulSecureLevel = k_iSeclevelSecureChannel;
WCHAR *szAUAttrName;
if (SECURELEVEL_USE_HTTPS(ulSecureLevel))
szAUAttrName = L"AuthSecure";
else
szAUAttrName = L"Auth";
cnc = g_config->checkoutNexusConfig();
if (NULL == cnc)
{
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
if (hasLCID == CV_DEFAULT)
Lang = m_pRegistryConfig->getDefaultLCID();
if (hasTW == CV_DEFAULT)
TimeWindow = m_pRegistryConfig->getDefaultTicketAge();
if (hasFL == CV_DEFAULT)
ForceLogin = m_pRegistryConfig->forceLoginP() ? VARIANT_TRUE : VARIANT_FALSE;
if (hasCB == CV_DEFAULT)
CBT = m_pRegistryConfig->getDefaultCoBrand();
if (hasRU == CV_DEFAULT)
returnUrl = m_pRegistryConfig->getDefaultRU();
if (hasKPP == CV_DEFAULT)
nKPP = m_pRegistryConfig->getKPP();
if (returnUrl == NULL)
returnUrl = L"";
// **************************************************
// Logging
PassportLog(" RU = %ws\r\n", returnUrl);
PassportLog(" TW = %X, SL = %X, L = %d, KPP = %X\r\n", TimeWindow, ulSecureLevel, Lang, nKPP);
if (NULL != NameSpace)
{
PassportLog(" NS = %ws\r\n", NameSpace);
}
if (NULL != CBT)
{
PassportLog(" CBT = %ws\r\n", CBT);
}
// **************************************************
if ((TimeWindow != 0 && TimeWindow < PPM_TIMEWINDOW_MIN) || TimeWindow > PPM_TIMEWINDOW_MAX)
{
WCHAR buf[20];
_itow(TimeWindow,buf,10);
AtlReportError(CLSID_Manager, (LPCOLESTR) PP_E_INVALID_TIMEWINDOWSTR,
IID_IPassportManager, PP_E_INVALID_TIMEWINDOW);
hr = PP_E_INVALID_TIMEWINDOW;
goto Cleanup;
}
if (m_ticketValid)
{
LPCWSTR domain = NULL;
WCHAR url[MAX_URL_LENGTH];
VARIANT freeMe;
VariantInit(&freeMe);
if (m_pRegistryConfig->DisasterModeP())
lstrcpynW(url, m_pRegistryConfig->getDisasterUrl(), sizeof(url)/sizeof(WCHAR));
else
{
if (m_profileValid &&
m_piProfile->get_ByIndex(MEMBERNAME_INDEX, &freeMe) == S_OK &&
freeMe.vt == VT_BSTR)
{
domain = wcsrchr(freeMe.bstrVal, L'@');
}
cnc->getDomainAttribute(L"Default",
L"Logout",
sizeof(url)/sizeof(WCHAR),
url,
Lang);
}
// find out if there are any updates
m_piProfile->get_updateString(&upd);
if (upd)
{
TAKEOVER_BSTR(upd);
// form the appropriate URL
CCoCrypt* crypt = NULL;
BSTR newCH = NULL;
crypt = m_pRegistryConfig->getCurrentCrypt(); // IsValid ensures this is non-null
if (!crypt->Encrypt(m_pRegistryConfig->getCurrentCryptVersion(),
(LPSTR)upd,
SysStringByteLen(upd),
&newCH))
{
AtlReportError(CLSID_Manager, (LPCOLESTR) PP_E_UNABLE_TO_ENCRYPTSTR,
IID_IPassportManager, PP_E_UNABLE_TO_ENCRYPT);
hr = PP_E_UNABLE_TO_ENCRYPT;
goto Cleanup;
}
TAKEOVER_BSTR(newCH);
WCHAR iurlbuf[1024] = L"";
LPCWSTR iurl;
cnc->getDomainAttribute(domain ? domain+1 : L"Default",
L"Update",
sizeof(iurlbuf) >> 1,
iurlbuf,
Lang);
if(*iurlbuf == 0)
{
cnc->getDomainAttribute(L"Default",
L"Update",
sizeof(iurlbuf) >> 1,
iurlbuf,
Lang);
}
// convert this url to https as appropriate
if(!bSecure)
iurl = iurlbuf;
else
{
LPWSTR psz;
pszNewURL = SysAllocStringByteLen(NULL, (lstrlenW(iurlbuf) + 2) * sizeof(WCHAR));
if(pszNewURL)
{
psz = wcsstr(iurlbuf, L"http:");
if(psz != NULL)
{
psz += 4;
lstrcpynW(pszNewURL, iurlbuf, (psz - iurlbuf + 1));
lstrcatW(pszNewURL, L"s");
lstrcatW(pszNewURL, psz);
iurl = pszNewURL;
}
}
}
// This is a bit gross... we need to find the $1 in the update url...
LPCWSTR ins = iurl ? (wcsstr(iurl, L"$1")) : NULL;
// We'll break if null, but won't crash...
if (ins && *url != L'\0')
{
*pVal = FormatUpdateLogoTag(
url,
m_pRegistryConfig->getSiteId(),
returnUrl,
TimeWindow,
ForceLogin,
m_pRegistryConfig->getCurrentCryptVersion(),
ct,
CBT,
nKPP,
iurl,
bSecure,
newCH,
PM_LOGOTYPE_SIGNOUT,
ulSecureLevel,
m_pRegistryConfig,
IfCreateTPF()
);
}
FREE_BSTR(newCH);
}
else
{
WCHAR iurl[MAX_URL_LENGTH] = L"";
cnc->getDomainAttribute(L"Default",
szSOAttrName,
sizeof(iurl)/sizeof(WCHAR),
iurl,
Lang);
if (*iurl != L'\0')
{
*pVal = FormatNormalLogoTag(
url,
m_pRegistryConfig->getSiteId(),
returnUrl,
TimeWindow,
ForceLogin,
m_pRegistryConfig->getCurrentCryptVersion(),
ct,
CBT,
iurl,
NULL,
nKPP,
PM_LOGOTYPE_SIGNOUT,
Lang,
ulSecureLevel,
m_pRegistryConfig,
fRedirToSelf,
IfCreateTPF()
);
}
}
VariantClear(&freeMe);
if (NULL == *pVal)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
else
{
WCHAR url[MAX_URL_LENGTH];
if (!(m_pRegistryConfig->DisasterModeP()))
cnc->getDomainAttribute(L"Default",
szAUAttrName,
sizeof(url)/sizeof(WCHAR),
url,
Lang);
else
lstrcpynW(url, m_pRegistryConfig->getDisasterUrl(), sizeof(url)/sizeof(WCHAR));
WCHAR iurl[MAX_URL_LENGTH];
cnc->getDomainAttribute(L"Default",
szSIAttrName,
sizeof(iurl)/sizeof(WCHAR),
iurl,
Lang);
if (*iurl != L'\0')
{
*pVal = FormatNormalLogoTag(
url,
m_pRegistryConfig->getSiteId(),
returnUrl,
TimeWindow,
ForceLogin,
m_pRegistryConfig->getCurrentCryptVersion(),
ct,
CBT,
iurl,
NameSpace,
nKPP,
PM_LOGOTYPE_SIGNIN,
Lang,
ulSecureLevel,
m_pRegistryConfig,
fRedirToSelf,
IfCreateTPF()
);
if (NULL == *pVal)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
}
Cleanup:
if (NULL != cnc)
{
cnc->Release();
}
if (NULL != upd)
FREE_BSTR(upd);
if (pszNewURL)
SysFreeString(pszNewURL);
if (hasRU == CV_FREE && returnUrl)
FREE_BSTR(returnUrl);
if (hasCB == CV_FREE && CBT)
FREE_BSTR(CBT);
if (hasNameSpace == CV_FREE && NameSpace)
FREE_BSTR(NameSpace);
PassportLog("CManager::CommonLogoTag Exit: %X\r\n", hr);
return hr;
}
//===========================================================================
//
// HasProfile -- if valid profile is present
//
STDMETHODIMP CManager::HasProfile(VARIANT var, VARIANT_BOOL *pVal)
{
LPWSTR profileName;
PassportLog("CManager::HasProfile Enter:\r\n");
if (var.vt == (VT_BSTR | VT_BYREF))
profileName = *var.pbstrVal;
else if (var.vt == VT_BSTR)
profileName = var.bstrVal;
else if (var.vt == (VT_VARIANT | VT_BYREF))
{
return HasProfile(*(var.pvarVal), pVal);
}
else
profileName = NULL;
if ((!profileName) || (!_wcsicmp(profileName, L"core")))
{
HRESULT ok = m_piProfile->get_IsValid(pVal);
if (ok != S_OK)
*pVal = VARIANT_FALSE;
}
else
{
VARIANT vAtt;
VariantInit(&vAtt);
PassportLog(" %ws\r\n", profileName);
HRESULT ok = m_piProfile->get_Attribute(profileName, &vAtt);
if (ok != S_OK)
{
if (g_pAlert)
g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_PROFILETYPE);
*pVal = VARIANT_FALSE;
}
else
{
if (vAtt.vt == VT_I4)
*pVal = vAtt.lVal > 0 ? VARIANT_TRUE : VARIANT_FALSE;
else if (vAtt.vt == VT_I2)
*pVal = vAtt.iVal > 0 ? VARIANT_TRUE : VARIANT_FALSE;
else
{
if (g_pAlert)
g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_INVALID_PROFILETYPE);
}
VariantClear(&vAtt);
}
}
PassportLog("CManager::HasProfile Exit: %X\r\n", *pVal);
return(S_OK);
}
//===========================================================================
//
// get_HasTicket
//
STDMETHODIMP CManager::get_HasTicket(VARIANT_BOOL *pVal)
{
PassportLog("CManager::get_HasTicket:\r\n");
if(!pVal) return E_POINTER;
*pVal = m_ticketValid ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
//===========================================================================
//
// get_FromNetworkServer -- if it's authenticated by QueryString
//
STDMETHODIMP CManager::get_FromNetworkServer(VARIANT_BOOL *pVal)
{
PassportLog("CManager::get_FromNetworkServer:\r\n");
*pVal = (m_fromQueryString &&
m_ticketValid) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
//===========================================================================
//
// HasFlag -- obsolete function
//
STDMETHODIMP CManager::HasFlag(VARIANT var, VARIANT_BOOL *pVal)
{
PassportLog("CManager::HasFlag:\r\n");
AtlReportError(CLSID_Manager, PP_E_GETFLAGS_OBSOLETESTR,
IID_IPassportManager, E_NOTIMPL);
return E_NOTIMPL;
}
//===========================================================================
//
// get_TicketAge -- get how long has passed since ticket was created
//
STDMETHODIMP CManager::get_TicketAge(int *pVal)
{
PassportLog("CManager::get_TicketAge:\r\n");
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->get_TicketAge(pVal);
}
//===========================================================================
//
// get_TicketTime -- get when the ticket was created
//
STDMETHODIMP CManager::get_TicketTime(long *pVal)
{
PassportLog("CManager::get_TicketTime:\r\n");
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->get_TicketTime(pVal);
}
//===========================================================================
//
// get_SignInTime -- get last signin time
//
STDMETHODIMP CManager::get_SignInTime(long *pVal)
{
PassportLog("CManager::get_SignInTime:\r\n");
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->get_SignInTime(pVal);
}
//===========================================================================
//
// get_TimeSinceSignIn -- time passed since last signin
//
STDMETHODIMP CManager::get_TimeSinceSignIn(int *pVal)
{
PassportLog("CManager::get_TimeSinceSignIn:\r\n");
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->get_TimeSinceSignIn(pVal);
}
//===========================================================================
//
// GetDomainAttribute -- return information defined in partner.xml file
//
STDMETHODIMP CManager::GetDomainAttribute(BSTR attributeName, VARIANT lcid, VARIANT domain, BSTR *pAttrVal)
{
HRESULT hr = S_OK;
PassportLog("CManager::GetDomainAttribute Enter:\r\n");
if(attributeName == NULL || *attributeName == 0)
return E_INVALIDARG;
PassportLog(" %ws\r\n", attributeName);
if (!g_config || !g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
LPWSTR d;
BSTR dn = NULL;
if (domain.vt == (VT_BSTR | VT_BYREF))
d = *domain.pbstrVal;
else if (domain.vt == VT_BSTR)
d = domain.bstrVal;
else if (domain.vt == (VT_VARIANT | VT_BYREF))
{
return GetDomainAttribute(attributeName, lcid, *(domain.pvarVal), pAttrVal);
}
else
{
// domain best be not filled in this case, that's why we reuse it here
// if not, let dfmn generate the error
HRESULT hr = DomainFromMemberName(domain, &dn);
if (hr != S_OK)
return hr;
TAKEOVER_BSTR(dn);
d = dn;
}
if (NULL != d)
{
PassportLog(" %ws\r\n", d);
}
CNexusConfig* cnc = g_config->checkoutNexusConfig();
USHORT sLcid = 0;
VARIANT innerLC;
VariantInit(&innerLC);
if (lcid.vt != VT_ERROR && VariantChangeType(&innerLC, &lcid, 0, VT_UI2) == S_OK)
sLcid = innerLC.iVal;
else
{
sLcid = m_pRegistryConfig->getDefaultLCID();
// Check user profile
if (!sLcid && m_profileValid)
{
m_piProfile->get_ByIndex(LANGPREF_INDEX, &innerLC);
if (innerLC.vt == VT_I2 || innerLC.vt == VT_UI2)
sLcid = innerLC.iVal;
VariantClear(&innerLC);
}
}
WCHAR data[PP_MAX_ATTRIBUTE_LENGTH] = L"";
cnc->getDomainAttribute(d,
attributeName,
sizeof(data)/sizeof(WCHAR),
data,
sLcid);
// try default domain
if (!(*data) && (!d || !(*d) || lstrcmpiW(d, L"Default")))
{
cnc->getDomainAttribute(L"Default",
attributeName,
sizeof(data)/sizeof(WCHAR),
data,
sLcid);
}
if (*data)
{
*pAttrVal = ALLOC_AND_GIVEAWAY_BSTR(data);
}
else
{
/* fix bug: 12102 -- for backward compitible, not to return error
hr = E_INVALIDARG;
*/
*pAttrVal = NULL;
}
cnc->Release();
if (dn) FREE_BSTR(dn);
PassportLog("CManager::GetDomainAttribute Exit: %X, %ws\r\n", hr, pAttrVal);
return hr;
}
//===========================================================================
//
// DomainFromMemberName -- returns domain name with given user id
//
STDMETHODIMP CManager::DomainFromMemberName(VARIANT var, BSTR *pDomainName)
{
HRESULT hr;
LPWSTR psz, memberName;
VARIANT intoVar;
PassportLog("CManager::DomainFromMemberName Enter:\r\n");
VariantInit(&intoVar);
if (var.vt == (VT_BSTR | VT_BYREF))
memberName = *var.pbstrVal;
else if (var.vt == VT_BSTR)
memberName = var.bstrVal;
else if (var.vt == (VT_VARIANT | VT_BYREF))
{
return DomainFromMemberName(*(var.pvarVal), pDomainName);
}
else
{
// Try to get it from the profile
if (!m_profileValid)
{
*pDomainName = ALLOC_AND_GIVEAWAY_BSTR(L"Default");
return S_OK;
}
HRESULT hr = m_piProfile->get_Attribute(L"internalmembername", &intoVar);
if (hr != S_OK)
{
*pDomainName = NULL;
return hr;
}
if (VariantChangeType(&intoVar,&intoVar, 0, VT_BSTR) != S_OK)
{
AtlReportError(CLSID_Manager, L"PassportManager: Couldn't convert memberName to string. Call partner support.",
IID_IPassportManager, E_FAIL);
return E_FAIL;
}
memberName = intoVar.bstrVal;
}
if(memberName == NULL)
{
hr = E_POINTER;
goto Cleanup;
}
PassportLog(" %ws\r\n", memberName);
psz = wcsrchr(memberName, L'@');
if(psz == NULL)
{
// fix bug: 13380
// hr = E_INVALIDARG;
// goto Cleanup;
psz = L"@Default";
}
psz++;
*pDomainName = ALLOC_AND_GIVEAWAY_BSTR(psz);
hr = S_OK;
Cleanup:
VariantClear(&intoVar);
PassportLog("CManager::DomainFromMemberName Exit: %X\r\n", hr);
if (S_OK == hr)
{
PassportLog(" %ws\r\n", *pDomainName);
}
return hr;
}
//===========================================================================
//
// get_Profile -- get property from profile property bag
//
STDMETHODIMP CManager::get_Profile(BSTR attributeName, VARIANT *pVal)
{
HRESULT hr = m_piProfile->get_Attribute(attributeName,pVal);
PassportLog("CManager::get_Profile: %ws\r\n", attributeName);
if(hr == S_OK && pVal->vt != VT_EMPTY)
{
if(g_pPerf)
{
g_pPerf->incrementCounter(PM_VALIDPROFILEREQ_SEC);
g_pPerf->incrementCounter(PM_VALIDPROFILEREQ_TOTAL);
}
else
{
_ASSERT(g_pPerf);
}
}
return hr;
}
//===========================================================================
//
// put_Profile -- put property in profile property bag -- obselete
//
STDMETHODIMP CManager::put_Profile(BSTR attributeName, VARIANT newVal)
{
if (!m_piProfile)
{
return E_OUTOFMEMORY;
}
PassportLog("CManager::put_Profile: %ws\r\n", attributeName);
return m_piProfile->put_Attribute(attributeName,newVal);
}
//===========================================================================
//
// get_HexPUID
//
STDMETHODIMP CManager::get_HexPUID(BSTR *pVal)
{
PassportLog("CManager::get_HexPUID:\r\n");
if(!pVal) return E_INVALIDARG;
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
if(m_piTicket)
return m_piTicket->get_MemberId(pVal);
else
{
AtlReportError(CLSID_Manager, PP_E_INVALID_TICKETSTR,
IID_IPassportManager, PP_E_INVALID_TICKET);
return PP_E_INVALID_TICKET;
}
}
//===========================================================================
//
// get_PUID
//
STDMETHODIMP CManager::get_PUID(BSTR *pVal)
{
PassportLog("CManager::get_HexPUID:\r\n");
if(!pVal) return E_INVALIDARG;
if(m_piTicket)
{
HRESULT hr = S_OK;
WCHAR id[64] = L"0";
int l = 0;
int h = 0;
LARGE_INTEGER ui64;
hr = m_piTicket->get_MemberIdLow(&l);
if (S_OK != hr) return hr;
hr = m_piTicket->get_MemberIdHigh(&h);
if (S_OK != hr) return hr;
ui64.HighPart = h;
ui64.LowPart = l;
_ui64tow(ui64.QuadPart, id, 10);
*pVal = SysAllocString(id);
if(*pVal == NULL)
{
hr = E_OUTOFMEMORY;
}
return hr;
}
else
{
AtlReportError(CLSID_Manager, PP_E_INVALID_TICKETSTR,
IID_IPassportManager, PP_E_INVALID_TICKET);
return PP_E_INVALID_TICKET;
}
}
STDMETHODIMP CManager::get_Option(
/* [in] */ BSTR name,
/* [retval][out] */ VARIANT *pVal)
{
if (!name || _wcsicmp(name, L"iMode") != 0 || !pVal)
return E_INVALIDARG;
VariantCopy(pVal, (VARIANT*)&m_iModeOption);
return S_OK;
}
STDMETHODIMP CManager::put_Option(
/* [in] */ BSTR name,
/* [in] */ VARIANT newVal)
{
// support only this option for now.
if (!name || _wcsicmp(name, L"iMode") != 0)
return E_INVALIDARG;
m_iModeOption = newVal;
return S_OK;
}
//===========================================================================
//
// get_Ticket -- get new introduced ticket property from the bag.
//
STDMETHODIMP CManager::get_Ticket(BSTR attributeName, VARIANT *pVal)
{
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->GetProperty(attributeName,pVal);
}
//===========================================================================
//
// LogoutURL -- returns LogoutURL with given parameters
//
STDMETHODIMP CManager::LogoutURL(
/* [optional][in] */ VARIANT vRU,
/* [optional][in] */ VARIANT vCoBrand,
/* [optional][in] */ VARIANT lang_id,
/* [optional][in] */ VARIANT Namespace,
/* [optional][in] */ VARIANT bSecure,
/* [retval][out] */ BSTR __RPC_FAR *pVal)
{
HRESULT hr = S_OK;
VARIANT_BOOL bUseSecure = VARIANT_FALSE;
BSTR CBT = NULL, returnUrl = NULL, bstrNameSpace = NULL;
int hasCB, hasRU, hasLCID, hasNameSpace, hasUseSec;
USHORT Lang;
WCHAR nameSpace[MAX_PATH] = L"";
bool bUrlFromSecureKey = false;
WCHAR UrlBuf[MAX_URL_LENGTH] = L"";
WCHAR retUrlBuf[MAX_URL_LENGTH] = L"";
DWORD bufLen = MAX_URL_LENGTH;
WCHAR qsLeadCh = L'?';
CNexusConfig* cnc = NULL;
int iRet = 0;
if (!pVal) return E_INVALIDARG;
if (!g_config)
{
return PP_E_NOT_CONFIGURED;
}
cnc = g_config->checkoutNexusConfig();
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if ((hasUseSec = GetBoolArg(bSecure, &bUseSecure)) == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if ((hasLCID = GetShortArg(lang_id,&Lang)) == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (hasLCID == CV_DEFAULT)
Lang = m_pRegistryConfig->getDefaultLCID();
hasCB = GetBstrArg(vCoBrand, &CBT);
if (hasCB == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hasRU = GetBstrArg(vRU, &returnUrl);
if (hasRU == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hasNameSpace = GetBstrArg(Namespace, &bstrNameSpace);
if (hasNameSpace == CV_BAD)
{
hr = E_INVALIDARG;
goto Cleanup;
}
// get the right URL -- namespace, secure
// namespace
if (!IsEmptyString(bstrNameSpace))
{
if(0 == _snwprintf(nameSpace, sizeof(nameSpace) / sizeof(WCHAR), L"%s", bstrNameSpace))
{
hr = HRESULT_FROM_WIN32(GetLastError());
if FAILED(hr)
goto Cleanup;
}
}
if (hasCB == CV_DEFAULT)
CBT = m_pRegistryConfig->getDefaultCoBrand();
if (hasRU == CV_DEFAULT)
returnUrl = m_pRegistryConfig->getDefaultRU();
if (returnUrl == NULL)
returnUrl = L"";
if (*nameSpace == 0) // 0 length string
wcscpy(nameSpace, L"Default");
if(hasUseSec == CV_DEFAULT)
{
ULONG ulSecureLevel = m_pRegistryConfig->getSecureLevel();
bUseSecure = (SECURELEVEL_USE_HTTPS(ulSecureLevel)) ? VARIANT_TRUE : VARIANT_FALSE;
}
// secure
if(bUseSecure == VARIANT_TRUE)
{
cnc->getDomainAttribute(nameSpace,
L"LogoutSecure",
sizeof(UrlBuf)/sizeof(WCHAR),
UrlBuf,
Lang);
if (*UrlBuf != 0)
{
bUrlFromSecureKey = true;
}
}
// insecure
if (*UrlBuf == 0)
{
cnc->getDomainAttribute(nameSpace,
L"Logout",
sizeof(UrlBuf)/sizeof(WCHAR),
UrlBuf,
Lang);
}
// error case
if(*UrlBuf == 0)
{
AtlReportError(CLSID_Profile, PP_E_LOGOUTURL_NOTDEFINEDSTR,
IID_IPassportProfile, PP_E_LOGOUTURL_NOTDEFINED);
hr = PP_E_LOGOUTURL_NOTDEFINED;
goto Cleanup;
}
if(bUseSecure == VARIANT_TRUE && !bUrlFromSecureKey) // translate from http to https
{
if (_wcsnicmp(UrlBuf, L"http:", 5) == 0) // replace with HTTPS
{
memmove(UrlBuf + 5, UrlBuf + 4, sizeof(UrlBuf) - 5 * sizeof(WCHAR));
memcpy(UrlBuf, L"https", 5 * sizeof(WCHAR));
}
}
// us common function to append the thing one by one ...
if (wcsstr(UrlBuf, L"?")) // ? already exists in the URL, use & to start
qsLeadCh = L'&';
if (CBT)
_snwprintf(retUrlBuf, sizeof(retUrlBuf) / sizeof(WCHAR), L"%s%cid=%-d&ru=%s&lcid=%-d&cb=%s",
UrlBuf, qsLeadCh, m_pRegistryConfig->getSiteId(), returnUrl, Lang, CBT);
else
_snwprintf(retUrlBuf, sizeof(retUrlBuf) / sizeof(WCHAR), L"%s%cid=%-d&ru=%s&lcid=%-d",
UrlBuf, qsLeadCh, m_pRegistryConfig->getSiteId(), returnUrl, Lang);
*pVal = ALLOC_AND_GIVEAWAY_BSTR(retUrlBuf);
Cleanup:
if (NULL != cnc)
{
cnc->Release();
}
return hr;
}
//===========================================================================
//
// get_ProfileByIndex -- get property value by index of the property
//
STDMETHODIMP CManager::get_ProfileByIndex(int index, VARIANT *pVal)
{
HRESULT hr = m_piProfile->get_ByIndex(index,pVal);
if(hr == S_OK && pVal->vt != VT_EMPTY)
{
if(g_pPerf)
{
g_pPerf->incrementCounter(PM_VALIDPROFILEREQ_SEC);
g_pPerf->incrementCounter(PM_VALIDPROFILEREQ_TOTAL);
}
else
{
_ASSERT(g_pPerf);
}
}
return hr;
}
//===========================================================================
//
// put_ProfileByIndex -- put property value by index
//
STDMETHODIMP CManager::put_ProfileByIndex(int index, VARIANT newVal)
{
return m_piProfile->put_ByIndex(index,newVal);
}
//===========================================================================
//
// handleQueryStringData -- authenticate with T & P from Query String
//
BOOL CManager::handleQueryStringData(BSTR a, BSTR p)
{
BOOL retVal; //whither to set cookies
HRESULT hr;
VARIANT vFalse;
_variant_t vFlags;
//
// check for empty ticket
//
if (!a || !*a)
return FALSE;
if (!m_piTicket || !m_piProfile)
{
return FALSE;
}
hr = DecryptTicketAndProfile(a, p, FALSE, NULL, m_pRegistryConfig, m_piTicket, m_piProfile);
if(hr != S_OK)
{
m_ticketValid = VARIANT_FALSE;
m_profileValid = VARIANT_FALSE;
retVal = FALSE;
goto Cleanup;
}
VariantInit(&vFalse);
vFalse.vt = VT_BOOL;
vFalse.boolVal = VARIANT_FALSE;
m_piTicket->get_IsAuthenticated(0,
VARIANT_FALSE,
vFalse,
&m_ticketValid);
if(!m_bSecureTransported) // secure bit should NOI set
{
if (S_OK == m_piTicket->GetProperty(ATTR_PASSPORTFLAGS, &vFlags))
{ // the bit should NOT set
if ( vFlags.vt == VT_I4 && (vFlags.lVal & k_ulFlagsSecuredTransportedTicket) != 0)
m_ticketValid = VARIANT_FALSE;
}
}
// let the ticket to valid if secure signin
if(m_ticketValid)
m_piTicket->DoSecureCheckInTicket(m_bSecureTransported);
// profile stuff
m_piProfile->get_IsValid(&m_profileValid);
if (m_ticketValid)
{
m_fromQueryString = true;
// Set the cookies
if (!m_pRegistryConfig->setCookiesP())
{
retVal = FALSE;
goto Cleanup;
}
}
else
{
retVal = FALSE;
goto Cleanup;
}
retVal = TRUE;
Cleanup:
return retVal;
}
//===========================================================================
//
// handleCookieData -- authenticate with cookies
//
BOOL CManager::handleCookieData(
BSTR auth,
BSTR prof,
BSTR consent,
BSTR secAuth
)
{
BOOL retVal;
HRESULT hr;
VARIANT vDoSecureCheck;
VARIANT_BOOL bValid;
_variant_t vFlags;
// bail out on empty cookie
if (!auth || !*auth)
return FALSE;
if (!m_piTicket || !m_piProfile)
{
return FALSE;
}
// the consent cookie
if(consent != NULL && SysStringLen(consent) != 0)
{
hr = DecryptTicketAndProfile( auth,
prof,
!(m_pRegistryConfig->bInDA()),
consent,
m_pRegistryConfig,
m_piTicket,
m_piProfile);
}
else
{
//
// If regular cookie domain/path is identical to consent cookie domain/path, then
// MSPProf cookie is equivalent to consent cookie, and we should set m_bUsingConsentCookie
// to true
//
BOOL bCheckConsentCookie = (
lstrcmpA(m_pRegistryConfig->getTicketDomain(), m_pRegistryConfig->getProfileDomain())
|| lstrcmpA(m_pRegistryConfig->getTicketPath(), m_pRegistryConfig->getProfilePath())
);
hr = DecryptTicketAndProfile( auth,
prof,
!(m_pRegistryConfig->bInDA()) && bCheckConsentCookie,
NULL,
m_pRegistryConfig,
m_piTicket,
m_piProfile);
}
if(hr != S_OK)
{
m_ticketValid = VARIANT_FALSE;
m_profileValid = VARIANT_FALSE;
retVal = FALSE;
goto Cleanup;
}
VariantInit(&vDoSecureCheck);
vDoSecureCheck.vt = VT_BOOL;
if(secAuth && secAuth[0] && m_bSecureTransported)
{
if(DoSecureCheck(secAuth, m_pRegistryConfig, m_piTicket) == S_OK)
vDoSecureCheck.boolVal = VARIANT_TRUE;
else
vDoSecureCheck.boolVal = VARIANT_FALSE;
}
else
vDoSecureCheck.boolVal = VARIANT_FALSE;
m_piTicket->get_IsAuthenticated(0,
VARIANT_FALSE,
vDoSecureCheck,
&m_ticketValid);
// a partner cookie should not include the secure bit
if (!m_pRegistryConfig->bInDA() && S_OK == m_piTicket->GetProperty(ATTR_PASSPORTFLAGS, &vFlags))
{ // the bit should NOT set
if ( vFlags.vt == VT_I4 && (vFlags.lVal & k_ulFlagsSecuredTransportedTicket) != 0)
m_ticketValid = VARIANT_FALSE;
}
// for insecure case, the secure cookie should not come
if(!m_bSecureTransported && (secAuth && secAuth[0])) // this should not come
{
m_ticketValid = VARIANT_FALSE;
}
// profile stuff
m_piProfile->get_IsValid(&m_profileValid);
if(!m_ticketValid)
{
retVal = FALSE;
goto Cleanup;
}
retVal = TRUE;
Cleanup:
return retVal;
}
//===========================================================================
//
// get_HasSavedPassword -- if users chooses to persiste cookies
//
STDMETHODIMP CManager::get_HasSavedPassword(VARIANT_BOOL *pVal)
{
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
PassportLog("CManager::get_HasSavedPassword:\r\n");
// TODO: using flags for this
return m_piTicket->get_HasSavedPassword(pVal);
}
//===========================================================================
//
// Commit -- post changes of profile back to the cookie
//
STDMETHODIMP CManager::Commit(BSTR *pNewProfileCookie)
{
PassportLog("CManager::Commit:\r\n");
if (!g_config) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!g_config->isValid() || !m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_piTicket || !m_piProfile)
{
return E_OUTOFMEMORY;
}
if (!m_ticketValid || !m_profileValid)
{
AtlReportError(CLSID_Manager, PP_E_IT_FOR_COMMITSTR,
IID_IPassportManager, PP_E_INVALID_TICKET);
return PP_E_INVALID_TICKET;
}
// Write new passport profile cookie...
// return a safearray if we aren't used from ASP
BSTR newP = NULL;
HRESULT hr = m_piProfile->incrementVersion();
hr = m_piProfile->get_unencryptedProfile(&newP);
TAKEOVER_BSTR(newP);
if (hr != S_OK || newP == NULL)
{
AtlReportError(CLSID_Manager,
L"PassportManager.Commit: unknown failure.",
IID_IPassportManager, E_FAIL);
return E_FAIL;
}
CCoCrypt* crypt = NULL;
BSTR newCH = NULL;
crypt = m_pRegistryConfig->getCurrentCrypt(); // IsValid ensures this is non-null
if ((!crypt->Encrypt(m_pRegistryConfig->getCurrentCryptVersion(),
(LPSTR)newP,
SysStringByteLen(newP),
&newCH)) ||
!newCH)
{
AtlReportError(CLSID_Manager,
L"PassportManager.Commit: encryption failure.",
IID_IPassportManager, E_FAIL);
FREE_BSTR(newP);
return E_FAIL;
}
FREE_BSTR(newP);
TAKEOVER_BSTR(newCH);
if (m_bOnStartPageCalled)
{
if (m_pRegistryConfig->setCookiesP())
{
try
{
VARIANT_BOOL persist;
_bstr_t domain;
_bstr_t path;
if (m_pRegistryConfig->getTicketPath())
path = m_pRegistryConfig->getTicketPath();
else
path = L"/";
m_piTicket->get_HasSavedPassword(&persist);
IRequestDictionaryPtr piCookies = m_piResponse->Cookies;
VARIANT vtNoParam;
VariantInit(&vtNoParam);
vtNoParam.vt = VT_ERROR;
vtNoParam.scode = DISP_E_PARAMNOTFOUND;
IWriteCookiePtr piCookie = piCookies->Item[L"MSPProf"];
piCookie->Item[vtNoParam] = newCH;
domain = m_pRegistryConfig->getTicketDomain();
if (domain.length())
piCookie->put_Domain(domain);
if (persist)
piCookie->put_Expires(g_dtExpire);
piCookie->put_Path(path);
}
catch (...)
{
FREE_BSTR(newCH);
return E_FAIL;
}
}
}
GIVEAWAY_BSTR(newCH);
*pNewProfileCookie = newCH;
if(g_pPerf)
{
g_pPerf->incrementCounter(PM_PROFILECOMMITS_SEC);
g_pPerf->incrementCounter(PM_PROFILECOMMITS_TOTAL);
}
else
{
_ASSERT(g_pPerf);
}
return S_OK;
}
//===========================================================================
//
// _Ticket -- ticket object property
//
STDMETHODIMP CManager::_Ticket(IPassportTicket** piTicket)
{
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
return m_piTicket->QueryInterface(IID_IPassportTicket,(void**)piTicket);
}
//===========================================================================
//
// _Profile
//
STDMETHODIMP CManager::_Profile(IPassportProfile** piProfile)
{
return m_piProfile->QueryInterface(IID_IPassportProfile,(void**)piProfile);
}
//===========================================================================
//
// DomainExists -- if a domain exists
//
STDMETHODIMP CManager::DomainExists(
BSTR bstrDomainName,
VARIANT_BOOL* pbExists
)
{
PassportLog("CManager::DomainExists Enter:\r\n");
if(!pbExists)
return E_INVALIDARG;
if(!bstrDomainName || (bstrDomainName[0] == L'\0'))
return E_INVALIDARG;
if(!g_config || !g_config->isValid())
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
CNexusConfig* cnc = g_config->checkoutNexusConfig();
*pbExists = cnc->DomainExists(bstrDomainName) ? VARIANT_TRUE : VARIANT_FALSE;
cnc->Release();
PassportLog("CManager::DomainExists Exit:\r\n");
return S_OK;
}
//===========================================================================
//
// get_Domains -- get a list of domains
//
STDMETHODIMP CManager::get_Domains(VARIANT *pArrayVal)
{
CNexusConfig* cnc = NULL;
LPCWSTR* arr = NULL;
int iArr = 0;
HRESULT hr;
PassportLog("CManager::get_Domains Enter:\r\n");
if (!pArrayVal)
return E_INVALIDARG;
if (!g_config || !g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
cnc = g_config->checkoutNexusConfig();
arr = cnc->getDomains(&iArr);
if (!arr || iArr == 0)
{
VariantClear(pArrayVal);
hr = S_OK;
goto Cleanup;
}
// Make a safearray with all the goods
SAFEARRAYBOUND rgsabound;
rgsabound.lLbound = 0;
rgsabound.cElements = iArr;
SAFEARRAY *sa = SafeArrayCreate(VT_VARIANT, 1, &rgsabound);
if (!sa)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
VariantInit(pArrayVal);
pArrayVal->vt = VT_ARRAY | VT_VARIANT;
pArrayVal->parray = sa;
VARIANT *vArray;
SafeArrayAccessData(sa, (void**)&vArray);
for (long i = 0; i < iArr; i++)
{
vArray[i].vt = VT_BSTR;
vArray[i].bstrVal = ALLOC_AND_GIVEAWAY_BSTR(arr[i]);
}
SafeArrayUnaccessData(sa);
hr = S_OK;
Cleanup:
if (arr)
{
delete[] arr;
}
if (NULL != cnc)
{
cnc->Release();
}
PassportLog("CManager::DomainExists Exit:\r\n");
return hr;
}
//===========================================================================
//
// get_Error -- get the error returned with &f query parameter
//
STDMETHODIMP CManager::get_Error(long* plError)
{
if(plError == NULL)
return E_INVALIDARG;
if(m_ticketValid)
{
if (!m_piTicket)
{
return E_OUTOFMEMORY;
}
m_piTicket->get_Error(plError);
if(*plError == 0)
*plError = m_lNetworkError;
}
else
{
*plError = m_lNetworkError;
}
PassportLog("CManager::get_Error: %X\r\n", *plError);
return S_OK;
}
//===========================================================================
//
// GetServerInfo
//
STDMETHODIMP CManager::GetServerInfo(BSTR *pbstrOut)
{
if (!g_config || !g_config->isValid()) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if(!m_pRegistryConfig)
// This only happens when OnStartPage was not called first.
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!m_pRegistryConfig)
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
CNexusConfig* cnc = g_config->checkoutNexusConfig();
BSTR bstrVersion = cnc->GetXMLInfo();
cnc->Release();
WCHAR wszName[MAX_COMPUTERNAME_LENGTH+1];
DWORD dwSize = MAX_COMPUTERNAME_LENGTH+1;
GetComputerName(wszName, &dwSize);
*pbstrOut = ALLOC_AND_GIVEAWAY_BSTR_LEN(NULL,
wcslen(wszName) + ::SysStringLen(bstrVersion) + 2);
if (NULL == *pbstrOut)
{
return E_OUTOFMEMORY;
}
wcscpy(*pbstrOut, wszName);
BSTR p = *pbstrOut + wcslen(wszName);
*p = L' ';
wcsncpy(p+1, bstrVersion, ::SysStringLen(bstrVersion) + 1);
return S_OK;
}
//===========================================================================
//
// HaveConsent -- if the user has the specified consent
//
STDMETHODIMP
CManager::HaveConsent(
VARIANT_BOOL bNeedFullConsent,
VARIANT_BOOL bNeedBirthdate,
VARIANT_BOOL* pbHaveConsent)
{
HRESULT hr;
ULONG flags = 0;
VARIANT vBdayPrecision;
BOOL bKid;
BOOL bConsentSatisfied;
ConsentStatusEnum ConsentCode = ConsentStatus_Unknown;
VARIANT_BOOL bRequireConsentCookie;
if(pbHaveConsent == NULL)
{
hr = E_POINTER;
goto Cleanup;
}
*pbHaveConsent = VARIANT_FALSE;
VariantInit(&vBdayPrecision);
if (!m_piTicket || !m_piProfile || !m_pRegistryConfig)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
// If the cookies came in on the query string then there is no consent cookie yet so don't
// require one. Otherwise check to see if the consent cookie domain or path is set
// differently than the cookie domain or path. If so (and we aren't in the DA domain) then
// the consent cookie is required.
bRequireConsentCookie = !m_fromQueryString &&
((lstrcmpA(m_pRegistryConfig->getTicketDomain(), m_pRegistryConfig->getProfileDomain())
|| lstrcmpA(m_pRegistryConfig->getTicketPath(), m_pRegistryConfig->getProfilePath()))
&& !(m_pRegistryConfig->bInDA())) ? VARIANT_TRUE : VARIANT_FALSE;
//
// Get flags.
//
hr = m_piTicket->ConsentStatus(bRequireConsentCookie, &flags, &ConsentCode); // ignore return value
if (hr != S_OK)
{
hr = S_OK;
goto Cleanup;
}
// if old ticket, we get the consent info from the profile
if(ConsentCode == ConsentStatus_NotDefinedInTicket)
{
// then we get from profile
VARIANT_BOOL bValid;
CComVariant vFlags;
m_piProfile->get_IsValid(&bValid);
if(bValid == VARIANT_FALSE)
{
hr = S_OK;
goto Cleanup;
}
hr = m_piProfile->get_Attribute(L"flags", &vFlags);
if(hr != S_OK)
goto Cleanup;
bKid = ((V_I4(&vFlags) & k_ulFlagsAccountType) == k_ulFlagsAccountTypeKid);
}
else
bKid = ((flags & k_ulFlagsAccountType) == k_ulFlagsAccountTypeKid);
// we should have the flags by now
//
// Do we have the requested level of consent?
//
bConsentSatisfied = bNeedFullConsent ? (flags & 0x60) == 0x40 :
(flags & 0x60) != 0;
if(bKid)
{
*pbHaveConsent = (bConsentSatisfied) ? VARIANT_TRUE : VARIANT_FALSE;
}
else
{
//
// Make sure we have birthday if it was requested.
//
// no return value check need here, always returns S_OK.
VARIANT_BOOL bValid;
m_piProfile->get_IsValid(&bValid);
// if profile is not valid, then we don't have consent.
// return.
if(bValid == VARIANT_FALSE)
{
hr = S_OK;
goto Cleanup;
}
if(bNeedBirthdate)
{
hr = m_piProfile->get_Attribute(L"bday_precision", &vBdayPrecision);
if(hr != S_OK)
goto Cleanup;
*pbHaveConsent = (vBdayPrecision.iVal != 0 && vBdayPrecision.iVal != 3) ?
VARIANT_TRUE : VARIANT_FALSE;
}
else
*pbHaveConsent = VARIANT_TRUE;
}
hr = S_OK;
Cleanup:
VariantClear(&vBdayPrecision);
return hr;
}
//===========================================================================
//
// checkForPassportChallenge
//
//
// check the qs parameter. if challenge is requested,
// build the auth header and redirect with a modified qs
//
BOOL CManager::checkForPassportChallenge(IRequestDictionaryPtr piServerVariables)
{
BOOL fReturn = FALSE;
BSTR bstrBuf = NULL;
// just need the request string
_variant_t vtItemName, vtQueryString;
vtItemName = L"QUERY_STRING";
piServerVariables->get_Item(vtItemName, &vtQueryString);
if(vtQueryString.vt != VT_BSTR)
vtQueryString.ChangeType(VT_BSTR);
if (vtQueryString.bstrVal && *vtQueryString.bstrVal)
{
// check if pchg=1 is there. It is the first parameter ....
PWSTR psz = wcsstr(vtQueryString.bstrVal, L"pchg=1");
if (psz)
{
// we are in business. reformat the URL, insert the headers and
// redirect
psz = wcsstr(psz, PPLOGIN_PARAM);
_ASSERT(psz);
if (psz)
{
psz += wcslen(PPLOGIN_PARAM);
PWSTR pszEndLoginUrl = wcsstr(psz, L"&");
_ASSERT(pszEndLoginUrl);
if (pszEndLoginUrl)
{
*pszEndLoginUrl = L'\0';
// unescape the URL
// use temp buffer ...
DWORD cch = wcslen(psz) + 1;
bstrBuf = SysAllocStringLen(NULL, cch);
if (NULL == bstrBuf)
{
goto Cleanup;
}
if(!InternetCanonicalizeUrl(psz,
bstrBuf,
&cch,
ICU_DECODE | ICU_NO_ENCODE))
{
// what else can be done ???
_ASSERT(FALSE);
}
else
{
// copy the unescaped URL to the orig buffer
wcscpy(psz, (BSTR)bstrBuf);
// set headers first ...
// just use the qs param with some reformatting
_bstr_t bstrHeader;
if (HeaderFromQS(wcsstr(psz, L"?"), bstrHeader))
{
m_piResponse->AddHeader(L"WWW-Authenticate", bstrHeader);
// Url is ready, redirect ...
m_piResponse->Redirect(psz);
fReturn = TRUE;
}
}
}
}
}
}
Cleanup:
if (bstrBuf)
{
SysFreeString(bstrBuf);
}
return fReturn;
}
//===========================================================================
//
// HeaderFromQS
//
//
// given a queryString, format the www-authenticate header
//
BOOL
CManager::HeaderFromQS(PWSTR pszQS, _bstr_t& bstrHeader)
{
// common header start ...
bstrHeader = PASSPORT_PROT14;
BOOL fSuccess = TRUE;
BSTR signature = NULL;
// advance thru any leading junk ...
while(!iswalnum(*pszQS) && *pszQS) pszQS++;
if (!*pszQS)
{
fSuccess = FALSE;
goto Cleanup;
}
WCHAR rgszValue[1000]; // buffer large enough for most values ...
PCWSTR psz = pszQS, pszNext = pszQS;
while(TRUE)
{
// no param name is more than 10 ....
WCHAR rgszName[10];
LONG cch = sizeof(rgszName)/sizeof(WCHAR);
PCWSTR pszName = psz;
while(*pszNext && *pszNext != L'&') pszNext++;
// grab the next qsparam
// name first
while(*pszName != L'=' && pszName < pszNext) pszName++;
_ASSERT(pszName != pszNext); // this should never happen
if (pszName == pszNext)
{
// and if it does, skip this parameter and return FALSE ...
fSuccess = FALSE;
goto Cleanup;
}
else
{
PWSTR pszVal = rgszValue;
ULONG cchVal;
_ASSERT((pszName - psz) <= cch);
wcsncpy(rgszName, psz, cch - 1);
rgszName[cch - 1] = L'\0';
// next comes the value
pszName++;
cchVal = (pszNext - pszName); // note these are PWSTR pointers so the result is length in characters
if (cchVal >= (sizeof(rgszValue) / sizeof(rgszValue[0])) )
{
// have to allocate ...
pszVal = new WCHAR[cchVal + 1];
if (!pszVal)
{
fSuccess = FALSE;
goto Cleanup;
}
}
// copy the value ...
wcsncpy(pszVal, pszName, cchVal );
pszVal[cchVal] = L'\0';
// and insert in the header ...
if (psz != pszQS)
// this is not the first param
bstrHeader += L",";
else
// first separator is a space ...
bstrHeader += L" ";
bstrHeader += _bstr_t(rgszName) + L"=" + pszVal;
if (pszVal != rgszValue)
// it was alloc'd
delete[] pszVal;
} // else '=' found
// leave loop
if (!*pszNext)
break;
psz = ++pszNext;
} // while
// sign the header
// actually the signature is on the qs
HRESULT hr = PartnerHash(m_pRegistryConfig,
m_pRegistryConfig->getCurrentCryptVersion(),
pszQS,
wcslen(pszQS),
&signature);
if (S_OK == hr)
{
bstrHeader += _bstr_t(L",tpf=") + (BSTR)signature;
}
else
{
fSuccess = FALSE;
}
Cleanup:
if (signature)
{
SysFreeString(signature);
}
return fSuccess;
}
//===========================================================================
//
// FormatAuthHeaderFromParams
//
//
// format WWW-Auth from parameters
//
STDMETHODIMP CManager::FormatAuthHeaderFromParams(PCWSTR pszLoginUrl, // unused for now
PCWSTR pszRetUrl,
ULONG ulTimeWindow,
BOOL fForceLogin,
time_t ct,
PCWSTR pszCBT, // unused for now
PCWSTR pszNamespace,
int nKpp,
PWSTR pszLCID, // tweener needs the LCID
ULONG ulSecureLevel,
_bstr_t& strHeader // return result
)
{
WCHAR temp[40];
// based on the spec ...
// lcid is not really needed, however it is present when
// header is created from qs and it's used
strHeader = _bstr_t(PASSPORT_PROT14) + L" lc=" + pszLCID;
// site=
strHeader += "&id=";
_ultow(m_pRegistryConfig->getSiteId(), temp, 10);
strHeader += temp;
// rtw=
strHeader += "&tw=";
_ultow(ulTimeWindow, temp, 10);
strHeader += temp;
if (fForceLogin)
{
strHeader += _bstr_t("&fs=1");
}
if (pszNamespace && *pszNamespace)
{
strHeader += _bstr_t("&ns=") + pszNamespace;
}
// ru=
strHeader += _bstr_t("&ru=") + pszRetUrl;
// ct=
_ultow(ct, temp, 10);
strHeader += _bstr_t(L"&ct=") + temp;
// kpp
if (nKpp != -1)
{
_ultow(nKpp, temp, 10);
strHeader += _bstr_t(L"&kpp=") + temp;
}
// key version and version
_ultow(m_pRegistryConfig->getCurrentCryptVersion(), temp, 10);
strHeader += _bstr_t(L"&kv=") + temp;
strHeader += _bstr_t(L"&ver=") + GetVersionString();
// secure level
if (ulSecureLevel)
{
strHeader += _bstr_t(L"&seclog=") + _ultow(ulSecureLevel, temp, 10);
}
// sign the header
BSTR signature = NULL;
PWSTR szStart = wcsstr(strHeader, L"lc=");
HRESULT hr = PartnerHash(m_pRegistryConfig,
m_pRegistryConfig->getCurrentCryptVersion(),
szStart,
strHeader.length() - (szStart - strHeader),
&signature);
// replace '&' with ','
BSTR psz = (BSTR)strHeader;
while (*psz)
{
if (*psz == L'&') *psz = L',';
psz++;
}
if (S_OK == hr)
{
strHeader += _bstr_t(L",tpf=") + (BSTR)signature;
}
if (signature)
{
SysFreeString(signature);
}
return hr;
}
//===========================================================================
//
// GetLoginParams
//
//
// common code to parse user's parameters
// and get defaults from registry config
//
STDMETHODIMP CManager::GetLoginParams(VARIANT vRU,
VARIANT vTimeWindow,
VARIANT vForceLogin,
VARIANT vCoBrand,
VARIANT vLCID,
VARIANT vNameSpace,
VARIANT vKPP,
VARIANT vSecureLevel,
// these are the processed values
_bstr_t& strUrl,
_bstr_t& strReturnUrl,
UINT& TimeWindow,
VARIANT_BOOL& ForceLogin,
time_t& ct,
_bstr_t& strCBT,
_bstr_t& strNameSpace,
int& nKpp,
ULONG& ulSecureLevel,
PWSTR pszLCID)
{
USES_CONVERSION;
LPCWSTR url;
VARIANT freeMe;
BSTR CBT = NULL, returnUrl = NULL, bstrNameSpace = NULL;
int hasCB, hasRU, hasLCID, hasTW, hasFL, hasNameSpace, hasKPP, hasUseSec;
USHORT Lang;
CNexusConfig* cnc = NULL;
HRESULT hr = S_OK;
PassportLog("CManager::GetLoginParams Enter:\r\n");
if (!g_config) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
if (!m_pRegistryConfig)
m_pRegistryConfig = g_config->checkoutRegistryConfig();
if (!g_config->isValid() || !m_pRegistryConfig) // Guarantees config is non-null
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportManager, PP_E_NOT_CONFIGURED);
return PP_E_NOT_CONFIGURED;
}
// Make sure args are of the right type
if ((hasTW = GetIntArg(vTimeWindow, (int*) &TimeWindow)) == CV_BAD)
return E_INVALIDARG;
if ((hasFL = GetBoolArg(vForceLogin, &ForceLogin)) == CV_BAD)
return E_INVALIDARG;
if ((hasUseSec = GetIntArg(vSecureLevel, (int*)&ulSecureLevel)) == CV_BAD)
return E_INVALIDARG;
if ((hasLCID = GetShortArg(vLCID, &Lang)) == CV_BAD)
return E_INVALIDARG;
if ((hasKPP = GetIntArg(vKPP, &nKpp)) == CV_BAD)
return E_INVALIDARG;
hasCB = GetBstrArg(vCoBrand, &CBT);
if (hasCB == CV_BAD)
return E_INVALIDARG;
strCBT = CBT;
if (hasCB == CV_FREE)
{
TAKEOVER_BSTR(CBT);
}
hasRU = GetBstrArg(vRU, &returnUrl);
if (hasRU == CV_BAD)
{
if (hasCB == CV_FREE && CBT)
FREE_BSTR(CBT);
return E_INVALIDARG;
}
strReturnUrl = returnUrl;
if (hasRU == CV_FREE)
{
FREE_BSTR(returnUrl);
}
hasNameSpace = GetBstrArg(vNameSpace, &bstrNameSpace);
if (hasNameSpace == CV_BAD)
{
if (hasCB == CV_FREE && CBT)
FREE_BSTR(CBT);
return E_INVALIDARG;
}
if (hasNameSpace == CV_OK)
strNameSpace = bstrNameSpace;
if (hasNameSpace == CV_FREE)
{
FREE_BSTR(bstrNameSpace);
}
if (hasNameSpace == CV_DEFAULT)
{
if (NULL == m_pRegistryConfig->getNameSpace())
{
strNameSpace = L"";
}
else
{
strNameSpace = m_pRegistryConfig->getNameSpace();
}
}
if(hasUseSec == CV_DEFAULT)
ulSecureLevel = m_pRegistryConfig->getSecureLevel();
if(ulSecureLevel == VARIANT_TRUE) // special case for backward compatible
ulSecureLevel = k_iSeclevelSecureChannel;
WCHAR *szAUAttrName;
if (SECURELEVEL_USE_HTTPS(ulSecureLevel))
szAUAttrName = L"AuthSecure";
else
szAUAttrName = L"Auth";
cnc = g_config->checkoutNexusConfig();
if (hasLCID == CV_DEFAULT)
Lang = m_pRegistryConfig->getDefaultLCID();
if (hasKPP == CV_DEFAULT)
nKpp = m_pRegistryConfig->getKPP();
// convert the LCID to str for tweener ...
_itow((int)Lang, pszLCID, 10);
VariantInit(&freeMe);
// **************************************************
// Logging
if (NULL != returnUrl)
{
PassportLog(" RU = %ws\r\n", returnUrl);
}
PassportLog(" TW = %X, SL = %X, L = %d, KPP = %X\r\n", TimeWindow, ulSecureLevel, Lang, nKpp);
if (NULL != CBT)
{
PassportLog(" CBT = %ws\r\n", CBT);
}
// **************************************************
if (!m_pRegistryConfig->DisasterModeP())
{
// If I'm authenticated, get my domain specific url
WCHAR UrlBuf[MAX_URL_LENGTH];
if (m_ticketValid && m_profileValid)
{
HRESULT hr = m_piProfile->get_ByIndex(MEMBERNAME_INDEX, &freeMe);
if (hr != S_OK || freeMe.vt != VT_BSTR)
{
cnc->getDomainAttribute(L"Default",
szAUAttrName,
sizeof(UrlBuf)/sizeof(WCHAR),
UrlBuf,
Lang);
strUrl = UrlBuf;
}
else
{
LPCWSTR psz = wcsrchr(freeMe.bstrVal, L'@');
cnc->getDomainAttribute(psz ? psz+1 : L"Default",
szAUAttrName,
sizeof(UrlBuf)/sizeof(WCHAR),
UrlBuf,
Lang);
strUrl = UrlBuf;
}
}
if (strUrl.length() == 0)
{
cnc->getDomainAttribute(L"Default",
szAUAttrName,
sizeof(UrlBuf)/sizeof(WCHAR),
UrlBuf,
Lang);
strUrl = UrlBuf;
}
}
else
strUrl = m_pRegistryConfig->getDisasterUrl();
_ASSERT(strUrl.length() != 0);
time(&ct);
if (hasTW == CV_DEFAULT)
TimeWindow = m_pRegistryConfig->getDefaultTicketAge();
if (hasFL == CV_DEFAULT)
ForceLogin = m_pRegistryConfig->forceLoginP() ? VARIANT_TRUE : VARIANT_FALSE;
if (hasCB == CV_DEFAULT)
strCBT = m_pRegistryConfig->getDefaultCoBrand();
if (hasRU == CV_DEFAULT)
strReturnUrl = m_pRegistryConfig->getDefaultRU() ?
m_pRegistryConfig->getDefaultRU() : L"";
if ((TimeWindow != 0 && TimeWindow < PPM_TIMEWINDOW_MIN) || TimeWindow > PPM_TIMEWINDOW_MAX)
{
AtlReportError(CLSID_Manager, (LPCOLESTR) PP_E_INVALID_TIMEWINDOWSTR,
IID_IPassportManager, PP_E_INVALID_TIMEWINDOW);
hr = PP_E_INVALID_TIMEWINDOW;
goto Cleanup;
}
Cleanup:
if (NULL != cnc)
{
cnc->Release();
}
VariantClear(&freeMe);
PassportLog("CManager::GetLoginParams Exit: %X\r\n", hr);
return hr;
}
//===========================================================================
//
// GetTicketAndProfileFromHeader
//
//
// get ticket & profile from auth header
// params:
// AuthHeader - [in/out] contents of HTTP_Authorization header
// pszTicket - [out] ptr to the ticket part in the header
// pszProfile -[out] ptr to the profile
// pwszF - [out] ptr to error coming in the header
// Auth header contents is changed as a side effect of the function
//
static VOID GetTicketAndProfileFromHeader(PWSTR pszAuthHeader,
PWSTR& pszTicket,
PWSTR& pszProfile,
PWSTR& pszF)
{
// check for t=, p=, and f=
if (pszAuthHeader && *pszAuthHeader)
{
// format is 'Authorization: from-PP='t=xxx&p=xxx'
PWSTR pwsz = wcsstr(pszAuthHeader, L"from-PP");
if (pwsz)
{
// ticket and profile are enclosed in ''. Not very strict parsing indeed ....
while(*pwsz != L'\'' && *pwsz)
pwsz++;
if (*pwsz++)
{
if (*pwsz == L'f')
{
pwsz++;
if (*pwsz == L'=')
{
pwsz++;
// error case
pszF = pwsz;
}
}
else
{
// ticket and profile ...
_ASSERT(*pwsz == L't');
if (*pwsz == L't')
{
pwsz++;
if (*pwsz == L'=')
{
pwsz++;
pszTicket = pwsz;
}
}
while(*pwsz != L'&' && *pwsz)
pwsz++;
if (*pwsz)
*pwsz++ = L'\0';
if (*pwsz == L'p')
{
pwsz++;
if (*pwsz == L'=')
{
pwsz++;
pszProfile = pwsz;
}
}
// finally remove the last '
}
// set \0 terminator
while(*pwsz != L'\'' && *pwsz)
pwsz++;
if (*pwsz)
*pwsz = L'\0';
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// IPassportService implementation
//===========================================================================
//
// Initialize
//
STDMETHODIMP CManager::Initialize(BSTR configfile, IServiceProvider* p)
{
HRESULT hr;
// Initialized?
if (!g_config || !g_config->isValid()) // This calls UpdateNow if not yet initialized.
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportService, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// Shutdown
//
STDMETHODIMP CManager::Shutdown()
{
return S_OK;
}
//===========================================================================
//
// ReloadState
//
STDMETHODIMP CManager::ReloadState(IServiceProvider*)
{
HRESULT hr;
// Initialize.
if(!g_config || !g_config->PrepareUpdate(TRUE))
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportService, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// CommitState
//
STDMETHODIMP CManager::CommitState(IServiceProvider*)
{
HRESULT hr;
// Finish the two phase update.
if(!g_config || !g_config->CommitUpdate())
{
AtlReportError(CLSID_Manager, PP_E_NOT_CONFIGUREDSTR,
IID_IPassportService, PP_E_NOT_CONFIGURED);
hr = PP_E_NOT_CONFIGURED;
goto Cleanup;
}
hr = S_OK;
Cleanup:
return hr;
}
//===========================================================================
//
// DumpState
//
STDMETHODIMP CManager::DumpState(BSTR* pbstrState)
{
ATLASSERT( *pbstrState != NULL &&
"CManager:DumpState - "
"Are you sure you want to hand me a non-null BSTR?" );
if(!g_config)
{
return PP_E_NOT_CONFIGURED;
}
g_config->Dump(pbstrState);
return S_OK;
}