Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / caps / src / nsScriptSecurityManager.cpp
blobb83b23439b0a6af6560943734b73deb3d9b81da0
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 "nsScriptSecurityManager.h"
44 #include "nsIServiceManager.h"
45 #include "nsIScriptObjectPrincipal.h"
46 #include "nsIScriptContext.h"
47 #include "nsIURL.h"
48 #include "nsINestedURI.h"
49 #include "nspr.h"
50 #include "nsJSPrincipals.h"
51 #include "nsSystemPrincipal.h"
52 #include "nsPrincipal.h"
53 #include "nsNullPrincipal.h"
54 #include "nsXPIDLString.h"
55 #include "nsCRT.h"
56 #include "nsCRTGlue.h"
57 #include "nsIJSContextStack.h"
58 #include "nsDOMError.h"
59 #include "nsDOMCID.h"
60 #include "jsdbgapi.h"
61 #include "jsarena.h"
62 #include "jsfun.h"
63 #include "jsobj.h"
64 #include "nsIXPConnect.h"
65 #include "nsIXPCSecurityManager.h"
66 #include "nsTextFormatter.h"
67 #include "nsIStringBundle.h"
68 #include "nsNetUtil.h"
69 #include "nsIProperties.h"
70 #include "nsDirectoryServiceDefs.h"
71 #include "nsIFile.h"
72 #include "nsIFileURL.h"
73 #include "nsIZipReader.h"
74 #include "nsIJAR.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"
97 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
99 nsIIOService *nsScriptSecurityManager::sIOService = nsnull;
100 nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
101 nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
102 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
103 JSRuntime *nsScriptSecurityManager::sRuntime = 0;
104 PRBool nsScriptSecurityManager::sStrictFileOriginPolicy = PR_TRUE;
106 // Info we need about the JSClasses used by XPConnects wrapped
107 // natives, to avoid having to QI to nsIXPConnectWrappedNative all the
108 // time when doing security checks.
109 static const JSClass *sXPCWrappedNativeJSClass;
110 static JSGetObjectOps sXPCWrappedNativeGetObjOps1;
111 static JSGetObjectOps sXPCWrappedNativeGetObjOps2;
114 ///////////////////////////
115 // Convenience Functions //
116 ///////////////////////////
117 // Result of this function should not be freed.
118 static inline const PRUnichar *
119 JSValIDToString(JSContext *cx, const jsval idval)
121 JSAutoRequest ar(cx);
122 JSString *str = JS_ValueToString(cx, idval);
123 if(!str)
124 return nsnull;
125 return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
128 static
129 nsresult
130 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
131 nsACString& aOrigin)
133 aOrigin.Truncate();
135 nsCOMPtr<nsIURI> uri;
136 aPrincipal->GetDomain(getter_AddRefs(uri));
137 if (!uri) {
138 aPrincipal->GetURI(getter_AddRefs(uri));
140 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
142 uri = NS_GetInnermostURI(uri);
143 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
145 nsCAutoString hostPort;
147 nsresult rv = uri->GetHostPort(hostPort);
148 if (NS_SUCCEEDED(rv)) {
149 nsCAutoString scheme;
150 rv = uri->GetScheme(scheme);
151 NS_ENSURE_SUCCESS(rv, rv);
152 aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
154 else {
155 // Some URIs (e.g., nsSimpleURI) don't support host. Just
156 // get the full spec.
157 rv = uri->GetSpec(aOrigin);
158 NS_ENSURE_SUCCESS(rv, rv);
161 return NS_OK;
164 // Inline copy of JS_GetPrivate() for better inlining and optimization
165 // possibilities. Also doesn't take a cx argument as it's not
166 // needed. We access the private data only on objects whose private
167 // data is not expected to change during the lifetime of the object,
168 // so thus we won't worry about locking and holding on to slot values
169 // etc while referencing private data.
170 inline void *
171 caps_GetJSPrivate(JSObject *obj)
173 jsval v;
175 JS_ASSERT(STOBJ_GET_CLASS(obj)->flags & JSCLASS_HAS_PRIVATE);
176 v = obj->fslots[JSSLOT_PRIVATE];
177 if (!JSVAL_IS_INT(v))
178 return NULL;
179 return JSVAL_TO_PRIVATE(v);
182 static nsIScriptContext *
183 GetScriptContext(JSContext *cx)
185 return GetScriptContextFromJSContext(cx);
188 inline void SetPendingException(JSContext *cx, const char *aMsg)
190 JSAutoRequest ar(cx);
191 JS_ReportError(cx, "%s", aMsg);
194 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
196 JSAutoRequest ar(cx);
197 JS_ReportError(cx, "%hs", aMsg);
200 // DomainPolicy members
201 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
202 PRUint32 DomainPolicy::sObjects=0;
203 void DomainPolicy::_printPopulationInfo()
205 printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
206 sGeneration, sObjects);
208 #endif
209 PRUint32 DomainPolicy::sGeneration = 0;
211 // Helper class to get stuff from the ClassInfo and not waste extra time with
212 // virtual method calls for things it has already gotten
213 class ClassInfoData
215 public:
216 ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
217 : mClassInfo(aClassInfo),
218 mName(const_cast<char *>(aName)),
219 mDidGetFlags(PR_FALSE),
220 mMustFreeName(PR_FALSE)
224 ~ClassInfoData()
226 if (mMustFreeName)
227 nsMemory::Free(mName);
230 PRUint32 GetFlags()
232 if (!mDidGetFlags) {
233 if (mClassInfo) {
234 nsresult rv = mClassInfo->GetFlags(&mFlags);
235 if (NS_FAILED(rv)) {
236 mFlags = 0;
238 } else {
239 mFlags = 0;
242 mDidGetFlags = PR_TRUE;
245 return mFlags;
248 PRBool IsDOMClass()
250 return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
253 PRBool IsContentNode()
255 return !!(GetFlags() & nsIClassInfo::CONTENT_NODE);
258 const char* GetName()
260 if (!mName) {
261 if (mClassInfo) {
262 mClassInfo->GetClassDescription(&mName);
265 if (mName) {
266 mMustFreeName = PR_TRUE;
267 } else {
268 mName = const_cast<char *>("UnnamedClass");
272 return mName;
275 private:
276 nsIClassInfo *mClassInfo; // WEAK
277 PRUint32 mFlags;
278 char *mName;
279 PRPackedBool mDidGetFlags;
280 PRPackedBool mMustFreeName;
283 class AutoCxPusher {
284 public:
285 AutoCxPusher(nsIJSContextStack *aStack, JSContext *cx)
286 : mStack(aStack), mContext(cx)
288 if (NS_FAILED(mStack->Push(mContext))) {
289 mStack = nsnull;
293 ~AutoCxPusher()
295 if (mStack) {
296 mStack->Pop(nsnull);
300 private:
301 nsCOMPtr<nsIJSContextStack> mStack;
302 JSContext *mContext;
305 JSContext *
306 nsScriptSecurityManager::GetCurrentJSContext()
308 // Get JSContext from stack.
309 JSContext *cx;
310 if (NS_FAILED(sJSContextStack->Peek(&cx)))
311 return nsnull;
312 return cx;
315 JSContext *
316 nsScriptSecurityManager::GetSafeJSContext()
318 // Get JSContext from stack.
319 JSContext *cx;
320 if (NS_FAILED(sJSContextStack->GetSafeJSContext(&cx)))
321 return nsnull;
322 return cx;
325 /* static */
326 PRBool
327 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
328 nsIURI* aTargetURI)
330 return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
333 // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
334 // is consistent with NS_SecurityCompareURIs. See nsNetUtil.h.
335 PRUint32
336 nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
338 return NS_SecurityHashURI(aURI);
341 NS_IMETHODIMP
342 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
343 nsIPrincipal** aPrincipal)
345 NS_PRECONDITION(aChannel, "Must have channel!");
346 nsCOMPtr<nsISupports> owner;
347 aChannel->GetOwner(getter_AddRefs(owner));
348 if (owner) {
349 CallQueryInterface(owner, aPrincipal);
350 if (*aPrincipal) {
351 return NS_OK;
355 // OK, get the principal from the URI. Make sure this does the same thing
356 // as nsDocument::Reset and nsXULDocument::StartDocumentLoad.
357 nsCOMPtr<nsIURI> uri;
358 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
359 NS_ENSURE_SUCCESS(rv, rv);
361 return GetCodebasePrincipal(uri, aPrincipal);
364 NS_IMETHODIMP
365 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
366 PRBool* aIsSystem)
368 *aIsSystem = (aPrincipal == mSystemPrincipal);
369 return NS_OK;
372 NS_IMETHODIMP_(nsIPrincipal *)
373 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
375 NS_ASSERTION(cx == GetCurrentJSContext(),
376 "Uh, cx is not the current JS context!");
378 nsresult rv = NS_ERROR_FAILURE;
379 nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
380 if (NS_FAILED(rv))
381 return nsnull;
383 return principal;
386 NS_IMETHODIMP_(nsIPrincipal *)
387 nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
389 NS_ASSERTION(cx == GetCurrentJSContext(),
390 "Uh, cx is not the current JS context!");
392 nsresult rv = NS_ERROR_FAILURE;
393 nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
394 if (NS_FAILED(rv))
395 return nsnull;
397 return principal;
400 ////////////////////
401 // Policy Storage //
402 ////////////////////
404 // Table of security levels
405 static PRBool
406 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
408 NS_Free(aData);
409 return PR_TRUE;
412 //-- Per-Domain Policy - applies to one or more protocols or hosts
413 struct DomainEntry
415 DomainEntry(const char* aOrigin,
416 DomainPolicy* aDomainPolicy) : mOrigin(aOrigin),
417 mDomainPolicy(aDomainPolicy),
418 mNext(nsnull)
420 mDomainPolicy->Hold();
423 ~DomainEntry()
425 mDomainPolicy->Drop();
428 PRBool Matches(const char *anOrigin)
430 int len = strlen(anOrigin);
431 int thisLen = mOrigin.Length();
432 if (len < thisLen)
433 return PR_FALSE;
434 if (mOrigin.RFindChar(':', thisLen-1, 1) != -1)
435 //-- Policy applies to all URLs of this scheme, compare scheme only
436 return mOrigin.EqualsIgnoreCase(anOrigin, thisLen);
438 //-- Policy applies to a particular host; compare domains
439 if (!mOrigin.Equals(anOrigin + (len - thisLen)))
440 return PR_FALSE;
441 if (len == thisLen)
442 return PR_TRUE;
443 char charBefore = anOrigin[len-thisLen-1];
444 return (charBefore == '.' || charBefore == ':' || charBefore == '/');
447 nsCString mOrigin;
448 DomainPolicy* mDomainPolicy;
449 DomainEntry* mNext;
450 #if defined(DEBUG) || defined(DEBUG_CAPS_HACKER)
451 nsCString mPolicyName_DEBUG;
452 #endif
455 static PRBool
456 DeleteDomainEntry(nsHashKey *aKey, void *aData, void* closure)
458 DomainEntry *entry = (DomainEntry*) aData;
461 DomainEntry *next = entry->mNext;
462 delete entry;
463 entry = next;
464 } while (entry);
465 return PR_TRUE;
468 /////////////////////////////
469 // nsScriptSecurityManager //
470 /////////////////////////////
472 ////////////////////////////////////
473 // Methods implementing ISupports //
474 ////////////////////////////////////
475 NS_IMPL_ISUPPORTS5(nsScriptSecurityManager,
476 nsIScriptSecurityManager,
477 nsIXPCSecurityManager,
478 nsIPrefSecurityCheck,
479 nsIChannelEventSink,
480 nsIObserver)
482 ///////////////////////////////////////////////////
483 // Methods implementing nsIScriptSecurityManager //
484 ///////////////////////////////////////////////////
486 ///////////////// Security Checks /////////////////
487 JSBool
488 nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
489 jsval id, JSAccessMode mode,
490 jsval *vp)
492 // Get the security manager
493 nsScriptSecurityManager *ssm =
494 nsScriptSecurityManager::GetScriptSecurityManager();
496 NS_ASSERTION(ssm, "Failed to get security manager service");
497 if (!ssm)
498 return JS_FALSE;
500 // Get the object being accessed. We protect these cases:
501 // 1. The Function.prototype.caller property's value, which might lead
502 // an attacker up a call-stack to a function or another object from
503 // a different trust domain.
504 // 2. A user-defined getter or setter function accessible on another
505 // trust domain's window or document object.
506 // *vp can be a primitive, in that case, we use obj as the target
507 // object.
508 JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
510 // Do the same-origin check -- this sets a JS exception if the check fails.
511 // Pass the parent object's class name, as we have no class-info for it.
512 nsresult rv =
513 ssm->CheckPropertyAccess(cx, target, STOBJ_GET_CLASS(obj)->name, id,
514 (mode & JSACC_WRITE) ?
515 (PRInt32)nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
516 (PRInt32)nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
518 if (NS_FAILED(rv))
519 return JS_FALSE; // Security check failed (XXX was an error reported?)
521 return JS_TRUE;
524 NS_IMETHODIMP
525 nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
526 JSObject* aJSObject,
527 const char* aClassName,
528 jsval aProperty,
529 PRUint32 aAction)
531 return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
532 nsnull, nsnull, nsnull,
533 aClassName, aProperty, nsnull);
536 NS_IMETHODIMP
537 nsScriptSecurityManager::CheckConnect(JSContext* cx,
538 nsIURI* aTargetURI,
539 const char* aClassName,
540 const char* aPropertyName)
542 // Get a context if necessary
543 if (!cx)
545 cx = GetCurrentJSContext();
546 if (!cx)
547 return NS_OK; // No JS context, so allow the load
550 nsresult rv = CheckLoadURIFromScript(cx, aTargetURI);
551 if (NS_FAILED(rv)) return rv;
553 JSAutoRequest ar(cx);
555 JSString* propertyName = ::JS_InternString(cx, aPropertyName);
556 if (!propertyName)
557 return NS_ERROR_OUT_OF_MEMORY;
559 return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull,
560 cx, nsnull, nsnull, aTargetURI,
561 nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull);
564 NS_IMETHODIMP
565 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
566 nsIURI* aTargetURI)
568 nsresult rv;
570 // Get a context if necessary
571 if (!cx)
573 cx = GetCurrentJSContext();
574 if (!cx)
575 return NS_OK; // No JS context, so allow access
578 // Get a principal from the context
579 nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
580 if (NS_FAILED(rv))
581 return rv;
583 if (!sourcePrincipal)
585 NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
586 return NS_OK;
589 if (sourcePrincipal == mSystemPrincipal)
591 // This is a system (chrome) script, so allow access
592 return NS_OK;
595 // Get the original URI from the source principal.
596 // This has the effect of ignoring any change to document.domain
597 // which must be done to avoid DNS spoofing (bug 154930)
598 nsCOMPtr<nsIURI> sourceURI;
599 sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
600 if (!sourceURI) {
601 sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
602 NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
605 // Compare origins
606 if (!SecurityCompareURIs(sourceURI, aTargetURI))
608 ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
609 return NS_ERROR_DOM_BAD_URI;
611 return NS_OK;
614 NS_IMETHODIMP
615 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
616 nsIURI* aTargetURI,
617 PRBool reportError)
619 if (!SecurityCompareURIs(aSourceURI, aTargetURI))
621 if (reportError) {
622 ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"),
623 aSourceURI, aTargetURI);
625 return NS_ERROR_DOM_BAD_URI;
627 return NS_OK;
630 nsresult
631 nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
632 nsAXPCNativeCallContext* aCallContext,
633 JSContext* cx, JSObject* aJSObject,
634 nsISupports* aObj, nsIURI* aTargetURI,
635 nsIClassInfo* aClassInfo,
636 const char* aClassName, jsval aProperty,
637 void** aCachedClassPolicy)
639 nsresult rv;
640 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
641 if (NS_FAILED(rv))
642 return rv;
644 if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
645 // We have native code or the system principal: just allow access
646 return NS_OK;
648 nsCOMPtr<nsIPrincipal> objectPrincipal;
650 // Hold the class info data here so we don't have to go back to virtual
651 // methods all the time
652 ClassInfoData classInfoData(aClassInfo, aClassName);
653 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
654 nsCAutoString propertyName;
655 propertyName.AssignWithConversion((PRUnichar*)JSValIDToString(cx, aProperty));
656 printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(),
657 propertyName.get(), aAction);
658 #endif
660 //-- Look up the security policy for this class and subject domain
661 SecurityLevel securityLevel;
662 rv = LookupPolicy(subjectPrincipal, classInfoData, aProperty, aAction,
663 (ClassPolicy**)aCachedClassPolicy, &securityLevel);
664 if (NS_FAILED(rv))
665 return rv;
667 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
669 // No policy found for this property so use the default of last resort.
670 // If we were called from somewhere other than XPConnect
671 // (no XPC call context), assume this is a DOM class. Otherwise,
672 // ask the ClassInfo.
673 if (!aCallContext || classInfoData.IsDOMClass())
674 securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
675 else
676 securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
679 if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
680 // This flag means securityLevel is allAccess, noAccess, or sameOrigin
682 switch (securityLevel.level)
684 case SCRIPT_SECURITY_NO_ACCESS:
685 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
686 printf("noAccess ");
687 #endif
688 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
689 break;
691 case SCRIPT_SECURITY_ALL_ACCESS:
692 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
693 printf("allAccess ");
694 #endif
695 rv = NS_OK;
696 break;
698 case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS:
700 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
701 printf("sameOrigin ");
702 #endif
703 nsCOMPtr<nsIPrincipal> principalHolder;
704 if(aJSObject)
706 objectPrincipal = doGetObjectPrincipal(aJSObject);
707 if (!objectPrincipal)
708 rv = NS_ERROR_DOM_SECURITY_ERR;
710 else if(aTargetURI)
712 if (NS_FAILED(GetCodebasePrincipal(
713 aTargetURI, getter_AddRefs(objectPrincipal))))
714 return NS_ERROR_FAILURE;
716 else
718 NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
719 return NS_ERROR_FAILURE;
721 if(NS_SUCCEEDED(rv))
722 rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
723 aAction, aTargetURI != nsnull);
724 break;
726 default:
727 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
728 printf("ERROR ");
729 #endif
730 NS_ERROR("Bad Security Level Value");
731 return NS_ERROR_FAILURE;
734 else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
736 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
737 printf("Cap:%s ", securityLevel.capability);
738 #endif
739 PRBool capabilityEnabled = PR_FALSE;
740 rv = IsCapabilityEnabled(securityLevel.capability, &capabilityEnabled);
741 if (NS_FAILED(rv) || !capabilityEnabled)
742 rv = NS_ERROR_DOM_SECURITY_ERR;
743 else
744 rv = NS_OK;
747 if (NS_SUCCEEDED(rv) && classInfoData.IsContentNode())
749 // No access to anonymous content from the web! (bug 164086)
750 nsIContent *content = static_cast<nsIContent*>(aObj);
751 if (content->IsInNativeAnonymousSubtree()) {
752 rv = NS_ERROR_DOM_SECURITY_ERR;
756 if (NS_SUCCEEDED(rv))
758 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
759 printf(" GRANTED.\n");
760 #endif
761 return rv;
764 //--See if the object advertises a non-default level of access
765 // using nsISecurityCheckedComponent
766 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
767 do_QueryInterface(aObj);
769 nsXPIDLCString objectSecurityLevel;
770 if (checkedComponent)
772 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
773 nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
774 const nsIID* objIID;
775 rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
776 if (NS_SUCCEEDED(rv))
777 rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
778 if (NS_SUCCEEDED(rv))
779 rv = interfaceInfo->GetIIDShared(&objIID);
780 if (NS_SUCCEEDED(rv))
782 switch (aAction)
784 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
785 checkedComponent->CanGetProperty(objIID,
786 JSValIDToString(cx, aProperty),
787 getter_Copies(objectSecurityLevel));
788 break;
789 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
790 checkedComponent->CanSetProperty(objIID,
791 JSValIDToString(cx, aProperty),
792 getter_Copies(objectSecurityLevel));
793 break;
794 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
795 checkedComponent->CanCallMethod(objIID,
796 JSValIDToString(cx, aProperty),
797 getter_Copies(objectSecurityLevel));
801 rv = CheckXPCPermissions(aObj, objectSecurityLevel);
802 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
803 if(NS_SUCCEEDED(rv))
804 printf("CheckXPCPerms GRANTED.\n");
805 else
806 printf("CheckXPCPerms DENIED.\n");
807 #endif
809 if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
811 nsAutoString stringName;
812 switch(aAction)
814 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
815 stringName.AssignLiteral("GetPropertyDeniedOrigins");
816 break;
817 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
818 stringName.AssignLiteral("SetPropertyDeniedOrigins");
819 break;
820 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
821 stringName.AssignLiteral("CallMethodDeniedOrigins");
824 NS_ConvertUTF8toUTF16 className(classInfoData.GetName());
825 nsCAutoString subjectOrigin;
826 GetPrincipalDomainOrigin(subjectPrincipal, subjectOrigin);
827 NS_ConvertUTF8toUTF16 subjectOriginUnicode(subjectOrigin);
829 nsCAutoString objectOrigin;
830 if (objectPrincipal) {
831 GetPrincipalDomainOrigin(objectPrincipal, objectOrigin);
833 NS_ConvertUTF8toUTF16 objectOriginUnicode(objectOrigin);
835 nsXPIDLString errorMsg;
836 const PRUnichar *formatStrings[] =
838 subjectOriginUnicode.get(),
839 className.get(),
840 JSValIDToString(cx, aProperty),
841 objectOriginUnicode.get()
844 PRUint32 length = NS_ARRAY_LENGTH(formatStrings);
846 if (!objectPrincipal) {
847 stringName.AppendLiteral("OnlySubject");
848 --length;
851 // We need to keep our existing failure rv and not override it
852 // with a likely success code from the following string bundle
853 // call in order to throw the correct security exception later.
854 nsresult rv2 = sStrBundle->FormatStringFromName(stringName.get(),
855 formatStrings,
856 length,
857 getter_Copies(errorMsg));
858 if (NS_FAILED(rv2)) {
859 // Might just be missing the string... Do our best
860 errorMsg = stringName;
863 SetPendingException(cx, errorMsg.get());
866 return rv;
869 /* static */
870 nsresult
871 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
872 nsIPrincipal* aObject,
873 PRBool aIsCheckConnect)
876 ** Get origin of subject and object and compare.
878 if (aSubject == aObject)
879 return NS_OK;
881 // These booleans are only used when !aIsCheckConnect. Default
882 // them to false, and change if that turns out wrong.
883 PRBool subjectSetDomain = PR_FALSE;
884 PRBool objectSetDomain = PR_FALSE;
886 nsCOMPtr<nsIURI> subjectURI;
887 nsCOMPtr<nsIURI> objectURI;
889 if (aIsCheckConnect)
891 // Don't use domain for CheckConnect calls, since that's called for
892 // data-only load checks like XMLHTTPRequest (bug 290100).
893 aSubject->GetURI(getter_AddRefs(subjectURI));
894 aObject->GetURI(getter_AddRefs(objectURI));
896 else
898 aSubject->GetDomain(getter_AddRefs(subjectURI));
899 if (!subjectURI) {
900 aSubject->GetURI(getter_AddRefs(subjectURI));
901 } else {
902 subjectSetDomain = PR_TRUE;
905 aObject->GetDomain(getter_AddRefs(objectURI));
906 if (!objectURI) {
907 aObject->GetURI(getter_AddRefs(objectURI));
908 } else {
909 objectSetDomain = PR_TRUE;
913 if (SecurityCompareURIs(subjectURI, objectURI))
914 { // If either the subject or the object has changed its principal by
915 // explicitly setting document.domain then the other must also have
916 // done so in order to be considered the same origin. This prevents
917 // DNS spoofing based on document.domain (154930)
919 // But this restriction does not apply to CheckConnect calls, since
920 // that's called for data-only load checks like XMLHTTPRequest where
921 // we ignore domain (bug 290100).
922 if (aIsCheckConnect)
923 return NS_OK;
925 // If both or neither explicitly set their domain, allow the access
926 if (subjectSetDomain == objectSetDomain)
927 return NS_OK;
931 ** Access tests failed, so now report error.
933 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
936 // It's important that
938 // CheckSameOriginPrincipal(A, B, PR_FALSE) == NS_OK
940 // imply
942 // HashPrincipalByOrigin(A) == HashPrincipalByOrigin(B)
944 // if principals A and B could ever be used as keys in a hashtable.
945 // Violation of this invariant leads to spurious failures of hashtable
946 // lookups. See bug 454850.
948 /*static*/ PRUint32
949 nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
951 nsCOMPtr<nsIURI> uri;
952 aPrincipal->GetDomain(getter_AddRefs(uri));
953 if (!uri)
954 aPrincipal->GetURI(getter_AddRefs(uri));
955 return SecurityHashURI(uri);
958 nsresult
959 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
960 nsIPrincipal* aObject,
961 PRUint32 aAction,
962 PRBool aIsCheckConnect)
964 nsresult rv;
965 if (aIsCheckConnect) {
966 // Don't do equality compares, just do a same-origin compare,
967 // since the object principal isn't a real principal, just a
968 // GetCodebasePrincipal() on whatever URI we started with.
969 rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
970 } else {
971 PRBool subsumes;
972 rv = aSubject->Subsumes(aObject, &subsumes);
973 if (NS_SUCCEEDED(rv) && !subsumes) {
974 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
978 if (NS_SUCCEEDED(rv))
979 return NS_OK;
982 * Content can't ever touch chrome (we check for UniversalXPConnect later)
984 if (aObject == mSystemPrincipal)
985 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
988 * If we failed the origin tests it still might be the case that we
989 * are a signed script and have permissions to do this operation.
990 * Check for that here.
992 PRBool capabilityEnabled = PR_FALSE;
993 const char* cap = aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY ?
994 "UniversalBrowserWrite" : "UniversalBrowserRead";
995 rv = IsCapabilityEnabled(cap, &capabilityEnabled);
996 NS_ENSURE_SUCCESS(rv, rv);
997 if (capabilityEnabled)
998 return NS_OK;
1001 ** Access tests failed, so now report error.
1003 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1006 nsresult
1007 nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal,
1008 ClassInfoData& aClassData,
1009 jsval aProperty,
1010 PRUint32 aAction,
1011 ClassPolicy** aCachedClassPolicy,
1012 SecurityLevel* result)
1014 nsresult rv;
1015 result->level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
1017 DomainPolicy* dpolicy = nsnull;
1018 //-- Initialize policies if necessary
1019 if (mPolicyPrefsChanged)
1021 rv = InitPolicies();
1022 if (NS_FAILED(rv))
1023 return rv;
1025 else
1027 aPrincipal->GetSecurityPolicy((void**)&dpolicy);
1030 if (!dpolicy && mOriginToPolicyMap)
1032 //-- Look up the relevant domain policy, if any
1033 #ifdef DEBUG_CAPS_LookupPolicy
1034 printf("DomainLookup ");
1035 #endif
1037 nsCAutoString origin;
1038 rv = GetPrincipalDomainOrigin(aPrincipal, origin);
1039 NS_ENSURE_SUCCESS(rv, rv);
1041 char *start = origin.BeginWriting();
1042 const char *nextToLastDot = nsnull;
1043 const char *lastDot = nsnull;
1044 const char *colon = nsnull;
1045 char *p = start;
1047 //-- search domain (stop at the end of the string or at the 3rd slash)
1048 for (PRUint32 slashes=0; *p; p++)
1050 if (*p == '/' && ++slashes == 3)
1052 *p = '\0'; // truncate at 3rd slash
1053 break;
1055 if (*p == '.')
1057 nextToLastDot = lastDot;
1058 lastDot = p;
1060 else if (!colon && *p == ':')
1061 colon = p;
1064 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : start);
1065 DomainEntry *de = (DomainEntry*) mOriginToPolicyMap->Get(&key);
1066 if (!de)
1068 nsCAutoString scheme(start, colon-start+1);
1069 nsCStringKey schemeKey(scheme);
1070 de = (DomainEntry*) mOriginToPolicyMap->Get(&schemeKey);
1073 while (de)
1075 if (de->Matches(start))
1077 dpolicy = de->mDomainPolicy;
1078 break;
1080 de = de->mNext;
1083 if (!dpolicy)
1084 dpolicy = mDefaultPolicy;
1086 aPrincipal->SetSecurityPolicy((void*)dpolicy);
1089 ClassPolicy* cpolicy = nsnull;
1091 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1093 // No per-domain policy for this principal (the more common case)
1094 // so look for a cached class policy from the object wrapper
1095 cpolicy = *aCachedClassPolicy;
1098 if (!cpolicy)
1099 { //-- No cached policy for this class, need to look it up
1100 #ifdef DEBUG_CAPS_LookupPolicy
1101 printf("ClassLookup ");
1102 #endif
1104 cpolicy = static_cast<ClassPolicy*>
1105 (PL_DHashTableOperate(dpolicy,
1106 aClassData.GetName(),
1107 PL_DHASH_LOOKUP));
1109 if (PL_DHASH_ENTRY_IS_FREE(cpolicy))
1110 cpolicy = NO_POLICY_FOR_CLASS;
1112 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1113 *aCachedClassPolicy = cpolicy;
1116 // We look for a PropertyPolicy in the following places:
1117 // 1) The ClassPolicy for our class we got from our DomainPolicy
1118 // 2) The mWildcardPolicy of our DomainPolicy
1119 // 3) The ClassPolicy for our class we got from mDefaultPolicy
1120 // 4) The mWildcardPolicy of our mDefaultPolicy
1121 PropertyPolicy* ppolicy = nsnull;
1122 if (cpolicy != NO_POLICY_FOR_CLASS)
1124 ppolicy = static_cast<PropertyPolicy*>
1125 (PL_DHashTableOperate(cpolicy->mPolicy,
1126 (void*)aProperty,
1127 PL_DHASH_LOOKUP));
1130 // If there is no class policy for this property, and we have a wildcard
1131 // policy, try that.
1132 if (dpolicy->mWildcardPolicy &&
1133 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1135 ppolicy =
1136 static_cast<PropertyPolicy*>
1137 (PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy,
1138 (void*)aProperty,
1139 PL_DHASH_LOOKUP));
1142 // If dpolicy is not the defauly policy and there's no class or wildcard
1143 // policy for this property, check the default policy for this class and
1144 // the default wildcard policy
1145 if (dpolicy != mDefaultPolicy &&
1146 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1148 cpolicy = static_cast<ClassPolicy*>
1149 (PL_DHashTableOperate(mDefaultPolicy,
1150 aClassData.GetName(),
1151 PL_DHASH_LOOKUP));
1153 if (PL_DHASH_ENTRY_IS_BUSY(cpolicy))
1155 ppolicy =
1156 static_cast<PropertyPolicy*>
1157 (PL_DHashTableOperate(cpolicy->mPolicy,
1158 (void*)aProperty,
1159 PL_DHASH_LOOKUP));
1162 if ((!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)) &&
1163 mDefaultPolicy->mWildcardPolicy)
1165 ppolicy =
1166 static_cast<PropertyPolicy*>
1167 (PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy,
1168 (void*)aProperty,
1169 PL_DHASH_LOOKUP));
1173 if (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy))
1174 return NS_OK;
1176 // Get the correct security level from the property policy
1177 if (aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY)
1178 *result = ppolicy->mSet;
1179 else
1180 *result = ppolicy->mGet;
1182 return NS_OK;
1186 NS_IMETHODIMP
1187 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
1189 // Get principal of currently executing script.
1190 nsresult rv;
1191 nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
1192 if (NS_FAILED(rv))
1193 return rv;
1195 // Native code can load all URIs.
1196 if (!principal)
1197 return NS_OK;
1199 rv = CheckLoadURIWithPrincipal(principal, aURI,
1200 nsIScriptSecurityManager::STANDARD);
1201 if (NS_SUCCEEDED(rv)) {
1202 // OK to load
1203 return NS_OK;
1206 // See if we're attempting to load a file: URI. If so, let a
1207 // UniversalFileRead capability trump the above check.
1208 PRBool isFile = PR_FALSE;
1209 PRBool isRes = PR_FALSE;
1210 if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
1211 NS_FAILED(aURI->SchemeIs("resource", &isRes)))
1212 return NS_ERROR_FAILURE;
1213 if (isFile || isRes)
1215 PRBool enabled;
1216 if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled)))
1217 return NS_ERROR_FAILURE;
1218 if (enabled)
1219 return NS_OK;
1222 // Report error.
1223 nsCAutoString spec;
1224 if (NS_FAILED(aURI->GetAsciiSpec(spec)))
1225 return NS_ERROR_FAILURE;
1226 JS_ReportError(cx, "Access to '%s' from script denied", spec.get());
1227 return NS_ERROR_DOM_BAD_URI;
1230 NS_IMETHODIMP
1231 nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1232 PRUint32 aFlags)
1234 // FIXME: bug 327244 -- this function should really die... Really truly.
1235 NS_PRECONDITION(aSourceURI, "CheckLoadURI called with null source URI");
1236 NS_ENSURE_ARG_POINTER(aSourceURI);
1238 // Note: this is not _quite_ right if aSourceURI has
1239 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1240 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1241 // really needs to go away....
1242 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1243 nsresult rv = CreateCodebasePrincipal(aSourceURI,
1244 getter_AddRefs(sourcePrincipal));
1245 NS_ENSURE_SUCCESS(rv, rv);
1246 return CheckLoadURIWithPrincipal(sourcePrincipal, aTargetURI, aFlags);
1250 * Helper method to handle cases where a flag passed to
1251 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
1252 * nsIProtocolHandler flags set.
1253 * @return if success, access is allowed. Otherwise, deny access
1255 static nsresult
1256 DenyAccessIfURIHasFlags(nsIURI* aURI, PRUint32 aURIFlags)
1258 NS_PRECONDITION(aURI, "Must have URI!");
1260 PRBool uriHasFlags;
1261 nsresult rv =
1262 NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
1263 NS_ENSURE_SUCCESS(rv, rv);
1265 if (uriHasFlags) {
1266 return NS_ERROR_DOM_BAD_URI;
1269 return NS_OK;
1272 NS_IMETHODIMP
1273 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
1274 nsIURI *aTargetURI,
1275 PRUint32 aFlags)
1277 NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
1278 // If someone passes a flag that we don't understand, we should
1279 // fail, because they may need a security check that we don't
1280 // provide.
1281 NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
1282 nsIScriptSecurityManager::ALLOW_CHROME |
1283 nsIScriptSecurityManager::DISALLOW_SCRIPT |
1284 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL),
1285 NS_ERROR_UNEXPECTED);
1286 NS_ENSURE_ARG_POINTER(aPrincipal);
1288 if (aPrincipal == mSystemPrincipal) {
1289 // Allow access
1290 return NS_OK;
1293 nsCOMPtr<nsIURI> sourceURI;
1294 aPrincipal->GetURI(getter_AddRefs(sourceURI));
1295 if (!sourceURI) {
1296 NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
1297 "must have a URI!");
1298 return NS_ERROR_UNEXPECTED;
1301 // Automatic loads are not allowed from certain protocols.
1302 if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
1303 nsresult rv =
1304 DenyAccessIfURIHasFlags(sourceURI,
1305 nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
1306 NS_ENSURE_SUCCESS(rv, rv);
1309 // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
1310 // would do such inheriting. That would be URIs that do not have their own
1311 // security context.
1312 if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
1313 nsresult rv =
1314 DenyAccessIfURIHasFlags(aTargetURI,
1315 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
1316 NS_ENSURE_SUCCESS(rv, rv);
1319 // If either URI is a nested URI, get the base URI
1320 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
1321 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
1323 //-- get the target scheme
1324 nsCAutoString targetScheme;
1325 nsresult rv = targetBaseURI->GetScheme(targetScheme);
1326 if (NS_FAILED(rv)) return rv;
1328 //-- Some callers do not allow loading javascript:
1329 if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
1330 targetScheme.EqualsLiteral("javascript"))
1332 return NS_ERROR_DOM_BAD_URI;
1335 //-- get the source scheme
1336 nsCAutoString sourceScheme;
1337 rv = sourceBaseURI->GetScheme(sourceScheme);
1338 if (NS_FAILED(rv)) return rv;
1340 if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
1341 // A null principal can target its own URI.
1342 if (sourceURI == aTargetURI) {
1343 return NS_OK;
1346 else if (targetScheme.Equals(sourceScheme,
1347 nsCaseInsensitiveCStringComparator()))
1349 // every scheme can access another URI from the same scheme,
1350 // as long as they don't represent null principals.
1351 return NS_OK;
1354 NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
1356 // If the schemes don't match, the policy is specified by the protocol
1357 // flags on the target URI. Note that the order of policy checks here is
1358 // very important! We start from most restrictive and work our way down.
1359 // Note that since we're working with the innermost URI, we can just use
1360 // the methods that work on chains of nested URIs and they will only look
1361 // at the flags for our one URI.
1363 // Check for system target URI
1364 rv = DenyAccessIfURIHasFlags(targetBaseURI,
1365 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
1366 if (NS_FAILED(rv)) {
1367 // Deny access, since the origin principal is not system
1368 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1369 return rv;
1372 // Check for chrome target URI
1373 PRBool hasFlags;
1374 rv = NS_URIChainHasFlags(targetBaseURI,
1375 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1376 &hasFlags);
1377 NS_ENSURE_SUCCESS(rv, rv);
1378 if (hasFlags) {
1379 if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
1380 if (!targetScheme.EqualsLiteral("chrome")) {
1381 // for now don't change behavior for resource: or moz-icon:
1382 return NS_OK;
1385 // allow load only if chrome package is whitelisted
1386 nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
1387 NS_CHROMEREGISTRY_CONTRACTID));
1388 if (reg) {
1389 PRBool accessAllowed = PR_FALSE;
1390 reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
1391 if (accessAllowed) {
1392 return NS_OK;
1397 // resource: and chrome: are equivalent, securitywise
1398 // That's bogus!! Fix this. But watch out for
1399 // the view-source stylesheet?
1400 PRBool sourceIsChrome;
1401 rv = NS_URIChainHasFlags(sourceBaseURI,
1402 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1403 &sourceIsChrome);
1404 NS_ENSURE_SUCCESS(rv, rv);
1405 if (sourceIsChrome) {
1406 return NS_OK;
1408 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1409 return NS_ERROR_DOM_BAD_URI;
1412 // Check for target URI pointing to a file
1413 rv = NS_URIChainHasFlags(targetBaseURI,
1414 nsIProtocolHandler::URI_IS_LOCAL_FILE,
1415 &hasFlags);
1416 NS_ENSURE_SUCCESS(rv, rv);
1417 if (hasFlags) {
1418 // resource: and chrome: are equivalent, securitywise
1419 // That's bogus!! Fix this. But watch out for
1420 // the view-source stylesheet?
1421 PRBool sourceIsChrome;
1422 rv = NS_URIChainHasFlags(sourceURI,
1423 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1424 &sourceIsChrome);
1425 NS_ENSURE_SUCCESS(rv, rv);
1426 if (sourceIsChrome) {
1427 return NS_OK;
1430 // Now check capability policies
1431 static const char loadURIPrefGroup[] = "checkloaduri";
1432 ClassInfoData nameData(nsnull, loadURIPrefGroup);
1434 SecurityLevel secLevel;
1435 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1436 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1437 nsnull, &secLevel);
1438 if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
1440 // OK for this site!
1441 return NS_OK;
1444 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1445 return NS_ERROR_DOM_BAD_URI;
1448 // OK, everyone is allowed to load this, since unflagged handlers are
1449 // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
1450 // need to warn. At some point we'll want to make this warning into an
1451 // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
1452 rv = NS_URIChainHasFlags(targetBaseURI,
1453 nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
1454 &hasFlags);
1455 NS_ENSURE_SUCCESS(rv, rv);
1456 if (!hasFlags) {
1457 nsXPIDLString message;
1458 NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
1459 const PRUnichar* formatStrings[] = { ucsTargetScheme.get() };
1460 rv = sStrBundle->
1461 FormatStringFromName(NS_LITERAL_STRING("ProtocolFlagError").get(),
1462 formatStrings,
1463 NS_ARRAY_LENGTH(formatStrings),
1464 getter_Copies(message));
1465 if (NS_SUCCEEDED(rv)) {
1466 nsCOMPtr<nsIConsoleService> console(
1467 do_GetService("@mozilla.org/consoleservice;1"));
1468 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1470 console->LogStringMessage(message.get());
1471 #ifdef DEBUG
1472 fprintf(stderr, "%s\n", NS_ConvertUTF16toUTF8(message).get());
1473 #endif
1477 return NS_OK;
1480 nsresult
1481 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
1482 nsIURI* aSource, nsIURI* aTarget)
1484 nsresult rv;
1485 NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
1487 // Get the source URL spec
1488 nsCAutoString sourceSpec;
1489 rv = aSource->GetAsciiSpec(sourceSpec);
1490 NS_ENSURE_SUCCESS(rv, rv);
1492 // Get the target URL spec
1493 nsCAutoString targetSpec;
1494 rv = aTarget->GetAsciiSpec(targetSpec);
1495 NS_ENSURE_SUCCESS(rv, rv);
1497 // Localize the error message
1498 nsXPIDLString message;
1499 NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
1500 NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
1501 const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
1502 rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
1503 formatStrings,
1504 NS_ARRAY_LENGTH(formatStrings),
1505 getter_Copies(message));
1506 NS_ENSURE_SUCCESS(rv, rv);
1508 // If a JS context was passed in, set a JS exception.
1509 // Otherwise, print the error message directly to the JS console
1510 // and to standard output
1511 if (cx)
1513 SetPendingException(cx, message.get());
1515 else // Print directly to the console
1517 nsCOMPtr<nsIConsoleService> console(
1518 do_GetService("@mozilla.org/consoleservice;1"));
1519 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1521 console->LogStringMessage(message.get());
1522 #ifdef DEBUG
1523 fprintf(stderr, "%s\n", NS_LossyConvertUTF16toASCII(message).get());
1524 #endif
1526 return NS_OK;
1529 NS_IMETHODIMP
1530 nsScriptSecurityManager::CheckLoadURIStr(const nsACString& aSourceURIStr,
1531 const nsACString& aTargetURIStr,
1532 PRUint32 aFlags)
1534 // FIXME: bug 327244 -- this function should really die... Really truly.
1535 nsCOMPtr<nsIURI> source;
1536 nsresult rv = NS_NewURI(getter_AddRefs(source), aSourceURIStr,
1537 nsnull, nsnull, sIOService);
1538 NS_ENSURE_SUCCESS(rv, rv);
1540 // Note: this is not _quite_ right if aSourceURI has
1541 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1542 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1543 // really needs to go away....
1544 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1545 rv = CreateCodebasePrincipal(source,
1546 getter_AddRefs(sourcePrincipal));
1547 NS_ENSURE_SUCCESS(rv, rv);
1549 return CheckLoadURIStrWithPrincipal(sourcePrincipal, aTargetURIStr,
1550 aFlags);
1553 NS_IMETHODIMP
1554 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
1555 const nsACString& aTargetURIStr,
1556 PRUint32 aFlags)
1558 nsresult rv;
1559 nsCOMPtr<nsIURI> target;
1560 rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
1561 nsnull, nsnull, sIOService);
1562 NS_ENSURE_SUCCESS(rv, rv);
1564 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1565 NS_ENSURE_SUCCESS(rv, rv);
1567 // Now start testing fixup -- since aTargetURIStr is a string, not
1568 // an nsIURI, we may well end up fixing it up before loading.
1569 // Note: This needs to stay in sync with the nsIURIFixup api.
1570 nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
1571 if (!fixup) {
1572 return rv;
1575 PRUint32 flags[] = {
1576 nsIURIFixup::FIXUP_FLAG_NONE,
1577 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
1578 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
1579 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
1580 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
1583 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(flags); ++i) {
1584 rv = fixup->CreateFixupURI(aTargetURIStr, flags[i],
1585 getter_AddRefs(target));
1586 NS_ENSURE_SUCCESS(rv, rv);
1588 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1589 NS_ENSURE_SUCCESS(rv, rv);
1592 return rv;
1595 NS_IMETHODIMP
1596 nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
1597 void *aTargetObj)
1599 // This check is called for event handlers
1600 nsresult rv;
1601 nsIPrincipal* subject =
1602 GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
1604 // If subject is null, get a principal from the function object's scope.
1605 if (NS_SUCCEEDED(rv) && !subject)
1607 #ifdef DEBUG
1609 JSFunction *fun =
1610 (JSFunction *)caps_GetJSPrivate((JSObject *)aFunObj);
1611 JSScript *script = JS_GetFunctionScript(aCx, fun);
1613 NS_ASSERTION(!script, "Null principal for non-native function!");
1615 #endif
1617 subject = doGetObjectPrincipal((JSObject*)aFunObj);
1620 if (!subject)
1621 return NS_ERROR_FAILURE;
1623 if (subject == mSystemPrincipal)
1624 // This is the system principal: just allow access
1625 return NS_OK;
1627 // Check if the principal the function was compiled under is
1628 // allowed to execute scripts.
1630 PRBool result;
1631 rv = CanExecuteScripts(aCx, subject, &result);
1632 if (NS_FAILED(rv))
1633 return rv;
1635 if (!result)
1636 return NS_ERROR_DOM_SECURITY_ERR;
1639 ** Get origin of subject and object and compare.
1641 JSObject* obj = (JSObject*)aTargetObj;
1642 nsIPrincipal* object = doGetObjectPrincipal(obj);
1644 if (!object)
1645 return NS_ERROR_FAILURE;
1647 PRBool subsumes;
1648 rv = subject->Subsumes(object, &subsumes);
1649 if (NS_SUCCEEDED(rv) && !subsumes) {
1650 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1652 return rv;
1655 NS_IMETHODIMP
1656 nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
1657 nsIPrincipal *aPrincipal,
1658 PRBool *result)
1660 *result = PR_FALSE;
1662 if (aPrincipal == mSystemPrincipal)
1664 // Even if JavaScript is disabled, we must still execute system scripts
1665 *result = PR_TRUE;
1666 return NS_OK;
1669 //-- See if the current window allows JS execution
1670 nsIScriptContext *scriptContext = GetScriptContext(cx);
1671 if (!scriptContext) return NS_ERROR_FAILURE;
1673 if (!scriptContext->GetScriptsEnabled()) {
1674 // No scripting on this context, folks
1675 *result = PR_FALSE;
1676 return NS_OK;
1679 nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
1681 if (!sgo) {
1682 return NS_ERROR_FAILURE;
1685 // window can be null here if we're running with a non-DOM window
1686 // as the script global (i.e. a XUL prototype document).
1687 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
1688 nsCOMPtr<nsIDocShell> docshell;
1689 nsresult rv;
1691 if (window) {
1692 docshell = window->GetDocShell();
1695 nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
1696 do_QueryInterface(docshell);
1698 if (globalObjTreeItem)
1700 nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
1701 nsCOMPtr<nsIDocShellTreeItem> parentItem;
1703 // Walk up the docshell tree to see if any containing docshell disallows scripts
1706 rv = docshell->GetAllowJavascript(result);
1707 if (NS_FAILED(rv)) return rv;
1708 if (!*result)
1709 return NS_OK; // Do not run scripts
1710 treeItem->GetParent(getter_AddRefs(parentItem));
1711 treeItem.swap(parentItem);
1712 docshell = do_QueryInterface(treeItem);
1713 #ifdef DEBUG
1714 if (treeItem && !docshell) {
1715 NS_ERROR("cannot get a docshell from a treeItem!");
1717 #endif // DEBUG
1718 } while (treeItem && docshell);
1721 // OK, the docshell doesn't have script execution explicitly disabled.
1722 // Check whether our URI is an "about:" URI that allows scripts. If it is,
1723 // we need to allow JS to run. In this case, don't apply the JS enabled
1724 // pref or policies. On failures, just press on and don't do this special
1725 // case.
1726 nsCOMPtr<nsIURI> principalURI;
1727 aPrincipal->GetURI(getter_AddRefs(principalURI));
1728 if (!principalURI) {
1729 // Broken principal of some sort. Disallow.
1730 *result = PR_FALSE;
1731 return NS_ERROR_UNEXPECTED;
1734 PRBool isAbout;
1735 rv = principalURI->SchemeIs("about", &isAbout);
1736 if (NS_SUCCEEDED(rv) && isAbout) {
1737 nsCOMPtr<nsIAboutModule> module;
1738 rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
1739 if (NS_SUCCEEDED(rv)) {
1740 PRUint32 flags;
1741 rv = module->GetURIFlags(principalURI, &flags);
1742 if (NS_SUCCEEDED(rv) &&
1743 (flags & nsIAboutModule::ALLOW_SCRIPT)) {
1744 *result = PR_TRUE;
1745 return NS_OK;
1750 //-- See if JS is disabled globally (via prefs)
1751 *result = mIsJavaScriptEnabled;
1752 if (mIsJavaScriptEnabled != mIsMailJavaScriptEnabled && globalObjTreeItem)
1754 nsCOMPtr<nsIDocShellTreeItem> rootItem;
1755 globalObjTreeItem->GetRootTreeItem(getter_AddRefs(rootItem));
1756 docshell = do_QueryInterface(rootItem);
1757 if (docshell)
1759 // Is this script running from mail?
1760 PRUint32 appType;
1761 rv = docshell->GetAppType(&appType);
1762 if (NS_FAILED(rv)) return rv;
1763 if (appType == nsIDocShell::APP_TYPE_MAIL)
1765 *result = mIsMailJavaScriptEnabled;
1770 if (!*result)
1771 return NS_OK; // Do not run scripts
1773 //-- Check for a per-site policy
1774 static const char jsPrefGroupName[] = "javascript";
1775 ClassInfoData nameData(nsnull, jsPrefGroupName);
1777 SecurityLevel secLevel;
1778 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1779 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1780 nsnull, &secLevel);
1781 if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
1783 *result = PR_FALSE;
1784 return rv;
1787 //-- Nobody vetoed, so allow the JS to run.
1788 *result = PR_TRUE;
1789 return NS_OK;
1792 ///////////////// Principals ///////////////////////
1793 NS_IMETHODIMP
1794 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
1796 nsresult rv;
1797 *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
1798 if (NS_SUCCEEDED(rv))
1799 NS_IF_ADDREF(*aSubjectPrincipal);
1800 return rv;
1803 nsIPrincipal*
1804 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
1806 NS_PRECONDITION(rv, "Null out param");
1807 JSContext *cx = GetCurrentJSContext();
1808 if (!cx)
1810 *rv = NS_OK;
1811 return nsnull;
1813 return GetSubjectPrincipal(cx, rv);
1816 NS_IMETHODIMP
1817 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
1819 NS_ADDREF(*result = mSystemPrincipal);
1821 return NS_OK;
1824 NS_IMETHODIMP
1825 nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem)
1827 NS_ENSURE_ARG_POINTER(aIsSystem);
1828 *aIsSystem = PR_FALSE;
1830 if (!mSystemPrincipal)
1831 return NS_OK;
1833 nsCOMPtr<nsIPrincipal> subject;
1834 nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
1835 if (NS_FAILED(rv))
1836 return rv;
1838 if(!subject)
1840 // No subject principal means no JS is running;
1841 // this is the equivalent of system principal code
1842 *aIsSystem = PR_TRUE;
1843 return NS_OK;
1846 return mSystemPrincipal->Equals(subject, aIsSystem);
1849 NS_IMETHODIMP
1850 nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint,
1851 const nsACString& aSubjectName,
1852 const nsACString& aPrettyName,
1853 nsISupports* aCertificate,
1854 nsIURI* aURI,
1855 nsIPrincipal **result)
1857 *result = nsnull;
1859 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() &&
1860 !aSubjectName.IsEmpty() &&
1861 aCertificate);
1863 return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName,
1864 aPrettyName, aCertificate, aURI, PR_TRUE,
1865 result);
1868 nsresult
1869 nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
1870 const nsACString& aSubjectName,
1871 const nsACString& aPrettyName,
1872 nsISupports* aCertificate,
1873 nsIURI* aURI,
1874 PRBool aModifyTable,
1875 nsIPrincipal **result)
1877 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty());
1879 // Create a certificate principal out of the certificate ID
1880 // and URI given to us. We will use this principal to test
1881 // equality when doing our hashtable lookups below.
1882 nsRefPtr<nsPrincipal> certificate = new nsPrincipal();
1883 if (!certificate)
1884 return NS_ERROR_OUT_OF_MEMORY;
1886 nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
1887 aPrettyName, aCertificate, aURI);
1888 NS_ENSURE_SUCCESS(rv, rv);
1890 // Check to see if we already have this principal.
1891 nsCOMPtr<nsIPrincipal> fromTable;
1892 mPrincipals.Get(certificate, getter_AddRefs(fromTable));
1893 if (fromTable) {
1894 // Bingo. We found the certificate in the table, which means
1895 // that it has escalated privileges.
1897 if (aModifyTable) {
1898 // Make sure this principal has names, so if we ever go to save it
1899 // we'll save them. If we get a name mismatch here we'll throw,
1900 // but that's desirable.
1901 rv = static_cast<nsPrincipal*>
1902 (static_cast<nsIPrincipal*>(fromTable))
1903 ->EnsureCertData(aSubjectName, aPrettyName, aCertificate);
1904 if (NS_FAILED(rv)) {
1905 // We have a subject name mismatch for the same cert id.
1906 // Hand back the |certificate| object we created and don't give
1907 // it any rights from the table.
1908 NS_ADDREF(*result = certificate);
1909 return NS_OK;
1913 if (!aURI) {
1914 // We were asked to just get the base certificate, so output
1915 // what we have in the table.
1916 certificate = static_cast<nsPrincipal*>
1917 (static_cast<nsIPrincipal*>
1918 (fromTable));
1919 } else {
1920 // We found a certificate and now need to install a codebase
1921 // on it. We don't want to modify the principal in the hash
1922 // table, so create a new principal and clone the pertinent
1923 // things.
1924 nsXPIDLCString prefName;
1925 nsXPIDLCString id;
1926 nsXPIDLCString subjectName;
1927 nsXPIDLCString granted;
1928 nsXPIDLCString denied;
1929 PRBool isTrusted;
1930 rv = fromTable->GetPreferences(getter_Copies(prefName),
1931 getter_Copies(id),
1932 getter_Copies(subjectName),
1933 getter_Copies(granted),
1934 getter_Copies(denied),
1935 &isTrusted);
1936 // XXXbz assert something about subjectName and aSubjectName here?
1937 if (NS_SUCCEEDED(rv)) {
1938 NS_ASSERTION(!isTrusted, "Shouldn't have isTrusted true here");
1940 certificate = new nsPrincipal();
1941 if (!certificate)
1942 return NS_ERROR_OUT_OF_MEMORY;
1944 rv = certificate->InitFromPersistent(prefName, id,
1945 subjectName, aPrettyName,
1946 granted, denied,
1947 aCertificate,
1948 PR_TRUE, PR_FALSE);
1949 if (NS_FAILED(rv))
1950 return rv;
1952 certificate->SetURI(aURI);
1957 NS_ADDREF(*result = certificate);
1959 return rv;
1962 nsresult
1963 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **result)
1965 // I _think_ it's safe to not create null principals here based on aURI.
1966 // At least all the callers would do the right thing in those cases, as far
1967 // as I can tell. --bz
1968 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
1969 if (!codebase)
1970 return NS_ERROR_OUT_OF_MEMORY;
1972 nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
1973 EmptyCString(), nsnull, aURI);
1974 if (NS_FAILED(rv))
1975 return rv;
1977 NS_ADDREF(*result = codebase);
1979 return NS_OK;
1982 NS_IMETHODIMP
1983 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
1984 nsIPrincipal **result)
1986 NS_ENSURE_ARG(aURI);
1988 PRBool inheritsPrincipal;
1989 nsresult rv =
1990 NS_URIChainHasFlags(aURI,
1991 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
1992 &inheritsPrincipal);
1993 if (NS_FAILED(rv) || inheritsPrincipal) {
1994 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
1997 nsCOMPtr<nsIPrincipal> principal;
1998 rv = CreateCodebasePrincipal(aURI, getter_AddRefs(principal));
1999 if (NS_FAILED(rv)) return rv;
2001 if (mPrincipals.Count() > 0)
2003 //-- Check to see if we already have this principal.
2004 nsCOMPtr<nsIPrincipal> fromTable;
2005 mPrincipals.Get(principal, getter_AddRefs(fromTable));
2006 if (fromTable) {
2007 // We found an existing codebase principal. But it might have a
2008 // generic codebase for this origin on it. Install our particular
2009 // codebase.
2010 // XXXbz this is kinda similar to the code in
2011 // GetCertificatePrincipal, but just ever so slightly different.
2012 // Oh, well.
2013 nsXPIDLCString prefName;
2014 nsXPIDLCString id;
2015 nsXPIDLCString subjectName;
2016 nsXPIDLCString granted;
2017 nsXPIDLCString denied;
2018 PRBool isTrusted;
2019 rv = fromTable->GetPreferences(getter_Copies(prefName),
2020 getter_Copies(id),
2021 getter_Copies(subjectName),
2022 getter_Copies(granted),
2023 getter_Copies(denied),
2024 &isTrusted);
2025 if (NS_SUCCEEDED(rv)) {
2026 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2027 if (!codebase)
2028 return NS_ERROR_OUT_OF_MEMORY;
2030 rv = codebase->InitFromPersistent(prefName, id,
2031 subjectName, EmptyCString(),
2032 granted, denied,
2033 nsnull, PR_FALSE,
2034 isTrusted);
2035 if (NS_FAILED(rv))
2036 return rv;
2038 codebase->SetURI(aURI);
2039 principal = codebase;
2045 NS_IF_ADDREF(*result = principal);
2047 return NS_OK;
2050 NS_IMETHODIMP
2051 nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
2052 nsIPrincipal **result)
2054 *result = nsnull;
2056 nsIScriptContext *scriptContext = GetScriptContext(cx);
2058 if (!scriptContext)
2060 return NS_ERROR_FAILURE;
2063 nsCOMPtr<nsIScriptObjectPrincipal> globalData =
2064 do_QueryInterface(scriptContext->GetGlobalObject());
2065 if (globalData)
2066 NS_IF_ADDREF(*result = globalData->GetPrincipal());
2068 return NS_OK;
2071 // static
2072 nsIPrincipal*
2073 nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
2074 JSScript *script,
2075 nsresult* rv)
2077 NS_PRECONDITION(rv, "Null out param");
2078 *rv = NS_OK;
2079 if (!script)
2081 return nsnull;
2083 JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
2084 if (!jsp) {
2085 *rv = NS_ERROR_FAILURE;
2086 NS_ERROR("Script compiled without principals!");
2087 return nsnull;
2089 nsJSPrincipals *nsJSPrin = static_cast<nsJSPrincipals *>(jsp);
2090 nsIPrincipal* result = nsJSPrin->nsIPrincipalPtr;
2091 if (!result)
2092 *rv = NS_ERROR_FAILURE;
2093 return result;
2096 // static
2097 nsIPrincipal*
2098 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
2099 JSObject *obj,
2100 JSStackFrame *fp,
2101 nsresult *rv)
2103 NS_PRECONDITION(rv, "Null out param");
2104 JSFunction *fun = (JSFunction *) caps_GetJSPrivate(obj);
2105 JSScript *script = JS_GetFunctionScript(cx, fun);
2107 *rv = NS_OK;
2109 if (!script)
2111 // A native function: skip it in order to find its scripted caller.
2112 return nsnull;
2115 JSScript *frameScript = fp ? JS_GetFrameScript(cx, fp) : nsnull;
2117 if (frameScript && frameScript != script)
2119 // There is a frame script, and it's different from the
2120 // function script. In this case we're dealing with either
2121 // an eval or a Script object, and in these cases the
2122 // principal we want is in the frame's script, not in the
2123 // function's script. The function's script is where the
2124 // eval-calling code came from, not where the eval or new
2125 // Script object came from, and we want the principal of
2126 // the eval function object or new Script object.
2128 script = frameScript;
2130 else if (JS_GetFunctionObject(fun) != obj)
2132 // Here, obj is a cloned function object. In this case, the
2133 // clone's prototype may have been precompiled from brutally
2134 // shared chrome, or else it is a lambda or nested function.
2135 // The general case here is a function compiled against a
2136 // different scope than the one it is parented by at runtime,
2137 // hence the creation of a clone to carry the correct scope
2138 // chain linkage.
2140 // Since principals follow scope, we must get the object
2141 // principal from the clone's scope chain. There are no
2142 // reliable principals compiled into the function itself.
2144 nsIPrincipal *result = doGetObjectPrincipal(obj);
2145 if (!result)
2146 *rv = NS_ERROR_FAILURE;
2147 return result;
2150 return GetScriptPrincipal(cx, script, rv);
2153 // static
2154 nsIPrincipal*
2155 nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
2156 JSStackFrame *fp,
2157 nsresult *rv)
2159 NS_PRECONDITION(rv, "Null out param");
2160 JSObject *obj = JS_GetFrameFunctionObject(cx, fp);
2161 if (!obj)
2163 // Must be in a top-level script. Get principal from the script.
2164 JSScript *script = JS_GetFrameScript(cx, fp);
2165 return GetScriptPrincipal(cx, script, rv);
2168 nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
2170 #ifdef DEBUG
2171 if (NS_SUCCEEDED(*rv) && !result)
2173 JSFunction *fun = (JSFunction *)caps_GetJSPrivate(obj);
2174 JSScript *script = JS_GetFunctionScript(cx, fun);
2176 NS_ASSERTION(!script, "Null principal for non-native function!");
2178 #endif
2180 return result;
2183 // static
2184 nsIPrincipal*
2185 nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
2186 JSStackFrame **frameResult,
2187 nsresult* rv)
2189 NS_PRECONDITION(rv, "Null out param");
2190 //-- If there's no principal on the stack, look at the global object
2191 // and return the innermost frame for annotations.
2192 *rv = NS_OK;
2193 if (cx)
2195 // Get principals from innermost frame of JavaScript or Java.
2196 JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
2197 for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
2199 nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
2200 if (result)
2202 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
2203 *frameResult = fp;
2204 return result;
2208 nsIScriptContext *scriptContext = GetScriptContext(cx);
2209 if (scriptContext)
2211 nsCOMPtr<nsIScriptObjectPrincipal> globalData =
2212 do_QueryInterface(scriptContext->GetGlobalObject());
2213 if (!globalData)
2215 *rv = NS_ERROR_FAILURE;
2216 return nsnull;
2219 // Note that we're not in a loop or anything, and nothing comes
2220 // after this point in the function, so we can just return here.
2221 nsIPrincipal* result = globalData->GetPrincipal();
2222 if (result)
2224 JSStackFrame *inner = nsnull;
2225 *frameResult = JS_FrameIterator(cx, &inner);
2226 return result;
2231 return nsnull;
2234 // static
2235 nsIPrincipal*
2236 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
2237 nsresult* rv)
2239 NS_PRECONDITION(rv, "Null out param");
2240 JSStackFrame *fp;
2241 return GetPrincipalAndFrame(cx, &fp, rv);
2244 NS_IMETHODIMP
2245 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
2246 nsIPrincipal **result)
2248 *result = doGetObjectPrincipal(aObj);
2249 if (!*result)
2250 return NS_ERROR_FAILURE;
2251 NS_ADDREF(*result);
2252 return NS_OK;
2255 // static
2256 nsIPrincipal*
2257 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
2258 #ifdef DEBUG
2259 , PRBool aAllowShortCircuit
2260 #endif
2263 NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
2264 nsIPrincipal* result = nsnull;
2266 #ifdef DEBUG
2267 JSObject* origObj = aObj;
2268 #endif
2270 const JSClass *jsClass = STOBJ_GET_CLASS(aObj);
2272 // A common case seen in this code is that we enter this function
2273 // with aObj being a Function object, whose parent is a Call
2274 // object. Neither of those have object principals, so we can skip
2275 // those objects here before we enter the below loop. That way we
2276 // avoid wasting time checking properties of their classes etc in
2277 // the loop.
2279 if (jsClass == &js_FunctionClass) {
2280 aObj = STOBJ_GET_PARENT(aObj);
2282 if (!aObj)
2283 return nsnull;
2285 jsClass = STOBJ_GET_CLASS(aObj);
2287 if (jsClass == &js_CallClass) {
2288 aObj = STOBJ_GET_PARENT(aObj);
2290 if (!aObj)
2291 return nsnull;
2293 jsClass = STOBJ_GET_CLASS(aObj);
2297 do {
2298 // Note: jsClass is set before this loop, and also at the
2299 // *end* of this loop.
2301 // NOTE: These class and getObjectOps hook checks better match
2302 // what IS_WRAPPER_CLASS() does in xpconnect!
2303 if (jsClass == sXPCWrappedNativeJSClass ||
2304 jsClass->getObjectOps == sXPCWrappedNativeGetObjOps1 ||
2305 jsClass->getObjectOps == sXPCWrappedNativeGetObjOps2) {
2306 nsIXPConnectWrappedNative *xpcWrapper =
2307 (nsIXPConnectWrappedNative *)caps_GetJSPrivate(aObj);
2309 if (xpcWrapper) {
2310 #ifdef DEBUG
2311 if (aAllowShortCircuit) {
2312 #endif
2313 result = xpcWrapper->GetObjectPrincipal();
2315 if (result) {
2316 break;
2318 #ifdef DEBUG
2320 #endif
2322 // If not, check if it points to an
2323 // nsIScriptObjectPrincipal
2324 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2325 do_QueryWrappedNative(xpcWrapper);
2326 if (objPrin) {
2327 result = objPrin->GetPrincipal();
2329 if (result) {
2330 break;
2334 } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
2335 JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
2336 nsISupports *priv = (nsISupports *)caps_GetJSPrivate(aObj);
2338 #ifdef DEBUG
2339 if (aAllowShortCircuit) {
2340 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
2341 do_QueryInterface(priv);
2343 NS_ASSERTION(!xpcWrapper ||
2344 !strcmp(jsClass->name, "XPCNativeWrapper"),
2345 "Uh, an nsIXPConnectWrappedNative with the "
2346 "wrong JSClass or getObjectOps hooks!");
2348 #endif
2350 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2351 do_QueryInterface(priv);
2353 if (objPrin) {
2354 result = objPrin->GetPrincipal();
2356 if (result) {
2357 break;
2362 aObj = STOBJ_GET_PARENT(aObj);
2364 if (!aObj)
2365 break;
2367 jsClass = STOBJ_GET_CLASS(aObj);
2368 } while (1);
2370 NS_ASSERTION(!aAllowShortCircuit ||
2371 result == doGetObjectPrincipal(origObj, PR_FALSE),
2372 "Principal mismatch. Not good");
2374 return result;
2377 nsresult
2378 nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
2380 //-- Save to mPrincipals
2381 mPrincipals.Put(aToSave, aToSave);
2383 //-- Save to prefs
2384 nsXPIDLCString idPrefName;
2385 nsXPIDLCString id;
2386 nsXPIDLCString subjectName;
2387 nsXPIDLCString grantedList;
2388 nsXPIDLCString deniedList;
2389 PRBool isTrusted;
2390 nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName),
2391 getter_Copies(id),
2392 getter_Copies(subjectName),
2393 getter_Copies(grantedList),
2394 getter_Copies(deniedList),
2395 &isTrusted);
2396 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2398 nsCAutoString grantedPrefName;
2399 nsCAutoString deniedPrefName;
2400 nsCAutoString subjectNamePrefName;
2401 rv = GetPrincipalPrefNames( idPrefName,
2402 grantedPrefName,
2403 deniedPrefName,
2404 subjectNamePrefName );
2405 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2407 mIsWritingPrefs = PR_TRUE;
2408 if (grantedList)
2409 mSecurityPref->SecuritySetCharPref(grantedPrefName.get(), grantedList);
2410 else
2411 mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
2413 if (deniedList)
2414 mSecurityPref->SecuritySetCharPref(deniedPrefName.get(), deniedList);
2415 else
2416 mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
2418 if (grantedList || deniedList) {
2419 mSecurityPref->SecuritySetCharPref(idPrefName, id);
2420 mSecurityPref->SecuritySetCharPref(subjectNamePrefName.get(),
2421 subjectName);
2423 else {
2424 mSecurityPref->SecurityClearUserPref(idPrefName);
2425 mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
2428 mIsWritingPrefs = PR_FALSE;
2430 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
2431 NS_ENSURE_SUCCESS(rv, rv);
2432 return prefService->SavePrefFile(nsnull);
2435 ///////////////// Capabilities API /////////////////////
2436 NS_IMETHODIMP
2437 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
2438 PRBool *result)
2440 nsresult rv;
2441 JSStackFrame *fp = nsnull;
2442 JSContext *cx = GetCurrentJSContext();
2443 fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
2444 if (!fp)
2446 // No script code on stack. Allow execution.
2447 *result = PR_TRUE;
2448 return NS_OK;
2450 *result = PR_FALSE;
2451 nsIPrincipal* previousPrincipal = nsnull;
2454 nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
2455 if (NS_FAILED(rv))
2456 return rv;
2457 if (!principal)
2458 continue;
2459 // If caller has a different principal, stop looking up the stack.
2460 if(previousPrincipal)
2462 PRBool isEqual = PR_FALSE;
2463 if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
2464 break;
2466 else
2467 previousPrincipal = principal;
2469 // First check if the principal is even able to enable the
2470 // given capability. If not, don't look any further.
2471 PRInt16 canEnable;
2472 rv = principal->CanEnableCapability(capability, &canEnable);
2473 if (NS_FAILED(rv)) return rv;
2474 if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
2475 canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2476 return NS_OK;
2478 // Now see if the capability is enabled.
2479 void *annotation = JS_GetFrameAnnotation(cx, fp);
2480 rv = principal->IsCapabilityEnabled(capability, annotation, result);
2481 if (NS_FAILED(rv)) return rv;
2482 if (*result)
2483 return NS_OK;
2484 } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
2486 if (!previousPrincipal)
2488 // No principals on the stack, all native code. Allow
2489 // execution if the subject principal is the system principal.
2491 return SubjectPrincipalIsSystem(result);
2494 return NS_OK;
2497 void
2498 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
2500 nsAutoString newcaps;
2501 nsAutoString rawcap;
2502 NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
2503 PRInt32 pos;
2504 PRInt32 index = kNotFound;
2505 nsresult rv;
2507 NS_ASSERTION(kNotFound == -1, "Basic constant changed, algorithm broken!");
2509 do {
2510 pos = index+1;
2511 index = aCapability.FindChar(' ', pos);
2512 rawcap = Substring(aCapability, pos,
2513 (index == kNotFound) ? index : index - pos);
2515 nsXPIDLString capstr;
2516 rv = sStrBundle->GetStringFromName(
2517 nsPromiseFlatString(capdesc+rawcap).get(),
2518 getter_Copies(capstr));
2519 if (NS_SUCCEEDED(rv))
2520 newcaps += capstr;
2521 else
2523 nsXPIDLString extensionCap;
2524 const PRUnichar* formatArgs[] = { rawcap.get() };
2525 rv = sStrBundle->FormatStringFromName(
2526 NS_LITERAL_STRING("ExtensionCapability").get(),
2527 formatArgs,
2528 NS_ARRAY_LENGTH(formatArgs),
2529 getter_Copies(extensionCap));
2530 if (NS_SUCCEEDED(rv))
2531 newcaps += extensionCap;
2532 else
2533 newcaps += rawcap;
2536 newcaps += NS_LITERAL_STRING("\n");
2537 } while (index != kNotFound);
2539 aCapability = newcaps;
2542 PRBool
2543 nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
2544 const char* aCapability, PRBool *checkValue)
2546 nsresult rv;
2547 *checkValue = PR_FALSE;
2549 //-- Get a prompter for the current window.
2550 nsCOMPtr<nsIPrompt> prompter;
2551 if (cx)
2553 nsIScriptContext *scriptContext = GetScriptContext(cx);
2554 if (scriptContext)
2556 nsCOMPtr<nsIDOMWindowInternal> domWin =
2557 do_QueryInterface(scriptContext->GetGlobalObject());
2558 if (domWin)
2559 domWin->GetPrompter(getter_AddRefs(prompter));
2563 if (!prompter)
2565 //-- Couldn't get prompter from the current window, so get the prompt service.
2566 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2567 if (wwatch)
2568 wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
2569 if (!prompter)
2570 return PR_FALSE;
2573 //-- Localize the dialog text
2574 nsXPIDLString check;
2575 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
2576 getter_Copies(check));
2577 if (NS_FAILED(rv))
2578 return PR_FALSE;
2580 nsXPIDLString title;
2581 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
2582 getter_Copies(title));
2583 if (NS_FAILED(rv))
2584 return PR_FALSE;
2586 nsXPIDLString yesStr;
2587 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
2588 getter_Copies(yesStr));
2589 if (NS_FAILED(rv))
2590 return PR_FALSE;
2592 nsXPIDLString noStr;
2593 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(),
2594 getter_Copies(noStr));
2595 if (NS_FAILED(rv))
2596 return PR_FALSE;
2598 nsCAutoString val;
2599 PRBool hasCert;
2600 aPrincipal->GetHasCertificate(&hasCert);
2601 if (hasCert)
2602 rv = aPrincipal->GetPrettyName(val);
2603 else
2604 rv = GetPrincipalDomainOrigin(aPrincipal, val);
2606 if (NS_FAILED(rv))
2607 return PR_FALSE;
2609 NS_ConvertUTF8toUTF16 location(val);
2610 NS_ConvertASCIItoUTF16 capability(aCapability);
2611 FormatCapabilityString(capability);
2612 const PRUnichar *formatStrings[] = { location.get(), capability.get() };
2614 nsXPIDLString message;
2615 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
2616 formatStrings,
2617 NS_ARRAY_LENGTH(formatStrings),
2618 getter_Copies(message));
2619 if (NS_FAILED(rv))
2620 return PR_FALSE;
2622 PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
2623 rv = prompter->ConfirmEx(title.get(), message.get(),
2624 (nsIPrompt::BUTTON_DELAY_ENABLE) +
2625 (nsIPrompt::BUTTON_POS_1_DEFAULT) +
2626 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
2627 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1),
2628 yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed);
2630 if (NS_FAILED(rv))
2631 *checkValue = PR_FALSE;
2632 return (buttonPressed == 0);
2635 NS_IMETHODIMP
2636 nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal,
2637 const char *capability, PRInt16* canEnable)
2639 if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
2640 return NS_ERROR_FAILURE;
2641 if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2643 // Prompt user for permission to enable capability.
2644 JSContext* cx = GetCurrentJSContext();
2645 PRBool remember;
2646 if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
2647 *canEnable = nsIPrincipal::ENABLE_GRANTED;
2648 else
2649 *canEnable = nsIPrincipal::ENABLE_DENIED;
2650 if (remember)
2652 //-- Save principal to prefs and to mPrincipals
2653 if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
2654 return NS_ERROR_FAILURE;
2655 if (NS_FAILED(SavePrincipal(aPrincipal)))
2656 return NS_ERROR_FAILURE;
2659 return NS_OK;
2662 NS_IMETHODIMP
2663 nsScriptSecurityManager::EnableCapability(const char *capability)
2665 JSContext *cx = GetCurrentJSContext();
2666 JSStackFrame *fp;
2668 //-- Error checks for capability string length (200)
2669 if(PL_strlen(capability)>200)
2671 static const char msg[] = "Capability name too long";
2672 SetPendingException(cx, msg);
2673 return NS_ERROR_FAILURE;
2676 //-- Check capability string for valid characters
2678 // Logically we might have wanted this in nsPrincipal, but performance
2679 // worries dictate it can't go in IsCapabilityEnabled() and we may have
2680 // to show the capability on a dialog before we call the principal's
2681 // EnableCapability().
2683 // We don't need to validate the capability string on the other APIs
2684 // available to web content. Without the ability to enable junk then
2685 // isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
2686 // the right thing (effectively nothing) when passed unallowed chars.
2687 for (const char *ch = capability; *ch; ++ch)
2689 if (!NS_IS_ALPHA(*ch) && *ch != ' ' && !NS_IS_DIGIT(*ch)
2690 && *ch != '_' && *ch != '-' && *ch != '.')
2692 static const char msg[] = "Invalid character in capability name";
2693 SetPendingException(cx, msg);
2694 return NS_ERROR_FAILURE;
2698 nsresult rv;
2699 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2700 if (NS_FAILED(rv))
2701 return rv;
2702 if (!principal)
2703 return NS_ERROR_NOT_AVAILABLE;
2705 void *annotation = JS_GetFrameAnnotation(cx, fp);
2706 PRBool enabled;
2707 if (NS_FAILED(principal->IsCapabilityEnabled(capability, annotation,
2708 &enabled)))
2709 return NS_ERROR_FAILURE;
2710 if (enabled)
2711 return NS_OK;
2713 PRInt16 canEnable;
2714 if (NS_FAILED(RequestCapability(principal, capability, &canEnable)))
2715 return NS_ERROR_FAILURE;
2717 if (canEnable != nsIPrincipal::ENABLE_GRANTED)
2719 nsCAutoString val;
2720 PRBool hasCert;
2721 nsresult rv;
2722 principal->GetHasCertificate(&hasCert);
2723 if (hasCert)
2724 rv = principal->GetPrettyName(val);
2725 else
2726 rv = GetPrincipalDomainOrigin(principal, val);
2728 if (NS_FAILED(rv))
2729 return rv;
2731 NS_ConvertUTF8toUTF16 location(val);
2732 NS_ConvertUTF8toUTF16 cap(capability);
2733 const PRUnichar *formatStrings[] = { location.get(), cap.get() };
2735 nsXPIDLString message;
2736 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
2737 formatStrings,
2738 NS_ARRAY_LENGTH(formatStrings),
2739 getter_Copies(message));
2740 if (NS_FAILED(rv))
2741 return rv;
2743 SetPendingException(cx, message.get());
2745 return NS_ERROR_FAILURE; // XXX better error code?
2747 if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
2748 return NS_ERROR_FAILURE;
2749 JS_SetFrameAnnotation(cx, fp, annotation);
2750 return NS_OK;
2753 NS_IMETHODIMP
2754 nsScriptSecurityManager::RevertCapability(const char *capability)
2756 JSContext *cx = GetCurrentJSContext();
2757 JSStackFrame *fp;
2758 nsresult rv;
2759 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2760 if (NS_FAILED(rv))
2761 return rv;
2762 if (!principal)
2763 return NS_ERROR_NOT_AVAILABLE;
2764 void *annotation = JS_GetFrameAnnotation(cx, fp);
2765 principal->RevertCapability(capability, &annotation);
2766 JS_SetFrameAnnotation(cx, fp, annotation);
2767 return NS_OK;
2770 NS_IMETHODIMP
2771 nsScriptSecurityManager::DisableCapability(const char *capability)
2773 JSContext *cx = GetCurrentJSContext();
2774 JSStackFrame *fp;
2775 nsresult rv;
2776 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2777 if (NS_FAILED(rv))
2778 return rv;
2779 if (!principal)
2780 return NS_ERROR_NOT_AVAILABLE;
2781 void *annotation = JS_GetFrameAnnotation(cx, fp);
2782 principal->DisableCapability(capability, &annotation);
2783 JS_SetFrameAnnotation(cx, fp, annotation);
2784 return NS_OK;
2787 //////////////// Master Certificate Functions ///////////////////////////////////////
2788 NS_IMETHODIMP
2789 nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint,
2790 const char* capability,
2791 PRInt16 canEnable)
2793 NS_ENSURE_ARG(!certFingerprint.IsEmpty());
2795 nsresult rv;
2796 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv);
2797 if (NS_FAILED(rv))
2798 return rv;
2800 //-- Get the system certificate
2801 if (!mSystemCertificate)
2803 nsCOMPtr<nsIFile> systemCertFile;
2804 nsCOMPtr<nsIProperties> directoryService =
2805 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
2806 if (!directoryService) return NS_ERROR_FAILURE;
2807 rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
2808 getter_AddRefs(systemCertFile));
2809 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2810 systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
2811 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2812 nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv);
2813 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2814 rv = systemCertZip->Open(systemCertFile);
2815 if (NS_SUCCEEDED(rv))
2817 nsCOMPtr<nsIJAR> systemCertJar(do_QueryInterface(systemCertZip, &rv));
2818 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2819 rv = systemCertJar->GetCertificatePrincipal(nsnull,
2820 getter_AddRefs(mSystemCertificate));
2821 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2825 //-- Make sure the caller's principal is the system certificate
2826 PRBool isEqual = PR_FALSE;
2827 if (mSystemCertificate)
2829 rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual);
2830 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2832 if (!isEqual)
2834 JSContext* cx = GetCurrentJSContext();
2835 if (!cx) return NS_ERROR_FAILURE;
2836 static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
2837 static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
2838 SetPendingException(cx, mSystemCertificate ? msg1 : msg2);
2839 return NS_ERROR_FAILURE;
2842 //-- Get the target principal
2843 nsCOMPtr<nsIPrincipal> objectPrincipal;
2844 rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(),
2845 EmptyCString(), nsnull,
2846 nsnull, PR_FALSE,
2847 getter_AddRefs(objectPrincipal));
2848 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2849 rv = objectPrincipal->SetCanEnableCapability(capability, canEnable);
2850 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2851 return SavePrincipal(objectPrincipal);
2854 ////////////////////////////////////////////////
2855 // Methods implementing nsIXPCSecurityManager //
2856 ////////////////////////////////////////////////
2858 NS_IMETHODIMP
2859 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
2860 const nsIID &aIID,
2861 nsISupports *aObj,
2862 nsIClassInfo *aClassInfo,
2863 void **aPolicy)
2865 #ifdef DEBUG_CAPS_CanCreateWrapper
2866 char* iidStr = aIID.ToString();
2867 printf("### CanCreateWrapper(%s) ", iidStr);
2868 nsCRT::free(iidStr);
2869 #endif
2870 // XXX Special case for nsIXPCException ?
2871 ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nsnull);
2872 if (objClassInfo.IsDOMClass())
2874 #ifdef DEBUG_CAPS_CanCreateWrapper
2875 printf("DOM class - GRANTED.\n");
2876 #endif
2877 return NS_OK;
2880 //--See if the object advertises a non-default level of access
2881 // using nsISecurityCheckedComponent
2882 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
2883 do_QueryInterface(aObj);
2885 nsXPIDLCString objectSecurityLevel;
2886 if (checkedComponent)
2887 checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
2889 nsresult rv = CheckXPCPermissions(aObj, objectSecurityLevel);
2890 if (NS_FAILED(rv))
2892 //-- Access denied, report an error
2893 NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
2894 nsCAutoString origin;
2895 nsresult rv2;
2896 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2);
2897 if (NS_SUCCEEDED(rv2) && subjectPrincipal) {
2898 GetPrincipalDomainOrigin(subjectPrincipal, origin);
2900 NS_ConvertUTF8toUTF16 originUnicode(origin);
2901 NS_ConvertUTF8toUTF16 className(objClassInfo.GetName());
2902 const PRUnichar* formatStrings[] = {
2903 className.get(),
2904 originUnicode.get()
2906 PRUint32 length = NS_ARRAY_LENGTH(formatStrings);
2907 if (originUnicode.IsEmpty()) {
2908 --length;
2909 } else {
2910 strName.AppendLiteral("ForOrigin");
2912 nsXPIDLString errorMsg;
2913 // We need to keep our existing failure rv and not override it
2914 // with a likely success code from the following string bundle
2915 // call in order to throw the correct security exception later.
2916 rv2 = sStrBundle->FormatStringFromName(strName.get(),
2917 formatStrings,
2918 length,
2919 getter_Copies(errorMsg));
2920 NS_ENSURE_SUCCESS(rv2, rv2);
2922 SetPendingException(cx, errorMsg.get());
2924 #ifdef DEBUG_CAPS_CanCreateWrapper
2925 printf("DENIED.\n");
2927 else
2929 printf("GRANTED.\n");
2930 #endif
2933 return rv;
2936 #ifdef XPC_IDISPATCH_SUPPORT
2937 nsresult
2938 nsScriptSecurityManager::CheckComponentPermissions(JSContext *cx,
2939 const nsCID &aCID)
2941 nsresult rv;
2942 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
2943 if (NS_FAILED(rv))
2944 return rv;
2946 // Reformat the CID string so it's suitable for prefs
2947 nsXPIDLCString cidTemp;
2948 cidTemp.Adopt(aCID.ToString());
2949 nsCAutoString cid(NS_LITERAL_CSTRING("CID") +
2950 Substring(cidTemp, 1, cidTemp.Length() - 2));
2951 ToUpperCase(cid);
2953 #ifdef DEBUG_CAPS_CheckComponentPermissions
2954 printf("### CheckComponentPermissions(ClassID.%s) ",cid.get());
2955 #endif
2957 // Look up the policy for this class.
2958 // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD
2959 JSAutoRequest ar(cx);
2960 jsval cidVal = STRING_TO_JSVAL(::JS_InternString(cx, cid.get()));
2962 ClassInfoData nameData(nsnull, "ClassID");
2963 SecurityLevel securityLevel;
2964 rv = LookupPolicy(subjectPrincipal, nameData, cidVal,
2965 nsIXPCSecurityManager::ACCESS_CALL_METHOD,
2966 nsnull, &securityLevel);
2967 if (NS_FAILED(rv))
2968 return rv;
2970 // If there's no policy stored, use the "security.classID.allowByDefault" pref
2971 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
2972 securityLevel.level = mXPCDefaultGrantAll ? SCRIPT_SECURITY_ALL_ACCESS :
2973 SCRIPT_SECURITY_NO_ACCESS;
2975 if (securityLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
2977 #ifdef DEBUG_CAPS_CheckComponentPermissions
2978 printf(" GRANTED.\n");
2979 #endif
2980 return NS_OK;
2983 #ifdef DEBUG_CAPS_CheckComponentPermissions
2984 printf(" DENIED.\n");
2985 #endif
2986 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
2988 #endif
2990 NS_IMETHODIMP
2991 nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
2992 const nsCID &aCID)
2994 #ifdef DEBUG_CAPS_CanCreateInstance
2995 char* cidStr = aCID.ToString();
2996 printf("### CanCreateInstance(%s) ", cidStr);
2997 nsCRT::free(cidStr);
2998 #endif
3000 nsresult rv = CheckXPCPermissions(nsnull, nsnull);
3001 if (NS_FAILED(rv))
3002 #ifdef XPC_IDISPATCH_SUPPORT
3004 rv = CheckComponentPermissions(cx, aCID);
3006 if (NS_FAILED(rv))
3007 #endif
3009 //-- Access denied, report an error
3010 nsCAutoString errorMsg("Permission denied to create instance of class. CID=");
3011 char cidStr[NSID_LENGTH];
3012 aCID.ToProvidedString(cidStr);
3013 errorMsg.Append(cidStr);
3014 SetPendingException(cx, errorMsg.get());
3016 #ifdef DEBUG_CAPS_CanCreateInstance
3017 printf("DENIED\n");
3019 else
3021 printf("GRANTED\n");
3022 #endif
3024 return rv;
3027 NS_IMETHODIMP
3028 nsScriptSecurityManager::CanGetService(JSContext *cx,
3029 const nsCID &aCID)
3031 #ifdef DEBUG_CAPS_CanGetService
3032 char* cidStr = aCID.ToString();
3033 printf("### CanGetService(%s) ", cidStr);
3034 nsCRT::free(cidStr);
3035 #endif
3037 nsresult rv = CheckXPCPermissions(nsnull, nsnull);
3038 if (NS_FAILED(rv))
3040 //-- Access denied, report an error
3041 nsCAutoString errorMsg("Permission denied to get service. CID=");
3042 char cidStr[NSID_LENGTH];
3043 aCID.ToProvidedString(cidStr);
3044 errorMsg.Append(cidStr);
3045 SetPendingException(cx, errorMsg.get());
3047 #ifdef DEBUG_CAPS_CanGetService
3048 printf("DENIED\n");
3050 else
3052 printf("GRANTED\n");
3053 #endif
3056 return rv;
3060 NS_IMETHODIMP
3061 nsScriptSecurityManager::CanAccess(PRUint32 aAction,
3062 nsAXPCNativeCallContext* aCallContext,
3063 JSContext* cx,
3064 JSObject* aJSObject,
3065 nsISupports* aObj,
3066 nsIClassInfo* aClassInfo,
3067 jsval aPropertyName,
3068 void** aPolicy)
3070 return CheckPropertyAccessImpl(aAction, aCallContext, cx,
3071 aJSObject, aObj, nsnull, aClassInfo,
3072 nsnull, aPropertyName, aPolicy);
3075 nsresult
3076 nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj,
3077 const char* aObjectSecurityLevel)
3079 //-- Check for the all-powerful UniversalXPConnect privilege
3080 PRBool ok = PR_FALSE;
3081 if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok)) && ok)
3082 return NS_OK;
3084 //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
3085 if (aObjectSecurityLevel)
3087 if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
3088 return NS_OK;
3089 else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
3091 PRBool canAccess = PR_FALSE;
3092 if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel, &canAccess)) &&
3093 canAccess)
3094 return NS_OK;
3098 //-- If user allows scripting of plugins by untrusted scripts,
3099 // and the target object is a plugin, allow the access.
3100 if(aObj)
3102 nsresult rv;
3103 nsCOMPtr<nsIPluginInstance> plugin(do_QueryInterface(aObj, &rv));
3104 if (NS_SUCCEEDED(rv))
3106 static PRBool prefSet = PR_FALSE;
3107 static PRBool allowPluginAccess = PR_FALSE;
3108 if (!prefSet)
3110 rv = mSecurityPref->SecurityGetBoolPref("security.xpconnect.plugin.unrestricted",
3111 &allowPluginAccess);
3112 prefSet = PR_TRUE;
3114 if (allowPluginAccess)
3115 return NS_OK;
3119 //-- Access tests failed
3120 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
3123 //////////////////////////////////////////////
3124 // Method implementing nsIPrefSecurityCheck //
3125 //////////////////////////////////////////////
3127 NS_IMETHODIMP
3128 nsScriptSecurityManager::CanAccessSecurityPreferences(PRBool* _retval)
3130 return IsCapabilityEnabled("CapabilityPreferencesAccess", _retval);
3133 /////////////////////////////////////////////
3134 // Method implementing nsIChannelEventSink //
3135 /////////////////////////////////////////////
3136 NS_IMETHODIMP
3137 nsScriptSecurityManager::OnChannelRedirect(nsIChannel* oldChannel,
3138 nsIChannel* newChannel,
3139 PRUint32 redirFlags)
3141 nsCOMPtr<nsIPrincipal> oldPrincipal;
3142 GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
3144 nsCOMPtr<nsIURI> newURI;
3145 newChannel->GetURI(getter_AddRefs(newURI));
3146 nsCOMPtr<nsIURI> newOriginalURI;
3147 newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
3149 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
3151 const PRUint32 flags =
3152 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
3153 nsIScriptSecurityManager::DISALLOW_SCRIPT;
3154 nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
3155 if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
3156 rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
3158 return rv;
3162 /////////////////////////////////////
3163 // Method implementing nsIObserver //
3164 /////////////////////////////////////
3165 static const char sPrincipalPrefix[] = "capability.principal";
3166 static const char sPolicyPrefix[] = "capability.policy.";
3168 NS_IMETHODIMP
3169 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
3170 const PRUnichar* aMessage)
3172 nsresult rv = NS_OK;
3173 NS_ConvertUTF16toUTF8 messageStr(aMessage);
3174 const char *message = messageStr.get();
3176 static const char jsPrefix[] = "javascript.";
3177 static const char securityPrefix[] = "security.";
3178 if ((PL_strncmp(message, jsPrefix, sizeof(jsPrefix)-1) == 0) ||
3179 (PL_strncmp(message, securityPrefix, sizeof(securityPrefix)-1) == 0) )
3181 ScriptSecurityPrefChanged();
3183 else if (PL_strncmp(message, sPolicyPrefix, sizeof(sPolicyPrefix)-1) == 0)
3185 // This will force re-initialization of the pref table
3186 mPolicyPrefsChanged = PR_TRUE;
3188 else if ((PL_strncmp(message, sPrincipalPrefix, sizeof(sPrincipalPrefix)-1) == 0) &&
3189 !mIsWritingPrefs)
3191 static const char id[] = "id";
3192 char* lastDot = PL_strrchr(message, '.');
3193 //-- This check makes sure the string copy below doesn't overwrite its bounds
3194 if(PL_strlen(lastDot) >= sizeof(id))
3196 PL_strcpy(lastDot + 1, id);
3197 const char** idPrefArray = (const char**)&message;
3198 rv = InitPrincipals(1, idPrefArray, mSecurityPref);
3201 return rv;
3204 /////////////////////////////////////////////
3205 // Constructor, Destructor, Initialization //
3206 /////////////////////////////////////////////
3207 nsScriptSecurityManager::nsScriptSecurityManager(void)
3208 : mOriginToPolicyMap(nsnull),
3209 mDefaultPolicy(nsnull),
3210 mCapabilities(nsnull),
3211 mIsJavaScriptEnabled(PR_FALSE),
3212 mIsMailJavaScriptEnabled(PR_FALSE),
3213 mIsWritingPrefs(PR_FALSE),
3214 mPolicyPrefsChanged(PR_TRUE)
3215 #ifdef XPC_IDISPATCH_SUPPORT
3216 , mXPCDefaultGrantAll(PR_FALSE)
3217 #endif
3219 NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
3220 mPrincipals.Init(31);
3224 nsresult nsScriptSecurityManager::Init()
3226 nsresult rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
3227 NS_ENSURE_SUCCESS(rv, rv);
3229 rv = CallGetService("@mozilla.org/js/xpc/ContextStack;1", &sJSContextStack);
3230 NS_ENSURE_SUCCESS(rv, rv);
3232 JSContext* cx = GetSafeJSContext();
3233 if (!cx) return NS_ERROR_FAILURE; // this can happen of xpt loading fails
3235 ::JS_BeginRequest(cx);
3236 if (sEnabledID == JSVAL_VOID)
3237 sEnabledID = STRING_TO_JSVAL(::JS_InternString(cx, "enabled"));
3238 ::JS_EndRequest(cx);
3240 rv = InitPrefs();
3241 NS_ENSURE_SUCCESS(rv, rv);
3243 rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
3244 NS_ENSURE_SUCCESS(rv, rv);
3246 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
3247 NS_ENSURE_SUCCESS(rv, rv);
3249 rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
3250 NS_ENSURE_SUCCESS(rv, rv);
3252 // Create our system principal singleton
3253 nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
3254 NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
3256 rv = system->Init();
3257 NS_ENSURE_SUCCESS(rv, rv);
3259 mSystemPrincipal = system;
3261 //-- Register security check callback in the JS engine
3262 // Currently this is used to control access to function.caller
3263 nsCOMPtr<nsIJSRuntimeService> runtimeService =
3264 do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv);
3265 NS_ENSURE_SUCCESS(rv, rv);
3267 rv = runtimeService->GetRuntime(&sRuntime);
3268 NS_ENSURE_SUCCESS(rv, rv);
3270 static JSSecurityCallbacks securityCallbacks = {
3271 CheckObjectAccess,
3272 NULL,
3273 NULL
3276 #ifdef DEBUG
3277 JSSecurityCallbacks *oldcallbacks =
3278 #endif
3279 JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
3280 NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
3282 sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
3283 &sXPCWrappedNativeGetObjOps1,
3284 &sXPCWrappedNativeGetObjOps2);
3285 return NS_OK;
3288 static nsScriptSecurityManager *gScriptSecMan = nsnull;
3290 jsval nsScriptSecurityManager::sEnabledID = JSVAL_VOID;
3292 nsScriptSecurityManager::~nsScriptSecurityManager(void)
3294 delete mOriginToPolicyMap;
3295 if(mDefaultPolicy)
3296 mDefaultPolicy->Drop();
3297 delete mCapabilities;
3298 gScriptSecMan = nsnull;
3301 void
3302 nsScriptSecurityManager::Shutdown()
3304 if (sRuntime) {
3305 JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
3306 sRuntime = nsnull;
3308 sEnabledID = JSVAL_VOID;
3310 NS_IF_RELEASE(sIOService);
3311 NS_IF_RELEASE(sXPConnect);
3312 NS_IF_RELEASE(sJSContextStack);
3313 NS_IF_RELEASE(sStrBundle);
3316 nsScriptSecurityManager *
3317 nsScriptSecurityManager::GetScriptSecurityManager()
3319 if (!gScriptSecMan)
3321 nsScriptSecurityManager* ssManager = new nsScriptSecurityManager();
3322 if (!ssManager)
3323 return nsnull;
3324 nsresult rv;
3325 rv = ssManager->Init();
3326 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
3327 if (NS_FAILED(rv)) {
3328 delete ssManager;
3329 return nsnull;
3332 rv = nsJSPrincipals::Startup();
3333 if (NS_FAILED(rv)) {
3334 NS_WARNING("can't initialize JS engine security protocol glue!");
3335 delete ssManager;
3336 return nsnull;
3339 rv = sXPConnect->SetDefaultSecurityManager(ssManager,
3340 nsIXPCSecurityManager::HOOK_ALL);
3341 if (NS_FAILED(rv)) {
3342 NS_WARNING("Failed to install xpconnect security manager!");
3343 delete ssManager;
3344 return nsnull;
3347 gScriptSecMan = ssManager;
3349 return gScriptSecMan;
3352 // Currently this nsGenericFactory constructor is used only from FastLoad
3353 // (XPCOM object deserialization) code, when "creating" the system principal
3354 // singleton.
3355 nsSystemPrincipal *
3356 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
3358 nsIPrincipal *sysprin = nsnull;
3359 if (gScriptSecMan)
3360 NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
3361 return static_cast<nsSystemPrincipal*>(sysprin);
3364 nsresult
3365 nsScriptSecurityManager::InitPolicies()
3367 // Clear any policies cached on XPConnect wrappers
3368 NS_ENSURE_STATE(sXPConnect);
3369 nsresult rv = sXPConnect->ClearAllWrappedNativeSecurityPolicies();
3370 if (NS_FAILED(rv)) return rv;
3372 //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
3373 //-- whose dtor decrements refcount of stored DomainPolicy object
3374 delete mOriginToPolicyMap;
3376 //-- Marks all the survivor DomainPolicy objects (those cached
3377 //-- by nsPrincipal objects) as invalid: they will be released
3378 //-- on first nsPrincipal::GetSecurityPolicy() attempt.
3379 DomainPolicy::InvalidateAll();
3381 //-- Release old default policy
3382 if(mDefaultPolicy) {
3383 mDefaultPolicy->Drop();
3384 mDefaultPolicy = nsnull;
3387 //-- Initialize a new mOriginToPolicyMap
3388 mOriginToPolicyMap =
3389 new nsObjectHashtable(nsnull, nsnull, DeleteDomainEntry, nsnull);
3390 if (!mOriginToPolicyMap)
3391 return NS_ERROR_OUT_OF_MEMORY;
3393 //-- Create, refcount and initialize a new default policy
3394 mDefaultPolicy = new DomainPolicy();
3395 if (!mDefaultPolicy)
3396 return NS_ERROR_OUT_OF_MEMORY;
3398 mDefaultPolicy->Hold();
3399 if (!mDefaultPolicy->Init())
3400 return NS_ERROR_UNEXPECTED;
3402 //-- Initialize the table of security levels
3403 if (!mCapabilities)
3405 mCapabilities =
3406 new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
3407 if (!mCapabilities)
3408 return NS_ERROR_OUT_OF_MEMORY;
3411 // Get a JS context - we need it to create internalized strings later.
3412 JSContext* cx = GetSafeJSContext();
3413 NS_ASSERTION(cx, "failed to get JS context");
3414 AutoCxPusher autoPusher(sJSContextStack, cx);
3415 rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
3416 NS_ENSURE_SUCCESS(rv, rv);
3418 nsXPIDLCString policyNames;
3419 rv = mSecurityPref->SecurityGetCharPref("capability.policy.policynames",
3420 getter_Copies(policyNames));
3422 nsXPIDLCString defaultPolicyNames;
3423 rv = mSecurityPref->SecurityGetCharPref("capability.policy.default_policynames",
3424 getter_Copies(defaultPolicyNames));
3425 policyNames += NS_LITERAL_CSTRING(" ") + defaultPolicyNames;
3427 //-- Initialize domain policies
3428 char* policyCurrent = policyNames.BeginWriting();
3429 PRBool morePolicies = PR_TRUE;
3430 while (morePolicies)
3432 while(*policyCurrent == ' ' || *policyCurrent == ',')
3433 policyCurrent++;
3434 if (*policyCurrent == '\0')
3435 break;
3436 char* nameBegin = policyCurrent;
3438 while(*policyCurrent != '\0' && *policyCurrent != ' ' && *policyCurrent != ',')
3439 policyCurrent++;
3441 morePolicies = (*policyCurrent != '\0');
3442 *policyCurrent = '\0';
3443 policyCurrent++;
3445 nsCAutoString sitesPrefName(
3446 NS_LITERAL_CSTRING(sPolicyPrefix) +
3447 nsDependentCString(nameBegin) +
3448 NS_LITERAL_CSTRING(".sites"));
3449 nsXPIDLCString domainList;
3450 rv = mSecurityPref->SecurityGetCharPref(sitesPrefName.get(),
3451 getter_Copies(domainList));
3452 if (NS_FAILED(rv))
3453 continue;
3455 DomainPolicy* domainPolicy = new DomainPolicy();
3456 if (!domainPolicy)
3457 return NS_ERROR_OUT_OF_MEMORY;
3459 if (!domainPolicy->Init())
3461 delete domainPolicy;
3462 return NS_ERROR_UNEXPECTED;
3464 domainPolicy->Hold();
3465 //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
3466 char* domainStart = domainList.BeginWriting();
3467 char* domainCurrent = domainStart;
3468 char* lastDot = nsnull;
3469 char* nextToLastDot = nsnull;
3470 PRBool moreDomains = PR_TRUE;
3471 while (moreDomains)
3473 if (*domainCurrent == ' ' || *domainCurrent == '\0')
3475 moreDomains = (*domainCurrent != '\0');
3476 *domainCurrent = '\0';
3477 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : domainStart);
3478 DomainEntry *newEntry = new DomainEntry(domainStart, domainPolicy);
3479 if (!newEntry)
3481 domainPolicy->Drop();
3482 return NS_ERROR_OUT_OF_MEMORY;
3484 #ifdef DEBUG
3485 newEntry->mPolicyName_DEBUG = nameBegin;
3486 #endif
3487 DomainEntry *existingEntry = (DomainEntry *)
3488 mOriginToPolicyMap->Get(&key);
3489 if (!existingEntry)
3490 mOriginToPolicyMap->Put(&key, newEntry);
3491 else
3493 if (existingEntry->Matches(domainStart))
3495 newEntry->mNext = existingEntry;
3496 mOriginToPolicyMap->Put(&key, newEntry);
3498 else
3500 while (existingEntry->mNext)
3502 if (existingEntry->mNext->Matches(domainStart))
3504 newEntry->mNext = existingEntry->mNext;
3505 existingEntry->mNext = newEntry;
3506 break;
3508 existingEntry = existingEntry->mNext;
3510 if (!existingEntry->mNext)
3511 existingEntry->mNext = newEntry;
3514 domainStart = domainCurrent + 1;
3515 lastDot = nextToLastDot = nsnull;
3517 else if (*domainCurrent == '.')
3519 nextToLastDot = lastDot;
3520 lastDot = domainCurrent;
3522 domainCurrent++;
3525 rv = InitDomainPolicy(cx, nameBegin, domainPolicy);
3526 domainPolicy->Drop();
3527 if (NS_FAILED(rv))
3528 return rv;
3531 // Reset the "dirty" flag
3532 mPolicyPrefsChanged = PR_FALSE;
3534 #ifdef DEBUG_CAPS_HACKER
3535 PrintPolicyDB();
3536 #endif
3537 return NS_OK;
3541 nsresult
3542 nsScriptSecurityManager::InitDomainPolicy(JSContext* cx,
3543 const char* aPolicyName,
3544 DomainPolicy* aDomainPolicy)
3546 nsresult rv;
3547 nsCAutoString policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix) +
3548 nsDependentCString(aPolicyName) +
3549 NS_LITERAL_CSTRING("."));
3550 PRUint32 prefixLength = policyPrefix.Length() - 1; // subtract the '.'
3552 PRUint32 prefCount;
3553 char** prefNames;
3554 rv = mPrefBranch->GetChildList(policyPrefix.get(),
3555 &prefCount, &prefNames);
3556 if (NS_FAILED(rv)) return rv;
3557 if (prefCount == 0)
3558 return NS_OK;
3560 //-- Populate the policy
3561 PRUint32 currentPref = 0;
3562 for (; currentPref < prefCount; currentPref++)
3564 // Get the class name
3565 const char* start = prefNames[currentPref] + prefixLength + 1;
3566 char* end = PL_strchr(start, '.');
3567 if (!end) // malformed pref, bail on this one
3568 continue;
3569 static const char sitesStr[] = "sites";
3571 // We dealt with "sites" in InitPolicies(), so no need to do
3572 // that again...
3573 if (PL_strncmp(start, sitesStr, sizeof(sitesStr)-1) == 0)
3574 continue;
3576 // Get the pref value
3577 nsXPIDLCString prefValue;
3578 rv = mSecurityPref->SecurityGetCharPref(prefNames[currentPref],
3579 getter_Copies(prefValue));
3580 if (NS_FAILED(rv) || !prefValue)
3581 continue;
3583 SecurityLevel secLevel;
3584 if (PL_strcasecmp(prefValue, "noAccess") == 0)
3585 secLevel.level = SCRIPT_SECURITY_NO_ACCESS;
3586 else if (PL_strcasecmp(prefValue, "allAccess") == 0)
3587 secLevel.level = SCRIPT_SECURITY_ALL_ACCESS;
3588 else if (PL_strcasecmp(prefValue, "sameOrigin") == 0)
3589 secLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
3590 else
3591 { //-- pref value is the name of a capability
3592 nsCStringKey secLevelKey(prefValue);
3593 secLevel.capability =
3594 reinterpret_cast<char*>(mCapabilities->Get(&secLevelKey));
3595 if (!secLevel.capability)
3597 secLevel.capability = NS_strdup(prefValue);
3598 if (!secLevel.capability)
3599 break;
3600 mCapabilities->Put(&secLevelKey,
3601 secLevel.capability);
3605 *end = '\0';
3606 // Find or store this class in the classes table
3607 ClassPolicy* cpolicy =
3608 static_cast<ClassPolicy*>
3609 (PL_DHashTableOperate(aDomainPolicy, start,
3610 PL_DHASH_ADD));
3611 if (!cpolicy)
3612 break;
3614 // If this is the wildcard class (class '*'), save it in mWildcardPolicy
3615 // (we leave it stored in the hashtable too to take care of the cleanup)
3616 if ((*start == '*') && (end == start + 1)) {
3617 aDomainPolicy->mWildcardPolicy = cpolicy;
3619 // Make sure that cpolicy knows about aDomainPolicy so it can reset
3620 // the mWildcardPolicy pointer as needed if it gets moved in the
3621 // hashtable.
3622 cpolicy->mDomainWeAreWildcardFor = aDomainPolicy;
3625 // Get the property name
3626 start = end + 1;
3627 end = PL_strchr(start, '.');
3628 if (end)
3629 *end = '\0';
3631 JSAutoRequest ar(cx);
3633 JSString* propertyKey = ::JS_InternString(cx, start);
3634 if (!propertyKey)
3635 return NS_ERROR_OUT_OF_MEMORY;
3637 // Store this property in the class policy
3638 const void* ppkey =
3639 reinterpret_cast<const void*>(STRING_TO_JSVAL(propertyKey));
3640 PropertyPolicy* ppolicy =
3641 static_cast<PropertyPolicy*>
3642 (PL_DHashTableOperate(cpolicy->mPolicy, ppkey,
3643 PL_DHASH_ADD));
3644 if (!ppolicy)
3645 break;
3647 if (end) // The pref specifies an access mode
3649 start = end + 1;
3650 if (PL_strcasecmp(start, "set") == 0)
3651 ppolicy->mSet = secLevel;
3652 else
3653 ppolicy->mGet = secLevel;
3655 else
3657 if (ppolicy->mGet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3658 ppolicy->mGet = secLevel;
3659 if (ppolicy->mSet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3660 ppolicy->mSet = secLevel;
3664 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3665 if (currentPref < prefCount) // Loop exited early because of out-of-memory error
3666 return NS_ERROR_OUT_OF_MEMORY;
3667 return NS_OK;
3671 // XXXbz We should really just get a prefbranch to handle this...
3672 nsresult
3673 nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase,
3674 nsCString& grantedPref,
3675 nsCString& deniedPref,
3676 nsCString& subjectNamePref)
3678 char* lastDot = PL_strrchr(prefBase, '.');
3679 if (!lastDot) return NS_ERROR_FAILURE;
3680 PRInt32 prefLen = lastDot - prefBase + 1;
3682 grantedPref.Assign(prefBase, prefLen);
3683 deniedPref.Assign(prefBase, prefLen);
3684 subjectNamePref.Assign(prefBase, prefLen);
3686 #define GRANTED "granted"
3687 #define DENIED "denied"
3688 #define SUBJECTNAME "subjectName"
3690 grantedPref.AppendLiteral(GRANTED);
3691 if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) {
3692 return NS_ERROR_OUT_OF_MEMORY;
3695 deniedPref.AppendLiteral(DENIED);
3696 if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) {
3697 return NS_ERROR_OUT_OF_MEMORY;
3700 subjectNamePref.AppendLiteral(SUBJECTNAME);
3701 if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) {
3702 return NS_ERROR_OUT_OF_MEMORY;
3705 #undef SUBJECTNAME
3706 #undef DENIED
3707 #undef GRANTED
3709 return NS_OK;
3712 nsresult
3713 nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefNames,
3714 nsISecurityPref* aSecurityPref)
3716 /* This is the principal preference syntax:
3717 * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
3718 * For example:
3719 * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
3720 * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
3721 * user_pref("capability.principal.certificate.p1.denied","Capability3");
3724 /* codebaseTrusted means a codebase principal that can enable capabilities even if
3725 * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
3726 * URLs such as HTTPS URLs.
3729 static const char idSuffix[] = ".id";
3730 for (PRUint32 c = 0; c < aPrefCount; c++)
3732 PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) -
3733 (NS_ARRAY_LENGTH(idSuffix) - 1);
3734 if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0)
3735 continue;
3737 nsXPIDLCString id;
3738 if (NS_FAILED(mSecurityPref->SecurityGetCharPref(aPrefNames[c], getter_Copies(id))))
3739 return NS_ERROR_FAILURE;
3741 nsCAutoString grantedPrefName;
3742 nsCAutoString deniedPrefName;
3743 nsCAutoString subjectNamePrefName;
3744 nsresult rv = GetPrincipalPrefNames(aPrefNames[c],
3745 grantedPrefName,
3746 deniedPrefName,
3747 subjectNamePrefName);
3748 if (rv == NS_ERROR_OUT_OF_MEMORY)
3749 return rv;
3750 if (NS_FAILED(rv))
3751 continue;
3753 nsXPIDLCString grantedList;
3754 mSecurityPref->SecurityGetCharPref(grantedPrefName.get(),
3755 getter_Copies(grantedList));
3756 nsXPIDLCString deniedList;
3757 mSecurityPref->SecurityGetCharPref(deniedPrefName.get(),
3758 getter_Copies(deniedList));
3759 nsXPIDLCString subjectName;
3760 mSecurityPref->SecurityGetCharPref(subjectNamePrefName.get(),
3761 getter_Copies(subjectName));
3763 //-- Delete prefs if their value is the empty string
3764 if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty()))
3766 mSecurityPref->SecurityClearUserPref(aPrefNames[c]);
3767 mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
3768 mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
3769 mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
3770 continue;
3773 //-- Create a principal based on the prefs
3774 static const char certificateName[] = "capability.principal.certificate";
3775 static const char codebaseName[] = "capability.principal.codebase";
3776 static const char codebaseTrustedName[] = "capability.principal.codebaseTrusted";
3778 PRBool isCert = PR_FALSE;
3779 PRBool isTrusted = PR_FALSE;
3781 if (PL_strncmp(aPrefNames[c], certificateName,
3782 sizeof(certificateName) - 1) == 0)
3784 isCert = PR_TRUE;
3786 else if (PL_strncmp(aPrefNames[c], codebaseName,
3787 sizeof(codebaseName) - 1) == 0)
3789 isTrusted = (PL_strncmp(aPrefNames[c], codebaseTrustedName,
3790 sizeof(codebaseTrustedName) - 1) == 0);
3792 else
3794 NS_ERROR("Not a codebase or a certificate?!");
3797 nsRefPtr<nsPrincipal> newPrincipal = new nsPrincipal();
3798 if (!newPrincipal)
3799 return NS_ERROR_OUT_OF_MEMORY;
3801 rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
3802 EmptyCString(),
3803 grantedList, deniedList, nsnull,
3804 isCert, isTrusted);
3805 if (NS_SUCCEEDED(rv))
3806 mPrincipals.Put(newPrincipal, newPrincipal);
3808 return NS_OK;
3811 const char nsScriptSecurityManager::sJSEnabledPrefName[] =
3812 "javascript.enabled";
3813 const char nsScriptSecurityManager::sJSMailEnabledPrefName[] =
3814 "javascript.allow.mailnews";
3815 const char nsScriptSecurityManager::sFileOriginPolicyPrefName[] =
3816 "security.fileuri.strict_origin_policy";
3817 #ifdef XPC_IDISPATCH_SUPPORT
3818 const char nsScriptSecurityManager::sXPCDefaultGrantAllName[] =
3819 "security.classID.allowByDefault";
3820 #endif
3822 inline void
3823 nsScriptSecurityManager::ScriptSecurityPrefChanged()
3825 PRBool temp;
3826 nsresult rv = mSecurityPref->SecurityGetBoolPref(sJSEnabledPrefName, &temp);
3827 // JavaScript defaults to enabled in failure cases.
3828 mIsJavaScriptEnabled = NS_FAILED(rv) || temp;
3830 rv = mSecurityPref->SecurityGetBoolPref(sJSMailEnabledPrefName, &temp);
3831 // JavaScript in Mail defaults to disabled in failure cases.
3832 // disable javascript in mailnews for TB 3.0 beta1
3833 mIsMailJavaScriptEnabled = PR_FALSE; // NS_SUCCEEDED(rv) && temp;
3835 rv = mSecurityPref->SecurityGetBoolPref(sFileOriginPolicyPrefName, &temp);
3836 sStrictFileOriginPolicy = NS_SUCCEEDED(rv) && temp;
3838 #ifdef XPC_IDISPATCH_SUPPORT
3839 rv = mSecurityPref->SecurityGetBoolPref(sXPCDefaultGrantAllName, &temp);
3840 // Granting XPC Priveleges defaults to disabled in failure cases.
3841 mXPCDefaultGrantAll = NS_SUCCEEDED(rv) && temp;
3842 #endif
3845 nsresult
3846 nsScriptSecurityManager::InitPrefs()
3848 nsresult rv;
3849 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
3850 NS_ENSURE_SUCCESS(rv, rv);
3851 rv = prefService->GetBranch(nsnull, getter_AddRefs(mPrefBranch));
3852 NS_ENSURE_SUCCESS(rv, rv);
3853 nsCOMPtr<nsIPrefBranch2> prefBranchInternal(do_QueryInterface(mPrefBranch, &rv));
3854 NS_ENSURE_SUCCESS(rv, rv);
3855 mSecurityPref = do_QueryInterface(mPrefBranch, &rv);
3856 NS_ENSURE_SUCCESS(rv, rv);
3858 // Set the initial value of the "javascript.enabled" prefs
3859 ScriptSecurityPrefChanged();
3860 // set observer callbacks in case the value of the prefs change
3861 prefBranchInternal->AddObserver(sJSEnabledPrefName, this, PR_FALSE);
3862 prefBranchInternal->AddObserver(sJSMailEnabledPrefName, this, PR_FALSE);
3863 prefBranchInternal->AddObserver(sFileOriginPolicyPrefName, this, PR_FALSE);
3864 #ifdef XPC_IDISPATCH_SUPPORT
3865 prefBranchInternal->AddObserver(sXPCDefaultGrantAllName, this, PR_FALSE);
3866 #endif
3867 PRUint32 prefCount;
3868 char** prefNames;
3870 // Set a callback for policy pref changes
3871 prefBranchInternal->AddObserver(sPolicyPrefix, this, PR_FALSE);
3873 //-- Initialize the principals database from prefs
3874 rv = mPrefBranch->GetChildList(sPrincipalPrefix, &prefCount, &prefNames);
3875 if (NS_SUCCEEDED(rv) && prefCount > 0)
3877 rv = InitPrincipals(prefCount, (const char**)prefNames, mSecurityPref);
3878 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3879 NS_ENSURE_SUCCESS(rv, rv);
3881 //-- Set a callback for principal changes
3882 prefBranchInternal->AddObserver(sPrincipalPrefix, this, PR_FALSE);
3884 return NS_OK;
3887 ///////////////////////////////////////////////////////////////////////////////
3888 // The following code prints the contents of the policy DB to the console.
3889 #ifdef DEBUG_CAPS_HACKER
3891 //typedef PLDHashOperator
3892 //(* PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
3893 // PRUint32 number, void *arg);
3894 static PLDHashOperator
3895 PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3896 PRUint32 number, void *arg)
3898 PropertyPolicy* pp = (PropertyPolicy*)entry;
3899 nsCAutoString prop(" ");
3900 JSContext* cx = (JSContext*)arg;
3901 prop.AppendInt((PRUint32)pp->key);
3902 prop += ' ';
3903 prop.AppendWithConversion((PRUnichar*)JSValIDToString(cx, pp->key));
3904 prop += ": Get=";
3905 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet))
3906 prop.AppendInt(pp->mGet.level);
3907 else
3908 prop += pp->mGet.capability;
3910 prop += " Set=";
3911 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mSet))
3912 prop.AppendInt(pp->mSet.level);
3913 else
3914 prop += pp->mSet.capability;
3916 printf("%s.\n", prop.get());
3917 return PL_DHASH_NEXT;
3920 static PLDHashOperator
3921 PrintClassPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3922 PRUint32 number, void *arg)
3924 ClassPolicy* cp = (ClassPolicy*)entry;
3925 printf(" %s\n", cp->key);
3927 PL_DHashTableEnumerate(cp->mPolicy, PrintPropertyPolicy, arg);
3928 return PL_DHASH_NEXT;
3931 // typedef PRBool
3932 // (* nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
3933 static PRBool
3934 PrintDomainPolicy(nsHashKey *aKey, void *aData, void* aClosure)
3936 DomainEntry* de = (DomainEntry*)aData;
3937 printf("----------------------------\n");
3938 printf("Domain: %s Policy Name: %s.\n", de->mOrigin.get(),
3939 de->mPolicyName_DEBUG.get());
3940 PL_DHashTableEnumerate(de->mDomainPolicy, PrintClassPolicy, aClosure);
3941 return PR_TRUE;
3944 static PRBool
3945 PrintCapability(nsHashKey *aKey, void *aData, void* aClosure)
3947 char* cap = (char*)aData;
3948 printf(" %s.\n", cap);
3949 return PR_TRUE;
3952 void
3953 nsScriptSecurityManager::PrintPolicyDB()
3955 printf("############## Security Policies ###############\n");
3956 if(mOriginToPolicyMap)
3958 JSContext* cx = GetCurrentJSContext();
3959 if (!cx)
3960 cx = GetSafeJSContext();
3961 printf("----------------------------\n");
3962 printf("Domain: Default.\n");
3963 PL_DHashTableEnumerate(mDefaultPolicy, PrintClassPolicy, (void*)cx);
3964 mOriginToPolicyMap->Enumerate(PrintDomainPolicy, (void*)cx);
3966 printf("############ End Security Policies #############\n\n");
3967 printf("############## Capabilities ###############\n");
3968 mCapabilities->Enumerate(PrintCapability);
3969 printf("############## End Capabilities ###############\n");
3971 #endif