1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsPrincipal.h"
9 #include "mozIThirdPartyUtil.h"
11 #include "nsScriptSecurityManager.h"
13 #include "nsReadableUtils.h"
16 #include "nsJSPrincipals.h"
17 #include "nsIObjectInputStream.h"
18 #include "nsIObjectOutputStream.h"
19 #include "nsIClassInfoImpl.h"
21 #include "nsIContentSecurityPolicy.h"
22 #include "nsCxPusher.h"
23 #include "jswrapper.h"
25 #include "mozilla/Preferences.h"
26 #include "mozilla/HashFunctions.h"
28 #include "nsIAppsService.h"
29 #include "mozIApplication.h"
31 using namespace mozilla
;
33 static bool gCodeBasePrincipalSupport
= false;
34 static bool gIsObservingCodeBasePrincipalSupport
= false;
36 static bool URIIsImmutable(nsIURI
* aURI
)
38 nsCOMPtr
<nsIMutable
> mutableObj(do_QueryInterface(aURI
));
42 NS_SUCCEEDED(mutableObj
->GetMutable(&isMutable
)) &&
46 // Static member variables
47 const char nsBasePrincipal::sInvalid
[] = "Invalid";
49 NS_IMETHODIMP_(MozExternalRefCountType
)
50 nsBasePrincipal::AddRef()
52 NS_PRECONDITION(int32_t(refcount
) >= 0, "illegal refcnt");
53 // XXXcaa does this need to be threadsafe? See bug 143559.
54 nsrefcnt count
= ++refcount
;
55 NS_LOG_ADDREF(this, count
, "nsBasePrincipal", sizeof(*this));
59 NS_IMETHODIMP_(MozExternalRefCountType
)
60 nsBasePrincipal::Release()
62 NS_PRECONDITION(0 != refcount
, "dup release");
63 nsrefcnt count
= --refcount
;
64 NS_LOG_RELEASE(this, count
, "nsBasePrincipal");
72 nsBasePrincipal::nsBasePrincipal()
74 if (!gIsObservingCodeBasePrincipalSupport
) {
76 Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport
,
77 "signed.applets.codebase_principal_support",
79 gIsObservingCodeBasePrincipalSupport
= NS_SUCCEEDED(rv
);
80 NS_WARN_IF_FALSE(gIsObservingCodeBasePrincipalSupport
,
81 "Installing gCodeBasePrincipalSupport failed!");
85 nsBasePrincipal::~nsBasePrincipal(void)
90 nsBasePrincipal::GetCsp(nsIContentSecurityPolicy
** aCsp
)
92 NS_IF_ADDREF(*aCsp
= mCSP
);
97 nsBasePrincipal::SetCsp(nsIContentSecurityPolicy
* aCsp
)
99 // If CSP was already set, it should not be destroyed! Instead, it should
100 // get set anew when a new principal is created.
102 return NS_ERROR_ALREADY_INITIALIZED
;
109 void nsPrincipal::dumpImpl()
112 GetScriptLocation(str
);
113 fprintf(stderr
, "nsPrincipal (%p) = %s\n", static_cast<void*>(this), str
.get());
117 NS_IMPL_CLASSINFO(nsPrincipal
, nullptr, nsIClassInfo::MAIN_THREAD_ONLY
,
119 NS_IMPL_QUERY_INTERFACE_CI(nsPrincipal
,
122 NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal
,
125 NS_IMPL_ADDREF_INHERITED(nsPrincipal
, nsBasePrincipal
)
126 NS_IMPL_RELEASE_INHERITED(nsPrincipal
, nsBasePrincipal
)
128 nsPrincipal::nsPrincipal()
129 : mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID
)
130 , mInMozBrowser(false)
131 , mCodebaseImmutable(false)
132 , mDomainImmutable(false)
133 , mInitialized(false)
136 nsPrincipal::~nsPrincipal()
140 nsPrincipal::Init(nsIURI
*aCodebase
,
144 NS_ENSURE_STATE(!mInitialized
);
145 NS_ENSURE_ARG(aCodebase
);
149 mCodebase
= NS_TryToMakeImmutable(aCodebase
);
150 mCodebaseImmutable
= URIIsImmutable(mCodebase
);
153 mInMozBrowser
= aInMozBrowser
;
159 nsPrincipal::GetScriptLocation(nsACString
&aStr
)
161 mCodebase
->GetSpec(aStr
);
164 /* static */ nsresult
165 nsPrincipal::GetOriginForURI(nsIURI
* aURI
, char **aOrigin
)
168 return NS_ERROR_FAILURE
;
173 nsCOMPtr
<nsIURI
> origin
= NS_GetInnermostURI(aURI
);
175 return NS_ERROR_FAILURE
;
178 nsAutoCString hostPort
;
180 // chrome: URLs don't have a meaningful origin, so make
181 // sure we just get the full spec for them.
182 // XXX this should be removed in favor of the solution in
185 nsresult rv
= origin
->SchemeIs("chrome", &isChrome
);
186 if (NS_SUCCEEDED(rv
) && !isChrome
) {
187 rv
= origin
->GetAsciiHost(hostPort
);
188 // Some implementations return an empty string, treat it as no support
189 // for asciiHost by that implementation.
190 if (hostPort
.IsEmpty()) {
191 rv
= NS_ERROR_FAILURE
;
196 if (NS_SUCCEEDED(rv
) && !isChrome
) {
197 rv
= origin
->GetPort(&port
);
200 if (NS_SUCCEEDED(rv
) && !isChrome
) {
202 hostPort
.Append(':');
203 hostPort
.AppendInt(port
, 10);
206 nsAutoCString scheme
;
207 rv
= origin
->GetScheme(scheme
);
208 NS_ENSURE_SUCCESS(rv
, rv
);
210 *aOrigin
= ToNewCString(scheme
+ NS_LITERAL_CSTRING("://") + hostPort
);
213 // Some URIs (e.g., nsSimpleURI) don't support asciiHost. Just
214 // get the full spec.
216 // XXX nsMozIconURI and nsJARURI don't implement this correctly, they
217 // both fall back to GetSpec. That needs to be fixed.
218 rv
= origin
->GetAsciiSpec(spec
);
219 NS_ENSURE_SUCCESS(rv
, rv
);
221 *aOrigin
= ToNewCString(spec
);
224 return *aOrigin
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
228 nsPrincipal::GetOrigin(char **aOrigin
)
230 return GetOriginForURI(mCodebase
, aOrigin
);
234 nsPrincipal::EqualsConsideringDomain(nsIPrincipal
*aOther
, bool *aResult
)
239 NS_WARNING("Need a principal to compare this to!");
243 if (aOther
== this) {
248 if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther
)) {
252 // If either the subject or the object has changed its principal by
253 // explicitly setting document.domain then the other must also have
254 // done so in order to be considered the same origin. This prevents
255 // DNS spoofing based on document.domain (154930)
257 nsCOMPtr
<nsIURI
> thisURI
;
258 this->GetDomain(getter_AddRefs(thisURI
));
259 bool thisSetDomain
= !!thisURI
;
261 this->GetURI(getter_AddRefs(thisURI
));
264 nsCOMPtr
<nsIURI
> otherURI
;
265 aOther
->GetDomain(getter_AddRefs(otherURI
));
266 bool otherSetDomain
= !!otherURI
;
268 aOther
->GetURI(getter_AddRefs(otherURI
));
271 *aResult
= thisSetDomain
== otherSetDomain
&&
272 nsScriptSecurityManager::SecurityCompareURIs(thisURI
, otherURI
);
277 nsPrincipal::Equals(nsIPrincipal
*aOther
, bool *aResult
)
282 NS_WARNING("Need a principal to compare this to!");
286 if (aOther
== this) {
291 if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther
)) {
295 nsCOMPtr
<nsIURI
> otherURI
;
296 nsresult rv
= aOther
->GetURI(getter_AddRefs(otherURI
));
301 NS_ASSERTION(mCodebase
,
302 "shouldn't be calling this on principals from preferences");
304 // Compare codebases.
305 *aResult
= nsScriptSecurityManager::SecurityCompareURIs(mCodebase
,
311 nsPrincipal::Subsumes(nsIPrincipal
*aOther
, bool *aResult
)
313 return Equals(aOther
, aResult
);
317 nsPrincipal::SubsumesConsideringDomain(nsIPrincipal
*aOther
, bool *aResult
)
319 return EqualsConsideringDomain(aOther
, aResult
);
323 nsPrincipal::GetURI(nsIURI
** aURI
)
325 if (mCodebaseImmutable
) {
326 NS_ADDREF(*aURI
= mCodebase
);
335 return NS_EnsureSafeToReturn(mCodebase
, aURI
);
339 nsPrincipal::CheckMayLoad(nsIURI
* aURI
, bool aReport
, bool aAllowIfInheritsPrincipal
)
341 if (aAllowIfInheritsPrincipal
) {
342 // If the caller specified to allow loads of URIs that inherit
343 // our principal, allow the load if this URI inherits its principal
344 if (nsPrincipal::IsPrincipalInherited(aURI
)) {
349 if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase
, aURI
)) {
353 // If strict file origin policy is in effect, local files will always fail
354 // SecurityCompareURIs unless they are identical. Explicitly check file origin
355 // policy, in that case.
356 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
357 NS_URIIsLocalFile(aURI
) &&
358 NS_RelaxStrictFileOriginPolicy(aURI
, mCodebase
)) {
363 nsScriptSecurityManager::ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase
, aURI
);
365 return NS_ERROR_DOM_BAD_URI
;
369 nsPrincipal::SetURI(nsIURI
* aURI
)
371 mCodebase
= NS_TryToMakeImmutable(aURI
);
372 mCodebaseImmutable
= URIIsImmutable(mCodebase
);
376 nsPrincipal::GetHashValue(uint32_t* aValue
)
378 NS_PRECONDITION(mCodebase
, "Need a codebase");
380 *aValue
= nsScriptSecurityManager::HashPrincipalByOrigin(this);
385 nsPrincipal::GetDomain(nsIURI
** aDomain
)
392 if (mDomainImmutable
) {
393 NS_ADDREF(*aDomain
= mDomain
);
397 return NS_EnsureSafeToReturn(mDomain
, aDomain
);
401 nsPrincipal::SetDomain(nsIURI
* aDomain
)
403 mDomain
= NS_TryToMakeImmutable(aDomain
);
404 mDomainImmutable
= URIIsImmutable(mDomain
);
406 // Recompute all wrappers between compartments using this principal and other
407 // non-chrome compartments.
408 AutoSafeJSContext cx
;
409 JSPrincipals
*principals
= nsJSPrincipals::get(static_cast<nsIPrincipal
*>(this));
410 bool success
= js::RecomputeWrappers(cx
, js::ContentCompartmentsOnly(),
411 js::CompartmentsWithPrincipals(principals
));
412 NS_ENSURE_TRUE(success
, NS_ERROR_FAILURE
);
413 success
= js::RecomputeWrappers(cx
, js::CompartmentsWithPrincipals(principals
),
414 js::ContentCompartmentsOnly());
415 NS_ENSURE_TRUE(success
, NS_ERROR_FAILURE
);
421 nsPrincipal::GetJarPrefix(nsACString
& aJarPrefix
)
423 MOZ_ASSERT(mAppId
!= nsIScriptSecurityManager::UNKNOWN_APP_ID
);
425 mozilla::GetJarPrefix(mAppId
, mInMozBrowser
, aJarPrefix
);
430 nsPrincipal::GetAppStatus(uint16_t* aAppStatus
)
432 *aAppStatus
= GetAppStatus();
437 nsPrincipal::GetAppId(uint32_t* aAppId
)
439 if (mAppId
== nsIScriptSecurityManager::UNKNOWN_APP_ID
) {
441 *aAppId
= nsIScriptSecurityManager::NO_APP_ID
;
450 nsPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement
)
452 *aIsInBrowserElement
= mInMozBrowser
;
457 nsPrincipal::GetUnknownAppId(bool* aUnknownAppId
)
459 *aUnknownAppId
= mAppId
== nsIScriptSecurityManager::UNKNOWN_APP_ID
;
464 nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal
)
466 *aIsNullPrincipal
= false;
471 nsPrincipal::GetBaseDomain(nsACString
& aBaseDomain
)
473 // For a file URI, we return the file path.
474 if (NS_URIIsLocalFile(mCodebase
)) {
475 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(mCodebase
);
478 return url
->GetFilePath(aBaseDomain
);
482 // For everything else, we ask the TLD service via
483 // the ThirdPartyUtil.
484 nsCOMPtr
<mozIThirdPartyUtil
> thirdPartyUtil
=
485 do_GetService(THIRDPARTYUTIL_CONTRACTID
);
486 if (thirdPartyUtil
) {
487 return thirdPartyUtil
->GetBaseDomain(mCodebase
, aBaseDomain
);
494 nsPrincipal::Read(nsIObjectInputStream
* aStream
)
496 nsCOMPtr
<nsISupports
> supports
;
497 nsCOMPtr
<nsIURI
> codebase
;
498 nsresult rv
= NS_ReadOptionalObject(aStream
, true, getter_AddRefs(supports
));
503 codebase
= do_QueryInterface(supports
);
505 nsCOMPtr
<nsIURI
> domain
;
506 rv
= NS_ReadOptionalObject(aStream
, true, getter_AddRefs(supports
));
511 domain
= do_QueryInterface(supports
);
514 rv
= aStream
->Read32(&appId
);
515 NS_ENSURE_SUCCESS(rv
, rv
);
518 rv
= aStream
->ReadBoolean(&inMozBrowser
);
519 NS_ENSURE_SUCCESS(rv
, rv
);
521 rv
= NS_ReadOptionalObject(aStream
, true, getter_AddRefs(supports
));
522 NS_ENSURE_SUCCESS(rv
, rv
);
525 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= do_QueryInterface(supports
, &rv
);
527 rv
= Init(codebase
, appId
, inMozBrowser
);
528 NS_ENSURE_SUCCESS(rv
, rv
);
531 NS_ENSURE_SUCCESS(rv
, rv
);
533 // need to link in the CSP context here (link in the URI of the protected
536 csp
->SetRequestContext(codebase
, nullptr, nullptr);
545 nsPrincipal::Write(nsIObjectOutputStream
* aStream
)
547 NS_ENSURE_STATE(mCodebase
);
549 nsresult rv
= NS_WriteOptionalCompoundObject(aStream
, mCodebase
, NS_GET_IID(nsIURI
),
555 rv
= NS_WriteOptionalCompoundObject(aStream
, mDomain
, NS_GET_IID(nsIURI
),
561 aStream
->Write32(mAppId
);
562 aStream
->WriteBoolean(mInMozBrowser
);
564 rv
= NS_WriteOptionalCompoundObject(aStream
, mCSP
,
565 NS_GET_IID(nsIContentSecurityPolicy
),
571 // mCodebaseImmutable and mDomainImmutable will be recomputed based
572 // on the deserialized URIs in Read().
578 nsPrincipal::GetAppStatus()
580 if (mAppId
== nsIScriptSecurityManager::UNKNOWN_APP_ID
) {
581 NS_WARNING("Asking for app status on a principal with an unknown app id");
582 return nsIPrincipal::APP_STATUS_NOT_INSTALLED
;
584 return nsScriptSecurityManager::AppStatusForPrincipal(this);
587 /************************************************************************************************************************/
589 static const char EXPANDED_PRINCIPAL_SPEC
[] = "[Expanded Principal]";
591 NS_IMPL_CLASSINFO(nsExpandedPrincipal
, nullptr, nsIClassInfo::MAIN_THREAD_ONLY
,
592 NS_EXPANDEDPRINCIPAL_CID
)
593 NS_IMPL_QUERY_INTERFACE_CI(nsExpandedPrincipal
,
595 nsIExpandedPrincipal
)
596 NS_IMPL_CI_INTERFACE_GETTER(nsExpandedPrincipal
,
598 nsIExpandedPrincipal
)
599 NS_IMPL_ADDREF_INHERITED(nsExpandedPrincipal
, nsBasePrincipal
)
600 NS_IMPL_RELEASE_INHERITED(nsExpandedPrincipal
, nsBasePrincipal
)
602 nsExpandedPrincipal::nsExpandedPrincipal(nsTArray
<nsCOMPtr
<nsIPrincipal
> > &aWhiteList
)
604 mPrincipals
.AppendElements(aWhiteList
);
607 nsExpandedPrincipal::~nsExpandedPrincipal()
611 nsExpandedPrincipal::GetDomain(nsIURI
** aDomain
)
618 nsExpandedPrincipal::SetDomain(nsIURI
* aDomain
)
624 nsExpandedPrincipal::GetOrigin(char** aOrigin
)
626 *aOrigin
= ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC
));
627 return *aOrigin
? NS_OK
: NS_ERROR_OUT_OF_MEMORY
;
630 typedef nsresult (NS_STDCALL
nsIPrincipal::*nsIPrincipalMemFn
)(nsIPrincipal
* aOther
,
632 #define CALL_MEMBER_FUNCTION(THIS,MEM_FN) ((THIS)->*(MEM_FN))
634 // nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsConsideringDomain
635 // shares the same logic. The difference only that Equals requires 'this'
636 // and 'aOther' to Subsume each other while EqualsConsideringDomain requires
637 // bidirectional SubsumesConsideringDomain.
639 Equals(nsExpandedPrincipal
* aThis
, nsIPrincipalMemFn aFn
, nsIPrincipal
* aOther
,
642 // If (and only if) 'aThis' and 'aOther' both Subsume/SubsumesConsideringDomain
643 // each other, then they are Equal.
645 // Calling the corresponding subsume function on this (aFn).
646 nsresult rv
= CALL_MEMBER_FUNCTION(aThis
, aFn
)(aOther
, aResult
);
647 NS_ENSURE_SUCCESS(rv
, rv
);
651 // Calling the corresponding subsume function on aOther (aFn).
652 rv
= CALL_MEMBER_FUNCTION(aOther
, aFn
)(aThis
, aResult
);
653 NS_ENSURE_SUCCESS(rv
, rv
);
658 nsExpandedPrincipal::Equals(nsIPrincipal
* aOther
, bool* aResult
)
660 return ::Equals(this, &nsIPrincipal::Subsumes
, aOther
, aResult
);
664 nsExpandedPrincipal::EqualsConsideringDomain(nsIPrincipal
* aOther
, bool* aResult
)
666 return ::Equals(this, &nsIPrincipal::SubsumesConsideringDomain
, aOther
, aResult
);
669 // nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesConsideringDomain
670 // shares the same logic. The difference only that Subsumes calls are replaced
671 //with SubsumesConsideringDomain calls in the second case.
673 Subsumes(nsExpandedPrincipal
* aThis
, nsIPrincipalMemFn aFn
, nsIPrincipal
* aOther
,
677 nsCOMPtr
<nsIExpandedPrincipal
> expanded
= do_QueryInterface(aOther
);
679 // If aOther is an ExpandedPrincipal too, check if all of its
680 // principals are subsumed.
681 nsTArray
< nsCOMPtr
<nsIPrincipal
> >* otherList
;
682 expanded
->GetWhiteList(&otherList
);
683 for (uint32_t i
= 0; i
< otherList
->Length(); ++i
){
684 rv
= CALL_MEMBER_FUNCTION(aThis
, aFn
)((*otherList
)[i
], aResult
);
685 NS_ENSURE_SUCCESS(rv
, rv
);
687 // If we don't subsume at least one principal of aOther, return false.
692 // For a regular aOther, one of our principals must subsume it.
693 nsTArray
< nsCOMPtr
<nsIPrincipal
> >* list
;
694 aThis
->GetWhiteList(&list
);
695 for (uint32_t i
= 0; i
< list
->Length(); ++i
){
696 rv
= CALL_MEMBER_FUNCTION((*list
)[i
], aFn
)(aOther
, aResult
);
697 NS_ENSURE_SUCCESS(rv
, rv
);
699 // If one of our principal subsumes it, return true.
707 #undef CALL_MEMBER_FUNCTION
710 nsExpandedPrincipal::Subsumes(nsIPrincipal
* aOther
, bool* aResult
)
712 return ::Subsumes(this, &nsIPrincipal::Subsumes
, aOther
, aResult
);
716 nsExpandedPrincipal::SubsumesConsideringDomain(nsIPrincipal
* aOther
, bool* aResult
)
718 return ::Subsumes(this, &nsIPrincipal::SubsumesConsideringDomain
, aOther
, aResult
);
722 nsExpandedPrincipal::CheckMayLoad(nsIURI
* uri
, bool aReport
, bool aAllowIfInheritsPrincipal
)
725 for (uint32_t i
= 0; i
< mPrincipals
.Length(); ++i
){
726 rv
= mPrincipals
[i
]->CheckMayLoad(uri
, aReport
, aAllowIfInheritsPrincipal
);
727 if (NS_SUCCEEDED(rv
))
731 return NS_ERROR_DOM_BAD_URI
;
735 nsExpandedPrincipal::GetHashValue(uint32_t* result
)
737 MOZ_CRASH("extended principal should never be used as key in a hash map");
741 nsExpandedPrincipal::GetURI(nsIURI
** aURI
)
748 nsExpandedPrincipal::GetWhiteList(nsTArray
<nsCOMPtr
<nsIPrincipal
> >** aWhiteList
)
750 *aWhiteList
= &mPrincipals
;
755 nsExpandedPrincipal::GetJarPrefix(nsACString
& aJarPrefix
)
757 aJarPrefix
.Truncate();
762 nsExpandedPrincipal::GetAppStatus(uint16_t* aAppStatus
)
764 *aAppStatus
= nsIPrincipal::APP_STATUS_NOT_INSTALLED
;
769 nsExpandedPrincipal::GetAppId(uint32_t* aAppId
)
771 *aAppId
= nsIScriptSecurityManager::NO_APP_ID
;
776 nsExpandedPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement
)
778 *aIsInBrowserElement
= false;
783 nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId
)
785 *aUnknownAppId
= false;
790 nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal
)
792 *aIsNullPrincipal
= false;
797 nsExpandedPrincipal::GetBaseDomain(nsACString
& aBaseDomain
)
799 return NS_ERROR_NOT_AVAILABLE
;
803 nsExpandedPrincipal::GetScriptLocation(nsACString
& aStr
)
805 // Is that a good idea to list it's principals?
806 aStr
.Assign(EXPANDED_PRINCIPAL_SPEC
);
810 void nsExpandedPrincipal::dumpImpl()
812 fprintf(stderr
, "nsExpandedPrincipal (%p)\n", static_cast<void*>(this));
816 //////////////////////////////////////////
817 // Methods implementing nsISerializable //
818 //////////////////////////////////////////
821 nsExpandedPrincipal::Read(nsIObjectInputStream
* aStream
)
823 return NS_ERROR_NOT_IMPLEMENTED
;
827 nsExpandedPrincipal::Write(nsIObjectOutputStream
* aStream
)
829 return NS_ERROR_NOT_IMPLEMENTED
;