Exemplo n.º 1
0
static JSBool
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)
    {
        XPCThrower::Throw(NS_ERROR_UNEXPECTED, ccx);
        return JS_FALSE;
    } 
    nsIXPCSecurityManager* sm = ccx.GetXPCContext()
        ->GetAppropriateSecurityManager(nsIXPCSecurityManager::HOOK_CALL_METHOD);
    XPCWrappedNative * wrapper = ccx.GetWrapper();
    if(sm && NS_FAILED(sm->CanAccess(nsIXPCSecurityManager::ACCESS_CALL_METHOD,
                                      &ccx, ccx, ccx.GetFlattenedJSObject(),
                                      wrapper->GetIdentityObject(),
                                      wrapper->GetClassInfo(),
                                      rt->GetStringJSVal(name),
                                      wrapper->GetSecurityInfoAddr())))
    {
        // Security manager will have set an exception
        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;
    }

    JSString* str = JSVAL_TO_STRING(argv[0]);
    PRUint32 len = JS_GetStringLength(str);

    // Cap constructor argument length to keep from crashing in string
    // code.
    if(len > XPC_IDISPATCH_CTOR_MAX_ARG_LEN)
    {
      XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
      return JS_FALSE;
    }

    jschar * className = JS_GetStringChars(str);
    CComBSTR bstrClassName(len, reinterpret_cast<const WCHAR *>(className));
    if(!bstrClassName)
    {
        XPCThrower::Throw(NS_ERROR_XPC_COM_INVALID_CLASS_ID, ccx);
        return JS_FALSE;
    }
    // Instantiate the desired COM object
    CComPtr<IDispatch> pDispatch;
    HRESULT rv = XPCDispObject::COMCreateInstance(ccx, bstrClassName,
                                                  enforceSecurity, &pDispatch);
    if(FAILED(rv))
    {
        XPCThrower::ThrowCOMError(ccx, rv, NS_ERROR_XPC_COM_CREATE_FAILED);
        return JS_FALSE;
    }
    // Get a wrapper for our object
    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    nsresult nsrv = ccx.GetXPConnect()->WrapNative(
        ccx, ccx.GetOperandJSObject(), reinterpret_cast<nsISupports*>(pDispatch.p),
        NSID_IDISPATCH, getter_AddRefs(holder));
    if(NS_FAILED(nsrv))
    {
        XPCThrower::Throw(nsrv, ccx);
        return JS_FALSE;
    }
    // get and return the JS object wrapper
    JSObject * jsobj;
    nsrv = holder->GetJSObject(&jsobj);
    if(NS_FAILED(nsrv))
    {
        XPCThrower::Throw(nsrv, ccx);
        return JS_FALSE;
    }
    *rval = OBJECT_TO_JSVAL(jsobj);
    return JS_TRUE;
}
Exemplo n.º 2
0
JSObject *
WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj, uintN flags)
{
    // Don't unwrap an outer window, just double wrap it if needed.
    if (obj->getClass()->ext.innerObject)
        return DoubleWrap(cx, obj, flags);

    // Here are the rules for wrapping:
    // We should never get a proxy here (the JS engine unwraps those for us).
    JS_ASSERT(!obj->isWrapper());

    // As soon as an object is wrapped in a security wrapper, it morphs to be
    // a fat wrapper. (see also: bug XXX).
    if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
        return nsnull;

    // We only hand out outer objects to script.
    obj = GetCurrentOuter(cx, obj);
    if (obj->getClass()->ext.innerObject)
        return DoubleWrap(cx, obj, flags);

    // Now, our object is ready to be wrapped, but several objects (notably
    // nsJSIIDs) have a wrapper per scope. If we are about to wrap one of
    // those objects in a security wrapper, then we need to hand back the
    // wrapper for the new scope instead. Also, global objects don't move
    // between scopes so for those we also want to return the wrapper. So...
    if (!IS_WN_WRAPPER(obj) || !obj->getParent())
        return DoubleWrap(cx, obj, flags);

    XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));

    // If the object doesn't have classinfo we want to return the same
    // XPCWrappedNative so that we keep the same set of interfaces.
    if (!wn->GetClassInfo())
        return DoubleWrap(cx, obj, flags);

    JSAutoEnterCompartment ac;
    if (!ac.enter(cx, obj))
        return nsnull;
    XPCCallContext ccx(JS_CALLER, cx, obj);

    {
        if (NATIVE_HAS_FLAG(&ccx, WantPreCreate)) {
            // We have a precreate hook. This object might enforce that we only
            // ever create JS object for it.
            JSObject *originalScope = scope;
            nsresult rv = wn->GetScriptableInfo()->GetCallback()->
                PreCreate(wn->Native(), cx, scope, &scope);
            NS_ENSURE_SUCCESS(rv, DoubleWrap(cx, obj, flags));

            // If the handed back scope differs from the passed-in scope and is in
            // a separate compartment, then this object is explicitly requesting
            // that we don't create a second JS object for it: create a security
            // wrapper.
            if (originalScope->compartment() != scope->getCompartment())
                return DoubleWrap(cx, obj, flags);

            // Note: this penalizes objects that only have one wrapper, but are
            // being accessed across compartments. We would really prefer to
            // replace the above code with a test that says "do you only have one
            // wrapper?"
        }
    }

    // NB: Passing a holder here inhibits slim wrappers under
    // WrapNativeToJSVal.
    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;

    // This public WrapNativeToJSVal API enters the compartment of 'scope'
    // so we don't have to.
    jsval v;
    nsresult rv =
        nsXPConnect::FastGetXPConnect()->WrapNativeToJSVal(cx, scope, wn->Native(), nsnull,
                                                           &NS_GET_IID(nsISupports), PR_FALSE,
                                                           &v, getter_AddRefs(holder));
    if (NS_SUCCEEDED(rv)) {
        obj = JSVAL_TO_OBJECT(v);
        NS_ASSERTION(IS_WN_WRAPPER(obj), "bad object");

        XPCWrappedNative *newwn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
        if (newwn->GetSet()->GetInterfaceCount() < wn->GetSet()->GetInterfaceCount())
            newwn->SetSet(wn->GetSet());
    }

    return DoubleWrap(cx, obj, flags);
}
Exemplo n.º 3
0
JSBool XPCDispObject::Invoke(XPCCallContext & ccx, CallMode mode)
{
    nsresult rv = ccx.CanCallNow();
    if(NS_FAILED(rv))
    {
        // If the security manager is complaining then this is not really an
        // internal error in xpconnect. So, no reason to botch the assertion.
        NS_ASSERTION(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, 
                     "hmm? CanCallNow failed in XPCDispObject::Invoke. "
                     "We are finding out about this late!");
        XPCThrower::Throw(rv, ccx);
        return JS_FALSE;
    }

    // TODO: Remove type cast and change GetIDispatchMember to use the correct type
    XPCDispInterface::Member* member = reinterpret_cast<XPCDispInterface::Member*>(ccx.GetIDispatchMember());
    XPCJSRuntime* rt = ccx.GetRuntime();
    XPCContext* xpcc = ccx.GetXPCContext();
    XPCPerThreadData* tls = ccx.GetThreadData();
    
    jsval* argv = ccx.GetArgv();
    uintN argc = ccx.GetArgc();

    tls->SetException(nsnull);
    xpcc->SetLastResult(NS_ERROR_UNEXPECTED);

    // set up the method index and do the security check if needed

    PRUint32 secFlag;
    PRUint32 secAction;

    switch(mode)
    {
        case CALL_METHOD:
            secFlag   = nsIXPCSecurityManager::HOOK_CALL_METHOD;
            secAction = nsIXPCSecurityManager::ACCESS_CALL_METHOD;
            break;
        case CALL_GETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_GET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
            break;
        case CALL_SETTER:
            secFlag   = nsIXPCSecurityManager::HOOK_SET_PROPERTY;
            secAction = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
            break;
        default:
            NS_ASSERTION(0,"bad value");
            return JS_FALSE;
    }
    jsval name = member->GetName();

    nsIXPCSecurityManager* sm = xpcc->GetAppropriateSecurityManager(secFlag);
    XPCWrappedNative* wrapper = ccx.GetWrapper();
    if(sm && NS_FAILED(sm->CanAccess(secAction, &ccx, ccx,
                                     ccx.GetFlattenedJSObject(),
                                     wrapper->GetIdentityObject(),
                                     wrapper->GetClassInfo(), name,
                                     wrapper->GetSecurityInfoAddr())))
    {
        // the security manager vetoed. It should have set an exception.
        return JS_FALSE;
    }

    IDispatch * pObj = reinterpret_cast<IDispatch*>
                                       (ccx.GetTearOff()->GetNative());
    PRUint32 args = member->GetParamCount();
    uintN err;
    // Make sure setter has one argument
    if(mode == CALL_SETTER)
        args = 1;
    // Allow for optional parameters. We'll let COM handle the error if there
    // are not enough parameters
    if(argc < args)
        args = argc;
    XPCDispParams * params = new XPCDispParams(args);
    jsval val;
    // If this is a setter, we just need to convert the first parameter
    if(mode == CALL_SETTER)
    {
        params->SetNamedPropID();
        if(!XPCDispConvert::JSToCOM(ccx, argv[0], params->GetParamRef(0), err))
        {
            delete params;
            return ThrowBadParam(err, 0, ccx);
        }
    }
    else if(mode != CALL_GETTER)    // This is a function
    {
        // Convert the arguments to the function
        for(PRUint32 index = 0; index < args; ++index)
        {
            const XPCDispInterface::Member::ParamInfo & paramInfo = member->GetParamInfo(index);
            if(paramInfo.IsIn())
            {
                val = argv[index];
                if(paramInfo.IsOut())
                {
                    if(JSVAL_IS_PRIMITIVE(val) ||
                        !OBJ_GET_PROPERTY(ccx, JSVAL_TO_OBJECT(val),
                                          rt->GetStringID(XPCJSRuntime::IDX_VALUE),
                                          &val))
                    {
                        delete params;
                        return ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, index, ccx);
                    }
                    paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
                }
                if(!XPCDispConvert::JSToCOM(ccx, val, params->GetParamRef(index), err, paramInfo.IsOut()))
                {
                    delete params;
                    return ThrowBadParam(err, index, ccx);
                }
            }
            else
            {
                paramInfo.InitializeOutputParam(params->GetOutputBuffer(index), params->GetParamRef(index));
            }
        }
    }
    // If this is a parameterized property
    if(member->IsParameterizedProperty())
    {
        // We need to get a parameterized property object to return to JS
        // NewInstance takes ownership of params
        if(XPCDispParamPropJSClass::NewInstance(ccx, wrapper,
                                                member->GetDispID(),
                                                params, &val))
        {
            ccx.SetRetVal(val);
            if(!JS_IdToValue(ccx, 1, &val))
            {
                // This shouldn't fail
                NS_ERROR("JS_IdToValue failed in XPCDispParamPropJSClass::NewInstance");
                return JS_FALSE;
            }
            JS_SetCallReturnValue2(ccx, val);
            return JS_TRUE;
        }
        // NewInstance would only fail if there was an out of memory problem
        JS_ReportOutOfMemory(ccx);
        delete params;
        return JS_FALSE;
    }
    JSBool retval = Dispatch(ccx, pObj, member->GetDispID(), mode, params, &val, member, rt);
    if(retval && mode == CALL_SETTER)
    {
        ccx.SetRetVal(argv[0]);
    }
    else
    {
        ccx.SetRetVal(val);
    }
    delete params;
    return retval;
}