Another followup, deferred nit-pick for 547314.
[mozilla-central.git] / caps / include / nsScriptSecurityManager.h
blob0cb01490aa776309cdb591f9d11a3633b4481a3a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Norris Boyd <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"
47 #include "jsapi.h"
48 #include "jsdbgapi.h"
49 #include "nsIXPCSecurityManager.h"
50 #include "nsInterfaceHashtable.h"
51 #include "nsHashtable.h"
52 #include "nsCOMPtr.h"
53 #include "nsIPrefService.h"
54 #include "nsISecurityPref.h"
55 #include "nsIChannelEventSink.h"
56 #include "nsIJSContextStack.h"
57 #include "nsIObserver.h"
58 #include "pldhash.h"
59 #include "plstr.h"
61 class nsIDocShell;
62 class nsString;
63 class nsIClassInfo;
64 class nsIIOService;
65 class nsIXPConnect;
66 class nsIStringBundle;
67 class nsSystemPrincipal;
68 struct ClassPolicy;
69 class ClassInfoData;
70 class DomainPolicy;
72 #if defined(DEBUG_mstoltz) || defined(DEBUG_caillon)
73 #define DEBUG_CAPS_HACKER
74 #endif
76 #ifdef DEBUG_CAPS_HACKER
77 #define DEBUG_CAPS_CheckPropertyAccessImpl
78 #define DEBUG_CAPS_LookupPolicy
79 #define DEBUG_CAPS_CheckComponentPermissions
80 #endif
82 #if 0
83 #define DEBUG_CAPS_CanCreateWrapper
84 #define DEBUG_CAPS_CanCreateInstance
85 #define DEBUG_CAPS_CanGetService
86 #define DEBUG_CAPS_DomainPolicyLifeCycle
87 #endif
89 /////////////////////
90 // PrincipalKey //
91 /////////////////////
93 class PrincipalKey : public PLDHashEntryHdr
95 public:
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)
105 : mKey(toCopy.mKey)
109 ~PrincipalKey()
113 KeyType GetKey() const
115 return mKey;
118 PRBool KeyEquals(KeyTypePointer aKey) const
120 PRBool eq;
121 mKey->Equals(const_cast<nsIPrincipal*>(aKey),
122 &eq);
123 return eq;
126 static KeyTypePointer KeyToPointer(KeyType aKey)
128 return aKey;
131 static PLDHashNumber HashKey(KeyTypePointer aKey)
133 PRUint32 hash;
134 const_cast<nsIPrincipal*>(aKey)->GetHashValue(&hash);
135 return PLDHashNumber(hash);
138 enum { ALLOW_MEMMOVE = PR_TRUE };
140 private:
141 nsCOMPtr<nsIPrincipal> mKey;
144 ////////////////////
145 // Policy Storage //
146 ////////////////////
148 // Property Policy
149 union SecurityLevel
151 PRWord level;
152 char* capability;
155 // Security levels
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
179 SecurityLevel mGet;
180 SecurityLevel mSet;
183 static PRBool
184 InitPropertyPolicyEntry(PLDHashTable *table,
185 PLDHashEntryHdr *entry,
186 const void *key)
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;
192 return PR_TRUE;
195 static void
196 ClearPropertyPolicyEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
198 PropertyPolicy* pp = (PropertyPolicy*)entry;
199 pp->key = JSVAL_VOID;
202 // Class Policy
203 #define NO_POLICY_FOR_CLASS (ClassPolicy*)1
205 struct ClassPolicy : public PLDHashEntryHdr
207 char* key;
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;
215 static void
216 ClearClassPolicyEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
218 ClassPolicy* cp = (ClassPolicy *)entry;
219 if (cp->key)
221 PL_strfree(cp->key);
222 cp->key = nsnull;
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
229 static void
230 MoveClassPolicyEntry(PLDHashTable *table,
231 const PLDHashEntryHdr *from,
232 PLDHashEntryHdr *to);
234 static PRBool
235 InitClassPolicyEntry(PLDHashTable *table,
236 PLDHashEntryHdr *entry,
237 const void *key)
239 static PLDHashTableOps classPolicyOps =
241 PL_DHashAllocTable,
242 PL_DHashFreeTable,
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);
254 if (!cp->key)
255 return PR_FALSE;
256 cp->mPolicy = PL_NewDHashTable(&classPolicyOps, nsnull,
257 sizeof(PropertyPolicy), 16);
258 if (!cp->mPolicy) {
259 PL_strfree(cp->key);
260 cp->key = nsnull;
261 return PR_FALSE;
263 return PR_TRUE;
266 // Domain Policy
267 class DomainPolicy : public PLDHashTable
269 public:
270 DomainPolicy() : mWildcardPolicy(nsnull),
271 mRefCount(0)
273 mGeneration = sGeneration;
275 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
276 ++sObjects;
277 _printPopulationInfo();
278 #endif
282 PRBool Init()
284 static const PLDHashTableOps domainPolicyOps =
286 PL_DHashAllocTable,
287 PL_DHashFreeTable,
288 PL_DHashStringKey,
289 PL_DHashMatchStringKey,
290 MoveClassPolicyEntry,
291 ClearClassPolicyEntry,
292 PL_DHashFinalizeStub,
293 InitClassPolicyEntry
296 return PL_DHashTableInit(this, &domainPolicyOps, nsnull,
297 sizeof(ClassPolicy), 16);
300 ~DomainPolicy()
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);
306 --sObjects;
307 _printPopulationInfo();
308 #endif
312 void Hold()
314 mRefCount++;
317 void Drop()
319 if (--mRefCount == 0)
320 delete this;
323 static void InvalidateAll()
325 sGeneration++;
328 PRBool IsInvalid()
330 return mGeneration != sGeneration;
333 ClassPolicy* mWildcardPolicy;
335 private:
336 PRUint32 mRefCount;
337 PRUint32 mGeneration;
338 static PRUint32 sGeneration;
340 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
341 static PRUint32 sObjects;
342 static void _printPopulationInfo();
343 #endif
347 static void
348 MoveClassPolicyEntry(PLDHashTable *table,
349 const PLDHashEntryHdr *from,
350 PLDHashEntryHdr *to)
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,
374 public nsIObserver
376 public:
377 static void Shutdown();
379 NS_DEFINE_STATIC_CID_ACCESSOR(NS_SCRIPTSECURITYMANAGER_CID)
381 NS_DECL_ISUPPORTS
382 NS_DECL_NSISCRIPTSECURITYMANAGER
383 NS_DECL_NSIXPCSECURITYMANAGER
384 NS_DECL_NSIPREFSECURITYCHECK
385 NS_DECL_NSICHANNELEVENTSINK
386 NS_DECL_NSIOBSERVER
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,
402 * false otherwise.
404 static PRBool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
405 static PRUint32 SecurityHashURI(nsIURI* aURI);
407 static nsresult
408 ReportError(JSContext* cx, const nsAString& messageTag,
409 nsIURI* aSource, nsIURI* aTarget);
411 static nsresult
412 CheckSameOriginPrincipal(nsIPrincipal* aSubject,
413 nsIPrincipal* aObject);
414 static PRUint32
415 HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
417 static PRBool
418 GetStrictFileOriginPolicy()
420 return sStrictFileOriginPolicy;
423 private:
425 // GetScriptSecurityManager is the only call that can make one
426 nsScriptSecurityManager();
427 virtual ~nsScriptSecurityManager();
429 static JSBool
430 CheckObjectAccess(JSContext *cx, JSObject *obj,
431 jsval id, JSAccessMode mode,
432 jsval *vp);
434 // Returns null if a principal cannot be found; generally callers
435 // should error out at that point.
436 static nsIPrincipal*
437 doGetObjectPrincipal(JSObject *obj
438 #ifdef DEBUG
439 , PRBool aAllowShortCircuit = PR_TRUE
440 #endif
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.
445 nsIPrincipal*
446 doGetSubjectPrincipal(nsresult* rv);
448 nsresult
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);
457 nsresult
458 CheckSameOriginDOMProp(nsIPrincipal* aSubject,
459 nsIPrincipal* aObject,
460 PRUint32 aAction);
462 nsresult
463 LookupPolicy(nsIPrincipal* principal,
464 ClassInfoData& aClassData, jsval aProperty,
465 PRUint32 aAction,
466 ClassPolicy** aCachedClassPolicy,
467 SecurityLevel* result);
469 nsresult
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.
475 nsresult
476 DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
477 const nsACString& aSubjectName,
478 const nsACString& aPrettyName,
479 nsISupports* aCertificate,
480 nsIURI* aURI,
481 PRBool aModifyTable,
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.
487 nsIPrincipal*
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.
493 nsIPrincipal*
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.
499 static nsIPrincipal*
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.
508 static nsIPrincipal*
509 GetFunctionObjectPrincipal(JSContext* cx, JSObject* obj, JSStackFrame *fp,
510 nsresult* rv);
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.
515 nsIPrincipal*
516 GetPrincipalAndFrame(JSContext *cx,
517 JSStackFrame** frameResult,
518 nsresult* rv);
520 static PRBool
521 CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
522 const char* aCapability, PRBool *checkValue);
524 static void
525 FormatCapabilityString(nsAString& aCapability);
527 nsresult
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.
561 nsresult
562 CheckXPCPermissions(JSContext* cx,
563 nsISupports* aObj, JSObject* aJSObject,
564 nsIPrincipal* aSubjectPrincipal,
565 const char* aObjectSecurityLevel);
567 nsresult
568 Init();
570 nsresult
571 InitPrefs();
573 static nsresult
574 GetPrincipalPrefNames(const char* prefBase,
575 nsCString& grantedPref,
576 nsCString& deniedPref,
577 nsCString& subjectNamePref);
579 nsresult
580 InitPolicies();
582 nsresult
583 InitDomainPolicy(JSContext* cx, const char* aPolicyName,
584 DomainPolicy* aDomainPolicy);
586 nsresult
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.
594 nsresult
595 CheckComponentPermissions(JSContext *cx, const nsCID &aCID);
596 #endif
597 #ifdef DEBUG_CAPS_HACKER
598 void
599 PrintPolicyDB();
600 #endif
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;
608 JSContext *mCx;
609 JSStackFrame *mFp;
610 nsCOMPtr<nsIPrincipal> mPrincipal;
613 // JS strings we need to clean up on shutdown
614 static jsval sEnabledID;
616 inline void
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[];
638 #endif
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__