/****************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: Service.cpp Abstract: This file contains the implementation of IPCHService interface. Revision History: Davide Massarenti (Dmassare) 03/14/2000 created Kalyani Narlanka (Kalyanin) 10/20/2000 Added functionality for Unsolicited Remote Control ******************************************************************************/ #include "stdafx.h" #include #include #include #include #include "sessmgr_i.c" #include #include "rassistance.h" #include "rassistance_i.c" ///////////////////////////////////////////////////////////////////////////// static const WCHAR s_location_HELPCTR [] = HC_ROOT_HELPSVC_BINARIES L"\\HelpCtr.exe"; static const WCHAR s_location_HELPSVC [] = HC_ROOT_HELPSVC_BINARIES L"\\HelpSvc.exe"; static const WCHAR s_location_HELPHOST[] = HC_ROOT_HELPSVC_BINARIES L"\\HelpHost.exe"; static const LPCWSTR s_include_Generic[] = { s_location_HELPCTR , s_location_HELPSVC , s_location_HELPHOST, NULL }; static const LPCWSTR s_include_RegisterHost[] = { s_location_HELPHOST, NULL }; static const WCHAR c_szUnsolicitedRA [] = L"Software\\Policies\\Microsoft\\Windows NT\\Terminal Services"; static const WCHAR c_szUnsolicitedRA_SD[] = L"UnsolicitedAccessDACL"; static const WCHAR c_szUnsolicitedListKey[]= L"RAUnsolicit"; static const WCHAR c_szUnsolicitedNew_SD [] = L"UnsolicitedAccessNewDACL"; static HRESULT local_MakeDACL( MPC::WStringList& sColl, LPWSTR& pwszSD ); static HRESULT local_GetDACLValue( MPC::wstring& pSD, bool& fFound); ///////////////////////////////////////////////////////////////////////////// CPCHService::CPCHService() { __HCP_FUNC_ENTRY( "CPCHService::CPCHService" ); m_fVerified = false; // bool m_fVerified; } CPCHService::~CPCHService() { __HCP_FUNC_ENTRY( "CPCHService::~CPCHService" ); } ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHService::get_RemoteSKUs( /*[out, retval]*/ IPCHCollection* *pVal ) { __HCP_FUNC_ENTRY( "CPCHService::get_RemoteSKUs" ); HRESULT hr; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END(); // // Return a list with only the exported SKUs. // __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHTaxonomyDatabase::SelectInstalledSKUs( true, pVal )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// STDMETHODIMP CPCHService::IsTrusted( /*[in]*/ BSTR bstrURL, /*[out, retval]*/ VARIANT_BOOL *pfTrusted ) { __HCP_FUNC_ENTRY( "CPCHService::IsTrusted" ); HRESULT hr; bool fTrusted; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrURL); __MPC_PARAMCHECK_POINTER_AND_SET(pfTrusted,VARIANT_FALSE); __MPC_PARAMCHECK_NOTNULL(CPCHContentStore::s_GLOBAL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->IsTrusted( bstrURL, fTrusted )); if(fTrusted) *pfTrusted = VARIANT_TRUE; hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// STDMETHODIMP CPCHService::Utility( /*[in ]*/ BSTR bstrSKU , /*[in ]*/ long lLCID , /*[out]*/ IPCHUtility* *pVal ) { __HCP_FUNC_ENTRY( "CPCHService::Utility" ); HRESULT hr; CComPtr svc; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END(); // // Verify the caller is a trusted one. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::VerifyCallerIsTrusted( s_include_Generic )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &svc )); if(bstrSKU || lLCID) { CComPtr pchus; __MPC_EXIT_IF_METHOD_FAILS(hr, svc->get_UserSettings( &pchus )); __MPC_EXIT_IF_METHOD_FAILS(hr, pchus->Select( bstrSKU, lLCID )); } __MPC_EXIT_IF_METHOD_FAILS(hr, svc.QueryInterface( pVal )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::RemoteHelpContents( /*[in ]*/ BSTR bstrSKU , /*[in ]*/ long lLCID , /*[out]*/ IPCHRemoteHelpContents* *pVal ) { __HCP_FUNC_ENTRY( "CPCHService::RemoteHelpContents" ); HRESULT hr; CComPtr rhc; Taxonomy::HelpSet ths; Taxonomy::LockingHandle handle; Taxonomy::InstalledInstanceIter it; bool fFound; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_NOTNULL(Taxonomy::InstalledInstanceStore::s_GLOBAL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, ths.Initialize( bstrSKU, lLCID )); __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle )); __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->SKU_Find ( ths, fFound, it )); if(fFound) { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &rhc )); __MPC_EXIT_IF_METHOD_FAILS(hr, rhc->Init( it->m_inst )); __MPC_EXIT_IF_METHOD_FAILS(hr, rhc.QueryInterface( pVal )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// STDMETHODIMP CPCHService::RegisterHost( /*[in]*/ BSTR bstrID, /*[in]*/ IUnknown* pUnk ) { __HCP_FUNC_ENTRY( "CPCHService::RegisterHost" ); HRESULT hr; CComQIPtr pObj = pUnk; if(pObj == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE); // // Verify the caller is really HelpHost.exe. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::VerifyCallerIsTrusted( s_include_RegisterHost )); hr = CPCHUserProcess::s_GLOBAL ? CPCHUserProcess::s_GLOBAL->RegisterHost( bstrID, pObj ) : E_FAIL; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::CreateScriptWrapper( /*[in ]*/ REFCLSID rclsid , /*[in ]*/ BSTR bstrCode , /*[in ]*/ BSTR bstrURL , /*[out]*/ IUnknown* *ppObj ) { __HCP_FUNC_ENTRY( "CPCHService::CreateScriptWrapper" ); HRESULT hr; CComBSTR bstrRealCode; CPCHScriptWrapper_ServerSide::HeaderList lst; CPCHScriptWrapper_ServerSide::HeaderIter it; CPCHUserProcess::UserEntry ue; CComPtr sp; MPC::wstring strVendorID; MPC::wstring strSignature; if(bstrURL == NULL || CPCHContentStore::s_GLOBAL == NULL || CSAFReg ::s_GLOBAL == NULL || CPCHUserProcess ::s_GLOBAL == NULL ) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_ACCESS_DENIED); } __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHScriptWrapper_ServerSide::ProcessBody( bstrCode, bstrRealCode, lst )); // // Look for the vendor ID. // it = std::find( lst.begin(), lst.end(), L"VENDORID" ); if(it == lst.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_ACCESS_DENIED); } strVendorID = it->m_strValue; // // Make sure the VendorID declared in the script matches the one which has registered the URL as trusted. // { bool fTrusted; MPC::wstring strVendorURL; __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHContentStore::s_GLOBAL->IsTrusted( bstrURL, fTrusted, &strVendorURL )); if(MPC::StrICmp( strVendorID, strVendorURL )) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_ACCESS_DENIED); } } // // Look for the script signature. // it = std::find( lst.begin(), lst.end(), L"SIGNATURE" ); if(it == lst.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_ACCESS_DENIED); } strSignature = it->m_strValue; // // Lookup the vendor in the SAF store (this also prepares the creation of the user process). // __MPC_EXIT_IF_METHOD_FAILS(hr, CSAFReg::s_GLOBAL->LookupAccountData( CComBSTR( strVendorID.c_str() ), ue )); // // Verify signature. // { CPCHCryptKeys key; __MPC_EXIT_IF_METHOD_FAILS(hr, key.ImportPublic( ue.GetPublicKey() )); __MPC_EXIT_IF_METHOD_FAILS(hr, key.VerifyData( strSignature.c_str(), (BYTE*)(BSTR)bstrRealCode, ::SysStringLen( bstrRealCode ) * sizeof(WCHAR) )); } // // Create the vendor's process. // __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHUserProcess::s_GLOBAL->Connect( ue, &sp )); // // Forward request. // __MPC_EXIT_IF_METHOD_FAILS(hr, sp->CreateScriptWrapper( rclsid, bstrCode, bstrURL, ppObj )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// STDMETHODIMP CPCHService::TriggerScheduledDataCollection( /*[in]*/ VARIANT_BOOL fStart ) { return CPCHSystemMonitor::s_GLOBAL ? CPCHSystemMonitor::s_GLOBAL->TriggerDataCollection( fStart == VARIANT_TRUE ) : E_FAIL; } STDMETHODIMP CPCHService::PrepareForShutdown() { __HCP_FUNC_ENTRY( "CPCHService::PrepareForShutdown" ); _Module.ForceShutdown(); __HCP_FUNC_EXIT(S_OK); } //////////////////// STDMETHODIMP CPCHService::ForceSystemRestore() { __HCP_FUNC_ENTRY( "CPCHService::ForceSystemRestore" ); HRESULT hr; CComObject* hc = NULL; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::VerifyCallerIsTrusted( s_include_Generic )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hc )); __MPC_EXIT_IF_METHOD_FAILS(hr, hc->ForceSystemRestore()); hr = S_OK; __HCP_FUNC_CLEANUP; if(hc) hc->Release(); __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::UpgradeDetected() { __HCP_FUNC_ENTRY( "CPCHService::UpgradeDetected" ); HRESULT hr; // // Allow only ADMINS. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, NULL, MPC::IDENTITY_ADMINS )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::MUI_Install( /*[in]*/ long LCID, /*[in]*/ BSTR bstrFile ) { __HCP_FUNC_ENTRY( "CPCHService::MUI_Install" ); HRESULT hr; // // Allow only ADMINS. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, NULL, MPC::IDENTITY_ADMINS )); //////////////////////////////////////// { Installer::Package pkg; CComPtr sht; MPC::wstring strFile; // // Because of a possible problem with the INF, it could be that the filename has an extra "%LCID%" in it, instead of the straight %LCID%. // { WCHAR rgBufBad[64]; swprintf( rgBufBad, L"\"%04x\"", LCID ); WCHAR rgBufOk [64]; swprintf( rgBufOk , L"%04x" , LCID ); MPC::wstring::size_type pos; MPC::wstring::size_type len = wcslen( rgBufBad ); strFile = SAFEBSTR(bstrFile); while((pos = strFile.find( rgBufBad )) != strFile.npos) { strFile.replace( pos, len, rgBufOk ); } } __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &sht )); __MPC_EXIT_IF_METHOD_FAILS(hr, pkg.Init( strFile.c_str() )); __MPC_EXIT_IF_METHOD_FAILS(hr, pkg.Load( )); { Taxonomy::InstanceBase& base = pkg.GetData(); if(_wcsicmp( base.m_ths.GetSKU() , Taxonomy::HelpSet::GetMachineSKU() ) || base.m_ths.GetLanguage() != LCID || LCID == Taxonomy::HelpSet::GetMachineLanguage() ) // Don't overwrite system SKU!! { __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); // Mismatch in parameter, ignore it. } } __MPC_EXIT_IF_METHOD_FAILS(hr, sht->DirectInstall( pkg, /*fSetup*/false, /*fSystem*/false, /*fMUI*/true )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::MUI_Uninstall( /*[in]*/ long LCID ) { __HCP_FUNC_ENTRY( "CPCHService::MUI_Uninstall" ); HRESULT hr; // // Allow only ADMINS. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, NULL, MPC::IDENTITY_ADMINS )); //////////////////////////////////////// { Installer::Package pkg; CComPtr sht; Taxonomy::HelpSet ths; __MPC_EXIT_IF_METHOD_FAILS(hr, ths.Initialize( Taxonomy::HelpSet::GetMachineSKU(), LCID )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &sht )); __MPC_EXIT_IF_METHOD_FAILS(hr, sht->DirectUninstall( &ths )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// static void local_PackString( /*[in/out]*/ CComBSTR& bstr , /*[in ]*/ LPCWSTR szAppend ) { WCHAR rgLen[64]; SANITIZEWSTR( szAppend ); swprintf( rgLen, L"%d;", wcslen( szAppend ) ); bstr.Append( rgLen ); bstr.Append( szAppend ); } static HRESULT local_MakeDACL( MPC::WStringList& sColl, LPWSTR& pwszSD ) { __HCP_FUNC_ENTRY( "local_MakeDACL" ); SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY; SECURITY_DESCRIPTOR sd; SID_NAME_USE snu; WCHAR *pwszDomain = NULL, *pwszUser = NULL; WCHAR wszDom[1024]; DWORD cbNeedACL, cbNeed, cchDom, dwCount; DWORD cchSD; PACL pacl = NULL; PSID *rgsid = NULL, psidAdm = NULL; BOOL fRet = FALSE; int i, cSIDs = 0; long lCount; HRESULT hr; MPC::WStringIter it; lCount = sColl.size(); if (lCount == 0) __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); rgsid = (PSID *) malloc (lCount * sizeof(PSID)); if (rgsid == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); if (!AllocateAndInitializeSid(&siaNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdm)) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } cbNeedACL = sizeof(ACL); for(it = sColl.begin(); it != sColl.end(); it++) { LPCWSTR bstrVal = it->c_str(); cchDom = sizeof(wszDom)/sizeof(WCHAR); cbNeed = 0; fRet = LookupAccountNameW(NULL, bstrVal, NULL, &cbNeed, wszDom, &cchDom, &snu); rgsid[cSIDs] = (PSID) malloc (cbNeed); if (rgsid[cSIDs] == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); cchDom = sizeof(wszDom)/sizeof(WCHAR); fRet = LookupAccountNameW(NULL, bstrVal, rgsid[cSIDs], &cbNeed, wszDom, &cchDom, &snu); if (fRet == FALSE) { // invalid user name; free (rgsid[cSIDs]); rgsid[cSIDs] = NULL; continue; } cbNeedACL += GetLengthSid(rgsid[cSIDs]); cbNeedACL += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)); cSIDs++; } if (cbNeedACL == sizeof(ACL)) // No valid entry { __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); } pacl = (PACL) malloc (cbNeedACL); if (pacl == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); fRet = InitializeAcl(pacl, cbNeedACL, ACL_REVISION); if (fRet == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } for(i = 0; i < cSIDs; i++) { fRet = AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL | STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, rgsid[i]); if (fRet == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } } if (InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } // set the SD dacl if (SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE) == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } // set the SD owner if (SetSecurityDescriptorOwner(&sd, psidAdm, FALSE) == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } // set the SD group if (SetSecurityDescriptorGroup(&sd, psidAdm, FALSE) == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } // Verify if the SD is valid if (IsValidSecurityDescriptor(&sd) == FALSE) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } if (FALSE == ConvertSecurityDescriptorToStringSecurityDescriptorW(&sd, SDDL_REVISION_1, GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, &pwszSD, &cchSD)) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(GetLastError())); } __MPC_FUNC_CLEANUP; if (rgsid != NULL) { for(i = 0; i < cSIDs; i++) { if (rgsid[i] != NULL) free(rgsid[i]); } free(rgsid); } if (pacl != NULL) free(pacl); if (psidAdm != NULL) FreeSid(psidAdm); __MPC_FUNC_EXIT(hr); } static HRESULT local_GetDACLValue(MPC::wstring& pSD, bool& fFound) { __HCP_FUNC_ENTRY( "local_GetDACLValue" ); HRESULT hr; CRegKey cKey, cKeyDACL; LONG lRet; DWORD dwCount; LPWSTR pwBuf = NULL; if (ERROR_SUCCESS != cKey.Open(HKEY_LOCAL_MACHINE, c_szUnsolicitedRA)) { __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); } // Check to see if new DACL value exist dwCount = 0; if (ERROR_SUCCESS == cKey.QueryValue(NULL, c_szUnsolicitedNew_SD, &dwCount)) { if (NULL == (pwBuf = (LPWSTR)malloc(dwCount))) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); } if (ERROR_SUCCESS != (lRet = cKey.QueryValue(pwBuf, c_szUnsolicitedNew_SD, &dwCount))) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(lRet)); } pSD = pwBuf; __MPC_SET_ERROR_AND_EXIT(hr, S_OK); } // If we don't have DACL value, then we need to check DACL regkey list. if ( ERROR_SUCCESS != cKeyDACL.Open((HKEY)cKey, c_szUnsolicitedListKey)) { __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); } // 1. Do we have default value dwCount = 0; if ( ERROR_SUCCESS == cKeyDACL.QueryValue(NULL, NULL, &dwCount) && dwCount > sizeof(WCHAR)) // It's possible it contains '\0' { if (pwBuf) free(pwBuf); if (NULL == (pwBuf = (LPWSTR)malloc(dwCount))) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); } if ( ERROR_SUCCESS != (lRet = cKeyDACL.QueryValue(pwBuf, NULL, &dwCount))) { __MPC_SET_ERROR_AND_EXIT(hr, HRESULT_FROM_WIN32(lRet)); } pSD = pwBuf; } else // Need to calculate DACL { DWORD dwIndex = 0; DWORD dwType; WCHAR szName[257]; dwCount = 256; MPC::WStringList sColl; long lCount; while (ERROR_SUCCESS == RegEnumValueW((HKEY)cKeyDACL, dwIndex, &szName[0], &dwCount, NULL, &dwType, NULL, // no need to get it's data NULL)) { if ((dwType == REG_SZ || dwType == REG_MULTI_SZ || dwType == REG_EXPAND_SZ) && szName[0] != L'\0') { sColl.push_back( MPC::wstring(szName) ); } szName [0] = L'\0'; dwIndex ++; dwCount = 256; } if (sColl.size() > 0) { LPWSTR pwDACL = NULL; __MPC_EXIT_IF_METHOD_FAILS(hr, local_MakeDACL( sColl, pwDACL )); // Update default value if (pwDACL) { pSD = pwDACL; cKeyDACL.SetValue(pwDACL); LocalFree(pwDACL); } } else __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); } hr = S_OK; __HCP_FUNC_CLEANUP; if (pwBuf) { free(pwBuf); } fFound = (hr == S_OK); __MPC_FUNC_EXIT(hr); } static HRESULT local_CheckAccessRights() { __HCP_FUNC_ENTRY( "local_CheckAccessRights" ); HRESULT hr; bool fPermit = false; CComPtr pRARegSetting; BOOL fAllowUnsolicited; // // Check the policy settings to see whether Unsolicited RA is allowed, if not give an Access Denied error. // Create an instance of IRARegSetting. __MPC_EXIT_IF_METHOD_FAILS(hr, pRARegSetting.CoCreateInstance( CLSID_RARegSetting, NULL, CLSCTX_INPROC_SERVER )); // Call get_AllowUnSolicited() Method of IRARegSetting. __MPC_EXIT_IF_METHOD_FAILS(hr, pRARegSetting->get_AllowUnSolicited( &fAllowUnsolicited )); if(!fAllowUnsolicited) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_ACCESS_DISABLED_BY_POLICY); } // Allow someone from ADMINS to query for this data. if(SUCCEEDED(MPC::CheckCallerAgainstPrincipal( /*fImpersonate*/true, NULL, MPC::IDENTITY_ADMINS ))) { fPermit = true; } else // If not from ADMINS, check the caller against the SD stored in the Registry in the String Format. { MPC::AccessCheck ac; MPC::wstring strSD; bool fFound; BOOL fGranted = FALSE; DWORD dwGranted = 0; __MPC_EXIT_IF_METHOD_FAILS(hr, local_GetDACLValue( strSD, fFound)); if(!fFound) __MPC_SET_ERROR_AND_EXIT(hr, E_ACCESSDENIED); // Use the SD to check against the Caller. __MPC_EXIT_IF_METHOD_FAILS(hr, ac.GetTokenFromImpersonation()); if(SUCCEEDED(ac.Verify( ACCESS_READ, fGranted, dwGranted, strSD.c_str() )) && fGranted) { fPermit = true; } } if(!fPermit) { __MPC_SET_ERROR_AND_EXIT(hr, E_ACCESSDENIED); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::RemoteConnectionParms( /*[in ]*/ BSTR bstrUserName , /*[in ]*/ BSTR bstrDomainName , /*[in ]*/ long lSessionID , /*[in ]*/ BSTR bstrUserHelpBlob , /*[out]*/ BSTR *pbstrConnectionString ) { __HCP_FUNC_ENTRY( "CPCHService::RemoteConnectionParms" ); HRESULT hr; CComPtr pRDHelpSessionMgr; MPC::wstring strSID; CComBSTR bstrString1; CComBSTR bstrString2; CComBSTR bstrExpert; PSID pExpertSid = NULL; LPCWSTR szExpertUserName = NULL; LPCWSTR szExpertDomainName = NULL; BOOL fRevertSucceeded; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pbstrConnectionString,NULL); __MPC_PARAMCHECK_END(); // Fix for bug 367683 // If Unsolicited RA is done from one session to another on the same machine, // we need to RevertToSelf() before we do anything, this is because on the Expert end we do // an impersonation before calling this method. While this is correct when the expert // and novice are on two different machines, in case of a single machine, by the time the // novice side code is called there is an extra impersonation, which should not be there // we need to undo this by doing RevertToSelf() fRevertSucceeded = RevertToSelf(); __MPC_EXIT_IF_METHOD_FAILS(hr, local_CheckAccessRights()); // Create an instance of IRemoteDesktopHelpSessionMgr in order to call its method RemoteCreateHelpSession. __MPC_EXIT_IF_METHOD_FAILS(hr, pRDHelpSessionMgr.CoCreateInstance( CLSID_RemoteDesktopHelpSessionMgr, NULL, CLSCTX_LOCAL_SERVER )); __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoSetProxyBlanket( pRDHelpSessionMgr , RPC_C_AUTHN_DEFAULT , RPC_C_AUTHZ_DEFAULT , NULL , RPC_C_AUTHN_LEVEL_PKT_PRIVACY/*RPC_C_AUTHN_LEVEL_DEFAULT */, RPC_C_IMP_LEVEL_IMPERSONATE , NULL , EOAC_NONE )); // // Get the SID corresponding to the UserName and DomainName // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SecurityDescriptor::NormalizePrincipalToStringSID( bstrUserName, bstrDomainName, strSID )); // // Get the Expert SID and then get the username and domain name corresponding to the SID. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetCallerPrincipal ( /*fImpersonate*/true, bstrExpert )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SecurityDescriptor::ConvertPrincipalToSID( bstrExpert, pExpertSid )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SecurityDescriptor::ConvertSIDToPrincipal( pExpertSid, &szExpertUserName, &szExpertDomainName )); // Update the user Help Blob before invoking the RemoteCreateHelpSession() // The UserHelpBlob should have the following format. // Updated UserHelpBlob = string1 + string2 + original UserHelpBlob. // string1 = "13;UNSOLICITED=1" // string2 = #ofchars in expert identity;ID=expertDomainName\expertName local_PackString( bstrString1, L"UNSOLICITED=1" ); bstrString2 = L"ID="; bstrString2.Append( szExpertDomainName ); bstrString2.Append( L"\\" ); bstrString2.Append( szExpertUserName ); local_PackString( bstrString1, bstrString2 ); bstrString1.Append( bstrUserHelpBlob ); //Use Salem API to get the Connection Parameters. { // Fix for Bug 252092. static const REMOTE_DESKTOP_SHARING_CLASS c_sharingClass = VIEWDESKTOP_PERMISSION_NOT_REQUIRE; static const LONG c_lTimeOut = 301; // 5 mins. Timeout after which resolver kills helpctr if // no response from user (300 seconds) CComBSTR bstrSID( strSID.c_str() ); __MPC_EXIT_IF_METHOD_FAILS(hr, pRDHelpSessionMgr->RemoteCreateHelpSession( c_sharingClass, c_lTimeOut, lSessionID, bstrSID, bstrString1, pbstrConnectionString )); } hr = S_OK; __HCP_FUNC_CLEANUP; MPC::SecurityDescriptor::ReleaseMemory( (void*&)pExpertSid ); MPC::SecurityDescriptor::ReleaseMemory( (void*&)szExpertUserName ); MPC::SecurityDescriptor::ReleaseMemory( (void*&)szExpertDomainName ); __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHService::RemoteUserSessionInfo( /*[out]*/ IPCHCollection* *ppSessions ) { __HCP_FUNC_ENTRY( "CPCHService::RemoteUserSessionInfo" ); HRESULT hr; CComPtr pColl; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(ppSessions,NULL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, local_CheckAccessRights()); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl )); // Transfer the SessionInfoTable to the IPCHCollection. __MPC_EXIT_IF_METHOD_FAILS(hr, CSAFRemoteConnectionData::Populate( pColl )); __MPC_EXIT_IF_METHOD_FAILS(hr, pColl.QueryInterface( ppSessions )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// CPCHRemoteHelpContents::CPCHRemoteHelpContents() { // Taxonomy::Instance m_data; // Taxonomy::Settings m_ts; // MPC::wstring m_strDir; // // Taxonomy::Updater m_updater; // JetBlue::SessionHandle m_handle; m_db = NULL; // JetBlue::Database* m_db; } CPCHRemoteHelpContents::~CPCHRemoteHelpContents() { DetachFromDatabase(); } HRESULT CPCHRemoteHelpContents::AttachToDatabase() { __HCP_FUNC_ENTRY( "CPCHRemoteHelpContents::AttachToDatabase" ); HRESULT hr; if(m_db == NULL) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_ts.GetDatabase( m_handle, m_db, /*fReadOnly*/true )); __MPC_EXIT_IF_METHOD_FAILS(hr, m_updater.Init( m_ts, m_db )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } void CPCHRemoteHelpContents::DetachFromDatabase() { (void)m_updater.Close(); m_handle.Release(); m_db = NULL; } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHRemoteHelpContents::Init( /*[in]*/ const Taxonomy::Instance& data ) { __HCP_FUNC_ENTRY( "CPCHRemoteHelpContents::Init" ); HRESULT hr; m_data = data; m_ts = data.m_ths; m_strDir = m_data.m_strHelpFiles; m_strDir += L"\\"; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( m_strDir )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHRemoteHelpContents::get_SKU( /*[out, retval]*/ BSTR *pVal ) { __HCP_BEGIN_PROPERTY_GET("CPCHRemoteHelpContents::get_SKU",hr,pVal); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetBSTR( m_data.m_ths.GetSKU(), pVal )); __HCP_END_PROPERTY(hr); } STDMETHODIMP CPCHRemoteHelpContents::get_Language( /*[out, retval]*/ long *pVal ) { __HCP_BEGIN_PROPERTY_GET2("CPCHRemoteHelpContents::get_Language",hr,pVal,m_data.m_ths.GetLanguage()); __HCP_END_PROPERTY(hr); } STDMETHODIMP CPCHRemoteHelpContents::get_ListOfFiles( /*[out, retval]*/ VARIANT *pVal ) { __HCP_FUNC_ENTRY( "CPCHRemoteHelpContents::get_ListOfFiles" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); MPC::WStringList lstFiles; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(pVal); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, AttachToDatabase()); __MPC_EXIT_IF_METHOD_FAILS(hr, m_updater.ListAllTheHelpFiles( lstFiles )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::ConvertListToSafeArray( lstFiles, *pVal, VT_BSTR )); hr = S_OK; __HCP_FUNC_CLEANUP; DetachFromDatabase(); __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHRemoteHelpContents::GetDatabase( /*[out, retval]*/ IUnknown* *pVal ) { __HCP_FUNC_ENTRY( "CPCHRemoteHelpContents::GetDatabase" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); CComPtr stream; MPC::wstring strDataArchive; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END(); { Taxonomy::LockingHandle handle; Taxonomy::InstalledInstanceIter it; bool fFound; __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->GrabControl( handle )); __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::InstalledInstanceStore::s_GLOBAL->SKU_Find ( m_ts, fFound, it )); if(!fFound) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); } __MPC_EXIT_IF_METHOD_FAILS(hr, it->m_inst.GetFileName( strDataArchive )); } __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::OpenStreamForRead( strDataArchive.c_str(), &stream )); *pVal = stream.Detach(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHRemoteHelpContents::GetFile( /*[in]*/ BSTR bstrFileName, /*[out, retval]*/ IUnknown* *pVal ) { __HCP_FUNC_ENTRY( "CPCHRemoteHelpContents::GetFile" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); MPC::wstring strHelpFile; CComPtr stream; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrFileName); __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); __MPC_PARAMCHECK_END(); // // .. not allowed, for security reasons. // if(wcsstr( bstrFileName, L".." )) { __MPC_SET_ERROR_AND_EXIT(hr, E_ACCESSDENIED); } strHelpFile = m_strDir; strHelpFile += bstrFileName; __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::OpenStreamForRead( strHelpFile.c_str(), &stream )); *pVal = stream.Detach(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); }