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.
23 * Norris Boyd <nboyd@atg.com>
24 * Mitch Stoltz <mstoltz@netscape.com>
25 * Christopher A. Aillon <christopher@aillon.com>
26 * Giorgio Maone <g.maone@informaction.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #ifndef nsScriptSecurityManager_h__
43 #define nsScriptSecurityManager_h__
45 #include "nsIScriptSecurityManager.h"
46 #include "nsIPrincipal.h"
49 #include "nsIXPCSecurityManager.h"
50 #include "nsInterfaceHashtable.h"
51 #include "nsHashtable.h"
53 #include "nsIPrefService.h"
54 #include "nsISecurityPref.h"
55 #include "nsIChannelEventSink.h"
56 #include "nsIJSContextStack.h"
57 #include "nsIObserver.h"
66 class nsIStringBundle
;
67 class nsSystemPrincipal
;
72 #if defined(DEBUG_mstoltz) || defined(DEBUG_caillon)
73 #define DEBUG_CAPS_HACKER
76 #ifdef DEBUG_CAPS_HACKER
77 #define DEBUG_CAPS_CheckPropertyAccessImpl
78 #define DEBUG_CAPS_LookupPolicy
79 #define DEBUG_CAPS_CheckComponentPermissions
83 #define DEBUG_CAPS_CanCreateWrapper
84 #define DEBUG_CAPS_CanCreateInstance
85 #define DEBUG_CAPS_CanGetService
86 #define DEBUG_CAPS_DomainPolicyLifeCycle
93 class PrincipalKey
: public PLDHashEntryHdr
96 typedef const nsIPrincipal
* KeyType
;
97 typedef const nsIPrincipal
* KeyTypePointer
;
99 PrincipalKey(const nsIPrincipal
* key
)
100 : mKey(const_cast<nsIPrincipal
*>(key
))
104 PrincipalKey(const PrincipalKey
& toCopy
)
113 KeyType
GetKey() const
118 PRBool
KeyEquals(KeyTypePointer aKey
) const
121 mKey
->Equals(const_cast<nsIPrincipal
*>(aKey
),
126 static KeyTypePointer
KeyToPointer(KeyType aKey
)
131 static PLDHashNumber
HashKey(KeyTypePointer aKey
)
134 const_cast<nsIPrincipal
*>(aKey
)->GetHashValue(&hash
);
135 return PLDHashNumber(hash
);
138 enum { ALLOW_MEMMOVE
= PR_TRUE
};
141 nsCOMPtr
<nsIPrincipal
> mKey
;
156 // These values all have the low bit set (except UNDEFINED_ACCESS)
157 // to distinguish them from pointer values, because no pointer
158 // to allocated memory ever has the low bit set. A SecurityLevel
159 // contains either one of these constants or a pointer to a string
160 // representing the name of a capability.
162 #define SCRIPT_SECURITY_UNDEFINED_ACCESS 0
163 #define SCRIPT_SECURITY_ACCESS_IS_SET_BIT 1
164 #define SCRIPT_SECURITY_NO_ACCESS \
165 ((1 << 0) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
166 #define SCRIPT_SECURITY_SAME_ORIGIN_ACCESS \
167 ((1 << 1) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
168 #define SCRIPT_SECURITY_ALL_ACCESS \
169 ((1 << 2) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
171 #define SECURITY_ACCESS_LEVEL_FLAG(_sl) \
172 ((_sl.level == 0) || \
173 (_sl.level & SCRIPT_SECURITY_ACCESS_IS_SET_BIT))
176 struct PropertyPolicy
: public PLDHashEntryHdr
178 jsval key
; // property name as jsval
184 InitPropertyPolicyEntry(PLDHashTable
*table
,
185 PLDHashEntryHdr
*entry
,
188 PropertyPolicy
* pp
= (PropertyPolicy
*)entry
;
189 pp
->key
= (jsval
)key
;
190 pp
->mGet
.level
= SCRIPT_SECURITY_UNDEFINED_ACCESS
;
191 pp
->mSet
.level
= SCRIPT_SECURITY_UNDEFINED_ACCESS
;
196 ClearPropertyPolicyEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
198 PropertyPolicy
* pp
= (PropertyPolicy
*)entry
;
199 pp
->key
= JSVAL_VOID
;
203 #define NO_POLICY_FOR_CLASS (ClassPolicy*)1
205 struct ClassPolicy
: public PLDHashEntryHdr
208 PLDHashTable
* mPolicy
;
210 // Note: the DomainPolicy owns us, so if if dies we will too. Hence no
211 // need to refcount it here (and in fact, we'd probably leak if we tried).
212 DomainPolicy
* mDomainWeAreWildcardFor
;
216 ClearClassPolicyEntry(PLDHashTable
*table
, PLDHashEntryHdr
*entry
)
218 ClassPolicy
* cp
= (ClassPolicy
*)entry
;
224 PL_DHashTableDestroy(cp
->mPolicy
);
227 // Note: actual impl is going to be after the DomainPolicy class definition,
228 // since we need to access members of DomainPolicy in the impl
230 MoveClassPolicyEntry(PLDHashTable
*table
,
231 const PLDHashEntryHdr
*from
,
232 PLDHashEntryHdr
*to
);
235 InitClassPolicyEntry(PLDHashTable
*table
,
236 PLDHashEntryHdr
*entry
,
239 static PLDHashTableOps classPolicyOps
=
243 PL_DHashVoidPtrKeyStub
,
244 PL_DHashMatchEntryStub
,
245 PL_DHashMoveEntryStub
,
246 ClearPropertyPolicyEntry
,
247 PL_DHashFinalizeStub
,
248 InitPropertyPolicyEntry
251 ClassPolicy
* cp
= (ClassPolicy
*)entry
;
252 cp
->mDomainWeAreWildcardFor
= nsnull
;
253 cp
->key
= PL_strdup((const char*)key
);
256 cp
->mPolicy
= PL_NewDHashTable(&classPolicyOps
, nsnull
,
257 sizeof(PropertyPolicy
), 16);
267 class DomainPolicy
: public PLDHashTable
270 DomainPolicy() : mWildcardPolicy(nsnull
),
273 mGeneration
= sGeneration
;
275 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
277 _printPopulationInfo();
284 static const PLDHashTableOps domainPolicyOps
=
289 PL_DHashMatchStringKey
,
290 MoveClassPolicyEntry
,
291 ClearClassPolicyEntry
,
292 PL_DHashFinalizeStub
,
296 return PL_DHashTableInit(this, &domainPolicyOps
, nsnull
,
297 sizeof(ClassPolicy
), 16);
302 PL_DHashTableFinish(this);
303 NS_ASSERTION(mRefCount
== 0, "Wrong refcount in DomainPolicy dtor");
304 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
305 printf("DomainPolicy deleted with mRefCount = %d\n", mRefCount
);
307 _printPopulationInfo();
319 if (--mRefCount
== 0)
323 static void InvalidateAll()
330 return mGeneration
!= sGeneration
;
333 ClassPolicy
* mWildcardPolicy
;
337 PRUint32 mGeneration
;
338 static PRUint32 sGeneration
;
340 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
341 static PRUint32 sObjects
;
342 static void _printPopulationInfo();
348 MoveClassPolicyEntry(PLDHashTable
*table
,
349 const PLDHashEntryHdr
*from
,
352 memcpy(to
, from
, table
->entrySize
);
354 // Now update the mDefaultPolicy pointer that points to us, if any.
355 ClassPolicy
* cp
= static_cast<ClassPolicy
*>(to
);
356 if (cp
->mDomainWeAreWildcardFor
) {
357 NS_ASSERTION(cp
->mDomainWeAreWildcardFor
->mWildcardPolicy
==
358 static_cast<const ClassPolicy
*>(from
),
359 "Unexpected wildcard policy on mDomainWeAreWildcardFor");
360 cp
->mDomainWeAreWildcardFor
->mWildcardPolicy
= cp
;
364 /////////////////////////////
365 // nsScriptSecurityManager //
366 /////////////////////////////
367 #define NS_SCRIPTSECURITYMANAGER_CID \
368 { 0x7ee2a4c0, 0x4b93, 0x17d3, \
369 { 0xba, 0x18, 0x00, 0x60, 0xb0, 0xf1, 0x99, 0xa2 }}
371 class nsScriptSecurityManager
: public nsIScriptSecurityManager
,
372 public nsIPrefSecurityCheck
,
373 public nsIChannelEventSink
,
377 static void Shutdown();
379 NS_DEFINE_STATIC_CID_ACCESSOR(NS_SCRIPTSECURITYMANAGER_CID
)
382 NS_DECL_NSISCRIPTSECURITYMANAGER
383 NS_DECL_NSIXPCSECURITYMANAGER
384 NS_DECL_NSIPREFSECURITYCHECK
385 NS_DECL_NSICHANNELEVENTSINK
388 static nsScriptSecurityManager
*
389 GetScriptSecurityManager();
391 static nsSystemPrincipal
*
392 SystemPrincipalSingletonConstructor();
394 JSContext
* GetCurrentJSContext();
396 JSContext
* GetSafeJSContext();
399 * Utility method for comparing two URIs. For security purposes, two URIs
400 * are equivalent if their schemes, hosts, and ports (if any) match. This
401 * method returns true if aSubjectURI and aObjectURI have the same origin,
404 static PRBool
SecurityCompareURIs(nsIURI
* aSourceURI
, nsIURI
* aTargetURI
);
405 static PRUint32
SecurityHashURI(nsIURI
* aURI
);
408 ReportError(JSContext
* cx
, const nsAString
& messageTag
,
409 nsIURI
* aSource
, nsIURI
* aTarget
);
412 CheckSameOriginPrincipal(nsIPrincipal
* aSubject
,
413 nsIPrincipal
* aObject
);
415 HashPrincipalByOrigin(nsIPrincipal
* aPrincipal
);
418 GetStrictFileOriginPolicy()
420 return sStrictFileOriginPolicy
;
425 // GetScriptSecurityManager is the only call that can make one
426 nsScriptSecurityManager();
427 virtual ~nsScriptSecurityManager();
430 CheckObjectAccess(JSContext
*cx
, JSObject
*obj
,
431 jsval id
, JSAccessMode mode
,
434 // Returns null if a principal cannot be found; generally callers
435 // should error out at that point.
437 doGetObjectPrincipal(JSObject
*obj
439 , PRBool aAllowShortCircuit
= PR_TRUE
443 // Returns null if a principal cannot be found. Note that rv can be NS_OK
444 // when this happens -- this means that there was no JS running.
446 doGetSubjectPrincipal(nsresult
* rv
);
449 CheckPropertyAccessImpl(PRUint32 aAction
,
450 nsAXPCNativeCallContext
* aCallContext
,
451 JSContext
* cx
, JSObject
* aJSObject
,
452 nsISupports
* aObj
, nsIURI
* aTargetURI
,
453 nsIClassInfo
* aClassInfo
,
454 const char* aClassName
, jsval aProperty
,
455 void** aCachedClassPolicy
);
458 CheckSameOriginDOMProp(nsIPrincipal
* aSubject
,
459 nsIPrincipal
* aObject
,
463 LookupPolicy(nsIPrincipal
* principal
,
464 ClassInfoData
& aClassData
, jsval aProperty
,
466 ClassPolicy
** aCachedClassPolicy
,
467 SecurityLevel
* result
);
470 CreateCodebasePrincipal(nsIURI
* aURI
, nsIPrincipal
** result
);
472 // This is just like the API method, but it doesn't check that the subject
473 // name is non-empty or aCertificate is non-null, and it doesn't change the
474 // certificate in the table (if any) in any way if aModifyTable is false.
476 DoGetCertificatePrincipal(const nsACString
& aCertFingerprint
,
477 const nsACString
& aSubjectName
,
478 const nsACString
& aPrettyName
,
479 nsISupports
* aCertificate
,
482 nsIPrincipal
**result
);
484 // Returns null if a principal cannot be found. Note that rv can be NS_OK
485 // when this happens -- this means that there was no script for the
486 // context. Callers MUST pass in a non-null rv here.
488 GetSubjectPrincipal(JSContext
* cx
, nsresult
* rv
);
490 // Returns null if a principal cannot be found. Note that rv can be NS_OK
491 // when this happens -- this means that there was no script for the frame.
492 // Callers MUST pass in a non-null rv here.
494 GetFramePrincipal(JSContext
* cx
, JSStackFrame
* fp
, nsresult
* rv
);
496 // Returns null if a principal cannot be found. Note that rv can be NS_OK
497 // when this happens -- this means that there was no script. Callers MUST
498 // pass in a non-null rv here.
500 GetScriptPrincipal(JSContext
* cx
, JSScript
* script
, nsresult
* rv
);
502 // Returns null if a principal cannot be found. Note that rv can be NS_OK
503 // when this happens -- this means that there was no script associated
504 // with the function object, and no global object associated with the scope
505 // of obj (the last object on its parent chain). If the caller is walking
506 // the JS stack, fp must point to the current frame in the stack iteration.
507 // Callers MUST pass in a non-null rv here.
509 GetFunctionObjectPrincipal(JSContext
* cx
, JSObject
* obj
, JSStackFrame
*fp
,
512 // Returns null if a principal cannot be found. Note that rv can be NS_OK
513 // when this happens -- this means that there was no script
514 // running. Callers MUST pass in a non-null rv here.
516 GetPrincipalAndFrame(JSContext
*cx
,
517 JSStackFrame
** frameResult
,
521 CheckConfirmDialog(JSContext
* cx
, nsIPrincipal
* aPrincipal
,
522 const char* aCapability
, PRBool
*checkValue
);
525 FormatCapabilityString(nsAString
& aCapability
);
528 SavePrincipal(nsIPrincipal
* aToSave
);
531 * Check capability levels for an |aObj| that implements
532 * nsISecurityCheckedComponent.
534 * NB: This function also checks to see if aObj is a plugin and the user
535 * has set the "security.xpconnect.plugin.unrestricted" pref to allow
536 * anybody to script plugin objects from anywhere.
538 * @param cx The context we're running on.
539 * NB: If null, "sameOrigin" does not have any effect.
540 * @param aObj The nsISupports representation of the object in question
541 * object, possibly null.
542 * @param aJSObject The JSObject representation of the object in question
543 * if |cx| is non-null and |aObjectSecurityLevel| is
544 * "sameOrigin". If null will be calculated from aObj (if
545 * non-null) if and only if aObj is an XPCWrappedJS. The
546 * rationale behind this is that if we're creating a JS
547 * wrapper for an XPCWrappedJS, this object definitely
548 * expects to be exposed to JS.
549 * @param aSubjectPrincipal The nominal subject principal used when
550 * aObjectSecurityLevel is "sameOrigin". If null,
551 * this is calculated if it's needed.
552 * @param aObjectSecurityLevel Can be one of three values:
553 * - allAccess: Allow access no matter what.
554 * - noAccess: Deny access no matter what.
555 * - sameOrigin: If |cx| is null, behave like noAccess.
556 * Otherwise, possibly compute a subject
557 * and object principal and return true if
558 * and only if the subject has greater than
559 * or equal privileges to the object.
562 CheckXPCPermissions(JSContext
* cx
,
563 nsISupports
* aObj
, JSObject
* aJSObject
,
564 nsIPrincipal
* aSubjectPrincipal
,
565 const char* aObjectSecurityLevel
);
574 GetPrincipalPrefNames(const char* prefBase
,
575 nsCString
& grantedPref
,
576 nsCString
& deniedPref
,
577 nsCString
& subjectNamePref
);
583 InitDomainPolicy(JSContext
* cx
, const char* aPolicyName
,
584 DomainPolicy
* aDomainPolicy
);
587 InitPrincipals(PRUint32 prefCount
, const char** prefNames
,
588 nsISecurityPref
* securityPref
);
591 #ifdef XPC_IDISPATCH_SUPPORT
592 // While this header is included outside of caps, this class isn't
593 // referenced so this should be fine.
595 CheckComponentPermissions(JSContext
*cx
, const nsCID
&aCID
);
597 #ifdef DEBUG_CAPS_HACKER
602 struct ContextPrincipal
{
603 ContextPrincipal(ContextPrincipal
*next
, JSContext
*cx
,
604 JSStackFrame
*fp
, nsIPrincipal
*principal
)
605 : mNext(next
), mCx(cx
), mFp(fp
), mPrincipal(principal
) {}
607 ContextPrincipal
*mNext
;
610 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
613 // JS strings we need to clean up on shutdown
614 static jsval sEnabledID
;
617 ScriptSecurityPrefChanged();
619 static const char sJSEnabledPrefName
[];
620 static const char sFileOriginPolicyPrefName
[];
622 nsObjectHashtable
* mOriginToPolicyMap
;
623 DomainPolicy
* mDefaultPolicy
;
624 nsObjectHashtable
* mCapabilities
;
626 nsCOMPtr
<nsIPrefBranch
> mPrefBranch
;
627 nsCOMPtr
<nsISecurityPref
> mSecurityPref
;
628 nsCOMPtr
<nsIPrincipal
> mSystemPrincipal
;
629 nsCOMPtr
<nsIPrincipal
> mSystemCertificate
;
630 ContextPrincipal
*mContextPrincipals
;
631 nsInterfaceHashtable
<PrincipalKey
, nsIPrincipal
> mPrincipals
;
632 PRPackedBool mIsJavaScriptEnabled
;
633 PRPackedBool mIsWritingPrefs
;
634 PRPackedBool mPolicyPrefsChanged
;
635 #ifdef XPC_IDISPATCH_SUPPORT
636 PRPackedBool mXPCDefaultGrantAll
;
637 static const char sXPCDefaultGrantAllName
[];
640 static PRBool sStrictFileOriginPolicy
;
642 static nsIIOService
*sIOService
;
643 static nsIXPConnect
*sXPConnect
;
644 static nsIThreadJSContextStack
* sJSContextStack
;
645 static nsIStringBundle
*sStrBundle
;
646 static JSRuntime
*sRuntime
;
649 #endif // nsScriptSecurityManager_h__