Fixing regression bug 246923. Bring back to life the fix for bug 13871, and improve on the fix for bug 246448. r=dveditz@cruzio.com, sr=darin@meer.net

git-svn-id: svn://10.0.0.236/trunk@158368 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
jst%mozilla.jstenback.com
2004-06-23 17:42:31 +00:00
parent 9897041a64
commit 472233cafb
4 changed files with 133 additions and 196 deletions

View File

@@ -258,7 +258,7 @@ nsDocShell::nsDocShell():
mIsBeingDestroyed(PR_FALSE),
mUseExternalProtocolHandler(PR_FALSE),
mDisallowPopupWindows(PR_FALSE),
mValidateOrigin(PR_FALSE),
mValidateOrigin(PR_TRUE), // validate frame origins by default
mIsExecutingOnLoadHandler(PR_FALSE),
mIsPrintingOrPP(PR_FALSE),
mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
@@ -970,7 +970,8 @@ PRBool SameOrSubdomainOfTarget(nsIURI* aOriginURI, nsIURI* aTargetURI, PRBool aD
// of loading in the hands of the target, which is more secure. (per Nav 4.x)
//
static
PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, nsIDocShellTreeItem* aTargetTreeItem)
PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
nsIDocShellTreeItem* aTargetTreeItem)
{
// Get origin document uri (ignoring document.domain)
nsCOMPtr<nsIWebNavigation> originWebNav(do_QueryInterface(aOriginTreeItem));
@@ -982,13 +983,11 @@ PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, nsIDocShellTreeItem*
// Get target principal uri (including document.domain)
nsCOMPtr<nsIDOMDocument> targetDOMDocument(do_GetInterface(aTargetTreeItem));
NS_ENSURE_TRUE(targetDOMDocument, PR_TRUE);
nsCOMPtr<nsIDocument> targetDocument(do_QueryInterface(targetDOMDocument));
NS_ENSURE_TRUE(targetDocument, PR_TRUE);
nsIPrincipal *targetPrincipal = targetDocument->GetPrincipal();
NS_ENSURE_TRUE(targetPrincipal, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(targetPrincipal, PR_TRUE);
nsCOMPtr<nsIURI> targetPrincipalURI;
rv = targetPrincipal->GetURI(getter_AddRefs(targetPrincipalURI));
@@ -1005,7 +1004,8 @@ PRBool ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem, nsIDocShellTreeItem*
// Is origin same principal or a subdomain of target's document.domain
// Compare actual URI of origin document, not origin principal's URI. (Per Nav 4.x)
return SameOrSubdomainOfTarget(originDocumentURI, targetPrincipalURI, documentDomainSet);
return SameOrSubdomainOfTarget(originDocumentURI, targetPrincipalURI,
documentDomainSet);
}
nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget,
@@ -1084,27 +1084,42 @@ nsresult nsDocShell::FindTarget(const PRUnichar *aWindowTarget,
// Check to see if pref is true
if (mValidateOrigin && treeItem)
{
nsCOMPtr<nsIDocShellTreeItem> tmp;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(tmp));
// Is origin frame from the same domain as target frame?
if (! ValidateOrigin(this, treeItem))
{
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
// No. Is origin frame from the same domain as target's parent?
nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
rv = treeItem->GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
if (NS_SUCCEEDED(rv) && targetParentTreeItem)
{
if (! ValidateOrigin(this, targetParentTreeItem))
{
if (sameTypeRoot != tmp) {
// The load was initiated in another toplevel window.
// Assume we'll need to make a new window until we
// find that the target, or one of its ancestors, are
// from the same origin as the loading docshell.
mustMakeNewWindow = PR_TRUE;
// Neither is from the origin domain, send load to a new window (_blank)
mustMakeNewWindow = PR_TRUE;
name.Truncate();
} // else (target's parent from origin domain) allow this load
} // else (no parent) allow this load since shell is a toplevel window
} // else (target from origin domain) allow this load
} // else (pref is false) allow this load
tmp = treeItem;
do {
// Is origin frame from the same domain as target frame?
if (ValidateOrigin(this, tmp)) {
mustMakeNewWindow = PR_FALSE;
break;
}
nsCOMPtr<nsIDocShellTreeItem> t;
tmp->GetSameTypeParent(getter_AddRefs(t));
tmp.swap(t);
} while (tmp);
if (mustMakeNewWindow) {
// Origin mismatch, open the URL in a new blank
// window.
treeItem = nsnull;
name.Truncate();
}
}
}
}
if (mustMakeNewWindow)
@@ -4940,27 +4955,14 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
nsresult
nsDocShell::CheckLoadingPermissions(nsISupports *aOwner)
nsDocShell::CheckLoadingPermissions()
{
nsresult rv = NS_OK;
nsresult rv = NS_OK, sameOrigin = NS_OK;
if (mPrefs) {
PRBool frameLoadCheckDisabled = PR_FALSE;
rv = mPrefs->GetBoolPref("docshell.frameloadcheck.disabled",
&frameLoadCheckDisabled);
if (!mValidateOrigin || !IsFrame()) {
// Origin validation was turned off, or we're not a frame.
// Permit all loads.
if (NS_SUCCEEDED(rv) && frameLoadCheckDisabled) {
return rv;
}
}
// Check to see if we're a frame in a frameset frame, or iframe,
// and make sure the caller has the right to load a new uri into
// this frame.
nsCOMPtr<nsIDocShellTreeItem> parentItem;
rv = GetSameTypeParent(getter_AddRefs(parentItem));
if (NS_FAILED(rv) || !parentItem) {
return rv;
}
@@ -4972,100 +4974,88 @@ nsDocShell::CheckLoadingPermissions(nsISupports *aOwner)
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> caller(do_QueryInterface(aOwner));
if (!caller) {
rv = securityManager->GetSubjectPrincipal(getter_AddRefs(caller));
if (NS_FAILED(rv) || !caller) {
// No principal reachable, permit load (assuming the above
// call didn't fail)
return rv;
}
}
if (!aOwner && caller) {
// We were *not* passed a principal, but we found a subject
// principal. That means that JS is running. Check if
// "UniversalBrowserWrite" is enabled, and allow the load if
// it is.
PRBool ubwEnabled = PR_FALSE;
rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
&ubwEnabled);
if (NS_FAILED(rv) || ubwEnabled) {
return rv;
}
}
nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(parentItem));
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
nsIPrincipal *parentPrincipal;
if (!sop || !(parentPrincipal = sop->GetPrincipal())) {
return NS_ERROR_UNEXPECTED;
}
// Check if the caller is from the same origin as our parent.
rv = securityManager->CheckSameOriginPrincipal(caller, parentPrincipal);
if (NS_SUCCEEDED(rv)) {
// Same origin, permit load
PRBool ubwEnabled = PR_FALSE;
rv = securityManager->IsCapabilityEnabled("UniversalBrowserWrite",
&ubwEnabled);
if (NS_FAILED(rv) || ubwEnabled) {
return rv;
}
sop = do_QueryInterface(mScriptGlobal);
nsCOMPtr<nsIPrincipal> subjPrincipal;
rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjPrincipal));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && subjPrincipal, rv);
nsIPrincipal *principal;
if (!sop || !(principal = sop->GetPrincipal())) {
return NS_ERROR_UNEXPECTED;
}
// Check if the caller is from the same origin as this docshell,
// or any of it's ancestors.
nsCOMPtr<nsIDocShellTreeItem> item(this);
do {
nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(item));
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
// Check if the caller is from the same origin as we are.
rv = securityManager->CheckSameOriginPrincipal(caller, principal);
if (NS_SUCCEEDED(rv)) {
// Same origin, permit load
nsIPrincipal *p;
if (!sop || !(p = sop->GetPrincipal())) {
return NS_ERROR_UNEXPECTED;
}
return rv;
}
// Compare origins
sameOrigin =
securityManager->CheckSameOriginPrincipal(subjPrincipal, p);
if (NS_SUCCEEDED(sameOrigin)) {
// Same origin, permit load
// Caller and callee are not from the same origin. Only permit
// loading content if both are part of the same window, assuming
// we can find the window of the caller.
return sameOrigin;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeCalleeRoot;
GetSameTypeRootTreeItem(getter_AddRefs(sameTypeCalleeRoot));
nsCOMPtr<nsIDocShellTreeItem> tmp;
item->GetSameTypeParent(getter_AddRefs(tmp));
item.swap(tmp);
} while (item);
// The caller is not from the same origin as this item, or any if
// this items ancestors. Only permit loading content if both are
// part of the same window, assuming we can find the window of the
// caller.
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (!stack) {
return rv;
// No context stack available. Should never happen, but in
// case it does, return the sameOrigin error from the security
// check above.
return sameOrigin;
}
JSContext *cx = nsnull;
stack->Peek(&cx);
if (!cx) {
// No caller docshell reachable, disallow load.
// No caller docshell reachable, return the sameOrigin error
// from the security check above.
return rv;
return sameOrigin;
}
nsIScriptContext *currentCX =
GetScriptContextFromJSContext(cx);
nsIScriptContext *currentCX = GetScriptContextFromJSContext(cx);
nsCOMPtr<nsIDocShellTreeItem> callerTreeItem;
nsIScriptGlobalObject *sgo;
if (currentCX &&
(sgo = currentCX->GetGlobalObject())) {
nsCOMPtr<nsIDocShellTreeItem> sameTypeCallerRoot =
do_QueryInterface(sgo->GetDocShell());
(sgo = currentCX->GetGlobalObject()) &&
(callerTreeItem = do_QueryInterface(sgo->GetDocShell()))) {
nsCOMPtr<nsIDocShellTreeItem> callerRoot;
callerTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(callerRoot));
if (sameTypeCalleeRoot == sameTypeCallerRoot) {
rv = NS_OK;
nsCOMPtr<nsIDocShellTreeItem> ourRoot;
GetSameTypeRootTreeItem(getter_AddRefs(ourRoot));
if (ourRoot == callerRoot) {
// The running JS is in the same window as the target
// frame, permit load.
sameOrigin = NS_OK;
}
}
return rv;
return sameOrigin;
}
//*****************************************************************************
@@ -5331,7 +5321,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
return NS_ERROR_FAILURE;
}
rv = CheckLoadingPermissions(aOwner);
rv = CheckLoadingPermissions();
if (NS_FAILED(rv)) {
return rv;
}
@@ -5479,10 +5469,9 @@ nsDocShell::InternalLoad(nsIURI * aURI,
return rv;
}
NS_IMETHODIMP
void
nsDocShell::GetCurrentDocumentOwner(nsISupports ** aOwner)
{
nsresult rv;
*aOwner = nsnull;
nsCOMPtr<nsIDocument> document;
//-- Get the current document
@@ -5490,31 +5479,29 @@ nsDocShell::GetCurrentDocumentOwner(nsISupports ** aOwner)
nsCOMPtr<nsIDocumentViewer>
docViewer(do_QueryInterface(mContentViewer));
if (!docViewer)
return NS_ERROR_FAILURE;
rv = docViewer->GetDocument(getter_AddRefs(document));
return;
docViewer->GetDocument(getter_AddRefs(document));
}
else //-- If there's no document loaded yet, look at the parent (frameset)
{
nsCOMPtr<nsIDocShellTreeItem> parentItem;
rv = GetSameTypeParent(getter_AddRefs(parentItem));
if (NS_FAILED(rv) || !parentItem)
return rv;
GetSameTypeParent(getter_AddRefs(parentItem));
if (!parentItem)
return;
nsCOMPtr<nsIDOMWindowInternal>
parentWindow(do_GetInterface(parentItem));
if (!parentWindow)
return NS_OK;
return;
nsCOMPtr<nsIDOMDocument> parentDomDoc;
rv = parentWindow->GetDocument(getter_AddRefs(parentDomDoc));
parentWindow->GetDocument(getter_AddRefs(parentDomDoc));
if (!parentDomDoc)
return NS_OK;
return;
document = do_QueryInterface(parentDomDoc);
}
//-- Get the document's principal
nsIPrincipal *principal = document->GetPrincipal();
if (!principal)
return NS_ERROR_FAILURE;
return principal->QueryInterface(NS_GET_IID(nsISupports), (void **) aOwner);
*aOwner = document->GetPrincipal();
NS_IF_ADDREF(*aOwner);
}
nsresult

