/**********************************************************************/ /** 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 #include "Manager.h" #include #include #include #include #include #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(); } catch(...) { m_piTicket = NULL; } if(m_piTicket) m_piTicket->AddRef(); // profile object try { m_piProfile = new CComObject(); } 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 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 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 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 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 spResponse; CComQIPtr 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 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 func(PPTRACE_FUNC, hr, "OnStartPageECB", " <<< %lx, %lx, %d, %lx", pvECB, bufSize, *bufSize, pCookieHeader); ATL::CAutoVectorPtr spHTTPS; ATL::CAutoVectorPtr 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 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 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 func(PPTRACE_FUNC, hr, "OnStartPageFilter", " <<< %lx, %lx, %d, %lx", pvPFC, bufSize, *bufSize, pCookieHeader); ATL::CAutoVectorPtr spheaders; ATL::CAutoVectorPtr spHTTPS; ATL::CAutoVectorPtr 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 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; }