Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / caps / src / nsPrincipal.cpp
blob2c89c565c3eadd1ed41fe87330b5cb12faf8e24b
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 "nsIPrefBranch.h"
57 #include "nsIPrefService.h"
58 #include "nsIClassInfoImpl.h"
59 #include "nsDOMError.h"
61 #include "nsPrincipal.h"
63 static PRBool URIIsImmutable(nsIURI* aURI)
65 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(aURI));
66 PRBool isMutable;
67 return
68 mutableObj &&
69 NS_SUCCEEDED(mutableObj->GetMutable(&isMutable)) &&
70 !isMutable;
73 // Static member variables
74 PRInt32 nsPrincipal::sCapabilitiesOrdinal = 0;
75 const char nsPrincipal::sInvalid[] = "Invalid";
78 NS_IMPL_QUERY_INTERFACE2_CI(nsPrincipal,
79 nsIPrincipal,
80 nsISerializable)
81 NS_IMPL_CI_INTERFACE_GETTER2(nsPrincipal,
82 nsIPrincipal,
83 nsISerializable)
85 NS_IMETHODIMP_(nsrefcnt)
86 nsPrincipal::AddRef()
88 NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
89 // XXXcaa does this need to be threadsafe? See bug 143559.
90 nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
91 NS_LOG_ADDREF(this, count, "nsPrincipal", sizeof(*this));
92 return count;
95 NS_IMETHODIMP_(nsrefcnt)
96 nsPrincipal::Release()
98 NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
99 nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
100 NS_LOG_RELEASE(this, count, "nsPrincipal");
101 if (count == 0) {
102 NS_DELETEXPCOM(this);
105 return count;
108 nsPrincipal::nsPrincipal()
109 : mCapabilities(nsnull),
110 mSecurityPolicy(nsnull),
111 mTrusted(PR_FALSE),
112 mInitialized(PR_FALSE),
113 mCodebaseImmutable(PR_FALSE),
114 mDomainImmutable(PR_FALSE)
118 nsresult
119 nsPrincipal::Init(const nsACString& aCertFingerprint,
120 const nsACString& aSubjectName,
121 const nsACString& aPrettyName,
122 nsISupports* aCert,
123 nsIURI *aCodebase)
125 NS_ENSURE_STATE(!mInitialized);
126 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() || aCodebase); // better have one of these.
128 mInitialized = PR_TRUE;
130 mCodebase = NS_TryToMakeImmutable(aCodebase);
131 mCodebaseImmutable = URIIsImmutable(mCodebase);
133 nsresult rv;
134 if (!aCertFingerprint.IsEmpty()) {
135 rv = SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert);
136 if (NS_SUCCEEDED(rv)) {
137 rv = mJSPrincipals.Init(this, mCert->fingerprint);
140 else {
141 nsCAutoString spec;
142 rv = mCodebase->GetSpec(spec);
143 if (NS_SUCCEEDED(rv)) {
144 rv = mJSPrincipals.Init(this, spec);
148 NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrincipal::Init() failed");
150 return rv;
153 nsPrincipal::~nsPrincipal(void)
155 SetSecurityPolicy(nsnull);
156 delete mCapabilities;
159 NS_IMETHODIMP
160 nsPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **jsprin)
162 NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr, "mJSPrincipals is uninitialized!");
164 JSPRINCIPALS_HOLD(cx, &mJSPrincipals);
165 *jsprin = &mJSPrincipals;
166 return NS_OK;
169 NS_IMETHODIMP
170 nsPrincipal::GetOrigin(char **aOrigin)
172 *aOrigin = nsnull;
174 nsCOMPtr<nsIURI> origin;
175 if (mCodebase) {
176 origin = NS_GetInnermostURI(mCodebase);
179 if (!origin) {
180 NS_ASSERTION(mCert, "No Domain or Codebase for a non-cert principal");
181 return NS_ERROR_FAILURE;
184 nsCAutoString hostPort;
186 // chrome: URLs don't have a meaningful origin, so make
187 // sure we just get the full spec for them.
188 // XXX this should be removed in favor of the solution in
189 // bug 160042.
190 PRBool isChrome;
191 nsresult rv = origin->SchemeIs("chrome", &isChrome);
192 if (NS_SUCCEEDED(rv) && !isChrome) {
193 rv = origin->GetHostPort(hostPort);
196 if (NS_SUCCEEDED(rv) && !isChrome) {
197 nsCAutoString scheme;
198 rv = origin->GetScheme(scheme);
199 NS_ENSURE_SUCCESS(rv, rv);
200 *aOrigin = ToNewCString(scheme + NS_LITERAL_CSTRING("://") + hostPort);
202 else {
203 // Some URIs (e.g., nsSimpleURI) don't support host. Just
204 // get the full spec.
205 nsCAutoString spec;
206 rv = origin->GetSpec(spec);
207 NS_ENSURE_SUCCESS(rv, rv);
208 *aOrigin = ToNewCString(spec);
211 return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
214 NS_IMETHODIMP
215 nsPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
217 if (mSecurityPolicy && mSecurityPolicy->IsInvalid())
218 SetSecurityPolicy(nsnull);
220 *aSecurityPolicy = (void *) mSecurityPolicy;
221 return NS_OK;
224 NS_IMETHODIMP
225 nsPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
227 DomainPolicy *newPolicy = reinterpret_cast<DomainPolicy *>(aSecurityPolicy);
228 if (newPolicy)
229 newPolicy->Hold();
231 if (mSecurityPolicy)
232 mSecurityPolicy->Drop();
234 mSecurityPolicy = newPolicy;
235 return NS_OK;
238 NS_IMETHODIMP
239 nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
241 *aResult = PR_FALSE;
243 if (!aOther) {
244 NS_WARNING("Need a principal to compare this to!");
245 return NS_OK;
248 if (this != aOther) {
249 PRBool otherHasCert;
250 aOther->GetHasCertificate(&otherHasCert);
251 if (otherHasCert != (mCert != nsnull)) {
252 // One has a cert while the other doesn't. Not equal.
253 return NS_OK;
256 if (mCert) {
257 nsCAutoString str;
258 aOther->GetFingerprint(str);
259 *aResult = str.Equals(mCert->fingerprint);
261 // If either subject name is empty, just let the result stand (so that
262 // nsScriptSecurityManager::SetCanEnableCapability works), but if they're
263 // both non-empty, only claim equality if they're equal.
264 if (*aResult && !mCert->subjectName.IsEmpty()) {
265 // Check the other principal's subject name
266 aOther->GetSubjectName(str);
267 *aResult = str.Equals(mCert->subjectName) || str.IsEmpty();
270 if (!*aResult) {
271 return NS_OK;
274 // If either principal has no URI, it's the saved principal from
275 // preferences; in that case, test true. Do NOT test true if the two
276 // principals have URIs with different codebases.
277 nsCOMPtr<nsIURI> otherURI;
278 nsresult rv = aOther->GetURI(getter_AddRefs(otherURI));
279 if (NS_FAILED(rv)) {
280 *aResult = PR_FALSE;
281 return rv;
284 if (!otherURI || !mCodebase) {
285 return NS_OK;
288 // Fall through to the codebase comparison.
291 // Codebases are equal if they have the same origin.
292 *aResult =
293 NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
294 aOther,
295 PR_FALSE));
296 return NS_OK;
299 *aResult = PR_TRUE;
300 return NS_OK;
303 NS_IMETHODIMP
304 nsPrincipal::Subsumes(nsIPrincipal *aOther, PRBool *aResult)
306 return Equals(aOther, aResult);
309 static PRBool
310 URIIsLocalFile(nsIURI *aURI)
312 PRBool isFile;
313 nsCOMPtr<nsINetUtil> util = do_GetIOService();
315 return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
316 nsIProtocolHandler::URI_IS_LOCAL_FILE,
317 &isFile)) &&
318 isFile;
321 NS_IMETHODIMP
322 nsPrincipal::CheckMayLoad(nsIURI* aURI, PRBool aReport)
324 if (!nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
325 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
326 URIIsLocalFile(aURI)) {
327 nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(aURI));
329 if (!URIIsLocalFile(mCodebase)) {
330 // If the codebase is not also a file: uri then forget it
331 // (don't want resource: principals in a file: doc)
333 // note: we're not de-nesting jar: uris here, we want to
334 // keep archive content bottled up in its own little island
336 if (aReport) {
337 nsScriptSecurityManager::ReportError(
338 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
341 return NS_ERROR_DOM_BAD_URI;
345 // pull out the internal files
347 nsCOMPtr<nsIFileURL> codebaseFileURL(do_QueryInterface(mCodebase));
348 nsCOMPtr<nsIFile> targetFile;
349 nsCOMPtr<nsIFile> codebaseFile;
350 PRBool targetIsDir;
352 // Make sure targetFile is not a directory (bug 209234)
353 // and that it exists w/out unescaping (bug 395343)
355 if (!codebaseFileURL || !fileURL ||
356 NS_FAILED(fileURL->GetFile(getter_AddRefs(targetFile))) ||
357 NS_FAILED(codebaseFileURL->GetFile(getter_AddRefs(codebaseFile))) ||
358 !targetFile || !codebaseFile ||
359 NS_FAILED(targetFile->Normalize()) ||
360 NS_FAILED(codebaseFile->Normalize()) ||
361 NS_FAILED(targetFile->IsDirectory(&targetIsDir)) ||
362 targetIsDir) {
363 if (aReport) {
364 nsScriptSecurityManager::ReportError(
365 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
368 return NS_ERROR_DOM_BAD_URI;
372 // If the file to be loaded is in a subdirectory of the codebase
373 // (or same-dir if codebase is not a directory) then it will
374 // inherit its codebase principal and be scriptable by that codebase.
376 PRBool codebaseIsDir;
377 PRBool contained = PR_FALSE;
378 nsresult rv = codebaseFile->IsDirectory(&codebaseIsDir);
379 if (NS_SUCCEEDED(rv) && codebaseIsDir) {
380 rv = codebaseFile->Contains(targetFile, PR_TRUE, &contained);
382 else {
383 nsCOMPtr<nsIFile> codebaseParent;
384 rv = codebaseFile->GetParent(getter_AddRefs(codebaseParent));
385 if (NS_SUCCEEDED(rv) && codebaseParent) {
386 rv = codebaseParent->Contains(targetFile, PR_TRUE, &contained);
390 if (NS_SUCCEEDED(rv) && contained) {
391 return NS_OK;
395 if (aReport) {
396 nsScriptSecurityManager::ReportError(
397 nsnull, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI);
400 return NS_ERROR_DOM_BAD_URI;
403 return NS_OK;
406 NS_IMETHODIMP
407 nsPrincipal::CanEnableCapability(const char *capability, PRInt16 *result)
409 // If this principal is marked invalid, can't enable any capabilities
410 if (mCapabilities) {
411 nsCStringKey invalidKey(sInvalid);
412 if (mCapabilities->Exists(&invalidKey)) {
413 *result = nsIPrincipal::ENABLE_DENIED;
415 return NS_OK;
419 if (!mCert && !mTrusted) {
420 NS_ASSERTION(mInitialized, "Trying to enable a capability on an "
421 "uninitialized principal");
423 // If we are a non-trusted codebase principal, capabilities can not
424 // be enabled if the user has not set the pref allowing scripts to
425 // request enhanced capabilities; however, the file: and resource:
426 // schemes are special and may be able to get extra capabilities
427 // even with the pref disabled.
429 static const char pref[] = "signed.applets.codebase_principal_support";
430 nsCOMPtr<nsIPrefBranch> prefBranch =
431 do_GetService(NS_PREFSERVICE_CONTRACTID);
432 if (prefBranch) {
433 PRBool mightEnable;
434 nsresult rv = prefBranch->GetBoolPref(pref, &mightEnable);
435 if (NS_FAILED(rv) || !mightEnable) {
436 rv = mCodebase->SchemeIs("file", &mightEnable);
437 if (NS_FAILED(rv) || !mightEnable) {
438 rv = mCodebase->SchemeIs("resource", &mightEnable);
439 if (NS_FAILED(rv) || !mightEnable) {
440 *result = nsIPrincipal::ENABLE_DENIED;
442 return NS_OK;
449 const char *start = capability;
450 *result = nsIPrincipal::ENABLE_GRANTED;
451 for(;;) {
452 const char *space = PL_strchr(start, ' ');
453 PRInt32 len = space ? space - start : strlen(start);
454 nsCAutoString capString(start, len);
455 nsCStringKey key(capString);
456 PRInt16 value =
457 mCapabilities ? (PRInt16)NS_PTR_TO_INT32(mCapabilities->Get(&key)) : 0;
458 if (value == 0 || value == nsIPrincipal::ENABLE_UNKNOWN) {
459 // We don't know whether we can enable this capability,
460 // so we should ask the user.
461 value = nsIPrincipal::ENABLE_WITH_USER_PERMISSION;
464 if (value < *result) {
465 *result = value;
468 if (!space) {
469 break;
472 start = space + 1;
475 return NS_OK;
478 NS_IMETHODIMP
479 nsPrincipal::SetCanEnableCapability(const char *capability,
480 PRInt16 canEnable)
482 // If this principal is marked invalid, can't enable any capabilities
483 if (!mCapabilities) {
484 mCapabilities = new nsHashtable(7); // XXXbz gets bumped up to 16 anyway
485 NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
488 nsCStringKey invalidKey(sInvalid);
489 if (mCapabilities->Exists(&invalidKey)) {
490 return NS_OK;
493 if (PL_strcmp(capability, sInvalid) == 0) {
494 mCapabilities->Reset();
497 const char *start = capability;
498 for(;;) {
499 const char *space = PL_strchr(start, ' ');
500 int len = space ? space - start : strlen(start);
501 nsCAutoString capString(start, len);
502 nsCStringKey key(capString);
503 mCapabilities->Put(&key, NS_INT32_TO_PTR(canEnable));
504 if (!space) {
505 break;
508 start = space + 1;
511 return NS_OK;
514 NS_IMETHODIMP
515 nsPrincipal::IsCapabilityEnabled(const char *capability, void *annotation,
516 PRBool *result)
518 *result = PR_FALSE;
519 nsHashtable *ht = (nsHashtable *) annotation;
520 if (!ht) {
521 return NS_OK;
523 const char *start = capability;
524 for(;;) {
525 const char *space = PL_strchr(start, ' ');
526 int len = space ? space - start : strlen(start);
527 nsCAutoString capString(start, len);
528 nsCStringKey key(capString);
529 *result = (ht->Get(&key) == (void *) AnnotationEnabled);
530 if (!*result) {
531 // If any single capability is not enabled, then return false.
532 return NS_OK;
535 if (!space) {
536 return NS_OK;
539 start = space + 1;
542 return NS_OK;
545 NS_IMETHODIMP
546 nsPrincipal::EnableCapability(const char *capability, void **annotation)
548 return SetCapability(capability, annotation, AnnotationEnabled);
551 NS_IMETHODIMP
552 nsPrincipal::DisableCapability(const char *capability, void **annotation)
554 return SetCapability(capability, annotation, AnnotationDisabled);
557 NS_IMETHODIMP
558 nsPrincipal::RevertCapability(const char *capability, void **annotation)
560 if (*annotation) {
561 nsHashtable *ht = (nsHashtable *) *annotation;
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 ht->Remove(&key);
569 if (!space) {
570 return NS_OK;
573 start = space + 1;
576 return NS_OK;
579 nsresult
580 nsPrincipal::SetCapability(const char *capability, void **annotation,
581 AnnotationValue value)
583 if (*annotation == nsnull) {
584 nsHashtable* ht = new nsHashtable(5);
586 if (!ht) {
587 return NS_ERROR_OUT_OF_MEMORY;
590 // This object owns its annotations. Save them so we can release
591 // them when we destroy this object.
592 if (!mAnnotations.AppendElement(ht)) {
593 delete ht;
594 return NS_ERROR_OUT_OF_MEMORY;
597 *annotation = ht;
600 const char *start = capability;
601 for(;;) {
602 const char *space = PL_strchr(start, ' ');
603 int len = space ? space - start : strlen(start);
604 nsCAutoString capString(start, len);
605 nsCStringKey key(capString);
606 nsHashtable *ht = static_cast<nsHashtable *>(*annotation);
607 ht->Put(&key, (void *) value);
608 if (!space) {
609 break;
612 start = space + 1;
615 return NS_OK;
618 NS_IMETHODIMP
619 nsPrincipal::GetHasCertificate(PRBool* aResult)
621 *aResult = (mCert != nsnull);
623 return NS_OK;
626 NS_IMETHODIMP
627 nsPrincipal::GetURI(nsIURI** aURI)
629 if (mCodebaseImmutable) {
630 NS_ADDREF(*aURI = mCodebase);
631 return NS_OK;
634 if (!mCodebase) {
635 *aURI = nsnull;
636 return NS_OK;
639 return NS_EnsureSafeToReturn(mCodebase, aURI);
642 void
643 nsPrincipal::SetURI(nsIURI* aURI)
645 mCodebase = NS_TryToMakeImmutable(aURI);
646 mCodebaseImmutable = URIIsImmutable(mCodebase);
650 nsresult
651 nsPrincipal::SetCertificate(const nsACString& aFingerprint,
652 const nsACString& aSubjectName,
653 const nsACString& aPrettyName,
654 nsISupports* aCert)
656 NS_ENSURE_STATE(!mCert);
658 if (aFingerprint.IsEmpty()) {
659 return NS_ERROR_INVALID_ARG;
662 mCert = new Certificate(aFingerprint, aSubjectName, aPrettyName, aCert);
663 if (!mCert) {
664 return NS_ERROR_OUT_OF_MEMORY;
667 return NS_OK;
670 NS_IMETHODIMP
671 nsPrincipal::GetFingerprint(nsACString& aFingerprint)
673 NS_ENSURE_STATE(mCert);
675 aFingerprint = mCert->fingerprint;
677 return NS_OK;
680 NS_IMETHODIMP
681 nsPrincipal::GetPrettyName(nsACString& aName)
683 NS_ENSURE_STATE(mCert);
685 aName = mCert->prettyName;
687 return NS_OK;
690 NS_IMETHODIMP
691 nsPrincipal::GetSubjectName(nsACString& aName)
693 NS_ENSURE_STATE(mCert);
695 aName = mCert->subjectName;
697 return NS_OK;
700 NS_IMETHODIMP
701 nsPrincipal::GetCertificate(nsISupports** aCertificate)
703 if (mCert) {
704 NS_IF_ADDREF(*aCertificate = mCert->cert);
706 else {
707 *aCertificate = nsnull;
709 return NS_OK;
712 NS_IMETHODIMP
713 nsPrincipal::GetHashValue(PRUint32* aValue)
715 NS_PRECONDITION(mCert || mCodebase, "Need a cert or codebase");
717 // If there is a certificate, it takes precendence over the codebase.
718 if (mCert) {
719 *aValue = nsCRT::HashCode(mCert->fingerprint.get());
721 else {
722 *aValue = nsScriptSecurityManager::HashPrincipalByOrigin(this);
725 return NS_OK;
728 NS_IMETHODIMP
729 nsPrincipal::GetDomain(nsIURI** aDomain)
731 if (!mDomain) {
732 *aDomain = nsnull;
733 return NS_OK;
736 if (mDomainImmutable) {
737 NS_ADDREF(*aDomain = mDomain);
738 return NS_OK;
741 return NS_EnsureSafeToReturn(mDomain, aDomain);
744 NS_IMETHODIMP
745 nsPrincipal::SetDomain(nsIURI* aDomain)
747 mDomain = NS_TryToMakeImmutable(aDomain);
748 mDomainImmutable = URIIsImmutable(mDomain);
750 // Domain has changed, forget cached security policy
751 SetSecurityPolicy(nsnull);
753 return NS_OK;
756 nsresult
757 nsPrincipal::InitFromPersistent(const char* aPrefName,
758 const nsCString& aToken,
759 const nsCString& aSubjectName,
760 const nsACString& aPrettyName,
761 const char* aGrantedList,
762 const char* aDeniedList,
763 nsISupports* aCert,
764 PRBool aIsCert,
765 PRBool aTrusted)
767 NS_PRECONDITION(!mCapabilities || mCapabilities->Count() == 0,
768 "mCapabilities was already initialized?");
769 NS_PRECONDITION(mAnnotations.Length() == 0,
770 "mAnnotations was already initialized?");
771 NS_PRECONDITION(!mInitialized, "We were already initialized?");
773 mInitialized = PR_TRUE;
775 nsresult rv;
776 if (aIsCert) {
777 rv = SetCertificate(aToken, aSubjectName, aPrettyName, aCert);
779 if (NS_FAILED(rv)) {
780 return rv;
783 else {
784 rv = NS_NewURI(getter_AddRefs(mCodebase), aToken, nsnull);
785 if (NS_FAILED(rv)) {
786 NS_ERROR("Malformed URI in capability.principal preference.");
787 return rv;
790 NS_TryToSetImmutable(mCodebase);
791 mCodebaseImmutable = URIIsImmutable(mCodebase);
793 mTrusted = aTrusted;
796 rv = mJSPrincipals.Init(this, aToken);
797 NS_ENSURE_SUCCESS(rv, rv);
799 //-- Save the preference name
800 mPrefName = aPrefName;
802 const char* ordinalBegin = PL_strpbrk(aPrefName, "1234567890");
803 if (ordinalBegin) {
804 PRIntn n = atoi(ordinalBegin);
805 if (sCapabilitiesOrdinal <= n) {
806 sCapabilitiesOrdinal = n + 1;
810 //-- Store the capabilities
811 rv = NS_OK;
812 if (aGrantedList) {
813 rv = SetCanEnableCapability(aGrantedList, nsIPrincipal::ENABLE_GRANTED);
816 if (NS_SUCCEEDED(rv) && aDeniedList) {
817 rv = SetCanEnableCapability(aDeniedList, nsIPrincipal::ENABLE_DENIED);
820 return rv;
823 nsresult
824 nsPrincipal::EnsureCertData(const nsACString& aSubjectName,
825 const nsACString& aPrettyName,
826 nsISupports* aCert)
828 NS_ENSURE_STATE(mCert);
830 if (!mCert->subjectName.IsEmpty() &&
831 !mCert->subjectName.Equals(aSubjectName)) {
832 return NS_ERROR_INVALID_ARG;
835 mCert->subjectName = aSubjectName;
836 mCert->prettyName = aPrettyName;
837 mCert->cert = aCert;
838 return NS_OK;
841 struct CapabilityList
843 nsCString* granted;
844 nsCString* denied;
847 static PRBool
848 AppendCapability(nsHashKey *aKey, void *aData, void *capListPtr)
850 CapabilityList* capList = (CapabilityList*)capListPtr;
851 PRInt16 value = (PRInt16)NS_PTR_TO_INT32(aData);
852 nsCStringKey* key = (nsCStringKey *)aKey;
853 if (value == nsIPrincipal::ENABLE_GRANTED) {
854 capList->granted->Append(key->GetString(), key->GetStringLength());
855 capList->granted->Append(' ');
857 else if (value == nsIPrincipal::ENABLE_DENIED) {
858 capList->denied->Append(key->GetString(), key->GetStringLength());
859 capList->denied->Append(' ');
862 return PR_TRUE;
865 NS_IMETHODIMP
866 nsPrincipal::GetPreferences(char** aPrefName, char** aID,
867 char** aSubjectName,
868 char** aGrantedList, char** aDeniedList,
869 PRBool* aIsTrusted)
871 if (mPrefName.IsEmpty()) {
872 if (mCert) {
873 mPrefName.Assign("capability.principal.certificate.p");
875 else {
876 mPrefName.Assign("capability.principal.codebase.p");
879 mPrefName.AppendInt(sCapabilitiesOrdinal++);
880 mPrefName.Append(".id");
883 *aPrefName = nsnull;
884 *aID = nsnull;
885 *aSubjectName = nsnull;
886 *aGrantedList = nsnull;
887 *aDeniedList = nsnull;
888 *aIsTrusted = mTrusted;
890 char *prefName = nsnull;
891 char *id = nsnull;
892 char *subjectName = nsnull;
893 char *granted = nsnull;
894 char *denied = nsnull;
896 //-- Preference name
897 prefName = ToNewCString(mPrefName);
898 if (!prefName) {
899 return NS_ERROR_OUT_OF_MEMORY;
902 //-- ID
903 nsresult rv = NS_OK;
904 if (mCert) {
905 id = ToNewCString(mCert->fingerprint);
906 if (!id) {
907 rv = NS_ERROR_OUT_OF_MEMORY;
910 else {
911 rv = GetOrigin(&id);
914 if (NS_FAILED(rv)) {
915 nsMemory::Free(prefName);
916 return rv;
919 if (mCert) {
920 subjectName = ToNewCString(mCert->subjectName);
921 } else {
922 subjectName = ToNewCString(EmptyCString());
925 if (!subjectName) {
926 nsMemory::Free(prefName);
927 nsMemory::Free(id);
928 return NS_ERROR_OUT_OF_MEMORY;
931 //-- Capabilities
932 nsCAutoString grantedListStr, deniedListStr;
933 if (mCapabilities) {
934 CapabilityList capList = CapabilityList();
935 capList.granted = &grantedListStr;
936 capList.denied = &deniedListStr;
937 mCapabilities->Enumerate(AppendCapability, (void*)&capList);
940 if (!grantedListStr.IsEmpty()) {
941 grantedListStr.Truncate(grantedListStr.Length() - 1);
942 granted = ToNewCString(grantedListStr);
943 if (!granted) {
944 nsMemory::Free(prefName);
945 nsMemory::Free(id);
946 nsMemory::Free(subjectName);
947 return NS_ERROR_OUT_OF_MEMORY;
951 if (!deniedListStr.IsEmpty()) {
952 deniedListStr.Truncate(deniedListStr.Length() - 1);
953 denied = ToNewCString(deniedListStr);
954 if (!denied) {
955 nsMemory::Free(prefName);
956 nsMemory::Free(id);
957 nsMemory::Free(subjectName);
958 if (granted) {
959 nsMemory::Free(granted);
961 return NS_ERROR_OUT_OF_MEMORY;
965 *aPrefName = prefName;
966 *aID = id;
967 *aSubjectName = subjectName;
968 *aGrantedList = granted;
969 *aDeniedList = denied;
971 return NS_OK;
974 static nsresult
975 ReadAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey** aKey,
976 void** aData)
978 nsresult rv;
979 nsCStringKey* key = new nsCStringKey(aStream, &rv);
980 if (NS_FAILED(rv)) {
981 return rv;
984 PRUint32 value;
985 rv = aStream->Read32(&value);
986 if (NS_FAILED(rv)) {
987 delete key;
988 return rv;
991 *aKey = key;
992 *aData = (void*) value;
993 return NS_OK;
996 static void
997 FreeAnnotationEntry(nsIObjectInputStream* aStream, nsHashKey* aKey,
998 void* aData)
1000 delete aKey;
1003 NS_IMETHODIMP
1004 nsPrincipal::Read(nsIObjectInputStream* aStream)
1006 PRBool hasCapabilities;
1007 nsresult rv = aStream->ReadBoolean(&hasCapabilities);
1008 if (NS_SUCCEEDED(rv) && hasCapabilities) {
1009 mCapabilities = new nsHashtable(aStream, ReadAnnotationEntry,
1010 FreeAnnotationEntry, &rv);
1011 NS_ENSURE_TRUE(mCapabilities, NS_ERROR_OUT_OF_MEMORY);
1014 if (NS_FAILED(rv)) {
1015 return rv;
1018 rv = NS_ReadOptionalCString(aStream, mPrefName);
1019 if (NS_FAILED(rv)) {
1020 return rv;
1023 const char* ordinalBegin = PL_strpbrk(mPrefName.get(), "1234567890");
1024 if (ordinalBegin) {
1025 PRIntn n = atoi(ordinalBegin);
1026 if (sCapabilitiesOrdinal <= n) {
1027 sCapabilitiesOrdinal = n + 1;
1031 PRBool haveCert;
1032 rv = aStream->ReadBoolean(&haveCert);
1033 if (NS_FAILED(rv)) {
1034 return rv;
1037 nsCString fingerprint;
1038 nsCString subjectName;
1039 nsCString prettyName;
1040 nsCOMPtr<nsISupports> cert;
1041 if (haveCert) {
1042 rv = NS_ReadOptionalCString(aStream, fingerprint);
1043 if (NS_FAILED(rv)) {
1044 return rv;
1047 rv = NS_ReadOptionalCString(aStream, subjectName);
1048 if (NS_FAILED(rv)) {
1049 return rv;
1052 rv = NS_ReadOptionalCString(aStream, prettyName);
1053 if (NS_FAILED(rv)) {
1054 return rv;
1057 rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(cert));
1058 if (NS_FAILED(rv)) {
1059 return rv;
1063 nsCOMPtr<nsIURI> codebase;
1064 rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(codebase));
1065 if (NS_FAILED(rv)) {
1066 return rv;
1069 rv = Init(fingerprint, subjectName, prettyName, cert, codebase);
1070 NS_ENSURE_SUCCESS(rv, rv);
1072 nsCOMPtr<nsIURI> domain;
1073 rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(domain));
1074 if (NS_FAILED(rv)) {
1075 return rv;
1078 SetDomain(domain);
1080 rv = aStream->Read8(&mTrusted);
1081 if (NS_FAILED(rv)) {
1082 return rv;
1085 return NS_OK;
1088 static nsresult
1089 WriteScalarValue(nsIObjectOutputStream* aStream, void* aData)
1091 PRUint32 value = NS_PTR_TO_INT32(aData);
1093 return aStream->Write32(value);
1096 NS_IMETHODIMP
1097 nsPrincipal::Write(nsIObjectOutputStream* aStream)
1099 NS_ENSURE_STATE(mCert || mCodebase);
1101 // mAnnotations is transient data associated to specific JS stack frames. We
1102 // don't want to serialize that.
1104 PRBool hasCapabilities = (mCapabilities && mCapabilities->Count() > 0);
1105 nsresult rv = aStream->WriteBoolean(hasCapabilities);
1106 if (NS_SUCCEEDED(rv) && hasCapabilities) {
1107 rv = mCapabilities->Write(aStream, WriteScalarValue);
1110 if (NS_FAILED(rv)) {
1111 return rv;
1114 rv = NS_WriteOptionalStringZ(aStream, mPrefName.get());
1115 if (NS_FAILED(rv)) {
1116 return rv;
1119 rv = aStream->WriteBoolean(mCert != nsnull);
1120 if (NS_FAILED(rv)) {
1121 return rv;
1124 if (mCert) {
1125 NS_ENSURE_STATE(mCert->cert);
1127 rv = NS_WriteOptionalStringZ(aStream, mCert->fingerprint.get());
1128 if (NS_FAILED(rv)) {
1129 return rv;
1132 rv = NS_WriteOptionalStringZ(aStream, mCert->subjectName.get());
1133 if (NS_FAILED(rv)) {
1134 return rv;
1137 rv = NS_WriteOptionalStringZ(aStream, mCert->prettyName.get());
1138 if (NS_FAILED(rv)) {
1139 return rv;
1142 rv = aStream->WriteCompoundObject(mCert->cert, NS_GET_IID(nsISupports),
1143 PR_TRUE);
1144 if (NS_FAILED(rv)) {
1145 return rv;
1149 // mSecurityPolicy is an optimization; it'll get looked up again as needed.
1150 // Don't bother saving and restoring it, esp. since it might change if
1151 // preferences change.
1153 rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI),
1154 PR_TRUE);
1155 if (NS_FAILED(rv)) {
1156 return rv;
1159 rv = NS_WriteOptionalCompoundObject(aStream, mDomain, NS_GET_IID(nsIURI),
1160 PR_TRUE);
1161 if (NS_FAILED(rv)) {
1162 return rv;
1165 rv = aStream->Write8(mTrusted);
1166 if (NS_FAILED(rv)) {
1167 return rv;
1170 // mCodebaseImmutable and mDomainImmutable will be recomputed based
1171 // on the deserialized URIs in Read().
1173 return NS_OK;