Bug 545431, fix versioning of mac sdks, r=ted.mielczarek
[gecko.git] / caps / src / nsPrincipal.cpp
blob1c3c0a561dcf5d6ff0e14c0c3cdd23bc5434d339
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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2003
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Christopher A. Aillon <christopher@aillon.com>
25 * Giorgio Maone <g.maone@informaction.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nscore.h"
42 #include "nsScriptSecurityManager.h"
43 #include "nsString.h"
44 #include "nsReadableUtils.h"
45 #include "plstr.h"
46 #include "nsCRT.h"
47 #include "nsIURI.h"
48 #include "nsIFileURL.h"
49 #include "nsIProtocolHandler.h"
50 #include "nsNetUtil.h"
51 #include "nsJSPrincipals.h"
52 #include "nsVoidArray.h"
53 #include "nsHashtable.h"
54 #include "nsIObjectInputStream.h"
55 #include "nsIObjectOutputStream.h"
56 #include "nsIPrefBranch2.h"
57 #include "nsIPrefService.h"
58 #include "nsIClassInfoImpl.h"
59 #include "nsDOMError.h"
60 #include "nsIContentSecurityPolicy.h"
62 #include "nsPrincipal.h"
64 class nsCodeBasePrefObserver : nsIObserver
66 public:
67 nsCodeBasePrefObserver()
69 NS_ASSERTION(!sObserverInstalled, "Shouldn't recreate observer\n");
71 ~nsCodeBasePrefObserver()
73 sObserverInstalled = PR_FALSE;
76 void Init()
78 nsCOMPtr<nsIPrefBranch2> prefBranch =
79 do_GetService(NS_PREFSERVICE_CONTRACTID);
80 if (prefBranch) {
81 if (NS_FAILED(prefBranch->GetBoolPref(PrefName(), &sPrefValue))) {
82 sPrefValue = PR_FALSE;
84 if (NS_SUCCEEDED(prefBranch->AddObserver(PrefName(), this, PR_FALSE))) {
85 sObserverInstalled = PR_TRUE;
90 NS_DECL_ISUPPORTS
92 NS_IMETHOD Observe(nsISupports* aSubject,
93 const char* aTopic,
94 const PRUnichar* aData)
96 NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
97 "Wrong topic!");
98 NS_ASSERTION(!strcmp(NS_ConvertUTF16toUTF8(aData).get(), PrefName()),
99 "Wrong pref!");
101 nsCOMPtr<nsIPrefBranch> prefBranch(do_QueryInterface(aSubject));
102 if (!prefBranch ||
103 NS_FAILED(prefBranch->GetBoolPref(PrefName(), &sPrefValue))) {
104 sPrefValue = PR_FALSE;
106 return NS_OK;
109 const char* PrefName()
111 static const char pref[] = "signed.applets.codebase_principal_support";
112 return pref;
115 static PRBool PrefValue() { return sPrefValue; }
116 static PRBool Installed() { return sObserverInstalled; }
119 protected:
120 static PRBool sPrefValue;
121 static PRBool sObserverInstalled;
124 PRBool nsCodeBasePrefObserver::sPrefValue = PR_FALSE;
125 PRBool nsCodeBasePrefObserver::sObserverInstalled = PR_FALSE;
126 NS_IMPL_ISUPPORTS1(nsCodeBasePrefObserver, nsIObserver)
128 static PRBool URIIsImmutable(nsIURI* aURI)
130 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(aURI));
131 PRBool isMutable;
132 return
133 mutableObj &&
134 NS_SUCCEEDED(mutableObj->GetMutable(&isMutable)) &&
135 !isMutable;
138 // Static member variables
139 PRInt32 nsPrincipal::sCapabilitiesOrdinal = 0;
140 const char nsPrincipal::sInvalid[] = "Invalid";
143 NS_IMPL_QUERY_INTERFACE2_CI(nsPrincipal,
144 nsIPrincipal,
145 nsISerializable)
146 NS_IMPL_CI_INTERFACE_GETTER2(nsPrincipal,
147 nsIPrincipal,
148 nsISerializable)
150 NS_IMETHODIMP_(nsrefcnt)
151 nsPrincipal::AddRef()
153 NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
154 // XXXcaa does this need to be threadsafe? See bug 143559.
155 nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
156 NS_LOG_ADDREF(this, count, "nsPrincipal", sizeof(*this));
157 return count;
160 NS_IMETHODIMP_(nsrefcnt)
161 nsPrincipal::Release()
163 NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
164 nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
165 NS_LOG_RELEASE(this, count, "nsPrincipal");
166 if (count == 0) {
167 NS_DELETEXPCOM(this);
170 return count;
173 nsPrincipal::nsPrincipal()
174 : mCapabilities(nsnull),
175 mSecurityPolicy(nsnull),
176 mTrusted(PR_FALSE),
177 mInitialized(PR_FALSE),
178 mCodebaseImmutable(PR_FALSE),
179 mDomainImmutable(PR_FALSE)
181 if (!nsCodeBasePrefObserver::Installed()) {
182 nsRefPtr<nsCodeBasePrefObserver> obs = new nsCodeBasePrefObserver();
183 if (obs)
184 obs->Init();
185 NS_WARN_IF_FALSE(nsCodeBasePrefObserver::Installed(),
186 "Installing nsCodeBasePrefObserver failed!");
190 nsresult
191 nsPrincipal::Init(const nsACString& aCertFingerprint,
192 const nsACString& aSubjectName,
193 const nsACString& aPrettyName,
194 nsISupports* aCert,
195 nsIURI *aCodebase)
197 NS_ENSURE_STATE(!mInitialized);
198 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() || aCodebase); // better have one of these.
200 mInitialized = PR_TRUE;
202 mCodebase = NS_TryToMakeImmutable(aCodebase);
203 mCodebaseImmutable = URIIsImmutable(mCodebase);
205 nsresult rv;
206 if (!aCertFingerprint.IsEmpty()) {
207 rv = SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert);
208 if (NS_SUCCEEDED(rv)) {
209 rv = mJSPrincipals.Init(this, mCert->fingerprint);
212 else {
213 nsCAutoString spec;
214 rv = mCodebase->GetSpec(spec);
215 if (NS_SUCCEEDED(rv)) {
216 rv = mJSPrincipals.Init(this, spec);
220 NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrincipal::Init() failed");
222 return rv;
225 nsPrincipal::~nsPrincipal(void)
227 SetSecurityPolicy(nsnull);
228 delete mCapabilities;
231 NS_IMETHODIMP
232 nsPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **jsprin)
234 NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr, "mJSPrincipals is uninitialized!");
236 JSPRINCIPALS_HOLD(cx, &mJSPrincipals);
237 *jsprin = &mJSPrincipals;
238 return NS_OK;
241 NS_IMETHODIMP
242 nsPrincipal::GetOrigin(char **aOrigin)
244 *aOrigin = nsnull;
246 nsCOMPtr<nsIURI> origin;
247 if (mCodebase) {
248 origin = NS_GetInnermostURI(mCodebase);
251 if (!origin) {
252 NS_ASSERTION(mCert, "No Domain or Codebase for a non-cert principal");
253 return NS_ERROR_FAILURE;
256 nsCAutoString hostPort;
258 // chrome: URLs don't have a meaningful origin, so make
259 // sure we just get the full spec for them.
260 // XXX this should be removed in favor of the solution in
261 // bug 160042.
262 PRBool isChrome;
263 nsresult rv = origin->SchemeIs("chrome", &isChrome);
264 if (NS_SUCCEEDED(rv) && !isChrome) {
265 rv = origin->GetHostPort(hostPort);
268 if (NS_SUCCEEDED(rv) && !isChrome) {
269 nsCAutoString scheme;
270 rv = origin->GetScheme(scheme);
271 NS_ENSURE_SUCCESS(rv, rv);
272 *aOrigin = ToNewCString(scheme + NS_LITERAL_CSTRING("://") + hostPort);
274 else {
275 // Some URIs (e.g., nsSimpleURI) don't support host. Just
276 // get the full spec.
277 nsCAutoString spec;
278 rv = origin->GetSpec(spec);
279 NS_ENSURE_SUCCESS(rv, rv);
280 *aOrigin = ToNewCString(spec);
283 return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
286 NS_IMETHODIMP
287 nsPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
289 if (mSecurityPolicy && mSecurityPolicy->IsInvalid())
290 SetSecurityPolicy(nsnull);
292 *aSecurityPolicy = (void *) mSecurityPolicy;
293 return NS_OK;
296 NS_IMETHODIMP
297 nsPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
299 DomainPolicy *newPolicy = reinterpret_cast<DomainPolicy *>(aSecurityPolicy);
300 if (newPolicy)
301 newPolicy->Hold();
303 if (mSecurityPolicy)
304 mSecurityPolicy->Drop();
306 mSecurityPolicy = newPolicy;
307 return NS_OK;
310 NS_IMETHODIMP
311 nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
313 *aResult = PR_FALSE;
315 if (!aOther) {
316 NS_WARNING("Need a principal to compare this to!");
317 return NS_OK;
320 if (this != aOther) {
321 PRBool otherHasCert;
322 aOther->GetHasCertificate(&otherHasCert);
323 if (otherHasCert != (mCert != nsnull)) {
324 // One has a cert while the other doesn't. Not equal.
325 return NS_OK;
328 if (mCert) {
329 nsCAutoString str;
330 aOther->GetFingerprint(str);
331 *aResult = str.Equals(mCert->fingerprint);
333 // If either subject name is empty, just let the result stand (so that
334 // nsScriptSecurityManager::SetCanEnableCapability works), but if they're
335 // both non-empty, only claim equality if they're equal.
336 if (*aResult && !mCert->subjectName.IsEmpty()) {
337 // Check the other principal's subject name
338 aOther->GetSubjectName(str);
339 *aResult = str.Equals(mCert->subjectName) || str.IsEmpty();
342 if (!*aResult) {
343 return NS_OK;
346 // If either principal has no URI, it's the saved principal from
347 // preferences; in that case, test true. Do NOT test true if the two
348 // principals have URIs with different codebases.
349 nsCOMPtr<nsIURI> otherURI;
350 nsresult rv = aOther->GetURI(getter_AddRefs(otherURI));
351 if (NS_FAILED(rv)) {
352 *aResult = PR_FALSE;
353 return rv;
356 if (!otherURI || !mCodebase) {
357 return NS_OK;
360 // Fall through to the codebase comparison.
363 // Codebases are equal if they have the same origin.
364 *aResult =
365 NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
366 aOther));
367 return NS_OK;
370 *aResult = PR_TRUE;
371 return NS_OK;
374 NS_IMETHODIMP
375 nsPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
377 return Equals(aOther, aResult);
380 static PRBool
381 URIIsLocalFile(nsIURI *aURI)
383 PRBool isFile;
384 nsCOMPtr<nsINetUtil> util = do_GetIOService();
386 return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
387 nsIProtocolHandler::URI_IS_LOCAL_FILE,
388 &isFile)) &&
389 isFile;
392 NS_IMETHODIMP
393 nsPrincipal::CheckMayLoad(nsIURI* aURI, PRBool aReport)
395 if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
396 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
397 URIIsLocalFile(aURI)) {
398 nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(aURI));
400 if (!URIIsLocalFile(mCodebase)) {
401 // If the codebase is not also a file: uri then forget it
402 // (don't want resource: principals in a file: doc)
404 // note: we're not de-nesting jar: uris here, we want to
405 // keep archive content bottled up in its own little island
407 if (aReport) {
408 nsScriptSecurityManager::ReportError(
409 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
412 return NS_ERROR_DOM_BAD_URI;
416 // pull out the internal files
418 nsCOMPtr<nsIFileURL> codebaseFileURL(do_QueryInterface(mCodebase));
419 nsCOMPtr<nsIFile> targetFile;
420 nsCOMPtr<nsIFile> codebaseFile;
421 PRBool targetIsDir;
423 // Make sure targetFile is not a directory (bug 209234)
424 // and that it exists w/out unescaping (bug 395343)
426 if (!codebaseFileURL || !fileURL ||
427 NS_FAILED(fileURL->GetFile(getter_AddRefs(targetFile))) ||
428 NS_FAILED(codebaseFileURL->GetFile(getter_AddRefs(codebaseFile))) ||
429 !targetFile || !codebaseFile ||
430 NS_FAILED(targetFile->Normalize()) ||
431 NS_FAILED(codebaseFile->Normalize()) ||
432 NS_FAILED(targetFile->IsDirectory(&targetIsDir)) ||
433 targetIsDir) {
434 if (aReport) {
435 nsScriptSecurityManager::ReportError(
436 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
439 return NS_ERROR_DOM_BAD_URI;
443 // If the file to be loaded is in a subdirectory of the codebase
444 // (or same-dir if codebase is not a directory) then it will
445 // inherit its codebase principal and be scriptable by that codebase.
447 PRBool codebaseIsDir;
448 PRBool contained = PR_FALSE;
449 nsresult rv = codebaseFile->IsDirectory(&codebaseIsDir);
450 if (NS_SUCCEEDED(rv) && codebaseIsDir) {
451 rv = codebaseFile->Contains(targetFile, PR_TRUE, &contained);
453 else {
454 nsCOMPtr<nsIFile> codebaseParent;
455 rv = codebaseFile->GetParent(getter_AddRefs(codebaseParent));
456 if (NS_SUCCEEDED(rv) && codebaseParent) {
457 rv = codebaseParent->Contains(targetFile, PR_TRUE, &contained);
461 if (NS_SUCCEEDED(rv) && contained) {
462 return NS_OK;
466 if (aReport) {
467 nsScriptSecurityManager::ReportError(
468 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
471 return NS_ERROR_DOM_BAD_URI;
474 return NS_OK;
477 NS_IMETHODIMP
478 nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
480 // If this principal is marked invalid, can't enable any capabilities
481 if (mCapabilities) {
482 nsCStringKey invalidKey(sInvalid);
483 if (mCapabilities->Exists(&invalidKey)) {
484 *result = nsIPrincipal::ENABLE_DENIED;
486 return NS_OK;
490 if (!mCert && !mTrusted) {
491 NS_ASSERTION(mInitialized, "Trying to enable a capability on an "
492 "uninitialized principal");
494 // If we are a non-trusted codebase principal, capabilities can not
495 // be enabled if the user has not set the pref allowing scripts to
496 // request enhanced capabilities; however, the file: and resource:
497 // schemes are special and may be able to get extra capabilities
498 // even with the pref disabled.
500 if (!nsCodeBasePrefObserver::PrefValue()) {
501 PRBool mightEnable = PR_FALSE;
502 nsresult rv = mCodebase->SchemeIs("file", &mightEnable);
503 if (NS_FAILED(rv) || !mightEnable) {
504 rv = mCodebase->SchemeIs("resource", &mightEnable);
505 if (NS_FAILED(rv) || !mightEnable) {
506 *result = nsIPrincipal::ENABLE_DENIED;
508 return NS_OK;
514 const char *start = capability;
515 *result = nsIPrincipal::ENABLE_GRANTED;
516 for(;;) {
517 const char *space = PL_strchr(start, ' ');
518 PRInt32 len = space ? space - start : strlen(start);
519 nsCAutoString capString(start, len);
520 nsCStringKey key(capString);
521 PRInt16 value =
522 mCapabilities ? (PRInt16)NS_PTR_TO_INT32(mCapabilities->Get(&key)) : 0;
523 if (value == 0 || value == nsIPrincipal::ENABLE_UNKNOWN) {
524 // We don't know whether we can enable this capability,
525 // so we should ask the user.
526 value = nsIPrincipal::ENABLE_WITH_USER_PERMISSION;
529 if (value < *result) {
530 *result = value;
533 if (!space) {
534 break;
537 start = space + 1;
540 return NS_OK;
543 NS_IMETHODIMP
544 nsPrincipal::SetCanEnableCapability(const char *capability,
545 PRInt16 canEnable)
547 // If this principal is marked invalid, can't enable any capabilities
548 if (!mCapabilities) {
549 mCapabilities = new nsHashtable(7); // XXXbz gets bumped up to 16 anyway
550 NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
553 nsCStringKey invalidKey(sInvalid);
554 if (mCapabilities->Exists(&invalidKey)) {
555 return NS_OK;
558 if (PL_strcmp(capability, sInvalid) == 0) {
559 mCapabilities->Reset();
562 const char *start = capability;
563 for(;;) {
564 const char *space = PL_strchr(start, ' ');
565 int len = space ? space - start : strlen(start);
566 nsCAutoString capString(start, len);
567 nsCStringKey key(capString);
568 mCapabilities->Put(&key, NS_INT32_TO_PTR(canEnable));
569 if (!space) {
570 break;
573 start = space + 1;
576 return NS_OK;
579 NS_IMETHODIMP
580 nsPrincipal::IsCapabilityEnabled(const char *capability, void *annotation,
581 PRBool *result)
583 *result = PR_FALSE;
584 nsHashtable *ht = (nsHashtable *) annotation;
585 if (!ht) {
586 return NS_OK;
588 const char *start = capability;
589 for(;;) {
590 const char *space = PL_strchr(start, ' ');
591 int len = space ? space - start : strlen(start);
592 nsCAutoString capString(start, len);
593 nsCStringKey key(capString);
594 *result = (ht->Get(&key) == (void *) AnnotationEnabled);
595 if (!*result) {
596 // If any single capability is not enabled, then return false.
597 return NS_OK;
600 if (!space) {
601 return NS_OK;
604 start = space + 1;
607 return NS_OK;
610 NS_IMETHODIMP
611 nsPrincipal::EnableCapability(const char *capability, void **annotation)
613 return SetCapability(capability, annotation, AnnotationEnabled);
616 NS_IMETHODIMP
617 nsPrincipal::DisableCapability(const char *capability, void **annotation)
619 return SetCapability(capability, annotation, AnnotationDisabled);
622 NS_IMETHODIMP
623 nsPrincipal::RevertCapability(const char *capability, void **annotation)
625 if (*annotation) {
626 nsHashtable *ht = (nsHashtable *) *annotation;
627 const char *start = capability;
628 for(;;) {
629 const char *space = PL_strchr(start, ' ');
630 int len = space ? space - start : strlen(start);
631 nsCAutoString capString(start, len);
632 nsCStringKey key(capString);
633 ht->Remove(&key);
634 if (!space) {
635 return NS_OK;
638 start = space + 1;
641 return NS_OK;
644 nsresult
645 nsPrincipal::SetCapability(const char *capability, void **annotation,
646 AnnotationValue value)
648 if (*annotation == nsnull) {
649 nsHashtable* ht = new nsHashtable(5);
651 if (!ht) {
652 return NS_ERROR_OUT_OF_MEMORY;
655 // This object owns its annotations. Save them so we can release
656 // them when we destroy this object.
657 if (!mAnnotations.AppendElement(ht)) {
658 delete ht;
659 return NS_ERROR_OUT_OF_MEMORY;
662 *annotation = ht;
665 const char *start = capability;
666 for(;;) {
667 const char *space = PL_strchr(start, ' ');
668 int len = space ? space - start : strlen(start);
669 nsCAutoString capString(start, len);
670 nsCStringKey key(capString);
671 nsHashtable *ht = static_cast<nsHashtable *>(*annotation);
672 ht->Put(&key, (void *) value);
673 if (!space) {
674 break;
677 start = space + 1;
680 return NS_OK;
683 NS_IMETHODIMP
684 nsPrincipal::GetHasCertificate(PRBool* aResult)
686 *aResult = (mCert != nsnull);
688 return NS_OK;
691 NS_IMETHODIMP
692 nsPrincipal::GetURI(nsIURI** aURI)
694 if (mCodebaseImmutable) {
695 NS_ADDREF(*aURI = mCodebase);
696 return NS_OK;
699 if (!mCodebase) {
700 *aURI = nsnull;
701 return NS_OK;
704 return NS_EnsureSafeToReturn(mCodebase, aURI);
707 void
708 nsPrincipal::SetURI(nsIURI* aURI)
710 mCodebase = NS_TryToMakeImmutable(aURI);
711 mCodebaseImmutable = URIIsImmutable(mCodebase);
715 nsresult
716 nsPrincipal::SetCertificate(const nsACString& aFingerprint,
717 const nsACString& aSubjectName,
718 const nsACString& aPrettyName,
719 nsISupports* aCert)
721 NS_ENSURE_STATE(!mCert);
723 if (aFingerprint.IsEmpty()) {
724 return NS_ERROR_INVALID_ARG;
727 mCert = new Certificate(aFingerprint, aSubjectName, aPrettyName, aCert);
728 if (!mCert) {
729 return NS_ERROR_OUT_OF_MEMORY;
732 return NS_OK;
735 NS_IMETHODIMP
736 nsPrincipal::GetFingerprint(nsACString& aFingerprint)
738 NS_ENSURE_STATE(mCert);
740 aFingerprint = mCert->fingerprint;
742 return NS_OK;
745 NS_IMETHODIMP
746 nsPrincipal::GetPrettyName(nsACString& aName)
748 NS_ENSURE_STATE(mCert);
750 aName = mCert->prettyName;
752 return NS_OK;
755 NS_IMETHODIMP
756 nsPrincipal::GetSubjectName(nsACString& aName)
758 NS_ENSURE_STATE(mCert);
760 aName = mCert->subjectName;
762 return NS_OK;
765 NS_IMETHODIMP
766 nsPrincipal::GetCertificate(nsISupports** aCertificate)
768 if (mCert) {
769 NS_IF_ADDREF(*aCertificate = mCert->cert);
771 else {
772 *aCertificate = nsnull;
774 return NS_OK;
777 NS_IMETHODIMP
778 nsPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
780 NS_IF_ADDREF(*aCsp = mCSP);
781 return NS_OK;
784 NS_IMETHODIMP
785 nsPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
787 // If CSP was already set, it should not be destroyed! Instead, it should
788 // get set anew when a new principal is created.
789 if (mCSP)
790 return NS_ERROR_ALREADY_INITIALIZED;
792 mCSP = aCsp;
793 return NS_OK;
796 NS_IMETHODIMP
797 nsPrincipal::GetHashValue(PRUint32* aValue)
799 NS_PRECONDITION(mCert || mCodebase, "Need a cert or codebase");
801 // If there is a certificate, it takes precendence over the codebase.
802 if (mCert) {
803 *aValue = nsCRT::HashCode(mCert->fingerprint.get());
805 else {
806 *aValue = nsScriptSecurityManager::HashPrincipalByOrigin(this);
809 return NS_OK;
812 NS_IMETHODIMP
813 nsPrincipal::GetDomain(nsIURI** aDomain)
815 if (!mDomain) {
816 *aDomain = nsnull;
817 return NS_OK;
820 if (mDomainImmutable) {
821 NS_ADDREF(*aDomain = mDomain);
822 return NS_OK;
825 return NS_EnsureSafeToReturn(mDomain, aDomain);
828 NS_IMETHODIMP
829 nsPrincipal::SetDomain(nsIURI* aDomain)
831 mDomain = NS_TryToMakeImmutable(aDomain);
832 mDomainImmutable = URIIsImmutable(mDomain);
834 // Domain has changed, forget cached security policy
835 SetSecurityPolicy(nsnull);
837 return NS_OK;
840 nsresult
841 nsPrincipal::InitFromPersistent(const char* aPrefName,
842 const nsCString& aToken,
843 const nsCString& aSubjectName,
844 const nsACString& aPrettyName,
845 const char* aGrantedList,
846 const char* aDeniedList,
847 nsISupports* aCert,
848 PRBool aIsCert,
849 PRBool aTrusted)
851 NS_PRECONDITION(!mCapabilities || mCapabilities->Count() == 0,
852 "mCapabilities was already initialized?");
853 NS_PRECONDITION(mAnnotations.Length() == 0,
854 "mAnnotations was already initialized?");
855 NS_PRECONDITION(!mInitialized, "We were already initialized?");
857 mInitialized = PR_TRUE;
859 nsresult rv;
860 if (aIsCert) {
861 rv = SetCertificate(aToken, aSubjectName, aPrettyName, aCert);
863 if (NS_FAILED(rv)) {
864 return rv;
867 else {
868 rv = NS_NewURI(getter_AddRefs(mCodebase), aToken, nsnull);
869 if (NS_FAILED(rv)) {
870 NS_ERROR("Malformed URI in capability.principal preference.");
871 return rv;
874 NS_TryToSetImmutable(mCodebase);
875 mCodebaseImmutable = URIIsImmutable(mCodebase);
877 mTrusted = aTrusted;
880 rv = mJSPrincipals.Init(this, aToken);
881 NS_ENSURE_SUCCESS(rv, rv);
883 //-- Save the preference name
884 mPrefName = aPrefName;
886 const char* ordinalBegin = PL_strpbrk(aPrefName, "1234567890");
887 if (ordinalBegin) {
888 PRIntn n = atoi(ordinalBegin);
889 if (sCapabilitiesOrdinal <= n) {
890 sCapabilitiesOrdinal = n + 1;
894 //-- Store the capabilities
895 rv = NS_OK;
896 if (aGrantedList) {
897 rv = SetCanEnableCapability(aGrantedList, nsIPrincipal::ENABLE_GRANTED);
900 if (NS_SUCCEEDED(rv) && aDeniedList) {
901 rv = SetCanEnableCapability(aDeniedList, nsIPrincipal::ENABLE_DENIED);
904 return rv;
907 nsresult
908 nsPrincipal::EnsureCertData(const nsACString& aSubjectName,
909 const nsACString& aPrettyName,
910 nsISupports* aCert)
912 NS_ENSURE_STATE(mCert);
914 if (!mCert->subjectName.IsEmpty() &&
915 !mCert->subjectName.Equals(aSubjectName)) {
916 return NS_ERROR_INVALID_ARG;
919 mCert->subjectName = aSubjectName;
920 mCert->prettyName = aPrettyName;
921 mCert->cert = aCert;
922 return NS_OK;
925 struct CapabilityList
927 nsCString* granted;
928 nsCString* denied;
931 static PRBool
932 AppendCapability(nsHashKey *aKey, void *aData, void *capListPtr)
934 CapabilityList* capList = (CapabilityList*)capListPtr;
935 PRInt16 value = (PRInt16)NS_PTR_TO_INT32(aData);
936 nsCStringKey* key = (nsCStringKey *)aKey;
937 if (value == nsIPrincipal::ENABLE_GRANTED) {
938 capList->granted->Append(key->GetString(), key->GetStringLength());
939 capList->granted->Append(' ');
941 else if (value == nsIPrincipal::ENABLE_DENIED) {
942 capList->denied->Append(key->GetString(), key->GetStringLength());
943 capList->denied->Append(' ');
946 return PR_TRUE;
949 NS_IMETHODIMP
950 nsPrincipal::GetPreferences(char** aPrefName, char** aID,
951 char** aSubjectName,
952 char** aGrantedList, char** aDeniedList,
953 PRBool* aIsTrusted)
955 if (mPrefName.IsEmpty()) {
956 if (mCert) {
957 mPrefName.Assign("capability.principal.certificate.p");
959 else {
960 mPrefName.Assign("capability.principal.codebase.p");
963 mPrefName.AppendInt(sCapabilitiesOrdinal++);
964 mPrefName.Append(".id");
967 *aPrefName = nsnull;
968 *aID = nsnull;
969 *aSubjectName = nsnull;
970 *aGrantedList = nsnull;
971 *aDeniedList = nsnull;
972 *aIsTrusted = mTrusted;
974 char *prefName = nsnull;
975 char *id = nsnull;
976 char *subjectName = nsnull;
977 char *granted = nsnull;
978 char *denied = nsnull;
980 //-- Preference name
981 prefName = ToNewCString(mPrefName);
982 if (!prefName) {
983 return NS_ERROR_OUT_OF_MEMORY;
986 //-- ID
987 nsresult rv = NS_OK;
988 if (mCert) {
989 id = ToNewCString(mCert->fingerprint);
990 if (!id) {
991 rv = NS_ERROR_OUT_OF_MEMORY;
994 else {
995 rv = GetOrigin(&id);
998 if (NS_FAILED(rv)) {
999 nsMemory::Free(prefName);
1000 return rv;
1003 if (mCert) {
1004 subjectName = ToNewCString(mCert->subjectName);
1005 } else {
1006 subjectName = ToNewCString(EmptyCString());
1009 if (!subjectName) {
1010 nsMemory::Free(prefName);
1011 nsMemory::Free(id);
1012 return NS_ERROR_OUT_OF_MEMORY;
1015 //-- Capabilities
1016 nsCAutoString grantedListStr, deniedListStr;
1017 if (mCapabilities) {
1018 CapabilityList capList = CapabilityList();
1019 capList.granted = &grantedListStr;
1020 capList.denied = &deniedListStr;
1021 mCapabilities->Enumerate(AppendCapability, (void*)&capList);
1024 if (!grantedListStr.IsEmpty()) {
1025 grantedListStr.Truncate(grantedListStr.Length() - 1);
1026 granted = ToNewCString(grantedListStr);
1027 if (!granted) {
1028 nsMemory::Free(prefName);
1029 nsMemory::Free(id);
1030 nsMemory::Free(subjectName);
1031 return NS_ERROR_OUT_OF_MEMORY;
1035 if (!deniedListStr.IsEmpty()) {
1036 deniedListStr.Truncate(deniedListStr.Length() - 1);
1037 denied = ToNewCString(deniedListStr);
1038 if (!denied) {
1039 nsMemory::Free(prefName);
1040 nsMemory::Free(id);
1041 nsMemory::Free(subjectName);
1042 if (granted) {
1043 nsMemory::Free(granted);
1045 return NS_ERROR_OUT_OF_MEMORY;
1049 *aPrefName = prefName;
1050 *aID = id;
1051 *aSubjectName = subjectName;
1052 *aGrantedList = granted;
1053 *aDeniedList = denied;
1055 return NS_OK;
1058 static nsresult
1059 ReadAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey** aKey,
1060 void** aData)
1062 nsresult rv;
1063 nsCStringKey* key = new nsCStringKey(aStream, &rv);
1064 if (!key)
1065 return NS_ERROR_OUT_OF_MEMORY;
1067 if (NS_FAILED(rv)) {
1068 delete key;
1069 return rv;
1072 PRUint32 value;
1073 rv = aStream->Read32(&value);
1074 if (NS_FAILED(rv)) {
1075 delete key;
1076 return rv;
1079 *aKey = key;
1080 *aData = (void*) value;
1081 return NS_OK;
1084 static void
1085 FreeAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey* aKey,
1086 void* aData)
1088 delete aKey;
1091 NS_IMETHODIMP
1092 nsPrincipal::Read(nsIObjectInputStream* aStream)
1094 PRBool hasCapabilities;
1095 nsresult rv = aStream->ReadBoolean(&hasCapabilities);
1096 if (NS_SUCCEEDED(rv) && hasCapabilities) {
1097 mCapabilities = new nsHashtable(aStream, ReadAnnotationEntry,
1098 FreeAnnotationEntry, &rv);
1099 NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
1102 if (NS_FAILED(rv)) {
1103 return rv;
1106 rv = NS_ReadOptionalCString(aStream, mPrefName);
1107 if (NS_FAILED(rv)) {
1108 return rv;
1111 const char* ordinalBegin = PL_strpbrk(mPrefName.get(), "1234567890");
1112 if (ordinalBegin) {
1113 PRIntn n = atoi(ordinalBegin);
1114 if (sCapabilitiesOrdinal <= n) {
1115 sCapabilitiesOrdinal = n + 1;
1119 PRBool haveCert;
1120 rv = aStream->ReadBoolean(&haveCert);
1121 if (NS_FAILED(rv)) {
1122 return rv;
1125 nsCString fingerprint;
1126 nsCString subjectName;
1127 nsCString prettyName;
1128 nsCOMPtr<nsISupports> cert;
1129 if (haveCert) {
1130 rv = NS_ReadOptionalCString(aStream, fingerprint);
1131 if (NS_FAILED(rv)) {
1132 return rv;
1135 rv = NS_ReadOptionalCString(aStream, subjectName);
1136 if (NS_FAILED(rv)) {
1137 return rv;
1140 rv = NS_ReadOptionalCString(aStream, prettyName);
1141 if (NS_FAILED(rv)) {
1142 return rv;
1145 rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(cert));
1146 if (NS_FAILED(rv)) {
1147 return rv;
1151 nsCOMPtr<nsIURI> codebase;
1152 rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(codebase));
1153 if (NS_FAILED(rv)) {
1154 return rv;
1157 rv = Init(fingerprint, subjectName, prettyName, cert, codebase);
1158 NS_ENSURE_SUCCESS(rv, rv);
1160 nsCOMPtr<nsIURI> domain;
1161 rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(domain));
1162 if (NS_FAILED(rv)) {
1163 return rv;
1166 SetDomain(domain);
1168 rv = aStream->Read8(&mTrusted);
1169 if (NS_FAILED(rv)) {
1170 return rv;
1173 return NS_OK;
1176 static nsresult
1177 WriteScalarValue(nsIObjectOutputStream* aStream, void* aData)
1179 PRUint32 value = NS_PTR_TO_INT32(aData);
1181 return aStream->Write32(value);
1184 NS_IMETHODIMP
1185 nsPrincipal::Write(nsIObjectOutputStream* aStream)
1187 NS_ENSURE_STATE(mCert || mCodebase);
1189 // mAnnotations is transient data associated to specific JS stack frames. We
1190 // don't want to serialize that.
1192 PRBool hasCapabilities = (mCapabilities && mCapabilities->Count() > 0);
1193 nsresult rv = aStream->WriteBoolean(hasCapabilities);
1194 if (NS_SUCCEEDED(rv) && hasCapabilities) {
1195 rv = mCapabilities->Write(aStream, WriteScalarValue);
1198 if (NS_FAILED(rv)) {
1199 return rv;
1202 rv = NS_WriteOptionalStringZ(aStream, mPrefName.get());
1203 if (NS_FAILED(rv)) {
1204 return rv;
1207 rv = aStream->WriteBoolean(mCert != nsnull);
1208 if (NS_FAILED(rv)) {
1209 return rv;
1212 if (mCert) {
1213 NS_ENSURE_STATE(mCert->cert);
1215 rv = NS_WriteOptionalStringZ(aStream, mCert->fingerprint.get());
1216 if (NS_FAILED(rv)) {
1217 return rv;
1220 rv = NS_WriteOptionalStringZ(aStream, mCert->subjectName.get());
1221 if (NS_FAILED(rv)) {
1222 return rv;
1225 rv = NS_WriteOptionalStringZ(aStream, mCert->prettyName.get());
1226 if (NS_FAILED(rv)) {
1227 return rv;
1230 rv = aStream->WriteCompoundObject(mCert->cert, NS_GET_IID(nsISupports),
1231 PR_TRUE);
1232 if (NS_FAILED(rv)) {
1233 return rv;
1237 // mSecurityPolicy is an optimization; it'll get looked up again as needed.
1238 // Don't bother saving and restoring it, esp. since it might change if
1239 // preferences change.
1241 rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI),
1242 PR_TRUE);
1243 if (NS_FAILED(rv)) {
1244 return rv;
1247 rv = NS_WriteOptionalCompoundObject(aStream, mDomain, NS_GET_IID(nsIURI),
1248 PR_TRUE);
1249 if (NS_FAILED(rv)) {
1250 return rv;
1253 rv = aStream->Write8(mTrusted);
1254 if (NS_FAILED(rv)) {
1255 return rv;
1258 // mCodebaseImmutable and mDomainImmutable will be recomputed based
1259 // on the deserialized URIs in Read().
1261 return NS_OK;