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
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.
26 * Christopher A. Aillon
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"
48 #include "nsINestedURI.h"
50 #include "nsJSPrincipals.h"
51 #include "nsSystemPrincipal.h"
52 #include "nsPrincipal.h"
53 #include "nsNullPrincipal.h"
54 #include "nsXPIDLString.h"
56 #include "nsCRTGlue.h"
57 #include "nsIJSContextStack.h"
58 #include "nsDOMError.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"
72 #include "nsIFileURL.h"
73 #include "nsIZipReader.h"
75 #include "nsIPluginInstance.h"
76 #include "nsIXPConnect.h"
77 #include "nsIScriptGlobalObject.h"
78 #include "nsPIDOMWindow.h"
79 #include "nsIDocShell.h"
80 #include "nsIDocShellTreeItem.h"
81 #include "nsIPrompt.h"
82 #include "nsIWindowWatcher.h"
83 #include "nsIConsoleService.h"
84 #include "nsISecurityCheckedComponent.h"
85 #include "nsIPrefBranch2.h"
86 #include "nsIJSRuntimeService.h"
87 #include "nsIObserverService.h"
88 #include "nsIContent.h"
89 #include "nsAutoPtr.h"
90 #include "nsDOMJSUtils.h"
91 #include "nsAboutProtocolUtils.h"
92 #include "nsIClassInfo.h"
93 #include "nsIURIFixup.h"
94 #include "nsCDefaultURIFixup.h"
95 #include "nsIChromeRegistry.h"
97 static NS_DEFINE_CID(kZipReaderCID
, NS_ZIPREADER_CID
);
99 nsIIOService
*nsScriptSecurityManager::sIOService
= nsnull
;
100 nsIXPConnect
*nsScriptSecurityManager::sXPConnect
= nsnull
;
101 nsIStringBundle
*nsScriptSecurityManager::sStrBundle
= nsnull
;
102 JSRuntime
*nsScriptSecurityManager::sRuntime
= 0;
103 PRBool
nsScriptSecurityManager::sStrictFileOriginPolicy
= PR_TRUE
;
105 // Info we need about the JSClasses used by XPConnects wrapped
106 // natives, to avoid having to QI to nsIXPConnectWrappedNative all the
107 // time when doing security checks.
108 static const JSClass
*sXPCWrappedNativeJSClass
;
109 static JSGetObjectOps sXPCWrappedNativeGetObjOps1
;
110 static JSGetObjectOps sXPCWrappedNativeGetObjOps2
;
113 ///////////////////////////
114 // Convenience Functions //
115 ///////////////////////////
116 // Result of this function should not be freed.
117 static inline const PRUnichar
*
118 JSValIDToString(JSContext
*cx
, const jsval idval
)
120 JSAutoRequest
ar(cx
);
121 JSString
*str
= JS_ValueToString(cx
, idval
);
124 return reinterpret_cast<PRUnichar
*>(JS_GetStringChars(str
));
127 // Inline copy of JS_GetPrivate() for better inlining and optimization
128 // possibilities. Also doesn't take a cx argument as it's not
129 // needed. We access the private data only on objects whose private
130 // data is not expected to change during the lifetime of the object,
131 // so thus we won't worry about locking and holding on to slot values
132 // etc while referencing private data.
134 caps_GetJSPrivate(JSObject
*obj
)
138 JS_ASSERT(STOBJ_GET_CLASS(obj
)->flags
& JSCLASS_HAS_PRIVATE
);
139 v
= obj
->fslots
[JSSLOT_PRIVATE
];
140 if (!JSVAL_IS_INT(v
))
142 return JSVAL_TO_PRIVATE(v
);
145 static nsIScriptContext
*
146 GetScriptContext(JSContext
*cx
)
148 return GetScriptContextFromJSContext(cx
);
151 inline void SetPendingException(JSContext
*cx
, const char *aMsg
)
153 JSAutoRequest
ar(cx
);
154 JS_ReportError(cx
, "%s", aMsg
);
157 inline void SetPendingException(JSContext
*cx
, const PRUnichar
*aMsg
)
159 JSAutoRequest
ar(cx
);
160 JS_ReportError(cx
, "%hs", aMsg
);
163 // DomainPolicy members
164 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
165 PRUint32
DomainPolicy::sObjects
=0;
166 void DomainPolicy::_printPopulationInfo()
168 printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
169 sGeneration
, sObjects
);
172 PRUint32
DomainPolicy::sGeneration
= 0;
174 // Helper class to get stuff from the ClassInfo and not waste extra time with
175 // virtual method calls for things it has already gotten
179 ClassInfoData(nsIClassInfo
*aClassInfo
, const char *aName
)
180 : mClassInfo(aClassInfo
),
181 mName(const_cast<char *>(aName
)),
182 mDidGetFlags(PR_FALSE
),
183 mMustFreeName(PR_FALSE
)
190 nsMemory::Free(mName
);
197 nsresult rv
= mClassInfo
->GetFlags(&mFlags
);
205 mDidGetFlags
= PR_TRUE
;
213 return !!(GetFlags() & nsIClassInfo::DOM_OBJECT
);
216 PRBool
IsContentNode()
218 return !!(GetFlags() & nsIClassInfo::CONTENT_NODE
);
221 const char* GetName()
225 mClassInfo
->GetClassDescription(&mName
);
229 mMustFreeName
= PR_TRUE
;
231 mName
= const_cast<char *>("UnnamedClass");
239 nsIClassInfo
*mClassInfo
; // WEAK
242 PRPackedBool mDidGetFlags
;
243 PRPackedBool mMustFreeName
;
247 nsScriptSecurityManager::GetCurrentJSContext()
249 // Get JSContext from stack.
250 if (!mJSContextStack
)
252 mJSContextStack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1");
253 if (!mJSContextStack
)
257 if (NS_FAILED(mJSContextStack
->Peek(&cx
)))
263 nsScriptSecurityManager::GetSafeJSContext()
265 // Get JSContext from stack.
266 if (!mJSContextStack
) {
267 mJSContextStack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1");
268 if (!mJSContextStack
)
273 if (NS_FAILED(mJSContextStack
->GetSafeJSContext(&cx
)))
280 nsScriptSecurityManager::SecurityCompareURIs(nsIURI
* aSourceURI
,
283 // Note that this is not an Equals() test on purpose -- for URIs that don't
284 // support host/port, we want equality to basically be object identity, for
285 // security purposes. Otherwise, for example, two javascript: URIs that
286 // are otherwise unrelated could end up "same origin", which would be
288 if (aSourceURI
&& aSourceURI
== aTargetURI
)
293 if (!aTargetURI
|| !aSourceURI
)
298 // If either URI is a nested URI, get the base URI
299 nsCOMPtr
<nsIURI
> sourceBaseURI
= NS_GetInnermostURI(aSourceURI
);
300 nsCOMPtr
<nsIURI
> targetBaseURI
= NS_GetInnermostURI(aTargetURI
);
302 if (!sourceBaseURI
|| !targetBaseURI
)
306 nsCAutoString targetScheme
;
307 PRBool sameScheme
= PR_FALSE
;
308 if (NS_FAILED( targetBaseURI
->GetScheme(targetScheme
) ) ||
309 NS_FAILED( sourceBaseURI
->SchemeIs(targetScheme
.get(), &sameScheme
) ) ||
312 // Not same-origin if schemes differ
316 // special handling for file: URIs
317 if (targetScheme
.EqualsLiteral("file"))
319 // in traditional unsafe behavior all files are the same origin
320 if (!sStrictFileOriginPolicy
)
323 nsCOMPtr
<nsIFileURL
> sourceFileURL(do_QueryInterface(sourceBaseURI
));
324 nsCOMPtr
<nsIFileURL
> targetFileURL(do_QueryInterface(targetBaseURI
));
326 if (!sourceFileURL
|| !targetFileURL
)
329 nsCOMPtr
<nsIFile
> sourceFile
, targetFile
;
331 sourceFileURL
->GetFile(getter_AddRefs(sourceFile
));
332 targetFileURL
->GetFile(getter_AddRefs(targetFile
));
334 if (!sourceFile
|| !targetFile
)
337 // Otherwise they had better match
338 PRBool filesAreEqual
= PR_FALSE
;
339 nsresult rv
= sourceFile
->Equals(targetFile
, &filesAreEqual
);
340 return NS_SUCCEEDED(rv
) && filesAreEqual
;
343 // Special handling for mailnews schemes
344 if (targetScheme
.EqualsLiteral("imap") ||
345 targetScheme
.EqualsLiteral("mailbox") ||
346 targetScheme
.EqualsLiteral("news"))
348 // Each message is a distinct trust domain; use the
349 // whole spec for comparison
350 nsCAutoString targetSpec
;
351 nsCAutoString sourceSpec
;
352 return ( NS_SUCCEEDED( targetBaseURI
->GetSpec(targetSpec
) ) &&
353 NS_SUCCEEDED( sourceBaseURI
->GetSpec(sourceSpec
) ) &&
354 targetSpec
.Equals(sourceSpec
) );
358 nsCAutoString targetHost
;
359 nsCAutoString sourceHost
;
360 if (NS_FAILED( targetBaseURI
->GetHost(targetHost
) ) ||
361 NS_FAILED( sourceBaseURI
->GetHost(sourceHost
) ) ||
362 !targetHost
.Equals(sourceHost
, nsCaseInsensitiveCStringComparator()))
364 // Not same-origin if hosts differ
370 nsresult rv
= targetBaseURI
->GetPort(&targetPort
);
372 if (NS_SUCCEEDED(rv
))
373 rv
= sourceBaseURI
->GetPort(&sourcePort
);
374 PRBool result
= NS_SUCCEEDED(rv
) && targetPort
== sourcePort
;
375 // If the port comparison failed, see if either URL has a
376 // port of -1. If so, replace -1 with the default port
378 if (NS_SUCCEEDED(rv
) && !result
&&
379 (sourcePort
== -1 || targetPort
== -1))
381 NS_ENSURE_TRUE(sIOService
, PR_FALSE
);
383 PRInt32 defaultPort
= NS_GetDefaultPort(targetScheme
.get());
384 if (defaultPort
== -1)
385 return PR_FALSE
; // No default port for this scheme
387 if (sourcePort
== -1)
388 sourcePort
= defaultPort
;
389 else if (targetPort
== -1)
390 targetPort
= defaultPort
;
391 result
= targetPort
== sourcePort
;
398 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel
* aChannel
,
399 nsIPrincipal
** aPrincipal
)
401 NS_PRECONDITION(aChannel
, "Must have channel!");
402 nsCOMPtr
<nsISupports
> owner
;
403 aChannel
->GetOwner(getter_AddRefs(owner
));
405 CallQueryInterface(owner
, aPrincipal
);
411 // OK, get the principal from the URI. Make sure this does the same thing
412 // as nsDocument::Reset and nsXULDocument::StartDocumentLoad.
413 nsCOMPtr
<nsIURI
> uri
;
414 nsresult rv
= NS_GetFinalChannelURI(aChannel
, getter_AddRefs(uri
));
415 NS_ENSURE_SUCCESS(rv
, rv
);
417 return GetCodebasePrincipal(uri
, aPrincipal
);
421 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal
* aPrincipal
,
424 *aIsSystem
= (aPrincipal
== mSystemPrincipal
);
428 NS_IMETHODIMP_(nsIPrincipal
*)
429 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext
*cx
)
431 NS_ASSERTION(cx
== GetCurrentJSContext(),
432 "Uh, cx is not the current JS context!");
434 nsresult rv
= NS_ERROR_FAILURE
;
435 nsIPrincipal
*principal
= GetSubjectPrincipal(cx
, &rv
);
446 // Table of security levels
447 PR_STATIC_CALLBACK(PRBool
)
448 DeleteCapability(nsHashKey
*aKey
, void *aData
, void* closure
)
454 //-- Per-Domain Policy - applies to one or more protocols or hosts
457 DomainEntry(const char* aOrigin
,
458 DomainPolicy
* aDomainPolicy
) : mOrigin(aOrigin
),
459 mDomainPolicy(aDomainPolicy
),
462 mDomainPolicy
->Hold();
467 mDomainPolicy
->Drop();
470 PRBool
Matches(const char *anOrigin
)
472 int len
= strlen(anOrigin
);
473 int thisLen
= mOrigin
.Length();
476 if (mOrigin
.RFindChar(':', thisLen
-1, 1) != -1)
477 //-- Policy applies to all URLs of this scheme, compare scheme only
478 return mOrigin
.EqualsIgnoreCase(anOrigin
, thisLen
);
480 //-- Policy applies to a particular host; compare domains
481 if (!mOrigin
.Equals(anOrigin
+ (len
- thisLen
)))
485 char charBefore
= anOrigin
[len
-thisLen
-1];
486 return (charBefore
== '.' || charBefore
== ':' || charBefore
== '/');
490 DomainPolicy
* mDomainPolicy
;
492 #if defined(DEBUG) || defined(DEBUG_CAPS_HACKER)
493 nsCString mPolicyName_DEBUG
;
497 PR_STATIC_CALLBACK(PRBool
)
498 DeleteDomainEntry(nsHashKey
*aKey
, void *aData
, void* closure
)
500 DomainEntry
*entry
= (DomainEntry
*) aData
;
503 DomainEntry
*next
= entry
->mNext
;
510 /////////////////////////////
511 // nsScriptSecurityManager //
512 /////////////////////////////
514 ////////////////////////////////////
515 // Methods implementing ISupports //
516 ////////////////////////////////////
517 NS_IMPL_ISUPPORTS5(nsScriptSecurityManager
,
518 nsIScriptSecurityManager
,
519 nsIXPCSecurityManager
,
520 nsIPrefSecurityCheck
,
524 ///////////////////////////////////////////////////
525 // Methods implementing nsIScriptSecurityManager //
526 ///////////////////////////////////////////////////
528 ///////////////// Security Checks /////////////////
529 JSBool JS_DLL_CALLBACK
530 nsScriptSecurityManager::CheckObjectAccess(JSContext
*cx
, JSObject
*obj
,
531 jsval id
, JSAccessMode mode
,
534 // Get the security manager
535 nsScriptSecurityManager
*ssm
=
536 nsScriptSecurityManager::GetScriptSecurityManager();
538 NS_ASSERTION(ssm
, "Failed to get security manager service");
542 // Get the object being accessed. We protect these cases:
543 // 1. The Function.prototype.caller property's value, which might lead
544 // an attacker up a call-stack to a function or another object from
545 // a different trust domain.
546 // 2. A user-defined getter or setter function accessible on another
547 // trust domain's window or document object.
548 // *vp can be a primitive, in that case, we use obj as the target
550 JSObject
* target
= JSVAL_IS_PRIMITIVE(*vp
) ? obj
: JSVAL_TO_OBJECT(*vp
);
552 // Do the same-origin check -- this sets a JS exception if the check fails.
553 // Pass the parent object's class name, as we have no class-info for it.
555 ssm
->CheckPropertyAccess(cx
, target
, STOBJ_GET_CLASS(obj
)->name
, id
,
556 (mode
& JSACC_WRITE
) ?
557 nsIXPCSecurityManager::ACCESS_SET_PROPERTY
:
558 nsIXPCSecurityManager::ACCESS_GET_PROPERTY
);
561 return JS_FALSE
; // Security check failed (XXX was an error reported?)
567 nsScriptSecurityManager::CheckPropertyAccess(JSContext
* cx
,
569 const char* aClassName
,
573 return CheckPropertyAccessImpl(aAction
, nsnull
, cx
, aJSObject
,
574 nsnull
, nsnull
, nsnull
,
575 aClassName
, aProperty
, nsnull
);
579 nsScriptSecurityManager::CheckConnect(JSContext
* cx
,
581 const char* aClassName
,
582 const char* aPropertyName
)
584 // Get a context if necessary
587 cx
= GetCurrentJSContext();
589 return NS_OK
; // No JS context, so allow the load
592 nsresult rv
= CheckLoadURIFromScript(cx
, aTargetURI
);
593 if (NS_FAILED(rv
)) return rv
;
595 JSAutoRequest
ar(cx
);
597 JSString
* propertyName
= ::JS_InternString(cx
, aPropertyName
);
599 return NS_ERROR_OUT_OF_MEMORY
;
601 return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD
, nsnull
,
602 cx
, nsnull
, nsnull
, aTargetURI
,
603 nsnull
, aClassName
, STRING_TO_JSVAL(propertyName
), nsnull
);
607 nsScriptSecurityManager::CheckSameOrigin(JSContext
* cx
,
612 // Get a context if necessary
615 cx
= GetCurrentJSContext();
617 return NS_OK
; // No JS context, so allow access
620 // Get a principal from the context
621 nsIPrincipal
* sourcePrincipal
= GetSubjectPrincipal(cx
, &rv
);
625 if (!sourcePrincipal
)
627 NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
631 if (sourcePrincipal
== mSystemPrincipal
)
633 // This is a system (chrome) script, so allow access
637 // Get the original URI from the source principal.
638 // This has the effect of ignoring any change to document.domain
639 // which must be done to avoid DNS spoofing (bug 154930)
640 nsCOMPtr
<nsIURI
> sourceURI
;
641 sourcePrincipal
->GetDomain(getter_AddRefs(sourceURI
));
643 sourcePrincipal
->GetURI(getter_AddRefs(sourceURI
));
644 NS_ENSURE_TRUE(sourceURI
, NS_ERROR_FAILURE
);
648 if (!SecurityCompareURIs(sourceURI
, aTargetURI
))
650 ReportError(cx
, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI
, aTargetURI
);
651 return NS_ERROR_DOM_BAD_URI
;
657 nsScriptSecurityManager::CheckSameOriginURI(nsIURI
* aSourceURI
,
661 if (!SecurityCompareURIs(aSourceURI
, aTargetURI
))
664 ReportError(nsnull
, NS_LITERAL_STRING("CheckSameOriginError"),
665 aSourceURI
, aTargetURI
);
667 return NS_ERROR_DOM_BAD_URI
;
673 nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction
,
674 nsAXPCNativeCallContext
* aCallContext
,
675 JSContext
* cx
, JSObject
* aJSObject
,
676 nsISupports
* aObj
, nsIURI
* aTargetURI
,
677 nsIClassInfo
* aClassInfo
,
678 const char* aClassName
, jsval aProperty
,
679 void** aCachedClassPolicy
)
682 nsIPrincipal
* subjectPrincipal
= GetSubjectPrincipal(cx
, &rv
);
686 if (!subjectPrincipal
|| subjectPrincipal
== mSystemPrincipal
)
687 // We have native code or the system principal: just allow access
690 // Hold the class info data here so we don't have to go back to virtual
691 // methods all the time
692 ClassInfoData
classInfoData(aClassInfo
, aClassName
);
693 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
694 nsCAutoString propertyName
;
695 propertyName
.AssignWithConversion((PRUnichar
*)JSValIDToString(cx
, aProperty
));
696 printf("### CanAccess(%s.%s, %i) ", classInfoData
.GetName(),
697 propertyName
.get(), aAction
);
700 //-- Look up the security policy for this class and subject domain
701 SecurityLevel securityLevel
;
702 rv
= LookupPolicy(subjectPrincipal
, classInfoData
, aProperty
, aAction
,
703 (ClassPolicy
**)aCachedClassPolicy
, &securityLevel
);
707 if (securityLevel
.level
== SCRIPT_SECURITY_UNDEFINED_ACCESS
)
709 // No policy found for this property so use the default of last resort.
710 // If we were called from somewhere other than XPConnect
711 // (no XPC call context), assume this is a DOM class. Otherwise,
712 // ask the ClassInfo.
713 if (!aCallContext
|| classInfoData
.IsDOMClass())
714 securityLevel
.level
= SCRIPT_SECURITY_SAME_ORIGIN_ACCESS
;
716 securityLevel
.level
= SCRIPT_SECURITY_NO_ACCESS
;
719 if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel
))
720 // This flag means securityLevel is allAccess, noAccess, or sameOrigin
722 switch (securityLevel
.level
)
724 case SCRIPT_SECURITY_NO_ACCESS
:
725 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
728 rv
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
731 case SCRIPT_SECURITY_ALL_ACCESS
:
732 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
733 printf("allAccess ");
738 case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS
:
740 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
741 printf("sameOrigin ");
743 nsCOMPtr
<nsIPrincipal
> principalHolder
;
744 nsIPrincipal
*objectPrincipal
;
747 objectPrincipal
= doGetObjectPrincipal(aJSObject
);
748 if (!objectPrincipal
)
749 rv
= NS_ERROR_DOM_SECURITY_ERR
;
753 if (NS_FAILED(GetCodebasePrincipal(
754 aTargetURI
, getter_AddRefs(principalHolder
))))
755 return NS_ERROR_FAILURE
;
757 objectPrincipal
= principalHolder
;
761 NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
762 return NS_ERROR_FAILURE
;
765 rv
= CheckSameOriginDOMProp(subjectPrincipal
, objectPrincipal
,
766 aAction
, aTargetURI
!= nsnull
);
770 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
773 NS_ERROR("Bad Security Level Value");
774 return NS_ERROR_FAILURE
;
777 else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
779 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
780 printf("Cap:%s ", securityLevel
.capability
);
782 PRBool capabilityEnabled
= PR_FALSE
;
783 rv
= IsCapabilityEnabled(securityLevel
.capability
, &capabilityEnabled
);
784 if (NS_FAILED(rv
) || !capabilityEnabled
)
785 rv
= NS_ERROR_DOM_SECURITY_ERR
;
790 if (NS_SUCCEEDED(rv
) && classInfoData
.IsContentNode())
792 // No access to anonymous content from the web! (bug 164086)
793 nsIContent
*content
= static_cast<nsIContent
*>(aObj
);
794 if (content
->IsInNativeAnonymousSubtree()) {
795 rv
= NS_ERROR_DOM_SECURITY_ERR
;
799 if (NS_SUCCEEDED(rv
))
801 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
802 printf(" GRANTED.\n");
807 //--See if the object advertises a non-default level of access
808 // using nsISecurityCheckedComponent
809 nsCOMPtr
<nsISecurityCheckedComponent
> checkedComponent
=
810 do_QueryInterface(aObj
);
812 nsXPIDLCString objectSecurityLevel
;
813 if (checkedComponent
)
815 nsCOMPtr
<nsIXPConnectWrappedNative
> wrapper
;
816 nsCOMPtr
<nsIInterfaceInfo
> interfaceInfo
;
818 rv
= aCallContext
->GetCalleeWrapper(getter_AddRefs(wrapper
));
819 if (NS_SUCCEEDED(rv
))
820 rv
= wrapper
->FindInterfaceWithMember(aProperty
, getter_AddRefs(interfaceInfo
));
821 if (NS_SUCCEEDED(rv
))
822 rv
= interfaceInfo
->GetIIDShared(&objIID
);
823 if (NS_SUCCEEDED(rv
))
827 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY
:
828 checkedComponent
->CanGetProperty(objIID
,
829 JSValIDToString(cx
, aProperty
),
830 getter_Copies(objectSecurityLevel
));
832 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY
:
833 checkedComponent
->CanSetProperty(objIID
,
834 JSValIDToString(cx
, aProperty
),
835 getter_Copies(objectSecurityLevel
));
837 case nsIXPCSecurityManager::ACCESS_CALL_METHOD
:
838 checkedComponent
->CanCallMethod(objIID
,
839 JSValIDToString(cx
, aProperty
),
840 getter_Copies(objectSecurityLevel
));
844 rv
= CheckXPCPermissions(aObj
, objectSecurityLevel
);
845 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
847 printf("CheckXPCPerms GRANTED.\n");
849 printf("CheckXPCPerms DENIED.\n");
852 if (NS_FAILED(rv
)) //-- Security tests failed, access is denied, report error
854 nsAutoString stringName
;
857 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY
:
858 stringName
.AssignLiteral("GetPropertyDenied");
860 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY
:
861 stringName
.AssignLiteral("SetPropertyDenied");
863 case nsIXPCSecurityManager::ACCESS_CALL_METHOD
:
864 stringName
.AssignLiteral("CallMethodDenied");
867 NS_ConvertUTF8toUTF16
className(classInfoData
.GetName());
868 const PRUnichar
*formatStrings
[] =
871 JSValIDToString(cx
, aProperty
)
874 nsXPIDLString errorMsg
;
875 // We need to keep our existing failure rv and not override it
876 // with a likely success code from the following string bundle
877 // call in order to throw the correct security exception later.
878 nsresult rv2
= sStrBundle
->FormatStringFromName(stringName
.get(),
880 NS_ARRAY_LENGTH(formatStrings
),
881 getter_Copies(errorMsg
));
882 NS_ENSURE_SUCCESS(rv2
, rv2
);
884 SetPendingException(cx
, errorMsg
.get());
888 nsAXPCNativeCallContext
*xpcCallContext
= nsnull
;
889 sXPConnect
->GetCurrentNativeCallContext(&xpcCallContext
);
891 xpcCallContext
->SetExceptionWasThrown(PR_TRUE
);
900 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal
* aSubject
,
901 nsIPrincipal
* aObject
,
902 PRBool aIsCheckConnect
)
905 ** Get origin of subject and object and compare.
907 if (aSubject
== aObject
)
910 // These booleans are only used when !aIsCheckConnect. Default
911 // them to false, and change if that turns out wrong.
912 PRBool subjectSetDomain
= PR_FALSE
;
913 PRBool objectSetDomain
= PR_FALSE
;
915 nsCOMPtr
<nsIURI
> subjectURI
;
916 nsCOMPtr
<nsIURI
> objectURI
;
920 // Don't use domain for CheckConnect calls, since that's called for
921 // data-only load checks like XMLHTTPRequest (bug 290100).
922 aSubject
->GetURI(getter_AddRefs(subjectURI
));
923 aObject
->GetURI(getter_AddRefs(objectURI
));
927 aSubject
->GetDomain(getter_AddRefs(subjectURI
));
929 aSubject
->GetURI(getter_AddRefs(subjectURI
));
931 subjectSetDomain
= PR_TRUE
;
934 aObject
->GetDomain(getter_AddRefs(objectURI
));
936 aObject
->GetURI(getter_AddRefs(objectURI
));
938 objectSetDomain
= PR_TRUE
;
942 if (SecurityCompareURIs(subjectURI
, objectURI
))
943 { // If either the subject or the object has changed its principal by
944 // explicitly setting document.domain then the other must also have
945 // done so in order to be considered the same origin. This prevents
946 // DNS spoofing based on document.domain (154930)
948 // But this restriction does not apply to CheckConnect calls, since
949 // that's called for data-only load checks like XMLHTTPRequest where
950 // we ignore domain (bug 290100).
954 // If both or neither explicitly set their domain, allow the access
955 if (subjectSetDomain
== objectSetDomain
)
960 ** Access tests failed, so now report error.
962 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
967 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal
* aSubject
,
968 nsIPrincipal
* aObject
,
970 PRBool aIsCheckConnect
)
973 if (aIsCheckConnect
) {
974 // Don't do equality compares, just do a same-origin compare,
975 // since the object principal isn't a real principal, just a
976 // GetCodebasePrincipal() on whatever URI we started with.
977 rv
= CheckSameOriginPrincipal(aSubject
, aObject
, aIsCheckConnect
);
980 rv
= aSubject
->Subsumes(aObject
, &subsumes
);
981 if (NS_SUCCEEDED(rv
) && !subsumes
) {
982 rv
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
986 if (NS_SUCCEEDED(rv
))
990 * Content can't ever touch chrome (we check for UniversalXPConnect later)
992 if (aObject
== mSystemPrincipal
)
993 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
996 * If we failed the origin tests it still might be the case that we
997 * are a signed script and have permissions to do this operation.
998 * Check for that here.
1000 PRBool capabilityEnabled
= PR_FALSE
;
1001 const char* cap
= aAction
== nsIXPCSecurityManager::ACCESS_SET_PROPERTY
?
1002 "UniversalBrowserWrite" : "UniversalBrowserRead";
1003 rv
= IsCapabilityEnabled(cap
, &capabilityEnabled
);
1004 NS_ENSURE_SUCCESS(rv
, rv
);
1005 if (capabilityEnabled
)
1009 ** Access tests failed, so now report error.
1011 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
1016 GetPrincipalDomainOrigin(nsIPrincipal
* aPrincipal
,
1017 nsACString
& aOrigin
)
1021 nsCOMPtr
<nsIURI
> uri
;
1022 aPrincipal
->GetDomain(getter_AddRefs(uri
));
1024 aPrincipal
->GetURI(getter_AddRefs(uri
));
1027 NS_ENSURE_TRUE(uri
, NS_ERROR_UNEXPECTED
);
1029 nsCAutoString hostPort
;
1031 nsresult rv
= uri
->GetHostPort(hostPort
);
1032 if (NS_SUCCEEDED(rv
)) {
1033 nsCAutoString scheme
;
1034 rv
= uri
->GetScheme(scheme
);
1035 NS_ENSURE_SUCCESS(rv
, rv
);
1036 aOrigin
= scheme
+ NS_LITERAL_CSTRING("://") + hostPort
;
1039 // Some URIs (e.g., nsSimpleURI) don't support host. Just
1040 // get the full spec.
1041 rv
= uri
->GetSpec(aOrigin
);
1042 NS_ENSURE_SUCCESS(rv
, rv
);
1049 nsScriptSecurityManager::LookupPolicy(nsIPrincipal
* aPrincipal
,
1050 ClassInfoData
& aClassData
,
1053 ClassPolicy
** aCachedClassPolicy
,
1054 SecurityLevel
* result
)
1057 result
->level
= SCRIPT_SECURITY_UNDEFINED_ACCESS
;
1059 DomainPolicy
* dpolicy
= nsnull
;
1060 //-- Initialize policies if necessary
1061 if (mPolicyPrefsChanged
)
1063 rv
= InitPolicies();
1069 aPrincipal
->GetSecurityPolicy((void**)&dpolicy
);
1072 if (!dpolicy
&& mOriginToPolicyMap
)
1074 //-- Look up the relevant domain policy, if any
1075 #ifdef DEBUG_CAPS_LookupPolicy
1076 printf("DomainLookup ");
1079 nsCAutoString origin
;
1080 rv
= GetPrincipalDomainOrigin(aPrincipal
, origin
);
1081 NS_ENSURE_SUCCESS(rv
, rv
);
1083 char *start
= origin
.BeginWriting();
1084 const char *nextToLastDot
= nsnull
;
1085 const char *lastDot
= nsnull
;
1086 const char *colon
= nsnull
;
1089 //-- search domain (stop at the end of the string or at the 3rd slash)
1090 for (PRUint32 slashes
=0; *p
; p
++)
1092 if (*p
== '/' && ++slashes
== 3)
1094 *p
= '\0'; // truncate at 3rd slash
1099 nextToLastDot
= lastDot
;
1102 else if (!colon
&& *p
== ':')
1106 nsCStringKey
key(nextToLastDot
? nextToLastDot
+1 : start
);
1107 DomainEntry
*de
= (DomainEntry
*) mOriginToPolicyMap
->Get(&key
);
1110 nsCAutoString
scheme(start
, colon
-start
+1);
1111 nsCStringKey
schemeKey(scheme
);
1112 de
= (DomainEntry
*) mOriginToPolicyMap
->Get(&schemeKey
);
1117 if (de
->Matches(start
))
1119 dpolicy
= de
->mDomainPolicy
;
1126 dpolicy
= mDefaultPolicy
;
1128 aPrincipal
->SetSecurityPolicy((void*)dpolicy
);
1131 ClassPolicy
* cpolicy
= nsnull
;
1133 if ((dpolicy
== mDefaultPolicy
) && aCachedClassPolicy
)
1135 // No per-domain policy for this principal (the more common case)
1136 // so look for a cached class policy from the object wrapper
1137 cpolicy
= *aCachedClassPolicy
;
1141 { //-- No cached policy for this class, need to look it up
1142 #ifdef DEBUG_CAPS_LookupPolicy
1143 printf("ClassLookup ");
1146 cpolicy
= static_cast<ClassPolicy
*>
1147 (PL_DHashTableOperate(dpolicy
,
1148 aClassData
.GetName(),
1151 if (PL_DHASH_ENTRY_IS_FREE(cpolicy
))
1152 cpolicy
= NO_POLICY_FOR_CLASS
;
1154 if ((dpolicy
== mDefaultPolicy
) && aCachedClassPolicy
)
1155 *aCachedClassPolicy
= cpolicy
;
1158 // We look for a PropertyPolicy in the following places:
1159 // 1) The ClassPolicy for our class we got from our DomainPolicy
1160 // 2) The mWildcardPolicy of our DomainPolicy
1161 // 3) The ClassPolicy for our class we got from mDefaultPolicy
1162 // 4) The mWildcardPolicy of our mDefaultPolicy
1163 PropertyPolicy
* ppolicy
= nsnull
;
1164 if (cpolicy
!= NO_POLICY_FOR_CLASS
)
1166 ppolicy
= static_cast<PropertyPolicy
*>
1167 (PL_DHashTableOperate(cpolicy
->mPolicy
,
1172 // If there is no class policy for this property, and we have a wildcard
1173 // policy, try that.
1174 if (dpolicy
->mWildcardPolicy
&&
1175 (!ppolicy
|| PL_DHASH_ENTRY_IS_FREE(ppolicy
)))
1178 static_cast<PropertyPolicy
*>
1179 (PL_DHashTableOperate(dpolicy
->mWildcardPolicy
->mPolicy
,
1184 // If dpolicy is not the defauly policy and there's no class or wildcard
1185 // policy for this property, check the default policy for this class and
1186 // the default wildcard policy
1187 if (dpolicy
!= mDefaultPolicy
&&
1188 (!ppolicy
|| PL_DHASH_ENTRY_IS_FREE(ppolicy
)))
1190 cpolicy
= static_cast<ClassPolicy
*>
1191 (PL_DHashTableOperate(mDefaultPolicy
,
1192 aClassData
.GetName(),
1195 if (PL_DHASH_ENTRY_IS_BUSY(cpolicy
))
1198 static_cast<PropertyPolicy
*>
1199 (PL_DHashTableOperate(cpolicy
->mPolicy
,
1204 if ((!ppolicy
|| PL_DHASH_ENTRY_IS_FREE(ppolicy
)) &&
1205 mDefaultPolicy
->mWildcardPolicy
)
1208 static_cast<PropertyPolicy
*>
1209 (PL_DHashTableOperate(mDefaultPolicy
->mWildcardPolicy
->mPolicy
,
1215 if (!ppolicy
|| PL_DHASH_ENTRY_IS_FREE(ppolicy
))
1218 // Get the correct security level from the property policy
1219 if (aAction
== nsIXPCSecurityManager::ACCESS_SET_PROPERTY
)
1220 *result
= ppolicy
->mSet
;
1222 *result
= ppolicy
->mGet
;
1229 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext
*cx
, nsIURI
*aURI
)
1231 // Get principal of currently executing script.
1233 nsIPrincipal
* principal
= GetSubjectPrincipal(cx
, &rv
);
1237 // Native code can load all URIs.
1241 rv
= CheckLoadURIWithPrincipal(principal
, aURI
,
1242 nsIScriptSecurityManager::STANDARD
);
1243 if (NS_SUCCEEDED(rv
)) {
1248 // See if we're attempting to load a file: URI. If so, let a
1249 // UniversalFileRead capability trump the above check.
1250 PRBool isFile
= PR_FALSE
;
1251 PRBool isRes
= PR_FALSE
;
1252 if (NS_FAILED(aURI
->SchemeIs("file", &isFile
)) ||
1253 NS_FAILED(aURI
->SchemeIs("resource", &isRes
)))
1254 return NS_ERROR_FAILURE
;
1255 if (isFile
|| isRes
)
1258 if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled
)))
1259 return NS_ERROR_FAILURE
;
1266 if (NS_FAILED(aURI
->GetAsciiSpec(spec
)))
1267 return NS_ERROR_FAILURE
;
1268 JS_ReportError(cx
, "Access to '%s' from script denied", spec
.get());
1269 return NS_ERROR_DOM_BAD_URI
;
1273 nsScriptSecurityManager::CheckLoadURI(nsIURI
*aSourceURI
, nsIURI
*aTargetURI
,
1276 // FIXME: bug 327244 -- this function should really die... Really truly.
1277 NS_PRECONDITION(aSourceURI
, "CheckLoadURI called with null source URI");
1278 NS_ENSURE_ARG_POINTER(aSourceURI
);
1280 // Note: this is not _quite_ right if aSourceURI has
1281 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1282 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1283 // really needs to go away....
1284 nsCOMPtr
<nsIPrincipal
> sourcePrincipal
;
1285 nsresult rv
= CreateCodebasePrincipal(aSourceURI
,
1286 getter_AddRefs(sourcePrincipal
));
1287 NS_ENSURE_SUCCESS(rv
, rv
);
1288 return CheckLoadURIWithPrincipal(sourcePrincipal
, aTargetURI
, aFlags
);
1292 * Helper method to handle cases where a flag passed to
1293 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
1294 * nsIProtocolHandler flags set.
1295 * @return if success, access is allowed. Otherwise, deny access
1298 DenyAccessIfURIHasFlags(nsIURI
* aURI
, PRUint32 aURIFlags
)
1300 NS_PRECONDITION(aURI
, "Must have URI!");
1304 NS_URIChainHasFlags(aURI
, aURIFlags
, &uriHasFlags
);
1305 NS_ENSURE_SUCCESS(rv
, rv
);
1308 return NS_ERROR_DOM_BAD_URI
;
1315 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal
* aPrincipal
,
1319 NS_PRECONDITION(aPrincipal
, "CheckLoadURIWithPrincipal must have a principal");
1320 // If someone passes a flag that we don't understand, we should
1321 // fail, because they may need a security check that we don't
1323 NS_ENSURE_FALSE(aFlags
& ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
|
1324 nsIScriptSecurityManager::ALLOW_CHROME
|
1325 nsIScriptSecurityManager::DISALLOW_SCRIPT
|
1326 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
),
1327 NS_ERROR_UNEXPECTED
);
1328 NS_ENSURE_ARG_POINTER(aPrincipal
);
1330 if (aPrincipal
== mSystemPrincipal
) {
1335 nsCOMPtr
<nsIURI
> sourceURI
;
1336 aPrincipal
->GetURI(getter_AddRefs(sourceURI
));
1338 NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
1339 "must have a URI!");
1340 return NS_ERROR_UNEXPECTED
;
1343 // Automatic loads are not allowed from certain protocols.
1344 if (aFlags
& nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
) {
1346 DenyAccessIfURIHasFlags(sourceURI
,
1347 nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT
);
1348 NS_ENSURE_SUCCESS(rv
, rv
);
1351 // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
1352 // would do such inheriting. That would be URIs that do not have their own
1353 // security context.
1354 if (aFlags
& nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
) {
1356 DenyAccessIfURIHasFlags(aTargetURI
,
1357 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
);
1358 NS_ENSURE_SUCCESS(rv
, rv
);
1361 // If either URI is a nested URI, get the base URI
1362 nsCOMPtr
<nsIURI
> sourceBaseURI
= NS_GetInnermostURI(sourceURI
);
1363 nsCOMPtr
<nsIURI
> targetBaseURI
= NS_GetInnermostURI(aTargetURI
);
1365 //-- get the target scheme
1366 nsCAutoString targetScheme
;
1367 nsresult rv
= targetBaseURI
->GetScheme(targetScheme
);
1368 if (NS_FAILED(rv
)) return rv
;
1370 //-- Some callers do not allow loading javascript:
1371 if ((aFlags
& nsIScriptSecurityManager::DISALLOW_SCRIPT
) &&
1372 targetScheme
.EqualsLiteral("javascript"))
1374 return NS_ERROR_DOM_BAD_URI
;
1377 //-- get the source scheme
1378 nsCAutoString sourceScheme
;
1379 rv
= sourceBaseURI
->GetScheme(sourceScheme
);
1380 if (NS_FAILED(rv
)) return rv
;
1382 if (sourceScheme
.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME
)) {
1383 // A null principal can target its own URI.
1384 if (sourceURI
== aTargetURI
) {
1388 else if (targetScheme
.Equals(sourceScheme
,
1389 nsCaseInsensitiveCStringComparator()))
1391 // every scheme can access another URI from the same scheme,
1392 // as long as they don't represent null principals.
1396 NS_NAMED_LITERAL_STRING(errorTag
, "CheckLoadURIError");
1398 // If the schemes don't match, the policy is specified by the protocol
1399 // flags on the target URI. Note that the order of policy checks here is
1400 // very important! We start from most restrictive and work our way down.
1401 // Note that since we're working with the innermost URI, we can just use
1402 // the methods that work on chains of nested URIs and they will only look
1403 // at the flags for our one URI.
1405 // Check for system target URI
1406 rv
= DenyAccessIfURIHasFlags(targetBaseURI
,
1407 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD
);
1408 if (NS_FAILED(rv
)) {
1409 // Deny access, since the origin principal is not system
1410 ReportError(nsnull
, errorTag
, sourceURI
, aTargetURI
);
1414 // Check for chrome target URI
1416 rv
= NS_URIChainHasFlags(targetBaseURI
,
1417 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
1419 NS_ENSURE_SUCCESS(rv
, rv
);
1421 if (aFlags
& nsIScriptSecurityManager::ALLOW_CHROME
) {
1422 if (!targetScheme
.EqualsLiteral("chrome")) {
1423 // for now don't change behavior for resource: or moz-icon:
1427 // allow load only if chrome package is whitelisted
1428 nsCOMPtr
<nsIXULChromeRegistry
> reg(do_GetService(
1429 NS_CHROMEREGISTRY_CONTRACTID
));
1431 PRBool accessAllowed
= PR_FALSE
;
1432 reg
->AllowContentToAccess(targetBaseURI
, &accessAllowed
);
1433 if (accessAllowed
) {
1439 // resource: and chrome: are equivalent, securitywise
1440 // That's bogus!! Fix this. But watch out for
1441 // the view-source stylesheet?
1442 PRBool sourceIsChrome
;
1443 rv
= NS_URIChainHasFlags(sourceBaseURI
,
1444 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
1446 NS_ENSURE_SUCCESS(rv
, rv
);
1447 if (sourceIsChrome
) {
1450 ReportError(nsnull
, errorTag
, sourceURI
, aTargetURI
);
1451 return NS_ERROR_DOM_BAD_URI
;
1454 // Check for target URI pointing to a file
1455 rv
= NS_URIChainHasFlags(targetBaseURI
,
1456 nsIProtocolHandler::URI_IS_LOCAL_FILE
,
1458 NS_ENSURE_SUCCESS(rv
, rv
);
1460 // resource: and chrome: are equivalent, securitywise
1461 // That's bogus!! Fix this. But watch out for
1462 // the view-source stylesheet?
1463 PRBool sourceIsChrome
;
1464 rv
= NS_URIChainHasFlags(sourceURI
,
1465 nsIProtocolHandler::URI_IS_UI_RESOURCE
,
1467 NS_ENSURE_SUCCESS(rv
, rv
);
1468 if (sourceIsChrome
) {
1472 // Now check capability policies
1473 static const char loadURIPrefGroup
[] = "checkloaduri";
1474 ClassInfoData
nameData(nsnull
, loadURIPrefGroup
);
1476 SecurityLevel secLevel
;
1477 rv
= LookupPolicy(aPrincipal
, nameData
, sEnabledID
,
1478 nsIXPCSecurityManager::ACCESS_GET_PROPERTY
,
1480 if (NS_SUCCEEDED(rv
) && secLevel
.level
== SCRIPT_SECURITY_ALL_ACCESS
)
1482 // OK for this site!
1486 ReportError(nsnull
, errorTag
, sourceURI
, aTargetURI
);
1487 return NS_ERROR_DOM_BAD_URI
;
1490 // OK, everyone is allowed to load this, since unflagged handlers are
1491 // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
1492 // need to warn. At some point we'll want to make this warning into an
1493 // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
1494 rv
= NS_URIChainHasFlags(targetBaseURI
,
1495 nsIProtocolHandler::URI_LOADABLE_BY_ANYONE
,
1497 NS_ENSURE_SUCCESS(rv
, rv
);
1499 nsXPIDLString message
;
1500 NS_ConvertASCIItoUTF16
ucsTargetScheme(targetScheme
);
1501 const PRUnichar
* formatStrings
[] = { ucsTargetScheme
.get() };
1503 FormatStringFromName(NS_LITERAL_STRING("ProtocolFlagError").get(),
1505 NS_ARRAY_LENGTH(formatStrings
),
1506 getter_Copies(message
));
1507 if (NS_SUCCEEDED(rv
)) {
1508 nsCOMPtr
<nsIConsoleService
> console(
1509 do_GetService("@mozilla.org/consoleservice;1"));
1510 NS_ENSURE_TRUE(console
, NS_ERROR_FAILURE
);
1512 console
->LogStringMessage(message
.get());
1514 fprintf(stderr
, "%s\n", NS_ConvertUTF16toUTF8(message
).get());
1523 nsScriptSecurityManager::ReportError(JSContext
* cx
, const nsAString
& messageTag
,
1524 nsIURI
* aSource
, nsIURI
* aTarget
)
1527 NS_ENSURE_TRUE(aSource
&& aTarget
, NS_ERROR_NULL_POINTER
);
1529 // Get the source URL spec
1530 nsCAutoString sourceSpec
;
1531 rv
= aSource
->GetAsciiSpec(sourceSpec
);
1532 NS_ENSURE_SUCCESS(rv
, rv
);
1534 // Get the target URL spec
1535 nsCAutoString targetSpec
;
1536 rv
= aTarget
->GetAsciiSpec(targetSpec
);
1537 NS_ENSURE_SUCCESS(rv
, rv
);
1539 // Localize the error message
1540 nsXPIDLString message
;
1541 NS_ConvertASCIItoUTF16
ucsSourceSpec(sourceSpec
);
1542 NS_ConvertASCIItoUTF16
ucsTargetSpec(targetSpec
);
1543 const PRUnichar
*formatStrings
[] = { ucsSourceSpec
.get(), ucsTargetSpec
.get() };
1544 rv
= sStrBundle
->FormatStringFromName(PromiseFlatString(messageTag
).get(),
1546 NS_ARRAY_LENGTH(formatStrings
),
1547 getter_Copies(message
));
1548 NS_ENSURE_SUCCESS(rv
, rv
);
1550 // If a JS context was passed in, set a JS exception.
1551 // Otherwise, print the error message directly to the JS console
1552 // and to standard output
1555 SetPendingException(cx
, message
.get());
1556 // Tell XPConnect that an exception was thrown, if appropriate
1559 nsAXPCNativeCallContext
* xpcCallContext
= nsnull
;
1560 sXPConnect
->GetCurrentNativeCallContext(&xpcCallContext
);
1562 xpcCallContext
->SetExceptionWasThrown(PR_TRUE
);
1565 else // Print directly to the console
1567 nsCOMPtr
<nsIConsoleService
> console(
1568 do_GetService("@mozilla.org/consoleservice;1"));
1569 NS_ENSURE_TRUE(console
, NS_ERROR_FAILURE
);
1571 console
->LogStringMessage(message
.get());
1573 fprintf(stderr
, "%s\n", NS_LossyConvertUTF16toASCII(message
).get());
1580 nsScriptSecurityManager::CheckLoadURIStr(const nsACString
& aSourceURIStr
,
1581 const nsACString
& aTargetURIStr
,
1584 // FIXME: bug 327244 -- this function should really die... Really truly.
1585 nsCOMPtr
<nsIURI
> source
;
1586 nsresult rv
= NS_NewURI(getter_AddRefs(source
), aSourceURIStr
,
1587 nsnull
, nsnull
, sIOService
);
1588 NS_ENSURE_SUCCESS(rv
, rv
);
1590 // Note: this is not _quite_ right if aSourceURI has
1591 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1592 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1593 // really needs to go away....
1594 nsCOMPtr
<nsIPrincipal
> sourcePrincipal
;
1595 rv
= CreateCodebasePrincipal(source
,
1596 getter_AddRefs(sourcePrincipal
));
1597 NS_ENSURE_SUCCESS(rv
, rv
);
1599 return CheckLoadURIStrWithPrincipal(sourcePrincipal
, aTargetURIStr
,
1604 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal
* aPrincipal
,
1605 const nsACString
& aTargetURIStr
,
1609 nsCOMPtr
<nsIURI
> target
;
1610 rv
= NS_NewURI(getter_AddRefs(target
), aTargetURIStr
,
1611 nsnull
, nsnull
, sIOService
);
1612 NS_ENSURE_SUCCESS(rv
, rv
);
1614 rv
= CheckLoadURIWithPrincipal(aPrincipal
, target
, aFlags
);
1615 NS_ENSURE_SUCCESS(rv
, rv
);
1617 // Now start testing fixup -- since aTargetURIStr is a string, not
1618 // an nsIURI, we may well end up fixing it up before loading.
1619 // Note: This needs to stay in sync with the nsIURIFixup api.
1620 nsCOMPtr
<nsIURIFixup
> fixup
= do_GetService(NS_URIFIXUP_CONTRACTID
);
1625 PRUint32 flags
[] = {
1626 nsIURIFixup::FIXUP_FLAG_NONE
,
1627 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
,
1628 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
,
1629 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
|
1630 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
1633 for (PRUint32 i
= 0; i
< NS_ARRAY_LENGTH(flags
); ++i
) {
1634 rv
= fixup
->CreateFixupURI(aTargetURIStr
, flags
[i
],
1635 getter_AddRefs(target
));
1636 NS_ENSURE_SUCCESS(rv
, rv
);
1638 rv
= CheckLoadURIWithPrincipal(aPrincipal
, target
, aFlags
);
1639 NS_ENSURE_SUCCESS(rv
, rv
);
1646 nsScriptSecurityManager::CheckFunctionAccess(JSContext
*aCx
, void *aFunObj
,
1649 // This check is called for event handlers
1651 nsIPrincipal
* subject
=
1652 GetFunctionObjectPrincipal(aCx
, (JSObject
*)aFunObj
, nsnull
, &rv
);
1654 // If subject is null, get a principal from the function object's scope.
1655 if (NS_SUCCEEDED(rv
) && !subject
)
1660 (JSFunction
*)caps_GetJSPrivate((JSObject
*)aFunObj
);
1661 JSScript
*script
= JS_GetFunctionScript(aCx
, fun
);
1663 NS_ASSERTION(!script
, "Null principal for non-native function!");
1667 subject
= doGetObjectPrincipal((JSObject
*)aFunObj
);
1671 return NS_ERROR_FAILURE
;
1673 if (subject
== mSystemPrincipal
)
1674 // This is the system principal: just allow access
1677 // Check if the principal the function was compiled under is
1678 // allowed to execute scripts.
1681 rv
= CanExecuteScripts(aCx
, subject
, &result
);
1686 return NS_ERROR_DOM_SECURITY_ERR
;
1689 ** Get origin of subject and object and compare.
1691 JSObject
* obj
= (JSObject
*)aTargetObj
;
1692 nsIPrincipal
* object
= doGetObjectPrincipal(obj
);
1695 return NS_ERROR_FAILURE
;
1698 rv
= subject
->Subsumes(object
, &subsumes
);
1699 if (NS_SUCCEEDED(rv
) && !subsumes
) {
1700 rv
= NS_ERROR_DOM_PROP_ACCESS_DENIED
;
1706 nsScriptSecurityManager::CanExecuteScripts(JSContext
* cx
,
1707 nsIPrincipal
*aPrincipal
,
1712 if (aPrincipal
== mSystemPrincipal
)
1714 // Even if JavaScript is disabled, we must still execute system scripts
1719 //-- See if the current window allows JS execution
1720 nsIScriptContext
*scriptContext
= GetScriptContext(cx
);
1721 if (!scriptContext
) return NS_ERROR_FAILURE
;
1723 if (!scriptContext
->GetScriptsEnabled()) {
1724 // No scripting on this context, folks
1729 nsIScriptGlobalObject
*sgo
= scriptContext
->GetGlobalObject();
1732 return NS_ERROR_FAILURE
;
1735 // window can be null here if we're running with a non-DOM window
1736 // as the script global (i.e. a XUL prototype document).
1737 nsCOMPtr
<nsPIDOMWindow
> window
= do_QueryInterface(sgo
);
1738 nsCOMPtr
<nsIDocShell
> docshell
;
1742 docshell
= window
->GetDocShell();
1745 nsCOMPtr
<nsIDocShellTreeItem
> globalObjTreeItem
=
1746 do_QueryInterface(docshell
);
1748 if (globalObjTreeItem
)
1750 nsCOMPtr
<nsIDocShellTreeItem
> treeItem(globalObjTreeItem
);
1751 nsCOMPtr
<nsIDocShellTreeItem
> parentItem
;
1753 // Walk up the docshell tree to see if any containing docshell disallows scripts
1756 rv
= docshell
->GetAllowJavascript(result
);
1757 if (NS_FAILED(rv
)) return rv
;
1759 return NS_OK
; // Do not run scripts
1760 treeItem
->GetParent(getter_AddRefs(parentItem
));
1761 treeItem
.swap(parentItem
);
1762 docshell
= do_QueryInterface(treeItem
);
1764 if (treeItem
&& !docshell
) {
1765 NS_ERROR("cannot get a docshell from a treeItem!");
1768 } while (treeItem
&& docshell
);
1771 // OK, the docshell doesn't have script execution explicitly disabled.
1772 // Check whether our URI is an "about:" URI that allows scripts. If it is,
1773 // we need to allow JS to run. In this case, don't apply the JS enabled
1774 // pref or policies. On failures, just press on and don't do this special
1776 nsCOMPtr
<nsIURI
> principalURI
;
1777 aPrincipal
->GetURI(getter_AddRefs(principalURI
));
1778 if (!principalURI
) {
1779 // Broken principal of some sort. Disallow.
1781 return NS_ERROR_UNEXPECTED
;
1785 rv
= principalURI
->SchemeIs("about", &isAbout
);
1786 if (NS_SUCCEEDED(rv
) && isAbout
) {
1787 nsCOMPtr
<nsIAboutModule
> module
;
1788 rv
= NS_GetAboutModule(principalURI
, getter_AddRefs(module
));
1789 if (NS_SUCCEEDED(rv
)) {
1791 rv
= module
->GetURIFlags(principalURI
, &flags
);
1792 if (NS_SUCCEEDED(rv
) &&
1793 (flags
& nsIAboutModule::ALLOW_SCRIPT
)) {
1800 //-- See if JS is disabled globally (via prefs)
1801 *result
= mIsJavaScriptEnabled
;
1802 if (mIsJavaScriptEnabled
!= mIsMailJavaScriptEnabled
&& globalObjTreeItem
)
1804 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
1805 globalObjTreeItem
->GetRootTreeItem(getter_AddRefs(rootItem
));
1806 docshell
= do_QueryInterface(rootItem
);
1809 // Is this script running from mail?
1811 rv
= docshell
->GetAppType(&appType
);
1812 if (NS_FAILED(rv
)) return rv
;
1813 if (appType
== nsIDocShell::APP_TYPE_MAIL
)
1815 *result
= mIsMailJavaScriptEnabled
;
1821 return NS_OK
; // Do not run scripts
1823 //-- Check for a per-site policy
1824 static const char jsPrefGroupName
[] = "javascript";
1825 ClassInfoData
nameData(nsnull
, jsPrefGroupName
);
1827 SecurityLevel secLevel
;
1828 rv
= LookupPolicy(aPrincipal
, nameData
, sEnabledID
,
1829 nsIXPCSecurityManager::ACCESS_GET_PROPERTY
,
1831 if (NS_FAILED(rv
) || secLevel
.level
== SCRIPT_SECURITY_NO_ACCESS
)
1837 //-- Nobody vetoed, so allow the JS to run.
1842 ///////////////// Principals ///////////////////////
1844 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal
**aSubjectPrincipal
)
1847 *aSubjectPrincipal
= doGetSubjectPrincipal(&rv
);
1848 if (NS_SUCCEEDED(rv
))
1849 NS_IF_ADDREF(*aSubjectPrincipal
);
1854 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult
* rv
)
1856 NS_PRECONDITION(rv
, "Null out param");
1857 JSContext
*cx
= GetCurrentJSContext();
1863 return GetSubjectPrincipal(cx
, rv
);
1867 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal
**result
)
1869 NS_ADDREF(*result
= mSystemPrincipal
);
1875 nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool
* aIsSystem
)
1877 NS_ENSURE_ARG_POINTER(aIsSystem
);
1878 *aIsSystem
= PR_FALSE
;
1880 if (!mSystemPrincipal
)
1883 nsCOMPtr
<nsIPrincipal
> subject
;
1884 nsresult rv
= GetSubjectPrincipal(getter_AddRefs(subject
));
1890 // No subject principal means no JS is running;
1891 // this is the equivalent of system principal code
1892 *aIsSystem
= PR_TRUE
;
1896 return mSystemPrincipal
->Equals(subject
, aIsSystem
);
1900 nsScriptSecurityManager::GetCertificatePrincipal(const nsACString
& aCertFingerprint
,
1901 const nsACString
& aSubjectName
,
1902 const nsACString
& aPrettyName
,
1903 nsISupports
* aCertificate
,
1905 nsIPrincipal
**result
)
1909 NS_ENSURE_ARG(!aCertFingerprint
.IsEmpty() &&
1910 !aSubjectName
.IsEmpty() &&
1913 return DoGetCertificatePrincipal(aCertFingerprint
, aSubjectName
,
1914 aPrettyName
, aCertificate
, aURI
, PR_TRUE
,
1919 nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString
& aCertFingerprint
,
1920 const nsACString
& aSubjectName
,
1921 const nsACString
& aPrettyName
,
1922 nsISupports
* aCertificate
,
1924 PRBool aModifyTable
,
1925 nsIPrincipal
**result
)
1927 NS_ENSURE_ARG(!aCertFingerprint
.IsEmpty());
1929 // Create a certificate principal out of the certificate ID
1930 // and URI given to us. We will use this principal to test
1931 // equality when doing our hashtable lookups below.
1932 nsRefPtr
<nsPrincipal
> certificate
= new nsPrincipal();
1934 return NS_ERROR_OUT_OF_MEMORY
;
1936 nsresult rv
= certificate
->Init(aCertFingerprint
, aSubjectName
,
1937 aPrettyName
, aCertificate
, aURI
);
1938 NS_ENSURE_SUCCESS(rv
, rv
);
1940 // Check to see if we already have this principal.
1941 nsCOMPtr
<nsIPrincipal
> fromTable
;
1942 mPrincipals
.Get(certificate
, getter_AddRefs(fromTable
));
1944 // Bingo. We found the certificate in the table, which means
1945 // that it has escalated privileges.
1948 // Make sure this principal has names, so if we ever go to save it
1949 // we'll save them. If we get a name mismatch here we'll throw,
1950 // but that's desirable.
1951 rv
= static_cast<nsPrincipal
*>
1952 (static_cast<nsIPrincipal
*>(fromTable
))
1953 ->EnsureCertData(aSubjectName
, aPrettyName
, aCertificate
);
1954 if (NS_FAILED(rv
)) {
1955 // We have a subject name mismatch for the same cert id.
1956 // Hand back the |certificate| object we created and don't give
1957 // it any rights from the table.
1958 NS_ADDREF(*result
= certificate
);
1964 // We were asked to just get the base certificate, so output
1965 // what we have in the table.
1966 certificate
= static_cast<nsPrincipal
*>
1967 (static_cast<nsIPrincipal
*>
1970 // We found a certificate and now need to install a codebase
1971 // on it. We don't want to modify the principal in the hash
1972 // table, so create a new principal and clone the pertinent
1974 nsXPIDLCString prefName
;
1976 nsXPIDLCString subjectName
;
1977 nsXPIDLCString granted
;
1978 nsXPIDLCString denied
;
1980 rv
= fromTable
->GetPreferences(getter_Copies(prefName
),
1982 getter_Copies(subjectName
),
1983 getter_Copies(granted
),
1984 getter_Copies(denied
),
1986 // XXXbz assert something about subjectName and aSubjectName here?
1987 if (NS_SUCCEEDED(rv
)) {
1988 NS_ASSERTION(!isTrusted
, "Shouldn't have isTrusted true here");
1990 certificate
= new nsPrincipal();
1992 return NS_ERROR_OUT_OF_MEMORY
;
1994 rv
= certificate
->InitFromPersistent(prefName
, id
,
1995 subjectName
, aPrettyName
,
2002 certificate
->SetURI(aURI
);
2007 NS_ADDREF(*result
= certificate
);
2013 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI
* aURI
, nsIPrincipal
**result
)
2015 // I _think_ it's safe to not create null principals here based on aURI.
2016 // At least all the callers would do the right thing in those cases, as far
2017 // as I can tell. --bz
2018 nsRefPtr
<nsPrincipal
> codebase
= new nsPrincipal();
2020 return NS_ERROR_OUT_OF_MEMORY
;
2022 nsresult rv
= codebase
->Init(EmptyCString(), EmptyCString(),
2023 EmptyCString(), nsnull
, aURI
);
2027 NS_ADDREF(*result
= codebase
);
2033 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI
*aURI
,
2034 nsIPrincipal
**result
)
2036 NS_ENSURE_ARG(aURI
);
2038 PRBool inheritsPrincipal
;
2040 NS_URIChainHasFlags(aURI
,
2041 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT
,
2042 &inheritsPrincipal
);
2043 if (NS_FAILED(rv
) || inheritsPrincipal
) {
2044 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID
, result
);
2047 nsCOMPtr
<nsIPrincipal
> principal
;
2048 rv
= CreateCodebasePrincipal(aURI
, getter_AddRefs(principal
));
2049 if (NS_FAILED(rv
)) return rv
;
2051 if (mPrincipals
.Count() > 0)
2053 //-- Check to see if we already have this principal.
2054 nsCOMPtr
<nsIPrincipal
> fromTable
;
2055 mPrincipals
.Get(principal
, getter_AddRefs(fromTable
));
2058 //-- Check to see if we have a more general principal
2060 // XXXbz if only GetOrigin returned a URI! Or better yet if the
2061 // HashKey function on principals were smarter. As it is, we can
2062 // have cases where two principals will have different hashkeys but
2063 // test equal via KeyEquals, which is absolutely silly. That's
2064 // what we're working around here.
2065 nsXPIDLCString originUrl
;
2066 rv
= principal
->GetOrigin(getter_Copies(originUrl
));
2067 if (NS_FAILED(rv
)) return rv
;
2068 nsCOMPtr
<nsIURI
> newURI
;
2069 rv
= NS_NewURI(getter_AddRefs(newURI
), originUrl
, nsnull
, sIOService
);
2070 if (NS_FAILED(rv
)) return rv
;
2071 nsCOMPtr
<nsIPrincipal
> principal2
;
2072 rv
= CreateCodebasePrincipal(newURI
, getter_AddRefs(principal2
));
2073 if (NS_FAILED(rv
)) return rv
;
2074 mPrincipals
.Get(principal2
, getter_AddRefs(fromTable
));
2078 // We found an existing codebase principal. But it might have a
2079 // generic codebase for this origin on it. Install our particular
2081 // XXXbz this is kinda similar to the code in
2082 // GetCertificatePrincipal, but just ever so slightly different.
2084 nsXPIDLCString prefName
;
2086 nsXPIDLCString subjectName
;
2087 nsXPIDLCString granted
;
2088 nsXPIDLCString denied
;
2090 rv
= fromTable
->GetPreferences(getter_Copies(prefName
),
2092 getter_Copies(subjectName
),
2093 getter_Copies(granted
),
2094 getter_Copies(denied
),
2096 if (NS_SUCCEEDED(rv
)) {
2097 nsRefPtr
<nsPrincipal
> codebase
= new nsPrincipal();
2099 return NS_ERROR_OUT_OF_MEMORY
;
2101 rv
= codebase
->InitFromPersistent(prefName
, id
,
2102 subjectName
, EmptyCString(),
2109 codebase
->SetURI(aURI
);
2110 principal
= codebase
;
2116 NS_IF_ADDREF(*result
= principal
);
2122 nsScriptSecurityManager::GetPrincipalFromContext(JSContext
*cx
,
2123 nsIPrincipal
**result
)
2127 nsIScriptContext
*scriptContext
= GetScriptContext(cx
);
2131 return NS_ERROR_FAILURE
;
2134 nsCOMPtr
<nsIScriptObjectPrincipal
> globalData
=
2135 do_QueryInterface(scriptContext
->GetGlobalObject());
2137 NS_IF_ADDREF(*result
= globalData
->GetPrincipal());
2144 nsScriptSecurityManager::GetScriptPrincipal(JSContext
*cx
,
2148 NS_PRECONDITION(rv
, "Null out param");
2154 JSPrincipals
*jsp
= JS_GetScriptPrincipals(cx
, script
);
2156 *rv
= NS_ERROR_FAILURE
;
2157 // Script didn't have principals -- shouldn't happen.
2160 nsJSPrincipals
*nsJSPrin
= static_cast<nsJSPrincipals
*>(jsp
);
2161 nsIPrincipal
* result
= nsJSPrin
->nsIPrincipalPtr
;
2163 *rv
= NS_ERROR_FAILURE
;
2169 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext
*cx
,
2174 NS_PRECONDITION(rv
, "Null out param");
2175 JSFunction
*fun
= (JSFunction
*) caps_GetJSPrivate(obj
);
2176 JSScript
*script
= JS_GetFunctionScript(cx
, fun
);
2182 // A native function: skip it in order to find its scripted caller.
2186 JSScript
*frameScript
= fp
? JS_GetFrameScript(cx
, fp
) : nsnull
;
2188 if (frameScript
&& frameScript
!= script
)
2190 // There is a frame script, and it's different from the
2191 // function script. In this case we're dealing with either
2192 // an eval or a Script object, and in these cases the
2193 // principal we want is in the frame's script, not in the
2194 // function's script. The function's script is where the
2195 // eval-calling code came from, not where the eval or new
2196 // Script object came from, and we want the principal of
2197 // the eval function object or new Script object.
2199 script
= frameScript
;
2201 else if (JS_GetFunctionObject(fun
) != obj
)
2203 // Here, obj is a cloned function object. In this case, the
2204 // clone's prototype may have been precompiled from brutally
2205 // shared chrome, or else it is a lambda or nested function.
2206 // The general case here is a function compiled against a
2207 // different scope than the one it is parented by at runtime,
2208 // hence the creation of a clone to carry the correct scope
2211 // Since principals follow scope, we must get the object
2212 // principal from the clone's scope chain. There are no
2213 // reliable principals compiled into the function itself.
2215 nsIPrincipal
*result
= doGetObjectPrincipal(obj
);
2217 *rv
= NS_ERROR_FAILURE
;
2221 return GetScriptPrincipal(cx
, script
, rv
);
2226 nsScriptSecurityManager::GetFramePrincipal(JSContext
*cx
,
2230 NS_PRECONDITION(rv
, "Null out param");
2231 JSObject
*obj
= JS_GetFrameFunctionObject(cx
, fp
);
2234 // Must be in a top-level script. Get principal from the script.
2235 JSScript
*script
= JS_GetFrameScript(cx
, fp
);
2236 return GetScriptPrincipal(cx
, script
, rv
);
2239 nsIPrincipal
* result
= GetFunctionObjectPrincipal(cx
, obj
, fp
, rv
);
2242 if (NS_SUCCEEDED(*rv
) && !result
)
2244 JSFunction
*fun
= (JSFunction
*)caps_GetJSPrivate(obj
);
2245 JSScript
*script
= JS_GetFunctionScript(cx
, fun
);
2247 NS_ASSERTION(!script
, "Null principal for non-native function!");
2256 nsScriptSecurityManager::GetPrincipalAndFrame(JSContext
*cx
,
2257 JSStackFrame
**frameResult
,
2260 NS_PRECONDITION(rv
, "Null out param");
2261 //-- If there's no principal on the stack, look at the global object
2262 // and return the innermost frame for annotations.
2266 // Get principals from innermost frame of JavaScript or Java.
2267 JSStackFrame
*fp
= nsnull
; // tell JS_FrameIterator to start at innermost
2268 for (fp
= JS_FrameIterator(cx
, &fp
); fp
; fp
= JS_FrameIterator(cx
, &fp
))
2270 nsIPrincipal
* result
= GetFramePrincipal(cx
, fp
, rv
);
2273 NS_ASSERTION(NS_SUCCEEDED(*rv
), "Weird return");
2279 nsIScriptContext
*scriptContext
= GetScriptContext(cx
);
2282 nsCOMPtr
<nsIScriptObjectPrincipal
> globalData
=
2283 do_QueryInterface(scriptContext
->GetGlobalObject());
2286 *rv
= NS_ERROR_FAILURE
;
2290 // Note that we're not in a loop or anything, and nothing comes
2291 // after this point in the function, so we can just return here.
2292 nsIPrincipal
* result
= globalData
->GetPrincipal();
2295 JSStackFrame
*inner
= nsnull
;
2296 *frameResult
= JS_FrameIterator(cx
, &inner
);
2307 nsScriptSecurityManager::GetSubjectPrincipal(JSContext
*cx
,
2310 NS_PRECONDITION(rv
, "Null out param");
2312 return GetPrincipalAndFrame(cx
, &fp
, rv
);
2316 nsScriptSecurityManager::GetObjectPrincipal(JSContext
*aCx
, JSObject
*aObj
,
2317 nsIPrincipal
**result
)
2319 *result
= doGetObjectPrincipal(aObj
);
2321 return NS_ERROR_FAILURE
;
2328 nsScriptSecurityManager::doGetObjectPrincipal(JSObject
*aObj
2330 , PRBool aAllowShortCircuit
2334 NS_ASSERTION(aObj
, "Bad call to doGetObjectPrincipal()!");
2335 nsIPrincipal
* result
= nsnull
;
2338 JSObject
* origObj
= aObj
;
2341 const JSClass
*jsClass
= STOBJ_GET_CLASS(aObj
);
2343 // A common case seen in this code is that we enter this function
2344 // with aObj being a Function object, whose parent is a Call
2345 // object. Neither of those have object principals, so we can skip
2346 // those objects here before we enter the below loop. That way we
2347 // avoid wasting time checking properties of their classes etc in
2350 if (jsClass
== &js_FunctionClass
) {
2351 aObj
= STOBJ_GET_PARENT(aObj
);
2356 jsClass
= STOBJ_GET_CLASS(aObj
);
2358 if (jsClass
== &js_CallClass
) {
2359 aObj
= STOBJ_GET_PARENT(aObj
);
2364 jsClass
= STOBJ_GET_CLASS(aObj
);
2369 // Note: jsClass is set before this loop, and also at the
2370 // *end* of this loop.
2372 // NOTE: These class and getObjectOps hook checks better match
2373 // what IS_WRAPPER_CLASS() does in xpconnect!
2374 if (jsClass
== sXPCWrappedNativeJSClass
||
2375 jsClass
->getObjectOps
== sXPCWrappedNativeGetObjOps1
||
2376 jsClass
->getObjectOps
== sXPCWrappedNativeGetObjOps2
) {
2377 nsIXPConnectWrappedNative
*xpcWrapper
=
2378 (nsIXPConnectWrappedNative
*)caps_GetJSPrivate(aObj
);
2382 if (aAllowShortCircuit
) {
2384 result
= xpcWrapper
->GetObjectPrincipal();
2393 // If not, check if it points to an
2394 // nsIScriptObjectPrincipal
2395 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrin
=
2396 do_QueryWrappedNative(xpcWrapper
);
2398 result
= objPrin
->GetPrincipal();
2405 } else if (!(~jsClass
->flags
& (JSCLASS_HAS_PRIVATE
|
2406 JSCLASS_PRIVATE_IS_NSISUPPORTS
))) {
2407 nsISupports
*priv
= (nsISupports
*)caps_GetJSPrivate(aObj
);
2410 if (aAllowShortCircuit
) {
2411 nsCOMPtr
<nsIXPConnectWrappedNative
> xpcWrapper
=
2412 do_QueryInterface(priv
);
2414 NS_ASSERTION(!xpcWrapper
||
2415 !strcmp(jsClass
->name
, "XPCNativeWrapper"),
2416 "Uh, an nsIXPConnectWrappedNative with the "
2417 "wrong JSClass or getObjectOps hooks!");
2421 nsCOMPtr
<nsIScriptObjectPrincipal
> objPrin
=
2422 do_QueryInterface(priv
);
2425 result
= objPrin
->GetPrincipal();
2433 aObj
= STOBJ_GET_PARENT(aObj
);
2438 jsClass
= STOBJ_GET_CLASS(aObj
);
2441 NS_ASSERTION(!aAllowShortCircuit
||
2442 result
== doGetObjectPrincipal(origObj
, PR_FALSE
),
2443 "Principal mismatch. Not good");
2449 nsScriptSecurityManager::SavePrincipal(nsIPrincipal
* aToSave
)
2451 //-- Save to mPrincipals
2452 mPrincipals
.Put(aToSave
, aToSave
);
2455 nsXPIDLCString idPrefName
;
2457 nsXPIDLCString subjectName
;
2458 nsXPIDLCString grantedList
;
2459 nsXPIDLCString deniedList
;
2461 nsresult rv
= aToSave
->GetPreferences(getter_Copies(idPrefName
),
2463 getter_Copies(subjectName
),
2464 getter_Copies(grantedList
),
2465 getter_Copies(deniedList
),
2467 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2469 nsCAutoString grantedPrefName
;
2470 nsCAutoString deniedPrefName
;
2471 nsCAutoString subjectNamePrefName
;
2472 rv
= GetPrincipalPrefNames( idPrefName
,
2475 subjectNamePrefName
);
2476 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2478 mIsWritingPrefs
= PR_TRUE
;
2480 mSecurityPref
->SecuritySetCharPref(grantedPrefName
.get(), grantedList
);
2482 mSecurityPref
->SecurityClearUserPref(grantedPrefName
.get());
2485 mSecurityPref
->SecuritySetCharPref(deniedPrefName
.get(), deniedList
);
2487 mSecurityPref
->SecurityClearUserPref(deniedPrefName
.get());
2489 if (grantedList
|| deniedList
) {
2490 mSecurityPref
->SecuritySetCharPref(idPrefName
, id
);
2491 mSecurityPref
->SecuritySetCharPref(subjectNamePrefName
.get(),
2495 mSecurityPref
->SecurityClearUserPref(idPrefName
);
2496 mSecurityPref
->SecurityClearUserPref(subjectNamePrefName
.get());
2499 mIsWritingPrefs
= PR_FALSE
;
2501 nsCOMPtr
<nsIPrefService
> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
2502 NS_ENSURE_SUCCESS(rv
, rv
);
2503 return prefService
->SavePrefFile(nsnull
);
2506 ///////////////// Capabilities API /////////////////////
2508 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability
,
2512 JSStackFrame
*fp
= nsnull
;
2513 JSContext
*cx
= GetCurrentJSContext();
2514 fp
= cx
? JS_FrameIterator(cx
, &fp
) : nsnull
;
2517 // No script code on stack. Allow execution.
2522 nsIPrincipal
* previousPrincipal
= nsnull
;
2525 nsIPrincipal
* principal
= GetFramePrincipal(cx
, fp
, &rv
);
2530 // If caller has a different principal, stop looking up the stack.
2531 if(previousPrincipal
)
2533 PRBool isEqual
= PR_FALSE
;
2534 if(NS_FAILED(previousPrincipal
->Equals(principal
, &isEqual
)) || !isEqual
)
2538 previousPrincipal
= principal
;
2540 // First check if the principal is even able to enable the
2541 // given capability. If not, don't look any further.
2543 rv
= principal
->CanEnableCapability(capability
, &canEnable
);
2544 if (NS_FAILED(rv
)) return rv
;
2545 if (canEnable
!= nsIPrincipal::ENABLE_GRANTED
&&
2546 canEnable
!= nsIPrincipal::ENABLE_WITH_USER_PERMISSION
)
2549 // Now see if the capability is enabled.
2550 void *annotation
= JS_GetFrameAnnotation(cx
, fp
);
2551 rv
= principal
->IsCapabilityEnabled(capability
, annotation
, result
);
2552 if (NS_FAILED(rv
)) return rv
;
2555 } while ((fp
= JS_FrameIterator(cx
, &fp
)) != nsnull
);
2557 if (!previousPrincipal
)
2559 // No principals on the stack, all native code. Allow
2560 // execution if the subject principal is the system principal.
2562 return SubjectPrincipalIsSystem(result
);
2569 nsScriptSecurityManager::FormatCapabilityString(nsAString
& aCapability
)
2571 nsAutoString newcaps
;
2572 nsAutoString rawcap
;
2573 NS_NAMED_LITERAL_STRING(capdesc
, "capdesc.");
2575 PRInt32 index
= kNotFound
;
2578 NS_ASSERTION(kNotFound
== -1, "Basic constant changed, algorithm broken!");
2582 index
= aCapability
.FindChar(' ', pos
);
2583 rawcap
= Substring(aCapability
, pos
,
2584 (index
== kNotFound
) ? index
: index
- pos
);
2586 nsXPIDLString capstr
;
2587 rv
= sStrBundle
->GetStringFromName(
2588 nsPromiseFlatString(capdesc
+rawcap
).get(),
2589 getter_Copies(capstr
));
2590 if (NS_SUCCEEDED(rv
))
2594 nsXPIDLString extensionCap
;
2595 const PRUnichar
* formatArgs
[] = { rawcap
.get() };
2596 rv
= sStrBundle
->FormatStringFromName(
2597 NS_LITERAL_STRING("ExtensionCapability").get(),
2599 NS_ARRAY_LENGTH(formatArgs
),
2600 getter_Copies(extensionCap
));
2601 if (NS_SUCCEEDED(rv
))
2602 newcaps
+= extensionCap
;
2607 newcaps
+= NS_LITERAL_STRING("\n");
2608 } while (index
!= kNotFound
);
2610 aCapability
= newcaps
;
2614 nsScriptSecurityManager::CheckConfirmDialog(JSContext
* cx
, nsIPrincipal
* aPrincipal
,
2615 const char* aCapability
, PRBool
*checkValue
)
2618 *checkValue
= PR_FALSE
;
2620 //-- Get a prompter for the current window.
2621 nsCOMPtr
<nsIPrompt
> prompter
;
2624 nsIScriptContext
*scriptContext
= GetScriptContext(cx
);
2627 nsCOMPtr
<nsIDOMWindowInternal
> domWin
=
2628 do_QueryInterface(scriptContext
->GetGlobalObject());
2630 domWin
->GetPrompter(getter_AddRefs(prompter
));
2636 //-- Couldn't get prompter from the current window, so get the prompt service.
2637 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
2639 wwatch
->GetNewPrompter(0, getter_AddRefs(prompter
));
2644 //-- Localize the dialog text
2645 nsXPIDLString check
;
2646 rv
= sStrBundle
->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
2647 getter_Copies(check
));
2651 nsXPIDLString title
;
2652 rv
= sStrBundle
->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
2653 getter_Copies(title
));
2657 nsXPIDLString yesStr
;
2658 rv
= sStrBundle
->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
2659 getter_Copies(yesStr
));
2663 nsXPIDLString noStr
;
2664 rv
= sStrBundle
->GetStringFromName(NS_LITERAL_STRING("No").get(),
2665 getter_Copies(noStr
));
2671 aPrincipal
->GetHasCertificate(&hasCert
);
2673 rv
= aPrincipal
->GetPrettyName(val
);
2675 rv
= GetPrincipalDomainOrigin(aPrincipal
, val
);
2680 NS_ConvertUTF8toUTF16
location(val
);
2681 NS_ConvertASCIItoUTF16
capability(aCapability
);
2682 FormatCapabilityString(capability
);
2683 const PRUnichar
*formatStrings
[] = { location
.get(), capability
.get() };
2685 nsXPIDLString message
;
2686 rv
= sStrBundle
->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
2688 NS_ARRAY_LENGTH(formatStrings
),
2689 getter_Copies(message
));
2693 PRInt32 buttonPressed
= 1; // If the user exits by clicking the close box, assume No (button 1)
2694 rv
= prompter
->ConfirmEx(title
.get(), message
.get(),
2695 (nsIPrompt::BUTTON_DELAY_ENABLE
) +
2696 (nsIPrompt::BUTTON_POS_1_DEFAULT
) +
2697 (nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_0
) +
2698 (nsIPrompt::BUTTON_TITLE_IS_STRING
* nsIPrompt::BUTTON_POS_1
),
2699 yesStr
.get(), noStr
.get(), nsnull
, check
.get(), checkValue
, &buttonPressed
);
2702 *checkValue
= PR_FALSE
;
2703 return (buttonPressed
== 0);
2707 nsScriptSecurityManager::RequestCapability(nsIPrincipal
* aPrincipal
,
2708 const char *capability
, PRInt16
* canEnable
)
2710 if (NS_FAILED(aPrincipal
->CanEnableCapability(capability
, canEnable
)))
2711 return NS_ERROR_FAILURE
;
2712 if (*canEnable
== nsIPrincipal::ENABLE_WITH_USER_PERMISSION
)
2714 // Prompt user for permission to enable capability.
2715 JSContext
* cx
= GetCurrentJSContext();
2717 if (CheckConfirmDialog(cx
, aPrincipal
, capability
, &remember
))
2718 *canEnable
= nsIPrincipal::ENABLE_GRANTED
;
2720 *canEnable
= nsIPrincipal::ENABLE_DENIED
;
2723 //-- Save principal to prefs and to mPrincipals
2724 if (NS_FAILED(aPrincipal
->SetCanEnableCapability(capability
, *canEnable
)))
2725 return NS_ERROR_FAILURE
;
2726 if (NS_FAILED(SavePrincipal(aPrincipal
)))
2727 return NS_ERROR_FAILURE
;
2734 nsScriptSecurityManager::EnableCapability(const char *capability
)
2736 JSContext
*cx
= GetCurrentJSContext();
2739 //-- Error checks for capability string length (200)
2740 if(PL_strlen(capability
)>200)
2742 static const char msg
[] = "Capability name too long";
2743 SetPendingException(cx
, msg
);
2744 return NS_ERROR_FAILURE
;
2747 //-- Check capability string for valid characters
2749 // Logically we might have wanted this in nsPrincipal, but performance
2750 // worries dictate it can't go in IsCapabilityEnabled() and we may have
2751 // to show the capability on a dialog before we call the principal's
2752 // EnableCapability().
2754 // We don't need to validate the capability string on the other APIs
2755 // available to web content. Without the ability to enable junk then
2756 // isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
2757 // the right thing (effectively nothing) when passed unallowed chars.
2758 for (const char *ch
= capability
; *ch
; ++ch
)
2760 if (!NS_IS_ALPHA(*ch
) && *ch
!= ' ' && !NS_IS_DIGIT(*ch
)
2761 && *ch
!= '_' && *ch
!= '-' && *ch
!= '.')
2763 static const char msg
[] = "Invalid character in capability name";
2764 SetPendingException(cx
, msg
);
2765 return NS_ERROR_FAILURE
;
2770 nsIPrincipal
* principal
= GetPrincipalAndFrame(cx
, &fp
, &rv
);
2774 return NS_ERROR_NOT_AVAILABLE
;
2776 void *annotation
= JS_GetFrameAnnotation(cx
, fp
);
2778 if (NS_FAILED(principal
->IsCapabilityEnabled(capability
, annotation
,
2780 return NS_ERROR_FAILURE
;
2785 if (NS_FAILED(RequestCapability(principal
, capability
, &canEnable
)))
2786 return NS_ERROR_FAILURE
;
2788 if (canEnable
!= nsIPrincipal::ENABLE_GRANTED
)
2793 principal
->GetHasCertificate(&hasCert
);
2795 rv
= principal
->GetPrettyName(val
);
2797 rv
= GetPrincipalDomainOrigin(principal
, val
);
2802 NS_ConvertUTF8toUTF16
location(val
);
2803 NS_ConvertUTF8toUTF16
cap(capability
);
2804 const PRUnichar
*formatStrings
[] = { location
.get(), cap
.get() };
2806 nsXPIDLString message
;
2807 rv
= sStrBundle
->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
2809 NS_ARRAY_LENGTH(formatStrings
),
2810 getter_Copies(message
));
2814 SetPendingException(cx
, message
.get());
2816 return NS_ERROR_FAILURE
; // XXX better error code?
2818 if (NS_FAILED(principal
->EnableCapability(capability
, &annotation
)))
2819 return NS_ERROR_FAILURE
;
2820 JS_SetFrameAnnotation(cx
, fp
, annotation
);
2825 nsScriptSecurityManager::RevertCapability(const char *capability
)
2827 JSContext
*cx
= GetCurrentJSContext();
2830 nsIPrincipal
* principal
= GetPrincipalAndFrame(cx
, &fp
, &rv
);
2834 return NS_ERROR_NOT_AVAILABLE
;
2835 void *annotation
= JS_GetFrameAnnotation(cx
, fp
);
2836 principal
->RevertCapability(capability
, &annotation
);
2837 JS_SetFrameAnnotation(cx
, fp
, annotation
);
2842 nsScriptSecurityManager::DisableCapability(const char *capability
)
2844 JSContext
*cx
= GetCurrentJSContext();
2847 nsIPrincipal
* principal
= GetPrincipalAndFrame(cx
, &fp
, &rv
);
2851 return NS_ERROR_NOT_AVAILABLE
;
2852 void *annotation
= JS_GetFrameAnnotation(cx
, fp
);
2853 principal
->DisableCapability(capability
, &annotation
);
2854 JS_SetFrameAnnotation(cx
, fp
, annotation
);
2858 //////////////// Master Certificate Functions ///////////////////////////////////////
2860 nsScriptSecurityManager::SetCanEnableCapability(const nsACString
& certFingerprint
,
2861 const char* capability
,
2864 NS_ENSURE_ARG(!certFingerprint
.IsEmpty());
2867 nsIPrincipal
* subjectPrincipal
= doGetSubjectPrincipal(&rv
);
2871 //-- Get the system certificate
2872 if (!mSystemCertificate
)
2874 nsCOMPtr
<nsIFile
> systemCertFile
;
2875 nsCOMPtr
<nsIProperties
> directoryService
=
2876 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
);
2877 if (!directoryService
) return NS_ERROR_FAILURE
;
2878 rv
= directoryService
->Get(NS_XPCOM_CURRENT_PROCESS_DIR
, NS_GET_IID(nsIFile
),
2879 getter_AddRefs(systemCertFile
));
2880 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2881 systemCertFile
->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
2882 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2883 nsCOMPtr
<nsIZipReader
> systemCertZip
= do_CreateInstance(kZipReaderCID
, &rv
);
2884 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2885 rv
= systemCertZip
->Open(systemCertFile
);
2886 if (NS_SUCCEEDED(rv
))
2888 nsCOMPtr
<nsIJAR
> systemCertJar(do_QueryInterface(systemCertZip
, &rv
));
2889 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2890 rv
= systemCertJar
->GetCertificatePrincipal(nsnull
,
2891 getter_AddRefs(mSystemCertificate
));
2892 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2896 //-- Make sure the caller's principal is the system certificate
2897 PRBool isEqual
= PR_FALSE
;
2898 if (mSystemCertificate
)
2900 rv
= mSystemCertificate
->Equals(subjectPrincipal
, &isEqual
);
2901 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2905 JSContext
* cx
= GetCurrentJSContext();
2906 if (!cx
) return NS_ERROR_FAILURE
;
2907 static const char msg1
[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
2908 static const char msg2
[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
2909 SetPendingException(cx
, mSystemCertificate
? msg1
: msg2
);
2910 return NS_ERROR_FAILURE
;
2913 //-- Get the target principal
2914 nsCOMPtr
<nsIPrincipal
> objectPrincipal
;
2915 rv
= DoGetCertificatePrincipal(certFingerprint
, EmptyCString(),
2916 EmptyCString(), nsnull
,
2918 getter_AddRefs(objectPrincipal
));
2919 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2920 rv
= objectPrincipal
->SetCanEnableCapability(capability
, canEnable
);
2921 if (NS_FAILED(rv
)) return NS_ERROR_FAILURE
;
2922 return SavePrincipal(objectPrincipal
);
2925 ////////////////////////////////////////////////
2926 // Methods implementing nsIXPCSecurityManager //
2927 ////////////////////////////////////////////////
2930 nsScriptSecurityManager::CanCreateWrapper(JSContext
*cx
,
2933 nsIClassInfo
*aClassInfo
,
2936 #ifdef DEBUG_CAPS_CanCreateWrapper
2937 char* iidStr
= aIID
.ToString();
2938 printf("### CanCreateWrapper(%s) ", iidStr
);
2939 nsCRT::free(iidStr
);
2941 // XXX Special case for nsIXPCException ?
2942 ClassInfoData objClassInfo
= ClassInfoData(aClassInfo
, nsnull
);
2943 if (objClassInfo
.IsDOMClass())
2945 #ifdef DEBUG_CAPS_CanCreateWrapper
2946 printf("DOM class - GRANTED.\n");
2951 //--See if the object advertises a non-default level of access
2952 // using nsISecurityCheckedComponent
2953 nsCOMPtr
<nsISecurityCheckedComponent
> checkedComponent
=
2954 do_QueryInterface(aObj
);
2956 nsXPIDLCString objectSecurityLevel
;
2957 if (checkedComponent
)
2958 checkedComponent
->CanCreateWrapper((nsIID
*)&aIID
, getter_Copies(objectSecurityLevel
));
2960 nsresult rv
= CheckXPCPermissions(aObj
, objectSecurityLevel
);
2963 //-- Access denied, report an error
2965 NS_NAMED_LITERAL_STRING(strName
, "CreateWrapperDenied");
2966 NS_ConvertUTF8toUTF16
className(objClassInfo
.GetName());
2967 const PRUnichar
* formatStrings
[] = { className
.get() };
2968 nsXPIDLString errorMsg
;
2969 // We need to keep our existing failure rv and not override it
2970 // with a likely success code from the following string bundle
2971 // call in order to throw the correct security exception later.
2973 sStrBundle
->FormatStringFromName(strName
.get(),
2975 NS_ARRAY_LENGTH(formatStrings
),
2976 getter_Copies(errorMsg
));
2977 NS_ENSURE_SUCCESS(rv2
, rv2
);
2979 SetPendingException(cx
, errorMsg
.get());
2981 #ifdef DEBUG_CAPS_CanCreateWrapper
2982 printf("DENIED.\n");
2986 printf("GRANTED.\n");
2993 #ifdef XPC_IDISPATCH_SUPPORT
2995 nsScriptSecurityManager::CheckComponentPermissions(JSContext
*cx
,
2999 nsIPrincipal
* subjectPrincipal
= GetSubjectPrincipal(cx
, &rv
);
3003 // Reformat the CID string so it's suitable for prefs
3004 nsXPIDLCString cidTemp
;
3005 cidTemp
.Adopt(aCID
.ToString());
3006 nsCAutoString
cid(NS_LITERAL_CSTRING("CID") +
3007 Substring(cidTemp
, 1, cidTemp
.Length() - 2));
3010 #ifdef DEBUG_CAPS_CheckComponentPermissions
3011 printf("### CheckComponentPermissions(ClassID.%s) ",cid
.get());
3014 // Look up the policy for this class.
3015 // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD
3016 JSAutoRequest
ar(cx
);
3017 jsval cidVal
= STRING_TO_JSVAL(::JS_InternString(cx
, cid
.get()));
3019 ClassInfoData
nameData(nsnull
, "ClassID");
3020 SecurityLevel securityLevel
;
3021 rv
= LookupPolicy(subjectPrincipal
, nameData
, cidVal
,
3022 nsIXPCSecurityManager::ACCESS_CALL_METHOD
,
3023 nsnull
, &securityLevel
);
3027 // If there's no policy stored, use the "security.classID.allowByDefault" pref
3028 if (securityLevel
.level
== SCRIPT_SECURITY_UNDEFINED_ACCESS
)
3029 securityLevel
.level
= mXPCDefaultGrantAll
? SCRIPT_SECURITY_ALL_ACCESS
:
3030 SCRIPT_SECURITY_NO_ACCESS
;
3032 if (securityLevel
.level
== SCRIPT_SECURITY_ALL_ACCESS
)
3034 #ifdef DEBUG_CAPS_CheckComponentPermissions
3035 printf(" GRANTED.\n");
3040 #ifdef DEBUG_CAPS_CheckComponentPermissions
3041 printf(" DENIED.\n");
3043 return NS_ERROR_DOM_PROP_ACCESS_DENIED
;
3048 nsScriptSecurityManager::CanCreateInstance(JSContext
*cx
,
3051 #ifdef DEBUG_CAPS_CanCreateInstance
3052 char* cidStr
= aCID
.ToString();
3053 printf("### CanCreateInstance(%s) ", cidStr
);
3054 nsCRT::free(cidStr
);
3057 nsresult rv
= CheckXPCPermissions(nsnull
, nsnull
);
3059 #ifdef XPC_IDISPATCH_SUPPORT
3061 rv
= CheckComponentPermissions(cx
, aCID
);
3066 //-- Access denied, report an error
3067 nsCAutoString
errorMsg("Permission denied to create instance of class. CID=");
3068 char cidStr
[NSID_LENGTH
];
3069 aCID
.ToProvidedString(cidStr
);
3070 errorMsg
.Append(cidStr
);
3071 SetPendingException(cx
, errorMsg
.get());
3073 #ifdef DEBUG_CAPS_CanCreateInstance
3078 printf("GRANTED\n");
3085 nsScriptSecurityManager::CanGetService(JSContext
*cx
,
3088 #ifdef DEBUG_CAPS_CanGetService
3089 char* cidStr
= aCID
.ToString();
3090 printf("### CanGetService(%s) ", cidStr
);
3091 nsCRT::free(cidStr
);
3094 nsresult rv
= CheckXPCPermissions(nsnull
, nsnull
);
3097 //-- Access denied, report an error
3098 nsCAutoString
errorMsg("Permission denied to get service. CID=");
3099 char cidStr
[NSID_LENGTH
];
3100 aCID
.ToProvidedString(cidStr
);
3101 errorMsg
.Append(cidStr
);
3102 SetPendingException(cx
, errorMsg
.get());
3104 #ifdef DEBUG_CAPS_CanGetService
3109 printf("GRANTED\n");
3118 nsScriptSecurityManager::CanAccess(PRUint32 aAction
,
3119 nsAXPCNativeCallContext
* aCallContext
,
3121 JSObject
* aJSObject
,
3123 nsIClassInfo
* aClassInfo
,
3124 jsval aPropertyName
,
3127 return CheckPropertyAccessImpl(aAction
, aCallContext
, cx
,
3128 aJSObject
, aObj
, nsnull
, aClassInfo
,
3129 nsnull
, aPropertyName
, aPolicy
);
3133 nsScriptSecurityManager::CheckXPCPermissions(nsISupports
* aObj
,
3134 const char* aObjectSecurityLevel
)
3136 //-- Check for the all-powerful UniversalXPConnect privilege
3137 PRBool ok
= PR_FALSE
;
3138 if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok
)) && ok
)
3141 //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
3142 if (aObjectSecurityLevel
)
3144 if (PL_strcasecmp(aObjectSecurityLevel
, "allAccess") == 0)
3146 else if (PL_strcasecmp(aObjectSecurityLevel
, "noAccess") != 0)
3148 PRBool canAccess
= PR_FALSE
;
3149 if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel
, &canAccess
)) &&
3155 //-- If user allows scripting of plugins by untrusted scripts,
3156 // and the target object is a plugin, allow the access.
3160 nsCOMPtr
<nsIPluginInstance
> plugin(do_QueryInterface(aObj
, &rv
));
3161 if (NS_SUCCEEDED(rv
))
3163 static PRBool prefSet
= PR_FALSE
;
3164 static PRBool allowPluginAccess
= PR_FALSE
;
3167 rv
= mSecurityPref
->SecurityGetBoolPref("security.xpconnect.plugin.unrestricted",
3168 &allowPluginAccess
);
3171 if (allowPluginAccess
)
3176 //-- Access tests failed
3177 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED
;
3180 //////////////////////////////////////////////
3181 // Method implementing nsIPrefSecurityCheck //
3182 //////////////////////////////////////////////
3185 nsScriptSecurityManager::CanAccessSecurityPreferences(PRBool
* _retval
)
3187 return IsCapabilityEnabled("CapabilityPreferencesAccess", _retval
);
3190 /////////////////////////////////////////////
3191 // Method implementing nsIChannelEventSink //
3192 /////////////////////////////////////////////
3194 nsScriptSecurityManager::OnChannelRedirect(nsIChannel
* oldChannel
,
3195 nsIChannel
* newChannel
,
3196 PRUint32 redirFlags
)
3198 nsCOMPtr
<nsIPrincipal
> oldPrincipal
;
3199 GetChannelPrincipal(oldChannel
, getter_AddRefs(oldPrincipal
));
3201 nsCOMPtr
<nsIURI
> newURI
;
3202 newChannel
->GetURI(getter_AddRefs(newURI
));
3203 nsCOMPtr
<nsIURI
> newOriginalURI
;
3204 newChannel
->GetOriginalURI(getter_AddRefs(newOriginalURI
));
3206 NS_ENSURE_STATE(oldPrincipal
&& newURI
&& newOriginalURI
);
3208 const PRUint32 flags
=
3209 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT
|
3210 nsIScriptSecurityManager::DISALLOW_SCRIPT
;
3211 nsresult rv
= CheckLoadURIWithPrincipal(oldPrincipal
, newURI
, flags
);
3212 if (NS_SUCCEEDED(rv
) && newOriginalURI
!= newURI
) {
3213 rv
= CheckLoadURIWithPrincipal(oldPrincipal
, newOriginalURI
, flags
);
3219 /////////////////////////////////////
3220 // Method implementing nsIObserver //
3221 /////////////////////////////////////
3222 static const char sPrincipalPrefix
[] = "capability.principal";
3223 static const char sPolicyPrefix
[] = "capability.policy.";
3226 nsScriptSecurityManager::Observe(nsISupports
* aObject
, const char* aTopic
,
3227 const PRUnichar
* aMessage
)
3229 nsresult rv
= NS_OK
;
3230 NS_ConvertUTF16toUTF8
messageStr(aMessage
);
3231 const char *message
= messageStr
.get();
3233 static const char jsPrefix
[] = "javascript.";
3234 static const char securityPrefix
[] = "security.";
3235 if ((PL_strncmp(message
, jsPrefix
, sizeof(jsPrefix
)-1) == 0) ||
3236 (PL_strncmp(message
, securityPrefix
, sizeof(securityPrefix
)-1) == 0) )
3238 ScriptSecurityPrefChanged();
3240 else if (PL_strncmp(message
, sPolicyPrefix
, sizeof(sPolicyPrefix
)-1) == 0)
3242 // This will force re-initialization of the pref table
3243 mPolicyPrefsChanged
= PR_TRUE
;
3245 else if ((PL_strncmp(message
, sPrincipalPrefix
, sizeof(sPrincipalPrefix
)-1) == 0) &&
3248 static const char id
[] = "id";
3249 char* lastDot
= PL_strrchr(message
, '.');
3250 //-- This check makes sure the string copy below doesn't overwrite its bounds
3251 if(PL_strlen(lastDot
) >= sizeof(id
))
3253 PL_strcpy(lastDot
+ 1, id
);
3254 const char** idPrefArray
= (const char**)&message
;
3255 rv
= InitPrincipals(1, idPrefArray
, mSecurityPref
);
3261 /////////////////////////////////////////////
3262 // Constructor, Destructor, Initialization //
3263 /////////////////////////////////////////////
3264 nsScriptSecurityManager::nsScriptSecurityManager(void)
3265 : mOriginToPolicyMap(nsnull
),
3266 mDefaultPolicy(nsnull
),
3267 mCapabilities(nsnull
),
3268 mIsJavaScriptEnabled(PR_FALSE
),
3269 mIsMailJavaScriptEnabled(PR_FALSE
),
3270 mIsWritingPrefs(PR_FALSE
),
3271 mPolicyPrefsChanged(PR_TRUE
)
3272 #ifdef XPC_IDISPATCH_SUPPORT
3273 , mXPCDefaultGrantAll(PR_FALSE
)
3276 NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
3277 mPrincipals
.Init(31);
3281 nsresult
nsScriptSecurityManager::Init()
3283 JSContext
* cx
= GetSafeJSContext();
3284 if (!cx
) return NS_ERROR_FAILURE
; // this can happen of xpt loading fails
3286 ::JS_BeginRequest(cx
);
3287 if (sEnabledID
== JSVAL_VOID
)
3288 sEnabledID
= STRING_TO_JSVAL(::JS_InternString(cx
, "enabled"));
3289 ::JS_EndRequest(cx
);
3291 nsresult rv
= InitPrefs();
3292 NS_ENSURE_SUCCESS(rv
, rv
);
3294 rv
= CallGetService(NS_IOSERVICE_CONTRACTID
, &sIOService
);
3295 NS_ENSURE_SUCCESS(rv
, rv
);
3297 rv
= CallGetService(nsIXPConnect::GetCID(), &sXPConnect
);
3298 NS_ENSURE_SUCCESS(rv
, rv
);
3300 nsCOMPtr
<nsIStringBundleService
> bundleService
= do_GetService(NS_STRINGBUNDLE_CONTRACTID
, &rv
);
3301 NS_ENSURE_SUCCESS(rv
, rv
);
3303 rv
= bundleService
->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle
);
3304 NS_ENSURE_SUCCESS(rv
, rv
);
3306 // Create our system principal singleton
3307 nsRefPtr
<nsSystemPrincipal
> system
= new nsSystemPrincipal();
3308 NS_ENSURE_TRUE(system
, NS_ERROR_OUT_OF_MEMORY
);
3310 rv
= system
->Init();
3311 NS_ENSURE_SUCCESS(rv
, rv
);
3313 mSystemPrincipal
= system
;
3315 //-- Register security check callback in the JS engine
3316 // Currently this is used to control access to function.caller
3317 nsCOMPtr
<nsIJSRuntimeService
> runtimeService
=
3318 do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv
);
3319 NS_ENSURE_SUCCESS(rv
, rv
);
3321 rv
= runtimeService
->GetRuntime(&sRuntime
);
3322 NS_ENSURE_SUCCESS(rv
, rv
);
3325 JSCheckAccessOp oldCallback
=
3327 JS_SetCheckObjectAccessCallback(sRuntime
, CheckObjectAccess
);
3329 sXPConnect
->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass
,
3330 &sXPCWrappedNativeGetObjOps1
,
3331 &sXPCWrappedNativeGetObjOps2
);
3333 // For now, assert that no callback was set previously
3334 NS_ASSERTION(!oldCallback
, "Someone already set a JS CheckObjectAccess callback");
3338 static nsScriptSecurityManager
*gScriptSecMan
= nsnull
;
3340 jsval
nsScriptSecurityManager::sEnabledID
= JSVAL_VOID
;
3342 nsScriptSecurityManager::~nsScriptSecurityManager(void)
3344 delete mOriginToPolicyMap
;
3346 mDefaultPolicy
->Drop();
3347 delete mCapabilities
;
3348 gScriptSecMan
= nsnull
;
3352 nsScriptSecurityManager::Shutdown()
3356 JSCheckAccessOp oldCallback
=
3358 JS_SetCheckObjectAccessCallback(sRuntime
, nsnull
);
3359 NS_ASSERTION(oldCallback
== CheckObjectAccess
, "Oops, we just clobbered someone else, oh well.");
3362 sEnabledID
= JSVAL_VOID
;
3364 NS_IF_RELEASE(sIOService
);
3365 NS_IF_RELEASE(sXPConnect
);
3366 NS_IF_RELEASE(sStrBundle
);
3369 nsScriptSecurityManager
*
3370 nsScriptSecurityManager::GetScriptSecurityManager()
3374 nsScriptSecurityManager
* ssManager
= new nsScriptSecurityManager();
3378 rv
= ssManager
->Init();
3379 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to initialize nsScriptSecurityManager");
3380 if (NS_FAILED(rv
)) {
3385 rv
= nsJSPrincipals::Startup();
3386 if (NS_FAILED(rv
)) {
3387 NS_WARNING("can't initialize JS engine security protocol glue!");
3392 rv
= sXPConnect
->SetDefaultSecurityManager(ssManager
,
3393 nsIXPCSecurityManager::HOOK_ALL
);
3394 if (NS_FAILED(rv
)) {
3395 NS_WARNING("Failed to install xpconnect security manager!");
3400 gScriptSecMan
= ssManager
;
3402 return gScriptSecMan
;
3405 // Currently this nsGenericFactory constructor is used only from FastLoad
3406 // (XPCOM object deserialization) code, when "creating" the system principal
3409 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
3411 nsIPrincipal
*sysprin
= nsnull
;
3413 NS_ADDREF(sysprin
= gScriptSecMan
->mSystemPrincipal
);
3414 return static_cast<nsSystemPrincipal
*>(sysprin
);
3418 nsScriptSecurityManager::InitPolicies()
3420 // Clear any policies cached on XPConnect wrappers
3421 NS_ENSURE_STATE(sXPConnect
);
3422 nsresult rv
= sXPConnect
->ClearAllWrappedNativeSecurityPolicies();
3423 if (NS_FAILED(rv
)) return rv
;
3425 //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
3426 //-- whose dtor decrements refcount of stored DomainPolicy object
3427 delete mOriginToPolicyMap
;
3429 //-- Marks all the survivor DomainPolicy objects (those cached
3430 //-- by nsPrincipal objects) as invalid: they will be released
3431 //-- on first nsPrincipal::GetSecurityPolicy() attempt.
3432 DomainPolicy::InvalidateAll();
3434 //-- Release old default policy
3435 if(mDefaultPolicy
) {
3436 mDefaultPolicy
->Drop();
3437 mDefaultPolicy
= nsnull
;
3440 //-- Initialize a new mOriginToPolicyMap
3441 mOriginToPolicyMap
=
3442 new nsObjectHashtable(nsnull
, nsnull
, DeleteDomainEntry
, nsnull
);
3443 if (!mOriginToPolicyMap
)
3444 return NS_ERROR_OUT_OF_MEMORY
;
3446 //-- Create, refcount and initialize a new default policy
3447 mDefaultPolicy
= new DomainPolicy();
3448 if (!mDefaultPolicy
)
3449 return NS_ERROR_OUT_OF_MEMORY
;
3451 mDefaultPolicy
->Hold();
3452 if (!mDefaultPolicy
->Init())
3453 return NS_ERROR_UNEXPECTED
;
3455 //-- Initialize the table of security levels
3459 new nsObjectHashtable(nsnull
, nsnull
, DeleteCapability
, nsnull
);
3461 return NS_ERROR_OUT_OF_MEMORY
;
3464 // Get a JS context - we need it to create internalized strings later.
3465 JSContext
* cx
= GetSafeJSContext();
3466 NS_ASSERTION(cx
, "failed to get JS context");
3467 rv
= InitDomainPolicy(cx
, "default", mDefaultPolicy
);
3468 NS_ENSURE_SUCCESS(rv
, rv
);
3470 nsXPIDLCString policyNames
;
3471 rv
= mSecurityPref
->SecurityGetCharPref("capability.policy.policynames",
3472 getter_Copies(policyNames
));
3474 nsXPIDLCString defaultPolicyNames
;
3475 rv
= mSecurityPref
->SecurityGetCharPref("capability.policy.default_policynames",
3476 getter_Copies(defaultPolicyNames
));
3477 policyNames
+= NS_LITERAL_CSTRING(" ") + defaultPolicyNames
;
3479 //-- Initialize domain policies
3480 char* policyCurrent
= policyNames
.BeginWriting();
3481 PRBool morePolicies
= PR_TRUE
;
3482 while (morePolicies
)
3484 while(*policyCurrent
== ' ' || *policyCurrent
== ',')
3486 if (*policyCurrent
== '\0')
3488 char* nameBegin
= policyCurrent
;
3490 while(*policyCurrent
!= '\0' && *policyCurrent
!= ' ' && *policyCurrent
!= ',')
3493 morePolicies
= (*policyCurrent
!= '\0');
3494 *policyCurrent
= '\0';
3497 nsCAutoString
sitesPrefName(
3498 NS_LITERAL_CSTRING(sPolicyPrefix
) +
3499 nsDependentCString(nameBegin
) +
3500 NS_LITERAL_CSTRING(".sites"));
3501 nsXPIDLCString domainList
;
3502 rv
= mSecurityPref
->SecurityGetCharPref(sitesPrefName
.get(),
3503 getter_Copies(domainList
));
3507 DomainPolicy
* domainPolicy
= new DomainPolicy();
3509 return NS_ERROR_OUT_OF_MEMORY
;
3511 if (!domainPolicy
->Init())
3513 delete domainPolicy
;
3514 return NS_ERROR_UNEXPECTED
;
3516 domainPolicy
->Hold();
3517 //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
3518 char* domainStart
= domainList
.BeginWriting();
3519 char* domainCurrent
= domainStart
;
3520 char* lastDot
= nsnull
;
3521 char* nextToLastDot
= nsnull
;
3522 PRBool moreDomains
= PR_TRUE
;
3525 if (*domainCurrent
== ' ' || *domainCurrent
== '\0')
3527 moreDomains
= (*domainCurrent
!= '\0');
3528 *domainCurrent
= '\0';
3529 nsCStringKey
key(nextToLastDot
? nextToLastDot
+1 : domainStart
);
3530 DomainEntry
*newEntry
= new DomainEntry(domainStart
, domainPolicy
);
3533 domainPolicy
->Drop();
3534 return NS_ERROR_OUT_OF_MEMORY
;
3537 newEntry
->mPolicyName_DEBUG
= nameBegin
;
3539 DomainEntry
*existingEntry
= (DomainEntry
*)
3540 mOriginToPolicyMap
->Get(&key
);
3542 mOriginToPolicyMap
->Put(&key
, newEntry
);
3545 if (existingEntry
->Matches(domainStart
))
3547 newEntry
->mNext
= existingEntry
;
3548 mOriginToPolicyMap
->Put(&key
, newEntry
);
3552 while (existingEntry
->mNext
)
3554 if (existingEntry
->mNext
->Matches(domainStart
))
3556 newEntry
->mNext
= existingEntry
->mNext
;
3557 existingEntry
->mNext
= newEntry
;
3560 existingEntry
= existingEntry
->mNext
;
3562 if (!existingEntry
->mNext
)
3563 existingEntry
->mNext
= newEntry
;
3566 domainStart
= domainCurrent
+ 1;
3567 lastDot
= nextToLastDot
= nsnull
;
3569 else if (*domainCurrent
== '.')
3571 nextToLastDot
= lastDot
;
3572 lastDot
= domainCurrent
;
3577 rv
= InitDomainPolicy(cx
, nameBegin
, domainPolicy
);
3578 domainPolicy
->Drop();
3583 // Reset the "dirty" flag
3584 mPolicyPrefsChanged
= PR_FALSE
;
3586 #ifdef DEBUG_CAPS_HACKER
3594 nsScriptSecurityManager::InitDomainPolicy(JSContext
* cx
,
3595 const char* aPolicyName
,
3596 DomainPolicy
* aDomainPolicy
)
3599 nsCAutoString
policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix
) +
3600 nsDependentCString(aPolicyName
) +
3601 NS_LITERAL_CSTRING("."));
3602 PRUint32 prefixLength
= policyPrefix
.Length() - 1; // subtract the '.'
3606 rv
= mPrefBranch
->GetChildList(policyPrefix
.get(),
3607 &prefCount
, &prefNames
);
3608 if (NS_FAILED(rv
)) return rv
;
3612 //-- Populate the policy
3613 PRUint32 currentPref
= 0;
3614 for (; currentPref
< prefCount
; currentPref
++)
3616 // Get the class name
3617 const char* start
= prefNames
[currentPref
] + prefixLength
+ 1;
3618 char* end
= PL_strchr(start
, '.');
3619 if (!end
) // malformed pref, bail on this one
3621 static const char sitesStr
[] = "sites";
3623 // We dealt with "sites" in InitPolicies(), so no need to do
3625 if (PL_strncmp(start
, sitesStr
, sizeof(sitesStr
)-1) == 0)
3628 // Get the pref value
3629 nsXPIDLCString prefValue
;
3630 rv
= mSecurityPref
->SecurityGetCharPref(prefNames
[currentPref
],
3631 getter_Copies(prefValue
));
3632 if (NS_FAILED(rv
) || !prefValue
)
3635 SecurityLevel secLevel
;
3636 if (PL_strcasecmp(prefValue
, "noAccess") == 0)
3637 secLevel
.level
= SCRIPT_SECURITY_NO_ACCESS
;
3638 else if (PL_strcasecmp(prefValue
, "allAccess") == 0)
3639 secLevel
.level
= SCRIPT_SECURITY_ALL_ACCESS
;
3640 else if (PL_strcasecmp(prefValue
, "sameOrigin") == 0)
3641 secLevel
.level
= SCRIPT_SECURITY_SAME_ORIGIN_ACCESS
;
3643 { //-- pref value is the name of a capability
3644 nsCStringKey
secLevelKey(prefValue
);
3645 secLevel
.capability
=
3646 reinterpret_cast<char*>(mCapabilities
->Get(&secLevelKey
));
3647 if (!secLevel
.capability
)
3649 secLevel
.capability
= NS_strdup(prefValue
);
3650 if (!secLevel
.capability
)
3652 mCapabilities
->Put(&secLevelKey
,
3653 secLevel
.capability
);
3658 // Find or store this class in the classes table
3659 ClassPolicy
* cpolicy
=
3660 static_cast<ClassPolicy
*>
3661 (PL_DHashTableOperate(aDomainPolicy
, start
,
3666 // If this is the wildcard class (class '*'), save it in mWildcardPolicy
3667 // (we leave it stored in the hashtable too to take care of the cleanup)
3668 if ((*start
== '*') && (end
== start
+ 1)) {
3669 aDomainPolicy
->mWildcardPolicy
= cpolicy
;
3671 // Make sure that cpolicy knows about aDomainPolicy so it can reset
3672 // the mWildcardPolicy pointer as needed if it gets moved in the
3674 cpolicy
->mDomainWeAreWildcardFor
= aDomainPolicy
;
3677 // Get the property name
3679 end
= PL_strchr(start
, '.');
3683 JSAutoRequest
ar(cx
);
3685 JSString
* propertyKey
= ::JS_InternString(cx
, start
);
3687 return NS_ERROR_OUT_OF_MEMORY
;
3689 // Store this property in the class policy
3691 reinterpret_cast<const void*>(STRING_TO_JSVAL(propertyKey
));
3692 PropertyPolicy
* ppolicy
=
3693 static_cast<PropertyPolicy
*>
3694 (PL_DHashTableOperate(cpolicy
->mPolicy
, ppkey
,
3699 if (end
) // The pref specifies an access mode
3702 if (PL_strcasecmp(start
, "set") == 0)
3703 ppolicy
->mSet
= secLevel
;
3705 ppolicy
->mGet
= secLevel
;
3709 if (ppolicy
->mGet
.level
== SCRIPT_SECURITY_UNDEFINED_ACCESS
)
3710 ppolicy
->mGet
= secLevel
;
3711 if (ppolicy
->mSet
.level
== SCRIPT_SECURITY_UNDEFINED_ACCESS
)
3712 ppolicy
->mSet
= secLevel
;
3716 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount
, prefNames
);
3717 if (currentPref
< prefCount
) // Loop exited early because of out-of-memory error
3718 return NS_ERROR_OUT_OF_MEMORY
;
3723 // XXXbz We should really just get a prefbranch to handle this...
3725 nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase
,
3726 nsCString
& grantedPref
,
3727 nsCString
& deniedPref
,
3728 nsCString
& subjectNamePref
)
3730 char* lastDot
= PL_strrchr(prefBase
, '.');
3731 if (!lastDot
) return NS_ERROR_FAILURE
;
3732 PRInt32 prefLen
= lastDot
- prefBase
+ 1;
3734 grantedPref
.Assign(prefBase
, prefLen
);
3735 deniedPref
.Assign(prefBase
, prefLen
);
3736 subjectNamePref
.Assign(prefBase
, prefLen
);
3738 #define GRANTED "granted"
3739 #define DENIED "denied"
3740 #define SUBJECTNAME "subjectName"
3742 grantedPref
.AppendLiteral(GRANTED
);
3743 if (grantedPref
.Length() != prefLen
+ sizeof(GRANTED
) - 1) {
3744 return NS_ERROR_OUT_OF_MEMORY
;
3747 deniedPref
.AppendLiteral(DENIED
);
3748 if (deniedPref
.Length() != prefLen
+ sizeof(DENIED
) - 1) {
3749 return NS_ERROR_OUT_OF_MEMORY
;
3752 subjectNamePref
.AppendLiteral(SUBJECTNAME
);
3753 if (subjectNamePref
.Length() != prefLen
+ sizeof(SUBJECTNAME
) - 1) {
3754 return NS_ERROR_OUT_OF_MEMORY
;
3765 nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount
, const char** aPrefNames
,
3766 nsISecurityPref
* aSecurityPref
)
3768 /* This is the principal preference syntax:
3769 * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
3771 * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
3772 * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
3773 * user_pref("capability.principal.certificate.p1.denied","Capability3");
3776 /* codebaseTrusted means a codebase principal that can enable capabilities even if
3777 * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
3778 * URLs such as HTTPS URLs.
3781 static const char idSuffix
[] = ".id";
3782 for (PRUint32 c
= 0; c
< aPrefCount
; c
++)
3784 PRInt32 prefNameLen
= PL_strlen(aPrefNames
[c
]) -
3785 (NS_ARRAY_LENGTH(idSuffix
) - 1);
3786 if (PL_strcasecmp(aPrefNames
[c
] + prefNameLen
, idSuffix
) != 0)
3790 if (NS_FAILED(mSecurityPref
->SecurityGetCharPref(aPrefNames
[c
], getter_Copies(id
))))
3791 return NS_ERROR_FAILURE
;
3793 nsCAutoString grantedPrefName
;
3794 nsCAutoString deniedPrefName
;
3795 nsCAutoString subjectNamePrefName
;
3796 nsresult rv
= GetPrincipalPrefNames(aPrefNames
[c
],
3799 subjectNamePrefName
);
3800 if (rv
== NS_ERROR_OUT_OF_MEMORY
)
3805 nsXPIDLCString grantedList
;
3806 mSecurityPref
->SecurityGetCharPref(grantedPrefName
.get(),
3807 getter_Copies(grantedList
));
3808 nsXPIDLCString deniedList
;
3809 mSecurityPref
->SecurityGetCharPref(deniedPrefName
.get(),
3810 getter_Copies(deniedList
));
3811 nsXPIDLCString subjectName
;
3812 mSecurityPref
->SecurityGetCharPref(subjectNamePrefName
.get(),
3813 getter_Copies(subjectName
));
3815 //-- Delete prefs if their value is the empty string
3816 if (id
.IsEmpty() || (grantedList
.IsEmpty() && deniedList
.IsEmpty()))
3818 mSecurityPref
->SecurityClearUserPref(aPrefNames
[c
]);
3819 mSecurityPref
->SecurityClearUserPref(grantedPrefName
.get());
3820 mSecurityPref
->SecurityClearUserPref(deniedPrefName
.get());
3821 mSecurityPref
->SecurityClearUserPref(subjectNamePrefName
.get());
3825 //-- Create a principal based on the prefs
3826 static const char certificateName
[] = "capability.principal.certificate";
3827 static const char codebaseName
[] = "capability.principal.codebase";
3828 static const char codebaseTrustedName
[] = "capability.principal.codebaseTrusted";
3830 PRBool isCert
= PR_FALSE
;
3831 PRBool isTrusted
= PR_FALSE
;
3833 if (PL_strncmp(aPrefNames
[c
], certificateName
,
3834 sizeof(certificateName
) - 1) == 0)
3838 else if (PL_strncmp(aPrefNames
[c
], codebaseName
,
3839 sizeof(codebaseName
) - 1) == 0)
3841 isTrusted
= (PL_strncmp(aPrefNames
[c
], codebaseTrustedName
,
3842 sizeof(codebaseTrustedName
) - 1) == 0);
3846 NS_ERROR("Not a codebase or a certificate?!");
3849 nsRefPtr
<nsPrincipal
> newPrincipal
= new nsPrincipal();
3851 return NS_ERROR_OUT_OF_MEMORY
;
3853 rv
= newPrincipal
->InitFromPersistent(aPrefNames
[c
], id
, subjectName
,
3855 grantedList
, deniedList
, nsnull
,
3857 if (NS_SUCCEEDED(rv
))
3858 mPrincipals
.Put(newPrincipal
, newPrincipal
);
3863 const char nsScriptSecurityManager::sJSEnabledPrefName
[] =
3864 "javascript.enabled";
3865 const char nsScriptSecurityManager::sJSMailEnabledPrefName
[] =
3866 "javascript.allow.mailnews";
3867 const char nsScriptSecurityManager::sFileOriginPolicyPrefName
[] =
3868 "security.fileuri.strict_origin_policy";
3869 #ifdef XPC_IDISPATCH_SUPPORT
3870 const char nsScriptSecurityManager::sXPCDefaultGrantAllName
[] =
3871 "security.classID.allowByDefault";
3875 nsScriptSecurityManager::ScriptSecurityPrefChanged()
3878 nsresult rv
= mSecurityPref
->SecurityGetBoolPref(sJSEnabledPrefName
, &temp
);
3879 // JavaScript defaults to enabled in failure cases.
3880 mIsJavaScriptEnabled
= NS_FAILED(rv
) || temp
;
3882 rv
= mSecurityPref
->SecurityGetBoolPref(sJSMailEnabledPrefName
, &temp
);
3883 // JavaScript in Mail defaults to disabled in failure cases.
3884 mIsMailJavaScriptEnabled
= NS_SUCCEEDED(rv
) && temp
;
3886 rv
= mSecurityPref
->SecurityGetBoolPref(sFileOriginPolicyPrefName
, &temp
);
3887 sStrictFileOriginPolicy
= NS_SUCCEEDED(rv
) && temp
;
3889 #ifdef XPC_IDISPATCH_SUPPORT
3890 rv
= mSecurityPref
->SecurityGetBoolPref(sXPCDefaultGrantAllName
, &temp
);
3891 // Granting XPC Priveleges defaults to disabled in failure cases.
3892 mXPCDefaultGrantAll
= NS_SUCCEEDED(rv
) && temp
;
3897 nsScriptSecurityManager::InitPrefs()
3900 nsCOMPtr
<nsIPrefService
> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
3901 NS_ENSURE_SUCCESS(rv
, rv
);
3902 rv
= prefService
->GetBranch(nsnull
, getter_AddRefs(mPrefBranch
));
3903 NS_ENSURE_SUCCESS(rv
, rv
);
3904 nsCOMPtr
<nsIPrefBranch2
> prefBranchInternal(do_QueryInterface(mPrefBranch
, &rv
));
3905 NS_ENSURE_SUCCESS(rv
, rv
);
3906 mSecurityPref
= do_QueryInterface(mPrefBranch
, &rv
);
3907 NS_ENSURE_SUCCESS(rv
, rv
);
3909 // Set the initial value of the "javascript.enabled" prefs
3910 ScriptSecurityPrefChanged();
3911 // set observer callbacks in case the value of the prefs change
3912 prefBranchInternal
->AddObserver(sJSEnabledPrefName
, this, PR_FALSE
);
3913 prefBranchInternal
->AddObserver(sJSMailEnabledPrefName
, this, PR_FALSE
);
3914 prefBranchInternal
->AddObserver(sFileOriginPolicyPrefName
, this, PR_FALSE
);
3915 #ifdef XPC_IDISPATCH_SUPPORT
3916 prefBranchInternal
->AddObserver(sXPCDefaultGrantAllName
, this, PR_FALSE
);
3921 // Set a callback for policy pref changes
3922 prefBranchInternal
->AddObserver(sPolicyPrefix
, this, PR_FALSE
);
3924 //-- Initialize the principals database from prefs
3925 rv
= mPrefBranch
->GetChildList(sPrincipalPrefix
, &prefCount
, &prefNames
);
3926 if (NS_SUCCEEDED(rv
) && prefCount
> 0)
3928 rv
= InitPrincipals(prefCount
, (const char**)prefNames
, mSecurityPref
);
3929 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount
, prefNames
);
3930 NS_ENSURE_SUCCESS(rv
, rv
);
3932 //-- Set a callback for principal changes
3933 prefBranchInternal
->AddObserver(sPrincipalPrefix
, this, PR_FALSE
);
3938 ///////////////////////////////////////////////////////////////////////////////
3939 // The following code prints the contents of the policy DB to the console.
3940 #ifdef DEBUG_CAPS_HACKER
3942 //typedef PLDHashOperator
3943 //(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
3944 // PRUint32 number, void *arg);
3945 PR_STATIC_CALLBACK(PLDHashOperator
)
3946 PrintPropertyPolicy(PLDHashTable
*table
, PLDHashEntryHdr
*entry
,
3947 PRUint32 number
, void *arg
)
3949 PropertyPolicy
* pp
= (PropertyPolicy
*)entry
;
3950 nsCAutoString
prop(" ");
3951 JSContext
* cx
= (JSContext
*)arg
;
3952 prop
.AppendInt((PRUint32
)pp
->key
);
3954 prop
.AppendWithConversion((PRUnichar
*)JSValIDToString(cx
, pp
->key
));
3956 if (SECURITY_ACCESS_LEVEL_FLAG(pp
->mGet
))
3957 prop
.AppendInt(pp
->mGet
.level
);
3959 prop
+= pp
->mGet
.capability
;
3962 if (SECURITY_ACCESS_LEVEL_FLAG(pp
->mSet
))
3963 prop
.AppendInt(pp
->mSet
.level
);
3965 prop
+= pp
->mSet
.capability
;
3967 printf("%s.\n", prop
.get());
3968 return PL_DHASH_NEXT
;
3971 PR_STATIC_CALLBACK(PLDHashOperator
)
3972 PrintClassPolicy(PLDHashTable
*table
, PLDHashEntryHdr
*entry
,
3973 PRUint32 number
, void *arg
)
3975 ClassPolicy
* cp
= (ClassPolicy
*)entry
;
3976 printf(" %s\n", cp
->key
);
3978 PL_DHashTableEnumerate(cp
->mPolicy
, PrintPropertyPolicy
, arg
);
3979 return PL_DHASH_NEXT
;
3983 // (*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
3984 PR_STATIC_CALLBACK(PRBool
)
3985 PrintDomainPolicy(nsHashKey
*aKey
, void *aData
, void* aClosure
)
3987 DomainEntry
* de
= (DomainEntry
*)aData
;
3988 printf("----------------------------\n");
3989 printf("Domain: %s Policy Name: %s.\n", de
->mOrigin
.get(),
3990 de
->mPolicyName_DEBUG
.get());
3991 PL_DHashTableEnumerate(de
->mDomainPolicy
, PrintClassPolicy
, aClosure
);
3995 PR_STATIC_CALLBACK(PRBool
)
3996 PrintCapability(nsHashKey
*aKey
, void *aData
, void* aClosure
)
3998 char* cap
= (char*)aData
;
3999 printf(" %s.\n", cap
);
4004 nsScriptSecurityManager::PrintPolicyDB()
4006 printf("############## Security Policies ###############\n");
4007 if(mOriginToPolicyMap
)
4009 JSContext
* cx
= GetCurrentJSContext();
4011 cx
= GetSafeJSContext();
4012 printf("----------------------------\n");
4013 printf("Domain: Default.\n");
4014 PL_DHashTableEnumerate(mDefaultPolicy
, PrintClassPolicy
, (void*)cx
);
4015 mOriginToPolicyMap
->Enumerate(PrintDomainPolicy
, (void*)cx
);
4017 printf("############ End Security Policies #############\n\n");
4018 printf("############## Capabilities ###############\n");
4019 mCapabilities
->Enumerate(PrintCapability
);
4020 printf("############## End Capabilities ###############\n");