Automated checkin: version bump remove "pre" from version number for firefox 4.0b1...
[mozilla-central.git] / caps / include / nsScriptSecurityManager.h
blobb4ddf6f558c57c28aaeef0c90f7455bdebd2e7ea
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 "nsIChannelEventSink.h"
55 #include "nsIJSContextStack.h"
56 #include "nsIObserver.h"
57 #include "pldhash.h"
58 #include "plstr.h"
59 #include "nsIScriptExternalNameSet.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 nsIChannelEventSink,
373 public nsIObserver
375 public:
376 static void Shutdown();
378 NS_DEFINE_STATIC_CID_ACCESSOR(NS_SCRIPTSECURITYMANAGER_CID)
380 NS_DECL_ISUPPORTS
381 NS_DECL_NSISCRIPTSECURITYMANAGER
382 NS_DECL_NSIXPCSECURITYMANAGER
383 NS_DECL_NSICHANNELEVENTSINK
384 NS_DECL_NSIOBSERVER
386 static nsScriptSecurityManager*
387 GetScriptSecurityManager();
389 static nsSystemPrincipal*
390 SystemPrincipalSingletonConstructor();
392 JSContext* GetCurrentJSContext();
394 JSContext* GetSafeJSContext();
397 * Utility method for comparing two URIs. For security purposes, two URIs
398 * are equivalent if their schemes, hosts, and ports (if any) match. This
399 * method returns true if aSubjectURI and aObjectURI have the same origin,
400 * false otherwise.
402 static PRBool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
403 static PRUint32 SecurityHashURI(nsIURI* aURI);
405 static nsresult
406 ReportError(JSContext* cx, const nsAString& messageTag,
407 nsIURI* aSource, nsIURI* aTarget);
409 static nsresult
410 CheckSameOriginPrincipal(nsIPrincipal* aSubject,
411 nsIPrincipal* aObject);
412 static PRUint32
413 HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
415 static PRBool
416 GetStrictFileOriginPolicy()
418 return sStrictFileOriginPolicy;
421 private:
423 // GetScriptSecurityManager is the only call that can make one
424 nsScriptSecurityManager();
425 virtual ~nsScriptSecurityManager();
427 static JSBool
428 CheckObjectAccess(JSContext *cx, JSObject *obj,
429 jsval id, JSAccessMode mode,
430 jsval *vp);
432 // Decides, based on CSP, whether or not eval() and stuff can be executed.
433 static JSBool
434 ContentSecurityPolicyPermitsJSAction(JSContext *cx);
436 // Returns null if a principal cannot be found; generally callers
437 // should error out at that point.
438 static nsIPrincipal*
439 doGetObjectPrincipal(JSObject *obj
440 #ifdef DEBUG
441 , PRBool aAllowShortCircuit = PR_TRUE
442 #endif
445 // Returns null if a principal cannot be found. Note that rv can be NS_OK
446 // when this happens -- this means that there was no JS running.
447 nsIPrincipal*
448 doGetSubjectPrincipal(nsresult* rv);
450 nsresult
451 CheckPropertyAccessImpl(PRUint32 aAction,
452 nsAXPCNativeCallContext* aCallContext,
453 JSContext* cx, JSObject* aJSObject,
454 nsISupports* aObj, nsIURI* aTargetURI,
455 nsIClassInfo* aClassInfo,
456 const char* aClassName, jsval aProperty,
457 void** aCachedClassPolicy);
459 nsresult
460 CheckSameOriginDOMProp(nsIPrincipal* aSubject,
461 nsIPrincipal* aObject,
462 PRUint32 aAction);
464 nsresult
465 LookupPolicy(nsIPrincipal* principal,
466 ClassInfoData& aClassData, jsval aProperty,
467 PRUint32 aAction,
468 ClassPolicy** aCachedClassPolicy,
469 SecurityLevel* result);
471 nsresult
472 CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal** result);
474 // This is just like the API method, but it doesn't check that the subject
475 // name is non-empty or aCertificate is non-null, and it doesn't change the
476 // certificate in the table (if any) in any way if aModifyTable is false.
477 nsresult
478 DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
479 const nsACString& aSubjectName,
480 const nsACString& aPrettyName,
481 nsISupports* aCertificate,
482 nsIURI* aURI,
483 PRBool aModifyTable,
484 nsIPrincipal **result);
486 // Returns null if a principal cannot be found. Note that rv can be NS_OK
487 // when this happens -- this means that there was no script for the
488 // context. Callers MUST pass in a non-null rv here.
489 nsIPrincipal*
490 GetSubjectPrincipal(JSContext* cx, nsresult* rv);
492 // Returns null if a principal cannot be found. Note that rv can be NS_OK
493 // when this happens -- this means that there was no script for the frame.
494 // Callers MUST pass in a non-null rv here.
495 nsIPrincipal*
496 GetFramePrincipal(JSContext* cx, JSStackFrame* fp, nsresult* rv);
498 // Returns null if a principal cannot be found. Note that rv can be NS_OK
499 // when this happens -- this means that there was no script. Callers MUST
500 // pass in a non-null rv here.
501 static nsIPrincipal*
502 GetScriptPrincipal(JSContext* cx, JSScript* script, nsresult* rv);
504 // Returns null if a principal cannot be found. Note that rv can be NS_OK
505 // when this happens -- this means that there was no script associated
506 // with the function object, and no global object associated with the scope
507 // of obj (the last object on its parent chain). If the caller is walking
508 // the JS stack, fp must point to the current frame in the stack iteration.
509 // Callers MUST pass in a non-null rv here.
510 static nsIPrincipal*
511 GetFunctionObjectPrincipal(JSContext* cx, JSObject* obj, JSStackFrame *fp,
512 nsresult* rv);
514 // Returns null if a principal cannot be found. Note that rv can be NS_OK
515 // when this happens -- this means that there was no script
516 // running. Callers MUST pass in a non-null rv here.
517 nsIPrincipal*
518 GetPrincipalAndFrame(JSContext *cx,
519 JSStackFrame** frameResult,
520 nsresult* rv);
522 static PRBool
523 CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
524 const char* aCapability, PRBool *checkValue);
526 static void
527 FormatCapabilityString(nsAString& aCapability);
529 nsresult
530 SavePrincipal(nsIPrincipal* aToSave);
533 * Check capability levels for an |aObj| that implements
534 * nsISecurityCheckedComponent.
536 * NB: This function also checks to see if aObj is a plugin and the user
537 * has set the "security.xpconnect.plugin.unrestricted" pref to allow
538 * anybody to script plugin objects from anywhere.
540 * @param cx The context we're running on.
541 * NB: If null, "sameOrigin" does not have any effect.
542 * @param aObj The nsISupports representation of the object in question
543 * object, possibly null.
544 * @param aJSObject The JSObject representation of the object in question
545 * if |cx| is non-null and |aObjectSecurityLevel| is
546 * "sameOrigin". If null will be calculated from aObj (if
547 * non-null) if and only if aObj is an XPCWrappedJS. The
548 * rationale behind this is that if we're creating a JS
549 * wrapper for an XPCWrappedJS, this object definitely
550 * expects to be exposed to JS.
551 * @param aSubjectPrincipal The nominal subject principal used when
552 * aObjectSecurityLevel is "sameOrigin". If null,
553 * this is calculated if it's needed.
554 * @param aObjectSecurityLevel Can be one of three values:
555 * - allAccess: Allow access no matter what.
556 * - noAccess: Deny access no matter what.
557 * - sameOrigin: If |cx| is null, behave like noAccess.
558 * Otherwise, possibly compute a subject
559 * and object principal and return true if
560 * and only if the subject has greater than
561 * or equal privileges to the object.
563 nsresult
564 CheckXPCPermissions(JSContext* cx,
565 nsISupports* aObj, JSObject* aJSObject,
566 nsIPrincipal* aSubjectPrincipal,
567 const char* aObjectSecurityLevel);
569 nsresult
570 Init();
572 nsresult
573 InitPrefs();
575 static nsresult
576 GetPrincipalPrefNames(const char* prefBase,
577 nsCString& grantedPref,
578 nsCString& deniedPref,
579 nsCString& subjectNamePref);
581 nsresult
582 InitPolicies();
584 nsresult
585 InitDomainPolicy(JSContext* cx, const char* aPolicyName,
586 DomainPolicy* aDomainPolicy);
588 nsresult
589 InitPrincipals(PRUint32 prefCount, const char** prefNames);
592 #ifdef XPC_IDISPATCH_SUPPORT
593 // While this header is included outside of caps, this class isn't
594 // referenced so this should be fine.
595 nsresult
596 CheckComponentPermissions(JSContext *cx, const nsCID &aCID);
597 #endif
598 #ifdef DEBUG_CAPS_HACKER
599 void
600 PrintPolicyDB();
601 #endif
603 struct ContextPrincipal {
604 ContextPrincipal(ContextPrincipal *next, JSContext *cx,
605 JSStackFrame *fp, nsIPrincipal *principal)
606 : mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {}
608 ContextPrincipal *mNext;
609 JSContext *mCx;
610 JSStackFrame *mFp;
611 nsCOMPtr<nsIPrincipal> mPrincipal;
614 // JS strings we need to clean up on shutdown
615 static jsval sEnabledID;
617 inline void
618 ScriptSecurityPrefChanged();
620 static const char sJSEnabledPrefName[];
621 static const char sFileOriginPolicyPrefName[];
623 nsObjectHashtable* mOriginToPolicyMap;
624 DomainPolicy* mDefaultPolicy;
625 nsObjectHashtable* mCapabilities;
627 nsCOMPtr<nsIPrefBranch> mPrefBranch;
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 #define NS_SECURITYNAMESET_CID \
650 { 0x7c02eadc, 0x76, 0x4d03, \
651 { 0x99, 0x8d, 0x80, 0xd7, 0x79, 0xc4, 0x85, 0x89 } }
652 #define NS_SECURITYNAMESET_CONTRACTID "@mozilla.org/security/script/nameset;1"
654 class nsSecurityNameSet : public nsIScriptExternalNameSet
656 public:
657 nsSecurityNameSet();
658 virtual ~nsSecurityNameSet();
660 NS_DECL_ISUPPORTS
662 NS_IMETHOD InitializeNameSet(nsIScriptContext* aScriptContext);
665 #endif // nsScriptSecurityManager_h__