Back to index

lightning-sunbird  0.9+nobinonly
nsScriptSecurityManager.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Norris Boyd  <nboyd@atg.com>
00024  *   Mitch Stoltz <mstoltz@netscape.com>
00025  *   Christopher A. Aillon <christopher@aillon.com>
00026  *   Giorgio Maone <g.maone@informaction.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #ifndef nsScriptSecurityManager_h__
00043 #define nsScriptSecurityManager_h__
00044 
00045 #include "nsIScriptSecurityManager.h"
00046 #include "nsIPrincipal.h"
00047 #include "jsapi.h"
00048 #include "jsdbgapi.h"
00049 #include "nsIXPCSecurityManager.h"
00050 #include "nsInterfaceHashtable.h"
00051 #include "nsHashtable.h"
00052 #include "nsCOMPtr.h"
00053 #include "nsIPrefService.h"
00054 #include "nsISecurityPref.h"
00055 #include "nsIJSContextStack.h"
00056 #include "nsIObserver.h"
00057 #include "pldhash.h"
00058 #include "plstr.h"
00059 
00060 class nsIDocShell;
00061 class nsString;
00062 class nsIClassInfo;
00063 class nsIIOService;
00064 class nsIXPConnect;
00065 class nsIStringBundle;
00066 class nsSystemPrincipal;
00067 struct ClassPolicy;
00068 class DomainPolicy;
00069 
00070 #if defined(DEBUG_mstoltz) || defined(DEBUG_caillon)
00071 #define DEBUG_CAPS_HACKER
00072 #endif
00073 
00074 #ifdef DEBUG_CAPS_HACKER
00075 #define DEBUG_CAPS_CheckPropertyAccessImpl
00076 #define DEBUG_CAPS_LookupPolicy
00077 #define DEBUG_CAPS_CheckComponentPermissions
00078 #endif
00079 
00080 #if 0
00081 #define DEBUG_CAPS_CanCreateWrapper
00082 #define DEBUG_CAPS_CanCreateInstance
00083 #define DEBUG_CAPS_CanGetService
00084 #define DEBUG_CAPS_DomainPolicyLifeCycle
00085 #endif
00086 
00088 // PrincipalKey //
00090 
00091 class PrincipalKey : public PLDHashEntryHdr
00092 {
00093 public:
00094     typedef const nsIPrincipal* KeyType;
00095     typedef const nsIPrincipal* KeyTypePointer;
00096 
00097     PrincipalKey(const nsIPrincipal* key)
00098       : mKey(NS_CONST_CAST(nsIPrincipal*, key))
00099     {
00100     }
00101 
00102     PrincipalKey(const PrincipalKey& toCopy)
00103       : mKey(toCopy.mKey)
00104     {
00105     } 
00106 
00107     ~PrincipalKey()
00108     {
00109     }
00110 
00111     KeyType GetKey() const
00112     {
00113         return mKey;
00114     }
00115 
00116     KeyTypePointer GetKeyPointer() const
00117     {
00118         return mKey;
00119     }
00120 
00121     PRBool KeyEquals(KeyTypePointer aKey) const
00122     {
00123         PRBool eq;
00124         mKey->Equals(NS_CONST_CAST(nsIPrincipal*, aKey),
00125                      &eq);
00126         return eq;
00127     }
00128 
00129     static KeyTypePointer KeyToPointer(KeyType aKey)
00130     {
00131         return aKey;
00132     }
00133 
00134     static PLDHashNumber HashKey(KeyTypePointer aKey)
00135     {
00136         PRUint32 hash;
00137         NS_CONST_CAST(nsIPrincipal*, aKey)->GetHashValue(&hash);
00138         return PLDHashNumber(hash);
00139     }
00140 
00141     enum { ALLOW_MEMMOVE = PR_TRUE };
00142 
00143 private:
00144     nsCOMPtr<nsIPrincipal> mKey;
00145 };
00146 
00148 // Policy Storage //
00150 
00151 // Property Policy
00152 union SecurityLevel
00153 {
00154     PRInt32  level;
00155     char*    capability;
00156 };
00157 
00158 // Security levels
00159 // These values all have the low bit set (except UNDEFINED_ACCESS)
00160 // to distinguish them from pointer values, because no pointer
00161 // to allocated memory ever has the low bit set. A SecurityLevel
00162 // contains either one of these constants or a pointer to a string
00163 // representing the name of a capability.
00164 
00165 #define SCRIPT_SECURITY_UNDEFINED_ACCESS 0
00166 #define SCRIPT_SECURITY_ACCESS_IS_SET_BIT 1
00167 #define SCRIPT_SECURITY_NO_ACCESS \
00168   ((1 << 0) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
00169 #define SCRIPT_SECURITY_SAME_ORIGIN_ACCESS \
00170   ((1 << 1) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
00171 #define SCRIPT_SECURITY_ALL_ACCESS \
00172   ((1 << 2) | SCRIPT_SECURITY_ACCESS_IS_SET_BIT)
00173 
00174 #define SECURITY_ACCESS_LEVEL_FLAG(_sl) \
00175            ((_sl.level == 0) || \
00176             (_sl.level & SCRIPT_SECURITY_ACCESS_IS_SET_BIT))
00177 
00178 
00179 struct PropertyPolicy : public PLDHashEntryHdr
00180 {
00181     jsval          key;  // property name as jsval
00182     SecurityLevel  mGet;
00183     SecurityLevel  mSet;
00184 };
00185 
00186 PR_STATIC_CALLBACK(PRBool)
00187 InitPropertyPolicyEntry(PLDHashTable *table,
00188                      PLDHashEntryHdr *entry,
00189                      const void *key)
00190 {
00191     PropertyPolicy* pp = (PropertyPolicy*)entry;
00192     pp->key = (jsval)key;
00193     pp->mGet.level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
00194     pp->mSet.level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
00195     return PR_TRUE;
00196 }
00197 
00198 PR_STATIC_CALLBACK(void)
00199 ClearPropertyPolicyEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00200 {
00201     PropertyPolicy* pp = (PropertyPolicy*)entry;
00202     pp->key = JSVAL_VOID;
00203 }
00204 
00205 // Class Policy
00206 #define NO_POLICY_FOR_CLASS (ClassPolicy*)1
00207 
00208 struct ClassPolicy : public PLDHashEntryHdr
00209 {
00210     char* key;
00211     PLDHashTable* mPolicy;
00212 
00213     // Note: the DomainPolicy owns us, so if if dies we will too.  Hence no
00214     // need to refcount it here (and in fact, we'd probably leak if we tried).
00215     DomainPolicy* mDomainWeAreWildcardFor;
00216 };
00217 
00218 PR_STATIC_CALLBACK(void)
00219 ClearClassPolicyEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00220 {
00221     ClassPolicy* cp = (ClassPolicy *)entry;
00222     if (cp->key)
00223     {
00224         PL_strfree(cp->key);
00225         cp->key = nsnull;
00226     }
00227     PL_DHashTableDestroy(cp->mPolicy);
00228 }
00229 
00230 // Note: actual impl is going to be after the DomainPolicy class definition,
00231 // since we need to access members of DomainPolicy in the impl
00232 PR_STATIC_CALLBACK(void)
00233 MoveClassPolicyEntry(PLDHashTable *table,
00234                      const PLDHashEntryHdr *from,
00235                      PLDHashEntryHdr *to);
00236 
00237 PR_STATIC_CALLBACK(PRBool)
00238 InitClassPolicyEntry(PLDHashTable *table,
00239                      PLDHashEntryHdr *entry,
00240                      const void *key)
00241 {
00242     static PLDHashTableOps classPolicyOps =
00243     {
00244         PL_DHashAllocTable,
00245         PL_DHashFreeTable,
00246         PL_DHashGetKeyStub,
00247         PL_DHashVoidPtrKeyStub,
00248         PL_DHashMatchEntryStub,
00249         PL_DHashMoveEntryStub,
00250         ClearPropertyPolicyEntry,
00251         PL_DHashFinalizeStub,
00252         InitPropertyPolicyEntry
00253     };
00254 
00255     ClassPolicy* cp = (ClassPolicy*)entry;
00256     cp->mDomainWeAreWildcardFor = nsnull;
00257     cp->key = PL_strdup((const char*)key);
00258     if (!cp->key)
00259         return PR_FALSE;
00260     cp->mPolicy = PL_NewDHashTable(&classPolicyOps, nsnull,
00261                                    sizeof(PropertyPolicy), 16);
00262     if (!cp->mPolicy) {
00263         PL_strfree(cp->key);
00264         cp->key = nsnull;
00265         return PR_FALSE;
00266     }
00267     return PR_TRUE;
00268 }
00269 
00270 // Domain Policy
00271 class DomainPolicy : public PLDHashTable
00272 {
00273 public:
00274     DomainPolicy() : mWildcardPolicy(nsnull),
00275                      mRefCount(0)
00276     {
00277         mGeneration = sGeneration;
00278 
00279 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
00280         ++sObjects;
00281         _printPopulationInfo();
00282 #endif
00283 
00284     }
00285 
00286     PRBool Init()
00287     {
00288         static const PLDHashTableOps domainPolicyOps =
00289         {
00290             PL_DHashAllocTable,
00291             PL_DHashFreeTable,
00292             PL_DHashGetKeyStub,
00293             PL_DHashStringKey,
00294             PL_DHashMatchStringKey,
00295             MoveClassPolicyEntry,
00296             ClearClassPolicyEntry,
00297             PL_DHashFinalizeStub,
00298             InitClassPolicyEntry
00299         };
00300 
00301         return PL_DHashTableInit(this, &domainPolicyOps, nsnull,
00302                                  sizeof(ClassPolicy), 16);
00303     }
00304 
00305     ~DomainPolicy()
00306     {
00307         PL_DHashTableFinish(this);
00308         NS_ASSERTION(mRefCount == 0, "Wrong refcount in DomainPolicy dtor");
00309 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
00310         printf("DomainPolicy deleted with mRefCount = %d\n", mRefCount);
00311         --sObjects;
00312         _printPopulationInfo();
00313 #endif
00314 
00315     }
00316 
00317     void Hold()
00318     {
00319         mRefCount++;
00320     }
00321 
00322     void Drop()
00323     {
00324         if (--mRefCount == 0)
00325             delete this;
00326     }
00327     
00328     static void InvalidateAll()
00329     {
00330         sGeneration++;
00331     }
00332     
00333     PRBool IsInvalid()
00334     {
00335         return mGeneration != sGeneration; 
00336     }
00337     
00338     ClassPolicy* mWildcardPolicy;
00339 
00340 private:
00341     PRUint32 mRefCount;
00342     PRUint32 mGeneration;
00343     static PRUint32 sGeneration;
00344     
00345 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
00346     static PRUint32 sObjects;
00347     static void _printPopulationInfo();
00348 #endif
00349 
00350 };
00351 
00352 PR_STATIC_CALLBACK(void)
00353 MoveClassPolicyEntry(PLDHashTable *table,
00354                      const PLDHashEntryHdr *from,
00355                      PLDHashEntryHdr *to)
00356 {
00357     memcpy(to, from, table->entrySize);
00358 
00359     // Now update the mDefaultPolicy pointer that points to us, if any.
00360     ClassPolicy* cp = NS_STATIC_CAST(ClassPolicy*, to);
00361     if (cp->mDomainWeAreWildcardFor) {
00362         NS_ASSERTION(cp->mDomainWeAreWildcardFor->mWildcardPolicy ==
00363                      NS_STATIC_CAST(const ClassPolicy*, from),
00364                      "Unexpected wildcard policy on mDomainWeAreWildcardFor");
00365         cp->mDomainWeAreWildcardFor->mWildcardPolicy = cp;
00366     }
00367 }
00368 
00370 // nsScriptSecurityManager //
00372 #define NS_SCRIPTSECURITYMANAGER_CID \
00373 { 0x7ee2a4c0, 0x4b93, 0x17d3, \
00374 { 0xba, 0x18, 0x00, 0x60, 0xb0, 0xf1, 0x99, 0xa2 }}
00375 
00376 class nsScriptSecurityManager : public nsIScriptSecurityManager,
00377                                 public nsIPrefSecurityCheck,
00378                                 public nsIObserver
00379 {
00380 public:
00381     static void Shutdown();
00382     
00383     NS_DEFINE_STATIC_CID_ACCESSOR(NS_SCRIPTSECURITYMANAGER_CID)
00384         
00385     NS_DECL_ISUPPORTS
00386     NS_DECL_NSISCRIPTSECURITYMANAGER
00387     NS_DECL_NSIXPCSECURITYMANAGER
00388     NS_DECL_NSIPREFSECURITYCHECK
00389     NS_DECL_NSIOBSERVER
00390 
00391     static nsScriptSecurityManager*
00392     GetScriptSecurityManager();
00393 
00394     static nsSystemPrincipal*
00395     SystemPrincipalSingletonConstructor();
00396 
00397     JSContext* GetCurrentJSContext();
00398 
00399     JSContext* GetSafeJSContext();
00400 
00407     static PRBool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
00408 
00409     static nsresult
00410     CheckSameOriginPrincipal(nsIPrincipal* aSubject,
00411                              nsIPrincipal* aObject,
00412                              PRBool aIsCheckConnect);
00413 private:
00414 
00415     // GetScriptSecurityManager is the only call that can make one
00416     nsScriptSecurityManager();
00417     virtual ~nsScriptSecurityManager();
00418 
00419     static JSBool JS_DLL_CALLBACK
00420     CheckObjectAccess(JSContext *cx, JSObject *obj,
00421                       jsval id, JSAccessMode mode,
00422                       jsval *vp);
00423 
00424     // Returns null if a principal cannot be found; generally callers
00425     // should error out at that point.
00426     static nsIPrincipal*
00427     doGetObjectPrincipal(JSContext *cx, JSObject *obj);
00428 
00429     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00430     // when this happens -- this means that there was no JS running.
00431     nsIPrincipal*
00432     doGetSubjectPrincipal(nsresult* rv);
00433     
00434     static nsresult
00435     GetBaseURIScheme(nsIURI* aURI, nsCString& aScheme);
00436 
00437     static nsresult 
00438     ReportError(JSContext* cx, const nsAString& messageTag,
00439                 nsIURI* aSource, nsIURI* aTarget);
00440 
00441     nsresult
00442     GetRootDocShell(JSContext* cx, nsIDocShell **result);
00443 
00444     nsresult
00445     CheckPropertyAccessImpl(PRUint32 aAction,
00446                             nsIXPCNativeCallContext* aCallContext,
00447                             JSContext* cx, JSObject* aJSObject,
00448                             nsISupports* aObj, nsIURI* aTargetURI,
00449                             nsIClassInfo* aClassInfo,
00450                             const char* aClassName, jsval aProperty,
00451                             void** aCachedClassPolicy);
00452 
00453     nsresult
00454     CheckSameOriginDOMProp(nsIPrincipal* aSubject, 
00455                            nsIPrincipal* aObject,
00456                            PRUint32 aAction,
00457                            PRBool aIsCheckConnect);
00458 
00459     nsresult
00460     LookupPolicy(nsIPrincipal* principal,
00461                  const char* aClassName, jsval aProperty,
00462                  PRUint32 aAction,
00463                  ClassPolicy** aCachedClassPolicy,
00464                  SecurityLevel* result);
00465 
00466     nsresult
00467     CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal** result);
00468 
00469     // This is just like the API method, but it doesn't check that the subject
00470     // name is non-empty or aCertificate is non-null, and it doesn't change the
00471     // certificate in the table (if any) in any way if aModifyTable is false.
00472     nsresult
00473     DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
00474                               const nsACString& aSubjectName,
00475                               const nsACString& aPrettyName,
00476                               nsISupports* aCertificate,
00477                               nsIURI* aURI,
00478                               PRBool aModifyTable,
00479                               nsIPrincipal **result);
00480 
00481     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00482     // when this happens -- this means that there was no script for the
00483     // context.  Callers MUST pass in a non-null rv here.
00484     static nsIPrincipal*
00485     GetSubjectPrincipal(JSContext* cx, nsresult* rv);
00486 
00487     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00488     // when this happens -- this means that there was no script for the frame.
00489     // Callers MUST pass in a non-null rv here.
00490     static nsIPrincipal*
00491     GetFramePrincipal(JSContext* cx, JSStackFrame* fp, nsresult* rv);
00492                                                      
00493     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00494     // when this happens -- this means that there was no script.  Callers MUST
00495     // pass in a non-null rv here.
00496     static nsIPrincipal*
00497     GetScriptPrincipal(JSContext* cx, JSScript* script, nsresult* rv);
00498 
00499     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00500     // when this happens -- this means that there was no script associated
00501     // with the function object, and no global object associated with the scope
00502     // of obj (the last object on its parent chain).  If the caller is walking
00503     // the JS stack, fp must point to the current frame in the stack iteration.
00504     // Callers MUST pass in a non-null rv here.
00505     static nsIPrincipal*
00506     GetFunctionObjectPrincipal(JSContext* cx, JSObject* obj, JSStackFrame *fp,
00507                                nsresult* rv);
00508 
00509     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
00510     // when this happens -- this means that there was no script
00511     // running.  Callers MUST pass in a non-null rv here.
00512     static nsIPrincipal*
00513     GetPrincipalAndFrame(JSContext *cx,
00514                          JSStackFrame** frameResult,
00515                          nsresult* rv);
00516 
00517     static PRBool
00518     CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
00519                        const char* aCapability, PRBool *checkValue);
00520 
00521     static void
00522     FormatCapabilityString(nsAString& aCapability);
00523 
00524     nsresult
00525     SavePrincipal(nsIPrincipal* aToSave);
00526 
00527     nsresult
00528     CheckXPCPermissions(nsISupports* aObj,
00529                         const char* aObjectSecurityLevel);
00530 
00531     nsresult
00532     Init();
00533     
00534     nsresult
00535     InitPrefs();
00536 
00537     static nsresult 
00538     GetPrincipalPrefNames(const char* prefBase,
00539                           nsCString& grantedPref,
00540                           nsCString& deniedPref,
00541                           nsCString& subjectNamePref);
00542 
00543     nsresult
00544     InitPolicies();
00545 
00546     nsresult
00547     InitDomainPolicy(JSContext* cx, const char* aPolicyName,
00548                      DomainPolicy* aDomainPolicy);
00549 
00550     nsresult
00551     InitPrincipals(PRUint32 prefCount, const char** prefNames,
00552                    nsISecurityPref* securityPref);
00553 
00554 #ifdef XPC_IDISPATCH_SUPPORT
00555     // While this header is included outside of caps, this class isn't 
00556     // referenced so this should be fine.
00557     nsresult
00558     CheckComponentPermissions(JSContext *cx, const nsCID &aCID);
00559 #endif
00560 #ifdef DEBUG_CAPS_HACKER
00561     void
00562     PrintPolicyDB();
00563 #endif
00564 
00565     // JS strings we need to clean up on shutdown
00566     static jsval sEnabledID;
00567 
00568     inline void
00569     JSEnabledPrefChanged(nsISecurityPref* aSecurityPref);
00570 
00571     static const char sJSEnabledPrefName[];
00572     static const char sJSMailEnabledPrefName[];
00573 
00574     nsObjectHashtable* mOriginToPolicyMap;
00575     DomainPolicy* mDefaultPolicy;
00576     nsObjectHashtable* mCapabilities;
00577 
00578     nsCOMPtr<nsIPrefBranch> mPrefBranch;
00579     nsCOMPtr<nsISecurityPref> mSecurityPref;
00580     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
00581     nsCOMPtr<nsIPrincipal> mSystemCertificate;
00582     nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
00583     nsCOMPtr<nsIThreadJSContextStack> mJSContextStack;
00584     PRPackedBool mIsJavaScriptEnabled;
00585     PRPackedBool mIsMailJavaScriptEnabled;
00586     PRPackedBool mIsWritingPrefs;
00587     PRPackedBool mPolicyPrefsChanged;
00588 #ifdef XPC_IDISPATCH_SUPPORT    
00589     PRPackedBool mXPCDefaultGrantAll;
00590     static const char sXPCDefaultGrantAllName[];
00591 #endif
00592 
00593     static nsIIOService    *sIOService;
00594     static nsIXPConnect    *sXPConnect;
00595     static nsIStringBundle *sStrBundle;
00596     static JSRuntime       *sRuntime;
00597 };
00598 
00599 #endif // nsScriptSecurityManager_h__