From 3cba7a04aec17a14a926abf9c1f72752a690a72d Mon Sep 17 00:00:00 2001 From: "mstoltz%netscape.com" Date: Fri, 14 Jun 2002 23:54:18 +0000 Subject: [PATCH] 133170 - Need to re-check host for security on a redirect after a call to XMLHttpRequest.open(). For xmlextras, r=heikki, sr=jband. For caps, r=bzbarsky, sr=jst 147754 - Add same-origin check to XMLSerializer. Patch by jst. r=mstoltz, sr=jband 113351 - Add same-origin check to XSL Include. Patch by peterv and jst, r=mstoltz, sr=rpotts 135267 - Add same-origin check to stylesheets included via LINK tags. r=dveditz, sr=scc git-svn-id: svn://10.0.0.236/trunk@123373 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/caps/idl/nsIScriptSecurityManager.idl | 14 + .../caps/include/nsScriptSecurityManager.h | 13 +- mozilla/caps/src/caps.properties | 5 +- mozilla/caps/src/nsCertificatePrincipal.cpp | 4 +- mozilla/caps/src/nsCodebasePrincipal.cpp | 135 +------ mozilla/caps/src/nsScriptSecurityManager.cpp | 353 +++++++++++++++--- .../content/base/src/nsSyncLoadService.cpp | 77 +++- .../html/style/src/nsCSSStyleSheet.cpp | 32 ++ mozilla/content/xml/document/src/Makefile.in | 1 + mozilla/content/xml/document/src/makefile.win | 1 + .../xml/document/src/nsXMLDocument.cpp | 87 ++++- .../content/xml/document/src/nsXMLDocument.h | 4 + .../source/xml/parser/Makefile.in | 1 - .../source/xml/parser/makefile.win | 1 - .../source/xml/parser/nsSyncLoader.cpp | 77 +++- .../source/xml/parser/nsSyncLoader.h | 12 +- .../extensions/xmlextras/base/src/Makefile.in | 1 + .../xmlextras/base/src/makefile.win | 1 + .../xmlextras/base/src/nsDOMSerializer.cpp | 63 +++- .../xmlextras/base/src/nsXMLHttpRequest.cpp | 93 +++++ .../xmlextras/base/src/nsXMLHttpRequest.h | 10 + mozilla/layout/style/nsCSSStyleSheet.cpp | 32 ++ 22 files changed, 804 insertions(+), 213 deletions(-) diff --git a/mozilla/caps/idl/nsIScriptSecurityManager.idl b/mozilla/caps/idl/nsIScriptSecurityManager.idl index 7b51341e15b..89d4f82df39 100644 --- a/mozilla/caps/idl/nsIScriptSecurityManager.idl +++ b/mozilla/caps/idl/nsIScriptSecurityManager.idl @@ -204,6 +204,20 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager */ boolean subjectPrincipalIsSystem(); + /** + * Returns OK if aJSContext and target have the same "origin" + * (scheme, host, and port). + */ + [noscript] void checkSameOrigin(in JSContextPtr aJSContext, + in nsIURI aTargetURI); + + /** + * Returns OK if aSourceURI and target have the same "origin" + * (scheme, host, and port). + */ + [noscript] void checkSameOriginURI(in nsIURI aSourceURI, + in nsIURI aTargetURI); + }; %{C++ diff --git a/mozilla/caps/include/nsScriptSecurityManager.h b/mozilla/caps/include/nsScriptSecurityManager.h index 8fc9d44719c..170a6b34be5 100644 --- a/mozilla/caps/include/nsScriptSecurityManager.h +++ b/mozilla/caps/include/nsScriptSecurityManager.h @@ -285,6 +285,11 @@ public: JSContext* GetSafeJSContext(); + static nsresult + SecurityCompareURIs(nsIURI* aSourceURI, + nsIURI* aTargetURI, + PRBool* result); + private: static JSBool JS_DLL_CALLBACK @@ -299,7 +304,8 @@ private: GetBaseURIScheme(nsIURI* aURI, char** aScheme); static nsresult - ReportErrorToConsole(nsIURI* aTarget); + ReportError(JSContext* cx, const nsAString& messageTag, + nsIURI* aSource, nsIURI* aTarget); nsresult GetRootDocShell(JSContext* cx, nsIDocShell **result); @@ -314,8 +320,9 @@ private: void** aCachedClassPolicy); nsresult - CheckSameOrigin(JSContext* aCx, nsIPrincipal* aSubject, - nsIPrincipal* aObject, PRUint32 aAction); + CheckSameOriginDOMProp(nsIPrincipal* aSubject, + nsIPrincipal* aObject, + PRUint32 aAction); PRInt32 GetSecurityLevel(nsIPrincipal *principal, diff --git a/mozilla/caps/src/caps.properties b/mozilla/caps/src/caps.properties index f51e82ae6ff..14f3486e4a5 100644 --- a/mozilla/caps/src/caps.properties +++ b/mozilla/caps/src/caps.properties @@ -15,11 +15,14 @@ # Copyright (C) 2000 Netscape Communications Corporation. All # Rights Reserved. # -# Contributor(s): +# Contributor(s): +# Mitch Stoltz # Yes = Yes No = No Titleline = Internet Security CheckMessage = Remember this decision EnableCapabilityQuery = A script from "%1$s" has requested enhanced privileges. You should grant these privileges only if you are comfortable downloading and executing a program from this source. Do you wish to allow these privileges? +CheckLoadURIError = Security Error: Content at %S may not load or link to %S. +CheckSameOriginError = Security Error: Content at %S may not load data from %S. diff --git a/mozilla/caps/src/nsCertificatePrincipal.cpp b/mozilla/caps/src/nsCertificatePrincipal.cpp index 5674aafa0c0..51c09bb3115 100644 --- a/mozilla/caps/src/nsCertificatePrincipal.cpp +++ b/mozilla/caps/src/nsCertificatePrincipal.cpp @@ -65,7 +65,7 @@ NS_IMETHODIMP nsCertificatePrincipal::GetCertificateID(char** aCertificateID) { *aCertificateID = nsCRT::strdup(mCertificateID); - return *mCertificateID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return *aCertificateID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } NS_IMETHODIMP @@ -80,7 +80,7 @@ nsCertificatePrincipal::SetCommonName(const char* aCommonName) { PR_FREEIF(mCommonName); mCommonName = nsCRT::strdup(aCommonName); - return * mCommonName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return mCommonName ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } /////////////////////////////////////// diff --git a/mozilla/caps/src/nsCodebasePrincipal.cpp b/mozilla/caps/src/nsCodebasePrincipal.cpp index 2e06cae3720..f6fb0c2572f 100644 --- a/mozilla/caps/src/nsCodebasePrincipal.cpp +++ b/mozilla/caps/src/nsCodebasePrincipal.cpp @@ -49,6 +49,7 @@ #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsCRT.h" +#include "nsScriptSecurityManager.h" NS_IMPL_QUERY_INTERFACE3_CI(nsCodebasePrincipal, nsICodebasePrincipal, @@ -179,129 +180,33 @@ nsCodebasePrincipal::GetSpec(char **spec) return *spec ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } - NS_IMETHODIMP -nsCodebasePrincipal::Equals(nsIPrincipal *other, PRBool *result) +nsCodebasePrincipal::Equals(nsIPrincipal *aOther, PRBool *result) { - // Equals is defined as object equality or same origin + if (this == aOther) + { + *result = PR_TRUE; + return NS_OK; + } *result = PR_FALSE; - if (this == other) - { - *result = PR_TRUE; - return NS_OK; - } - if (other == nsnull) - // return false + if (!aOther) return NS_OK; - // Get the other principal's URI - nsCOMPtr otherCodebase; - if (NS_FAILED(other->QueryInterface( - NS_GET_IID(nsICodebasePrincipal), - (void **) getter_AddRefs(otherCodebase)))) + // Get a URI from the other principal + nsCOMPtr otherCodebase( + do_QueryInterface(aOther)); + if (!otherCodebase) + { + // Other principal is not a codebase, so return false return NS_OK; + } nsCOMPtr otherURI; - if (NS_FAILED(otherCodebase->GetURI(getter_AddRefs(otherURI)))) - return NS_ERROR_FAILURE; + otherCodebase->GetURI(getter_AddRefs(otherURI)); - // If either uri is a jar URI, get the base URI - nsCOMPtr jarURI; - nsCOMPtr myBaseURI(mURI); - while((jarURI = do_QueryInterface(myBaseURI))) - { - jarURI->GetJARFile(getter_AddRefs(myBaseURI)); - } - while((jarURI = do_QueryInterface(otherURI))) - { - jarURI->GetJARFile(getter_AddRefs(otherURI)); - } - - if (!myBaseURI || !otherURI) - return NS_ERROR_FAILURE; - - // Compare schemes - nsCAutoString otherScheme; - nsresult rv = otherURI->GetScheme(otherScheme); - nsCAutoString myScheme; - if (NS_SUCCEEDED(rv)) - rv = myBaseURI->GetScheme(myScheme); - if (NS_SUCCEEDED(rv) && otherScheme.Equals(myScheme)) - { - if (otherScheme.Equals("file")) - { - // All file: urls are considered to have the same origin. - *result = PR_TRUE; - } - else if (otherScheme.Equals("imap") || - otherScheme.Equals("mailbox") || - otherScheme.Equals("news")) - { - // Each message is a distinct trust domain; use the - // whole spec for comparison - nsCAutoString otherSpec; - if (NS_FAILED(otherURI->GetSpec(otherSpec))) - return NS_ERROR_FAILURE; - nsCAutoString mySpec; - if (NS_FAILED(myBaseURI->GetSpec(mySpec))) - return NS_ERROR_FAILURE; - *result = otherSpec.Equals(mySpec); - } - else - { - // Compare hosts - nsCAutoString otherHost; - rv = otherURI->GetHost(otherHost); - nsCAutoString myHost; - if (NS_SUCCEEDED(rv)) - rv = myBaseURI->GetHost(myHost); - *result = NS_SUCCEEDED(rv) && otherHost.Equals(myHost); - if (*result) - { - // Compare ports - PRInt32 otherPort; - rv = otherURI->GetPort(&otherPort); - PRInt32 myPort; - if (NS_SUCCEEDED(rv)) - rv = myBaseURI->GetPort(&myPort); - *result = NS_SUCCEEDED(rv) && otherPort == myPort; - // If the port comparison failed, see if either URL has a - // port of -1. If so, replace -1 with the default port - // for that scheme. - if(!*result && (myPort == -1 || otherPort == -1)) - { - PRInt32 defaultPort; - //XXX had to hard-code the defualt port for http(s) here. - // remove this after darin fixes bug 113206 - if (myScheme.Equals("http")) - defaultPort = 80; - else if (myScheme.Equals("https")) - defaultPort = 443; - else - { - nsCOMPtr ioService( - do_GetService(NS_IOSERVICE_CONTRACTID)); - if (!ioService) - return NS_ERROR_FAILURE; - nsCOMPtr protocolHandler; - rv = ioService->GetProtocolHandler(myScheme.get(), - getter_AddRefs(protocolHandler)); - if (NS_FAILED(rv)) - return rv; - - rv = protocolHandler->GetDefaultPort(&defaultPort); - if (NS_FAILED(rv) || defaultPort == -1) - return NS_OK; // No default port for this scheme - } - if (myPort == -1) - myPort = defaultPort; - else if (otherPort == -1) - otherPort = defaultPort; - *result = otherPort == myPort; - } - } - } - } - return NS_OK; + NS_ENSURE_TRUE(otherURI, NS_ERROR_FAILURE); + return nsScriptSecurityManager::SecurityCompareURIs(mURI, + otherURI, + result); } ////////////////////////////////////////// diff --git a/mozilla/caps/src/nsScriptSecurityManager.cpp b/mozilla/caps/src/nsScriptSecurityManager.cpp index fd25b77c7a3..adf5c9b4379 100644 --- a/mozilla/caps/src/nsScriptSecurityManager.cpp +++ b/mozilla/caps/src/nsScriptSecurityManager.cpp @@ -182,6 +182,141 @@ private: PRBool mMustFree; }; +/* Static function for comparing two URIs - for security purposes, + * two URIs are equivalent if their scheme, host, and port are equal. + */ +/*static*/ nsresult +nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI, + nsIURI* aTargetURI, + PRBool* result) +{ + nsresult rv; + *result = PR_FALSE; + + if (aSourceURI == aTargetURI) + { + *result = PR_TRUE; + return NS_OK; + } + if (aTargetURI == nsnull) + { + // return false + return NS_OK; + } + + // If either uri is a jar URI, get the base URI + nsCOMPtr jarURI; + nsCOMPtr sourceBaseURI(aSourceURI); + while((jarURI = do_QueryInterface(sourceBaseURI))) + { + jarURI->GetJARFile(getter_AddRefs(sourceBaseURI)); + } + nsCOMPtr targetBaseURI(aTargetURI); + while((jarURI = do_QueryInterface(targetBaseURI))) + { + jarURI->GetJARFile(getter_AddRefs(targetBaseURI)); + } + + if (!sourceBaseURI || !targetBaseURI) + return NS_ERROR_FAILURE; + + // Compare schemes + nsCAutoString targetScheme; + rv = targetBaseURI->GetScheme(targetScheme); + nsCAutoString sourceScheme; + if (NS_SUCCEEDED(rv)) + rv = sourceBaseURI->GetScheme(sourceScheme); + if (NS_SUCCEEDED(rv) && + targetScheme.Equals(sourceScheme, nsCaseInsensitiveCStringComparator())) + { + if (targetScheme.Equals(NS_LITERAL_CSTRING("file"), + nsCaseInsensitiveCStringComparator())) + { + // All file: urls are considered to have the same origin. + *result = PR_TRUE; + } + else if (targetScheme.Equals(NS_LITERAL_CSTRING("imap"), + nsCaseInsensitiveCStringComparator()) || + targetScheme.Equals(NS_LITERAL_CSTRING("mailbox"), + nsCaseInsensitiveCStringComparator()) || + targetScheme.Equals(NS_LITERAL_CSTRING("news"), + nsCaseInsensitiveCStringComparator())) + { + // Each message is a distinct trust domain; use the + // whole spec for comparison + nsCAutoString targetSpec; + if (NS_FAILED(targetBaseURI->GetSpec(targetSpec))) + return NS_ERROR_FAILURE; + nsCAutoString sourceSpec; + if (NS_FAILED(sourceBaseURI->GetSpec(sourceSpec))) + return NS_ERROR_FAILURE; + *result = targetSpec.Equals(sourceSpec); + } + else + { + // Compare hosts + nsCAutoString targetHost; + rv = targetBaseURI->GetHost(targetHost); + nsCAutoString sourceHost; + if (NS_SUCCEEDED(rv)) + rv = sourceBaseURI->GetHost(sourceHost); + *result = NS_SUCCEEDED(rv) && + targetHost.Equals(sourceHost, + nsCaseInsensitiveCStringComparator()); + if (*result) + { + // Compare ports + PRInt32 targetPort; + rv = targetBaseURI->GetPort(&targetPort); + PRInt32 sourcePort; + if (NS_SUCCEEDED(rv)) + rv = sourceBaseURI->GetPort(&sourcePort); + *result = NS_SUCCEEDED(rv) && targetPort == sourcePort; + // If the port comparison failed, see if either URL has a + // port of -1. If so, replace -1 with the default port + // for that scheme. + if (!*result && (sourcePort == -1 || targetPort == -1)) + { + PRInt32 defaultPort; + //XXX had to hard-code the defualt port for http(s) here. + // remove this after darin fixes bug 113206 + if (sourceScheme.Equals(NS_LITERAL_CSTRING("http"), + nsCaseInsensitiveCStringComparator())) + defaultPort = 80; + else if (sourceScheme.Equals(NS_LITERAL_CSTRING("https"), + nsCaseInsensitiveCStringComparator())) + defaultPort = 443; + else + { + nsCOMPtr ioService( + do_GetService(NS_IOSERVICE_CONTRACTID)); + if (!ioService) + return NS_ERROR_FAILURE; + nsCOMPtr protocolHandler; + rv = ioService->GetProtocolHandler(sourceScheme.get(), + getter_AddRefs(protocolHandler)); + if (NS_FAILED(rv)) + { + *result = PR_FALSE; + return NS_OK; + } + + rv = protocolHandler->GetDefaultPort(&defaultPort); + if (NS_FAILED(rv) || defaultPort == -1) + return NS_OK; // No default port for this scheme + } + if (sourcePort == -1) + sourcePort = defaultPort; + else if (targetPort == -1) + targetPort = defaultPort; + *result = targetPort == sourcePort; + } + } + } + } + return NS_OK; +} + //////////////////// // Policy Storage // //////////////////// @@ -342,6 +477,79 @@ nsScriptSecurityManager::CheckConnect(JSContext* cx, nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull); } +NS_IMETHODIMP +nsScriptSecurityManager::CheckSameOrigin(JSContext* cx, + nsIURI* aTargetURI) +{ + nsresult rv; + + // Get a context if necessary + if (!cx) + { + cx = GetCurrentJSContext(); + if (!cx) + return NS_OK; // No JS context, so allow access + } + + // Get a principal from the context + nsCOMPtr sourcePrincipal; + rv = GetSubjectPrincipal(cx, getter_AddRefs(sourcePrincipal)); + if (NS_FAILED(rv)) + return rv; + + if (!sourcePrincipal) + { + NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?"); + return NS_OK; + } + + PRBool equals = PR_FALSE; + rv = sourcePrincipal->Equals(mSystemPrincipal, &equals); + if (NS_SUCCEEDED(rv) && equals) + { + // This is a system (chrome) script, so allow access + return NS_OK; + } + + // Get a URI from the source principal + nsCOMPtr sourceCodebase( + do_QueryInterface(sourcePrincipal, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr sourceURI; + rv = sourceCodebase->GetURI(getter_AddRefs(sourceURI)); + NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE); + + // Compare origins + PRBool sameOrigin = PR_FALSE; + rv = SecurityCompareURIs(sourceURI, aTargetURI, &sameOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (!sameOrigin) + { + ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI); + return NS_ERROR_DOM_BAD_URI; + } + return NS_OK; +} + +NS_IMETHODIMP +nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI, + nsIURI* aTargetURI) +{ + nsresult rv; + PRBool sameOrigin = PR_FALSE; + rv = SecurityCompareURIs(aSourceURI, aTargetURI, &sameOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + if (!sameOrigin) + { + ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"), + aSourceURI, aTargetURI); + return NS_ERROR_DOM_BAD_URI; + } + return NS_OK; +} + nsresult nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, nsIXPCNativeCallContext* aCallContext, @@ -432,7 +640,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, #ifdef DEBUG_mstoltz printf("noAccess "); #endif - rv = NS_ERROR_DOM_SECURITY_ERR; + rv = NS_ERROR_DOM_PROP_ACCESS_DENIED; break; case SCRIPT_SECURITY_ALL_ACCESS: @@ -468,9 +676,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, NS_ERROR("CheckPropertyAccessImpl called without a target object or URL"); return NS_ERROR_FAILURE; } - rv = CheckSameOrigin( - cx, subjectPrincipal, objectPrincipal, - aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY); + rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal, aAction); break; } default: @@ -582,9 +788,11 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, } nsresult -nsScriptSecurityManager::CheckSameOrigin(JSContext *aCx, nsIPrincipal* aSubject, - nsIPrincipal* aObject, PRUint32 aAction) +nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject, + nsIPrincipal* aObject, + PRUint32 aAction) { + nsresult rv; /* ** Get origin of subject and object and compare. */ @@ -592,8 +800,8 @@ nsScriptSecurityManager::CheckSameOrigin(JSContext *aCx, nsIPrincipal* aSubject, return NS_OK; PRBool isSameOrigin = PR_FALSE; - if (NS_FAILED(aSubject->Equals(aObject, &isSameOrigin))) - return NS_ERROR_FAILURE; + rv = aSubject->Equals(aObject, &isSameOrigin); + NS_ENSURE_SUCCESS(rv, rv); if (isSameOrigin) return NS_OK; @@ -603,22 +811,22 @@ nsScriptSecurityManager::CheckSameOrigin(JSContext *aCx, nsIPrincipal* aSubject, if (objectCodebase) { nsXPIDLCString origin; - if (NS_FAILED(objectCodebase->GetOrigin(getter_Copies(origin)))) - return NS_ERROR_FAILURE; + rv = objectCodebase->GetOrigin(getter_Copies(origin)); + NS_ENSURE_SUCCESS(rv, rv); if (nsCRT::strcasecmp(origin, "about:blank") == 0) return NS_OK; } /* - ** If we failed the origin tests it still might be the case that we - ** are a signed script and have permissions to do this operation. - ** Check for that here + * If we failed the origin tests it still might be the case that we + * are a signed script and have permissions to do this operation. + * Check for that here. */ PRBool capabilityEnabled = PR_FALSE; const char* cap = aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY ? "UniversalBrowserWrite" : "UniversalBrowserRead"; - if (NS_FAILED(IsCapabilityEnabled(cap, &capabilityEnabled))) - return NS_ERROR_FAILURE; + rv = IsCapabilityEnabled(cap, &capabilityEnabled); + NS_ENSURE_SUCCESS(rv, rv); if (capabilityEnabled) return NS_OK; @@ -822,7 +1030,7 @@ nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI) nsCAutoString spec; if (NS_FAILED(aURI->GetAsciiSpec(spec))) return NS_ERROR_FAILURE; - JS_ReportError(cx, "illegal URL method '%s'", spec.get()); + JS_ReportError(cx, "Access to '%s' from script denied", spec.get()); return NS_ERROR_DOM_BAD_URI; } @@ -953,6 +1161,7 @@ nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI, { "res", DenyProtocol } }; + NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError"); for (unsigned i=0; i < sizeof(protocolList)/sizeof(protocolList[0]); i++) { if (nsCRT::strcasecmp(targetScheme, protocolList[i].name) == 0) @@ -967,7 +1176,12 @@ nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI, // Allow access if pref is false { mSecurityPref->SecurityGetBoolPref("security.checkloaduri", &doCheck); - return doCheck ? ReportErrorToConsole(aTargetURI) : NS_OK; + if (doCheck) + { + ReportError(nsnull, errorTag, aSourceURI, aTargetURI); + return NS_ERROR_DOM_BAD_URI; + } + return NS_OK; } case ChromeProtocol: if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) @@ -976,10 +1190,12 @@ nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI, if ((PL_strcmp(sourceScheme, "chrome") == 0) || (PL_strcmp(sourceScheme, "resource") == 0)) return NS_OK; - return ReportErrorToConsole(aTargetURI); + ReportError(nsnull, errorTag, aSourceURI, aTargetURI); + return NS_ERROR_DOM_BAD_URI; case DenyProtocol: // Deny access - return ReportErrorToConsole(aTargetURI); + ReportError(nsnull, errorTag, aSourceURI, aTargetURI); + return NS_ERROR_DOM_BAD_URI; } } } @@ -992,38 +1208,76 @@ nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI, return NS_OK; } +#define PROPERTIES_URL "chrome://communicator/locale/security/caps.properties" + nsresult -nsScriptSecurityManager::ReportErrorToConsole(nsIURI* aTarget) +nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag, + nsIURI* aSource, nsIURI* aTarget) { - nsCAutoString spec; - nsresult rv = aTarget->GetAsciiSpec(spec); - if (NS_FAILED(rv)) return rv; + nsresult rv; + NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER); - nsAutoString msg; - msg.Assign(NS_LITERAL_STRING("The link to ")); - msg.AppendWithConversion(spec.get()); - msg.Append(NS_LITERAL_STRING(" was blocked by the security manager.\nRemote content may not link to local content.")); - // Report error in JS console - nsCOMPtr console(do_GetService("@mozilla.org/consoleservice;1")); - if (console) + // First, create the error message text + // create a bundle for the localization + nsCOMPtr bundleService(do_GetService(kStringBundleServiceCID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr bundle; + rv = bundleService->CreateBundle(PROPERTIES_URL, getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the source URL spec + nsCAutoString sourceSpec; + rv = aSource->GetAsciiSpec(sourceSpec); + NS_ENSURE_SUCCESS(rv, rv); + + // Get the target URL spec + nsCAutoString targetSpec; + rv = aTarget->GetAsciiSpec(targetSpec); + NS_ENSURE_SUCCESS(rv, rv); + + // Localize the error message + nsXPIDLString message; + NS_ConvertASCIItoUCS2 ucsSourceSpec(sourceSpec); + NS_ConvertASCIItoUCS2 ucsTargetSpec(targetSpec); + const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() }; + rv = bundle->FormatStringFromName(PromiseFlatString(messageTag).get(), + formatStrings, + 2, + getter_Copies(message)); + NS_ENSURE_SUCCESS(rv, rv); + + // If a JS context was passed in, set a JS exception. + // Otherwise, print the error message directly to the JS console + // and to standard output + if (cx) { - PRUnichar* messageUni = ToNewUnicode(msg); - if (!messageUni) - return NS_ERROR_FAILURE; - console->LogStringMessage(messageUni); - nsMemory::Free(messageUni); + JS_SetPendingException(cx, + STRING_TO_JSVAL(JS_NewUCStringCopyZ(cx, + NS_REINTERPRET_CAST(const jschar*, message.get())))); + // Tell XPConnect that an exception was thrown, if appropriate + nsCOMPtr xpc = do_GetService(nsIXPConnect::GetCID()); + if (xpc) + { + nsCOMPtr xpcCallContext; + xpc->GetCurrentNativeCallContext(getter_AddRefs(xpcCallContext)); + if (xpcCallContext) + xpcCallContext->SetExceptionWasThrown(PR_TRUE); + } } -#ifdef DEBUG - char* messageCstr = ToNewCString(msg); - if (!messageCstr) - return NS_ERROR_FAILURE; - fprintf(stderr, "%s\n", messageCstr); - PR_Free(messageCstr); -#endif - //-- Always returns an error - return NS_ERROR_DOM_BAD_URI; -} + else // Print directly to the console + { + nsCOMPtr console( + do_GetService("@mozilla.org/consoleservice;1")); + NS_ENSURE_TRUE(console, NS_ERROR_FAILURE); + console->LogStringMessage(message.get()); +#ifdef DEBUG + fprintf(stderr, "%s\n", NS_LossyConvertUCS2toASCII(message).get()); +#endif + } + return NS_OK; +} NS_IMETHODIMP nsScriptSecurityManager::CheckLoadURIStr(const char* aSourceURIStr, const char* aTargetURIStr, @@ -1673,8 +1927,6 @@ nsScriptSecurityManager::IsCapabilityEnabled(const char *capability, return NS_OK; } -#define PROPERTIES_URL "chrome://communicator/locale/security/caps.properties" - PRBool nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal, PRBool *checkValue) @@ -1737,14 +1989,15 @@ nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrinci rv = aPrincipal->ToUserVisibleString(getter_Copies(source)); if (NS_FAILED(rv)) return PR_FALSE; - nsXPIDLString message; - message.Assign(nsTextFormatter::smprintf(query.get(), source.get())); + PRUnichar* message = nsTextFormatter::smprintf(query.get(), source.get()); + NS_ENSURE_TRUE(message, PR_FALSE); PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1) - rv = prompter->ConfirmEx(title.get(), message.get(), + rv = prompter->ConfirmEx(title.get(), message, (nsIPrompt::BUTTON_TITLE_YES * nsIPrompt::BUTTON_POS_0) + (nsIPrompt::BUTTON_TITLE_NO * nsIPrompt::BUTTON_POS_1), nsnull, nsnull, nsnull, check.get(), checkValue, &buttonPressed); + nsTextFormatter::smprintf_free(message); if (NS_FAILED(rv)) *checkValue = PR_FALSE; diff --git a/mozilla/content/base/src/nsSyncLoadService.cpp b/mozilla/content/base/src/nsSyncLoadService.cpp index 776943109c0..cc2505d20cd 100644 --- a/mozilla/content/base/src/nsSyncLoadService.cpp +++ b/mozilla/content/base/src/nsSyncLoadService.cpp @@ -38,16 +38,20 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSyncLoader.h" +#include "jsapi.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDOMDOMImplementation.h" #include "nsIDOMEventReceiver.h" #include "nsIEventQueueService.h" +#include "nsIJSContextStack.h" #include "nsIPrivateDOMImplementation.h" +#include "nsIScriptGlobalObject.h" #include "nsIScriptSecurityManager.h" -#include "nsLayoutCID.h" +#include "nsContentCID.h" #include "nsNetUtil.h" +#include "nsIHttpChannel.h" static const char* kLoadAsData = "loadAsData"; @@ -168,24 +172,36 @@ nsSyncLoader::~nsSyncLoader() } } -NS_IMPL_ISUPPORTS3(nsSyncLoader, nsISyncLoader, nsIDOMLoadListener, nsISupportsWeakReference) +NS_IMPL_ISUPPORTS5(nsSyncLoader, + nsISyncLoader, + nsIDOMLoadListener, + nsIHttpEventSink, + nsIInterfaceRequestor, + nsISupportsWeakReference) NS_IMETHODIMP -nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocument **_retval) +nsSyncLoader::LoadDocument(nsIURI* aDocumentURI, + nsIDocument *aLoader, + nsIDOMDocument **aResult) { - nsresult rv = NS_OK; + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; nsCOMPtr loaderURI; aLoader->GetDocumentURL(getter_AddRefs(loaderURI)); + nsresult rv = NS_OK; nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - rv = securityManager->CheckLoadURI(loaderURI, documentURI, + rv = securityManager->CheckLoadURI(loaderURI, aDocumentURI, nsIScriptSecurityManager::STANDARD); NS_ENSURE_SUCCESS(rv, rv); + rv = securityManager->CheckSameOriginURI(loaderURI, aDocumentURI); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr loadGroup; rv = aLoader->GetDocumentLoadGroup(getter_AddRefs(loadGroup)); NS_ENSURE_SUCCESS(rv, rv); @@ -197,7 +213,7 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu nsCOMPtr privImplementation(do_QueryInterface(implementation, &rv)); NS_ENSURE_SUCCESS(rv, rv); - privImplementation->Init(documentURI); + privImplementation->Init(aDocumentURI); // Create an empty document from it nsString emptyStr; @@ -208,7 +224,7 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu getter_AddRefs(DOMDocument)); NS_ENSURE_SUCCESS(rv, rv); - rv = NS_NewChannel(getter_AddRefs(mChannel), documentURI, nsnull, loadGroup); + rv = NS_NewChannel(getter_AddRefs(mChannel), aDocumentURI, nsnull, loadGroup); NS_ENSURE_SUCCESS(rv, rv); // Make sure we've been opened @@ -257,6 +273,9 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu PR_FALSE); if (NS_SUCCEEDED(rv)) { + // Hook us up to listen to redirects and the like + mChannel->SetNotificationCallbacks(this); + // Start reading from the channel rv = mChannel->AsyncOpen(listener, nsnull); @@ -291,15 +310,13 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu rv = target->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*, proxy), NS_GET_IID(nsIDOMLoadListener)); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr documentElement; DOMDocument->GetDocumentElement(getter_AddRefs(documentElement)); if (mLoadSuccess && documentElement) { - *_retval = DOMDocument; - NS_ADDREF(*_retval); + *aResult = DOMDocument; + NS_ADDREF(*aResult); } rv = service->PopThreadEventQueue(currentThreadQ); @@ -351,3 +368,39 @@ nsSyncLoader::Error(nsIDOMEvent* aEvent) return NS_OK; } + +NS_IMETHODIMP +nsSyncLoader::OnRedirect(nsIHttpChannel *aHttpChannel, + nsIChannel *aNewChannel) +{ + NS_ENSURE_ARG_POINTER(aNewChannel); + + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr oldURI; + rv = aHttpChannel->GetURI(getter_AddRefs(oldURI)); // The original URI + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOriginURI(oldURI, newURI); + + NS_ENSURE_SUCCESS(rv, rv); + + mChannel = aNewChannel; + + return NS_OK; +} + +NS_IMETHODIMP +nsSyncLoader::GetInterface(const nsIID & aIID, + void **aResult) +{ + return QueryInterface(aIID, aResult); +} diff --git a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp index 402f0951982..da6674fa99b 100644 --- a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp +++ b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp @@ -103,6 +103,8 @@ #endif #include "nsContentUtils.h" +#include "nsIJSContextStack.h" +#include "nsIScriptSecurityManager.h" // An |AtomKey| is to be used for storage in the hashtable, and a // |DependentAtomKey| should be used on the stack to avoid the performance @@ -2357,6 +2359,8 @@ CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const NS_IMETHODIMP CSSStyleSheetImpl::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const { + // Important: If this function is ever made scriptable, we must add + // a security check here. See GetCSSRules below for an example. nsresult result = NS_ERROR_ILLEGAL_VALUE; if (mInner && mInner->mOrderedRules) { @@ -2775,6 +2779,34 @@ CSSStyleSheetImpl::GetOwnerRule(nsIDOMCSSRule** aOwnerRule) NS_IMETHODIMP CSSStyleSheetImpl::GetCssRules(nsIDOMCSSRuleList** aCssRules) { + //-- Security check: Only scripts from the same origin as the + // style sheet can access rule collections + + // Get JSContext from stack + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE); + + JSContext *cx = nsnull; + nsresult rv = NS_OK; + + rv = stack->Peek(&cx); + NS_ENSURE_SUCCESS(rv, rv); + if (!cx) + return NS_ERROR_FAILURE; + + // Get the security manager and do the same-origin check + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOrigin(cx, mInner->mURL); + + if (NS_FAILED(rv)) { + return rv; + } + + // OK, security check passed, so get the rule collection if (nsnull == mRuleCollection) { mRuleCollection = new CSSRuleListImpl(this); if (nsnull == mRuleCollection) { diff --git a/mozilla/content/xml/document/src/Makefile.in b/mozilla/content/xml/document/src/Makefile.in index 8fe229fd0fd..c52d84b1d29 100644 --- a/mozilla/content/xml/document/src/Makefile.in +++ b/mozilla/content/xml/document/src/Makefile.in @@ -50,6 +50,7 @@ REQUIRES = xpcom \ exthandler \ mimetype \ unicharutil \ + windowwatcher \ $(NULL) CPPSRCS = \ diff --git a/mozilla/content/xml/document/src/makefile.win b/mozilla/content/xml/document/src/makefile.win index 3ad6434dd86..e98c2591faf 100644 --- a/mozilla/content/xml/document/src/makefile.win +++ b/mozilla/content/xml/document/src/makefile.win @@ -45,6 +45,7 @@ REQUIRES = xpcom \ gfx \ layout \ unicharutil \ + windowwatcher \ $(NULL) DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN diff --git a/mozilla/content/xml/document/src/nsXMLDocument.cpp b/mozilla/content/xml/document/src/nsXMLDocument.cpp index 5e0a3178e72..7b1f7708750 100644 --- a/mozilla/content/xml/document/src/nsXMLDocument.cpp +++ b/mozilla/content/xml/document/src/nsXMLDocument.cpp @@ -100,6 +100,8 @@ #include "nsContentUtils.h" #include "nsIElementFactory.h" #include "nsCRT.h" +#include "nsIWindowWatcher.h" +#include "nsIAuthPrompt.h" static NS_DEFINE_CID(kHTMLStyleSheetCID,NS_HTMLSTYLESHEET_CID); @@ -217,7 +219,8 @@ NS_NewXMLDocument(nsIDocument** aInstancePtrResult) nsXMLDocument::nsXMLDocument() : mAttrStyleSheet(nsnull), mInlineStyleSheet(nsnull), - mCountCatalogSheets(0), mParser(nsnull) + mCountCatalogSheets(0), mParser(nsnull), + mCrossSiteAccessEnabled(PR_FALSE) { } @@ -280,38 +283,76 @@ nsXMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) return result; } +///////////////////////////////////////////////////// +// nsIInterfaceRequestor methods: +// NS_IMETHODIMP nsXMLDocument::GetInterface(const nsIID& aIID, void** aSink) { - // Since we implement all the interfaces that you can get with - // GetInterface() we can simply call QueryInterface() here and let - // it do all the work. + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { + NS_ENSURE_ARG_POINTER(aSink); + *aSink = nsnull; + + nsresult rv; + nsCOMPtr ww(do_GetService("@mozilla.org/embedcomp/window-watcher;1", &rv)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr prompt; + rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt)); + if (NS_FAILED(rv)) + return rv; + + nsIAuthPrompt *p = prompt.get(); + NS_ADDREF(p); + *aSink = p; + return NS_OK; + } + return QueryInterface(aIID, aSink); } - // nsIHttpEventSink NS_IMETHODIMP nsXMLDocument::OnRedirect(nsIHttpChannel *aHttpChannel, nsIChannel *aNewChannel) { + NS_ENSURE_ARG_POINTER(aNewChannel); + nsresult rv; - nsCOMPtr securityManager = + nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - - if (NS_FAILED(rv)) - return NS_ERROR_FAILURE; + if (NS_FAILED(rv)) + return rv; nsCOMPtr newLocation; - rv = aNewChannel->GetURI(getter_AddRefs(newLocation)); + rv = aNewChannel->GetURI(getter_AddRefs(newLocation)); // The redirected URI + if (NS_FAILED(rv)) + return rv; - if (NS_FAILED(rv)) - return NS_ERROR_FAILURE; + if (mScriptContext && !mCrossSiteAccessEnabled) { + nsCOMPtr stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", & rv)); + if (NS_FAILED(rv)) + return rv; + + JSContext *cx = (JSContext *)mScriptContext->GetNativeContext(); + if (!cx) + return NS_ERROR_UNEXPECTED; + + stack->Push(cx); + + rv = secMan->CheckSameOrigin(nsnull, newLocation); + + stack->Pop(&cx); + + if (NS_FAILED(rv)) + return rv; + } nsCOMPtr newCodebase; - rv = securityManager->GetCodebasePrincipal(newLocation, - getter_AddRefs(newCodebase)); + rv = secMan->GetCodebasePrincipal(newLocation, + getter_AddRefs(newCodebase)); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; @@ -365,6 +406,24 @@ nsXMLDocument::Load(const nsAString& aUrl) SetDocumentURL(uri); SetBaseURL(uri); + // Store script context, if any, in case we encounter redirect (because we need it there) + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + if (stack) { + JSContext *cx; + if (NS_SUCCEEDED(stack->Peek(&cx)) && cx) { + nsISupports *priv = (nsISupports *)::JS_GetContextPrivate(cx); + if (priv) { + priv->QueryInterface(NS_GET_IID(nsIScriptContext), getter_AddRefs(mScriptContext)); + } + } + } + + // Find out if UniversalBrowserRead privileges are enabled - we will need this + // in case of a redirect + rv = secMan->IsCapabilityEnabled("UniversalBrowserRead", &mCrossSiteAccessEnabled); + if (NS_FAILED(rv)) return rv; + // Create a channel rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, nsnull, this); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/content/xml/document/src/nsXMLDocument.h b/mozilla/content/xml/document/src/nsXMLDocument.h index fe024f48084..d8415cd1d53 100644 --- a/mozilla/content/xml/document/src/nsXMLDocument.h +++ b/mozilla/content/xml/document/src/nsXMLDocument.h @@ -46,6 +46,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIHttpEventSink.h" #include "nsIDOMXMLDocument.h" +#include "nsIScriptContext.h" class nsIParser; class nsIDOMNode; @@ -139,6 +140,9 @@ protected: nsString mBaseTarget; nsIParser *mParser; + + nsCOMPtr mScriptContext; + PRBool mCrossSiteAccessEnabled; }; diff --git a/mozilla/extensions/transformiix/source/xml/parser/Makefile.in b/mozilla/extensions/transformiix/source/xml/parser/Makefile.in index 3ad53107718..dac71cd7fc0 100644 --- a/mozilla/extensions/transformiix/source/xml/parser/Makefile.in +++ b/mozilla/extensions/transformiix/source/xml/parser/Makefile.in @@ -32,7 +32,6 @@ REQUIRES = string \ xpcom \ necko \ dom \ - layout \ content \ widget \ js \ diff --git a/mozilla/extensions/transformiix/source/xml/parser/makefile.win b/mozilla/extensions/transformiix/source/xml/parser/makefile.win index 3d1600b2842..29280ab81c8 100644 --- a/mozilla/extensions/transformiix/source/xml/parser/makefile.win +++ b/mozilla/extensions/transformiix/source/xml/parser/makefile.win @@ -25,7 +25,6 @@ REQUIRES = string \ xpcom \ necko \ dom \ - layout \ widget \ js \ appshell \ diff --git a/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.cpp b/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.cpp index 776943109c0..cc2505d20cd 100644 --- a/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.cpp +++ b/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.cpp @@ -38,16 +38,20 @@ * ***** END LICENSE BLOCK ***** */ #include "nsSyncLoader.h" +#include "jsapi.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMElement.h" #include "nsIDOMDOMImplementation.h" #include "nsIDOMEventReceiver.h" #include "nsIEventQueueService.h" +#include "nsIJSContextStack.h" #include "nsIPrivateDOMImplementation.h" +#include "nsIScriptGlobalObject.h" #include "nsIScriptSecurityManager.h" -#include "nsLayoutCID.h" +#include "nsContentCID.h" #include "nsNetUtil.h" +#include "nsIHttpChannel.h" static const char* kLoadAsData = "loadAsData"; @@ -168,24 +172,36 @@ nsSyncLoader::~nsSyncLoader() } } -NS_IMPL_ISUPPORTS3(nsSyncLoader, nsISyncLoader, nsIDOMLoadListener, nsISupportsWeakReference) +NS_IMPL_ISUPPORTS5(nsSyncLoader, + nsISyncLoader, + nsIDOMLoadListener, + nsIHttpEventSink, + nsIInterfaceRequestor, + nsISupportsWeakReference) NS_IMETHODIMP -nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocument **_retval) +nsSyncLoader::LoadDocument(nsIURI* aDocumentURI, + nsIDocument *aLoader, + nsIDOMDocument **aResult) { - nsresult rv = NS_OK; + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; nsCOMPtr loaderURI; aLoader->GetDocumentURL(getter_AddRefs(loaderURI)); + nsresult rv = NS_OK; nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - rv = securityManager->CheckLoadURI(loaderURI, documentURI, + rv = securityManager->CheckLoadURI(loaderURI, aDocumentURI, nsIScriptSecurityManager::STANDARD); NS_ENSURE_SUCCESS(rv, rv); + rv = securityManager->CheckSameOriginURI(loaderURI, aDocumentURI); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr loadGroup; rv = aLoader->GetDocumentLoadGroup(getter_AddRefs(loadGroup)); NS_ENSURE_SUCCESS(rv, rv); @@ -197,7 +213,7 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu nsCOMPtr privImplementation(do_QueryInterface(implementation, &rv)); NS_ENSURE_SUCCESS(rv, rv); - privImplementation->Init(documentURI); + privImplementation->Init(aDocumentURI); // Create an empty document from it nsString emptyStr; @@ -208,7 +224,7 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu getter_AddRefs(DOMDocument)); NS_ENSURE_SUCCESS(rv, rv); - rv = NS_NewChannel(getter_AddRefs(mChannel), documentURI, nsnull, loadGroup); + rv = NS_NewChannel(getter_AddRefs(mChannel), aDocumentURI, nsnull, loadGroup); NS_ENSURE_SUCCESS(rv, rv); // Make sure we've been opened @@ -257,6 +273,9 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu PR_FALSE); if (NS_SUCCEEDED(rv)) { + // Hook us up to listen to redirects and the like + mChannel->SetNotificationCallbacks(this); + // Start reading from the channel rv = mChannel->AsyncOpen(listener, nsnull); @@ -291,15 +310,13 @@ nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocu rv = target->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*, proxy), NS_GET_IID(nsIDOMLoadListener)); - if (NS_FAILED(rv)) { - return rv; - } + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr documentElement; DOMDocument->GetDocumentElement(getter_AddRefs(documentElement)); if (mLoadSuccess && documentElement) { - *_retval = DOMDocument; - NS_ADDREF(*_retval); + *aResult = DOMDocument; + NS_ADDREF(*aResult); } rv = service->PopThreadEventQueue(currentThreadQ); @@ -351,3 +368,39 @@ nsSyncLoader::Error(nsIDOMEvent* aEvent) return NS_OK; } + +NS_IMETHODIMP +nsSyncLoader::OnRedirect(nsIHttpChannel *aHttpChannel, + nsIChannel *aNewChannel) +{ + NS_ENSURE_ARG_POINTER(aNewChannel); + + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr oldURI; + rv = aHttpChannel->GetURI(getter_AddRefs(oldURI)); // The original URI + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOriginURI(oldURI, newURI); + + NS_ENSURE_SUCCESS(rv, rv); + + mChannel = aNewChannel; + + return NS_OK; +} + +NS_IMETHODIMP +nsSyncLoader::GetInterface(const nsIID & aIID, + void **aResult) +{ + return QueryInterface(aIID, aResult); +} diff --git a/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.h b/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.h index a282885aff5..ab61f487096 100644 --- a/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.h +++ b/mozilla/extensions/transformiix/source/xml/parser/nsSyncLoader.h @@ -43,12 +43,17 @@ #include "nsCOMPtr.h" #include "nsIChannel.h" #include "nsIDOMLoadListener.h" +#include "nsIHttpEventSink.h" +#include "nsIInterfaceRequestor.h" +#include "nsIScriptContext.h" #include "nsISyncLoader.h" #include "nsString.h" #include "nsWeakReference.h" class nsSyncLoader : public nsISyncLoader, public nsIDOMLoadListener, + public nsIHttpEventSink, + public nsIInterfaceRequestor, public nsSupportsWeakReference { public: @@ -68,9 +73,14 @@ public: NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_DECL_NSIHTTPEVENTSINK + + NS_DECL_NSIINTERFACEREQUESTOR + protected: nsCOMPtr mChannel; - PRBool mLoading, mLoadSuccess; + PRPackedBool mLoading; + PRPackedBool mLoadSuccess; }; #endif diff --git a/mozilla/extensions/xmlextras/base/src/Makefile.in b/mozilla/extensions/xmlextras/base/src/Makefile.in index 7e29425d3cc..78cdb5a060a 100644 --- a/mozilla/extensions/xmlextras/base/src/Makefile.in +++ b/mozilla/extensions/xmlextras/base/src/Makefile.in @@ -43,6 +43,7 @@ REQUIRES = xpcom \ xpconnect \ webbrwsr \ htmlparser \ + windowwatcher \ $(NULL) CPPSRCS = \ diff --git a/mozilla/extensions/xmlextras/base/src/makefile.win b/mozilla/extensions/xmlextras/base/src/makefile.win index 63dbe5e260d..26b6efc0770 100644 --- a/mozilla/extensions/xmlextras/base/src/makefile.win +++ b/mozilla/extensions/xmlextras/base/src/makefile.win @@ -38,6 +38,7 @@ REQUIRES = xpcom \ content \ gfx \ htmlparser \ + windowwatcher \ $(NULL) DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN diff --git a/mozilla/extensions/xmlextras/base/src/nsDOMSerializer.cpp b/mozilla/extensions/xmlextras/base/src/nsDOMSerializer.cpp index 8fb9ac1c3d8..ba457e665af 100644 --- a/mozilla/extensions/xmlextras/base/src/nsDOMSerializer.cpp +++ b/mozilla/extensions/xmlextras/base/src/nsDOMSerializer.cpp @@ -49,6 +49,11 @@ #include "nsString.h" #include "nsReadableUtils.h" +#include "nsIJSContextStack.h" +#include "nsIScriptSecurityManager.h" +#include "nsICodebasePrincipal.h" +#include "nsIURI.h" + #include "nsLayoutCID.h" // XXX Need range CID static NS_DEFINE_CID(kRangeCID,NS_RANGE_CID); @@ -136,8 +141,64 @@ nsDOMSerializer::SerializeToString(nsIDOMNode *root, PRUnichar **_retval) *_retval = nsnull; + // Get JSContext from stack. + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + + JSContext *cx = nsnull; + nsresult rv = NS_OK; + + if (stack) { + rv = stack->Peek(&cx); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (cx) { + // We're called from script, make sure the caller and the root are + // from the same origin... + + nsCOMPtr owner_doc(do_QueryInterface(root)); + + if (!owner_doc) { + root->GetOwnerDocument(getter_AddRefs(owner_doc)); + } + + nsCOMPtr doc(do_QueryInterface(owner_doc)); + + if (doc) { + nsCOMPtr principal; + nsCOMPtr root_uri; + + doc->GetPrincipal(getter_AddRefs(principal)); + + nsCOMPtr codebase_principal = + do_QueryInterface(principal); + + if (codebase_principal) { + codebase_principal->GetURI(getter_AddRefs(root_uri)); + } + + if (root_uri) { + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOrigin(cx, root_uri); + + if (NS_FAILED(rv)) { + // The node that's being serialized comes from a different + // origin than the calling script comes from... + + return rv; + } + } + } + } + + // We're ok security wise... + nsCOMPtr encoder; - nsresult rv = SetUpEncoder(root,nsnull,getter_AddRefs(encoder)); + rv = SetUpEncoder(root,nsnull,getter_AddRefs(encoder)); if (NS_FAILED(rv)) return rv; diff --git a/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp b/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp index 23666584a01..943f7f9d89b 100644 --- a/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp +++ b/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp @@ -82,6 +82,8 @@ #include "nsIVariant.h" #include "nsIParser.h" #include "nsLoadListenerProxy.h" +#include "nsIWindowWatcher.h" +#include "nsIAuthPrompt.h" static const char* kLoadAsData = "loadAsData"; #define LOADSTR NS_LITERAL_STRING("load") @@ -139,6 +141,7 @@ nsXMLHttpRequest::nsXMLHttpRequest() NS_INIT_ISUPPORTS(); ChangeState(XML_HTTP_REQUEST_UNINITIALIZED,PR_FALSE); mAsync = PR_TRUE; + mCrossSiteAccessEnabled = PR_FALSE; } nsXMLHttpRequest::~nsXMLHttpRequest() @@ -163,6 +166,8 @@ NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) NS_INTERFACE_MAP_ENTRY(nsIStreamListener) + NS_INTERFACE_MAP_ENTRY(nsIHttpEventSink) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(XMLHttpRequest) NS_INTERFACE_MAP_END @@ -661,6 +666,12 @@ nsXMLHttpRequest::Open(const char *method, const char *url) return NS_OK; } + // Find out if UniversalBrowserRead privileges are enabled + // we will need this in case of a redirect + rv = secMan->IsCapabilityEnabled("UniversalBrowserRead", + &mCrossSiteAccessEnabled); + if (NS_FAILED(rv)) return rv; + if (argc > 2) { JSBool asyncBool; JS_ValueToBoolean(cx, argv[2], &asyncBool); @@ -1194,6 +1205,11 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) } #endif + if (!mScriptContext) { + // We need a context to check if redirect (if any) is allowed + GetCurrentContext(getter_AddRefs(mScriptContext)); + } + rv = document->StartDocumentLoad(kLoadAsData, mChannel, nsnull, nsnull, getter_AddRefs(listener), @@ -1210,6 +1226,9 @@ nsXMLHttpRequest::Send(nsIVariant *aBody) if (NS_FAILED(rv)) return NS_ERROR_FAILURE; #endif + // Hook us up to listen to redirects and the like + mChannel->SetNotificationCallbacks(this); + // Start reading from the channel ChangeState(XML_HTTP_REQUEST_SENT); mXMLParserStreamListener = listener; @@ -1429,6 +1448,80 @@ nsXMLHttpRequest::ChangeState(nsXMLHttpRequestState aState, PRBool aBroadcast) return rv; } +///////////////////////////////////////////////////// +// nsIHttpEventSink methods: +// +NS_IMETHODIMP +nsXMLHttpRequest::OnRedirect(nsIHttpChannel *aHttpChannel, nsIChannel *aNewChannel) +{ + NS_ENSURE_ARG_POINTER(aNewChannel); + + if (mScriptContext && !mCrossSiteAccessEnabled) { + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", & rv)); + if (NS_FAILED(rv)) + return rv; + + JSContext *cx = (JSContext *)mScriptContext->GetNativeContext(); + if (!cx) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr newURI; + rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The redirected URI + if (NS_FAILED(rv)) + return rv; + + stack->Push(cx); + + rv = secMan->CheckSameOrigin(cx, newURI); + + stack->Pop(&cx); + + if (NS_FAILED(rv)) + return rv; + } + + mChannel = aNewChannel; + + return NS_OK; +} + +///////////////////////////////////////////////////// +// nsIInterfaceRequestor methods: +// +NS_IMETHODIMP +nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult) +{ + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nsnull; + + nsresult rv; + nsCOMPtr ww(do_GetService("@mozilla.org/embedcomp/window-watcher;1", &rv)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr prompt; + rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt)); + if (NS_FAILED(rv)) + return rv; + + nsIAuthPrompt *p = prompt.get(); + NS_ADDREF(p); + *aResult = p; + return NS_OK; + } + + return QueryInterface(aIID, aResult); +} + + NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor) NS_IMETHODIMP nsXMLHttpRequest:: diff --git a/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.h b/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.h index 71619d161a2..3480c874420 100644 --- a/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.h +++ b/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.h @@ -59,6 +59,8 @@ #include "nsISupportsArray.h" #include "jsapi.h" #include "nsIScriptContext.h" +#include "nsIHttpEventSink.h" +#include "nsIInterfaceRequestor.h" enum nsXMLHttpRequestState { @@ -76,6 +78,8 @@ class nsXMLHttpRequest : public nsIXMLHttpRequest, public nsIDOMLoadListener, public nsIDOMEventTarget, public nsIStreamListener, + public nsIHttpEventSink, + public nsIInterfaceRequestor, public nsSupportsWeakReference { public: @@ -108,6 +112,11 @@ public: // nsIRequestObserver NS_DECL_NSIREQUESTOBSERVER + // nsIHttpEventSink + NS_DECL_NSIHTTPEVENTSINK + + // nsIInterfaceRequestor + NS_DECL_NSIINTERFACEREQUESTOR protected: nsresult GetStreamForWString(const PRUnichar* aStr, PRInt32 aLength, @@ -163,6 +172,7 @@ protected: PRPackedBool mAsync; PRPackedBool mParseResponseBody; nsCString mOverrideMimeType; + PRBool mCrossSiteAccessEnabled; }; #endif diff --git a/mozilla/layout/style/nsCSSStyleSheet.cpp b/mozilla/layout/style/nsCSSStyleSheet.cpp index 402f0951982..da6674fa99b 100644 --- a/mozilla/layout/style/nsCSSStyleSheet.cpp +++ b/mozilla/layout/style/nsCSSStyleSheet.cpp @@ -103,6 +103,8 @@ #endif #include "nsContentUtils.h" +#include "nsIJSContextStack.h" +#include "nsIScriptSecurityManager.h" // An |AtomKey| is to be used for storage in the hashtable, and a // |DependentAtomKey| should be used on the stack to avoid the performance @@ -2357,6 +2359,8 @@ CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const NS_IMETHODIMP CSSStyleSheetImpl::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const { + // Important: If this function is ever made scriptable, we must add + // a security check here. See GetCSSRules below for an example. nsresult result = NS_ERROR_ILLEGAL_VALUE; if (mInner && mInner->mOrderedRules) { @@ -2775,6 +2779,34 @@ CSSStyleSheetImpl::GetOwnerRule(nsIDOMCSSRule** aOwnerRule) NS_IMETHODIMP CSSStyleSheetImpl::GetCssRules(nsIDOMCSSRuleList** aCssRules) { + //-- Security check: Only scripts from the same origin as the + // style sheet can access rule collections + + // Get JSContext from stack + nsCOMPtr stack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1"); + NS_ENSURE_TRUE(stack, NS_ERROR_FAILURE); + + JSContext *cx = nsnull; + nsresult rv = NS_OK; + + rv = stack->Peek(&cx); + NS_ENSURE_SUCCESS(rv, rv); + if (!cx) + return NS_ERROR_FAILURE; + + // Get the security manager and do the same-origin check + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = secMan->CheckSameOrigin(cx, mInner->mURL); + + if (NS_FAILED(rv)) { + return rv; + } + + // OK, security check passed, so get the rule collection if (nsnull == mRuleCollection) { mRuleCollection = new CSSRuleListImpl(this); if (nsnull == mRuleCollection) {