Fix opt failures using gczeal. (r=Waldo)
[mozilla-central.git] / caps / src / nsScriptSecurityManager.cpp
blob87326e2957ab0675f680d01ef37bec3a35ea1f4b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Norris Boyd
24 * Mitch Stoltz
25 * Steve Morse
26 * Christopher A. Aillon
27 * Giorgio Maone
28 * Daniel Veditz
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
43 #include "xpcprivate.h"
44 #include "nsScriptSecurityManager.h"
45 #include "nsIServiceManager.h"
46 #include "nsIScriptObjectPrincipal.h"
47 #include "nsIScriptContext.h"
48 #include "nsIURL.h"
49 #include "nsINestedURI.h"
50 #include "nspr.h"
51 #include "nsJSPrincipals.h"
52 #include "nsSystemPrincipal.h"
53 #include "nsPrincipal.h"
54 #include "nsNullPrincipal.h"
55 #include "nsXPIDLString.h"
56 #include "nsCRT.h"
57 #include "nsCRTGlue.h"
58 #include "nsIJSContextStack.h"
59 #include "nsDOMError.h"
60 #include "nsDOMCID.h"
61 #include "jsdbgapi.h"
62 #include "jsarena.h"
63 #include "jsfun.h"
64 #include "jsobj.h"
65 #include "nsIXPConnect.h"
66 #include "nsIXPCSecurityManager.h"
67 #include "nsTextFormatter.h"
68 #include "nsIStringBundle.h"
69 #include "nsNetUtil.h"
70 #include "nsIProperties.h"
71 #include "nsDirectoryServiceDefs.h"
72 #include "nsIFile.h"
73 #include "nsIFileURL.h"
74 #include "nsIZipReader.h"
75 #include "nsIPluginInstance.h"
76 #include "nsIXPConnect.h"
77 #include "nsIScriptGlobalObject.h"
78 #include "nsPIDOMWindow.h"
79 #include "nsIDocShell.h"
80 #include "nsIDocShellTreeItem.h"
81 #include "nsIPrompt.h"
82 #include "nsIWindowWatcher.h"
83 #include "nsIConsoleService.h"
84 #include "nsISecurityCheckedComponent.h"
85 #include "nsIPrefBranch2.h"
86 #include "nsIJSRuntimeService.h"
87 #include "nsIObserverService.h"
88 #include "nsIContent.h"
89 #include "nsAutoPtr.h"
90 #include "nsDOMJSUtils.h"
91 #include "nsAboutProtocolUtils.h"
92 #include "nsIClassInfo.h"
93 #include "nsIURIFixup.h"
94 #include "nsCDefaultURIFixup.h"
95 #include "nsIChromeRegistry.h"
96 #include "nsPrintfCString.h"
97 #include "nsIContentSecurityPolicy.h"
98 #include "nsIAsyncVerifyRedirectCallback.h"
100 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
102 nsIIOService *nsScriptSecurityManager::sIOService = nsnull;
103 nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
104 nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
105 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
106 JSRuntime *nsScriptSecurityManager::sRuntime = 0;
107 PRBool nsScriptSecurityManager::sStrictFileOriginPolicy = PR_TRUE;
109 ///////////////////////////
110 // Convenience Functions //
111 ///////////////////////////
112 // Result of this function should not be freed.
113 static inline const PRUnichar *
114 IDToString(JSContext *cx, jsid id)
116 if (JSID_IS_STRING(id))
117 return JS_GetInternedStringChars(JSID_TO_STRING(id));
119 JSAutoRequest ar(cx);
120 jsval idval;
121 if (!JS_IdToValue(cx, id, &idval))
122 return nsnull;
123 JSString *str = JS_ValueToString(cx, idval);
124 if(!str)
125 return nsnull;
126 return JS_GetStringCharsZ(cx, str);
129 class nsAutoInPrincipalDomainOriginSetter {
130 public:
131 nsAutoInPrincipalDomainOriginSetter() {
132 ++sInPrincipalDomainOrigin;
134 ~nsAutoInPrincipalDomainOriginSetter() {
135 --sInPrincipalDomainOrigin;
137 static PRUint32 sInPrincipalDomainOrigin;
139 PRUint32 nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
141 static
142 nsresult
143 GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin)
145 if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
146 // Allow a single recursive call to GetPrincipalDomainOrigin, since that
147 // might be happening on a different principal from the first call. But
148 // after that, cut off the recursion; it just indicates that something
149 // we're doing in this method causes us to reenter a security check here.
150 return NS_ERROR_NOT_AVAILABLE;
153 nsAutoInPrincipalDomainOriginSetter autoSetter;
155 nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
156 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
158 nsCAutoString hostPort;
160 nsresult rv = uri->GetHostPort(hostPort);
161 if (NS_SUCCEEDED(rv)) {
162 nsCAutoString scheme;
163 rv = uri->GetScheme(scheme);
164 NS_ENSURE_SUCCESS(rv, rv);
165 aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
167 else {
168 // Some URIs (e.g., nsSimpleURI) don't support host. Just
169 // get the full spec.
170 rv = uri->GetSpec(aOrigin);
171 NS_ENSURE_SUCCESS(rv, rv);
174 return NS_OK;
177 static
178 nsresult
179 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
180 nsACString& aOrigin)
183 nsCOMPtr<nsIURI> uri;
184 aPrincipal->GetDomain(getter_AddRefs(uri));
185 if (!uri) {
186 aPrincipal->GetURI(getter_AddRefs(uri));
188 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
190 return GetOriginFromURI(uri, aOrigin);
193 static nsIScriptContext *
194 GetScriptContext(JSContext *cx)
196 return GetScriptContextFromJSContext(cx);
199 inline void SetPendingException(JSContext *cx, const char *aMsg)
201 JSAutoRequest ar(cx);
202 JS_ReportError(cx, "%s", aMsg);
205 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
207 JSAutoRequest ar(cx);
208 JS_ReportError(cx, "%hs", aMsg);
211 // DomainPolicy members
212 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
213 PRUint32 DomainPolicy::sObjects=0;
214 void DomainPolicy::_printPopulationInfo()
216 printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
217 sGeneration, sObjects);
219 #endif
220 PRUint32 DomainPolicy::sGeneration = 0;
222 // Helper class to get stuff from the ClassInfo and not waste extra time with
223 // virtual method calls for things it has already gotten
224 class ClassInfoData
226 public:
227 ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
228 : mClassInfo(aClassInfo),
229 mName(const_cast<char *>(aName)),
230 mDidGetFlags(PR_FALSE),
231 mMustFreeName(PR_FALSE)
235 ~ClassInfoData()
237 if (mMustFreeName)
238 nsMemory::Free(mName);
241 PRUint32 GetFlags()
243 if (!mDidGetFlags) {
244 if (mClassInfo) {
245 nsresult rv = mClassInfo->GetFlags(&mFlags);
246 if (NS_FAILED(rv)) {
247 mFlags = 0;
249 } else {
250 mFlags = 0;
253 mDidGetFlags = PR_TRUE;
256 return mFlags;
259 PRBool IsDOMClass()
261 return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
264 const char* GetName()
266 if (!mName) {
267 if (mClassInfo) {
268 mClassInfo->GetClassDescription(&mName);
271 if (mName) {
272 mMustFreeName = PR_TRUE;
273 } else {
274 mName = const_cast<char *>("UnnamedClass");
278 return mName;
281 private:
282 nsIClassInfo *mClassInfo; // WEAK
283 PRUint32 mFlags;
284 char *mName;
285 PRPackedBool mDidGetFlags;
286 PRPackedBool mMustFreeName;
289 class AutoCxPusher {
290 public:
291 AutoCxPusher(nsIJSContextStack *aStack, JSContext *cx)
292 : mStack(aStack), mContext(cx)
294 if (NS_FAILED(mStack->Push(mContext))) {
295 mStack = nsnull;
299 ~AutoCxPusher()
301 if (mStack) {
302 mStack->Pop(nsnull);
306 private:
307 nsCOMPtr<nsIJSContextStack> mStack;
308 JSContext *mContext;
311 JSContext *
312 nsScriptSecurityManager::GetCurrentJSContext()
314 // Get JSContext from stack.
315 JSContext *cx;
316 if (NS_FAILED(sJSContextStack->Peek(&cx)))
317 return nsnull;
318 return cx;
321 JSContext *
322 nsScriptSecurityManager::GetSafeJSContext()
324 // Get JSContext from stack.
325 JSContext *cx;
326 if (NS_FAILED(sJSContextStack->GetSafeJSContext(&cx)))
327 return nsnull;
328 return cx;
331 /* static */
332 PRBool
333 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
334 nsIURI* aTargetURI)
336 return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
339 // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
340 // is consistent with NS_SecurityCompareURIs. See nsNetUtil.h.
341 PRUint32
342 nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
344 return NS_SecurityHashURI(aURI);
347 NS_IMETHODIMP
348 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
349 nsIPrincipal** aPrincipal)
351 NS_PRECONDITION(aChannel, "Must have channel!");
352 nsCOMPtr<nsISupports> owner;
353 aChannel->GetOwner(getter_AddRefs(owner));
354 if (owner) {
355 CallQueryInterface(owner, aPrincipal);
356 if (*aPrincipal) {
357 return NS_OK;
361 // OK, get the principal from the URI. Make sure this does the same thing
362 // as nsDocument::Reset and nsXULDocument::StartDocumentLoad.
363 nsCOMPtr<nsIURI> uri;
364 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
365 NS_ENSURE_SUCCESS(rv, rv);
367 return GetCodebasePrincipal(uri, aPrincipal);
370 NS_IMETHODIMP
371 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
372 PRBool* aIsSystem)
374 *aIsSystem = (aPrincipal == mSystemPrincipal);
375 return NS_OK;
378 NS_IMETHODIMP_(nsIPrincipal *)
379 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
381 NS_ASSERTION(cx == GetCurrentJSContext(),
382 "Uh, cx is not the current JS context!");
384 nsresult rv = NS_ERROR_FAILURE;
385 nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
386 if (NS_FAILED(rv))
387 return nsnull;
389 return principal;
392 NS_IMETHODIMP_(nsIPrincipal *)
393 nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
395 NS_ASSERTION(cx == GetCurrentJSContext(),
396 "Uh, cx is not the current JS context!");
398 nsresult rv = NS_ERROR_FAILURE;
399 nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
400 if (NS_FAILED(rv))
401 return nsnull;
403 return principal;
406 NS_IMETHODIMP
407 nsScriptSecurityManager::PushContextPrincipal(JSContext *cx,
408 JSStackFrame *fp,
409 nsIPrincipal *principal)
411 ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp,
412 principal);
413 if (!cp)
414 return NS_ERROR_OUT_OF_MEMORY;
416 mContextPrincipals = cp;
417 return NS_OK;
420 NS_IMETHODIMP
421 nsScriptSecurityManager::PopContextPrincipal(JSContext *cx)
423 NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop");
425 ContextPrincipal *next = mContextPrincipals->mNext;
426 delete mContextPrincipals;
427 mContextPrincipals = next;
429 return NS_OK;
432 ////////////////////
433 // Policy Storage //
434 ////////////////////
436 // Table of security levels
437 static PRBool
438 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
440 NS_Free(aData);
441 return PR_TRUE;
444 //-- Per-Domain Policy - applies to one or more protocols or hosts
445 struct DomainEntry
447 DomainEntry(const char* aOrigin,
448 DomainPolicy* aDomainPolicy) : mOrigin(aOrigin),
449 mDomainPolicy(aDomainPolicy),
450 mNext(nsnull)
452 mDomainPolicy->Hold();
455 ~DomainEntry()
457 mDomainPolicy->Drop();
460 PRBool Matches(const char *anOrigin)
462 int len = strlen(anOrigin);
463 int thisLen = mOrigin.Length();
464 if (len < thisLen)
465 return PR_FALSE;
466 if (mOrigin.RFindChar(':', thisLen-1, 1) != -1)
467 //-- Policy applies to all URLs of this scheme, compare scheme only
468 return mOrigin.EqualsIgnoreCase(anOrigin, thisLen);
470 //-- Policy applies to a particular host; compare domains
471 if (!mOrigin.Equals(anOrigin + (len - thisLen)))
472 return PR_FALSE;
473 if (len == thisLen)
474 return PR_TRUE;
475 char charBefore = anOrigin[len-thisLen-1];
476 return (charBefore == '.' || charBefore == ':' || charBefore == '/');
479 nsCString mOrigin;
480 DomainPolicy* mDomainPolicy;
481 DomainEntry* mNext;
482 #if defined(DEBUG) || defined(DEBUG_CAPS_HACKER)
483 nsCString mPolicyName_DEBUG;
484 #endif
487 static PRBool
488 DeleteDomainEntry(nsHashKey *aKey, void *aData, void* closure)
490 DomainEntry *entry = (DomainEntry*) aData;
493 DomainEntry *next = entry->mNext;
494 delete entry;
495 entry = next;
496 } while (entry);
497 return PR_TRUE;
500 /////////////////////////////
501 // nsScriptSecurityManager //
502 /////////////////////////////
504 ////////////////////////////////////
505 // Methods implementing ISupports //
506 ////////////////////////////////////
507 NS_IMPL_ISUPPORTS4(nsScriptSecurityManager,
508 nsIScriptSecurityManager,
509 nsIXPCSecurityManager,
510 nsIChannelEventSink,
511 nsIObserver)
513 ///////////////////////////////////////////////////
514 // Methods implementing nsIScriptSecurityManager //
515 ///////////////////////////////////////////////////
517 ///////////////// Security Checks /////////////////
518 JSBool
519 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
521 // Get the security manager
522 nsScriptSecurityManager *ssm =
523 nsScriptSecurityManager::GetScriptSecurityManager();
525 NS_ASSERTION(ssm, "Failed to get security manager service");
526 if (!ssm)
527 return JS_FALSE;
529 nsresult rv;
530 nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
532 NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
533 if (NS_FAILED(rv))
534 return JS_FALSE; // Not just absence of principal, but failure.
536 if (!subjectPrincipal) {
537 // See bug 553448 for discussion of this case.
538 NS_ASSERTION(!JS_GetSecurityCallbacks(cx)->findObjectPrincipals,
539 "CSP: Should have been able to find subject principal. "
540 "Reluctantly granting access.");
541 return JS_TRUE;
544 nsCOMPtr<nsIContentSecurityPolicy> csp;
545 rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
546 NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
548 // don't do anything unless there's a CSP
549 if (!csp)
550 return JS_TRUE;
552 PRBool evalOK = PR_TRUE;
553 // this call will send violation reports as warranted (and return true if
554 // reportOnly is set).
555 rv = csp->GetAllowsEval(&evalOK);
557 if (NS_FAILED(rv))
559 NS_WARNING("CSP: failed to get allowsEval");
560 return JS_TRUE; // fail open to not break sites.
563 return evalOK;
567 JSBool
568 nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
569 jsid id, JSAccessMode mode,
570 jsval *vp)
572 // Get the security manager
573 nsScriptSecurityManager *ssm =
574 nsScriptSecurityManager::GetScriptSecurityManager();
576 NS_ASSERTION(ssm, "Failed to get security manager service");
577 if (!ssm)
578 return JS_FALSE;
580 // Get the object being accessed. We protect these cases:
581 // 1. The Function.prototype.caller property's value, which might lead
582 // an attacker up a call-stack to a function or another object from
583 // a different trust domain.
584 // 2. A user-defined getter or setter function accessible on another
585 // trust domain's window or document object.
586 // *vp can be a primitive, in that case, we use obj as the target
587 // object.
588 JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
590 // Do the same-origin check -- this sets a JS exception if the check fails.
591 // Pass the parent object's class name, as we have no class-info for it.
592 nsresult rv =
593 ssm->CheckPropertyAccess(cx, target, obj->getClass()->name, id,
594 (mode & JSACC_WRITE) ?
595 (PRInt32)nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
596 (PRInt32)nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
598 if (NS_FAILED(rv))
599 return JS_FALSE; // Security check failed (XXX was an error reported?)
601 return JS_TRUE;
604 NS_IMETHODIMP
605 nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
606 JSObject* aJSObject,
607 const char* aClassName,
608 jsid aProperty,
609 PRUint32 aAction)
611 return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
612 nsnull, nsnull, nsnull,
613 aClassName, aProperty, nsnull);
616 NS_IMETHODIMP
617 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
618 nsIURI* aTargetURI)
620 nsresult rv;
622 // Get a context if necessary
623 if (!cx)
625 cx = GetCurrentJSContext();
626 if (!cx)
627 return NS_OK; // No JS context, so allow access
630 // Get a principal from the context
631 nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
632 if (NS_FAILED(rv))
633 return rv;
635 if (!sourcePrincipal)
637 NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
638 return NS_OK;
641 if (sourcePrincipal == mSystemPrincipal)
643 // This is a system (chrome) script, so allow access
644 return NS_OK;
647 // Get the original URI from the source principal.
648 // This has the effect of ignoring any change to document.domain
649 // which must be done to avoid DNS spoofing (bug 154930)
650 nsCOMPtr<nsIURI> sourceURI;
651 sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
652 if (!sourceURI) {
653 sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
654 NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
657 // Compare origins
658 if (!SecurityCompareURIs(sourceURI, aTargetURI))
660 ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
661 return NS_ERROR_DOM_BAD_URI;
663 return NS_OK;
666 NS_IMETHODIMP
667 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
668 nsIURI* aTargetURI,
669 PRBool reportError)
671 if (!SecurityCompareURIs(aSourceURI, aTargetURI))
673 if (reportError) {
674 ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"),
675 aSourceURI, aTargetURI);
677 return NS_ERROR_DOM_BAD_URI;
679 return NS_OK;
682 nsresult
683 nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
684 nsAXPCNativeCallContext* aCallContext,
685 JSContext* cx, JSObject* aJSObject,
686 nsISupports* aObj, nsIURI* aTargetURI,
687 nsIClassInfo* aClassInfo,
688 const char* aClassName, jsid aProperty,
689 void** aCachedClassPolicy)
691 nsresult rv;
692 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
693 if (NS_FAILED(rv))
694 return rv;
696 if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
697 // We have native code or the system principal: just allow access
698 return NS_OK;
700 nsCOMPtr<nsIPrincipal> objectPrincipal;
702 // Hold the class info data here so we don't have to go back to virtual
703 // methods all the time
704 ClassInfoData classInfoData(aClassInfo, aClassName);
705 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
706 nsCAutoString propertyName;
707 propertyName.AssignWithConversion((PRUnichar*)IDToString(cx, aProperty));
708 printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(),
709 propertyName.get(), aAction);
710 #endif
712 //-- Look up the security policy for this class and subject domain
713 SecurityLevel securityLevel;
714 rv = LookupPolicy(subjectPrincipal, classInfoData, aProperty, aAction,
715 (ClassPolicy**)aCachedClassPolicy, &securityLevel);
716 if (NS_FAILED(rv))
717 return rv;
719 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
721 // No policy found for this property so use the default of last resort.
722 // If we were called from somewhere other than XPConnect
723 // (no XPC call context), assume this is a DOM class. Otherwise,
724 // ask the ClassInfo.
725 if (!aCallContext || classInfoData.IsDOMClass())
726 securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
727 else
728 securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
731 if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
732 // This flag means securityLevel is allAccess, noAccess, or sameOrigin
734 switch (securityLevel.level)
736 case SCRIPT_SECURITY_NO_ACCESS:
737 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
738 printf("noAccess ");
739 #endif
740 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
741 break;
743 case SCRIPT_SECURITY_ALL_ACCESS:
744 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
745 printf("allAccess ");
746 #endif
747 rv = NS_OK;
748 break;
750 case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS:
752 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
753 printf("sameOrigin ");
754 #endif
755 nsCOMPtr<nsIPrincipal> principalHolder;
756 if(aJSObject)
758 objectPrincipal = doGetObjectPrincipal(aJSObject);
759 if (!objectPrincipal)
760 rv = NS_ERROR_DOM_SECURITY_ERR;
762 else if(aTargetURI)
764 if (NS_FAILED(GetCodebasePrincipal(
765 aTargetURI, getter_AddRefs(objectPrincipal))))
766 return NS_ERROR_FAILURE;
768 else
770 NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
771 return NS_ERROR_FAILURE;
773 if(NS_SUCCEEDED(rv))
774 rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
775 aAction);
776 break;
778 default:
779 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
780 printf("ERROR ");
781 #endif
782 NS_ERROR("Bad Security Level Value");
783 return NS_ERROR_FAILURE;
786 else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
788 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
789 printf("Cap:%s ", securityLevel.capability);
790 #endif
791 PRBool capabilityEnabled = PR_FALSE;
792 rv = IsCapabilityEnabled(securityLevel.capability, &capabilityEnabled);
793 if (NS_FAILED(rv) || !capabilityEnabled)
794 rv = NS_ERROR_DOM_SECURITY_ERR;
795 else
796 rv = NS_OK;
799 if (NS_SUCCEEDED(rv))
801 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
802 printf(" GRANTED.\n");
803 #endif
804 return rv;
807 //--See if the object advertises a non-default level of access
808 // using nsISecurityCheckedComponent
809 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
810 do_QueryInterface(aObj);
812 nsXPIDLCString objectSecurityLevel;
813 if (checkedComponent)
815 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
816 nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
817 const nsIID* objIID = nsnull;
818 rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
819 if (NS_SUCCEEDED(rv) && wrapper)
820 rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
821 if (NS_SUCCEEDED(rv) && interfaceInfo)
822 rv = interfaceInfo->GetIIDShared(&objIID);
823 if (NS_SUCCEEDED(rv) && objIID)
825 switch (aAction)
827 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
828 checkedComponent->CanGetProperty(objIID,
829 IDToString(cx, aProperty),
830 getter_Copies(objectSecurityLevel));
831 break;
832 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
833 checkedComponent->CanSetProperty(objIID,
834 IDToString(cx, aProperty),
835 getter_Copies(objectSecurityLevel));
836 break;
837 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
838 checkedComponent->CanCallMethod(objIID,
839 IDToString(cx, aProperty),
840 getter_Copies(objectSecurityLevel));
844 rv = CheckXPCPermissions(cx, aObj, aJSObject, subjectPrincipal,
845 objectSecurityLevel);
846 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
847 if(NS_SUCCEEDED(rv))
848 printf("CheckXPCPerms GRANTED.\n");
849 else
850 printf("CheckXPCPerms DENIED.\n");
851 #endif
853 if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
855 nsAutoString stringName;
856 switch(aAction)
858 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
859 stringName.AssignLiteral("GetPropertyDeniedOrigins");
860 break;
861 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
862 stringName.AssignLiteral("SetPropertyDeniedOrigins");
863 break;
864 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
865 stringName.AssignLiteral("CallMethodDeniedOrigins");
868 // Null out objectPrincipal for now, so we don't leak information about
869 // it. Whenever we can report different error strings to content and
870 // the UI we can take this out again.
871 objectPrincipal = nsnull;
873 NS_ConvertUTF8toUTF16 className(classInfoData.GetName());
874 nsCAutoString subjectOrigin;
875 nsCAutoString subjectDomain;
876 if (!nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin) {
877 nsCOMPtr<nsIURI> uri, domain;
878 subjectPrincipal->GetURI(getter_AddRefs(uri));
879 // Subject can't be system if we failed the security
880 // check, so |uri| is non-null.
881 NS_ASSERTION(uri, "How did that happen?");
882 GetOriginFromURI(uri, subjectOrigin);
883 subjectPrincipal->GetDomain(getter_AddRefs(domain));
884 if (domain) {
885 GetOriginFromURI(domain, subjectDomain);
887 } else {
888 subjectOrigin.AssignLiteral("the security manager");
890 NS_ConvertUTF8toUTF16 subjectOriginUnicode(subjectOrigin);
891 NS_ConvertUTF8toUTF16 subjectDomainUnicode(subjectDomain);
893 nsCAutoString objectOrigin;
894 nsCAutoString objectDomain;
895 if (!nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin &&
896 objectPrincipal) {
897 nsCOMPtr<nsIURI> uri, domain;
898 objectPrincipal->GetURI(getter_AddRefs(uri));
899 if (uri) { // Object principal might be system
900 GetOriginFromURI(uri, objectOrigin);
902 objectPrincipal->GetDomain(getter_AddRefs(domain));
903 if (domain) {
904 GetOriginFromURI(domain, objectDomain);
907 NS_ConvertUTF8toUTF16 objectOriginUnicode(objectOrigin);
908 NS_ConvertUTF8toUTF16 objectDomainUnicode(objectDomain);
910 nsXPIDLString errorMsg;
911 const PRUnichar *formatStrings[] =
913 subjectOriginUnicode.get(),
914 className.get(),
915 IDToString(cx, aProperty),
916 objectOriginUnicode.get(),
917 subjectDomainUnicode.get(),
918 objectDomainUnicode.get()
921 PRUint32 length = NS_ARRAY_LENGTH(formatStrings);
923 // XXXbz Our localization system is stupid and can't handle not showing
924 // some strings that get passed in. Which means that we have to get
925 // our length precisely right: it has to be exactly the number of
926 // strings our format string wants. This means we'll have to move
927 // strings in the array as needed, sadly...
928 if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin ||
929 !objectPrincipal) {
930 stringName.AppendLiteral("OnlySubject");
931 length -= 3;
932 } else {
933 // default to a length that doesn't include the domains, then
934 // increase it as needed.
935 length -= 2;
936 if (!subjectDomainUnicode.IsEmpty()) {
937 stringName.AppendLiteral("SubjectDomain");
938 length += 1;
940 if (!objectDomainUnicode.IsEmpty()) {
941 stringName.AppendLiteral("ObjectDomain");
942 length += 1;
943 if (length != NS_ARRAY_LENGTH(formatStrings)) {
944 // We have an object domain but not a subject domain.
945 // Scoot our string over one slot. See the XXX comment
946 // above for why we need to do this.
947 formatStrings[length-1] = formatStrings[length];
952 // We need to keep our existing failure rv and not override it
953 // with a likely success code from the following string bundle
954 // call in order to throw the correct security exception later.
955 nsresult rv2 = sStrBundle->FormatStringFromName(stringName.get(),
956 formatStrings,
957 length,
958 getter_Copies(errorMsg));
959 if (NS_FAILED(rv2)) {
960 // Might just be missing the string... Do our best
961 errorMsg = stringName;
964 SetPendingException(cx, errorMsg.get());
967 return rv;
970 /* static */
971 nsresult
972 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
973 nsIPrincipal* aObject)
976 ** Get origin of subject and object and compare.
978 if (aSubject == aObject)
979 return NS_OK;
981 // Default to false, and change if that turns out wrong.
982 PRBool subjectSetDomain = PR_FALSE;
983 PRBool objectSetDomain = PR_FALSE;
985 nsCOMPtr<nsIURI> subjectURI;
986 nsCOMPtr<nsIURI> objectURI;
988 aSubject->GetDomain(getter_AddRefs(subjectURI));
989 if (!subjectURI) {
990 aSubject->GetURI(getter_AddRefs(subjectURI));
991 } else {
992 subjectSetDomain = PR_TRUE;
995 aObject->GetDomain(getter_AddRefs(objectURI));
996 if (!objectURI) {
997 aObject->GetURI(getter_AddRefs(objectURI));
998 } else {
999 objectSetDomain = PR_TRUE;
1002 if (SecurityCompareURIs(subjectURI, objectURI))
1003 { // If either the subject or the object has changed its principal by
1004 // explicitly setting document.domain then the other must also have
1005 // done so in order to be considered the same origin. This prevents
1006 // DNS spoofing based on document.domain (154930)
1008 // If both or neither explicitly set their domain, allow the access
1009 if (subjectSetDomain == objectSetDomain)
1010 return NS_OK;
1014 ** Access tests failed, so now report error.
1016 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1019 // It's important that
1021 // CheckSameOriginPrincipal(A, B) == NS_OK
1023 // imply
1025 // HashPrincipalByOrigin(A) == HashPrincipalByOrigin(B)
1027 // if principals A and B could ever be used as keys in a hashtable.
1028 // Violation of this invariant leads to spurious failures of hashtable
1029 // lookups. See bug 454850.
1031 /*static*/ PRUint32
1032 nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
1034 nsCOMPtr<nsIURI> uri;
1035 aPrincipal->GetDomain(getter_AddRefs(uri));
1036 if (!uri)
1037 aPrincipal->GetURI(getter_AddRefs(uri));
1038 return SecurityHashURI(uri);
1041 nsresult
1042 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
1043 nsIPrincipal* aObject,
1044 PRUint32 aAction)
1046 nsresult rv;
1047 PRBool subsumes;
1048 rv = aSubject->Subsumes(aObject, &subsumes);
1049 if (NS_SUCCEEDED(rv) && !subsumes) {
1050 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1053 if (NS_SUCCEEDED(rv))
1054 return NS_OK;
1057 * Content can't ever touch chrome (we check for UniversalXPConnect later)
1059 if (aObject == mSystemPrincipal)
1060 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1063 * If we failed the origin tests it still might be the case that we
1064 * are a signed script and have permissions to do this operation.
1065 * Check for that here.
1067 PRBool capabilityEnabled = PR_FALSE;
1068 const char* cap = aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY ?
1069 "UniversalBrowserWrite" : "UniversalBrowserRead";
1070 rv = IsCapabilityEnabled(cap, &capabilityEnabled);
1071 NS_ENSURE_SUCCESS(rv, rv);
1072 if (capabilityEnabled)
1073 return NS_OK;
1076 ** Access tests failed, so now report error.
1078 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1081 nsresult
1082 nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal,
1083 ClassInfoData& aClassData,
1084 jsid aProperty,
1085 PRUint32 aAction,
1086 ClassPolicy** aCachedClassPolicy,
1087 SecurityLevel* result)
1089 nsresult rv;
1090 result->level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
1092 DomainPolicy* dpolicy = nsnull;
1093 //-- Initialize policies if necessary
1094 if (mPolicyPrefsChanged)
1096 if (!mPrefBranch) {
1097 rv = InitPrefs();
1098 NS_ENSURE_SUCCESS(rv, rv);
1100 rv = InitPolicies();
1101 if (NS_FAILED(rv))
1102 return rv;
1104 else
1106 aPrincipal->GetSecurityPolicy((void**)&dpolicy);
1109 if (!dpolicy && mOriginToPolicyMap)
1111 //-- Look up the relevant domain policy, if any
1112 #ifdef DEBUG_CAPS_LookupPolicy
1113 printf("DomainLookup ");
1114 #endif
1116 nsCAutoString origin;
1117 rv = GetPrincipalDomainOrigin(aPrincipal, origin);
1118 NS_ENSURE_SUCCESS(rv, rv);
1120 char *start = origin.BeginWriting();
1121 const char *nextToLastDot = nsnull;
1122 const char *lastDot = nsnull;
1123 const char *colon = nsnull;
1124 char *p = start;
1126 //-- search domain (stop at the end of the string or at the 3rd slash)
1127 for (PRUint32 slashes=0; *p; p++)
1129 if (*p == '/' && ++slashes == 3)
1131 *p = '\0'; // truncate at 3rd slash
1132 break;
1134 if (*p == '.')
1136 nextToLastDot = lastDot;
1137 lastDot = p;
1139 else if (!colon && *p == ':')
1140 colon = p;
1143 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : start);
1144 DomainEntry *de = (DomainEntry*) mOriginToPolicyMap->Get(&key);
1145 if (!de)
1147 nsCAutoString scheme(start, colon-start+1);
1148 nsCStringKey schemeKey(scheme);
1149 de = (DomainEntry*) mOriginToPolicyMap->Get(&schemeKey);
1152 while (de)
1154 if (de->Matches(start))
1156 dpolicy = de->mDomainPolicy;
1157 break;
1159 de = de->mNext;
1162 if (!dpolicy)
1163 dpolicy = mDefaultPolicy;
1165 aPrincipal->SetSecurityPolicy((void*)dpolicy);
1168 ClassPolicy* cpolicy = nsnull;
1170 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1172 // No per-domain policy for this principal (the more common case)
1173 // so look for a cached class policy from the object wrapper
1174 cpolicy = *aCachedClassPolicy;
1177 if (!cpolicy)
1178 { //-- No cached policy for this class, need to look it up
1179 #ifdef DEBUG_CAPS_LookupPolicy
1180 printf("ClassLookup ");
1181 #endif
1183 cpolicy = static_cast<ClassPolicy*>
1184 (PL_DHashTableOperate(dpolicy,
1185 aClassData.GetName(),
1186 PL_DHASH_LOOKUP));
1188 if (PL_DHASH_ENTRY_IS_FREE(cpolicy))
1189 cpolicy = NO_POLICY_FOR_CLASS;
1191 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1192 *aCachedClassPolicy = cpolicy;
1195 NS_ASSERTION(JSID_IS_INT(aProperty) || JSID_IS_OBJECT(aProperty) ||
1196 JSID_IS_STRING(aProperty), "Property must be a valid id");
1198 // Only atomized strings are stored in the policies' hash tables.
1199 if (!JSID_IS_STRING(aProperty))
1200 return NS_OK;
1202 JSString *propertyKey = JSID_TO_STRING(aProperty);
1204 // We look for a PropertyPolicy in the following places:
1205 // 1) The ClassPolicy for our class we got from our DomainPolicy
1206 // 2) The mWildcardPolicy of our DomainPolicy
1207 // 3) The ClassPolicy for our class we got from mDefaultPolicy
1208 // 4) The mWildcardPolicy of our mDefaultPolicy
1209 PropertyPolicy* ppolicy = nsnull;
1210 if (cpolicy != NO_POLICY_FOR_CLASS)
1212 ppolicy = static_cast<PropertyPolicy*>
1213 (PL_DHashTableOperate(cpolicy->mPolicy,
1214 propertyKey,
1215 PL_DHASH_LOOKUP));
1218 // If there is no class policy for this property, and we have a wildcard
1219 // policy, try that.
1220 if (dpolicy->mWildcardPolicy &&
1221 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1223 ppolicy =
1224 static_cast<PropertyPolicy*>
1225 (PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy,
1226 propertyKey,
1227 PL_DHASH_LOOKUP));
1230 // If dpolicy is not the defauly policy and there's no class or wildcard
1231 // policy for this property, check the default policy for this class and
1232 // the default wildcard policy
1233 if (dpolicy != mDefaultPolicy &&
1234 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1236 cpolicy = static_cast<ClassPolicy*>
1237 (PL_DHashTableOperate(mDefaultPolicy,
1238 aClassData.GetName(),
1239 PL_DHASH_LOOKUP));
1241 if (PL_DHASH_ENTRY_IS_BUSY(cpolicy))
1243 ppolicy =
1244 static_cast<PropertyPolicy*>
1245 (PL_DHashTableOperate(cpolicy->mPolicy,
1246 propertyKey,
1247 PL_DHASH_LOOKUP));
1250 if ((!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)) &&
1251 mDefaultPolicy->mWildcardPolicy)
1253 ppolicy =
1254 static_cast<PropertyPolicy*>
1255 (PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy,
1256 propertyKey,
1257 PL_DHASH_LOOKUP));
1261 if (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy))
1262 return NS_OK;
1264 // Get the correct security level from the property policy
1265 if (aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY)
1266 *result = ppolicy->mSet;
1267 else
1268 *result = ppolicy->mGet;
1270 return NS_OK;
1274 NS_IMETHODIMP
1275 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
1277 // Get principal of currently executing script.
1278 nsresult rv;
1279 nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
1280 if (NS_FAILED(rv))
1281 return rv;
1283 // Native code can load all URIs.
1284 if (!principal)
1285 return NS_OK;
1287 rv = CheckLoadURIWithPrincipal(principal, aURI,
1288 nsIScriptSecurityManager::STANDARD);
1289 if (NS_SUCCEEDED(rv)) {
1290 // OK to load
1291 return NS_OK;
1294 // See if we're attempting to load a file: URI. If so, let a
1295 // UniversalFileRead capability trump the above check.
1296 PRBool isFile = PR_FALSE;
1297 PRBool isRes = PR_FALSE;
1298 if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
1299 NS_FAILED(aURI->SchemeIs("resource", &isRes)))
1300 return NS_ERROR_FAILURE;
1301 if (isFile || isRes)
1303 PRBool enabled;
1304 if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled)))
1305 return NS_ERROR_FAILURE;
1306 if (enabled)
1307 return NS_OK;
1310 // Report error.
1311 nsCAutoString spec;
1312 if (NS_FAILED(aURI->GetAsciiSpec(spec)))
1313 return NS_ERROR_FAILURE;
1314 nsCAutoString msg("Access to '");
1315 msg.Append(spec);
1316 msg.AppendLiteral("' from script denied");
1317 SetPendingException(cx, msg.get());
1318 return NS_ERROR_DOM_BAD_URI;
1321 NS_IMETHODIMP
1322 nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1323 PRUint32 aFlags)
1325 // FIXME: bug 327244 -- this function should really die... Really truly.
1326 NS_PRECONDITION(aSourceURI, "CheckLoadURI called with null source URI");
1327 NS_ENSURE_ARG_POINTER(aSourceURI);
1329 // Note: this is not _quite_ right if aSourceURI has
1330 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1331 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1332 // really needs to go away....
1333 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1334 nsresult rv = CreateCodebasePrincipal(aSourceURI,
1335 getter_AddRefs(sourcePrincipal));
1336 NS_ENSURE_SUCCESS(rv, rv);
1337 return CheckLoadURIWithPrincipal(sourcePrincipal, aTargetURI, aFlags);
1341 * Helper method to handle cases where a flag passed to
1342 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
1343 * nsIProtocolHandler flags set.
1344 * @return if success, access is allowed. Otherwise, deny access
1346 static nsresult
1347 DenyAccessIfURIHasFlags(nsIURI* aURI, PRUint32 aURIFlags)
1349 NS_PRECONDITION(aURI, "Must have URI!");
1351 PRBool uriHasFlags;
1352 nsresult rv =
1353 NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
1354 NS_ENSURE_SUCCESS(rv, rv);
1356 if (uriHasFlags) {
1357 return NS_ERROR_DOM_BAD_URI;
1360 return NS_OK;
1363 NS_IMETHODIMP
1364 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
1365 nsIURI *aTargetURI,
1366 PRUint32 aFlags)
1368 NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
1369 // If someone passes a flag that we don't understand, we should
1370 // fail, because they may need a security check that we don't
1371 // provide.
1372 NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
1373 nsIScriptSecurityManager::ALLOW_CHROME |
1374 nsIScriptSecurityManager::DISALLOW_SCRIPT |
1375 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL),
1376 NS_ERROR_UNEXPECTED);
1377 NS_ENSURE_ARG_POINTER(aPrincipal);
1378 NS_ENSURE_ARG_POINTER(aTargetURI);
1380 if (aPrincipal == mSystemPrincipal) {
1381 // Allow access
1382 return NS_OK;
1385 nsCOMPtr<nsIURI> sourceURI;
1386 aPrincipal->GetURI(getter_AddRefs(sourceURI));
1387 if (!sourceURI) {
1388 NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
1389 "must have a URI!");
1390 return NS_ERROR_UNEXPECTED;
1393 // Automatic loads are not allowed from certain protocols.
1394 if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
1395 nsresult rv =
1396 DenyAccessIfURIHasFlags(sourceURI,
1397 nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
1398 NS_ENSURE_SUCCESS(rv, rv);
1401 // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
1402 // would do such inheriting. That would be URIs that do not have their own
1403 // security context.
1404 if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
1405 nsresult rv =
1406 DenyAccessIfURIHasFlags(aTargetURI,
1407 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
1408 NS_ENSURE_SUCCESS(rv, rv);
1411 // If either URI is a nested URI, get the base URI
1412 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
1413 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
1415 //-- get the target scheme
1416 nsCAutoString targetScheme;
1417 nsresult rv = targetBaseURI->GetScheme(targetScheme);
1418 if (NS_FAILED(rv)) return rv;
1420 //-- Some callers do not allow loading javascript:
1421 if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
1422 targetScheme.EqualsLiteral("javascript"))
1424 return NS_ERROR_DOM_BAD_URI;
1427 NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
1429 // Check for uris that are only loadable by principals that subsume them
1430 PRBool hasFlags;
1431 rv = NS_URIChainHasFlags(targetBaseURI,
1432 nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
1433 &hasFlags);
1434 NS_ENSURE_SUCCESS(rv, rv);
1436 if (hasFlags) {
1437 return aPrincipal->CheckMayLoad(targetBaseURI, PR_TRUE);
1440 //-- get the source scheme
1441 nsCAutoString sourceScheme;
1442 rv = sourceBaseURI->GetScheme(sourceScheme);
1443 if (NS_FAILED(rv)) return rv;
1445 if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
1446 // A null principal can target its own URI.
1447 if (sourceURI == aTargetURI) {
1448 return NS_OK;
1451 else if (targetScheme.Equals(sourceScheme,
1452 nsCaseInsensitiveCStringComparator()))
1454 // every scheme can access another URI from the same scheme,
1455 // as long as they don't represent null principals.
1456 return NS_OK;
1459 // If the schemes don't match, the policy is specified by the protocol
1460 // flags on the target URI. Note that the order of policy checks here is
1461 // very important! We start from most restrictive and work our way down.
1462 // Note that since we're working with the innermost URI, we can just use
1463 // the methods that work on chains of nested URIs and they will only look
1464 // at the flags for our one URI.
1466 // Check for system target URI
1467 rv = DenyAccessIfURIHasFlags(targetBaseURI,
1468 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
1469 if (NS_FAILED(rv)) {
1470 // Deny access, since the origin principal is not system
1471 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1472 return rv;
1475 // Check for chrome target URI
1476 rv = NS_URIChainHasFlags(targetBaseURI,
1477 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1478 &hasFlags);
1479 NS_ENSURE_SUCCESS(rv, rv);
1480 if (hasFlags) {
1481 if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
1482 if (!targetScheme.EqualsLiteral("chrome")) {
1483 // for now don't change behavior for resource: or moz-icon:
1484 return NS_OK;
1487 // allow load only if chrome package is whitelisted
1488 nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
1489 NS_CHROMEREGISTRY_CONTRACTID));
1490 if (reg) {
1491 PRBool accessAllowed = PR_FALSE;
1492 reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
1493 if (accessAllowed) {
1494 return NS_OK;
1499 // resource: and chrome: are equivalent, securitywise
1500 // That's bogus!! Fix this. But watch out for
1501 // the view-source stylesheet?
1502 PRBool sourceIsChrome;
1503 rv = NS_URIChainHasFlags(sourceBaseURI,
1504 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1505 &sourceIsChrome);
1506 NS_ENSURE_SUCCESS(rv, rv);
1507 if (sourceIsChrome) {
1508 return NS_OK;
1510 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1511 return NS_ERROR_DOM_BAD_URI;
1514 // Check for target URI pointing to a file
1515 rv = NS_URIChainHasFlags(targetBaseURI,
1516 nsIProtocolHandler::URI_IS_LOCAL_FILE,
1517 &hasFlags);
1518 NS_ENSURE_SUCCESS(rv, rv);
1519 if (hasFlags) {
1520 // resource: and chrome: are equivalent, securitywise
1521 // That's bogus!! Fix this. But watch out for
1522 // the view-source stylesheet?
1523 PRBool sourceIsChrome;
1524 rv = NS_URIChainHasFlags(sourceURI,
1525 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1526 &sourceIsChrome);
1527 NS_ENSURE_SUCCESS(rv, rv);
1528 if (sourceIsChrome) {
1529 return NS_OK;
1532 // Now check capability policies
1533 static const char loadURIPrefGroup[] = "checkloaduri";
1534 ClassInfoData nameData(nsnull, loadURIPrefGroup);
1536 SecurityLevel secLevel;
1537 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1538 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1539 nsnull, &secLevel);
1540 if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
1542 // OK for this site!
1543 return NS_OK;
1546 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1547 return NS_ERROR_DOM_BAD_URI;
1550 // OK, everyone is allowed to load this, since unflagged handlers are
1551 // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
1552 // need to warn. At some point we'll want to make this warning into an
1553 // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
1554 rv = NS_URIChainHasFlags(targetBaseURI,
1555 nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
1556 &hasFlags);
1557 NS_ENSURE_SUCCESS(rv, rv);
1558 if (!hasFlags) {
1559 nsXPIDLString message;
1560 NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
1561 const PRUnichar* formatStrings[] = { ucsTargetScheme.get() };
1562 rv = sStrBundle->
1563 FormatStringFromName(NS_LITERAL_STRING("ProtocolFlagError").get(),
1564 formatStrings,
1565 NS_ARRAY_LENGTH(formatStrings),
1566 getter_Copies(message));
1567 if (NS_SUCCEEDED(rv)) {
1568 nsCOMPtr<nsIConsoleService> console(
1569 do_GetService("@mozilla.org/consoleservice;1"));
1570 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1572 console->LogStringMessage(message.get());
1573 #ifdef DEBUG
1574 fprintf(stderr, "%s\n", NS_ConvertUTF16toUTF8(message).get());
1575 #endif
1579 return NS_OK;
1582 nsresult
1583 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
1584 nsIURI* aSource, nsIURI* aTarget)
1586 nsresult rv;
1587 NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
1589 // Get the source URL spec
1590 nsCAutoString sourceSpec;
1591 rv = aSource->GetAsciiSpec(sourceSpec);
1592 NS_ENSURE_SUCCESS(rv, rv);
1594 // Get the target URL spec
1595 nsCAutoString targetSpec;
1596 rv = aTarget->GetAsciiSpec(targetSpec);
1597 NS_ENSURE_SUCCESS(rv, rv);
1599 // Localize the error message
1600 nsXPIDLString message;
1601 NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
1602 NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
1603 const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
1604 rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
1605 formatStrings,
1606 NS_ARRAY_LENGTH(formatStrings),
1607 getter_Copies(message));
1608 NS_ENSURE_SUCCESS(rv, rv);
1610 // If a JS context was passed in, set a JS exception.
1611 // Otherwise, print the error message directly to the JS console
1612 // and to standard output
1613 if (cx)
1615 SetPendingException(cx, message.get());
1617 else // Print directly to the console
1619 nsCOMPtr<nsIConsoleService> console(
1620 do_GetService("@mozilla.org/consoleservice;1"));
1621 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1623 console->LogStringMessage(message.get());
1624 #ifdef DEBUG
1625 fprintf(stderr, "%s\n", NS_LossyConvertUTF16toASCII(message).get());
1626 #endif
1628 return NS_OK;
1631 NS_IMETHODIMP
1632 nsScriptSecurityManager::CheckLoadURIStr(const nsACString& aSourceURIStr,
1633 const nsACString& aTargetURIStr,
1634 PRUint32 aFlags)
1636 // FIXME: bug 327244 -- this function should really die... Really truly.
1637 nsCOMPtr<nsIURI> source;
1638 nsresult rv = NS_NewURI(getter_AddRefs(source), aSourceURIStr,
1639 nsnull, nsnull, sIOService);
1640 NS_ENSURE_SUCCESS(rv, rv);
1642 // Note: this is not _quite_ right if aSourceURI has
1643 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1644 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1645 // really needs to go away....
1646 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1647 rv = CreateCodebasePrincipal(source,
1648 getter_AddRefs(sourcePrincipal));
1649 NS_ENSURE_SUCCESS(rv, rv);
1651 return CheckLoadURIStrWithPrincipal(sourcePrincipal, aTargetURIStr,
1652 aFlags);
1655 NS_IMETHODIMP
1656 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
1657 const nsACString& aTargetURIStr,
1658 PRUint32 aFlags)
1660 nsresult rv;
1661 nsCOMPtr<nsIURI> target;
1662 rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
1663 nsnull, nsnull, sIOService);
1664 NS_ENSURE_SUCCESS(rv, rv);
1666 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1667 NS_ENSURE_SUCCESS(rv, rv);
1669 // Now start testing fixup -- since aTargetURIStr is a string, not
1670 // an nsIURI, we may well end up fixing it up before loading.
1671 // Note: This needs to stay in sync with the nsIURIFixup api.
1672 nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
1673 if (!fixup) {
1674 return rv;
1677 PRUint32 flags[] = {
1678 nsIURIFixup::FIXUP_FLAG_NONE,
1679 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
1680 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
1681 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
1682 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
1685 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(flags); ++i) {
1686 rv = fixup->CreateFixupURI(aTargetURIStr, flags[i],
1687 getter_AddRefs(target));
1688 NS_ENSURE_SUCCESS(rv, rv);
1690 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1691 NS_ENSURE_SUCCESS(rv, rv);
1694 return rv;
1697 NS_IMETHODIMP
1698 nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
1699 void *aTargetObj)
1701 // This check is called for event handlers
1702 nsresult rv;
1703 nsIPrincipal* subject =
1704 GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
1706 // If subject is null, get a principal from the function object's scope.
1707 if (NS_SUCCEEDED(rv) && !subject)
1709 #ifdef DEBUG
1711 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, (JSObject *)aFunObj);
1712 JSScript *script = JS_GetFunctionScript(aCx, fun);
1714 NS_ASSERTION(!script, "Null principal for non-native function!");
1716 #endif
1718 subject = doGetObjectPrincipal((JSObject*)aFunObj);
1721 if (!subject)
1722 return NS_ERROR_FAILURE;
1724 if (subject == mSystemPrincipal)
1725 // This is the system principal: just allow access
1726 return NS_OK;
1728 // Check if the principal the function was compiled under is
1729 // allowed to execute scripts.
1731 PRBool result;
1732 rv = CanExecuteScripts(aCx, subject, &result);
1733 if (NS_FAILED(rv))
1734 return rv;
1736 if (!result)
1737 return NS_ERROR_DOM_SECURITY_ERR;
1740 ** Get origin of subject and object and compare.
1742 JSObject* obj = (JSObject*)aTargetObj;
1743 nsIPrincipal* object = doGetObjectPrincipal(obj);
1745 if (!object)
1746 return NS_ERROR_FAILURE;
1748 PRBool subsumes;
1749 rv = subject->Subsumes(object, &subsumes);
1750 if (NS_SUCCEEDED(rv) && !subsumes) {
1751 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1753 return rv;
1756 NS_IMETHODIMP
1757 nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
1758 nsIPrincipal *aPrincipal,
1759 PRBool *result)
1761 *result = PR_FALSE;
1763 if (aPrincipal == mSystemPrincipal)
1765 // Even if JavaScript is disabled, we must still execute system scripts
1766 *result = PR_TRUE;
1767 return NS_OK;
1770 //-- See if the current window allows JS execution
1771 nsIScriptContext *scriptContext = GetScriptContext(cx);
1772 if (!scriptContext) return NS_ERROR_FAILURE;
1774 if (!scriptContext->GetScriptsEnabled()) {
1775 // No scripting on this context, folks
1776 *result = PR_FALSE;
1777 return NS_OK;
1780 nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
1782 if (!sgo) {
1783 return NS_ERROR_FAILURE;
1786 // window can be null here if we're running with a non-DOM window
1787 // as the script global (i.e. a XUL prototype document).
1788 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
1789 nsCOMPtr<nsIDocShell> docshell;
1790 nsresult rv;
1792 if (window) {
1793 docshell = window->GetDocShell();
1796 if (docshell) {
1797 rv = docshell->GetCanExecuteScripts(result);
1798 if (NS_FAILED(rv)) return rv;
1799 if (!*result) return NS_OK;
1802 // OK, the docshell doesn't have script execution explicitly disabled.
1803 // Check whether our URI is an "about:" URI that allows scripts. If it is,
1804 // we need to allow JS to run. In this case, don't apply the JS enabled
1805 // pref or policies. On failures, just press on and don't do this special
1806 // case.
1807 nsCOMPtr<nsIURI> principalURI;
1808 aPrincipal->GetURI(getter_AddRefs(principalURI));
1809 if (!principalURI) {
1810 // Broken principal of some sort. Disallow.
1811 *result = PR_FALSE;
1812 return NS_ERROR_UNEXPECTED;
1815 PRBool isAbout;
1816 rv = principalURI->SchemeIs("about", &isAbout);
1817 if (NS_SUCCEEDED(rv) && isAbout) {
1818 nsCOMPtr<nsIAboutModule> module;
1819 rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
1820 if (NS_SUCCEEDED(rv)) {
1821 PRUint32 flags;
1822 rv = module->GetURIFlags(principalURI, &flags);
1823 if (NS_SUCCEEDED(rv) &&
1824 (flags & nsIAboutModule::ALLOW_SCRIPT)) {
1825 *result = PR_TRUE;
1826 return NS_OK;
1831 *result = mIsJavaScriptEnabled;
1832 if (!*result)
1833 return NS_OK; // Do not run scripts
1835 //-- Check for a per-site policy
1836 static const char jsPrefGroupName[] = "javascript";
1837 ClassInfoData nameData(nsnull, jsPrefGroupName);
1839 SecurityLevel secLevel;
1840 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1841 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1842 nsnull, &secLevel);
1843 if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
1845 *result = PR_FALSE;
1846 return rv;
1849 //-- Nobody vetoed, so allow the JS to run.
1850 *result = PR_TRUE;
1851 return NS_OK;
1854 ///////////////// Principals ///////////////////////
1855 NS_IMETHODIMP
1856 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
1858 nsresult rv;
1859 *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
1860 if (NS_SUCCEEDED(rv))
1861 NS_IF_ADDREF(*aSubjectPrincipal);
1862 return rv;
1865 nsIPrincipal*
1866 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
1868 NS_PRECONDITION(rv, "Null out param");
1869 JSContext *cx = GetCurrentJSContext();
1870 if (!cx)
1872 *rv = NS_OK;
1873 return nsnull;
1875 return GetSubjectPrincipal(cx, rv);
1878 NS_IMETHODIMP
1879 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
1881 NS_ADDREF(*result = mSystemPrincipal);
1883 return NS_OK;
1886 NS_IMETHODIMP
1887 nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem)
1889 NS_ENSURE_ARG_POINTER(aIsSystem);
1890 *aIsSystem = PR_FALSE;
1892 if (!mSystemPrincipal)
1893 return NS_OK;
1895 nsCOMPtr<nsIPrincipal> subject;
1896 nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
1897 if (NS_FAILED(rv))
1898 return rv;
1900 if(!subject)
1902 // No subject principal means no JS is running;
1903 // this is the equivalent of system principal code
1904 *aIsSystem = PR_TRUE;
1905 return NS_OK;
1908 return mSystemPrincipal->Equals(subject, aIsSystem);
1911 NS_IMETHODIMP
1912 nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint,
1913 const nsACString& aSubjectName,
1914 const nsACString& aPrettyName,
1915 nsISupports* aCertificate,
1916 nsIURI* aURI,
1917 nsIPrincipal **result)
1919 *result = nsnull;
1921 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() &&
1922 !aSubjectName.IsEmpty() &&
1923 aCertificate);
1925 return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName,
1926 aPrettyName, aCertificate, aURI, PR_TRUE,
1927 result);
1930 nsresult
1931 nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
1932 const nsACString& aSubjectName,
1933 const nsACString& aPrettyName,
1934 nsISupports* aCertificate,
1935 nsIURI* aURI,
1936 PRBool aModifyTable,
1937 nsIPrincipal **result)
1939 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty());
1941 // Create a certificate principal out of the certificate ID
1942 // and URI given to us. We will use this principal to test
1943 // equality when doing our hashtable lookups below.
1944 nsRefPtr<nsPrincipal> certificate = new nsPrincipal();
1945 if (!certificate)
1946 return NS_ERROR_OUT_OF_MEMORY;
1948 nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
1949 aPrettyName, aCertificate, aURI);
1950 NS_ENSURE_SUCCESS(rv, rv);
1952 // Check to see if we already have this principal.
1953 nsCOMPtr<nsIPrincipal> fromTable;
1954 mPrincipals.Get(certificate, getter_AddRefs(fromTable));
1955 if (fromTable) {
1956 // Bingo. We found the certificate in the table, which means
1957 // that it has escalated privileges.
1959 if (aModifyTable) {
1960 // Make sure this principal has names, so if we ever go to save it
1961 // we'll save them. If we get a name mismatch here we'll throw,
1962 // but that's desirable.
1963 rv = static_cast<nsPrincipal*>
1964 (static_cast<nsIPrincipal*>(fromTable))
1965 ->EnsureCertData(aSubjectName, aPrettyName, aCertificate);
1966 if (NS_FAILED(rv)) {
1967 // We have a subject name mismatch for the same cert id.
1968 // Hand back the |certificate| object we created and don't give
1969 // it any rights from the table.
1970 NS_ADDREF(*result = certificate);
1971 return NS_OK;
1975 if (!aURI) {
1976 // We were asked to just get the base certificate, so output
1977 // what we have in the table.
1978 certificate = static_cast<nsPrincipal*>
1979 (static_cast<nsIPrincipal*>
1980 (fromTable));
1981 } else {
1982 // We found a certificate and now need to install a codebase
1983 // on it. We don't want to modify the principal in the hash
1984 // table, so create a new principal and clone the pertinent
1985 // things.
1986 nsXPIDLCString prefName;
1987 nsXPIDLCString id;
1988 nsXPIDLCString subjectName;
1989 nsXPIDLCString granted;
1990 nsXPIDLCString denied;
1991 PRBool isTrusted;
1992 rv = fromTable->GetPreferences(getter_Copies(prefName),
1993 getter_Copies(id),
1994 getter_Copies(subjectName),
1995 getter_Copies(granted),
1996 getter_Copies(denied),
1997 &isTrusted);
1998 // XXXbz assert something about subjectName and aSubjectName here?
1999 if (NS_SUCCEEDED(rv)) {
2000 NS_ASSERTION(!isTrusted, "Shouldn't have isTrusted true here");
2002 certificate = new nsPrincipal();
2003 if (!certificate)
2004 return NS_ERROR_OUT_OF_MEMORY;
2006 rv = certificate->InitFromPersistent(prefName, id,
2007 subjectName, aPrettyName,
2008 granted, denied,
2009 aCertificate,
2010 PR_TRUE, PR_FALSE);
2011 if (NS_FAILED(rv))
2012 return rv;
2014 certificate->SetURI(aURI);
2019 NS_ADDREF(*result = certificate);
2021 return rv;
2024 nsresult
2025 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **result)
2027 // I _think_ it's safe to not create null principals here based on aURI.
2028 // At least all the callers would do the right thing in those cases, as far
2029 // as I can tell. --bz
2031 nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
2032 if (uriPrinc) {
2033 nsCOMPtr<nsIPrincipal> principal;
2034 uriPrinc->GetPrincipal(getter_AddRefs(principal));
2035 if (!principal || principal == mSystemPrincipal) {
2036 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
2039 principal.forget(result);
2041 return NS_OK;
2044 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2045 if (!codebase)
2046 return NS_ERROR_OUT_OF_MEMORY;
2048 nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
2049 EmptyCString(), nsnull, aURI);
2050 if (NS_FAILED(rv))
2051 return rv;
2053 NS_ADDREF(*result = codebase);
2055 return NS_OK;
2058 NS_IMETHODIMP
2059 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
2060 nsIPrincipal **result)
2062 NS_ENSURE_ARG(aURI);
2064 PRBool inheritsPrincipal;
2065 nsresult rv =
2066 NS_URIChainHasFlags(aURI,
2067 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
2068 &inheritsPrincipal);
2069 if (NS_FAILED(rv) || inheritsPrincipal) {
2070 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
2073 nsCOMPtr<nsIPrincipal> principal;
2074 rv = CreateCodebasePrincipal(aURI, getter_AddRefs(principal));
2075 if (NS_FAILED(rv)) return rv;
2077 if (mPrincipals.Count() > 0)
2079 //-- Check to see if we already have this principal.
2080 nsCOMPtr<nsIPrincipal> fromTable;
2081 mPrincipals.Get(principal, getter_AddRefs(fromTable));
2082 if (fromTable) {
2083 // We found an existing codebase principal. But it might have a
2084 // generic codebase for this origin on it. Install our particular
2085 // codebase.
2086 // XXXbz this is kinda similar to the code in
2087 // GetCertificatePrincipal, but just ever so slightly different.
2088 // Oh, well.
2089 nsXPIDLCString prefName;
2090 nsXPIDLCString id;
2091 nsXPIDLCString subjectName;
2092 nsXPIDLCString granted;
2093 nsXPIDLCString denied;
2094 PRBool isTrusted;
2095 rv = fromTable->GetPreferences(getter_Copies(prefName),
2096 getter_Copies(id),
2097 getter_Copies(subjectName),
2098 getter_Copies(granted),
2099 getter_Copies(denied),
2100 &isTrusted);
2101 if (NS_SUCCEEDED(rv)) {
2102 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2103 if (!codebase)
2104 return NS_ERROR_OUT_OF_MEMORY;
2106 rv = codebase->InitFromPersistent(prefName, id,
2107 subjectName, EmptyCString(),
2108 granted, denied,
2109 nsnull, PR_FALSE,
2110 isTrusted);
2111 if (NS_FAILED(rv))
2112 return rv;
2114 codebase->SetURI(aURI);
2115 principal = codebase;
2121 NS_IF_ADDREF(*result = principal);
2123 return NS_OK;
2126 NS_IMETHODIMP
2127 nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
2128 nsIPrincipal **result)
2130 *result = nsnull;
2132 nsIScriptContextPrincipal* scp =
2133 GetScriptContextPrincipalFromJSContext(cx);
2135 if (!scp)
2137 return NS_ERROR_FAILURE;
2140 nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
2141 if (globalData)
2142 NS_IF_ADDREF(*result = globalData->GetPrincipal());
2144 return NS_OK;
2147 // static
2148 nsIPrincipal*
2149 nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
2150 JSScript *script,
2151 nsresult* rv)
2153 NS_PRECONDITION(rv, "Null out param");
2154 *rv = NS_OK;
2155 if (!script)
2157 return nsnull;
2159 JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
2160 if (!jsp) {
2161 *rv = NS_ERROR_FAILURE;
2162 NS_ERROR("Script compiled without principals!");
2163 return nsnull;
2165 nsJSPrincipals *nsJSPrin = static_cast<nsJSPrincipals *>(jsp);
2166 nsIPrincipal* result = nsJSPrin->nsIPrincipalPtr;
2167 if (!result)
2168 *rv = NS_ERROR_FAILURE;
2169 return result;
2172 // static
2173 nsIPrincipal*
2174 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
2175 JSObject *obj,
2176 JSStackFrame *fp,
2177 nsresult *rv)
2179 NS_PRECONDITION(rv, "Null out param");
2181 *rv = NS_OK;
2183 if (!JS_ObjectIsFunction(cx, obj))
2185 // Protect against pseudo-functions (like SJOWs).
2186 nsIPrincipal *result = doGetObjectPrincipal(obj);
2187 if (!result)
2188 *rv = NS_ERROR_FAILURE;
2189 return result;
2192 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
2193 JSScript *script = JS_GetFunctionScript(cx, fun);
2195 if (!script)
2197 // A native function: skip it in order to find its scripted caller.
2198 return nsnull;
2201 JSScript *frameScript = fp ? JS_GetFrameScript(cx, fp) : nsnull;
2203 if (frameScript && frameScript != script)
2205 // There is a frame script, and it's different from the
2206 // function script. In this case we're dealing with either
2207 // an eval or a Script object, and in these cases the
2208 // principal we want is in the frame's script, not in the
2209 // function's script. The function's script is where the
2210 // eval-calling code came from, not where the eval or new
2211 // Script object came from, and we want the principal of
2212 // the eval function object or new Script object.
2214 script = frameScript;
2216 else if (JS_GetFunctionObject(fun) != obj)
2218 // Here, obj is a cloned function object. In this case, the
2219 // clone's prototype may have been precompiled from brutally
2220 // shared chrome, or else it is a lambda or nested function.
2221 // The general case here is a function compiled against a
2222 // different scope than the one it is parented by at runtime,
2223 // hence the creation of a clone to carry the correct scope
2224 // chain linkage.
2226 // Since principals follow scope, we must get the object
2227 // principal from the clone's scope chain. There are no
2228 // reliable principals compiled into the function itself.
2230 nsIPrincipal *result = doGetObjectPrincipal(obj);
2231 if (!result)
2232 *rv = NS_ERROR_FAILURE;
2233 return result;
2236 return GetScriptPrincipal(cx, script, rv);
2239 nsIPrincipal*
2240 nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
2241 JSStackFrame *fp,
2242 nsresult *rv)
2244 NS_PRECONDITION(rv, "Null out param");
2245 JSObject *obj = JS_GetFrameFunctionObject(cx, fp);
2246 if (!obj)
2248 // Must be in a top-level script. Get principal from the script.
2249 JSScript *script = JS_GetFrameScript(cx, fp);
2250 return GetScriptPrincipal(cx, script, rv);
2253 nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
2255 #ifdef DEBUG
2256 if (NS_SUCCEEDED(*rv) && !result)
2258 JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
2259 JSScript *script = JS_GetFunctionScript(cx, fun);
2261 NS_ASSERTION(!script, "Null principal for non-native function!");
2263 #endif
2265 return result;
2268 nsIPrincipal*
2269 nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
2270 JSStackFrame **frameResult,
2271 nsresult* rv)
2273 NS_PRECONDITION(rv, "Null out param");
2274 //-- If there's no principal on the stack, look at the global object
2275 // and return the innermost frame for annotations.
2276 *rv = NS_OK;
2278 if (cx)
2280 JSStackFrame *target = nsnull;
2281 nsIPrincipal *targetPrincipal = nsnull;
2282 for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
2284 if (cp->mCx == cx)
2286 target = cp->mFp;
2287 targetPrincipal = cp->mPrincipal;
2288 break;
2292 // Get principals from innermost JavaScript frame.
2293 JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
2294 for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
2296 if (fp == target)
2297 break;
2298 nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
2299 if (result)
2301 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
2302 *frameResult = fp;
2303 return result;
2307 // If targetPrincipal is non-null, then it means that someone wants to
2308 // clamp the principals on this context to this principal. Note that
2309 // fp might not equal target here (fp might be null) because someone
2310 // could have set aside the frame chain in the meantime.
2311 if (targetPrincipal)
2313 if (fp && fp == target)
2315 *frameResult = fp;
2317 else
2319 JSStackFrame *inner = nsnull;
2320 *frameResult = JS_FrameIterator(cx, &inner);
2323 return targetPrincipal;
2326 nsIScriptContextPrincipal* scp =
2327 GetScriptContextPrincipalFromJSContext(cx);
2328 if (scp)
2330 nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
2331 if (!globalData)
2333 *rv = NS_ERROR_FAILURE;
2334 return nsnull;
2337 // Note that we're not in a loop or anything, and nothing comes
2338 // after this point in the function, so we can just return here.
2339 nsIPrincipal* result = globalData->GetPrincipal();
2340 if (result)
2342 JSStackFrame *inner = nsnull;
2343 *frameResult = JS_FrameIterator(cx, &inner);
2344 return result;
2349 return nsnull;
2352 nsIPrincipal*
2353 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
2354 nsresult* rv)
2356 NS_PRECONDITION(rv, "Null out param");
2357 JSStackFrame *fp;
2358 return GetPrincipalAndFrame(cx, &fp, rv);
2361 NS_IMETHODIMP
2362 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
2363 nsIPrincipal **result)
2365 *result = doGetObjectPrincipal(aObj);
2366 if (!*result)
2367 return NS_ERROR_FAILURE;
2368 NS_ADDREF(*result);
2369 return NS_OK;
2372 // static
2373 nsIPrincipal*
2374 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
2375 #ifdef DEBUG
2376 , PRBool aAllowShortCircuit
2377 #endif
2380 NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
2381 nsIPrincipal* result = nsnull;
2383 #ifdef DEBUG
2384 JSObject* origObj = aObj;
2385 #endif
2387 js::Class *jsClass = aObj->getClass();
2389 // A common case seen in this code is that we enter this function
2390 // with aObj being a Function object, whose parent is a Call
2391 // object. Neither of those have object principals, so we can skip
2392 // those objects here before we enter the below loop. That way we
2393 // avoid wasting time checking properties of their classes etc in
2394 // the loop.
2396 if (jsClass == &js_FunctionClass) {
2397 aObj = aObj->getParent();
2399 if (!aObj)
2400 return nsnull;
2402 jsClass = aObj->getClass();
2404 if (jsClass == &js_CallClass) {
2405 aObj = aObj->getParent();
2407 if (!aObj)
2408 return nsnull;
2410 jsClass = aObj->getClass();
2414 do {
2415 // Note: jsClass is set before this loop, and also at the
2416 // *end* of this loop.
2418 if (IS_WRAPPER_CLASS(jsClass)) {
2419 result = sXPConnect->GetPrincipal(aObj,
2420 #ifdef DEBUG
2421 aAllowShortCircuit
2422 #else
2423 PR_TRUE
2424 #endif
2426 if (result) {
2427 break;
2429 } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
2430 JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
2431 nsISupports *priv = (nsISupports *) aObj->getPrivate();
2433 #ifdef DEBUG
2434 if (aAllowShortCircuit) {
2435 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
2436 do_QueryInterface(priv);
2438 NS_ASSERTION(!xpcWrapper ||
2439 !strcmp(jsClass->name, "XPCNativeWrapper"),
2440 "Uh, an nsIXPConnectWrappedNative with the "
2441 "wrong JSClass or getObjectOps hooks!");
2443 #endif
2445 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2446 do_QueryInterface(priv);
2448 if (objPrin) {
2449 result = objPrin->GetPrincipal();
2451 if (result) {
2452 break;
2457 aObj = aObj->getParent();
2459 if (!aObj)
2460 break;
2462 jsClass = aObj->getClass();
2463 } while (1);
2465 #ifdef DEBUG
2466 if (aAllowShortCircuit) {
2467 nsIPrincipal *principal = doGetObjectPrincipal(origObj, PR_FALSE);
2469 // Location is always wrapped (even for same-compartment), so we can
2470 // loosen the check to same-origin instead of same-principal.
2471 NS_ASSERTION(strcmp(jsClass->name, "Location") == 0 ?
2472 NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)) :
2473 result == principal,
2474 "Principal mismatch. Not good");
2476 #endif
2478 return result;
2481 nsresult
2482 nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
2484 //-- Save to mPrincipals
2485 mPrincipals.Put(aToSave, aToSave);
2487 //-- Save to prefs
2488 nsXPIDLCString idPrefName;
2489 nsXPIDLCString id;
2490 nsXPIDLCString subjectName;
2491 nsXPIDLCString grantedList;
2492 nsXPIDLCString deniedList;
2493 PRBool isTrusted;
2494 nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName),
2495 getter_Copies(id),
2496 getter_Copies(subjectName),
2497 getter_Copies(grantedList),
2498 getter_Copies(deniedList),
2499 &isTrusted);
2500 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2502 nsCAutoString grantedPrefName;
2503 nsCAutoString deniedPrefName;
2504 nsCAutoString subjectNamePrefName;
2505 rv = GetPrincipalPrefNames( idPrefName,
2506 grantedPrefName,
2507 deniedPrefName,
2508 subjectNamePrefName );
2509 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2511 mIsWritingPrefs = PR_TRUE;
2512 if (grantedList)
2513 mPrefBranch->SetCharPref(grantedPrefName.get(), grantedList);
2514 else
2515 mPrefBranch->ClearUserPref(grantedPrefName.get());
2517 if (deniedList)
2518 mPrefBranch->SetCharPref(deniedPrefName.get(), deniedList);
2519 else
2520 mPrefBranch->ClearUserPref(deniedPrefName.get());
2522 if (grantedList || deniedList) {
2523 mPrefBranch->SetCharPref(idPrefName, id);
2524 mPrefBranch->SetCharPref(subjectNamePrefName.get(),
2525 subjectName);
2527 else {
2528 mPrefBranch->ClearUserPref(idPrefName);
2529 mPrefBranch->ClearUserPref(subjectNamePrefName.get());
2532 mIsWritingPrefs = PR_FALSE;
2534 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
2535 NS_ENSURE_SUCCESS(rv, rv);
2536 return prefService->SavePrefFile(nsnull);
2539 ///////////////// Capabilities API /////////////////////
2540 NS_IMETHODIMP
2541 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
2542 PRBool *result)
2544 nsresult rv;
2545 JSStackFrame *fp = nsnull;
2546 JSContext *cx = GetCurrentJSContext();
2547 fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
2548 if (!fp)
2550 // No script code on stack. Allow execution.
2551 *result = PR_TRUE;
2552 return NS_OK;
2554 *result = PR_FALSE;
2555 nsIPrincipal* previousPrincipal = nsnull;
2558 nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
2559 if (NS_FAILED(rv))
2560 return rv;
2561 if (!principal)
2562 continue;
2563 // If caller has a different principal, stop looking up the stack.
2564 if(previousPrincipal)
2566 PRBool isEqual = PR_FALSE;
2567 if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
2568 break;
2570 else
2571 previousPrincipal = principal;
2573 // First check if the principal is even able to enable the
2574 // given capability. If not, don't look any further.
2575 PRInt16 canEnable;
2576 rv = principal->CanEnableCapability(capability, &canEnable);
2577 if (NS_FAILED(rv)) return rv;
2578 if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
2579 canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2580 return NS_OK;
2582 // Now see if the capability is enabled.
2583 void *annotation = JS_GetFrameAnnotation(cx, fp);
2584 rv = principal->IsCapabilityEnabled(capability, annotation, result);
2585 if (NS_FAILED(rv)) return rv;
2586 if (*result)
2587 return NS_OK;
2588 } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
2590 if (!previousPrincipal)
2592 // No principals on the stack, all native code. Allow
2593 // execution if the subject principal is the system principal.
2595 return SubjectPrincipalIsSystem(result);
2598 return NS_OK;
2601 void
2602 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
2604 nsAutoString newcaps;
2605 nsAutoString rawcap;
2606 NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
2607 PRInt32 pos;
2608 PRInt32 index = kNotFound;
2609 nsresult rv;
2611 NS_ASSERTION(kNotFound == -1, "Basic constant changed, algorithm broken!");
2613 do {
2614 pos = index+1;
2615 index = aCapability.FindChar(' ', pos);
2616 rawcap = Substring(aCapability, pos,
2617 (index == kNotFound) ? index : index - pos);
2619 nsXPIDLString capstr;
2620 rv = sStrBundle->GetStringFromName(
2621 nsPromiseFlatString(capdesc+rawcap).get(),
2622 getter_Copies(capstr));
2623 if (NS_SUCCEEDED(rv))
2624 newcaps += capstr;
2625 else
2627 nsXPIDLString extensionCap;
2628 const PRUnichar* formatArgs[] = { rawcap.get() };
2629 rv = sStrBundle->FormatStringFromName(
2630 NS_LITERAL_STRING("ExtensionCapability").get(),
2631 formatArgs,
2632 NS_ARRAY_LENGTH(formatArgs),
2633 getter_Copies(extensionCap));
2634 if (NS_SUCCEEDED(rv))
2635 newcaps += extensionCap;
2636 else
2637 newcaps += rawcap;
2640 newcaps += NS_LITERAL_STRING("\n");
2641 } while (index != kNotFound);
2643 aCapability = newcaps;
2646 PRBool
2647 nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
2648 const char* aCapability, PRBool *checkValue)
2650 nsresult rv;
2651 *checkValue = PR_FALSE;
2653 //-- Get a prompter for the current window.
2654 nsCOMPtr<nsIPrompt> prompter;
2655 if (cx)
2657 nsIScriptContext *scriptContext = GetScriptContext(cx);
2658 if (scriptContext)
2660 nsCOMPtr<nsIDOMWindowInternal> domWin =
2661 do_QueryInterface(scriptContext->GetGlobalObject());
2662 if (domWin)
2663 domWin->GetPrompter(getter_AddRefs(prompter));
2667 if (!prompter)
2669 //-- Couldn't get prompter from the current window, so get the prompt service.
2670 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2671 if (wwatch)
2672 wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
2673 if (!prompter)
2674 return PR_FALSE;
2677 //-- Localize the dialog text
2678 nsXPIDLString check;
2679 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
2680 getter_Copies(check));
2681 if (NS_FAILED(rv))
2682 return PR_FALSE;
2684 nsXPIDLString title;
2685 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
2686 getter_Copies(title));
2687 if (NS_FAILED(rv))
2688 return PR_FALSE;
2690 nsXPIDLString yesStr;
2691 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
2692 getter_Copies(yesStr));
2693 if (NS_FAILED(rv))
2694 return PR_FALSE;
2696 nsXPIDLString noStr;
2697 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(),
2698 getter_Copies(noStr));
2699 if (NS_FAILED(rv))
2700 return PR_FALSE;
2702 nsCAutoString val;
2703 PRBool hasCert;
2704 aPrincipal->GetHasCertificate(&hasCert);
2705 if (hasCert)
2706 rv = aPrincipal->GetPrettyName(val);
2707 else
2708 rv = GetPrincipalDomainOrigin(aPrincipal, val);
2710 if (NS_FAILED(rv))
2711 return PR_FALSE;
2713 NS_ConvertUTF8toUTF16 location(val);
2714 NS_ConvertASCIItoUTF16 capability(aCapability);
2715 FormatCapabilityString(capability);
2716 const PRUnichar *formatStrings[] = { location.get(), capability.get() };
2718 nsXPIDLString message;
2719 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
2720 formatStrings,
2721 NS_ARRAY_LENGTH(formatStrings),
2722 getter_Copies(message));
2723 if (NS_FAILED(rv))
2724 return PR_FALSE;
2726 PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
2727 rv = prompter->ConfirmEx(title.get(), message.get(),
2728 (nsIPrompt::BUTTON_DELAY_ENABLE) +
2729 (nsIPrompt::BUTTON_POS_1_DEFAULT) +
2730 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
2731 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1),
2732 yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed);
2734 if (NS_FAILED(rv))
2735 *checkValue = PR_FALSE;
2736 return (buttonPressed == 0);
2739 NS_IMETHODIMP
2740 nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal,
2741 const char *capability, PRInt16* canEnable)
2743 if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
2744 return NS_ERROR_FAILURE;
2745 if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2747 // Prompt user for permission to enable capability.
2748 JSContext* cx = GetCurrentJSContext();
2749 PRBool remember;
2750 if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
2751 *canEnable = nsIPrincipal::ENABLE_GRANTED;
2752 else
2753 *canEnable = nsIPrincipal::ENABLE_DENIED;
2754 if (remember)
2756 //-- Save principal to prefs and to mPrincipals
2757 if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
2758 return NS_ERROR_FAILURE;
2759 if (NS_FAILED(SavePrincipal(aPrincipal)))
2760 return NS_ERROR_FAILURE;
2763 return NS_OK;
2766 NS_IMETHODIMP
2767 nsScriptSecurityManager::EnableCapability(const char *capability)
2769 JSContext *cx = GetCurrentJSContext();
2770 JSStackFrame *fp;
2772 //-- Error checks for capability string length (200)
2773 if(PL_strlen(capability)>200)
2775 static const char msg[] = "Capability name too long";
2776 SetPendingException(cx, msg);
2777 return NS_ERROR_FAILURE;
2780 //-- Check capability string for valid characters
2782 // Logically we might have wanted this in nsPrincipal, but performance
2783 // worries dictate it can't go in IsCapabilityEnabled() and we may have
2784 // to show the capability on a dialog before we call the principal's
2785 // EnableCapability().
2787 // We don't need to validate the capability string on the other APIs
2788 // available to web content. Without the ability to enable junk then
2789 // isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
2790 // the right thing (effectively nothing) when passed unallowed chars.
2791 for (const char *ch = capability; *ch; ++ch)
2793 if (!NS_IS_ALPHA(*ch) && *ch != ' ' && !NS_IS_DIGIT(*ch)
2794 && *ch != '_' && *ch != '-' && *ch != '.')
2796 static const char msg[] = "Invalid character in capability name";
2797 SetPendingException(cx, msg);
2798 return NS_ERROR_FAILURE;
2802 nsresult rv;
2803 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2804 if (NS_FAILED(rv))
2805 return rv;
2806 if (!principal)
2807 return NS_ERROR_NOT_AVAILABLE;
2809 void *annotation = JS_GetFrameAnnotation(cx, fp);
2810 PRBool enabled;
2811 if (NS_FAILED(principal->IsCapabilityEnabled(capability, annotation,
2812 &enabled)))
2813 return NS_ERROR_FAILURE;
2814 if (enabled)
2815 return NS_OK;
2817 PRInt16 canEnable;
2818 if (NS_FAILED(RequestCapability(principal, capability, &canEnable)))
2819 return NS_ERROR_FAILURE;
2821 if (canEnable != nsIPrincipal::ENABLE_GRANTED)
2823 nsCAutoString val;
2824 PRBool hasCert;
2825 nsresult rv;
2826 principal->GetHasCertificate(&hasCert);
2827 if (hasCert)
2828 rv = principal->GetPrettyName(val);
2829 else
2830 rv = GetPrincipalDomainOrigin(principal, val);
2832 if (NS_FAILED(rv))
2833 return rv;
2835 NS_ConvertUTF8toUTF16 location(val);
2836 NS_ConvertUTF8toUTF16 cap(capability);
2837 const PRUnichar *formatStrings[] = { location.get(), cap.get() };
2839 nsXPIDLString message;
2840 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
2841 formatStrings,
2842 NS_ARRAY_LENGTH(formatStrings),
2843 getter_Copies(message));
2844 if (NS_FAILED(rv))
2845 return rv;
2847 SetPendingException(cx, message.get());
2849 return NS_ERROR_FAILURE; // XXX better error code?
2851 if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
2852 return NS_ERROR_FAILURE;
2853 JS_SetFrameAnnotation(cx, fp, annotation);
2854 return NS_OK;
2857 NS_IMETHODIMP
2858 nsScriptSecurityManager::RevertCapability(const char *capability)
2860 JSContext *cx = GetCurrentJSContext();
2861 JSStackFrame *fp;
2862 nsresult rv;
2863 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2864 if (NS_FAILED(rv))
2865 return rv;
2866 if (!principal)
2867 return NS_ERROR_NOT_AVAILABLE;
2868 void *annotation = JS_GetFrameAnnotation(cx, fp);
2869 principal->RevertCapability(capability, &annotation);
2870 JS_SetFrameAnnotation(cx, fp, annotation);
2871 return NS_OK;
2874 NS_IMETHODIMP
2875 nsScriptSecurityManager::DisableCapability(const char *capability)
2877 JSContext *cx = GetCurrentJSContext();
2878 JSStackFrame *fp;
2879 nsresult rv;
2880 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2881 if (NS_FAILED(rv))
2882 return rv;
2883 if (!principal)
2884 return NS_ERROR_NOT_AVAILABLE;
2885 void *annotation = JS_GetFrameAnnotation(cx, fp);
2886 principal->DisableCapability(capability, &annotation);
2887 JS_SetFrameAnnotation(cx, fp, annotation);
2888 return NS_OK;
2891 //////////////// Master Certificate Functions ///////////////////////////////////////
2892 NS_IMETHODIMP
2893 nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint,
2894 const char* capability,
2895 PRInt16 canEnable)
2897 NS_ENSURE_ARG(!certFingerprint.IsEmpty());
2899 nsresult rv;
2900 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv);
2901 if (NS_FAILED(rv))
2902 return rv;
2904 //-- Get the system certificate
2905 if (!mSystemCertificate)
2907 nsCOMPtr<nsIFile> systemCertFile;
2908 nsCOMPtr<nsIProperties> directoryService =
2909 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
2910 if (!directoryService) return NS_ERROR_FAILURE;
2911 rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
2912 getter_AddRefs(systemCertFile));
2913 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2914 systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
2915 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2916 nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv);
2917 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2918 rv = systemCertZip->Open(systemCertFile);
2919 if (NS_SUCCEEDED(rv))
2921 rv = systemCertZip->GetCertificatePrincipal(nsnull,
2922 getter_AddRefs(mSystemCertificate));
2923 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2927 //-- Make sure the caller's principal is the system certificate
2928 PRBool isEqual = PR_FALSE;
2929 if (mSystemCertificate)
2931 rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual);
2932 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2934 if (!isEqual)
2936 JSContext* cx = GetCurrentJSContext();
2937 if (!cx) return NS_ERROR_FAILURE;
2938 static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
2939 static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
2940 SetPendingException(cx, mSystemCertificate ? msg1 : msg2);
2941 return NS_ERROR_FAILURE;
2944 //-- Get the target principal
2945 nsCOMPtr<nsIPrincipal> objectPrincipal;
2946 rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(),
2947 EmptyCString(), nsnull,
2948 nsnull, PR_FALSE,
2949 getter_AddRefs(objectPrincipal));
2950 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2951 rv = objectPrincipal->SetCanEnableCapability(capability, canEnable);
2952 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2953 return SavePrincipal(objectPrincipal);
2956 ////////////////////////////////////////////////
2957 // Methods implementing nsIXPCSecurityManager //
2958 ////////////////////////////////////////////////
2960 NS_IMETHODIMP
2961 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
2962 const nsIID &aIID,
2963 nsISupports *aObj,
2964 nsIClassInfo *aClassInfo,
2965 void **aPolicy)
2967 #ifdef DEBUG_CAPS_CanCreateWrapper
2968 char* iidStr = aIID.ToString();
2969 printf("### CanCreateWrapper(%s) ", iidStr);
2970 NS_Free(iidStr);
2971 #endif
2972 // XXX Special case for nsIXPCException ?
2973 ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nsnull);
2974 if (objClassInfo.IsDOMClass())
2976 #ifdef DEBUG_CAPS_CanCreateWrapper
2977 printf("DOM class - GRANTED.\n");
2978 #endif
2979 return NS_OK;
2982 //--See if the object advertises a non-default level of access
2983 // using nsISecurityCheckedComponent
2984 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
2985 do_QueryInterface(aObj);
2987 nsXPIDLCString objectSecurityLevel;
2988 if (checkedComponent)
2989 checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
2991 nsresult rv = CheckXPCPermissions(cx, aObj, nsnull, nsnull, objectSecurityLevel);
2992 if (NS_FAILED(rv))
2994 //-- Access denied, report an error
2995 NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
2996 nsCAutoString origin;
2997 nsresult rv2;
2998 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2);
2999 if (NS_SUCCEEDED(rv2) && subjectPrincipal) {
3000 GetPrincipalDomainOrigin(subjectPrincipal, origin);
3002 NS_ConvertUTF8toUTF16 originUnicode(origin);
3003 NS_ConvertUTF8toUTF16 className(objClassInfo.GetName());
3004 const PRUnichar* formatStrings[] = {
3005 className.get(),
3006 originUnicode.get()
3008 PRUint32 length = NS_ARRAY_LENGTH(formatStrings);
3009 if (originUnicode.IsEmpty()) {
3010 --length;
3011 } else {
3012 strName.AppendLiteral("ForOrigin");
3014 nsXPIDLString errorMsg;
3015 // We need to keep our existing failure rv and not override it
3016 // with a likely success code from the following string bundle
3017 // call in order to throw the correct security exception later.
3018 rv2 = sStrBundle->FormatStringFromName(strName.get(),
3019 formatStrings,
3020 length,
3021 getter_Copies(errorMsg));
3022 NS_ENSURE_SUCCESS(rv2, rv2);
3024 SetPendingException(cx, errorMsg.get());
3026 #ifdef DEBUG_CAPS_CanCreateWrapper
3027 printf("DENIED.\n");
3029 else
3031 printf("GRANTED.\n");
3032 #endif
3035 return rv;
3038 #ifdef XPC_IDISPATCH_SUPPORT
3039 nsresult
3040 nsScriptSecurityManager::CheckComponentPermissions(JSContext *cx,
3041 const nsCID &aCID)
3043 nsresult rv;
3044 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
3045 if (NS_FAILED(rv))
3046 return rv;
3048 // Reformat the CID string so it's suitable for prefs
3049 nsXPIDLCString cidTemp;
3050 cidTemp.Adopt(aCID.ToString());
3051 nsCAutoString cid(NS_LITERAL_CSTRING("CID") +
3052 Substring(cidTemp, 1, cidTemp.Length() - 2));
3053 ToUpperCase(cid);
3055 #ifdef DEBUG_CAPS_CheckComponentPermissions
3056 printf("### CheckComponentPermissions(ClassID.%s) ",cid.get());
3057 #endif
3059 // Look up the policy for this class.
3060 // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD
3061 JSAutoRequest ar(cx);
3062 jsid cidId = INTERNED_STRING_TO_JSID(::JS_InternString(cx, cid.get()));
3064 ClassInfoData nameData(nsnull, "ClassID");
3065 SecurityLevel securityLevel;
3066 rv = LookupPolicy(subjectPrincipal, nameData, cidId,
3067 nsIXPCSecurityManager::ACCESS_CALL_METHOD,
3068 nsnull, &securityLevel);
3069 if (NS_FAILED(rv))
3070 return rv;
3072 // If there's no policy stored, use the "security.classID.allowByDefault" pref
3073 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3074 securityLevel.level = mXPCDefaultGrantAll ? SCRIPT_SECURITY_ALL_ACCESS :
3075 SCRIPT_SECURITY_NO_ACCESS;
3077 if (securityLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
3079 #ifdef DEBUG_CAPS_CheckComponentPermissions
3080 printf(" GRANTED.\n");
3081 #endif
3082 return NS_OK;
3085 #ifdef DEBUG_CAPS_CheckComponentPermissions
3086 printf(" DENIED.\n");
3087 #endif
3088 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
3090 #endif
3092 NS_IMETHODIMP
3093 nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
3094 const nsCID &aCID)
3096 #ifdef DEBUG_CAPS_CanCreateInstance
3097 char* cidStr = aCID.ToString();
3098 printf("### CanCreateInstance(%s) ", cidStr);
3099 NS_Free(cidStr);
3100 #endif
3102 nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
3103 if (NS_FAILED(rv))
3104 #ifdef XPC_IDISPATCH_SUPPORT
3106 rv = CheckComponentPermissions(cx, aCID);
3108 if (NS_FAILED(rv))
3109 #endif
3111 //-- Access denied, report an error
3112 nsCAutoString errorMsg("Permission denied to create instance of class. CID=");
3113 char cidStr[NSID_LENGTH];
3114 aCID.ToProvidedString(cidStr);
3115 errorMsg.Append(cidStr);
3116 SetPendingException(cx, errorMsg.get());
3118 #ifdef DEBUG_CAPS_CanCreateInstance
3119 printf("DENIED\n");
3121 else
3123 printf("GRANTED\n");
3124 #endif
3126 return rv;
3129 NS_IMETHODIMP
3130 nsScriptSecurityManager::CanGetService(JSContext *cx,
3131 const nsCID &aCID)
3133 #ifdef DEBUG_CAPS_CanGetService
3134 char* cidStr = aCID.ToString();
3135 printf("### CanGetService(%s) ", cidStr);
3136 NS_Free(cidStr);
3137 #endif
3139 nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
3140 if (NS_FAILED(rv))
3142 //-- Access denied, report an error
3143 nsCAutoString errorMsg("Permission denied to get service. CID=");
3144 char cidStr[NSID_LENGTH];
3145 aCID.ToProvidedString(cidStr);
3146 errorMsg.Append(cidStr);
3147 SetPendingException(cx, errorMsg.get());
3149 #ifdef DEBUG_CAPS_CanGetService
3150 printf("DENIED\n");
3152 else
3154 printf("GRANTED\n");
3155 #endif
3158 return rv;
3162 NS_IMETHODIMP
3163 nsScriptSecurityManager::CanAccess(PRUint32 aAction,
3164 nsAXPCNativeCallContext* aCallContext,
3165 JSContext* cx,
3166 JSObject* aJSObject,
3167 nsISupports* aObj,
3168 nsIClassInfo* aClassInfo,
3169 jsid aPropertyName,
3170 void** aPolicy)
3172 return CheckPropertyAccessImpl(aAction, aCallContext, cx,
3173 aJSObject, aObj, nsnull, aClassInfo,
3174 nsnull, aPropertyName, aPolicy);
3177 nsresult
3178 nsScriptSecurityManager::CheckXPCPermissions(JSContext* cx,
3179 nsISupports* aObj, JSObject* aJSObject,
3180 nsIPrincipal* aSubjectPrincipal,
3181 const char* aObjectSecurityLevel)
3183 //-- Check for the all-powerful UniversalXPConnect privilege
3184 PRBool ok = PR_FALSE;
3185 if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok)) && ok)
3186 return NS_OK;
3188 //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
3189 if (aObjectSecurityLevel)
3191 if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
3192 return NS_OK;
3193 if (cx && PL_strcasecmp(aObjectSecurityLevel, "sameOrigin") == 0)
3195 nsresult rv;
3196 if (!aJSObject)
3198 nsCOMPtr<nsIXPConnectWrappedJS> xpcwrappedjs =
3199 do_QueryInterface(aObj);
3200 if (xpcwrappedjs)
3202 rv = xpcwrappedjs->GetJSObject(&aJSObject);
3203 NS_ENSURE_SUCCESS(rv, rv);
3207 if (!aSubjectPrincipal)
3209 // No subject principal passed in. Compute it.
3210 aSubjectPrincipal = GetSubjectPrincipal(cx, &rv);
3211 NS_ENSURE_SUCCESS(rv, rv);
3213 if (aSubjectPrincipal && aJSObject)
3215 nsIPrincipal* objectPrincipal = doGetObjectPrincipal(aJSObject);
3217 // Only do anything if we have both a subject and object
3218 // principal.
3219 if (objectPrincipal)
3221 PRBool subsumes;
3222 rv = aSubjectPrincipal->Subsumes(objectPrincipal, &subsumes);
3223 NS_ENSURE_SUCCESS(rv, rv);
3224 if (subsumes)
3225 return NS_OK;
3229 else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
3231 PRBool canAccess = PR_FALSE;
3232 if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel, &canAccess)) &&
3233 canAccess)
3234 return NS_OK;
3238 //-- If user allows scripting of plugins by untrusted scripts,
3239 // and the target object is a plugin, allow the access.
3240 if(aObj)
3242 nsresult rv;
3243 nsCOMPtr<nsIPluginInstance> plugin(do_QueryInterface(aObj, &rv));
3244 if (NS_SUCCEEDED(rv))
3246 static PRBool prefSet = PR_FALSE;
3247 static PRBool allowPluginAccess = PR_FALSE;
3248 if (!prefSet)
3250 rv = mPrefBranch->GetBoolPref("security.xpconnect.plugin.unrestricted",
3251 &allowPluginAccess);
3252 prefSet = PR_TRUE;
3254 if (allowPluginAccess)
3255 return NS_OK;
3259 //-- Access tests failed
3260 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
3263 /////////////////////////////////////////////
3264 // Method implementing nsIChannelEventSink //
3265 /////////////////////////////////////////////
3266 NS_IMETHODIMP
3267 nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel,
3268 nsIChannel* newChannel,
3269 PRUint32 redirFlags,
3270 nsIAsyncVerifyRedirectCallback *cb)
3272 nsCOMPtr<nsIPrincipal> oldPrincipal;
3273 GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
3275 nsCOMPtr<nsIURI> newURI;
3276 newChannel->GetURI(getter_AddRefs(newURI));
3277 nsCOMPtr<nsIURI> newOriginalURI;
3278 newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
3280 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
3282 const PRUint32 flags =
3283 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
3284 nsIScriptSecurityManager::DISALLOW_SCRIPT;
3285 nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
3286 if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
3287 rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
3290 if (NS_FAILED(rv))
3291 return rv;
3293 cb->OnRedirectVerifyCallback(NS_OK);
3294 return NS_OK;
3298 /////////////////////////////////////
3299 // Method implementing nsIObserver //
3300 /////////////////////////////////////
3301 static const char sPrincipalPrefix[] = "capability.principal";
3302 static const char sPolicyPrefix[] = "capability.policy.";
3304 NS_IMETHODIMP
3305 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
3306 const PRUnichar* aMessage)
3308 nsresult rv = NS_OK;
3309 NS_ConvertUTF16toUTF8 messageStr(aMessage);
3310 const char *message = messageStr.get();
3312 static const char jsPrefix[] = "javascript.";
3313 static const char securityPrefix[] = "security.";
3314 if ((PL_strncmp(message, jsPrefix, sizeof(jsPrefix)-1) == 0) ||
3315 (PL_strncmp(message, securityPrefix, sizeof(securityPrefix)-1) == 0) )
3317 ScriptSecurityPrefChanged();
3319 else if (PL_strncmp(message, sPolicyPrefix, sizeof(sPolicyPrefix)-1) == 0)
3321 // This will force re-initialization of the pref table
3322 mPolicyPrefsChanged = PR_TRUE;
3324 else if ((PL_strncmp(message, sPrincipalPrefix, sizeof(sPrincipalPrefix)-1) == 0) &&
3325 !mIsWritingPrefs)
3327 static const char id[] = "id";
3328 char* lastDot = PL_strrchr(message, '.');
3329 //-- This check makes sure the string copy below doesn't overwrite its bounds
3330 if(PL_strlen(lastDot) >= sizeof(id))
3332 PL_strcpy(lastDot + 1, id);
3333 const char** idPrefArray = (const char**)&message;
3334 rv = InitPrincipals(1, idPrefArray);
3337 return rv;
3340 /////////////////////////////////////////////
3341 // Constructor, Destructor, Initialization //
3342 /////////////////////////////////////////////
3343 nsScriptSecurityManager::nsScriptSecurityManager(void)
3344 : mOriginToPolicyMap(nsnull),
3345 mDefaultPolicy(nsnull),
3346 mCapabilities(nsnull),
3347 mContextPrincipals(nsnull),
3348 mIsJavaScriptEnabled(PR_FALSE),
3349 mIsWritingPrefs(PR_FALSE),
3350 mPolicyPrefsChanged(PR_TRUE)
3351 #ifdef XPC_IDISPATCH_SUPPORT
3352 , mXPCDefaultGrantAll(PR_FALSE)
3353 #endif
3355 NS_ASSERTION(sizeof(PRWord) == sizeof(void*),
3356 "PRWord and void* have different lengths on this platform. "
3357 "This may cause a security failure with the SecurityLevel union.");
3358 mPrincipals.Init(31);
3362 nsresult nsScriptSecurityManager::Init()
3364 nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
3365 if (!xpconnect)
3366 return NS_ERROR_FAILURE;
3368 NS_ADDREF(sXPConnect = xpconnect);
3369 NS_ADDREF(sJSContextStack = xpconnect);
3371 JSContext* cx = GetSafeJSContext();
3372 if (!cx) return NS_ERROR_FAILURE; // this can happen of xpt loading fails
3374 ::JS_BeginRequest(cx);
3375 if (sEnabledID == JSID_VOID)
3376 sEnabledID = INTERNED_STRING_TO_JSID(::JS_InternString(cx, "enabled"));
3377 ::JS_EndRequest(cx);
3379 InitPrefs();
3381 nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
3382 NS_ENSURE_SUCCESS(rv, rv);
3384 nsCOMPtr<nsIStringBundleService> bundleService =
3385 mozilla::services::GetStringBundleService();
3386 if (!bundleService)
3387 return NS_ERROR_FAILURE;
3389 rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
3390 NS_ENSURE_SUCCESS(rv, rv);
3392 // Create our system principal singleton
3393 nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
3394 NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
3396 rv = system->Init();
3397 NS_ENSURE_SUCCESS(rv, rv);
3399 mSystemPrincipal = system;
3401 //-- Register security check callback in the JS engine
3402 // Currently this is used to control access to function.caller
3403 nsCOMPtr<nsIJSRuntimeService> runtimeService =
3404 do_QueryInterface(sXPConnect, &rv);
3405 NS_ENSURE_SUCCESS(rv, rv);
3407 rv = runtimeService->GetRuntime(&sRuntime);
3408 NS_ENSURE_SUCCESS(rv, rv);
3410 static JSSecurityCallbacks securityCallbacks = {
3411 CheckObjectAccess,
3412 NULL,
3413 NULL,
3414 ContentSecurityPolicyPermitsJSAction
3417 #ifdef DEBUG
3418 JSSecurityCallbacks *oldcallbacks =
3419 #endif
3420 JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
3421 NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
3423 return NS_OK;
3426 static nsScriptSecurityManager *gScriptSecMan = nsnull;
3428 jsid nsScriptSecurityManager::sEnabledID = JSID_VOID;
3430 nsScriptSecurityManager::~nsScriptSecurityManager(void)
3432 NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals");
3433 delete mOriginToPolicyMap;
3434 if(mDefaultPolicy)
3435 mDefaultPolicy->Drop();
3436 delete mCapabilities;
3437 gScriptSecMan = nsnull;
3440 void
3441 nsScriptSecurityManager::Shutdown()
3443 if (sRuntime) {
3444 JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
3445 sRuntime = nsnull;
3447 sEnabledID = JSID_VOID;
3449 NS_IF_RELEASE(sIOService);
3450 NS_IF_RELEASE(sXPConnect);
3451 NS_IF_RELEASE(sJSContextStack);
3452 NS_IF_RELEASE(sStrBundle);
3455 nsScriptSecurityManager *
3456 nsScriptSecurityManager::GetScriptSecurityManager()
3458 if (!gScriptSecMan)
3460 nsScriptSecurityManager* ssManager = new nsScriptSecurityManager();
3461 if (!ssManager)
3462 return nsnull;
3463 nsresult rv;
3464 rv = ssManager->Init();
3465 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
3466 if (NS_FAILED(rv)) {
3467 delete ssManager;
3468 return nsnull;
3471 rv = nsJSPrincipals::Startup();
3472 if (NS_FAILED(rv)) {
3473 NS_WARNING("can't initialize JS engine security protocol glue!");
3474 delete ssManager;
3475 return nsnull;
3478 rv = sXPConnect->SetDefaultSecurityManager(ssManager,
3479 nsIXPCSecurityManager::HOOK_ALL);
3480 if (NS_FAILED(rv)) {
3481 NS_WARNING("Failed to install xpconnect security manager!");
3482 delete ssManager;
3483 return nsnull;
3486 gScriptSecMan = ssManager;
3488 return gScriptSecMan;
3491 // Currently this nsGenericFactory constructor is used only from FastLoad
3492 // (XPCOM object deserialization) code, when "creating" the system principal
3493 // singleton.
3494 nsSystemPrincipal *
3495 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
3497 nsIPrincipal *sysprin = nsnull;
3498 if (gScriptSecMan)
3499 NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
3500 return static_cast<nsSystemPrincipal*>(sysprin);
3503 nsresult
3504 nsScriptSecurityManager::InitPolicies()
3506 // Clear any policies cached on XPConnect wrappers
3507 NS_ENSURE_STATE(sXPConnect);
3508 nsresult rv = sXPConnect->ClearAllWrappedNativeSecurityPolicies();
3509 if (NS_FAILED(rv)) return rv;
3511 //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
3512 //-- whose dtor decrements refcount of stored DomainPolicy object
3513 delete mOriginToPolicyMap;
3515 //-- Marks all the survivor DomainPolicy objects (those cached
3516 //-- by nsPrincipal objects) as invalid: they will be released
3517 //-- on first nsPrincipal::GetSecurityPolicy() attempt.
3518 DomainPolicy::InvalidateAll();
3520 //-- Release old default policy
3521 if(mDefaultPolicy) {
3522 mDefaultPolicy->Drop();
3523 mDefaultPolicy = nsnull;
3526 //-- Initialize a new mOriginToPolicyMap
3527 mOriginToPolicyMap =
3528 new nsObjectHashtable(nsnull, nsnull, DeleteDomainEntry, nsnull);
3529 if (!mOriginToPolicyMap)
3530 return NS_ERROR_OUT_OF_MEMORY;
3532 //-- Create, refcount and initialize a new default policy
3533 mDefaultPolicy = new DomainPolicy();
3534 if (!mDefaultPolicy)
3535 return NS_ERROR_OUT_OF_MEMORY;
3537 mDefaultPolicy->Hold();
3538 if (!mDefaultPolicy->Init())
3539 return NS_ERROR_UNEXPECTED;
3541 //-- Initialize the table of security levels
3542 if (!mCapabilities)
3544 mCapabilities =
3545 new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
3546 if (!mCapabilities)
3547 return NS_ERROR_OUT_OF_MEMORY;
3550 // Get a JS context - we need it to create internalized strings later.
3551 JSContext* cx = GetSafeJSContext();
3552 NS_ASSERTION(cx, "failed to get JS context");
3553 AutoCxPusher autoPusher(sJSContextStack, cx);
3554 rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
3555 NS_ENSURE_SUCCESS(rv, rv);
3557 nsXPIDLCString policyNames;
3558 rv = mPrefBranch->GetCharPref("capability.policy.policynames",
3559 getter_Copies(policyNames));
3561 nsXPIDLCString defaultPolicyNames;
3562 rv = mPrefBranch->GetCharPref("capability.policy.default_policynames",
3563 getter_Copies(defaultPolicyNames));
3564 policyNames += NS_LITERAL_CSTRING(" ") + defaultPolicyNames;
3566 //-- Initialize domain policies
3567 char* policyCurrent = policyNames.BeginWriting();
3568 PRBool morePolicies = PR_TRUE;
3569 while (morePolicies)
3571 while(*policyCurrent == ' ' || *policyCurrent == ',')
3572 policyCurrent++;
3573 if (*policyCurrent == '\0')
3574 break;
3575 char* nameBegin = policyCurrent;
3577 while(*policyCurrent != '\0' && *policyCurrent != ' ' && *policyCurrent != ',')
3578 policyCurrent++;
3580 morePolicies = (*policyCurrent != '\0');
3581 *policyCurrent = '\0';
3582 policyCurrent++;
3584 nsCAutoString sitesPrefName(
3585 NS_LITERAL_CSTRING(sPolicyPrefix) +
3586 nsDependentCString(nameBegin) +
3587 NS_LITERAL_CSTRING(".sites"));
3588 nsXPIDLCString domainList;
3589 rv = mPrefBranch->GetCharPref(sitesPrefName.get(),
3590 getter_Copies(domainList));
3591 if (NS_FAILED(rv))
3592 continue;
3594 DomainPolicy* domainPolicy = new DomainPolicy();
3595 if (!domainPolicy)
3596 return NS_ERROR_OUT_OF_MEMORY;
3598 if (!domainPolicy->Init())
3600 delete domainPolicy;
3601 return NS_ERROR_UNEXPECTED;
3603 domainPolicy->Hold();
3604 //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
3605 char* domainStart = domainList.BeginWriting();
3606 char* domainCurrent = domainStart;
3607 char* lastDot = nsnull;
3608 char* nextToLastDot = nsnull;
3609 PRBool moreDomains = PR_TRUE;
3610 while (moreDomains)
3612 if (*domainCurrent == ' ' || *domainCurrent == '\0')
3614 moreDomains = (*domainCurrent != '\0');
3615 *domainCurrent = '\0';
3616 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : domainStart);
3617 DomainEntry *newEntry = new DomainEntry(domainStart, domainPolicy);
3618 if (!newEntry)
3620 domainPolicy->Drop();
3621 return NS_ERROR_OUT_OF_MEMORY;
3623 #ifdef DEBUG
3624 newEntry->mPolicyName_DEBUG = nameBegin;
3625 #endif
3626 DomainEntry *existingEntry = (DomainEntry *)
3627 mOriginToPolicyMap->Get(&key);
3628 if (!existingEntry)
3629 mOriginToPolicyMap->Put(&key, newEntry);
3630 else
3632 if (existingEntry->Matches(domainStart))
3634 newEntry->mNext = existingEntry;
3635 mOriginToPolicyMap->Put(&key, newEntry);
3637 else
3639 while (existingEntry->mNext)
3641 if (existingEntry->mNext->Matches(domainStart))
3643 newEntry->mNext = existingEntry->mNext;
3644 existingEntry->mNext = newEntry;
3645 break;
3647 existingEntry = existingEntry->mNext;
3649 if (!existingEntry->mNext)
3650 existingEntry->mNext = newEntry;
3653 domainStart = domainCurrent + 1;
3654 lastDot = nextToLastDot = nsnull;
3656 else if (*domainCurrent == '.')
3658 nextToLastDot = lastDot;
3659 lastDot = domainCurrent;
3661 domainCurrent++;
3664 rv = InitDomainPolicy(cx, nameBegin, domainPolicy);
3665 domainPolicy->Drop();
3666 if (NS_FAILED(rv))
3667 return rv;
3670 // Reset the "dirty" flag
3671 mPolicyPrefsChanged = PR_FALSE;
3673 #ifdef DEBUG_CAPS_HACKER
3674 PrintPolicyDB();
3675 #endif
3676 return NS_OK;
3680 nsresult
3681 nsScriptSecurityManager::InitDomainPolicy(JSContext* cx,
3682 const char* aPolicyName,
3683 DomainPolicy* aDomainPolicy)
3685 nsresult rv;
3686 nsCAutoString policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix) +
3687 nsDependentCString(aPolicyName) +
3688 NS_LITERAL_CSTRING("."));
3689 PRUint32 prefixLength = policyPrefix.Length() - 1; // subtract the '.'
3691 PRUint32 prefCount;
3692 char** prefNames;
3693 rv = mPrefBranch->GetChildList(policyPrefix.get(),
3694 &prefCount, &prefNames);
3695 if (NS_FAILED(rv)) return rv;
3696 if (prefCount == 0)
3697 return NS_OK;
3699 //-- Populate the policy
3700 PRUint32 currentPref = 0;
3701 for (; currentPref < prefCount; currentPref++)
3703 // Get the class name
3704 const char* start = prefNames[currentPref] + prefixLength + 1;
3705 char* end = PL_strchr(start, '.');
3706 if (!end) // malformed pref, bail on this one
3707 continue;
3708 static const char sitesStr[] = "sites";
3710 // We dealt with "sites" in InitPolicies(), so no need to do
3711 // that again...
3712 if (PL_strncmp(start, sitesStr, sizeof(sitesStr)-1) == 0)
3713 continue;
3715 // Get the pref value
3716 nsXPIDLCString prefValue;
3717 rv = mPrefBranch->GetCharPref(prefNames[currentPref],
3718 getter_Copies(prefValue));
3719 if (NS_FAILED(rv) || !prefValue)
3720 continue;
3722 SecurityLevel secLevel;
3723 if (PL_strcasecmp(prefValue, "noAccess") == 0)
3724 secLevel.level = SCRIPT_SECURITY_NO_ACCESS;
3725 else if (PL_strcasecmp(prefValue, "allAccess") == 0)
3726 secLevel.level = SCRIPT_SECURITY_ALL_ACCESS;
3727 else if (PL_strcasecmp(prefValue, "sameOrigin") == 0)
3728 secLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
3729 else
3730 { //-- pref value is the name of a capability
3731 nsCStringKey secLevelKey(prefValue);
3732 secLevel.capability =
3733 reinterpret_cast<char*>(mCapabilities->Get(&secLevelKey));
3734 if (!secLevel.capability)
3736 secLevel.capability = NS_strdup(prefValue);
3737 if (!secLevel.capability)
3738 break;
3739 mCapabilities->Put(&secLevelKey,
3740 secLevel.capability);
3744 *end = '\0';
3745 // Find or store this class in the classes table
3746 ClassPolicy* cpolicy =
3747 static_cast<ClassPolicy*>
3748 (PL_DHashTableOperate(aDomainPolicy, start,
3749 PL_DHASH_ADD));
3750 if (!cpolicy)
3751 break;
3753 // If this is the wildcard class (class '*'), save it in mWildcardPolicy
3754 // (we leave it stored in the hashtable too to take care of the cleanup)
3755 if ((*start == '*') && (end == start + 1)) {
3756 aDomainPolicy->mWildcardPolicy = cpolicy;
3758 // Make sure that cpolicy knows about aDomainPolicy so it can reset
3759 // the mWildcardPolicy pointer as needed if it gets moved in the
3760 // hashtable.
3761 cpolicy->mDomainWeAreWildcardFor = aDomainPolicy;
3764 // Get the property name
3765 start = end + 1;
3766 end = PL_strchr(start, '.');
3767 if (end)
3768 *end = '\0';
3770 JSAutoRequest ar(cx);
3772 JSString* propertyKey = ::JS_InternString(cx, start);
3773 if (!propertyKey)
3774 return NS_ERROR_OUT_OF_MEMORY;
3776 // Store this property in the class policy
3777 PropertyPolicy* ppolicy =
3778 static_cast<PropertyPolicy*>
3779 (PL_DHashTableOperate(cpolicy->mPolicy, propertyKey,
3780 PL_DHASH_ADD));
3781 if (!ppolicy)
3782 break;
3784 if (end) // The pref specifies an access mode
3786 start = end + 1;
3787 if (PL_strcasecmp(start, "set") == 0)
3788 ppolicy->mSet = secLevel;
3789 else
3790 ppolicy->mGet = secLevel;
3792 else
3794 if (ppolicy->mGet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3795 ppolicy->mGet = secLevel;
3796 if (ppolicy->mSet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3797 ppolicy->mSet = secLevel;
3801 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3802 if (currentPref < prefCount) // Loop exited early because of out-of-memory error
3803 return NS_ERROR_OUT_OF_MEMORY;
3804 return NS_OK;
3808 // XXXbz We should really just get a prefbranch to handle this...
3809 nsresult
3810 nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase,
3811 nsCString& grantedPref,
3812 nsCString& deniedPref,
3813 nsCString& subjectNamePref)
3815 char* lastDot = PL_strrchr(prefBase, '.');
3816 if (!lastDot) return NS_ERROR_FAILURE;
3817 PRInt32 prefLen = lastDot - prefBase + 1;
3819 grantedPref.Assign(prefBase, prefLen);
3820 deniedPref.Assign(prefBase, prefLen);
3821 subjectNamePref.Assign(prefBase, prefLen);
3823 #define GRANTED "granted"
3824 #define DENIED "denied"
3825 #define SUBJECTNAME "subjectName"
3827 grantedPref.AppendLiteral(GRANTED);
3828 if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) {
3829 return NS_ERROR_OUT_OF_MEMORY;
3832 deniedPref.AppendLiteral(DENIED);
3833 if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) {
3834 return NS_ERROR_OUT_OF_MEMORY;
3837 subjectNamePref.AppendLiteral(SUBJECTNAME);
3838 if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) {
3839 return NS_ERROR_OUT_OF_MEMORY;
3842 #undef SUBJECTNAME
3843 #undef DENIED
3844 #undef GRANTED
3846 return NS_OK;
3849 nsresult
3850 nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefNames)
3852 /* This is the principal preference syntax:
3853 * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
3854 * For example:
3855 * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
3856 * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
3857 * user_pref("capability.principal.certificate.p1.denied","Capability3");
3860 /* codebaseTrusted means a codebase principal that can enable capabilities even if
3861 * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
3862 * URLs such as HTTPS URLs.
3865 static const char idSuffix[] = ".id";
3866 for (PRUint32 c = 0; c < aPrefCount; c++)
3868 PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) -
3869 (NS_ARRAY_LENGTH(idSuffix) - 1);
3870 if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0)
3871 continue;
3873 nsXPIDLCString id;
3874 if (NS_FAILED(mPrefBranch->GetCharPref(aPrefNames[c], getter_Copies(id))))
3875 return NS_ERROR_FAILURE;
3877 nsCAutoString grantedPrefName;
3878 nsCAutoString deniedPrefName;
3879 nsCAutoString subjectNamePrefName;
3880 nsresult rv = GetPrincipalPrefNames(aPrefNames[c],
3881 grantedPrefName,
3882 deniedPrefName,
3883 subjectNamePrefName);
3884 if (rv == NS_ERROR_OUT_OF_MEMORY)
3885 return rv;
3886 if (NS_FAILED(rv))
3887 continue;
3889 nsXPIDLCString grantedList;
3890 mPrefBranch->GetCharPref(grantedPrefName.get(),
3891 getter_Copies(grantedList));
3892 nsXPIDLCString deniedList;
3893 mPrefBranch->GetCharPref(deniedPrefName.get(),
3894 getter_Copies(deniedList));
3895 nsXPIDLCString subjectName;
3896 mPrefBranch->GetCharPref(subjectNamePrefName.get(),
3897 getter_Copies(subjectName));
3899 //-- Delete prefs if their value is the empty string
3900 if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty()))
3902 mPrefBranch->ClearUserPref(aPrefNames[c]);
3903 mPrefBranch->ClearUserPref(grantedPrefName.get());
3904 mPrefBranch->ClearUserPref(deniedPrefName.get());
3905 mPrefBranch->ClearUserPref(subjectNamePrefName.get());
3906 continue;
3909 //-- Create a principal based on the prefs
3910 static const char certificateName[] = "capability.principal.certificate";
3911 static const char codebaseName[] = "capability.principal.codebase";
3912 static const char codebaseTrustedName[] = "capability.principal.codebaseTrusted";
3914 PRBool isCert = PR_FALSE;
3915 PRBool isTrusted = PR_FALSE;
3917 if (PL_strncmp(aPrefNames[c], certificateName,
3918 sizeof(certificateName) - 1) == 0)
3920 isCert = PR_TRUE;
3922 else if (PL_strncmp(aPrefNames[c], codebaseName,
3923 sizeof(codebaseName) - 1) == 0)
3925 isTrusted = (PL_strncmp(aPrefNames[c], codebaseTrustedName,
3926 sizeof(codebaseTrustedName) - 1) == 0);
3928 else
3930 NS_ERROR("Not a codebase or a certificate?!");
3933 nsRefPtr<nsPrincipal> newPrincipal = new nsPrincipal();
3934 if (!newPrincipal)
3935 return NS_ERROR_OUT_OF_MEMORY;
3937 rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
3938 EmptyCString(),
3939 grantedList, deniedList, nsnull,
3940 isCert, isTrusted);
3941 if (NS_SUCCEEDED(rv))
3942 mPrincipals.Put(newPrincipal, newPrincipal);
3944 return NS_OK;
3947 const char nsScriptSecurityManager::sJSEnabledPrefName[] =
3948 "javascript.enabled";
3949 const char nsScriptSecurityManager::sFileOriginPolicyPrefName[] =
3950 "security.fileuri.strict_origin_policy";
3951 #ifdef XPC_IDISPATCH_SUPPORT
3952 const char nsScriptSecurityManager::sXPCDefaultGrantAllName[] =
3953 "security.classID.allowByDefault";
3954 #endif
3956 inline void
3957 nsScriptSecurityManager::ScriptSecurityPrefChanged()
3959 // JavaScript defaults to enabled in failure cases.
3960 mIsJavaScriptEnabled = PR_TRUE;
3962 sStrictFileOriginPolicy = PR_TRUE;
3964 #ifdef XPC_IDISPATCH_SUPPORT
3965 // Granting XPC Priveleges defaults to disabled in failure cases.
3966 mXPCDefaultGrantAll = PR_FALSE;
3967 #endif
3969 nsresult rv;
3970 if (!mPrefBranch) {
3971 rv = InitPrefs();
3972 if (NS_FAILED(rv))
3973 return;
3976 PRBool temp;
3977 rv = mPrefBranch->GetBoolPref(sJSEnabledPrefName, &temp);
3978 if (NS_SUCCEEDED(rv))
3979 mIsJavaScriptEnabled = temp;
3981 rv = mPrefBranch->GetBoolPref(sFileOriginPolicyPrefName, &temp);
3982 if (NS_SUCCEEDED(rv))
3983 sStrictFileOriginPolicy = NS_SUCCEEDED(rv) && temp;
3985 #ifdef XPC_IDISPATCH_SUPPORT
3986 rv = mPrefBranch->GetBoolPref(sXPCDefaultGrantAllName, &temp);
3987 if (NS_SUCCEEDED(rv))
3988 mXPCDefaultGrantAll = temp;
3989 #endif
3992 nsresult
3993 nsScriptSecurityManager::InitPrefs()
3995 nsresult rv;
3996 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
3997 NS_ENSURE_SUCCESS(rv, rv);
3998 rv = prefService->GetBranch(nsnull, getter_AddRefs(mPrefBranch));
3999 NS_ENSURE_SUCCESS(rv, rv);
4000 nsCOMPtr<nsIPrefBranch2> prefBranchInternal(do_QueryInterface(mPrefBranch, &rv));
4001 NS_ENSURE_SUCCESS(rv, rv);
4003 // Set the initial value of the "javascript.enabled" prefs
4004 ScriptSecurityPrefChanged();
4005 // set observer callbacks in case the value of the prefs change
4006 prefBranchInternal->AddObserver(sJSEnabledPrefName, this, PR_FALSE);
4007 prefBranchInternal->AddObserver(sFileOriginPolicyPrefName, this, PR_FALSE);
4008 #ifdef XPC_IDISPATCH_SUPPORT
4009 prefBranchInternal->AddObserver(sXPCDefaultGrantAllName, this, PR_FALSE);
4010 #endif
4011 PRUint32 prefCount;
4012 char** prefNames;
4014 // Set a callback for policy pref changes
4015 prefBranchInternal->AddObserver(sPolicyPrefix, this, PR_FALSE);
4017 //-- Initialize the principals database from prefs
4018 rv = mPrefBranch->GetChildList(sPrincipalPrefix, &prefCount, &prefNames);
4019 if (NS_SUCCEEDED(rv) && prefCount > 0)
4021 rv = InitPrincipals(prefCount, (const char**)prefNames);
4022 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
4023 NS_ENSURE_SUCCESS(rv, rv);
4025 //-- Set a callback for principal changes
4026 prefBranchInternal->AddObserver(sPrincipalPrefix, this, PR_FALSE);
4028 return NS_OK;
4031 ///////////////////////////////////////////////////////////////////////////////
4032 // The following code prints the contents of the policy DB to the console.
4033 #ifdef DEBUG_CAPS_HACKER
4035 //typedef PLDHashOperator
4036 //(* PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
4037 // PRUint32 number, void *arg);
4038 static PLDHashOperator
4039 PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
4040 PRUint32 number, void *arg)
4042 PropertyPolicy* pp = (PropertyPolicy*)entry;
4043 nsCAutoString prop(" ");
4044 JSContext* cx = (JSContext*)arg;
4045 prop.AppendInt((PRUint32)pp->key);
4046 prop += ' ';
4047 prop.AppendWithConversion((PRUnichar*)JS_GetStringChars(pp->key));
4048 prop += ": Get=";
4049 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet))
4050 prop.AppendInt(pp->mGet.level);
4051 else
4052 prop += pp->mGet.capability;
4054 prop += " Set=";
4055 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mSet))
4056 prop.AppendInt(pp->mSet.level);
4057 else
4058 prop += pp->mSet.capability;
4060 printf("%s.\n", prop.get());
4061 return PL_DHASH_NEXT;
4064 static PLDHashOperator
4065 PrintClassPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
4066 PRUint32 number, void *arg)
4068 ClassPolicy* cp = (ClassPolicy*)entry;
4069 printf(" %s\n", cp->key);
4071 PL_DHashTableEnumerate(cp->mPolicy, PrintPropertyPolicy, arg);
4072 return PL_DHASH_NEXT;
4075 // typedef PRBool
4076 // (* nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
4077 static PRBool
4078 PrintDomainPolicy(nsHashKey *aKey, void *aData, void* aClosure)
4080 DomainEntry* de = (DomainEntry*)aData;
4081 printf("----------------------------\n");
4082 printf("Domain: %s Policy Name: %s.\n", de->mOrigin.get(),
4083 de->mPolicyName_DEBUG.get());
4084 PL_DHashTableEnumerate(de->mDomainPolicy, PrintClassPolicy, aClosure);
4085 return PR_TRUE;
4088 static PRBool
4089 PrintCapability(nsHashKey *aKey, void *aData, void* aClosure)
4091 char* cap = (char*)aData;
4092 printf(" %s.\n", cap);
4093 return PR_TRUE;
4096 void
4097 nsScriptSecurityManager::PrintPolicyDB()
4099 printf("############## Security Policies ###############\n");
4100 if(mOriginToPolicyMap)
4102 JSContext* cx = GetCurrentJSContext();
4103 if (!cx)
4104 cx = GetSafeJSContext();
4105 printf("----------------------------\n");
4106 printf("Domain: Default.\n");
4107 PL_DHashTableEnumerate(mDefaultPolicy, PrintClassPolicy, (void*)cx);
4108 mOriginToPolicyMap->Enumerate(PrintDomainPolicy, (void*)cx);
4110 printf("############ End Security Policies #############\n\n");
4111 printf("############## Capabilities ###############\n");
4112 mCapabilities->Enumerate(PrintCapability);
4113 printf("############## End Capabilities ###############\n");
4115 #endif