This commit is contained in:
locka%iol.ie 2002-12-09 21:04:22 +00:00
Родитель c7d9f92951
Коммит 1657fa34f3
14 изменённых файлов: 1309 добавлений и 412 удалений

Просмотреть файл

@ -45,13 +45,136 @@
std::list<CControlSite *> CControlSite::m_cControlList;
class CDefaultControlSiteSecurityPolicy : public CControlSiteSecurityPolicy
{
// Test if the specified class id implements the specified category
BOOL ClassImplementsCategory(const CLSID & clsid, const CATID &catid, BOOL &bClassExists);
public:
// Test if the class is safe to host
virtual BOOL IsClassSafeToHost(const CLSID & clsid);
// Test if the specified class is marked safe for scripting
virtual BOOL IsClassMarkedSafeForScripting(const CLSID & clsid, BOOL &bClassExists);
// Test if the instantiated object is safe for scripting on the specified interface
virtual BOOL IsObjectSafeForScripting(IUnknown *pObject, const IID &iid);
};
BOOL
CDefaultControlSiteSecurityPolicy::ClassImplementsCategory(const CLSID &clsid, const CATID &catid, BOOL &bClassExists)
{
bClassExists = FALSE;
// Test if there is a CLSID entry. If there isn't then obviously
// the object doesn't exist and therefore doesn't implement any category.
// In this situation, the function returns REGDB_E_CLASSNOTREG.
CRegKey key;
if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS)
{
// Must fail if we can't even open this!
return FALSE;
}
LPOLESTR szCLSID = NULL;
if (FAILED(StringFromCLSID(clsid, &szCLSID)))
{
return FALSE;
}
USES_CONVERSION;
CRegKey keyCLSID;
LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ);
CoTaskMemFree(szCLSID);
if (lResult != ERROR_SUCCESS)
{
// Class doesn't exist
return FALSE;
}
keyCLSID.Close();
// CLSID exists, so try checking what categories it implements
bClassExists = TRUE;
CIPtr(ICatInformation) spCatInfo;
HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, (LPVOID*) &spCatInfo);
if (spCatInfo == NULL)
{
// Must fail if we can't open the category manager
return FALSE;
}
// See what categories the class implements
CIPtr(IEnumCATID) spEnumCATID;
if (FAILED(spCatInfo->EnumImplCategoriesOfClass(clsid, &spEnumCATID)))
{
// Can't enumerate classes in category so fail
return FALSE;
}
// Search for matching categories
BOOL bFound = FALSE;
CATID catidNext = GUID_NULL;
while (spEnumCATID->Next(1, &catidNext, NULL) == S_OK)
{
if (::IsEqualCATID(catid, catidNext))
{
return TRUE;
}
}
return FALSE;
}
// Test if the class is safe to host
BOOL CDefaultControlSiteSecurityPolicy::IsClassSafeToHost(const CLSID & clsid)
{
return TRUE;
}
// Test if the specified class is marked safe for scripting
BOOL CDefaultControlSiteSecurityPolicy::IsClassMarkedSafeForScripting(const CLSID & clsid, BOOL &bClassExists)
{
// Test the category the object belongs to
return ClassImplementsCategory(clsid, CATID_SafeForScripting, bClassExists);
}
// Test if the instantiated object is safe for scripting on the specified interface
BOOL CDefaultControlSiteSecurityPolicy::IsObjectSafeForScripting(IUnknown *pObject, const IID &iid)
{
if (!pObject) {
return FALSE;
}
// Ask the control if its safe for scripting
CComQIPtr<IObjectSafety> spObjectSafety = pObject;
if (!spObjectSafety)
{
return FALSE;
}
DWORD dwSupported = 0; // Supported options (mask)
DWORD dwEnabled = 0; // Enabled options
// Assume scripting via IDispatch
if (FAILED(spObjectSafety->GetInterfaceSafetyOptions(
iid, &dwSupported, &dwEnabled)))
{
// Interface is not safe or failure.
return FALSE;
}
// Test if safe for scripting
if (!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
{
return FALSE;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// Constructor
CControlSite::CControlSite()
{
NG_TRACE_METHOD(CControlSite::CControlSite);
m_hWndParent = NULL;
m_clsid = CLSID_NULL;
m_CLSID = CLSID_NULL;
m_bSetClientSiteFirst = FALSE;
m_bVisibleAtRuntime = TRUE;
memset(&m_rcObjectPos, 0, sizeof(m_rcObjectPos));
@ -62,6 +185,8 @@ CControlSite::CControlSite()
m_bWindowless = FALSE;
m_bSupportWindowlessActivation = TRUE;
m_bSafeForScriptingObjectsOnly = FALSE;
m_pDefaultSecurityPolicy = new CDefaultControlSiteSecurityPolicy;
m_pSecurityPolicy = m_pDefaultSecurityPolicy;
// Initialise ambient properties
m_nAmbientLocale = 0;
@ -89,80 +214,11 @@ CControlSite::~CControlSite()
NG_TRACE_METHOD(CControlSite::~CControlSite);
Detach();
m_cControlList.remove(this);
if (m_pDefaultSecurityPolicy)
delete m_pDefaultSecurityPolicy;
}
// Helper method checks whether a class implements a particular category
HRESULT CControlSite::ClassImplementsCategory(const CLSID &clsid, const CATID &catid)
{
// Test if there is a CLSID entry. If there isn't then obviously
// the object doesn't exist and therefore doesn't implement any category.
// In this situation, the function returns REGDB_E_CLASSNOTREG.
CRegKey key;
if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS)
{
// Must fail if we can't even open this!
return E_FAIL;
}
LPOLESTR szCLSID = NULL;
if (FAILED(StringFromCLSID(clsid, &szCLSID)))
{
return E_FAIL;
}
USES_CONVERSION;
CRegKey keyCLSID;
LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ);
CoTaskMemFree(szCLSID);
if (lResult != ERROR_SUCCESS)
{
// Class doesn't exist
return REGDB_E_CLASSNOTREG;
}
keyCLSID.Close();
// CLSID exists, so try checking what categories it implements
CIPtr(ICatInformation) spCatInfo;
HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, (LPVOID*) &spCatInfo);
if (spCatInfo == NULL)
{
// Must fail if we can't open the category manager
return E_FAIL;
}
// See what categories the class implements
CIPtr(IEnumCATID) spEnumCATID;
if (FAILED(spCatInfo->EnumImplCategoriesOfClass(clsid, &spEnumCATID)))
{
// Can't enumerate classes in category so fail
return E_FAIL;
}
// Search for matching categories
BOOL bFound = FALSE;
CATID catidNext = GUID_NULL;
while (spEnumCATID->Next(1, &catidNext, NULL) == S_OK)
{
if (::IsEqualCATID(catid, catidNext))
{
bFound = TRUE;
}
}
if (!bFound)
{
return S_FALSE;
}
return S_OK;
}
#if 0
// For use when the SDK does not define it (which isn't the case these days)
static const CATID CATID_SafeForScripting =
{ 0x7DD95801, 0x9882, 0x11CF, { 0x9F, 0xA9, 0x00, 0xAA, 0x00, 0x6C, 0x42, 0xC4 } };
#endif
// Create the specified control, optionally providing properties to initialise
// it with and a name.
HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl,
@ -170,19 +226,26 @@ HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl,
{
NG_TRACE_METHOD(CControlSite::Create);
m_clsid = clsid;
m_CLSID = clsid;
m_ParameterList = pl;
// See if security policy will allow the control to be hosted
if (m_pSecurityPolicy && !m_pSecurityPolicy->IsClassSafeToHost(clsid))
{
return E_FAIL;
}
// See if object is script safe
BOOL checkForObjectSafety = FALSE;
if (m_bSafeForScriptingObjectsOnly)
if (m_pSecurityPolicy && m_bSafeForScriptingObjectsOnly)
{
HRESULT hrClass = ClassImplementsCategory(clsid, CATID_SafeForScripting);
if (hrClass == REGDB_E_CLASSNOTREG && szCodebase)
BOOL bClassExists = FALSE;
BOOL bIsSafe = m_pSecurityPolicy->IsClassMarkedSafeForScripting(clsid, bClassExists);
if (!bClassExists && szCodebase)
{
// Class doesn't exist, so allow code below to fetch it
}
else if (FAILED(hrClass))
else if (!bIsSafe)
{
// The class is not flagged as safe for scripting, so
// we'll have to create it to ask it if its safe.
@ -195,26 +258,8 @@ HRESULT CControlSite::Create(REFCLSID clsid, PropertyList &pl,
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (void **) &spObject);
if (SUCCEEDED(hr) && checkForObjectSafety)
{
// The control was created but it didn't check out as safe so
// it must be asked if its safe for scripting.
CComQIPtr<IObjectSafety> spObjectSafety = spObject;
if (!spObjectSafety)
{
return E_FAIL;
}
DWORD dwSupported = 0; // Supported options (mask)
DWORD dwEnabled = 0; // Enabled options
// Assume scripting via IDispatch
if (FAILED(spObjectSafety->GetInterfaceSafetyOptions(
__uuidof(IDispatch), &dwSupported, &dwEnabled)))
{
// Interface is not safe or failure.
return E_FAIL;
}
// Test if safe for scripting
if (!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
if (!m_pSecurityPolicy->IsObjectSafeForScripting(spObject, __uuidof(IDispatch)))
{
return E_FAIL;
}
@ -596,6 +641,37 @@ void CControlSite::SetAmbientUserMode(BOOL bUserMode)
}
}
///////////////////////////////////////////////////////////////////////////////
// CControlSiteSecurityPolicy implementation
// Test if the class is safe to host
BOOL CControlSite::IsClassSafeToHost(const CLSID & clsid)
{
if (m_pSecurityPolicy)
return m_pSecurityPolicy->IsClassSafeToHost(clsid);
return TRUE;
}
// Test if the specified class is marked safe for scripting
BOOL CControlSite::IsClassMarkedSafeForScripting(const CLSID & clsid, BOOL &bClassExists)
{
if (m_pSecurityPolicy)
return m_pSecurityPolicy->IsClassMarkedSafeForScripting(clsid, bClassExists);
return TRUE;
}
// Test if the instantiated object is safe for scripting on the specified interface
BOOL CControlSite::IsObjectSafeForScripting(IUnknown *pObject, const IID &iid)
{
if (m_pSecurityPolicy)
return m_pSecurityPolicy->IsObjectSafeForScripting(pObject, iid);
return TRUE;
}
BOOL CControlSite::IsObjectSafeForScripting(const IID &iid)
{
return IsObjectSafeForScripting(m_spObject, iid);
}
///////////////////////////////////////////////////////////////////////////////
// IServiceProvider implementation

Просмотреть файл

@ -61,6 +61,21 @@
COM_INTERFACE_ENTRY(IBindStatusCallback) \
COM_INTERFACE_ENTRY(IWindowForBindingUI)
// Class that defines the control's security policy with regards to
// what controls it hosts etc.
class CControlSiteSecurityPolicy
{
public:
// Test if the class is safe to host
virtual BOOL IsClassSafeToHost(const CLSID & clsid) = 0;
// Test if the specified class is marked safe for scripting
virtual BOOL IsClassMarkedSafeForScripting(const CLSID & clsid, BOOL &bClassExists) = 0;
// Test if the instantiated object is safe for scripting on the specified interface
virtual BOOL IsObjectSafeForScripting(IUnknown *pObject, const IID &iid) = 0;
};
//
// Class for hosting an ActiveX control
//
@ -85,6 +100,7 @@
// pSite = NULL;
class CControlSite : public CComObjectRootEx<CComSingleThreadModel>,
public CControlSiteSecurityPolicy,
public IOleClientSite,
public IOleInPlaceSiteWindowless,
public IOleControlSite,
@ -135,9 +151,13 @@ protected:
// Pointer to object's IOleInPlaceObjectWindowless interface
CComQIPtr<IOleInPlaceObjectWindowless, &IID_IOleInPlaceObjectWindowless> m_spIOleInPlaceObjectWindowless;
// CLSID of the control
CLSID m_clsid;
CLSID m_CLSID;
// Parameter list
PropertyList m_ParameterList;
// Default security policy
CControlSiteSecurityPolicy *m_pDefaultSecurityPolicy;
// Pointer to the security policy
CControlSiteSecurityPolicy *m_pSecurityPolicy;
// Binding variables
// Flag indicating whether binding is in progress
@ -196,9 +216,6 @@ END_OLECOMMAND_TABLE()
// List of controls
static std::list<CControlSite *> m_cControlList;
// Helper method
static HRESULT ClassImplementsCategory(const CLSID &clsid, const CATID &catid);
// Returns the window used when processing ole commands
HWND GetCommandTargetWindow()
{
@ -234,6 +251,16 @@ END_OLECOMMAND_TABLE()
{
m_spContainer = pContainer;
}
// Set the security policy object. Ownership of this object remains with the caller and the security
// policy object is meant to exist for as long as it is set here.
virtual void SetSecurityPolicy(CControlSiteSecurityPolicy *pSecurityPolicy)
{
m_pSecurityPolicy = pSecurityPolicy;
}
virtual CControlSiteSecurityPolicy *GetSecurityPolicy() const
{
return m_pSecurityPolicy;
}
// Methods to set ambient properties
virtual void SetAmbientUserMode(BOOL bUser);
@ -242,7 +269,7 @@ END_OLECOMMAND_TABLE()
// Returns the object's CLSID
virtual const CLSID &GetObjectCLSID() const
{
return m_clsid;
return m_CLSID;
}
// Tests if the object is valid or not
virtual BOOL IsObjectValid() const
@ -260,6 +287,16 @@ END_OLECOMMAND_TABLE()
return m_bInPlaceActive;
}
// CControlSiteSecurityPolicy
// Test if the class is safe to host
virtual BOOL IsClassSafeToHost(const CLSID & clsid);
// Test if the specified class is marked safe for scripting
virtual BOOL IsClassMarkedSafeForScripting(const CLSID & clsid, BOOL &bClassExists);
// Test if the instantiated object is safe for scripting on the specified interface
virtual BOOL IsObjectSafeForScripting(IUnknown *pObject, const IID &iid);
// Test if the instantiated object is safe for scripting on the specified interface
virtual BOOL IsObjectSafeForScripting(const IID &iid);
// IServiceProvider
virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void** ppv);

Просмотреть файл

@ -56,21 +56,20 @@
///////////////////////////////////////////////////////////////////////////////
// These are constants to control certain behaviours
// These are constants to control certain default behaviours
// Flag determines if only controls marked safe for scripting will be instantiated
const BOOL kSafeForScriptingControlsOnly = FALSE;
#ifndef MOZ_ACTIVEX_PLUGIN_XPCONNECT
// Flag determines if controls should be created if they are not marked
// safe for scripting.
const BOOL kHostSafeControlsOnly = FALSE;
// Flag determines if controls should be downloaded and installed if there is a
// codebase specified
const BOOL kDownloadControlsIfMissing = TRUE;
const BOOL kDownloadControlsIfMissing = FALSE;
#endif
// Flag determines whether the plugin will complain to the user if a page
// contains a control it cannot load
const BOOL kDisplayErrorMessages = FALSE;
// Registry keys containing lists of controls that the plugin explicitly does
// or does not support.
const TCHAR *kControlsToAllowKey = _T("Software\\Mozilla\\ActiveX\\Whitelist\\CLSID");
const TCHAR *kControlsToDenyKey = _T("Software\\Mozilla\\ActiveX\\Blacklist\\CLSID");
///////////////////////////////////////////////////////////////////////////////
// CInstallControlProgress
@ -256,24 +255,90 @@ jref NPP_GetJavaClass(void)
#define MIME_OLEOBJECT2 "application/oleobject"
#define MIME_ACTIVESCRIPT "text/x-activescript"
NPError NewScript(const char *pluginType,
PluginInstanceData *pData,
uint16 mode,
int16 argc,
char *argn[],
char *argv[])
enum MozAxPluginErrors
{
MozAxErrorActiveScriptNotSupported,
MozAxErrorControlIsNotSafeForScripting,
MozAxErrorCouldNotCreateControl,
};
static void
ShowError(MozAxPluginErrors errorCode, const CLSID &clsid)
{
if (!kDisplayErrorMessages)
return;
const TCHAR *szMsg = NULL;
const unsigned long kBufSize = 256;
TCHAR szBuffer[kBufSize];
// TODO errors are hardcoded for now
switch (errorCode)
{
case MozAxErrorActiveScriptNotSupported:
szMsg = _T("ActiveScript not supported yet!");
break;
case MozAxErrorControlIsNotSafeForScripting:
{
USES_CONVERSION;
LPOLESTR szClsid;
StringFromCLSID(clsid, &szClsid);
_sntprintf(szBuffer, kBufSize - 1,
_T("Could not create the control %s because it is not marked safe for scripting."), OLE2T(szClsid));
CoTaskMemFree(szClsid);
szMsg = szBuffer;
}
break;
case MozAxErrorCouldNotCreateControl:
{
USES_CONVERSION;
LPOLESTR szClsid;
StringFromCLSID(clsid, &szClsid);
_sntprintf(szBuffer, kBufSize - 1,
_T("Could not create the control %s. Check that it has been installed on your computer "
"and that this page correctly references it."), OLE2T(szClsid));
CoTaskMemFree(szClsid);
szMsg = szBuffer;
}
break;
}
szBuffer[kBufSize - 1] = TCHAR('\0');
if (szMsg)
MessageBox(NULL, szMsg, _T("ActiveX Error"), MB_OK | MB_ICONWARNING);
}
static NPError
NewScript(const char *pluginType,
PluginInstanceData *pData,
uint16 mode,
int16 argc,
char *argn[],
char *argv[])
{
CActiveScriptSiteInstance *pScriptSite = NULL;
CActiveScriptSiteInstance::CreateInstance(&pScriptSite);
// TODO support ActiveScript
if (kDisplayErrorMessages)
MessageBox(NULL, _T("ActiveScript not supported yet!"), NULL, MB_OK);
ShowError(MozAxErrorActiveScriptNotSupported, CLSID_NULL);
return NPERR_GENERIC_ERROR;
}
static BOOL WillHandleCLSID(const CLSID &clsid)
static BOOL
WillHandleCLSID(const CLSID &clsid)
{
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
// Ensure the control is safe for scripting
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
if (!dispSupport)
return FALSE;
nsCID cid;
memcpy(&cid, &clsid, sizeof(nsCID));
PRBool isSafe = PR_FALSE;
PRBool classExists = PR_FALSE;
dispSupport->IsClassSafeToHost(cid, &isSafe, &classExists);
if (classExists && !isSafe)
return FALSE;
return TRUE;
#else
if (::IsEqualCLSID(clsid, CLSID_NULL))
{
return FALSE;
@ -363,14 +428,225 @@ static BOOL WillHandleCLSID(const CLSID &clsid)
}
return TRUE;
#endif
}
NPError NewControl(const char *pluginType,
PluginInstanceData *pData,
uint16 mode,
int16 argc,
char *argn[],
char *argv[])
static NPError
CreateControl(const CLSID &clsid, PluginInstanceData *pData, PropertyList &pl, LPCOLESTR szCodebase)
{
// Make sure we got a CLSID we can handle
if (!WillHandleCLSID(clsid))
{
return NPERR_GENERIC_ERROR;
}
pData->clsid = clsid;
// Set flags to specify if it is allowed to host safe or unsafe controls
// and download them.
PRBool hostSafeControlsOnly;
PRBool downloadControlsIfMissing;
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_SAFE_OBJECTS &&
!(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS))
{
hostSafeControlsOnly = TRUE;
}
else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS)
{
hostSafeControlsOnly = FALSE;
}
else
{
// Plugin can host neither safe nor unsafe controls, so just return
// without creating anything.
return NPERR_GENERIC_ERROR;
}
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_DOWNLOAD_CONTROLS)
{
downloadControlsIfMissing = PR_TRUE;
}
else
{
downloadControlsIfMissing = PR_FALSE;
}
// Ensure we can obtain the nsIDispatchSupport service
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
if (!dispSupport)
{
return NPERR_GENERIC_ERROR;
}
// Now test if the CLSID is safe for scripting
PRBool classIsMarkedSafeForScripting = PR_FALSE;
if (hostSafeControlsOnly)
{
PRBool classExists = PR_FALSE;
PRBool isClassSafeForScripting = PR_FALSE;
nsCID cid;
memcpy(&cid, &clsid, sizeof(cid));
if (NS_SUCCEEDED(dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isClassSafeForScripting)) &&
classExists && isClassSafeForScripting)
{
classIsMarkedSafeForScripting = PR_TRUE;
}
}
#else
hostSafeControlsOnly = kHostSafeControlsOnly;
downloadControlsIfMissing = kDownloadControlsIfMissing;
#endif
// Create the control site
CControlSiteInstance *pSite = NULL;
CControlSiteInstance::CreateInstance(&pSite);
if (pSite == NULL)
{
return NPERR_GENERIC_ERROR;
}
pSite->m_bSupportWindowlessActivation = FALSE;
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
// We handle our own security further down
pSite->SetSecurityPolicy(NULL);
pSite->m_bSafeForScriptingObjectsOnly = FALSE;
#else
pSite->m_bSafeForScriptingObjectsOnly = hostSafeControlsOnly;
#endif
pSite->AddRef();
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
// Set up the service provider and container so the control can get hold
// of the IE DOM and other interfaces
CComPtr<IServiceProvider> sp;
MozAxPlugin::GetServiceProvider(pData, &sp);
if (sp)
pSite->SetServiceProvider(sp);
CComQIPtr<IOleContainer> container = sp;
if (container)
pSite->SetContainer(container);
#endif
// TODO check the object is installed and at least as recent as
// that specified in szCodebase
// Create the object
HRESULT hr;
if (!downloadControlsIfMissing || !szCodebase)
{
hr = pSite->Create(clsid, pl);
}
else if (szCodebase)
{
CComObject<CInstallControlProgress> *pProgress = NULL;
CComPtr<IBindCtx> spBindCtx;
CComPtr<IBindStatusCallback> spOldBSC;
CComObject<CInstallControlProgress>::CreateInstance(&pProgress);
pProgress->AddRef();
CreateBindCtx(0, &spBindCtx);
RegisterBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress), &spOldBSC, 0);
hr = pSite->Create(clsid, pl, szCodebase, spBindCtx);
if (hr == MK_S_ASYNCHRONOUS)
{
pProgress->mNPP = pData->pPluginInstance;
pProgress->mBindingInProgress = TRUE;
pProgress->mResult = E_FAIL;
// Spin around waiting for binding to complete
HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
while (pProgress->mBindingInProgress)
{
MSG msg;
// Process pending messages
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!::GetMessage(&msg, NULL, 0, 0))
{
pProgress->mBindingInProgress = FALSE;
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if (!pProgress->mBindingInProgress)
break;
// Sleep for a bit or the next msg to appear
::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS);
}
::CloseHandle(hFakeEvent);
hr = pProgress->mResult;
if (SUCCEEDED(hr))
{
hr = pSite->Create(clsid, pl);
}
}
if (pProgress)
{
RevokeBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress));
pProgress->Release();
}
}
if (FAILED(hr))
{
ShowError(MozAxErrorCouldNotCreateControl, clsid);
}
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
if (SUCCEEDED(hr) && hostSafeControlsOnly && !classIsMarkedSafeForScripting)
{
CComPtr<IUnknown> cpUnk;
pSite->GetControlUnknown(&cpUnk);
nsIID iidDispatch;
memcpy(&iidDispatch, &__uuidof(IDispatch), sizeof(nsIID));
PRBool isObjectSafe = PR_FALSE;
if (!cpUnk ||
NS_FAILED(dispSupport->IsObjectSafeForScripting(
reinterpret_cast<void *>(cpUnk.p), iidDispatch, &isObjectSafe)) ||
!isObjectSafe)
{
pSite->Detach();
hr = E_FAIL;
ShowError(MozAxErrorControlIsNotSafeForScripting, clsid);
// DROP THROUGH
}
}
#endif
// Clean up if the control could not be created
if (FAILED(hr))
{
pSite->Release();
return NPERR_GENERIC_ERROR;
}
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
// Hook up the event sink
nsEventSinkInstance *pSink = NULL;
nsEventSinkInstance::CreateInstance(&pSink);
if (pSink)
{
pSink->AddRef();
pSink->mPlugin = pData;
CComPtr<IUnknown> control;
pSite->GetControlUnknown(&control);
pSink->SubscribeToEvents(control);
}
pData->pControlEventSink = pSink;
#endif
pData->nType = itControl;
pData->pControlSite = pSite;
return NPERR_NO_ERROR;
}
static NPError
NewControl(const char *pluginType,
PluginInstanceData *pData,
uint16 mode,
int16 argc,
char *argn[],
char *argv[])
{
// Read the parameters
CLSID clsid = CLSID_NULL;
@ -380,7 +656,7 @@ NPError NewControl(const char *pluginType,
if (strcmp(pluginType, MIME_OLEOBJECT1) != 0 &&
strcmp(pluginType, MIME_OLEOBJECT2) != 0)
{
clsid = xpc_GetCLSIDForType(pluginType);
clsid = MozAxPlugin::GetCLSIDForType(pluginType);
}
for (int16 i = 0; i < argc; i++)
@ -490,129 +766,7 @@ NPError NewControl(const char *pluginType,
}
}
// Make sure we got a CLSID we can handle
if (!WillHandleCLSID(clsid))
{
return NPERR_GENERIC_ERROR;
}
pData->clsid = clsid;
// Create the control site
CControlSiteInstance *pSite = NULL;
CControlSiteInstance::CreateInstance(&pSite);
if (pSite == NULL)
{
return NPERR_GENERIC_ERROR;
}
pSite->m_bSafeForScriptingObjectsOnly = kSafeForScriptingControlsOnly;
pSite->m_bSupportWindowlessActivation = FALSE;
pSite->AddRef();
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
CComPtr<IServiceProvider> sp;
xpc_GetServiceProvider(pData, &sp);
if (sp)
pSite->SetServiceProvider(sp);
CComQIPtr<IOleContainer> container = sp;
if (container)
pSite->SetContainer(container);
#endif
// TODO check the object is installed and at least as recent as
// that specified in szCodebase
// Create the object
HRESULT hr;
if (!kDownloadControlsIfMissing || !codebase.m_str)
{
hr = pSite->Create(clsid, pl);
}
else if (codebase.m_str)
{
CComObject<CInstallControlProgress> *pProgress = NULL;
CComPtr<IBindCtx> spBindCtx;
CComPtr<IBindStatusCallback> spOldBSC;
CComObject<CInstallControlProgress>::CreateInstance(&pProgress);
pProgress->AddRef();
CreateBindCtx(0, &spBindCtx);
RegisterBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress), &spOldBSC, 0);
hr = pSite->Create(clsid, pl, codebase, spBindCtx);
if (hr == MK_S_ASYNCHRONOUS)
{
pProgress->mNPP = pData->pPluginInstance;
pProgress->mBindingInProgress = TRUE;
pProgress->mResult = E_FAIL;
// Spin around waiting for binding to complete
HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
while (pProgress->mBindingInProgress)
{
MSG msg;
// Process pending messages
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!::GetMessage(&msg, NULL, 0, 0))
{
pProgress->mBindingInProgress = FALSE;
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if (!pProgress->mBindingInProgress)
break;
// Sleep for a bit or the next msg to appear
::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS);
}
::CloseHandle(hFakeEvent);
hr = pProgress->mResult;
if (SUCCEEDED(hr))
{
hr = pSite->Create(clsid, pl);
}
}
if (pProgress)
{
RevokeBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress));
pProgress->Release();
}
}
if (FAILED(hr))
{
if (kDisplayErrorMessages)
{
USES_CONVERSION;
LPOLESTR szClsid;
StringFromCLSID(clsid, &szClsid);
TCHAR szBuffer[256];
_stprintf(szBuffer, _T("Could not create the control %s. Check that it has been installed on your computer and that this page correctly references it."), OLE2T(szClsid));
MessageBox(NULL, szBuffer, _T("ActiveX Error"), MB_OK | MB_ICONWARNING);
CoTaskMemFree(szClsid);
}
pSite->Release();
return NPERR_GENERIC_ERROR;
}
#ifdef XPC_IDISPATCH_SUPPORT
nsEventSinkInstance *pSink = NULL;
nsEventSinkInstance::CreateInstance(&pSink);
if (pSink)
{
pSink->AddRef();
pSink->mPlugin = pData;
CComPtr<IUnknown> control;
pSite->GetControlUnknown(&control);
pSink->SubscribeToEvents(control);
}
pData->pControlEventSink = pSink;
#endif
pData->nType = itControl;
pData->pControlSite = pSite;
return NPERR_NO_ERROR;
return CreateControl(clsid, pData, pl, codebase.m_str);
}
@ -651,7 +805,7 @@ NPError NP_LOADDS NPP_New(NPMIMEType pluginType,
// Create a plugin according to the mime type
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
xpc_AddRef();
MozAxPlugin::AddRef();
#endif
NPError rv = NPERR_GENERIC_ERROR;
@ -674,7 +828,7 @@ NPError NP_LOADDS NPP_New(NPMIMEType pluginType,
free(pData->szUrl);
delete pData;
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
xpc_Release();
MozAxPlugin::Release();
#endif
return rv;
}
@ -709,7 +863,7 @@ NPP_Destroy(NPP instance, NPSavedData** save)
pSite->Detach();
pSite->Release();
}
#ifdef XPC_IDISPATCH_SUPPORT
#if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
if (pData->pControlEventSink)
{
pData->pControlEventSink->UnsubscribeFromEvents();
@ -734,7 +888,7 @@ NPP_Destroy(NPP instance, NPSavedData** save)
free(pData->szContentType);
delete pData;
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
xpc_Release();
MozAxPlugin::Release();
#endif
instance->pdata = 0;
@ -971,7 +1125,7 @@ NPP_GetValue(NPP instance, NPPVariable variable, void *value)
{
NPError rv = NPERR_GENERIC_ERROR;
#ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
rv = xpc_GetValue(instance, variable, value);
rv = MozAxPlugin::GetValue(instance, variable, value);
#endif
return rv;
}

Просмотреть файл

@ -119,7 +119,6 @@ CPPSRCS = \
StdAfx.cpp \
LegacyPlugin.cpp \
MozActiveX.cpp \
PrefObserver.cpp \
npwin.cpp \
$(_CONTROL_CPPSRCS) \
$(NULL)
@ -133,6 +132,10 @@ CPPSRCS += LiveConnect.cpp
CSRCS += javastubs.c
endif
ifdef XPC_IDISPATCH_SUPPORT
CPPSRCS += PrefObserver.cpp
endif
LOCAL_INCLUDES = -I$(MOZCTLSRC)
ifdef MOZ_ACTIVEX_PLUGIN_LIVECONNECT
@ -198,6 +201,9 @@ install-class: MozAxPlugin.class
install-typelib: $(XPIDL_GEN_DIR)/nsIMozAxPlugin.xpt
$(INSTALL) $< $(DIST)/bin/plugins
install-securitypolicy: nsAxSecurityPolicy.js
$(INSTALL) $< $(DIST)/bin/components
libs:: install-plugin
ifdef MOZ_ACTIVEX_PLUGIN_LIVECONNECT
@ -208,6 +214,10 @@ ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
libs:: install-typelib
endif
ifdef XPC_IDISPATCH_SUPPORT
libs:: install-securitypolicy
endif
## Note: Ensure you create the redist dir containing the correct runtime dlls
xpi:: install.js $(SHARED_LIBRARY)

Просмотреть файл

@ -44,10 +44,25 @@
#include "npapi.h"
#include "nsIServiceManagerUtils.h"
#include "nsISupportsUtils.h"
#include "nsWeakReference.h"
#include "nsIObserver.h"
#include "nsIPrefService.h"
#include "nsIPrefBranchInternal.h"
#include "nsWeakReference.h"
#include "nsIObserver.h"
#include "nsCRT.h"
#include "nsString.h"
#include "XPConnect.h"
// These are the default hosting flags in the absence of a pref.
const PRUint32 kDefaultHostingFlags =
#ifdef XPC_IDISPATCH_SUPPORT
nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
#else
nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_SAFE_OBJECTS |
nsIActiveXSecurityPolicy::HOSTING_FLAGS_DOWNLOAD_CONTROLS |
nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS;
#endif
class PrefObserver :
public nsSupportsWeakReference,
@ -55,23 +70,38 @@ class PrefObserver :
{
public:
PrefObserver();
protected:
virtual ~PrefObserver();
static PrefObserver *sPrefObserver;
void Sync(nsIPrefBranch *aPrefBranch);
PRUint32 mHostingFlags;
nsCOMPtr<nsIPrefService> mPrefService;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static nsresult Subscribe();
static nsresult Unsubscribe();
static PrefObserver *sPrefObserver;
nsresult Subscribe();
nsresult Unsubscribe();
PRUint32 GetHostingFlags() const;
};
const char *kActiveXHostingFlags = "security.xpconnect.activex.";
const char *kUserAgentPref = "general.useragent.";
const char *kProxyPref = "network.http.";
PrefObserver *PrefObserver::sPrefObserver = nsnull;
PrefObserver::PrefObserver()
PrefObserver::PrefObserver() :
mHostingFlags(kDefaultHostingFlags)
{
NS_INIT_ISUPPORTS();
nsresult rv = NS_OK;
mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ASSERTION(mPrefService, "where is the pref service?");
}
PrefObserver::~PrefObserver()
@ -89,38 +119,65 @@ NS_INTERFACE_MAP_END
/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
NS_IMETHODIMP PrefObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
{
if (nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic) != 0)
{
return S_OK;
}
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject, &rv);
if (NS_FAILED(rv))
return rv;
nsCAutoString pref = NS_ConvertUCS2toUTF8(aData);
if (nsCRT::strcmp(kActiveXHostingFlags, pref.get()) == 0 ||
nsCRT::strcmp(kUserAgentPref, pref.get()) == 0 ||
nsCRT::strcmp(kProxyPref, pref.get()) == 0)
{
Sync(prefBranch);
}
return NS_OK;
}
void PrefObserver::Sync(nsIPrefBranch *aPrefBranch)
{
NS_ASSERTION(aPrefBranch, "no pref branch");
if (!aPrefBranch)
{
return;
}
// TODO
// const char *userAgent = NPN_UserAgent(mData->pPluginInstance);
// ::UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, userAgent, strlen(userAgent), 0);
// TODO
// INTERNET_PROXY_INFO ipi;
// UrlMkSetSessionOption(INTERNET_OPTION_PROXY, ....);
return NS_OK;
// ::UrlMkSetSessionOption(INTERNET_OPTION_PROXY, ....);
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
if (!dispSupport)
mHostingFlags = kDefaultHostingFlags;
else
dispSupport->GetHostingFlags(nsnull, &mHostingFlags);
}
nsresult
PrefObserver::Subscribe()
{
if (sPrefObserver)
{
return NS_OK;
}
NS_ENSURE_TRUE(mPrefService, NS_ERROR_FAILURE);
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(mPrefService, &rv);
if (NS_FAILED(rv)) return rv;
sPrefObserver = new PrefObserver();
NS_ENSURE_TRUE(sPrefObserver, NS_ERROR_OUT_OF_MEMORY);
sPrefObserver->AddRef();
nsCOMPtr<nsIPrefBranchInternal> prefInternal = do_QueryInterface(prefBranch, &rv);
if (NS_FAILED(rv)) return rv;
nsresult rv = NS_OK;
nsCOMPtr<nsIPrefService> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
prefInternal->AddObserver(kProxyPref, this, PR_TRUE);
prefInternal->AddObserver(kUserAgentPref, this, PR_TRUE);
prefInternal->AddObserver(kActiveXHostingFlags, this, PR_TRUE);
nsCOMPtr<nsIPrefBranch> prefBranch;
prefService->GetBranch(nsnull, getter_AddRefs(prefBranch));
NS_ENSURE_TRUE(prefBranch, NS_ERROR_FAILURE);
nsCOMPtr<nsIPrefBranchInternal> pbi = do_QueryInterface(prefBranch);
NS_ENSURE_TRUE(pbi, NS_ERROR_FAILURE);
pbi->AddObserver("network.http.proxy.", sPrefObserver, PR_TRUE);
pbi->AddObserver("general.useragent.", sPrefObserver, PR_TRUE);
Sync(prefBranch);
return S_OK;
}
@ -128,10 +185,50 @@ PrefObserver::Subscribe()
nsresult
PrefObserver::Unsubscribe()
{
if (sPrefObserver)
{
sPrefObserver->Release();
sPrefObserver = nsnull;
}
NS_ENSURE_TRUE(mPrefService, NS_ERROR_FAILURE);
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(mPrefService, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPrefBranchInternal> prefInternal = do_QueryInterface(prefBranch, &rv);
if (NS_FAILED(rv)) return rv;
prefInternal->RemoveObserver(kProxyPref, this);
prefInternal->RemoveObserver(kUserAgentPref, this);
prefInternal->RemoveObserver(kActiveXHostingFlags, this);
return NS_OK;
}
PRUint32 PrefObserver::GetHostingFlags() const
{
return mHostingFlags;
}
///////////////////////////////////////////////////////////////////////////////
PRUint32 MozAxPlugin::PrefGetHostingFlags()
{
if (!PrefObserver::sPrefObserver)
{
PrefObserver::sPrefObserver = new PrefObserver();
if (!PrefObserver::sPrefObserver)
{
return nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
}
PrefObserver::sPrefObserver->AddRef();
PrefObserver::sPrefObserver->Subscribe();
}
return PrefObserver::sPrefObserver->GetHostingFlags();
}
void MozAxPlugin::ReleasePrefObserver()
{
if (PrefObserver::sPrefObserver)
{
PrefObserver::sPrefObserver->Unsubscribe();
PrefObserver::sPrefObserver->Release();
PrefObserver::sPrefObserver = nsnull;
}
}

Просмотреть файл

@ -734,7 +734,7 @@ public:
mBrowser(NULL),
mData(NULL)
{
xpc_AddRef();
MozAxPlugin::AddRef();
}
HRESULT Init(PluginInstanceData *pData)
@ -799,7 +799,7 @@ public:
{
mWindow->Release();
}
xpc_Release();
MozAxPlugin::Release();
}
BEGIN_COM_MAP(IEDocument)
@ -1703,7 +1703,7 @@ END_COM_MAP()
};
HRESULT xpc_GetServiceProvider(PluginInstanceData *pData, IServiceProvider **pSP)
HRESULT MozAxPlugin::GetServiceProvider(PluginInstanceData *pData, IServiceProvider **pSP)
{
// Note this should be called on the main NPAPI thread
CComObject<IEDocument> *pDoc = NULL;

Просмотреть файл

@ -64,9 +64,6 @@
#include "nsIScriptEventManager.h"
#include "jsapi.h"
#ifdef XPC_IDISPATCH_SUPPORT
#include "nsIDispatchSupport.h"
#endif
#include "LegacyPlugin.h"
#include "XPConnect.h"
@ -82,13 +79,13 @@ nsScriptablePeer::nsScriptablePeer() :
{
NS_INIT_ISUPPORTS();
NS_ASSERTION(mTearOff, "can't create tearoff");
xpc_AddRef();
MozAxPlugin::AddRef();
}
nsScriptablePeer::~nsScriptablePeer()
{
delete mTearOff;
xpc_Release();
MozAxPlugin::Release();
}
NS_IMPL_ADDREF(nsScriptablePeer)
@ -760,10 +757,6 @@ nsEventSink::InternalInvoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wF
nsDependentString eventName(bstrName.m_str);
nsresult rv;
nsCOMPtr<nsIDOMDocument> domdoc;
nsCOMPtr<nsIDOMNodeList> scriptElements;
// Fire the script event handler...
nsCOMPtr<nsIDOMWindow> window;
NPN_GetValue(mPlugin->pPluginInstance, NPNVDOMWindow, (void *)&window);
@ -920,20 +913,28 @@ HRESULT STDMETHODCALLTYPE nsScriptablePeerTearOff::Invoke(DISPID dispIdMember, R
static PRUint32 gInstances = 0;
void xpc_AddRef()
void MozAxPlugin::AddRef()
{
if (gInstances == 0)
XPCOMGlueStartup(nsnull);
{
XPCOMGlueStartup(nsnull);
MozAxPlugin::PrefGetHostingFlags(); // Initial call to set it up
}
gInstances++;
}
void xpc_Release()
void MozAxPlugin::Release()
{
if (--gInstances == 0)
XPCOMGlueShutdown();
{
#ifdef XPC_IDISPATCH_SUPPORT
MozAxPlugin::ReleasePrefObserver();
#endif
XPCOMGlueShutdown();
}
}
CLSID xpc_GetCLSIDForType(const char *mimeType)
CLSID MozAxPlugin::GetCLSIDForType(const char *mimeType)
{
if (mimeType == NULL)
{
@ -954,7 +955,7 @@ CLSID xpc_GetCLSIDForType(const char *mimeType)
ULONG nCount = (sizeof(szGUID) / sizeof(szGUID[0])) - 1;
GUID guidValue = GUID_NULL;
if (keyMimeType.QueryValue(_T("CLSID"), szGUID, &nCount) == ERROR_SUCCESS &&
if (keyMimeType.QueryValue(szGUID, _T("CLSID"), &nCount) == ERROR_SUCCESS &&
SUCCEEDED(::CLSIDFromString(T2OLE(szGUID), &guidValue)))
{
return guidValue;
@ -966,20 +967,16 @@ CLSID xpc_GetCLSIDForType(const char *mimeType)
nsScriptablePeer *
xpc_GetPeerForCLSID(const CLSID &clsid)
MozAxPlugin::GetPeerForCLSID(const CLSID &clsid)
{
#ifdef XPC_IDISPATCH_SUPPORT
return new nsScriptablePeer();
#else
return new nsScriptablePeer();
#endif
}
void
xpc_GetIIDForCLSID(const CLSID &clsid, nsIID &iid)
MozAxPlugin::GetIIDForCLSID(const CLSID &clsid, nsIID &iid)
{
#ifdef XPC_IDISPATCH_SUPPORT
memcpy(&iid, &_uuidof(IDispatch), sizeof(iid));
memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
#else
iid = NS_GET_IID(nsIMozAxPlugin);
#endif
@ -987,7 +984,7 @@ xpc_GetIIDForCLSID(const CLSID &clsid, nsIID &iid)
// Called by NPP_GetValue to provide the scripting values
NPError
xpc_GetValue(NPP instance, NPPVariable variable, void *value)
MozAxPlugin::GetValue(NPP instance, NPPVariable variable, void *value)
{
if (instance == NULL)
{
@ -1002,6 +999,55 @@ xpc_GetValue(NPP instance, NPPVariable variable, void *value)
return NPERR_GENERIC_ERROR;
}
// Test if the object is allowed to be scripted
#ifdef XPC_IDISPATCH_SUPPORT
PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS &&
!(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS))
{
// Ensure the object is safe for scripting on the specified interface
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
if (!dispSupport) return NPERR_GENERIC_ERROR;
PRBool isScriptable = PR_FALSE;
// Test if the object says its safe for scripting on IDispatch
nsIID iid;
memcpy(&iid, &__uuidof(IDispatch), sizeof(iid));
CComPtr<IUnknown> controlUnk;
pData->pControlSite->GetControlUnknown(&controlUnk);
dispSupport->IsObjectSafeForScripting(reinterpret_cast<void *>(controlUnk.p), iid, &isScriptable);
// Test if the class id says safe for scripting
if (!isScriptable)
{
PRBool classExists = PR_FALSE;
nsCID cid;
memcpy(&iid, &pData->clsid, sizeof(cid));
dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isScriptable);
}
if (!isScriptable)
{
return NPERR_GENERIC_ERROR;
}
}
else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS)
{
// Drop through since all objects are scriptable
}
else
{
return NPERR_GENERIC_ERROR;
}
#else
// Object *must* be safe
if (!pData->pControlSite->IsObjectSafeForScripting(__uuidof(IDispatch)))
{
return NPERR_GENERIC_ERROR;
}
#endif
// Happy happy fun fun - redefine some NPPVariable values that we might
// be asked for but not defined by every PluginSDK
@ -1012,7 +1058,7 @@ xpc_GetValue(NPP instance, NPPVariable variable, void *value)
{
if (!pData->pScriptingPeer)
{
nsScriptablePeer *peer = xpc_GetPeerForCLSID(pData->clsid);
nsScriptablePeer *peer = MozAxPlugin::GetPeerForCLSID(pData->clsid);
if (peer)
{
peer->AddRef();
@ -1030,7 +1076,7 @@ xpc_GetValue(NPP instance, NPPVariable variable, void *value)
else if (variable == kVarScriptableIID)
{
nsIID *piid = (nsIID *) NPN_MemAlloc(sizeof(nsIID));
xpc_GetIIDForCLSID(pData->clsid, *piid);
GetIIDForCLSID(pData->clsid, *piid);
*((nsIID **) value) = piid;
return NPERR_NO_ERROR;
}

Просмотреть файл

@ -41,8 +41,16 @@
#include <servprov.h>
#ifdef XPC_IDISPATCH_SUPPORT
#include "nsIDispatchSupport.h"
#include "nsIActiveXSecurityPolicy.h"
#endif
#include "nsID.h"
#include "nsCOMPtr.h"
#include "nsIClassInfo.h"
#include "nsIMozAxPlugin.h"
#include "nsIServiceManagerUtils.h"
#include "ControlEventSink.h"
@ -133,12 +141,18 @@ public:
typedef CComObject<nsEventSink> nsEventSinkInstance;
#endif
extern void xpc_AddRef();
extern void xpc_Release();
extern CLSID xpc_GetCLSIDForType(const char *mimeType);
extern NPError xpc_GetValue(NPP instance, NPPVariable variable, void *value);
extern nsScriptablePeer *xpc_GetPeerForCLSID(const CLSID &clsid);
extern nsIID xpc_GetIIDForCLSID(const CLSID &clsid);
extern HRESULT xpc_GetServiceProvider(PluginInstanceData *pData, IServiceProvider **pSP);
namespace MozAxPlugin {
extern void AddRef();
extern void Release();
extern CLSID GetCLSIDForType(const char *mimeType);
extern NPError GetValue(NPP instance, NPPVariable variable, void *value);
extern nsScriptablePeer *GetPeerForCLSID(const CLSID &clsid);
extern void GetIIDForCLSID(const CLSID &clsid, nsIID &iid);
extern HRESULT GetServiceProvider(PluginInstanceData *pData, IServiceProvider **pSP);
#ifdef XPC_IDISPATCH_SUPPORT
extern PRUint32 PrefGetHostingFlags();
extern void ReleasePrefObserver();
#endif
}
#endif

Просмотреть файл

@ -0,0 +1,201 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Adam Lock <adamlock@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const NS_IACTIVEXSECURITYPOLICY_CONTRACTID =
"@mozilla.org/nsactivexsecuritypolicy;1";
const NS_IACTIVEXSECURITYPOLICY_CID =
Components.ID("{B9BDB43B-109E-44b8-858C-B68C6C3DF86F}");
const nsISupports = Components.interfaces.nsISupports;
const nsIObserver = Components.interfaces.nsIObserver;
const nsIActiveXSecurityPolicy = Components.interfaces.nsIActiveXSecurityPolicy;
// TODO lockdown this value
const kDefaultGlobalHostingFlags =
nsIActiveXSecurityPolicy.HOSTING_FLAGS_HOST_SAFE_OBJECTS |
nsIActiveXSecurityPolicy.HOSTING_FLAGS_DOWNLOAD_CONTROLS |
nsIActiveXSecurityPolicy.HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS;
const kDefaultOtherHostingFlags =
nsIActiveXSecurityPolicy.HOSTING_FLAGS_HOST_NOTHING;
var gPref = null;
function addPrefListener(observer, domain)
{
try {
if (gPref == null)
{
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
gPref = prefService.getBranch(null);
}
var pbi = gPref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
pbi.addObserver(domain, observer, false);
} catch(ex) {
dump("Failed to observe prefs: " + ex + "\n");
}
}
function AxSecurityPolicy()
{
this.prefPart1 = "security.xpconnect.activex.";
this.prefPart2 = ".hosting_flags";
this.globalPrefName = this.prefPart1 + "global" + this.prefPart2;
// TODO read from prefs
// addPrefListener(this, this.globalPrefName);
this.syncPrefs();
}
AxSecurityPolicy.prototype = {
syncPrefs: function()
{
this.globalHostingFlags = kDefaultGlobalHostingFlags;
// TODO read from prefs
/*
try {
if (gPref == null) {
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
gPref = prefService.getBranch(null);
}
this.globalHostingFlags = gPref.getIntPref(this.globalPrefName);
}
catch (ex) {
dump("Failed to read prefs from " + this.globalPrefName + " : " + ex + "\n");
this.globalHostingFlags = kDefaultGlobalHostingFlags;
}
*/
},
// nsIActiveXSecurityPolicy
getHostingFlags: function(context)
{
var hostingFlags;
if (context == null || context == "global") {
hostingFlags = this.globalHostingFlags;
}
else {
// TODO read from prefs
/*
try {
var prefName = prefPart1 + context + prefPart2;
hostingFlags = gPref.getIntPref(prefName);
}
catch (ex) {
dump("Failed to read prefs from " + prefName + " : " + ex + "\n");
hostingFlags = kDefaultOtherHostingFlags;
}
*/
hostingFlags = kDefaultOtherHostingFlags;
}
return hostingFlags;
},
// nsIObserver
observe: function(subject, topic, prefName)
{
if (topic != "nsPref:changed")
return;
this.syncPrefs();
},
// nsISupports
QueryInterface: function(iid) {
if (!iid.equals(nsISupports) &&
!iid.equals(nsIActiveXSecurityPolicy) &&
!iid.equals(nsIObserver))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
/* factory for AxSecurityPolicy */
var AxSecurityPolicyFactory = {
createInstance: function (outer, iid)
{
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
if (!iid.equals(nsISupports) &&
!iid.equals(nsIActiveXSecurityPolicy) &&
!iid.equals(nsIObserver))
throw Components.results.NS_ERROR_INVALID_ARG;
return new AxSecurityPolicy();
}
};
var AxSecurityPolicyModule = {
registerSelf: function (compMgr, fileSpec, location, type)
{
debug("*** Registering axsecurity policy.\n");
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
compMgr.registerFactoryLocation(
NS_IACTIVEXSECURITYPOLICY_CID ,
"ActiveX Security Policy Service",
NS_IACTIVEXSECURITYPOLICY_CONTRACTID,
fileSpec,
location,
type);
},
unregisterSelf: function(compMgr, fileSpec, location)
{
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
compMgr.unregisterFactoryLocation(NS_IACTIVEXSECURITYPOLICY_CID, fileSpec);
},
getClassObject: function(compMgr, cid, iid)
{
if (cid.equals(NS_IACTIVEXSECURITYPOLICY_CID))
return AxSecurityPolicyFactory;
if (!iid.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
canUnload: function(compMgr)
{
return true;
}
};
/* entrypoint */
function NSGetModule(compMgr, fileSpec) {
return AxSecurityPolicyModule;
}

Просмотреть файл

@ -39,6 +39,9 @@
#include "nsIVariant.idl"
%{ C++
// Pull in jsval definition
#include "jspubtd.h"
// {40c4883d-079f-43db-82a9-df0a59d37998}
#define NS_IDISPATCH_SUPPORT_CID \
{ 0x40c4883d, 0x079f, 0x43db, \
@ -62,24 +65,58 @@ interface IDispatch;
interface nsIDispatchSupport : nsISupports
{
/**
* Converts a COM Variant to a jsval
* @param comvar The COM Variant to be converted
* @param val The jsval to receive the converted value
* Converts a COM Variant to a jsval.
* @param comvar The COM Variant to be converted.
* @param val The jsval to receive the converted value.
*/
void COMVariant2JSVal(in COMVARIANTPtr comvar, out JSVal val);
/**
* Converts a jsval to a COM Variant
* @param var The jsval to be converted
* @param var The jsval to be converted.
* @param comvar The COM Variant to receive the converted value
*/
void JSVal2COMVariant(in JSVal var, out COMVARIANT comvar);
/**
* Instantiate a COM component
* This checks to see if the component is scriptable. If it is, it instantiates it
* @param className contract ID or class ID of the desired component to instantiate
* Instantiate a COM component.
* @param className ProgID or Class ID of the desired object to instantiate
* @return The IDispatch interface pointer if instantiated
*/
IDispatch CreateInstance(in astring className, in PRBool testScriptability);
IDispatch createInstance(in astring className);
/**
* Test if the class is safe to host.
* @param clsid The nsID representation of the CLSID to test.
* @param classExists Returns containing PR_FALSE if the class is
* not registered.
*/
boolean isClassSafeToHost(in nsCIDRef cid, out boolean classExists);
/**
* Test if the specified class is marked safe for scripting.
* @param cid The nsID representation of the CLSID to test.
* @param classExists Returns containing PR_FALSE if the class is not
* registered.
*/
boolean isClassMarkedSafeForScripting(in nsCIDRef cid, out boolean classExists);
/**
* Test if the instantiated object is safe for scripting on the specified
* interface.
* @param theObject The object to test (an IUnknown cast into a void *).
* @param iid The interface to test if it is safe for scripting on.
*/
boolean isObjectSafeForScripting(in voidPtr theObject, in nsIIDRef id);
/**
* Return the ActiveX security and hosting flags. See nsIActiveXSecurityPolicy
* for list of flags.
* @param context The context for which flags are requested. At present the
* only valid value is nsnull.
*/
unsigned long getHostingFlags(in string aContext);
};
%{ C++

Просмотреть файл

@ -41,6 +41,7 @@
* XPC_IDispatch_GetterSetter, and XPC_IDispatch_CallMethod
*/
#include "xpcprivate.h"
#include "nsIActiveXSecurityPolicy.h"
/**
* This is COM's IDispatch IID, but in XPCOM's nsID type
@ -72,88 +73,68 @@ XPCDispObject::WrapIDispatch(IDispatch *pDispatch, XPCCallContext &ccx,
return PR_TRUE;
}
/**
* Helper function to determine whether an object has the safe scripting
* category
* @param the class ID of the COM object to be created
* @return true if it has the category
*/
static PRBool HasSafeScriptingCategory(const CLSID & classID)
HRESULT XPCDispObject::COMCreateInstance(BSTR className, PRBool enforceSecurity, IDispatch ** result)
{
// TODO: probably should look into caching this if this becomes
// a performance issue
CComPtr<ICatInformation> catInfo;
HRESULT hr = catInfo.CoCreateInstance(CLSID_StdComponentCategoriesMgr);
// Must fail if we can't open the category manager
if(!catInfo)
return PR_FALSE;
// See what categories the class implements
CComPtr<IEnumCATID> enumCATID;
if(FAILED(catInfo->EnumImplCategoriesOfClass(classID, &enumCATID)))
return PR_FALSE; // Can't enumerate classes in category so fail
// Search for matching categories
CATID catidNext = GUID_NULL;
// Get the next category, and no, I don't know what the 1 is
while(enumCATID->Next(1, &catidNext, NULL) == S_OK)
{
if(::IsEqualCATID(CATID_SafeForScripting, catidNext))
{
return PR_TRUE;
}
}
return PR_FALSE;
}
// Turn the string into a CLSID
_bstr_t bstrName(className);
CLSID classID = CLSID_NULL;
HRESULT hr = CLSIDFromString(bstrName, &classID);
if (FAILED(hr))
hr = CLSIDFromProgID(bstrName, &classID);
if(FAILED(hr) || ::IsEqualCLSID(classID, CLSID_NULL))
return hr;
/**
* Returns true if the desired scriptable flags are set
* @return true if the desired scriptable flags are set
*/
inline
PRBool ScriptOK(DWORD value)
{
return value & (INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA);
}
nsresult rv;
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID, &rv);
if (NS_FAILED(rv)) return E_UNEXPECTED;
HRESULT XPCDispObject::COMCreateInstance(BSTR className, PRBool testScriptability, IDispatch ** result)
{
CLSID classID;
HRESULT hr;
// If this looks like a class ID
if(FAILED(CLSIDFromString(className, &classID)))
PRUint32 hostingFlags = nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
dispSupport->GetHostingFlags(nsnull, &hostingFlags);
PRBool allowSafeObjects;
if (hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS))
allowSafeObjects = PR_TRUE;
else
allowSafeObjects = PR_FALSE;
PRBool allowAnyObjects;
if (hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_ALL_OBJECTS))
allowAnyObjects = PR_TRUE;
else
allowAnyObjects = PR_FALSE;
// There is no point proceeding if flags say we can't script safe or unsafe objects
if(enforceSecurity && !allowSafeObjects && !allowAnyObjects)
{
hr = CLSIDFromProgID(className, &classID);
if(FAILED(hr))
return hr;
return E_FAIL;
}
// Test if the object is scriptable
PRBool isScriptable = PR_FALSE;
if(enforceSecurity && !allowAnyObjects)
{
nsCID cid;
memcpy(&cid, &classID, sizeof(nsCID));
PRBool classExists = PR_FALSE;
dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isScriptable);
if(!classExists)
return REGDB_E_CLASSNOTREG;
}
PRBool scriptableOK = PR_TRUE;
if(testScriptability)
scriptableOK = HasSafeScriptingCategory(classID);
// Didn't have the safe for scripting category so lets look at IObjectSafety
// Create the object
CComPtr<IDispatch> disp;
HRESULT hResult = disp.CoCreateInstance(classID);
if(FAILED(hResult))
return hResult;
hr = disp.CoCreateInstance(classID);
if(FAILED(hr))
return hr;
// If we're testing scriptability and it didn't have a scripting category
// If we're enforcing security and it didn't have a scripting category
// we'll check via the IObjectSafety interface
if(testScriptability && !scriptableOK)
if(enforceSecurity && !allowAnyObjects && !isScriptable)
{
CComQIPtr<IObjectSafety> objSafety(disp);
// Didn't have IObjectSafety so we'll bail
if(!objSafety)
return E_FAIL;
DWORD supported;
DWORD state;
hr = objSafety->GetInterfaceSafetyOptions(IID_IDispatch, &supported, &state);
if(FAILED(hr))
return hr;
if(!ScriptOK(supported) || !ScriptOK(state))
dispSupport->IsObjectSafeForScripting(disp, NSID_IDISPATCH, &isScriptable);
if (!isScriptable)
return E_FAIL;
}
// Copy and addref
disp.CopyTo(result);
return S_OK;

Просмотреть файл

@ -1005,13 +1005,14 @@ public:
* Instantiates a COM object given a class ID or a prog ID
* @param className a prog ID or a class ID in the form of
* {00000000-0000-0000-0000-000000000000}
* @param testScriptability if true, this tests the objects for scripting
* this tests the category and the IObjectSafety interface
* @param enforceSecurity if true, will apply checks to ensure
* the object can be created giving the current
* security settings.
* @param result pointer to the pointer to receive the interface pointer
*/
static
HRESULT COMCreateInstance(BSTR className,
PRBool testScriptability, IDispatch ** result);
PRBool enforceSecurity, IDispatch ** result);
/**
* Wraps an IDispatch interface, returning the object as a jsval
* @param pDispatch IDispatch pointer

Просмотреть файл

@ -42,7 +42,7 @@ PRBool XPCIDispatchExtension::mIsEnabled = PR_TRUE;
static JSBool
CommonConstructor(XPCCallContext &ccx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval, PRBool testScriptability)
jsval *rval, PRBool enforceSecurity)
{
// Check if IDispatch is enabled, fail if not
if (!nsXPConnect::IsIDispatchEnabled())
@ -66,7 +66,7 @@ CommonConstructor(XPCCallContext &ccx, JSObject *obj, uintN argc, jsval *argv,
}
// Instantiate the desired COM object
CComPtr<IDispatch> pDispatch;
HRESULT rv = XPCDispObject::COMCreateInstance(bstrClassName, testScriptability, &pDispatch);
HRESULT rv = XPCDispObject::COMCreateInstance(bstrClassName, enforceSecurity, &pDispatch);
if(FAILED(rv))
{
XPCThrower::ThrowCOMError(ccx, rv, NS_ERROR_XPC_COM_CREATE_FAILED);

Просмотреть файл

@ -43,19 +43,115 @@
#include "XPCPrivate.h"
#include "nsIActiveXSecurityPolicy.h"
static nsresult
ClassIsListed(HKEY hkeyRoot, const TCHAR *szKey, const CLSID &clsid, PRBool &listIsEmpty)
{
// Test if the specified CLSID is found in the specified registry key
listIsEmpty = PR_FALSE;
CRegKey keyList;
if(keyList.Open(hkeyRoot, szKey, KEY_READ) != ERROR_SUCCESS)
{
return NS_ERROR_FAILURE;
}
// Enumerate CLSIDs looking for this one
int i = 0;
do {
USES_CONVERSION;
TCHAR szCLSID[64];
const DWORD kBufLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
if(::RegEnumKey(keyList, i, szCLSID, kBufLength) != ERROR_SUCCESS)
{
// An empty list
if(i == 0)
listIsEmpty = PR_TRUE;
break;
}
++i;
szCLSID[kBufLength - 1] = TCHAR('\0');
CLSID clsidToCompare = GUID_NULL;
if(SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
::IsEqualCLSID(clsid, clsidToCompare))
{
return NS_OK;
}
} while (1);
return NS_ERROR_FAILURE;
}
static PRBool
ClassExists(const CLSID &clsid)
{
// Test if there is a CLSID entry. If there isn't then obviously
// the object doesn't exist.
CRegKey key;
if(key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS)
return PR_FALSE; // Must fail if we can't even open this!
LPOLESTR szCLSID = NULL;
if(FAILED(StringFromCLSID(clsid, &szCLSID)))
return PR_FALSE; // Can't allocate string from CLSID
USES_CONVERSION;
CRegKey keyCLSID;
LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ);
CoTaskMemFree(szCLSID);
if(lResult != ERROR_SUCCESS)
return PR_FALSE; // Class doesn't exist
return PR_TRUE;
}
static PRBool
ClassImplementsCategory(const CLSID &clsid, const CATID &catid, PRBool &bClassExists)
{
bClassExists = ClassExists(clsid);
// Non existent classes won't implement any category...
if(!bClassExists)
return PR_FALSE;
// CLSID exists, so try checking what categories it implements
bClassExists = TRUE;
CComPtr<ICatInformation> catInfo;
HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
CLSCTX_INPROC_SERVER, __uuidof(ICatInformation), (LPVOID*) &catInfo);
if(catInfo == NULL)
return PR_FALSE; // Must fail if we can't open the category manager
// See what categories the class implements
CComPtr<IEnumCATID> enumCATID;
if(FAILED(catInfo->EnumImplCategoriesOfClass(clsid, &enumCATID)))
return PR_FALSE; // Can't enumerate classes in category so fail
// Search for matching categories
BOOL bFound = FALSE;
CATID catidNext = GUID_NULL;
while (enumCATID->Next(1, &catidNext, NULL) == S_OK)
{
if(::IsEqualCATID(catid, catidNext))
return PR_TRUE; // Match
}
return PR_FALSE;
}
nsDispatchSupport* nsDispatchSupport::mInstance = nsnull;
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDispatchSupport, nsIDispatchSupport)
nsDispatchSupport::nsDispatchSupport()
{
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
NS_INIT_ISUPPORTS();
/* member initializers and constructor code */
}
nsDispatchSupport::~nsDispatchSupport()
{
/* destructor code */
/* destructor code */
}
/**
@ -86,6 +182,154 @@ NS_IMETHODIMP nsDispatchSupport::JSVal2COMVariant(jsval val, VARIANT * comvar)
return retval;
}
/* boolean isClassSafeToHost (in nsCIDRef clsid, out boolean classExists); */
NS_IMETHODIMP nsDispatchSupport::IsClassSafeToHost(const nsCID & cid, PRBool *classExists, PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
NS_ENSURE_ARG_POINTER(classExists);
*_retval = PR_FALSE;
CLSID clsid = XPCDispnsCID2CLSID(cid);
*classExists = ClassExists(clsid);
// Test the Internet Explorer black list
const TCHAR kIEControlsBlacklist[] = _T("SOFTWARE\\Microsoft\\Internet Explorer\\ActiveX Compatibility");
CRegKey keyExplorer;
if(keyExplorer.Open(HKEY_LOCAL_MACHINE,
kIEControlsBlacklist, KEY_READ) == ERROR_SUCCESS)
{
LPOLESTR szCLSID = NULL;
::StringFromCLSID(clsid, &szCLSID);
if(szCLSID)
{
CRegKey keyCLSID;
USES_CONVERSION;
if(keyCLSID.Open(keyExplorer, W2T(szCLSID), KEY_READ) == ERROR_SUCCESS)
{
DWORD dwType = REG_DWORD;
DWORD dwFlags = 0;
DWORD dwBufSize = sizeof(dwFlags);
if(::RegQueryValueEx(keyCLSID, _T("Compatibility Flags"),
NULL, &dwType, (LPBYTE) &dwFlags, &dwBufSize) == ERROR_SUCCESS)
{
// Documented flags for this reg key
const DWORD kKillBit = 0x00000400; // MS Knowledge Base 240797
if(dwFlags & kKillBit)
{
::CoTaskMemFree(szCLSID);
*_retval = PR_FALSE;
return NS_OK;
}
}
}
::CoTaskMemFree(szCLSID);
}
}
// Registry keys containing lists of controls that the Gecko explicitly does
// or does not support.
const TCHAR kControlsToDenyKey[] = _T("Software\\Mozilla\\ActiveX\\Blacklist\\CLSID");
const TCHAR kControlsToAllowKey[] = _T("Software\\Mozilla\\ActiveX\\Whitelist\\CLSID");
// Check if the CLSID belongs to a list that the Gecko does not support
PRBool listIsEmpty = PR_FALSE;
if(NS_SUCCEEDED(ClassIsListed(HKEY_LOCAL_MACHINE, kControlsToDenyKey, clsid, listIsEmpty)))
{
*_retval = PR_FALSE;
return NS_OK;
}
// Check if the CLSID is in the whitelist. This test only cares when the whitelist is
// non-empty, to indicates that it is being used.
listIsEmpty = PR_FALSE;
if(NS_FAILED(ClassIsListed(HKEY_LOCAL_MACHINE, kControlsToAllowKey, clsid, listIsEmpty)) &&
!listIsEmpty)
{
*_retval = PR_FALSE;
return NS_OK;
}
*_retval = PR_TRUE;
return NS_OK;
}
/* boolean isClassMarkedSafeForScripting (in nsCIDRef clsid, out boolean classExists); */
NS_IMETHODIMP nsDispatchSupport::IsClassMarkedSafeForScripting(const nsCID & cid, PRBool *classExists, PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
NS_ENSURE_ARG_POINTER(classExists);
// Test the category the object belongs to
CLSID clsid = XPCDispnsCID2CLSID(cid);
*_retval = ClassImplementsCategory(clsid, CATID_SafeForScripting, *classExists);
return NS_OK;
}
/* boolean isObjectSafeForScripting (in voidPtr theObject, in nsIIDRef iid); */
NS_IMETHODIMP nsDispatchSupport::IsObjectSafeForScripting(void * theObject, const nsIID & id, PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(theObject);
NS_ENSURE_ARG_POINTER(_retval);
// Test if the object implements IObjectSafety and is marked safe for scripting
IUnknown *pObject = (IUnknown *) theObject;
IID iid = XPCDispIID2IID(id);
// Ask the control if its safe for scripting
CComQIPtr<IObjectSafety> objectSafety = pObject;
if(!objectSafety)
{
*_retval = PR_FALSE;
return NS_OK;
}
DWORD dwSupported = 0; // Supported options (mask)
DWORD dwEnabled = 0; // Enabled options
// Assume scripting via IDispatch
if(FAILED(objectSafety->GetInterfaceSafetyOptions(
iid, &dwSupported, &dwEnabled)))
{
// Interface is not safe or failure.
*_retval = PR_FALSE;
return NS_OK;
}
// Test if safe for scripting
if(!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
{
*_retval = PR_FALSE;
return NS_OK;
}
*_retval = PR_TRUE;
return NS_OK;
}
static const PRUint32 kDefaultHostingFlags =
nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
/* unsigned long getHostingFlags (in string aContext); */
NS_IMETHODIMP nsDispatchSupport::GetHostingFlags(const char *aContext, PRUint32 *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
// Ask the activex security policy what the hosting flags are
nsresult rv;
nsCOMPtr<nsIActiveXSecurityPolicy> securityPolicy =
do_GetService(NS_IACTIVEXSECURITYPOLICY_CONTRACTID, &rv);
if(NS_SUCCEEDED(rv) && securityPolicy)
return securityPolicy->GetHostingFlags(aContext, _retval);
// No policy so use the defaults
*_retval = kDefaultHostingFlags;
return NS_OK;
}
/**
* Creates an instance of an COM object, returning it as an IDispatch interface.
* This also allows testing of scriptability.
@ -97,14 +341,13 @@ NS_IMETHODIMP nsDispatchSupport::JSVal2COMVariant(jsval val, VARIANT * comvar)
* @return nsresult
*/
NS_IMETHODIMP nsDispatchSupport::CreateInstance(const nsAString & className,
PRBool testScriptability,
IDispatch ** result)
{
if (!nsXPConnect::IsIDispatchEnabled())
return NS_ERROR_XPC_IDISPATCH_NOT_ENABLED;
const nsPromiseFlatString & flat = PromiseFlatString(className);
CComBSTR name(flat.Length(), flat.get());
return XPCDispObject::COMCreateInstance(name, testScriptability, result);
return XPCDispObject::COMCreateInstance(name, PR_TRUE, result);
}
nsDispatchSupport* nsDispatchSupport::GetSingleton()