From 1e7ae8efa5188410c19339860d4f039a2c52e1e3 Mon Sep 17 00:00:00 2001 From: "dbradley%netscape.com" Date: Fri, 20 Jun 2003 04:08:17 +0000 Subject: [PATCH] Bug 204894 - Implement GeckoActiveXObject.supports(clsid). r=dbradley, sr=alecf --- js/src/xpconnect/src/XPCDispObject.cpp | 80 ++++++++----- js/src/xpconnect/src/XPCDispPrivate.h | 11 ++ .../xpconnect/src/XPCIDispatchExtension.cpp | 113 +++++++++++++++--- js/src/xpconnect/src/xpcjsruntime.cpp | 1 + js/src/xpconnect/src/xpcprivate.h | 1 + 5 files changed, 158 insertions(+), 48 deletions(-) diff --git a/js/src/xpconnect/src/XPCDispObject.cpp b/js/src/xpconnect/src/XPCDispObject.cpp index ca2df2c3de00..6eca54cf2e3e 100644 --- a/js/src/xpconnect/src/XPCDispObject.cpp +++ b/js/src/xpconnect/src/XPCDispObject.cpp @@ -73,26 +73,15 @@ XPCDispObject::WrapIDispatch(IDispatch *pDispatch, XPCCallContext &ccx, return PR_TRUE; } -HRESULT XPCDispObject::COMCreateInstance(XPCCallContext & ccx, BSTR className, - PRBool enforceSecurity, - IDispatch ** result) +HRESULT XPCDispObject::SecurityCheck(XPCCallContext & ccx, const CLSID & aCID, + IDispatch ** createdObject) { - // 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; - nsresult rv; nsCOMPtr dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID, &rv); if(NS_FAILED(rv)) return E_UNEXPECTED; PRUint32 hostingFlags = nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING; dispSupport->GetHostingFlags(nsnull, &hostingFlags); - PRBool allowSafeObjects; if(hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS)) allowSafeObjects = PR_TRUE; @@ -103,46 +92,75 @@ HRESULT XPCDispObject::COMCreateInstance(XPCCallContext & ccx, BSTR className, 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) - { + if(!allowSafeObjects && !allowAnyObjects) return E_FAIL; - } + PRBool classExists = PR_FALSE; PRBool ok = PR_FALSE; - const nsCID & ourCID = XPCDispCLSID2nsCID(classID); + const nsCID & ourCID = XPCDispCLSID2nsCID(aCID); dispSupport->IsClassSafeToHost(ccx, ourCID, PR_FALSE, &classExists, &ok); if(classExists && !ok) return E_FAIL; // Test if the object is scriptable PRBool isScriptable = PR_FALSE; - if(enforceSecurity && !allowAnyObjects) + if(!allowAnyObjects) { PRBool classExists = PR_FALSE; dispSupport->IsClassMarkedSafeForScripting(ourCID, &classExists, &isScriptable); if(!classExists) return REGDB_E_CLASSNOTREG; } - + // Create the object + CComPtr disp; + // If createdObject isn't null we need to create the object + if (createdObject) + { + HRESULT hr = disp.CoCreateInstance(aCID); + if(FAILED(hr)) + return hr; + // if we don't allow just any object, and it wasn't marked + // safe for scripting then ask the object (MS idea of security) + if (!allowAnyObjects && !isScriptable) + { + dispSupport->IsObjectSafeForScripting(disp, NSID_IDISPATCH, &isScriptable); + if(!isScriptable) + return E_FAIL; + } + disp.CopyTo(createdObject); + } + + return S_OK; +} + +HRESULT XPCDispObject::COMCreateInstance(XPCCallContext & ccx, BSTR className, + PRBool enforceSecurity, + IDispatch ** result) +{ + NS_ENSURE_ARG_POINTER(result); + // 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; + + // If the caller cares about security do the necessary checks + // This results in the object being instantiated, so we'll use + // it + if(enforceSecurity) + return SecurityCheck(ccx, classID, result); + CComPtr disp; hr = disp.CoCreateInstance(classID); if(FAILED(hr)) return hr; - // If we're enforcing security and it didn't have a scripting category - // we'll check via the IObjectSafety interface - if(enforceSecurity && !allowAnyObjects && !isScriptable) - { - dispSupport->IsObjectSafeForScripting(disp, NSID_IDISPATCH, &isScriptable); - if(!isScriptable) - return E_FAIL; - } - - // Copy and addref disp.CopyTo(result); + return S_OK; } diff --git a/js/src/xpconnect/src/XPCDispPrivate.h b/js/src/xpconnect/src/XPCDispPrivate.h index 9c88c0211e34..7e634bd066cd 100644 --- a/js/src/xpconnect/src/XPCDispPrivate.h +++ b/js/src/xpconnect/src/XPCDispPrivate.h @@ -1088,6 +1088,17 @@ public: */ static JSBool Invoke(XPCCallContext & ccx, CallMode mode); + /** + * Performs the various security checks, caps, hosting flags, etc. + * Instantiates the object and will return that object if createdObject + * result is not null + * @param ccx an XPConnect call context + * @param aCID the class ID to be tested + * @param createdObject is the optional object to be returned + */ + static + HRESULT SecurityCheck(XPCCallContext & ccx, const CLSID & aCID, + IDispatch ** createdObject = nsnull); /** * Instantiates a COM object given a class ID or a prog ID * @param ccx an XPConnect call context diff --git a/js/src/xpconnect/src/XPCIDispatchExtension.cpp b/js/src/xpconnect/src/XPCIDispatchExtension.cpp index cf25be4c0e6f..3086b64fcc3f 100644 --- a/js/src/xpconnect/src/XPCIDispatchExtension.cpp +++ b/js/src/xpconnect/src/XPCIDispatchExtension.cpp @@ -45,8 +45,14 @@ CommonConstructor(JSContext *cx, int name, JSObject *obj, uintN argc, jsval *argv, jsval *rval, PRBool enforceSecurity) { XPCCallContext ccx(JS_CALLER, cx, JS_GetGlobalObject(cx)); + // Check if IDispatch is enabled, fail if not + if(!nsXPConnect::IsIDispatchEnabled()) + { + XPCThrower::Throw(NS_ERROR_XPC_IDISPATCH_NOT_ENABLED, ccx); + return JS_FALSE; + } XPCJSRuntime *rt = ccx.GetRuntime(); - if (!rt) + if(!rt) { XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx); return JS_FALSE; @@ -64,12 +70,6 @@ CommonConstructor(JSContext *cx, int name, JSObject *obj, uintN argc, // Security manager will have set an exception return JS_FALSE; } - // Check if IDispatch is enabled, fail if not - if(!nsXPConnect::IsIDispatchEnabled()) - { - XPCThrower::Throw(NS_ERROR_XPC_IDISPATCH_NOT_ENABLED, ccx); - return JS_FALSE; - } // Make sure we were called with one string parameter if(argc != 1 || (argc == 1 && !JSVAL_IS_STRING(argv[0]))) { @@ -131,21 +131,100 @@ ActiveXConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, rval, PR_TRUE); } +JS_STATIC_DLL_CALLBACK(JSBool) +ActiveXSupports(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) +{ + XPCCallContext ccx(JS_CALLER, cx, JS_GetGlobalObject(cx)); + // Check if IDispatch is enabled, fail if not + if(!nsXPConnect::IsIDispatchEnabled()) + { + XPCThrower::Throw(NS_ERROR_XPC_IDISPATCH_NOT_ENABLED, ccx); + return JS_FALSE; + } + XPCJSRuntime *rt = ccx.GetRuntime(); + if(!rt) + { + XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx); + return JS_FALSE; + } + // Make sure we were called with one string parameter + if(argc != 1 || (argc == 1 && !JSVAL_IS_STRING(argv[0]))) + { + XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx); + return JS_FALSE; + } + PRUint32 len; + jschar * className = xpc_JSString2String(ccx, argv[0], &len); + CComBSTR bstrClassName(len, className); + if(!className) + { + XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx); + return JS_FALSE; + } + CLSID classID = CLSID_NULL; + HRESULT hr = CLSIDFromString(bstrClassName, &classID); + if(FAILED(hr) || ::IsEqualCLSID(classID, CLSID_NULL)) + { + XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx); + return JS_FALSE; + } + // Instantiate the desired COM object + HRESULT rv = XPCDispObject::SecurityCheck(ccx, classID); + *rval = BOOLEAN_TO_JSVAL(SUCCEEDED(rv)); + return JS_TRUE; +} + +class xpcFunctionDefiner +{ +public: + xpcFunctionDefiner(JSContext * aJSContext); + JSFunction * Define(JSObject * globalObject, uintN aNameIndex, + JSNative aCall); +private: + XPCJSRuntime * m_Runtime; + JSContext * m_JSContext; +}; + +inline +xpcFunctionDefiner::xpcFunctionDefiner(JSContext * aJSContext) : + m_Runtime(nsXPConnect::GetRuntime()), m_JSContext(aJSContext) +{ + NS_ASSERTION(m_Runtime, "nsXPConnect::GetRuntime() returned null"); + NS_ASSERTION(aJSContext, "xpcFunctionDefiner constructor passed a null context"); +} + +inline +JSFunction * xpcFunctionDefiner::Define(JSObject * globalObject, + uintN aNameIndex, JSNative aCall) +{ + return JS_DefineFunction(m_JSContext, globalObject, + m_Runtime->GetStringName(aNameIndex), + aCall, 1, JSPROP_PERMANENT | JSPROP_READONLY); +} + JSBool XPCIDispatchExtension::Initialize(JSContext * aJSContext, JSObject * aGlobalJSObj) { - JSBool result = JS_DefineFunction(aJSContext, aGlobalJSObj, - nsXPConnect::GetRuntime()->GetStringName( - XPCJSRuntime::IDX_ACTIVEX_OBJECT), - ActiveXConstructor, 1, 0) != nsnull; + xpcFunctionDefiner fd(aJSContext); + JSFunction * func = fd.Define(aGlobalJSObj, + XPCJSRuntime::IDX_ACTIVEX_OBJECT, + ActiveXConstructor); + if(!func) + return JS_FALSE; + + JSObject * funcObject = JS_GetFunctionObject(func); + if(!funcObject) + return JS_FALSE; + + if(!fd.Define(funcObject, XPCJSRuntime::IDX_ACTIVEX_SUPPORTS, ActiveXSupports)) + return JS_FALSE; + #ifdef XPC_COMOBJECT - if(result) - result = JS_DefineFunction(aJSContext, aGlobalJSObj, - nsXPConnect::GetRuntime()->GetStringName( - XPCJSRuntime::IDX_COM_OBJECT), - COMObjectConstructor, 1, 0) != nsnull; + if(!fd.Define(aGlobalJSObj, XPCJSRuntime::IDX_COM_OBJECT, COMObjectConstructor)) + return JS_FALSE; #endif - return result; + return JS_TRUE; } nsresult XPCIDispatchExtension::IDispatchQIWrappedJS(nsXPCWrappedJS * self, diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 353023d17abb..1b4eeefb0b0c 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -55,6 +55,7 @@ const char* XPCJSRuntime::mStrings[] = { #ifdef XPC_IDISPATCH_SUPPORT , "GeckoActiveXObject" // IDX_ACTIVEX_OBJECT , "COMObject" // IDX_COMOBJECT + , "supports" // IDX_ACTIVEX_SUPPORTS #endif }; diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index bc00759a71c8..4e909a467864 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -554,6 +554,7 @@ public: #ifdef XPC_IDISPATCH_SUPPORT IDX_ACTIVEX_OBJECT , IDX_COM_OBJECT , + IDX_ACTIVEX_SUPPORTS , #endif IDX_TOTAL_COUNT // just a count of the above };