diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index a2e76106a72..f5bffba5b65 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -225,6 +225,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager [noscript] void checkSameOriginPrincipal(in nsIPrincipal aSourcePrincipal, in nsIPrincipal aTargetPrincipal); + /** + * Returns the principal of the global object of the given context, or null + * if no global or no principal. + */ + [noscript] nsIPrincipal getPrincipalFromContext(in JSContextPtr cx); + }; %{C++ diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 9ca0c2fe294..197785edb6a 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -1753,6 +1753,28 @@ nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI, return NS_OK; } +nsresult +nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx, + nsIPrincipal **result) +{ + *result = nsnull; + NS_ENSURE_TRUE(::JS_GetOptions(cx) & JSOPTION_PRIVATE_IS_NSISUPPORTS, + NS_ERROR_FAILURE); + nsISupports* scriptContextSupports = + NS_REINTERPRET_CAST(nsISupports*, JS_GetContextPrivate(cx)); + nsCOMPtr scriptContext(do_QueryInterface(scriptContextSupports)); + + if (scriptContext) + { + nsCOMPtr global; + scriptContext->GetGlobalObject(getter_AddRefs(global)); + nsCOMPtr globalData(do_QueryInterface(global)); + if (globalData) + globalData->GetPrincipal(result); + } + return NS_OK; +} + nsresult nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx, JSScript *script, diff --git a/js/src/liveconnect/Makefile.in b/js/src/liveconnect/Makefile.in index 998e9f25721..a7ad00bc3cb 100644 --- a/js/src/liveconnect/Makefile.in +++ b/js/src/liveconnect/Makefile.in @@ -49,6 +49,9 @@ REQUIRES = js \ xpcom \ xpconnect \ java \ + caps \ + necko \ + string \ $(NULL) CSRCS = \ diff --git a/js/src/liveconnect/nsCLiveconnect.cpp b/js/src/liveconnect/nsCLiveconnect.cpp index 5b68719296c..d6a153593c0 100644 --- a/js/src/liveconnect/nsCLiveconnect.cpp +++ b/js/src/liveconnect/nsCLiveconnect.cpp @@ -48,8 +48,7 @@ #include "jsj_private.h" #include "jsjava.h" -#include "jscntxt.h" /* For js_ReportErrorAgain(). - TODO - get rid of private header */ +#include "jscntxt.h" /* For js_ReportErrorAgain().*/ #include "netscape_javascript_JSObject.h" /* javah-generated headers */ #include "nsISecurityContext.h" @@ -70,6 +69,57 @@ PR_END_EXTERN_C #include "nsCLiveconnect.h" +#include "jsinterp.h" // XXX private API so we can auto-push a JSStackFrame + +#include "nsIPrincipal.h" +#include "nsNetUtil.h" +#include "nsISecurityContext.h" +#include "nsIScriptSecurityManager.h" +#include "prmem.h" + +static nsresult +CreatePrincipal(nsISupports* securitySupports, + nsIPrincipal ** outPrincipal) +{ + nsresult rv; + nsCOMPtr securityContext( + do_QueryInterface(securitySupports, &rv)); + if (NS_FAILED(rv)) return rv; + + char originBuf1[512]; + char* origin = originBuf1; + size_t originSize = sizeof(originBuf1); + rv = securityContext->GetOrigin(origin, originSize); + while (NS_FAILED(rv) && originSize < 65536U) + { // Try allocating a larger buffer on the heap + if (origin != originBuf1) + PR_Free(origin); + originSize *= 2; + origin = (char*)PR_Malloc(originSize); + if (!origin) + return NS_ERROR_OUT_OF_MEMORY; + rv = securityContext->GetOrigin(origin, originSize); + } + if (NS_FAILED(rv)) + { + if (origin != originBuf1) + PR_Free(origin); + return rv; + } + + nsCOMPtr originURI; + rv = NS_NewURI(getter_AddRefs(originURI), origin); + if (origin != originBuf1) + PR_Free(origin); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr secMan( + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv)); + if (NS_FAILED(rv)) return rv; + + return secMan->GetCodebasePrincipal(originURI, outPrincipal); +} + /***************************************************************************/ // A class to put on the stack to manage JS contexts when we are entering JS. // This pushes and pops the given context @@ -81,41 +131,104 @@ PR_END_EXTERN_C class AutoPushJSContext { public: - AutoPushJSContext(JSContext *cx) - { - mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + AutoPushJSContext(nsISupports* aSecuritySupports, JSContext *cx); - if(mContextStack) - { - JSContext* currentCX; - if(NS_SUCCEEDED(mContextStack->Peek(¤tCX))) - { - // Is the current context already on the stack? - if(cx == currentCX) - mContextStack = nsnull; - else - { - mContextStack->Push(cx); - // Leave the reference to the mContextStack to - // indicate that we need to pop it in our dtor. - } - } - } - } + ~AutoPushJSContext(); - ~AutoPushJSContext() - { - if(mContextStack) - { - mContextStack->Pop(nsnull); - mContextStack = nsnull; - } - } + nsresult ResultOfPush() { return mPushResult; }; private: nsCOMPtr mContextStack; + JSContext* mContext; + JSStackFrame mFrame; + nsresult mPushResult; }; +AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports, + JSContext *cx) + : mContext(cx), mPushResult(NS_OK) +{ + mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + + if(mContextStack) + { + JSContext* currentCX; + if(NS_SUCCEEDED(mContextStack->Peek(¤tCX))) + { + // Is the current context already on the stack? + if(cx == currentCX) + mContextStack = nsnull; + else + { + mContextStack->Push(cx); + // Leave the reference to the mContextStack to + // indicate that we need to pop it in our dtor. + } + + } + } + + memset(&mFrame, 0, sizeof(mFrame)); + + // See if there are any scripts on the stack. + // If not, we need to add a dummy frame with a principal. + PRBool hasScript = PR_FALSE; + JSStackFrame* tempFP = cx->fp; + while (tempFP) + { + if (tempFP->script) + { + hasScript = PR_TRUE; + break; + } + tempFP = tempFP->down; + }; + + if (!hasScript) + { + nsCOMPtr principal; + if (aSecuritySupports) + mPushResult = CreatePrincipal(aSecuritySupports, getter_AddRefs(principal)); + else + { + nsCOMPtr secMan( + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &mPushResult)); + if (NS_SUCCEEDED(mPushResult)) + mPushResult = secMan->GetPrincipalFromContext(cx, getter_AddRefs(principal)); + } + + if (NS_SUCCEEDED(mPushResult)) + { + JSPrincipals* jsprinc; + principal->GetJSPrincipals(&jsprinc); + + mFrame.script = JS_CompileScriptForPrincipals(cx, JS_GetGlobalObject(cx), + jsprinc, "", 0, "", 1); + JSPRINCIPALS_DROP(cx, jsprinc); + + if (mFrame.script) + { + mFrame.down = cx->fp; + cx->fp = &mFrame; + } + else + mPushResult = NS_ERROR_OUT_OF_MEMORY; + } + else + JS_ReportError(cx, "failed to get a principal"); + } +} + +AutoPushJSContext::~AutoPushJSContext() +{ + if (mContextStack) + mContextStack->Pop(nsnull); + + if (mFrame.script) + mContext->fp = mFrame.down; + +} + //////////////////////////////////////////////////////////////////////////// // from nsISupports and AggregatedQueryInterface: @@ -182,7 +295,9 @@ nsCLiveconnect::GetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize l if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; if (!name) { JS_ReportError(cx, "illegal null member name"); @@ -238,7 +353,9 @@ nsCLiveconnect::GetSlot(JNIEnv *jEnv, jsobject obj, jint slot, void* principalsA if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; // =-= sudu: check to see if slot can be passed in as is. // Should it be converted to a jsint? @@ -286,7 +403,9 @@ nsCLiveconnect::SetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize l if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; if (!name) { JS_ReportError(cx, "illegal null member name"); @@ -334,7 +453,9 @@ nsCLiveconnect::SetSlot(JNIEnv *jEnv, jsobject obj, jint slot, jobject java_obj, if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val)) goto done; @@ -373,7 +494,9 @@ nsCLiveconnect::RemoveMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsiz if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; if (!name) { JS_ReportError(cx, "illegal null member name"); @@ -425,9 +548,11 @@ nsCLiveconnect::Call(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize length if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); - result = NULL; + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; + if (!name) { JS_ReportError(cx, "illegal null JavaScript function name"); goto done; @@ -502,9 +627,11 @@ nsCLiveconnect::Eval(JNIEnv *jEnv, jsobject obj, const jchar *script, jsize leng if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); - result = NULL; + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; + if (!script) { JS_ReportError(cx, "illegal null string eval argument"); goto done; @@ -571,9 +698,11 @@ nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *pJavaObject, void* principalsArra if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); - err_msg = NULL; + AutoPushJSContext autopush(securitySupports, cx); + if (NS_FAILED(autopush.ResultOfPush())) + goto done; + js_obj = JSJ_callbacks->map_java_object_to_js_object(jEnv, mJavaClient, &err_msg); if (!js_obj) { if (err_msg) { @@ -650,9 +779,11 @@ nsCLiveconnect::ToString(JNIEnv *jEnv, jsobject obj, jstring *pjstring) if (!jsj_env) return NS_ERROR_FAILURE; - AutoPushJSContext autopush(cx); - result = NULL; + AutoPushJSContext autopush(nsnull, cx); + if (NS_FAILED(autopush.ResultOfPush())) + return NS_ERROR_FAILURE; + jsstr = JS_ValueToString(cx, OBJECT_TO_JSVAL(js_obj)); if (jsstr) result = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);