michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 et tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsPrincipal.h" michael@0: michael@0: #include "mozIThirdPartyUtil.h" michael@0: #include "nscore.h" michael@0: #include "nsScriptSecurityManager.h" michael@0: #include "nsString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "pratom.h" michael@0: #include "nsIURI.h" michael@0: #include "nsJSPrincipals.h" michael@0: #include "nsIObjectInputStream.h" michael@0: #include "nsIObjectOutputStream.h" michael@0: #include "nsIClassInfoImpl.h" michael@0: #include "nsError.h" michael@0: #include "nsIContentSecurityPolicy.h" michael@0: #include "nsCxPusher.h" michael@0: #include "jswrapper.h" michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/HashFunctions.h" michael@0: michael@0: #include "nsIAppsService.h" michael@0: #include "mozIApplication.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static bool gCodeBasePrincipalSupport = false; michael@0: static bool gIsObservingCodeBasePrincipalSupport = false; michael@0: michael@0: static bool URIIsImmutable(nsIURI* aURI) michael@0: { michael@0: nsCOMPtr mutableObj(do_QueryInterface(aURI)); michael@0: bool isMutable; michael@0: return michael@0: mutableObj && michael@0: NS_SUCCEEDED(mutableObj->GetMutable(&isMutable)) && michael@0: !isMutable; michael@0: } michael@0: michael@0: // Static member variables michael@0: const char nsBasePrincipal::sInvalid[] = "Invalid"; michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: nsBasePrincipal::AddRef() michael@0: { michael@0: NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt"); michael@0: // XXXcaa does this need to be threadsafe? See bug 143559. michael@0: nsrefcnt count = ++refcount; michael@0: NS_LOG_ADDREF(this, count, "nsBasePrincipal", sizeof(*this)); michael@0: return count; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: nsBasePrincipal::Release() michael@0: { michael@0: NS_PRECONDITION(0 != refcount, "dup release"); michael@0: nsrefcnt count = --refcount; michael@0: NS_LOG_RELEASE(this, count, "nsBasePrincipal"); michael@0: if (count == 0) { michael@0: delete this; michael@0: } michael@0: michael@0: return count; michael@0: } michael@0: michael@0: nsBasePrincipal::nsBasePrincipal() michael@0: { michael@0: if (!gIsObservingCodeBasePrincipalSupport) { michael@0: nsresult rv = michael@0: Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport, michael@0: "signed.applets.codebase_principal_support", michael@0: false); michael@0: gIsObservingCodeBasePrincipalSupport = NS_SUCCEEDED(rv); michael@0: NS_WARN_IF_FALSE(gIsObservingCodeBasePrincipalSupport, michael@0: "Installing gCodeBasePrincipalSupport failed!"); michael@0: } michael@0: } michael@0: michael@0: nsBasePrincipal::~nsBasePrincipal(void) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) michael@0: { michael@0: NS_IF_ADDREF(*aCsp = mCSP); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsBasePrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) michael@0: { michael@0: // If CSP was already set, it should not be destroyed! Instead, it should michael@0: // get set anew when a new principal is created. michael@0: if (mCSP) michael@0: return NS_ERROR_ALREADY_INITIALIZED; michael@0: michael@0: mCSP = aCsp; michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: void nsPrincipal::dumpImpl() michael@0: { michael@0: nsAutoCString str; michael@0: GetScriptLocation(str); michael@0: fprintf(stderr, "nsPrincipal (%p) = %s\n", static_cast(this), str.get()); michael@0: } michael@0: #endif michael@0: michael@0: NS_IMPL_CLASSINFO(nsPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, michael@0: NS_PRINCIPAL_CID) michael@0: NS_IMPL_QUERY_INTERFACE_CI(nsPrincipal, michael@0: nsIPrincipal, michael@0: nsISerializable) michael@0: NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal, michael@0: nsIPrincipal, michael@0: nsISerializable) michael@0: NS_IMPL_ADDREF_INHERITED(nsPrincipal, nsBasePrincipal) michael@0: NS_IMPL_RELEASE_INHERITED(nsPrincipal, nsBasePrincipal) michael@0: michael@0: nsPrincipal::nsPrincipal() michael@0: : mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID) michael@0: , mInMozBrowser(false) michael@0: , mCodebaseImmutable(false) michael@0: , mDomainImmutable(false) michael@0: , mInitialized(false) michael@0: { } michael@0: michael@0: nsPrincipal::~nsPrincipal() michael@0: { } michael@0: michael@0: nsresult michael@0: nsPrincipal::Init(nsIURI *aCodebase, michael@0: uint32_t aAppId, michael@0: bool aInMozBrowser) michael@0: { michael@0: NS_ENSURE_STATE(!mInitialized); michael@0: NS_ENSURE_ARG(aCodebase); michael@0: michael@0: mInitialized = true; michael@0: michael@0: mCodebase = NS_TryToMakeImmutable(aCodebase); michael@0: mCodebaseImmutable = URIIsImmutable(mCodebase); michael@0: michael@0: mAppId = aAppId; michael@0: mInMozBrowser = aInMozBrowser; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsPrincipal::GetScriptLocation(nsACString &aStr) michael@0: { michael@0: mCodebase->GetSpec(aStr); michael@0: } michael@0: michael@0: /* static */ nsresult michael@0: nsPrincipal::GetOriginForURI(nsIURI* aURI, char **aOrigin) michael@0: { michael@0: if (!aURI) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *aOrigin = nullptr; michael@0: michael@0: nsCOMPtr origin = NS_GetInnermostURI(aURI); michael@0: if (!origin) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsAutoCString hostPort; michael@0: michael@0: // chrome: URLs don't have a meaningful origin, so make michael@0: // sure we just get the full spec for them. michael@0: // XXX this should be removed in favor of the solution in michael@0: // bug 160042. michael@0: bool isChrome; michael@0: nsresult rv = origin->SchemeIs("chrome", &isChrome); michael@0: if (NS_SUCCEEDED(rv) && !isChrome) { michael@0: rv = origin->GetAsciiHost(hostPort); michael@0: // Some implementations return an empty string, treat it as no support michael@0: // for asciiHost by that implementation. michael@0: if (hostPort.IsEmpty()) { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: int32_t port; michael@0: if (NS_SUCCEEDED(rv) && !isChrome) { michael@0: rv = origin->GetPort(&port); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv) && !isChrome) { michael@0: if (port != -1) { michael@0: hostPort.AppendLiteral(":"); michael@0: hostPort.AppendInt(port, 10); michael@0: } michael@0: michael@0: nsAutoCString scheme; michael@0: rv = origin->GetScheme(scheme); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aOrigin = ToNewCString(scheme + NS_LITERAL_CSTRING("://") + hostPort); michael@0: } michael@0: else { michael@0: // Some URIs (e.g., nsSimpleURI) don't support asciiHost. Just michael@0: // get the full spec. michael@0: nsAutoCString spec; michael@0: // XXX nsMozIconURI and nsJARURI don't implement this correctly, they michael@0: // both fall back to GetSpec. That needs to be fixed. michael@0: rv = origin->GetAsciiSpec(spec); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aOrigin = ToNewCString(spec); michael@0: } michael@0: michael@0: return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetOrigin(char **aOrigin) michael@0: { michael@0: return GetOriginForURI(mCodebase, aOrigin); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult) michael@0: { michael@0: *aResult = false; michael@0: michael@0: if (!aOther) { michael@0: NS_WARNING("Need a principal to compare this to!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aOther == this) { michael@0: *aResult = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If either the subject or the object has changed its principal by michael@0: // explicitly setting document.domain then the other must also have michael@0: // done so in order to be considered the same origin. This prevents michael@0: // DNS spoofing based on document.domain (154930) michael@0: michael@0: nsCOMPtr thisURI; michael@0: this->GetDomain(getter_AddRefs(thisURI)); michael@0: bool thisSetDomain = !!thisURI; michael@0: if (!thisURI) { michael@0: this->GetURI(getter_AddRefs(thisURI)); michael@0: } michael@0: michael@0: nsCOMPtr otherURI; michael@0: aOther->GetDomain(getter_AddRefs(otherURI)); michael@0: bool otherSetDomain = !!otherURI; michael@0: if (!otherURI) { michael@0: aOther->GetURI(getter_AddRefs(otherURI)); michael@0: } michael@0: michael@0: *aResult = thisSetDomain == otherSetDomain && michael@0: nsScriptSecurityManager::SecurityCompareURIs(thisURI, otherURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::Equals(nsIPrincipal *aOther, bool *aResult) michael@0: { michael@0: *aResult = false; michael@0: michael@0: if (!aOther) { michael@0: NS_WARNING("Need a principal to compare this to!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aOther == this) { michael@0: *aResult = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr otherURI; michael@0: nsresult rv = aOther->GetURI(getter_AddRefs(otherURI)); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: NS_ASSERTION(mCodebase, michael@0: "shouldn't be calling this on principals from preferences"); michael@0: michael@0: // Compare codebases. michael@0: *aResult = nsScriptSecurityManager::SecurityCompareURIs(mCodebase, michael@0: otherURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult) michael@0: { michael@0: return Equals(aOther, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult) michael@0: { michael@0: return EqualsConsideringDomain(aOther, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetURI(nsIURI** aURI) michael@0: { michael@0: if (mCodebaseImmutable) { michael@0: NS_ADDREF(*aURI = mCodebase); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!mCodebase) { michael@0: *aURI = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_EnsureSafeToReturn(mCodebase, aURI); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal) michael@0: { michael@0: if (aAllowIfInheritsPrincipal) { michael@0: // If the caller specified to allow loads of URIs that inherit michael@0: // our principal, allow the load if this URI inherits its principal michael@0: if (nsPrincipal::IsPrincipalInherited(aURI)) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If strict file origin policy is in effect, local files will always fail michael@0: // SecurityCompareURIs unless they are identical. Explicitly check file origin michael@0: // policy, in that case. michael@0: if (nsScriptSecurityManager::GetStrictFileOriginPolicy() && michael@0: NS_URIIsLocalFile(aURI) && michael@0: NS_RelaxStrictFileOriginPolicy(aURI, mCodebase)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aReport) { michael@0: nsScriptSecurityManager::ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI); michael@0: } michael@0: return NS_ERROR_DOM_BAD_URI; michael@0: } michael@0: michael@0: void michael@0: nsPrincipal::SetURI(nsIURI* aURI) michael@0: { michael@0: mCodebase = NS_TryToMakeImmutable(aURI); michael@0: mCodebaseImmutable = URIIsImmutable(mCodebase); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetHashValue(uint32_t* aValue) michael@0: { michael@0: NS_PRECONDITION(mCodebase, "Need a codebase"); michael@0: michael@0: *aValue = nsScriptSecurityManager::HashPrincipalByOrigin(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetDomain(nsIURI** aDomain) michael@0: { michael@0: if (!mDomain) { michael@0: *aDomain = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mDomainImmutable) { michael@0: NS_ADDREF(*aDomain = mDomain); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_EnsureSafeToReturn(mDomain, aDomain); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::SetDomain(nsIURI* aDomain) michael@0: { michael@0: mDomain = NS_TryToMakeImmutable(aDomain); michael@0: mDomainImmutable = URIIsImmutable(mDomain); michael@0: michael@0: // Recompute all wrappers between compartments using this principal and other michael@0: // non-chrome compartments. michael@0: AutoSafeJSContext cx; michael@0: JSPrincipals *principals = nsJSPrincipals::get(static_cast(this)); michael@0: bool success = js::RecomputeWrappers(cx, js::ContentCompartmentsOnly(), michael@0: js::CompartmentsWithPrincipals(principals)); michael@0: NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); michael@0: success = js::RecomputeWrappers(cx, js::CompartmentsWithPrincipals(principals), michael@0: js::ContentCompartmentsOnly()); michael@0: NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetJarPrefix(nsACString& aJarPrefix) michael@0: { michael@0: MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); michael@0: michael@0: mozilla::GetJarPrefix(mAppId, mInMozBrowser, aJarPrefix); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetAppStatus(uint16_t* aAppStatus) michael@0: { michael@0: *aAppStatus = GetAppStatus(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetAppId(uint32_t* aAppId) michael@0: { michael@0: if (mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { michael@0: MOZ_ASSERT(false); michael@0: *aAppId = nsIScriptSecurityManager::NO_APP_ID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aAppId = mAppId; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement) michael@0: { michael@0: *aIsInBrowserElement = mInMozBrowser; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetUnknownAppId(bool* aUnknownAppId) michael@0: { michael@0: *aUnknownAppId = mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) michael@0: { michael@0: *aIsNullPrincipal = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) michael@0: { michael@0: // For a file URI, we return the file path. michael@0: if (NS_URIIsLocalFile(mCodebase)) { michael@0: nsCOMPtr url = do_QueryInterface(mCodebase); michael@0: michael@0: if (url) { michael@0: return url->GetFilePath(aBaseDomain); michael@0: } michael@0: } michael@0: michael@0: // For everything else, we ask the TLD service via michael@0: // the ThirdPartyUtil. michael@0: nsCOMPtr thirdPartyUtil = michael@0: do_GetService(THIRDPARTYUTIL_CONTRACTID); michael@0: if (thirdPartyUtil) { michael@0: return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::Read(nsIObjectInputStream* aStream) michael@0: { michael@0: nsCOMPtr supports; michael@0: nsCOMPtr codebase; michael@0: nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: codebase = do_QueryInterface(supports); michael@0: michael@0: nsCOMPtr domain; michael@0: rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: domain = do_QueryInterface(supports); michael@0: michael@0: uint32_t appId; michael@0: rv = aStream->Read32(&appId); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: bool inMozBrowser; michael@0: rv = aStream->ReadBoolean(&inMozBrowser); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // This may be null. michael@0: nsCOMPtr csp = do_QueryInterface(supports, &rv); michael@0: michael@0: rv = Init(codebase, appId, inMozBrowser); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = SetCsp(csp); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // need to link in the CSP context here (link in a reference to this michael@0: // nsIPrincipal and to the URI of the protected resource). michael@0: if (csp) { michael@0: csp->SetRequestContext(codebase, nullptr, this, nullptr); michael@0: } michael@0: michael@0: SetDomain(domain); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsPrincipal::Write(nsIObjectOutputStream* aStream) michael@0: { michael@0: NS_ENSURE_STATE(mCodebase); michael@0: michael@0: nsresult rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI), michael@0: true); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: rv = NS_WriteOptionalCompoundObject(aStream, mDomain, NS_GET_IID(nsIURI), michael@0: true); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: aStream->Write32(mAppId); michael@0: aStream->WriteBoolean(mInMozBrowser); michael@0: michael@0: rv = NS_WriteOptionalCompoundObject(aStream, mCSP, michael@0: NS_GET_IID(nsIContentSecurityPolicy), michael@0: true); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: // mCodebaseImmutable and mDomainImmutable will be recomputed based michael@0: // on the deserialized URIs in Read(). michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint16_t michael@0: nsPrincipal::GetAppStatus() michael@0: { michael@0: NS_WARN_IF_FALSE(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID, michael@0: "Asking for app status on a principal with an unknown app id"); michael@0: // Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID) michael@0: // and they are not inside a mozbrowser. michael@0: if (mAppId == nsIScriptSecurityManager::NO_APP_ID || michael@0: mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID || mInMozBrowser) { michael@0: return nsIPrincipal::APP_STATUS_NOT_INSTALLED; michael@0: } michael@0: michael@0: nsCOMPtr appsService = do_GetService(APPS_SERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: nsCOMPtr app; michael@0: appsService->GetAppByLocalId(mAppId, getter_AddRefs(app)); michael@0: NS_ENSURE_TRUE(app, nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: uint16_t status = nsIPrincipal::APP_STATUS_INSTALLED; michael@0: NS_ENSURE_SUCCESS(app->GetAppStatus(&status), michael@0: nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: nsAutoCString origin; michael@0: NS_ENSURE_SUCCESS(GetOrigin(getter_Copies(origin)), michael@0: nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: nsString appOrigin; michael@0: NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin), michael@0: nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: // We go from string -> nsIURI -> origin to be sure we michael@0: // compare two punny-encoded origins. michael@0: nsCOMPtr appURI; michael@0: NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin), michael@0: nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: nsAutoCString appOriginPunned; michael@0: NS_ENSURE_SUCCESS(GetOriginForURI(appURI, getter_Copies(appOriginPunned)), michael@0: nsIPrincipal::APP_STATUS_NOT_INSTALLED); michael@0: michael@0: if (!appOriginPunned.Equals(origin)) { michael@0: return nsIPrincipal::APP_STATUS_NOT_INSTALLED; michael@0: } michael@0: michael@0: return status; michael@0: } michael@0: michael@0: /************************************************************************************************************************/ michael@0: michael@0: static const char EXPANDED_PRINCIPAL_SPEC[] = "[Expanded Principal]"; michael@0: michael@0: NS_IMPL_CLASSINFO(nsExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, michael@0: NS_EXPANDEDPRINCIPAL_CID) michael@0: NS_IMPL_QUERY_INTERFACE_CI(nsExpandedPrincipal, michael@0: nsIPrincipal, michael@0: nsIExpandedPrincipal) michael@0: NS_IMPL_CI_INTERFACE_GETTER(nsExpandedPrincipal, michael@0: nsIPrincipal, michael@0: nsIExpandedPrincipal) michael@0: NS_IMPL_ADDREF_INHERITED(nsExpandedPrincipal, nsBasePrincipal) michael@0: NS_IMPL_RELEASE_INHERITED(nsExpandedPrincipal, nsBasePrincipal) michael@0: michael@0: nsExpandedPrincipal::nsExpandedPrincipal(nsTArray > &aWhiteList) michael@0: { michael@0: mPrincipals.AppendElements(aWhiteList); michael@0: } michael@0: michael@0: nsExpandedPrincipal::~nsExpandedPrincipal() michael@0: { } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetDomain(nsIURI** aDomain) michael@0: { michael@0: *aDomain = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::SetDomain(nsIURI* aDomain) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetOrigin(char** aOrigin) michael@0: { michael@0: *aOrigin = ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC)); michael@0: return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: typedef nsresult (NS_STDCALL nsIPrincipal::*nsIPrincipalMemFn)(nsIPrincipal* aOther, michael@0: bool* aResult); michael@0: #define CALL_MEMBER_FUNCTION(THIS,MEM_FN) ((THIS)->*(MEM_FN)) michael@0: michael@0: // nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsConsideringDomain michael@0: // shares the same logic. The difference only that Equals requires 'this' michael@0: // and 'aOther' to Subsume each other while EqualsConsideringDomain requires michael@0: // bidirectional SubsumesConsideringDomain. michael@0: static nsresult michael@0: Equals(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, michael@0: bool* aResult) michael@0: { michael@0: // If (and only if) 'aThis' and 'aOther' both Subsume/SubsumesConsideringDomain michael@0: // each other, then they are Equal. michael@0: *aResult = false; michael@0: // Calling the corresponding subsume function on this (aFn). michael@0: nsresult rv = CALL_MEMBER_FUNCTION(aThis, aFn)(aOther, aResult); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!*aResult) michael@0: return NS_OK; michael@0: michael@0: // Calling the corresponding subsume function on aOther (aFn). michael@0: rv = CALL_MEMBER_FUNCTION(aOther, aFn)(aThis, aResult); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::Equals(nsIPrincipal* aOther, bool* aResult) michael@0: { michael@0: return ::Equals(this, &nsIPrincipal::Subsumes, aOther, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::EqualsConsideringDomain(nsIPrincipal* aOther, bool* aResult) michael@0: { michael@0: return ::Equals(this, &nsIPrincipal::SubsumesConsideringDomain, aOther, aResult); michael@0: } michael@0: michael@0: // nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesConsideringDomain michael@0: // shares the same logic. The difference only that Subsumes calls are replaced michael@0: //with SubsumesConsideringDomain calls in the second case. michael@0: static nsresult michael@0: Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, michael@0: bool* aResult) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr expanded = do_QueryInterface(aOther); michael@0: if (expanded) { michael@0: // If aOther is an ExpandedPrincipal too, check if all of its michael@0: // principals are subsumed. michael@0: nsTArray< nsCOMPtr >* otherList; michael@0: expanded->GetWhiteList(&otherList); michael@0: for (uint32_t i = 0; i < otherList->Length(); ++i){ michael@0: rv = CALL_MEMBER_FUNCTION(aThis, aFn)((*otherList)[i], aResult); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!*aResult) { michael@0: // If we don't subsume at least one principal of aOther, return false. michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } else { michael@0: // For a regular aOther, one of our principals must subsume it. michael@0: nsTArray< nsCOMPtr >* list; michael@0: aThis->GetWhiteList(&list); michael@0: for (uint32_t i = 0; i < list->Length(); ++i){ michael@0: rv = CALL_MEMBER_FUNCTION((*list)[i], aFn)(aOther, aResult); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (*aResult) { michael@0: // If one of our principal subsumes it, return true. michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #undef CALL_MEMBER_FUNCTION michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::Subsumes(nsIPrincipal* aOther, bool* aResult) michael@0: { michael@0: return ::Subsumes(this, &nsIPrincipal::Subsumes, aOther, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::SubsumesConsideringDomain(nsIPrincipal* aOther, bool* aResult) michael@0: { michael@0: return ::Subsumes(this, &nsIPrincipal::SubsumesConsideringDomain, aOther, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal) michael@0: { michael@0: nsresult rv; michael@0: for (uint32_t i = 0; i < mPrincipals.Length(); ++i){ michael@0: rv = mPrincipals[i]->CheckMayLoad(uri, aReport, aAllowIfInheritsPrincipal); michael@0: if (NS_SUCCEEDED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: return NS_ERROR_DOM_BAD_URI; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetHashValue(uint32_t* result) michael@0: { michael@0: MOZ_CRASH("extended principal should never be used as key in a hash map"); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetURI(nsIURI** aURI) michael@0: { michael@0: *aURI = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) michael@0: { michael@0: *aWhiteList = &mPrincipals; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetJarPrefix(nsACString& aJarPrefix) michael@0: { michael@0: aJarPrefix.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetAppStatus(uint16_t* aAppStatus) michael@0: { michael@0: *aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetAppId(uint32_t* aAppId) michael@0: { michael@0: *aAppId = nsIScriptSecurityManager::NO_APP_ID; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement) michael@0: { michael@0: *aIsInBrowserElement = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId) michael@0: { michael@0: *aUnknownAppId = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) michael@0: { michael@0: *aIsNullPrincipal = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: void michael@0: nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) michael@0: { michael@0: // Is that a good idea to list it's principals? michael@0: aStr.Assign(EXPANDED_PRINCIPAL_SPEC); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: void nsExpandedPrincipal::dumpImpl() michael@0: { michael@0: fprintf(stderr, "nsExpandedPrincipal (%p)\n", static_cast(this)); michael@0: } michael@0: #endif michael@0: michael@0: ////////////////////////////////////////// michael@0: // Methods implementing nsISerializable // michael@0: ////////////////////////////////////////// michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::Read(nsIObjectInputStream* aStream) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsExpandedPrincipal::Write(nsIObjectOutputStream* aStream) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: }