View File

@@ -243,7 +243,7 @@ protected:
NS_IMETHOD SetupNewViewer(nsIContentViewer * aNewViewer);
NS_IMETHOD GetEldestPresContext(nsIPresContext** aPresContext);
NS_IMETHOD GetCurrentDocumentOwner(nsISupports ** aOwner);
void GetCurrentDocumentOwner(nsISupports ** aOwner);
virtual nsresult DoURILoad(nsIURI * aURI,
nsIURI * aReferrer,
nsISupports * aOwner,
@@ -326,7 +326,7 @@ protected:
nsIChannel * aChannel,
nsresult aResult);
nsresult CheckLoadingPermissions(nsISupports *aOwner);
nsresult CheckLoadingPermissions();
protected:
PRPackedBool mAllowSubframes;

View File

@@ -58,7 +58,6 @@
#include "nsIRefreshURI.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIScriptSecurityManager.h"
#include "nsIDOMEvent.h"
#include "nsIPresContext.h"
#include "nsIComponentManager.h"
@@ -424,17 +423,15 @@ nsWebShell::SetRendering(PRBool aRender)
struct OnLinkClickEvent : public PLEvent {
OnLinkClickEvent(nsWebShell* aHandler, nsIContent* aContent,
nsLinkVerb aVerb, nsIURI* aURI,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsISupports *aOwner);
const PRUnichar* aTargetSpec, nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0);
~OnLinkClickEvent();
void HandleEvent() {
mHandler->OnLinkClickSyncInternal(mContent, mVerb, mURI,
mTargetSpec.get(), mPostDataStream,
mHeadersDataStream,
nsnull, nsnull, mOwner);
mHandler->OnLinkClickSync(mContent, mVerb, mURI,
mTargetSpec.get(), mPostDataStream,
mHeadersDataStream,
nsnull, nsnull);
}
nsWebShell* mHandler;
@@ -444,7 +441,6 @@ struct OnLinkClickEvent : public PLEvent {
nsCOMPtr<nsIInputStream> mHeadersDataStream;
nsCOMPtr<nsIContent> mContent;
nsLinkVerb mVerb;
nsCOMPtr<nsISupports> mOwner;
};
static void PR_CALLBACK HandlePLEvent(OnLinkClickEvent* aEvent)
@@ -463,8 +459,7 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
nsIURI* aURI,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsISupports *aOwner)
nsIInputStream* aHeadersDataStream)
{
mHandler = aHandler;
NS_ADDREF(aHandler);
@@ -474,7 +469,6 @@ OnLinkClickEvent::OnLinkClickEvent(nsWebShell* aHandler,
mHeadersDataStream = aHeadersDataStream;
mContent = aContent;
mVerb = aVerb;
mOwner = aOwner;
PL_InitEvent(this, nsnull,
(PLHandleEventProc) ::HandlePLEvent,
@@ -502,20 +496,10 @@ nsWebShell::OnLinkClick(nsIContent* aContent,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream)
{
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
NS_ENSURE_TRUE(securityManager, NS_ERROR_UNEXPECTED);
OnLinkClickEvent* ev;
nsCOMPtr<nsIPrincipal> principal;
securityManager->GetSubjectPrincipal(getter_AddRefs(principal));
if (!principal && aContent && aContent->GetDocument()) {
principal = aContent->GetDocument()->GetPrincipal();
}
OnLinkClickEvent* ev =
new OnLinkClickEvent(this, aContent, aVerb, aURI, aTargetSpec,
aPostDataStream, aHeadersDataStream, principal);
ev = new OnLinkClickEvent(this, aContent, aVerb, aURI,
aTargetSpec, aPostDataStream, aHeadersDataStream);
if (!ev) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -534,7 +518,7 @@ nsWebShell::GetEventQueue(nsIEventQueue **aQueue)
return *aQueue ? NS_OK : NS_ERROR_FAILURE;
}
nsresult
NS_IMETHODIMP
nsWebShell::OnLinkClickSync(nsIContent *aContent,
nsLinkVerb aVerb,
nsIURI* aURI,
@@ -544,33 +528,7 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
nsIDocShell** aDocShell,
nsIRequest** aRequest)
{
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
NS_ENSURE_TRUE(securityManager, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIPrincipal> principal;
securityManager->GetSubjectPrincipal(getter_AddRefs(principal));
if (!principal && aContent && aContent->GetDocument()) {
principal = aContent->GetDocument()->GetPrincipal();
}
return OnLinkClickSyncInternal(aContent, aVerb, aURI, aTargetSpec,
aPostDataStream, aHeadersDataStream,
aDocShell, aRequest, principal);
}
nsresult
nsWebShell::OnLinkClickSyncInternal(nsIContent *aContent,
nsLinkVerb aVerb,
nsIURI* aURI,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsIDocShell** aDocShell,
nsIRequest** aRequest,
nsISupports *aOwner)
{
PRBool earlyReturn = PR_FALSE;
{
// defer to an external protocol handler if necessary...
nsCOMPtr<nsIExternalProtocolService> extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
@@ -584,15 +542,16 @@ nsWebShell::OnLinkClickSyncInternal(nsIContent *aContent,
nsresult rv = extProtService->IsExposedProtocol(scheme.get(), &isExposed);
if (NS_SUCCEEDED(rv) && !isExposed) {
rv = extProtService->LoadUrl(aURI);
if (NS_SUCCEEDED(rv))
return NS_OK;
NS_WARNING("failed to launch external protocol handler");
earlyReturn = PR_TRUE;
else
NS_WARNING("failed to launch external protocol handler");
}
}
}
}
if (earlyReturn)
return NS_OK;
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
@@ -604,7 +563,7 @@ nsWebShell::OnLinkClickSyncInternal(nsIContent *aContent,
aURI->SchemeIs("data", &isData);
if (isJS || isData) {
nsIDocument *sourceDoc = aContent->GetDocument();
nsCOMPtr<nsIDocument> sourceDoc = aContent->GetDocument();
if (!sourceDoc) {
// The source is in a 'zombie' document, or not part of a
@@ -672,7 +631,7 @@ nsWebShell::OnLinkClickSyncInternal(nsIContent *aContent,
{
return InternalLoad(aURI, // New URI
referer, // Referer URI
aOwner, // Owner (nsIPrincipal)
nsnull, // No onwer
PR_TRUE, // Inherit owner from document
target.get(), // Window target
NS_LossyConvertUCS2toASCII(typeHint).get(),

View File

@@ -115,15 +115,6 @@ public:
// NS_IMETHOD SetURL(const PRUnichar* aURL);
nsresult OnLinkClickSyncInternal(nsIContent* aContent, nsLinkVerb aVerb,
nsIURI* aURI,
const PRUnichar* aTargetSpec,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsIDocShell** aDocShell,
nsIRequest** aRequest,
nsISupports *aOwner);
protected:
// void GetRootWebShellEvenIfChrome(nsIWebShell** aResult);
void InitFrameData();