Bug 204894 - Implement GeckoActiveXObject.supports(clsid). r=dbradley, sr=alecf

This commit is contained in:
dbradley%netscape.com 2003-06-20 04:08:17 +00:00
parent 0c73334798
commit 1e7ae8efa5
5 changed files with 158 additions and 48 deletions

View File

@ -73,26 +73,15 @@ XPCDispObject::WrapIDispatch(IDispatch *pDispatch, XPCCallContext &ccx,
return PR_TRUE; return PR_TRUE;
} }
HRESULT XPCDispObject::COMCreateInstance(XPCCallContext & ccx, BSTR className, HRESULT XPCDispObject::SecurityCheck(XPCCallContext & ccx, const CLSID & aCID,
PRBool enforceSecurity, IDispatch ** createdObject)
IDispatch ** 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;
nsresult rv; nsresult rv;
nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID, &rv); nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID, &rv);
if(NS_FAILED(rv)) return E_UNEXPECTED; if(NS_FAILED(rv)) return E_UNEXPECTED;
PRUint32 hostingFlags = nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING; PRUint32 hostingFlags = nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
dispSupport->GetHostingFlags(nsnull, &hostingFlags); dispSupport->GetHostingFlags(nsnull, &hostingFlags);
PRBool allowSafeObjects; PRBool allowSafeObjects;
if(hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS)) if(hostingFlags & (nsIActiveXSecurityPolicy::HOSTING_FLAGS_SCRIPT_SAFE_OBJECTS))
allowSafeObjects = PR_TRUE; allowSafeObjects = PR_TRUE;
@ -103,46 +92,75 @@ HRESULT XPCDispObject::COMCreateInstance(XPCCallContext & ccx, BSTR className,
allowAnyObjects = PR_TRUE; allowAnyObjects = PR_TRUE;
else else
allowAnyObjects = PR_FALSE; allowAnyObjects = PR_FALSE;
if(!allowSafeObjects && !allowAnyObjects)
// There is no point proceeding if flags say we can't script safe or unsafe objects
if(enforceSecurity && !allowSafeObjects && !allowAnyObjects)
{
return E_FAIL; return E_FAIL;
}
PRBool classExists = PR_FALSE; PRBool classExists = PR_FALSE;
PRBool ok = PR_FALSE; PRBool ok = PR_FALSE;
const nsCID & ourCID = XPCDispCLSID2nsCID(classID); const nsCID & ourCID = XPCDispCLSID2nsCID(aCID);
dispSupport->IsClassSafeToHost(ccx, ourCID, PR_FALSE, &classExists, &ok); dispSupport->IsClassSafeToHost(ccx, ourCID, PR_FALSE, &classExists, &ok);
if(classExists && !ok) if(classExists && !ok)
return E_FAIL; return E_FAIL;
// Test if the object is scriptable // Test if the object is scriptable
PRBool isScriptable = PR_FALSE; PRBool isScriptable = PR_FALSE;
if(enforceSecurity && !allowAnyObjects) if(!allowAnyObjects)
{ {
PRBool classExists = PR_FALSE; PRBool classExists = PR_FALSE;
dispSupport->IsClassMarkedSafeForScripting(ourCID, &classExists, &isScriptable); dispSupport->IsClassMarkedSafeForScripting(ourCID, &classExists, &isScriptable);
if(!classExists) if(!classExists)
return REGDB_E_CLASSNOTREG; return REGDB_E_CLASSNOTREG;
} }
// Create the object // Create the object
CComPtr<IDispatch> 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<IDispatch> disp; CComPtr<IDispatch> disp;
hr = disp.CoCreateInstance(classID); hr = disp.CoCreateInstance(classID);
if(FAILED(hr)) if(FAILED(hr))
return 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); disp.CopyTo(result);
return S_OK; return S_OK;
} }

View File

@ -1088,6 +1088,17 @@ public:
*/ */
static static
JSBool Invoke(XPCCallContext & ccx, CallMode mode); 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 * Instantiates a COM object given a class ID or a prog ID
* @param ccx an XPConnect call context * @param ccx an XPConnect call context

View File

@ -45,8 +45,14 @@ CommonConstructor(JSContext *cx, int name, JSObject *obj, uintN argc,
jsval *argv, jsval *rval, PRBool enforceSecurity) jsval *argv, jsval *rval, PRBool enforceSecurity)
{ {
XPCCallContext ccx(JS_CALLER, cx, JS_GetGlobalObject(cx)); 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(); XPCJSRuntime *rt = ccx.GetRuntime();
if (!rt) if(!rt)
{ {
XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx); XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx);
return JS_FALSE; return JS_FALSE;
@ -64,12 +70,6 @@ CommonConstructor(JSContext *cx, int name, JSObject *obj, uintN argc,
// Security manager will have set an exception // Security manager will have set an exception
return JS_FALSE; 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 // Make sure we were called with one string parameter
if(argc != 1 || (argc == 1 && !JSVAL_IS_STRING(argv[0]))) 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); 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, JSBool XPCIDispatchExtension::Initialize(JSContext * aJSContext,
JSObject * aGlobalJSObj) JSObject * aGlobalJSObj)
{ {
JSBool result = JS_DefineFunction(aJSContext, aGlobalJSObj, xpcFunctionDefiner fd(aJSContext);
nsXPConnect::GetRuntime()->GetStringName( JSFunction * func = fd.Define(aGlobalJSObj,
XPCJSRuntime::IDX_ACTIVEX_OBJECT), XPCJSRuntime::IDX_ACTIVEX_OBJECT,
ActiveXConstructor, 1, 0) != nsnull; 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 #ifdef XPC_COMOBJECT
if(result) if(!fd.Define(aGlobalJSObj, XPCJSRuntime::IDX_COM_OBJECT, COMObjectConstructor))
result = JS_DefineFunction(aJSContext, aGlobalJSObj, return JS_FALSE;
nsXPConnect::GetRuntime()->GetStringName(
XPCJSRuntime::IDX_COM_OBJECT),
COMObjectConstructor, 1, 0) != nsnull;
#endif #endif
return result; return JS_TRUE;
} }
nsresult XPCIDispatchExtension::IDispatchQIWrappedJS(nsXPCWrappedJS * self, nsresult XPCIDispatchExtension::IDispatchQIWrappedJS(nsXPCWrappedJS * self,

View File

@ -55,6 +55,7 @@ const char* XPCJSRuntime::mStrings[] = {
#ifdef XPC_IDISPATCH_SUPPORT #ifdef XPC_IDISPATCH_SUPPORT
, "GeckoActiveXObject" // IDX_ACTIVEX_OBJECT , "GeckoActiveXObject" // IDX_ACTIVEX_OBJECT
, "COMObject" // IDX_COMOBJECT , "COMObject" // IDX_COMOBJECT
, "supports" // IDX_ACTIVEX_SUPPORTS
#endif #endif
}; };

View File

@ -554,6 +554,7 @@ public:
#ifdef XPC_IDISPATCH_SUPPORT #ifdef XPC_IDISPATCH_SUPPORT
IDX_ACTIVEX_OBJECT , IDX_ACTIVEX_OBJECT ,
IDX_COM_OBJECT , IDX_COM_OBJECT ,
IDX_ACTIVEX_SUPPORTS ,
#endif #endif
IDX_TOTAL_COUNT // just a count of the above IDX_TOTAL_COUNT // just a count of the above
}; };