Back to index

lightning-sunbird  0.9+nobinonly
nsScriptSecurityManager.cpp
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
00024  *   Mitch Stoltz
00025  *   Steve Morse
00026  *   Christopher A. Aillon
00027  *   Giorgio Maone
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 #include "nsScriptSecurityManager.h"
00043 #include "nsIServiceManager.h"
00044 #include "nsIScriptObjectPrincipal.h"
00045 #include "nsIScriptContext.h"
00046 #include "nsIURL.h"
00047 #include "nsIJARURI.h"
00048 #include "nspr.h"
00049 #include "nsJSPrincipals.h"
00050 #include "nsSystemPrincipal.h"
00051 #include "nsPrincipal.h"
00052 #include "nsXPIDLString.h"
00053 #include "nsCRT.h"
00054 #include "nsIJSContextStack.h"
00055 #include "nsDOMError.h"
00056 #include "nsDOMCID.h"
00057 #include "jsdbgapi.h"
00058 #include "nsIXPConnect.h"
00059 #include "nsIXPCSecurityManager.h"
00060 #include "nsTextFormatter.h"
00061 #include "nsIStringBundle.h"
00062 #include "nsNetUtil.h"
00063 #include "nsIProperties.h"
00064 #include "nsDirectoryServiceDefs.h"
00065 #include "nsIFile.h"
00066 #include "nsIZipReader.h"
00067 #include "nsIJAR.h"
00068 #include "nsIPluginInstance.h"
00069 #include "nsIXPConnect.h"
00070 #include "nsIScriptGlobalObject.h"
00071 #include "nsIDOMWindowInternal.h"
00072 #include "nsIDocShell.h"
00073 #include "nsIDocShellTreeItem.h"
00074 #include "nsIPrompt.h"
00075 #include "nsIWindowWatcher.h"
00076 #include "nsIConsoleService.h"
00077 #include "nsISecurityCheckedComponent.h"
00078 #include "nsIPrefBranch2.h"
00079 #include "nsIJSRuntimeService.h"
00080 #include "nsIObserverService.h"
00081 #include "nsIContent.h"
00082 #include "nsAutoPtr.h"
00083 #include "nsAboutProtocolUtils.h"
00084 #include "nsIURIFixup.h"
00085 #include "nsCDefaultURIFixup.h"
00086 
00087 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
00088 
00089 nsIIOService    *nsScriptSecurityManager::sIOService = nsnull;
00090 nsIXPConnect    *nsScriptSecurityManager::sXPConnect = nsnull;
00091 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
00092 JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
00093 
00095 // Convenience Functions //
00097 // Result of this function should not be freed.
00098 static inline const PRUnichar *
00099 JSValIDToString(JSContext *cx, const jsval idval)
00100 {
00101     JSString *str = JS_ValueToString(cx, idval);
00102     if(!str)
00103         return nsnull;
00104     return NS_REINTERPRET_CAST(PRUnichar*, JS_GetStringChars(str));
00105 }
00106 
00107 static nsIScriptContext *
00108 GetScriptContext(JSContext *cx)
00109 {
00110     return GetScriptContextFromJSContext(cx);
00111 }
00112 
00113 inline void SetPendingException(JSContext *cx, const char *aMsg)
00114 {
00115     JSString *str = JS_NewStringCopyZ(cx, aMsg);
00116     if (str)
00117         JS_SetPendingException(cx, STRING_TO_JSVAL(str));
00118 }
00119 
00120 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
00121 {
00122     JSString *str = JS_NewUCStringCopyZ(cx,
00123                         NS_REINTERPRET_CAST(const jschar*, aMsg));
00124     if (str)
00125         JS_SetPendingException(cx, STRING_TO_JSVAL(str));
00126 }
00127 
00128 // DomainPolicy members
00129 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
00130 PRUint32 DomainPolicy::sObjects=0;
00131 void DomainPolicy::_printPopulationInfo()
00132 {
00133     printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
00134         sGeneration, sObjects);
00135 }
00136 #endif
00137 PRUint32 DomainPolicy::sGeneration = 0;
00138 
00139 // Helper class to get stuff from the ClassInfo and not waste extra time with
00140 // virtual method calls for things it has already gotten
00141 class ClassInfoData
00142 {
00143 public:
00144     ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
00145         : mClassInfo(aClassInfo),
00146           mName(NS_CONST_CAST(char *, aName)),
00147           mDidGetFlags(PR_FALSE),
00148           mMustFreeName(PR_FALSE)
00149     {
00150     }
00151 
00152     ~ClassInfoData()
00153     {
00154         if (mMustFreeName)
00155             nsMemory::Free(mName);
00156     }
00157 
00158     PRUint32 GetFlags()
00159     {
00160         if (!mDidGetFlags) {
00161             if (mClassInfo) {
00162                 nsresult rv = mClassInfo->GetFlags(&mFlags);
00163                 if (NS_FAILED(rv)) {
00164                     mFlags = 0;
00165                 }
00166             } else {
00167                 mFlags = 0;
00168             }
00169 
00170             mDidGetFlags = PR_TRUE;
00171         }
00172 
00173         return mFlags;
00174     }
00175 
00176     PRBool IsDOMClass()
00177     {
00178         return GetFlags() & nsIClassInfo::DOM_OBJECT;
00179     }
00180 
00181     PRBool IsContentNode()
00182     {
00183         return GetFlags() & nsIClassInfo::CONTENT_NODE;
00184     }
00185 
00186     const char* GetName()
00187     {
00188         if (!mName) {
00189             if (mClassInfo) {
00190                 mClassInfo->GetClassDescription(&mName);
00191             }
00192 
00193             if (mName) {
00194                 mMustFreeName = PR_TRUE;
00195             } else {
00196                 mName = NS_CONST_CAST(char *, "UnnamedClass");
00197             }
00198         }
00199 
00200         return mName;
00201     }
00202 
00203 private:
00204     nsIClassInfo *mClassInfo; // WEAK
00205     PRUint32 mFlags;
00206     char *mName;
00207     PRPackedBool mDidGetFlags;
00208     PRPackedBool mMustFreeName;
00209 };
00210  
00211 JSContext *
00212 nsScriptSecurityManager::GetCurrentJSContext()
00213 {
00214     // Get JSContext from stack.
00215     if (!mJSContextStack)
00216     {
00217         mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
00218         if (!mJSContextStack)
00219             return nsnull;
00220     }
00221     JSContext *cx;
00222     if (NS_FAILED(mJSContextStack->Peek(&cx)))
00223         return nsnull;
00224     return cx;
00225 }
00226 
00227 JSContext *
00228 nsScriptSecurityManager::GetSafeJSContext()
00229 {
00230     // Get JSContext from stack.
00231     if (!mJSContextStack) {
00232         mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
00233         if (!mJSContextStack)
00234             return nsnull;
00235     }
00236 
00237     JSContext *cx;
00238     if (NS_FAILED(mJSContextStack->GetSafeJSContext(&cx)))
00239         return nsnull;
00240     return cx;
00241 }
00242 
00243 // Both params are inout
00244 static nsresult
00245 MaybeFixupURIAndScheme(nsCOMPtr<nsIURI>& aURI, nsCString& aScheme)
00246 {
00247     nsresult rv = NS_OK;
00248     if (aScheme.EqualsLiteral("wyciwyg")) {
00249         // Need to dig out the real URI
00250         nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
00251         if (fixup) {
00252             nsCOMPtr<nsIURI> newURI;
00253             rv = fixup->CreateExposableURI(aURI, getter_AddRefs(newURI));
00254             if (NS_SUCCEEDED(rv) && newURI != aURI) {
00255                 aURI = newURI;
00256                 rv = aURI->GetScheme(aScheme);
00257             }
00258         }
00259     }
00260     return rv;
00261 }
00262 
00263 NS_IMETHODIMP
00264  nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
00265                                               nsIURI* aTargetURI,
00266                                               PRBool* result)
00267 {
00268     *result = SecurityCompareURIs(aSourceURI, aTargetURI);
00269 
00270     return NS_OK;
00271 }
00272 
00273 // static
00274 PRBool
00275 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
00276                                              nsIURI* aTargetURI)
00277 {
00278     if (aSourceURI == aTargetURI)
00279     {
00280         return PR_TRUE;
00281     }
00282 
00283     if (!aTargetURI || !aSourceURI) 
00284     {
00285         return PR_FALSE;
00286     }
00287 
00288     // If either uri is a jar URI, get the base URI
00289     nsCOMPtr<nsIJARURI> jarURI;
00290     nsCOMPtr<nsIURI> sourceBaseURI(aSourceURI);
00291     while((jarURI = do_QueryInterface(sourceBaseURI)))
00292     {
00293         jarURI->GetJARFile(getter_AddRefs(sourceBaseURI));
00294     }
00295     nsCOMPtr<nsIURI> targetBaseURI(aTargetURI);
00296     while((jarURI = do_QueryInterface(targetBaseURI)))
00297     {
00298         jarURI->GetJARFile(getter_AddRefs(targetBaseURI));
00299     }
00300 
00301     if (!sourceBaseURI || !targetBaseURI)
00302         return PR_FALSE;
00303 
00304     // Compare schemes
00305     nsCAutoString targetScheme;
00306     nsresult rv = targetBaseURI->GetScheme(targetScheme);
00307     if (NS_SUCCEEDED(rv))
00308         rv = MaybeFixupURIAndScheme(targetBaseURI, targetScheme);
00309 
00310     nsCAutoString sourceScheme;
00311     if (NS_SUCCEEDED(rv))
00312         rv = sourceBaseURI->GetScheme(sourceScheme);
00313     if (NS_SUCCEEDED(rv))
00314         rv = MaybeFixupURIAndScheme(sourceBaseURI, sourceScheme);
00315     
00316     if (NS_SUCCEEDED(rv) && targetScheme.Equals(sourceScheme))
00317     {
00318         if (targetScheme.EqualsLiteral("file"))
00319         {
00320             // All file: urls are considered to have the same origin.
00321             return PR_TRUE;
00322         }
00323         else if (targetScheme.EqualsLiteral("imap") ||
00324                  targetScheme.EqualsLiteral("mailbox") ||
00325                  targetScheme.EqualsLiteral("news"))
00326         {
00327             // Each message is a distinct trust domain; use the 
00328             // whole spec for comparison
00329             nsCAutoString targetSpec;
00330             if (NS_FAILED(targetBaseURI->GetSpec(targetSpec)))
00331                 return PR_FALSE;
00332             nsCAutoString sourceSpec;
00333             if (NS_FAILED(sourceBaseURI->GetSpec(sourceSpec)))
00334                 return PR_FALSE;
00335             return targetSpec.Equals(sourceSpec);
00336         }
00337         else
00338         {
00339             // Compare hosts
00340             nsCAutoString targetHost;
00341             nsCAutoString sourceHost;
00342             if (NS_FAILED(targetBaseURI->GetHost(targetHost)) ||
00343                 NS_FAILED(sourceBaseURI->GetHost(sourceHost)))
00344             {
00345                 return PR_FALSE;
00346             }
00347 
00348             PRBool result =
00349                 targetHost.Equals(sourceHost,
00350                                   nsCaseInsensitiveCStringComparator());
00351             if (result) 
00352             {
00353                 // Compare ports
00354                 PRInt32 targetPort;
00355                 rv = targetBaseURI->GetPort(&targetPort);
00356                 PRInt32 sourcePort;
00357                 if (NS_SUCCEEDED(rv))
00358                     rv = sourceBaseURI->GetPort(&sourcePort);
00359                 result = NS_SUCCEEDED(rv) && targetPort == sourcePort;
00360                 // If the port comparison failed, see if either URL has a
00361                 // port of -1. If so, replace -1 with the default port
00362                 // for that scheme.
00363                 if (NS_SUCCEEDED(rv) && !result &&
00364                     (sourcePort == -1 || targetPort == -1))
00365                 {
00366                     NS_ENSURE_STATE(sIOService);
00367 
00368                     NS_ASSERTION(targetScheme.Equals(sourceScheme),
00369                                  "Schemes should be equal here");
00370                     
00371                     PRInt32 defaultPort;
00372                     nsCOMPtr<nsIProtocolHandler> protocolHandler;
00373                     rv = sIOService->GetProtocolHandler(sourceScheme.get(),
00374                                                         getter_AddRefs(protocolHandler));
00375                     if (NS_FAILED(rv))
00376                     {
00377                         return PR_FALSE;
00378                     }
00379                     
00380                     rv = protocolHandler->GetDefaultPort(&defaultPort);
00381                     if (NS_FAILED(rv) || defaultPort == -1)
00382                         return PR_FALSE; // No default port for this scheme
00383 
00384                     if (sourcePort == -1)
00385                         sourcePort = defaultPort;
00386                     else if (targetPort == -1)
00387                         targetPort = defaultPort;
00388                     result = targetPort == sourcePort;
00389                 }
00390 
00391                 return result;
00392             }
00393         }
00394     }
00395 
00396     return PR_FALSE;
00397 }
00398 
00400 // Policy Storage //
00402 
00403 // Table of security levels
00404 PR_STATIC_CALLBACK(PRBool)
00405 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
00406 {
00407     nsMemory::Free(aData);
00408     return PR_TRUE;
00409 }
00410 
00411 //-- Per-Domain Policy - applies to one or more protocols or hosts
00412 struct DomainEntry
00413 {
00414     DomainEntry(const char* aOrigin,
00415                 DomainPolicy* aDomainPolicy) : mOrigin(aOrigin),
00416                                                mDomainPolicy(aDomainPolicy),
00417                                                mNext(nsnull)
00418     {
00419         mDomainPolicy->Hold();
00420     }
00421 
00422     ~DomainEntry()
00423     {
00424         mDomainPolicy->Drop();
00425     }
00426 
00427     PRBool Matches(const char *anOrigin)
00428     {
00429         int len = strlen(anOrigin);
00430         int thisLen = mOrigin.Length();
00431         if (len < thisLen)
00432             return PR_FALSE;
00433         if (mOrigin.RFindChar(':', thisLen-1, 1) != -1)
00434         //-- Policy applies to all URLs of this scheme, compare scheme only
00435             return mOrigin.EqualsIgnoreCase(anOrigin, thisLen);
00436 
00437         //-- Policy applies to a particular host; compare domains
00438         if (!mOrigin.Equals(anOrigin + (len - thisLen)))
00439             return PR_FALSE;
00440         if (len == thisLen)
00441             return PR_TRUE;
00442         char charBefore = anOrigin[len-thisLen-1];
00443         return (charBefore == '.' || charBefore == ':' || charBefore == '/');
00444     }
00445 
00446     nsCString         mOrigin;
00447     DomainPolicy*     mDomainPolicy;
00448     DomainEntry*      mNext;
00449 #ifdef DEBUG
00450     nsCString         mPolicyName_DEBUG;
00451 #endif
00452 };
00453 
00454 PR_STATIC_CALLBACK(PRBool)
00455 DeleteDomainEntry(nsHashKey *aKey, void *aData, void* closure)
00456 {
00457     DomainEntry *entry = (DomainEntry*) aData;
00458     do
00459     {
00460         DomainEntry *next = entry->mNext;
00461         delete entry;
00462         entry = next;
00463     } while (entry);
00464     return PR_TRUE;
00465 }
00466 
00468 // nsScriptSecurityManager //
00470 
00472 // Methods implementing ISupports //
00474 NS_IMPL_ISUPPORTS4(nsScriptSecurityManager,
00475                    nsIScriptSecurityManager,
00476                    nsIXPCSecurityManager,
00477                    nsIPrefSecurityCheck,
00478                    nsIObserver)
00479 
00480 
00481 // Methods implementing nsIScriptSecurityManager //
00483 
00485 JSBool JS_DLL_CALLBACK
00486 nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
00487                                            jsval id, JSAccessMode mode,
00488                                            jsval *vp)
00489 {
00490     // Get the security manager
00491     nsScriptSecurityManager *ssm =
00492         nsScriptSecurityManager::GetScriptSecurityManager();
00493 
00494     NS_ASSERTION(ssm, "Failed to get security manager service");
00495     if (!ssm)
00496         return JS_FALSE;
00497 
00498     // Get the object being accessed.  We protect these cases:
00499     // 1. The Function.prototype.caller property's value, which might lead
00500     //    an attacker up a call-stack to a function or another object from
00501     //    a different trust domain.
00502     // 2. A user-defined getter or setter function accessible on another
00503     //    trust domain's window or document object.
00504     // *vp can be a primitive, in that case, we use obj as the target
00505     // object.
00506     JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
00507 
00508     // Do the same-origin check -- this sets a JS exception if the check fails.
00509     // Pass the parent object's class name, as we have no class-info for it.
00510     nsresult rv =
00511         ssm->CheckPropertyAccess(cx, target, JS_GetClass(cx, obj)->name, id,
00512                                  (mode & JSACC_WRITE) ?
00513                                  nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
00514                                  nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
00515 
00516     if (NS_FAILED(rv))
00517         return JS_FALSE; // Security check failed (XXX was an error reported?)
00518 
00519     return JS_TRUE;
00520 }
00521 
00522 NS_IMETHODIMP
00523 nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
00524                                              JSObject* aJSObject,
00525                                              const char* aClassName,
00526                                              jsval aProperty,
00527                                              PRUint32 aAction)
00528 {
00529     return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
00530                                    nsnull, nsnull, nsnull,
00531                                    aClassName, aProperty, nsnull);
00532 }
00533 
00534 NS_IMETHODIMP
00535 nsScriptSecurityManager::CheckConnect(JSContext* cx,
00536                                       nsIURI* aTargetURI,
00537                                       const char* aClassName,
00538                                       const char* aPropertyName)
00539 {
00540     // Get a context if necessary
00541     if (!cx)
00542     {
00543         cx = GetCurrentJSContext();
00544         if (!cx)
00545             return NS_OK; // No JS context, so allow the load
00546     }
00547 
00548     nsresult rv = CheckLoadURIFromScript(cx, aTargetURI);
00549     if (NS_FAILED(rv)) return rv;
00550 
00551     JSString* propertyName = ::JS_InternString(cx, aPropertyName);
00552     if (!propertyName)
00553         return NS_ERROR_OUT_OF_MEMORY;
00554 
00555     return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull,
00556                                    cx, nsnull, nsnull, aTargetURI,
00557                                    nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull);
00558 }
00559 
00560 NS_IMETHODIMP
00561 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
00562                                          nsIURI* aTargetURI)
00563 {
00564     nsresult rv;
00565 
00566     // Get a context if necessary
00567     if (!cx)
00568     {
00569         cx = GetCurrentJSContext();
00570         if (!cx)
00571             return NS_OK; // No JS context, so allow access
00572     }
00573 
00574     // Get a principal from the context
00575     nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
00576     if (NS_FAILED(rv))
00577         return rv;
00578 
00579     if (!sourcePrincipal)
00580     {
00581         NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
00582         return NS_OK;
00583     }
00584 
00585     if (sourcePrincipal == mSystemPrincipal)
00586     {
00587         // This is a system (chrome) script, so allow access
00588         return NS_OK;
00589     }
00590 
00591     // Get the original URI from the source principal.
00592     // This has the effect of ignoring any change to document.domain
00593     // which must be done to avoid DNS spoofing (bug 154930)
00594     nsCOMPtr<nsIURI> sourceURI;
00595     sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
00596     if (!sourceURI) {
00597       sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
00598       NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
00599     }
00600 
00601     // Compare origins
00602     PRBool sameOrigin = PR_FALSE;
00603     rv = SecurityCompareURIs(sourceURI, aTargetURI, &sameOrigin);
00604     NS_ENSURE_SUCCESS(rv, rv);
00605 
00606     if (!sameOrigin)
00607     {
00608          ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
00609          return NS_ERROR_DOM_BAD_URI;
00610     }
00611     return NS_OK;
00612 }
00613 
00614 NS_IMETHODIMP
00615 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
00616                                             nsIURI* aTargetURI)
00617 {
00618     nsresult rv;
00619     PRBool sameOrigin = PR_FALSE;
00620     rv = SecurityCompareURIs(aSourceURI, aTargetURI, &sameOrigin);
00621     NS_ENSURE_SUCCESS(rv, rv);
00622 
00623     if (!sameOrigin)
00624     {
00625          ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"), 
00626                      aSourceURI, aTargetURI);
00627          return NS_ERROR_DOM_BAD_URI;
00628     }
00629     return NS_OK;
00630 }
00631 
00632 NS_IMETHODIMP
00633 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSourcePrincipal,
00634                                                   nsIPrincipal* aTargetPrincipal)
00635 {
00636     return CheckSameOriginPrincipal(aSourcePrincipal, aTargetPrincipal,
00637                                     PR_FALSE);
00638 }
00639 
00640 
00641 nsresult
00642 nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
00643                                                  nsIXPCNativeCallContext* aCallContext,
00644                                                  JSContext* cx, JSObject* aJSObject,
00645                                                  nsISupports* aObj, nsIURI* aTargetURI,
00646                                                  nsIClassInfo* aClassInfo,
00647                                                  const char* aClassName, jsval aProperty,
00648                                                  void** aCachedClassPolicy)
00649 {
00650     nsresult rv;
00651     nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
00652     if (NS_FAILED(rv))
00653         return rv;
00654 
00655     if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
00656         // We have native code or the system principal: just allow access
00657         return NS_OK;
00658 
00659     // Hold the class info data here so we don't have to go back to virtual
00660     // methods all the time
00661     ClassInfoData classInfoData(aClassInfo, aClassName);
00662 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00663     nsCAutoString propertyName;
00664     propertyName.AssignWithConversion((PRUnichar*)JSValIDToString(cx, aProperty));
00665     printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(), 
00666            propertyName.get(), aAction);
00667 #endif
00668 
00669     //-- Look up the security policy for this class and subject domain
00670     SecurityLevel securityLevel;
00671     rv = LookupPolicy(subjectPrincipal, classInfoData.GetName(), aProperty, aAction, 
00672                       (ClassPolicy**)aCachedClassPolicy, &securityLevel);
00673     if (NS_FAILED(rv))
00674         return rv;
00675 
00676     if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
00677     {   
00678         // No policy found for this property so use the default of last resort.
00679         // If we were called from somewhere other than XPConnect
00680         // (no XPC call context), assume this is a DOM class. Otherwise,
00681         // ask the ClassInfo.
00682         if (!aCallContext || classInfoData.IsDOMClass())
00683             securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
00684         else
00685             securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
00686     }
00687 
00688     if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
00689     // This flag means securityLevel is allAccess, noAccess, or sameOrigin
00690     {
00691         switch (securityLevel.level)
00692         {
00693         case SCRIPT_SECURITY_NO_ACCESS:
00694 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00695             printf("noAccess ");
00696 #endif
00697             rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
00698             break;
00699 
00700         case SCRIPT_SECURITY_ALL_ACCESS:
00701 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00702             printf("allAccess ");
00703 #endif
00704             rv = NS_OK;
00705             break;
00706 
00707         case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS:
00708             {
00709 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00710                 printf("sameOrigin ");
00711 #endif
00712                 nsCOMPtr<nsIPrincipal> objectPrincipal;
00713                 if(aJSObject)
00714                 {
00715                     objectPrincipal = doGetObjectPrincipal(cx, aJSObject);
00716                     if (!objectPrincipal)
00717                         return NS_ERROR_FAILURE;
00718                 }
00719                 else if(aTargetURI)
00720                 {
00721                     if (NS_FAILED(GetCodebasePrincipal(
00722                           aTargetURI, getter_AddRefs(objectPrincipal))))
00723                         return NS_ERROR_FAILURE;
00724                 }
00725                 else
00726                 {
00727                     NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
00728                     return NS_ERROR_FAILURE;
00729                 }
00730                 rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
00731                                             aAction, aTargetURI != nsnull);
00732                 break;
00733             }
00734         default:
00735 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00736                 printf("ERROR ");
00737 #endif
00738             NS_ERROR("Bad Security Level Value");
00739             return NS_ERROR_FAILURE;
00740         }
00741     }
00742     else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
00743     {
00744 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00745         printf("Cap:%s ", securityLevel.capability);
00746 #endif
00747         PRBool capabilityEnabled = PR_FALSE;
00748         rv = IsCapabilityEnabled(securityLevel.capability, &capabilityEnabled);
00749         if (NS_FAILED(rv) || !capabilityEnabled)
00750             rv = NS_ERROR_DOM_SECURITY_ERR;
00751         else
00752             rv = NS_OK;
00753     }
00754 
00755     if (NS_SUCCEEDED(rv) && classInfoData.IsContentNode())
00756     {
00757         // No access to anonymous content from the web!  (bug 164086)
00758         nsCOMPtr<nsIContent> content(do_QueryInterface(aObj));
00759         NS_ASSERTION(content, "classinfo had CONTENT_NODE set but node did not"
00760                               "implement nsIContent!  Fasten your seat belt.");
00761         if (content->IsNativeAnonymous()) {
00762             rv = NS_ERROR_DOM_SECURITY_ERR;
00763         }
00764     }
00765 
00766     if (NS_SUCCEEDED(rv))
00767     {
00768 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00769     printf(" GRANTED.\n");
00770 #endif
00771         return rv;
00772     }
00773 
00774     //--See if the object advertises a non-default level of access
00775     //  using nsISecurityCheckedComponent
00776     nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
00777         do_QueryInterface(aObj);
00778 
00779     nsXPIDLCString objectSecurityLevel;
00780     if (checkedComponent)
00781     {
00782         nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
00783         nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
00784         const nsIID* objIID;
00785         rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
00786         if (NS_SUCCEEDED(rv))
00787             rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
00788         if (NS_SUCCEEDED(rv))
00789             rv = interfaceInfo->GetIIDShared(&objIID);
00790         if (NS_SUCCEEDED(rv))
00791         {
00792             switch (aAction)
00793             {
00794             case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
00795                 checkedComponent->CanGetProperty(objIID,
00796                                                  JSValIDToString(cx, aProperty),
00797                                                  getter_Copies(objectSecurityLevel));
00798                 break;
00799             case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
00800                 checkedComponent->CanSetProperty(objIID,
00801                                                  JSValIDToString(cx, aProperty),
00802                                                  getter_Copies(objectSecurityLevel));
00803                 break;
00804             case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
00805                 checkedComponent->CanCallMethod(objIID,
00806                                                 JSValIDToString(cx, aProperty),
00807                                                 getter_Copies(objectSecurityLevel));
00808             }
00809         }
00810     }
00811     rv = CheckXPCPermissions(aObj, objectSecurityLevel);
00812 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
00813     if(NS_SUCCEEDED(rv))
00814         printf("CheckXPCPerms GRANTED.\n");
00815     else
00816         printf("CheckXPCPerms DENIED.\n");
00817 #endif
00818 
00819     if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
00820     {
00821         nsAutoString stringName;
00822         switch(aAction)
00823         {
00824         case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
00825             stringName.AssignLiteral("GetPropertyDenied");
00826             break;
00827         case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
00828             stringName.AssignLiteral("SetPropertyDenied");
00829             break;
00830         case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
00831             stringName.AssignLiteral("CallMethodDenied");
00832         }
00833 
00834         NS_ConvertUTF8toUTF16 className(classInfoData.GetName());
00835         const PRUnichar *formatStrings[] =
00836         {
00837             className.get(),
00838             JSValIDToString(cx, aProperty)
00839         };
00840 
00841         nsXPIDLString errorMsg;
00842         // We need to keep our existing failure rv and not override it
00843         // with a likely success code from the following string bundle
00844         // call in order to throw the correct security exception later.
00845         nsresult rv2 = sStrBundle->FormatStringFromName(stringName.get(),
00846                                                         formatStrings,
00847                                                         NS_ARRAY_LENGTH(formatStrings),
00848                                                         getter_Copies(errorMsg));
00849         NS_ENSURE_SUCCESS(rv2, rv2);
00850 
00851         SetPendingException(cx, errorMsg.get());
00852 
00853         if (sXPConnect)
00854         {
00855             nsCOMPtr<nsIXPCNativeCallContext> xpcCallContext;
00856             sXPConnect->GetCurrentNativeCallContext(getter_AddRefs(xpcCallContext));
00857             if (xpcCallContext)
00858                 xpcCallContext->SetExceptionWasThrown(PR_TRUE);
00859         }
00860     }
00861 
00862     return rv;
00863 }
00864 
00865 // static
00866 nsresult
00867 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
00868                                                   nsIPrincipal* aObject,
00869                                                   PRBool aIsCheckConnect)
00870 {
00871     /*
00872     ** Get origin of subject and object and compare.
00873     */
00874     if (aSubject == aObject)
00875         return NS_OK;
00876 
00877     // These booleans are only used when !aIsCheckConnect.  Default
00878     // them to false, and change if that turns out wrong.
00879     PRBool subjectSetDomain = PR_FALSE;
00880     PRBool objectSetDomain = PR_FALSE;
00881     
00882     nsCOMPtr<nsIURI> subjectURI;
00883     nsCOMPtr<nsIURI> objectURI;
00884 
00885     if (aIsCheckConnect)
00886     {
00887         // Don't use domain for CheckConnect calls, since that's called for
00888         // data-only load checks like XMLHTTPRequest (bug 290100).
00889         aSubject->GetURI(getter_AddRefs(subjectURI));
00890         aObject->GetURI(getter_AddRefs(objectURI));
00891     }
00892     else
00893     {
00894         aSubject->GetDomain(getter_AddRefs(subjectURI));
00895         if (!subjectURI) {
00896             aSubject->GetURI(getter_AddRefs(subjectURI));
00897         } else {
00898             subjectSetDomain = PR_TRUE;
00899         }
00900 
00901         aObject->GetDomain(getter_AddRefs(objectURI));
00902         if (!objectURI) {
00903             aObject->GetURI(getter_AddRefs(objectURI));
00904         } else {
00905             objectSetDomain = PR_TRUE;
00906         }
00907     }
00908 
00909     if (SecurityCompareURIs(subjectURI, objectURI))
00910     {   // If either the subject or the object has changed its principal by
00911         // explicitly setting document.domain then the other must also have
00912         // done so in order to be considered the same origin. This prevents
00913         // DNS spoofing based on document.domain (154930)
00914 
00915         // But this restriction does not apply to CheckConnect calls, since
00916         // that's called for data-only load checks like XMLHTTPRequest where
00917         // we ignore domain (bug 290100).
00918         if (aIsCheckConnect)
00919             return NS_OK;
00920 
00921         // If both or neither explicitly set their domain, allow the access
00922         if (subjectSetDomain == objectSetDomain)
00923             return NS_OK;
00924     }
00925 
00926     /*
00927     ** Access tests failed, so now report error.
00928     */
00929     return NS_ERROR_DOM_PROP_ACCESS_DENIED;
00930 }
00931 
00932 
00933 nsresult
00934 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
00935                                                 nsIPrincipal* aObject,
00936                                                 PRUint32 aAction,
00937                                                 PRBool aIsCheckConnect)
00938 {
00939     nsresult rv;
00940     if (aIsCheckConnect) {
00941         // Don't do equality compares, just do a same-origin compare,
00942         // since the object principal isn't a real principal, just a
00943         // GetCodebasePrincipal() on whatever URI we started with.
00944         rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
00945     } else {
00946         PRBool subsumes;
00947         rv = aSubject->Subsumes(aObject, &subsumes);
00948         if (NS_SUCCEEDED(rv) && !subsumes) {
00949             rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
00950         }
00951     }
00952     
00953     if (NS_SUCCEEDED(rv))
00954         return NS_OK;
00955 
00956     /*
00957     * Content can't ever touch chrome (we check for UniversalXPConnect later)
00958     */
00959     if (aObject == mSystemPrincipal)
00960         return NS_ERROR_DOM_PROP_ACCESS_DENIED;
00961 
00962     /*
00963     * If we failed the origin tests it still might be the case that we
00964     * are a signed script and have permissions to do this operation.
00965     * Check for that here.
00966     */
00967     PRBool capabilityEnabled = PR_FALSE;
00968     const char* cap = aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY ?
00969                       "UniversalBrowserWrite" : "UniversalBrowserRead";
00970     rv = IsCapabilityEnabled(cap, &capabilityEnabled);
00971     NS_ENSURE_SUCCESS(rv, rv);
00972     if (capabilityEnabled)
00973         return NS_OK;
00974 
00975     /*
00976     ** Access tests failed, so now report error.
00977     */
00978     return NS_ERROR_DOM_PROP_ACCESS_DENIED;
00979 }
00980 
00981 static
00982 nsresult
00983 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
00984                          nsACString& aOrigin)
00985 {
00986     aOrigin.Truncate();
00987 
00988     nsCOMPtr<nsIURI> uri;
00989     aPrincipal->GetDomain(getter_AddRefs(uri));
00990     if (!uri) {
00991         aPrincipal->GetURI(getter_AddRefs(uri));
00992     }
00993 
00994     // de-nest jar: origins
00995     nsCOMPtr<nsIJARURI> jarURI;
00996     while((jarURI = do_QueryInterface(uri)))
00997     {
00998         jarURI->GetJARFile(getter_AddRefs(uri));
00999     }
01000     NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
01001 
01002     nsCAutoString hostPort;
01003 
01004     nsresult rv = uri->GetHostPort(hostPort);
01005     if (NS_SUCCEEDED(rv)) {
01006         nsCAutoString scheme;
01007         rv = uri->GetScheme(scheme);
01008         NS_ENSURE_SUCCESS(rv, rv);
01009         aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
01010     }
01011     else {
01012         // Some URIs (e.g., nsSimpleURI) don't support host. Just
01013         // get the full spec.
01014         rv = uri->GetSpec(aOrigin);
01015         NS_ENSURE_SUCCESS(rv, rv);
01016     }
01017 
01018     return NS_OK;
01019 }
01020 
01021 nsresult
01022 nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal,
01023                                      const char* aClassName, jsval aProperty,
01024                                      PRUint32 aAction,
01025                                      ClassPolicy** aCachedClassPolicy,
01026                                      SecurityLevel* result)
01027 {
01028     nsresult rv;
01029     result->level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
01030 
01031     DomainPolicy* dpolicy = nsnull;
01032     //-- Initialize policies if necessary
01033     if (mPolicyPrefsChanged)
01034     {
01035         rv = InitPolicies();
01036         if (NS_FAILED(rv))
01037             return rv;
01038     }
01039     else
01040     {
01041         aPrincipal->GetSecurityPolicy((void**)&dpolicy);
01042     }
01043 
01044     if (!dpolicy && mOriginToPolicyMap)
01045     {
01046         //-- Look up the relevant domain policy, if any
01047 #ifdef DEBUG_CAPS_LookupPolicy
01048         printf("DomainLookup ");
01049 #endif
01050 
01051         nsCAutoString origin;
01052         rv = GetPrincipalDomainOrigin(aPrincipal, origin);
01053         NS_ENSURE_SUCCESS(rv, rv);
01054  
01055         char *start = origin.BeginWriting();
01056         const char *nextToLastDot = nsnull;
01057         const char *lastDot = nsnull;
01058         const char *colon = nsnull;
01059         char *p = start;
01060 
01061         //-- search domain (stop at the end of the string or at the 3rd slash)
01062         for (PRUint32 slashes=0; *p; p++)
01063         {
01064             if (*p == '/' && ++slashes == 3) 
01065             {
01066                 *p = '\0'; // truncate at 3rd slash
01067                 break;
01068             }
01069             if (*p == '.')
01070             {
01071                 nextToLastDot = lastDot;
01072                 lastDot = p;
01073             } 
01074             else if (!colon && *p == ':')
01075                 colon = p;
01076         }
01077 
01078         nsCStringKey key(nextToLastDot ? nextToLastDot+1 : start);
01079         DomainEntry *de = (DomainEntry*) mOriginToPolicyMap->Get(&key);
01080         if (!de)
01081         {
01082             nsCAutoString scheme(start, colon-start+1);
01083             nsCStringKey schemeKey(scheme);
01084             de = (DomainEntry*) mOriginToPolicyMap->Get(&schemeKey);
01085         }
01086 
01087         while (de)
01088         {
01089             if (de->Matches(start))
01090             {
01091                 dpolicy = de->mDomainPolicy;
01092                 break;
01093             }
01094             de = de->mNext;
01095         }
01096 
01097         if (!dpolicy)
01098             dpolicy = mDefaultPolicy;
01099 
01100         aPrincipal->SetSecurityPolicy((void*)dpolicy);
01101     }
01102 
01103     ClassPolicy* cpolicy = nsnull;
01104 
01105     if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
01106     {
01107         // No per-domain policy for this principal (the more common case)
01108         // so look for a cached class policy from the object wrapper
01109         cpolicy = *aCachedClassPolicy;
01110     }
01111 
01112     if (!cpolicy)
01113     { //-- No cached policy for this class, need to look it up
01114 #ifdef DEBUG_CAPS_LookupPolicy
01115         printf("ClassLookup ");
01116 #endif
01117 
01118         cpolicy = NS_STATIC_CAST(ClassPolicy*,
01119                                  PL_DHashTableOperate(dpolicy,
01120                                                       aClassName,
01121                                                       PL_DHASH_LOOKUP));
01122 
01123         if (PL_DHASH_ENTRY_IS_FREE(cpolicy))
01124             cpolicy = NO_POLICY_FOR_CLASS;
01125 
01126         if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
01127             *aCachedClassPolicy = cpolicy;
01128     }
01129 
01130     // We look for a PropertyPolicy in the following places:
01131     // 1)  The ClassPolicy for our class we got from our DomainPolicy
01132     // 2)  The mWildcardPolicy of our DomainPolicy
01133     // 3)  The ClassPolicy for our class we got from mDefaultPolicy
01134     // 4)  The mWildcardPolicy of our mDefaultPolicy
01135     PropertyPolicy* ppolicy = nsnull;
01136     if (cpolicy != NO_POLICY_FOR_CLASS)
01137     {
01138         ppolicy = NS_STATIC_CAST(PropertyPolicy*,
01139                                  PL_DHashTableOperate(cpolicy->mPolicy,
01140                                                       (void*)aProperty,
01141                                                       PL_DHASH_LOOKUP));
01142     }
01143 
01144     // If there is no class policy for this property, and we have a wildcard
01145     // policy, try that.
01146     if (dpolicy->mWildcardPolicy &&
01147         (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
01148     {
01149         ppolicy =
01150             NS_STATIC_CAST(PropertyPolicy*,
01151                            PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy,
01152                                                 (void*)aProperty,
01153                                                 PL_DHASH_LOOKUP));
01154     }
01155 
01156     // If dpolicy is not the defauly policy and there's no class or wildcard
01157     // policy for this property, check the default policy for this class and
01158     // the default wildcard policy
01159     if (dpolicy != mDefaultPolicy &&
01160         (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
01161     {
01162         cpolicy = NS_STATIC_CAST(ClassPolicy*,
01163                                  PL_DHashTableOperate(mDefaultPolicy,
01164                                                       aClassName,
01165                                                       PL_DHASH_LOOKUP));
01166 
01167         if (PL_DHASH_ENTRY_IS_BUSY(cpolicy))
01168         {
01169             ppolicy =
01170                 NS_STATIC_CAST(PropertyPolicy*,
01171                                PL_DHashTableOperate(cpolicy->mPolicy,
01172                                                     (void*)aProperty,
01173                                                     PL_DHASH_LOOKUP));
01174         }
01175 
01176         if ((!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)) &&
01177             mDefaultPolicy->mWildcardPolicy)
01178         {
01179             ppolicy =
01180               NS_STATIC_CAST(PropertyPolicy*,
01181                              PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy,
01182                                                   (void*)aProperty,
01183                                                   PL_DHASH_LOOKUP));
01184         }
01185     }
01186 
01187     if (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy))
01188         return NS_OK;
01189 
01190     // Get the correct security level from the property policy
01191     if (aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY)
01192         *result = ppolicy->mSet;
01193     else
01194         *result = ppolicy->mGet;
01195 
01196     return NS_OK;
01197 }
01198 
01199 
01200 NS_IMETHODIMP
01201 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
01202 {
01203     // Get principal of currently executing script.
01204     nsresult rv;
01205     nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
01206     if (NS_FAILED(rv))
01207         return rv;
01208 
01209     // Native code can load all URIs.
01210     if (!principal)
01211         return NS_OK;
01212 
01213     // The system principal can load all URIs.
01214     if (principal == mSystemPrincipal)
01215         return NS_OK;
01216 
01217     // Otherwise, principal should have a codebase URI that we can use to
01218     // do the remaining tests.
01219     nsCOMPtr<nsIURI> uri;
01220     if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))))
01221         return NS_ERROR_FAILURE;
01222     if (NS_SUCCEEDED(CheckLoadURI(uri, aURI, nsIScriptSecurityManager::STANDARD )))
01223         return NS_OK;
01224 
01225     // See if we're attempting to load a file: URI. If so, let a
01226     // UniversalFileRead capability trump the above check.
01227     PRBool isFile = PR_FALSE;
01228     PRBool isRes = PR_FALSE;
01229     if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
01230         NS_FAILED(aURI->SchemeIs("resource", &isRes)))
01231         return NS_ERROR_FAILURE;
01232     if (isFile || isRes)
01233     {
01234         PRBool enabled;
01235         if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled)))
01236             return NS_ERROR_FAILURE;
01237         if (enabled)
01238             return NS_OK;
01239     }
01240 
01241     // Report error.
01242     nsCAutoString spec;
01243     if (NS_FAILED(aURI->GetAsciiSpec(spec)))
01244         return NS_ERROR_FAILURE;
01245     JS_ReportError(cx, "Access to '%s' from script denied", spec.get());
01246     return NS_ERROR_DOM_BAD_URI;
01247 }
01248 
01249 // static
01250 nsresult
01251 nsScriptSecurityManager::GetBaseURIScheme(nsIURI* aURI,
01252                                           nsCString& aScheme)
01253 {
01254     if (!aURI)
01255        return NS_ERROR_FAILURE;
01256 
01257     nsresult rv;
01258 
01259     //-- get the source scheme
01260     rv = aURI->GetScheme(aScheme);
01261     if (NS_FAILED(rv)) return rv;
01262 
01263     //-- If aURI is a view-source URI, drill down to the base URI
01264     if (aScheme.EqualsLiteral("view-source"))
01265     {
01266         nsCAutoString path;
01267         rv = aURI->GetPath(path);
01268         if (NS_FAILED(rv)) return rv;
01269         nsCOMPtr<nsIURI> innerURI;
01270         rv = NS_NewURI(getter_AddRefs(innerURI), path, nsnull, nsnull,
01271                        sIOService);
01272         if (NS_FAILED(rv)) return rv;
01273         return nsScriptSecurityManager::GetBaseURIScheme(innerURI, aScheme);
01274     }
01275 
01276     //-- If aURI is a jar URI, drill down again
01277     nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(aURI);
01278     if (jarURI)
01279     {
01280         nsCOMPtr<nsIURI> innerURI;
01281         jarURI->GetJARFile(getter_AddRefs(innerURI));
01282         if (!innerURI) return NS_ERROR_FAILURE;
01283         return nsScriptSecurityManager::GetBaseURIScheme(innerURI, aScheme);
01284     }
01285 
01286     //-- if aURI is an about uri, distinguish 'safe' and 'unsafe' about URIs
01287     if(aScheme.EqualsLiteral("about"))
01288     {
01289         nsCAutoString path;
01290         rv = NS_GetAboutModuleName(aURI, path);
01291         NS_ENSURE_SUCCESS(rv, rv);
01292         if (path.EqualsLiteral("blank")   ||
01293             path.EqualsLiteral("mozilla") ||
01294             path.EqualsLiteral("logo")    ||
01295             path.EqualsLiteral("license") ||
01296             path.EqualsLiteral("licence") ||
01297             path.EqualsLiteral("credits") ||
01298             path.EqualsLiteral("neterror") ||
01299             path.EqualsLiteral("feeds")) // FIXME: make this list extendable
01300         {
01301             aScheme = NS_LITERAL_CSTRING("about safe");
01302             return NS_OK;
01303         }
01304     }
01305 
01306     return NS_OK;
01307 }
01308 
01309 NS_IMETHODIMP
01310 nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
01311                                       PRUint32 aFlags)
01312 {
01313     NS_PRECONDITION(aSourceURI, "CheckLoadURI called with null source URI");
01314     NS_ENSURE_ARG_POINTER(aSourceURI);
01315     
01316     nsCOMPtr<nsIPrincipal> sourcePrincipal;
01317     nsresult rv = CreateCodebasePrincipal(aSourceURI,
01318                                           getter_AddRefs(sourcePrincipal));
01319     NS_ENSURE_SUCCESS(rv, rv);
01320     return CheckLoadURIWithPrincipal(sourcePrincipal, aTargetURI, aFlags);
01321 }
01322 
01323 NS_IMETHODIMP
01324 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
01325                                                    nsIURI *aTargetURI,
01326                                                    PRUint32 aFlags)
01327 {
01328     NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
01329     // If someone passes a flag that we don't understand, we should
01330     // fail, because they may need a security check that we don't
01331     // provide.
01332     NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::DISALLOW_FROM_MAIL |
01333                                nsIScriptSecurityManager::ALLOW_CHROME |
01334                                nsIScriptSecurityManager::DISALLOW_SCRIPT |
01335                                nsIScriptSecurityManager::DISALLOW_SCRIPT_OR_DATA),
01336                     NS_ERROR_UNEXPECTED);
01337     NS_ENSURE_ARG_POINTER(aPrincipal);
01338 
01339     if (aPrincipal == mSystemPrincipal) {
01340         // Allow access
01341         return NS_OK;
01342     }
01343     
01344     nsCOMPtr<nsIURI> sourceURI;
01345     aPrincipal->GetURI(getter_AddRefs(sourceURI));
01346 
01347     NS_ASSERTION(sourceURI, "Non-system principals passed to CheckLoadURIWithPrincipal must have a URI!");
01348     
01349     //-- get the source scheme
01350     nsCAutoString sourceScheme;
01351     nsresult rv = GetBaseURIScheme(sourceURI, sourceScheme);
01352     if (NS_FAILED(rv)) return rv;
01353 
01354     // Some loads are not allowed from mail/news messages
01355     if ((aFlags & nsIScriptSecurityManager::DISALLOW_FROM_MAIL) &&
01356         (sourceScheme.LowerCaseEqualsLiteral("mailbox") ||
01357          sourceScheme.LowerCaseEqualsLiteral("imap")    ||
01358          sourceScheme.LowerCaseEqualsLiteral("news")))
01359     {
01360         return NS_ERROR_DOM_BAD_URI;
01361     }
01362 
01363     //-- get the target scheme
01364     nsCAutoString targetScheme;
01365     rv = GetBaseURIScheme(aTargetURI, targetScheme);
01366     if (NS_FAILED(rv)) return rv;
01367 
01368     //-- Some callers do not allow loading javascript: or data: URLs
01369     if (((aFlags & (nsIScriptSecurityManager::DISALLOW_SCRIPT |
01370                     nsIScriptSecurityManager::DISALLOW_SCRIPT_OR_DATA)) &&
01371          targetScheme.Equals("javascript")) ||
01372         ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT_OR_DATA) &&
01373          targetScheme.Equals("data")))
01374     {
01375        return NS_ERROR_DOM_BAD_URI;
01376     }
01377 
01378     if (nsCRT::strcasecmp(targetScheme.get(), sourceScheme.get()) == 0)
01379     {
01380         // every scheme can access another URI from the same scheme
01381         return NS_OK;
01382     }
01383 
01384     //-- If the schemes don't match, the policy is specified in this table.
01385     enum Action { AllowProtocol, DenyProtocol, PrefControlled, ChromeProtocol};
01386     static const struct
01387     {
01388         const char *name;
01389         Action action;
01390     } protocolList[] =
01391     {
01392         //-- Keep the most commonly used protocols at the top of the list
01393         //   to increase performance
01394         { "http",            AllowProtocol  },
01395         { "chrome",          ChromeProtocol },
01396         { "file",            PrefControlled },
01397         { "https",           AllowProtocol  },
01398         { "mailbox",         DenyProtocol   },
01399         { "pop",             AllowProtocol  },
01400         { "imap",            DenyProtocol   },
01401         { "pop3",            DenyProtocol   },
01402         { "news",            AllowProtocol  },
01403         { "javascript",      AllowProtocol  },
01404         { "ftp",             AllowProtocol  },
01405         { "about safe",      AllowProtocol  },
01406         { "about",           DenyProtocol   },
01407         { "mailto",          AllowProtocol  },
01408         { "aim",             AllowProtocol  },
01409         { "data",            AllowProtocol  },
01410         { "keyword",         DenyProtocol   },
01411         { "resource",        ChromeProtocol },
01412         { "gopher",          AllowProtocol  },
01413         { "datetime",        DenyProtocol   },
01414         { "finger",          AllowProtocol  },
01415         { "res",             DenyProtocol   },
01416         { "x-jsd",           DenyProtocol   },
01417         { "wyciwyg",         DenyProtocol   }
01418     };
01419 
01420     NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
01421     for (unsigned i=0; i < sizeof(protocolList)/sizeof(protocolList[0]); i++)
01422     {
01423         if (targetScheme.LowerCaseEqualsASCII(protocolList[i].name))
01424         {
01425             switch (protocolList[i].action)
01426             {
01427             case AllowProtocol:
01428                 // everyone can access these schemes.
01429                 return NS_OK;
01430             case PrefControlled:
01431                 {
01432                     // resource: and chrome: are equivalent, securitywise
01433                     if (sourceScheme.EqualsLiteral("chrome") ||
01434                         sourceScheme.EqualsLiteral("resource"))
01435                         return NS_OK;
01436 
01437                     // Now check capability policies
01438                     static const char loadURIPrefGroup[] = "checkloaduri";
01439 
01440                     SecurityLevel secLevel;
01441                     rv = LookupPolicy(aPrincipal,
01442                                       (char*)loadURIPrefGroup,
01443                                       sEnabledID,
01444                                       nsIXPCSecurityManager::ACCESS_GET_PROPERTY, 
01445                                       nsnull, &secLevel);
01446                     if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
01447                     {
01448                         // OK for this site!
01449                         return NS_OK;
01450                     }
01451 
01452                     ReportError(nsnull, errorTag, sourceURI, aTargetURI);
01453                     return NS_ERROR_DOM_BAD_URI;
01454                 }
01455             case ChromeProtocol:
01456                 if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME)
01457                     return NS_OK;
01458                 // resource: and chrome: are equivalent, securitywise
01459                 if (sourceScheme.EqualsLiteral("chrome") ||
01460                     sourceScheme.EqualsLiteral("resource"))
01461                     return NS_OK;
01462                 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
01463                 return NS_ERROR_DOM_BAD_URI;
01464             case DenyProtocol:
01465                 // Deny access
01466                 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
01467                 return NS_ERROR_DOM_BAD_URI;
01468             }
01469         }
01470     }
01471 
01472     // See whether this URI is going to be handled by gnome-vfs.  If
01473     // it is, deny the load.
01474 #ifdef MOZ_X11
01475     nsCOMPtr<nsIProtocolHandler> gnomeVFSHandler =
01476         do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"moz-gnomevfs");
01477     if (gnomeVFSHandler) {
01478         nsCOMPtr<nsIPrefBranch> prefService =
01479             do_GetService(NS_PREFSERVICE_CONTRACTID);
01480         if (prefService) {
01481             nsXPIDLCString gnomeVFSProtocols;
01482             nsresult result =
01483                 prefService->GetCharPref("network.gnomevfs.supported-protocols",
01484                                          getter_Copies(gnomeVFSProtocols));
01485             if (NS_SUCCEEDED(result))
01486                 gnomeVFSProtocols.StripWhitespace();
01487             else
01488                 gnomeVFSProtocols.Truncate();
01489 
01490             // Now see whether the target scheme is supported
01491             nsCAutoString scheme(targetScheme);
01492             scheme.Append(':');
01493             nsACString::const_iterator begin, end, iter;
01494             gnomeVFSProtocols.BeginReading(begin);
01495             gnomeVFSProtocols.EndReading(end);
01496             iter = begin;
01497             if (CaseInsensitiveFindInReadable(scheme, iter, end) &&
01498                 (iter == begin || *(--iter) == ',')) {
01499                 // Deny this load
01500                 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
01501                 return NS_ERROR_DOM_BAD_URI;
01502             }
01503         }
01504     }
01505 #endif
01506 
01507     // If we reach here, we have an unknown protocol. Warn, but allow.
01508     // This is risky from a security standpoint, but allows flexibility
01509     // in installing new protocol handlers after initial ship.
01510     NS_WARNING("unknown protocol in nsScriptSecurityManager::CheckLoadURI");
01511 
01512     return NS_OK;
01513 }
01514 
01515 nsresult
01516 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
01517                                      nsIURI* aSource, nsIURI* aTarget)
01518 {
01519     nsresult rv;
01520     NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
01521 
01522     // Get the source URL spec
01523     nsCAutoString sourceSpec;
01524     rv = aSource->GetAsciiSpec(sourceSpec);
01525     NS_ENSURE_SUCCESS(rv, rv);
01526 
01527     // Get the target URL spec
01528     nsCAutoString targetSpec;
01529     rv = aTarget->GetAsciiSpec(targetSpec);
01530     NS_ENSURE_SUCCESS(rv, rv);
01531 
01532     // Localize the error message
01533     nsXPIDLString message;
01534     NS_ConvertASCIItoUCS2 ucsSourceSpec(sourceSpec);
01535     NS_ConvertASCIItoUCS2 ucsTargetSpec(targetSpec);
01536     const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
01537     rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
01538                                           formatStrings,
01539                                           NS_ARRAY_LENGTH(formatStrings),
01540                                           getter_Copies(message));
01541     NS_ENSURE_SUCCESS(rv, rv);
01542 
01543     // If a JS context was passed in, set a JS exception.
01544     // Otherwise, print the error message directly to the JS console
01545     // and to standard output
01546     if (cx)
01547     {
01548         SetPendingException(cx, message.get());
01549         // Tell XPConnect that an exception was thrown, if appropriate
01550         if (sXPConnect)
01551         {
01552             nsCOMPtr<nsIXPCNativeCallContext> xpcCallContext;
01553             sXPConnect->GetCurrentNativeCallContext(getter_AddRefs(xpcCallContext));
01554              if (xpcCallContext)
01555                 xpcCallContext->SetExceptionWasThrown(PR_TRUE);
01556         }
01557     }
01558     else // Print directly to the console
01559     {
01560         nsCOMPtr<nsIConsoleService> console(
01561             do_GetService("@mozilla.org/consoleservice;1"));
01562         NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
01563 
01564         console->LogStringMessage(message.get());
01565 #ifdef DEBUG
01566         fprintf(stderr, "%s\n", NS_LossyConvertUCS2toASCII(message).get());
01567 #endif
01568     }
01569     return NS_OK;
01570 }
01571 
01572 NS_IMETHODIMP
01573 nsScriptSecurityManager::CheckLoadURIStr(const nsACString& aSourceURIStr,
01574                                          const nsACString& aTargetURIStr,
01575                                          PRUint32 aFlags)
01576 {
01577     nsCOMPtr<nsIURI> source;
01578     nsresult rv = NS_NewURI(getter_AddRefs(source), aSourceURIStr,
01579                             nsnull, nsnull, sIOService);
01580     NS_ENSURE_SUCCESS(rv, rv);
01581 
01582     nsCOMPtr<nsIURI> target;
01583     rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
01584                    nsnull, nsnull, sIOService);
01585     NS_ENSURE_SUCCESS(rv, rv);
01586 
01587     rv = CheckLoadURI(source, target, aFlags);
01588     NS_ENSURE_SUCCESS(rv, rv);
01589 
01590     // Now start testing fixup -- since aTargetURIStr is a string, not
01591     // an nsIURI, we may well end up fixing it up before loading.
01592     // Note: This needs to stay in sync with the nsIURIFixup api.
01593     nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
01594     if (!fixup) {
01595         return rv;
01596     }
01597 
01598     PRUint32 flags[] = {
01599         nsIURIFixup::FIXUP_FLAG_NONE,
01600         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
01601         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
01602         nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
01603         nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
01604     };
01605 
01606     for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(flags); ++i) {
01607         rv = fixup->CreateFixupURI(aTargetURIStr, flags[i],
01608                                    getter_AddRefs(target));
01609         NS_ENSURE_SUCCESS(rv, rv);
01610 
01611         rv = CheckLoadURI(source, target, aFlags);
01612         NS_ENSURE_SUCCESS(rv, rv);
01613     }
01614 
01615     return rv;
01616 }
01617 
01618 NS_IMETHODIMP
01619 nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
01620                                              void *aTargetObj)
01621 {
01622     // This check is called for event handlers
01623     nsresult rv;
01624     nsIPrincipal* subject =
01625         GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
01626 
01627     // If subject is null, get a principal from the function object's scope.
01628     if (NS_SUCCEEDED(rv) && !subject)
01629     {
01630 #ifdef DEBUG
01631         {
01632             JSFunction *fun =
01633                 (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj);
01634             JSScript *script = JS_GetFunctionScript(aCx, fun);
01635 
01636             NS_ASSERTION(!script, "Null principal for non-native function!");
01637         }
01638 #endif
01639 
01640         subject = doGetObjectPrincipal(aCx, (JSObject*)aFunObj);
01641     }
01642 
01643     if (!subject)
01644         return NS_ERROR_FAILURE;
01645 
01646     if (subject == mSystemPrincipal)
01647         // This is the system principal: just allow access
01648         return NS_OK;
01649 
01650     // Check if the principal the function was compiled under is
01651     // allowed to execute scripts.
01652 
01653     PRBool result;
01654     rv = CanExecuteScripts(aCx, subject, &result);
01655     if (NS_FAILED(rv))
01656       return rv;
01657 
01658     if (!result)
01659       return NS_ERROR_DOM_SECURITY_ERR;
01660 
01661     /*
01662     ** Get origin of subject and object and compare.
01663     */
01664     JSObject* obj = (JSObject*)aTargetObj;
01665     nsIPrincipal* object = doGetObjectPrincipal(aCx, obj);
01666 
01667     if (!object)
01668         return NS_ERROR_FAILURE;        
01669 
01670     // Note that CheckSameOriginPrincipal already does an equality
01671     // comparison on subject and object, so no need for us to do it.
01672     return CheckSameOriginPrincipal(subject, object, PR_TRUE);
01673 }
01674 
01675 nsresult
01676 nsScriptSecurityManager::GetRootDocShell(JSContext *cx, nsIDocShell **result)
01677 {
01678     nsresult rv;
01679     *result = nsnull;
01680     nsIScriptContext *scriptContext = GetScriptContext(cx);
01681     if (!scriptContext)
01682         return NS_ERROR_FAILURE;
01683 
01684     nsIScriptGlobalObject *globalObject = scriptContext->GetGlobalObject();
01685     if (!globalObject)
01686         return NS_ERROR_FAILURE;
01687 
01688     nsCOMPtr<nsIDocShellTreeItem> docshellTreeItem =
01689         do_QueryInterface(globalObject->GetDocShell(), &rv);
01690     if (NS_FAILED(rv)) return rv;
01691 
01692     nsCOMPtr<nsIDocShellTreeItem> rootItem;
01693     rv = docshellTreeItem->GetRootTreeItem(getter_AddRefs(rootItem));
01694     if (NS_FAILED(rv)) return rv;
01695 
01696     return rootItem->QueryInterface(NS_GET_IID(nsIDocShell), (void**)result);
01697 }
01698 
01699 NS_IMETHODIMP
01700 nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
01701                                            nsIPrincipal *aPrincipal,
01702                                            PRBool *result)
01703 {
01704     *result = PR_FALSE; 
01705 
01706     if (aPrincipal == mSystemPrincipal)
01707     {
01708         // Even if JavaScript is disabled, we must still execute system scripts
01709         *result = PR_TRUE;
01710         return NS_OK;
01711     }
01712 
01713     //-- See if the current window allows JS execution
01714     nsIScriptContext *scriptContext = GetScriptContext(cx);
01715     if (!scriptContext) return NS_ERROR_FAILURE;
01716 
01717     if (!scriptContext->GetScriptsEnabled()) {
01718         // No scripting on this context, folks
01719         *result = PR_FALSE;
01720         return NS_OK;
01721     }
01722     
01723     nsIScriptGlobalObject *globalObject = scriptContext->GetGlobalObject();
01724     if (!globalObject) return NS_ERROR_FAILURE;
01725 
01726     nsresult rv;
01727     nsCOMPtr<nsIDocShell> docshell = globalObject->GetDocShell();
01728     nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem = do_QueryInterface(docshell);
01729     if (globalObjTreeItem) 
01730     {
01731         nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
01732         nsCOMPtr<nsIDocShellTreeItem> parentItem;
01733 
01734         // Walk up the docshell tree to see if any containing docshell disallows scripts
01735         do
01736         {
01737             rv = docshell->GetAllowJavascript(result);
01738             if (NS_FAILED(rv)) return rv;
01739             if (!*result)
01740                 return NS_OK; // Do not run scripts
01741             treeItem->GetParent(getter_AddRefs(parentItem));
01742             treeItem.swap(parentItem);
01743             docshell = do_QueryInterface(treeItem);
01744 #ifdef DEBUG
01745             if (treeItem && !docshell) {
01746               NS_ERROR("cannot get a docshell from a treeItem!");
01747             }
01748 #endif // DEBUG
01749         } while (treeItem && docshell);
01750     }
01751 
01752     // OK, the docshell doesn't have script execution explicitly disabled.
01753     // Check whether our URI is "about:".  If it is, we need to allow JS to
01754     // run...  In this case, don't apply the JS enabled pref or policies.
01755     nsCOMPtr<nsIURI> principalURI;
01756     aPrincipal->GetURI(getter_AddRefs(principalURI));
01757     if (principalURI)
01758     {
01759         nsCAutoString spec;
01760         principalURI->GetSpec(spec);
01761         if (spec.EqualsLiteral("about:") ||
01762             StringBeginsWith(spec, NS_LITERAL_CSTRING("about:neterror?")) ||
01763             spec.EqualsLiteral("about:feeds")) // FIXME: make this list extendable
01764         {
01765             *result = PR_TRUE;
01766             return NS_OK;              
01767         }
01768     }
01769 
01770     //-- See if JS is disabled globally (via prefs)
01771     *result = mIsJavaScriptEnabled;
01772     if (mIsJavaScriptEnabled != mIsMailJavaScriptEnabled && globalObjTreeItem) 
01773     {
01774         nsCOMPtr<nsIDocShellTreeItem> rootItem;
01775         globalObjTreeItem->GetRootTreeItem(getter_AddRefs(rootItem));
01776         docshell = do_QueryInterface(rootItem);
01777         if (docshell) 
01778         {
01779             // Is this script running from mail?
01780             PRUint32 appType;
01781             rv = docshell->GetAppType(&appType);
01782             if (NS_FAILED(rv)) return rv;
01783             if (appType == nsIDocShell::APP_TYPE_MAIL) 
01784             {
01785                 *result = mIsMailJavaScriptEnabled;
01786             }
01787         }
01788     }
01789 
01790     if (!*result)
01791         return NS_OK; // Do not run scripts
01792 
01793     //-- Check for a per-site policy
01794     static const char jsPrefGroupName[] = "javascript";
01795 
01796     SecurityLevel secLevel;
01797     rv = LookupPolicy(aPrincipal, (char*)jsPrefGroupName, sEnabledID,
01798                       nsIXPCSecurityManager::ACCESS_GET_PROPERTY, 
01799                       nsnull, &secLevel);
01800     if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
01801     {
01802         *result = PR_FALSE;
01803         return rv;
01804     }
01805 
01806     //-- Nobody vetoed, so allow the JS to run.
01807     *result = PR_TRUE;
01808     return NS_OK;
01809 }
01810 
01812 NS_IMETHODIMP
01813 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
01814 {
01815     nsresult rv;
01816     *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
01817     if (NS_SUCCEEDED(rv))
01818         NS_IF_ADDREF(*aSubjectPrincipal);
01819     return rv;
01820 }
01821 
01822 nsIPrincipal*
01823 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
01824 {
01825     NS_PRECONDITION(rv, "Null out param");
01826     JSContext *cx = GetCurrentJSContext();
01827     if (!cx)
01828     {
01829         *rv = NS_OK;
01830         return nsnull;
01831     }
01832     return GetSubjectPrincipal(cx, rv);
01833 }
01834 
01835 NS_IMETHODIMP
01836 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
01837 {
01838     if (!mSystemPrincipal)
01839     {
01840         nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
01841         if (!system)
01842             return NS_ERROR_OUT_OF_MEMORY;
01843 
01844         nsresult rv = system->Init();
01845         if (NS_FAILED(rv))
01846             return rv;
01847 
01848         mSystemPrincipal = system;
01849     }
01850 
01851     NS_ADDREF(*result = mSystemPrincipal);
01852 
01853     return NS_OK;
01854 }
01855 
01856 NS_IMETHODIMP
01857 nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem)
01858 {
01859     NS_ENSURE_ARG_POINTER(aIsSystem);
01860     *aIsSystem = PR_FALSE;
01861 
01862     if (!mSystemPrincipal)
01863         return NS_OK;
01864 
01865     nsCOMPtr<nsIPrincipal> subject;
01866     nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
01867     if (NS_FAILED(rv))
01868         return rv;
01869 
01870     if(!subject)
01871     {
01872         // No subject principal means no JS is running;
01873         // this is the equivalent of system principal code
01874         *aIsSystem = PR_TRUE;
01875         return NS_OK;
01876     }
01877 
01878     return mSystemPrincipal->Equals(subject, aIsSystem);
01879 }
01880 
01881 NS_IMETHODIMP
01882 nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint,
01883                                                  const nsACString& aSubjectName,
01884                                                  const nsACString& aPrettyName,
01885                                                  nsISupports* aCertificate,
01886                                                  nsIURI* aURI,
01887                                                  nsIPrincipal **result)
01888 {
01889     *result = nsnull;
01890     
01891     NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() &&
01892                   !aSubjectName.IsEmpty() &&
01893                   aCertificate);
01894 
01895     return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName,
01896                                      aPrettyName, aCertificate, aURI, PR_TRUE,
01897                                      result);
01898 }
01899     
01900 nsresult
01901 nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
01902                                                    const nsACString& aSubjectName,
01903                                                    const nsACString& aPrettyName,
01904                                                    nsISupports* aCertificate,
01905                                                    nsIURI* aURI,
01906                                                    PRBool aModifyTable,
01907                                                    nsIPrincipal **result)
01908 {
01909     NS_ENSURE_ARG(!aCertFingerprint.IsEmpty());
01910     
01911     // Create a certificate principal out of the certificate ID
01912     // and URI given to us.  We will use this principal to test
01913     // equality when doing our hashtable lookups below.
01914     nsRefPtr<nsPrincipal> certificate = new nsPrincipal();
01915     if (!certificate)
01916         return NS_ERROR_OUT_OF_MEMORY;
01917 
01918     nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
01919                                     aPrettyName, aCertificate, aURI);
01920     NS_ENSURE_SUCCESS(rv, rv);
01921 
01922     // Check to see if we already have this principal.
01923     nsCOMPtr<nsIPrincipal> fromTable;
01924     mPrincipals.Get(certificate, getter_AddRefs(fromTable));
01925     if (fromTable) {
01926         // Bingo.  We found the certificate in the table, which means
01927         // that it has escalated privileges.
01928 
01929         if (aModifyTable) {
01930             // Make sure this principal has names, so if we ever go to save it
01931             // we'll save them.  If we get a name mismatch here we'll throw,
01932             // but that's desirable.
01933             rv = NS_STATIC_CAST(nsPrincipal*,
01934                                 NS_STATIC_CAST(nsIPrincipal*, fromTable))
01935                 ->EnsureCertData(aSubjectName, aPrettyName, aCertificate);
01936             if (NS_FAILED(rv)) {
01937                 // We have a subject name mismatch for the same cert id.
01938                 // Hand back the |certificate| object we created and don't give
01939                 // it any rights from the table.
01940                 NS_ADDREF(*result = certificate);
01941                 return NS_OK;
01942             }                
01943         }
01944         
01945         if (!aURI) {
01946             // We were asked to just get the base certificate, so output
01947             // what we have in the table.
01948             certificate = NS_STATIC_CAST(nsPrincipal*,
01949                                          NS_STATIC_CAST(nsIPrincipal*,
01950                                                         fromTable));
01951         } else {
01952             // We found a certificate and now need to install a codebase
01953             // on it.  We don't want to modify the principal in the hash
01954             // table, so create a new principal and clone the pertinent
01955             // things.
01956             nsXPIDLCString prefName;
01957             nsXPIDLCString id;
01958             nsXPIDLCString subjectName;
01959             nsXPIDLCString granted;
01960             nsXPIDLCString denied;
01961             rv = fromTable->GetPreferences(getter_Copies(prefName),
01962                                            getter_Copies(id),
01963                                            getter_Copies(subjectName),
01964                                            getter_Copies(granted),
01965                                            getter_Copies(denied));
01966             // XXXbz assert something about subjectName and aSubjectName here?
01967             if (NS_SUCCEEDED(rv)) {
01968                 certificate = new nsPrincipal();
01969                 if (!certificate)
01970                     return NS_ERROR_OUT_OF_MEMORY;
01971 
01972                 rv = certificate->InitFromPersistent(prefName, id,
01973                                                      subjectName, aPrettyName,
01974                                                      granted, denied,
01975                                                      aCertificate,
01976                                                      PR_TRUE, PR_FALSE);
01977                 if (NS_SUCCEEDED(rv))
01978                     certificate->SetURI(aURI);
01979             }
01980         }
01981     }
01982 
01983     NS_ADDREF(*result = certificate);
01984 
01985     return rv;
01986 }
01987 
01988 nsresult
01989 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **result)
01990 {
01991     nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
01992     if (!codebase)
01993         return NS_ERROR_OUT_OF_MEMORY;
01994 
01995     nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
01996                                  EmptyCString(), nsnull, aURI);
01997     if (NS_FAILED(rv))
01998         return rv;
01999 
02000     NS_ADDREF(*result = codebase);
02001 
02002     return NS_OK;
02003 }
02004 
02005 NS_IMETHODIMP
02006 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
02007                                               nsIPrincipal **result)
02008 {
02009     nsresult rv;
02010     nsCOMPtr<nsIPrincipal> principal;
02011     rv = CreateCodebasePrincipal(aURI, getter_AddRefs(principal));
02012     if (NS_FAILED(rv)) return rv;
02013 
02014     if (mPrincipals.Count() > 0)
02015     {
02016         //-- Check to see if we already have this principal.
02017         nsCOMPtr<nsIPrincipal> fromTable;
02018         mPrincipals.Get(principal, getter_AddRefs(fromTable));
02019         if (fromTable)
02020             principal = fromTable;
02021         else //-- Check to see if we have a more general principal
02022         {
02023             nsXPIDLCString originUrl;
02024             rv = principal->GetOrigin(getter_Copies(originUrl));
02025             if (NS_FAILED(rv)) return rv;
02026             nsCOMPtr<nsIURI> newURI;
02027             rv = NS_NewURI(getter_AddRefs(newURI), originUrl, nsnull, sIOService);
02028             if (NS_FAILED(rv)) return rv;
02029             nsCOMPtr<nsIPrincipal> principal2;
02030             rv = CreateCodebasePrincipal(newURI, getter_AddRefs(principal2));
02031             if (NS_FAILED(rv)) return rv;
02032             mPrincipals.Get(principal2, getter_AddRefs(fromTable));
02033             if (fromTable)
02034                 principal = fromTable;
02035         }
02036     }
02037 
02038     NS_IF_ADDREF(*result = principal);
02039 
02040     return NS_OK;
02041 }
02042 
02043 NS_IMETHODIMP
02044 nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
02045                                                  nsIPrincipal **result)
02046 {
02047     *result = nsnull;
02048 
02049     nsIScriptContext *scriptContext = GetScriptContext(cx);
02050 
02051     if (!scriptContext)
02052     {
02053         return NS_ERROR_FAILURE;
02054     }
02055 
02056     nsCOMPtr<nsIScriptObjectPrincipal> globalData =
02057         do_QueryInterface(scriptContext->GetGlobalObject());
02058     if (globalData)
02059         NS_IF_ADDREF(*result = globalData->GetPrincipal());
02060 
02061     return NS_OK;
02062 }
02063 
02064 // static
02065 nsIPrincipal*
02066 nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
02067                                             JSScript *script,
02068                                             nsresult* rv)
02069 {
02070     NS_PRECONDITION(rv, "Null out param");
02071     *rv = NS_OK;
02072     if (!script)
02073     {
02074         return nsnull;
02075     }
02076     JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
02077     if (!jsp) {
02078         *rv = NS_ERROR_FAILURE;
02079         // Script didn't have principals -- shouldn't happen.
02080         return nsnull;
02081     }
02082     nsJSPrincipals *nsJSPrin = NS_STATIC_CAST(nsJSPrincipals *, jsp);
02083     nsIPrincipal* result = nsJSPrin->nsIPrincipalPtr;
02084     if (!result)
02085         *rv = NS_ERROR_FAILURE;
02086     return result;
02087 }
02088 
02089 // static
02090 nsIPrincipal*
02091 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
02092                                                     JSObject *obj,
02093                                                     JSStackFrame *fp,
02094                                                     nsresult *rv)
02095 {
02096     NS_PRECONDITION(rv, "Null out param");
02097     JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, obj);
02098     JSScript *script = JS_GetFunctionScript(cx, fun);
02099 
02100     *rv = NS_OK;
02101 
02102     if (!script)
02103     {
02104         // A native function: skip it in order to find its scripted caller.
02105         return nsnull;
02106     }
02107 
02108     JSScript *frameScript = fp ? JS_GetFrameScript(cx, fp) : nsnull;
02109 
02110     if (frameScript && frameScript != script)
02111     {
02112         // There is a frame script, and it's different from the
02113         // function script. In this case we're dealing with either
02114         // an eval or a Script object, and in these cases the
02115         // principal we want is in the frame's script, not in the
02116         // function's script. The function's script is where the
02117         // eval-calling code came from, not where the eval or new
02118         // Script object came from, and we want the principal of
02119         // the eval function object or new Script object.
02120 
02121         script = frameScript;
02122     }
02123     else if (JS_GetFunctionObject(fun) != obj)
02124     {
02125         // Here, obj is a cloned function object.  In this case, the
02126         // clone's prototype may have been precompiled from brutally
02127         // shared chrome, or else it is a lambda or nested function.
02128         // The general case here is a function compiled against a
02129         // different scope than the one it is parented by at runtime,
02130         // hence the creation of a clone to carry the correct scope
02131         // chain linkage.
02132         //
02133         // Since principals follow scope, we must get the object
02134         // principal from the clone's scope chain. There are no
02135         // reliable principals compiled into the function itself.
02136 
02137         nsIPrincipal *result = doGetObjectPrincipal(cx, obj);
02138         if (!result)
02139             *rv = NS_ERROR_FAILURE;
02140         return result;
02141     }
02142 
02143     return GetScriptPrincipal(cx, script, rv);
02144 }
02145 
02146 // static
02147 nsIPrincipal*
02148 nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
02149                                            JSStackFrame *fp,
02150                                            nsresult *rv)
02151 {
02152     NS_PRECONDITION(rv, "Null out param");
02153     JSObject *obj = JS_GetFrameFunctionObject(cx, fp);
02154     if (!obj)
02155     {
02156         // Must be in a top-level script. Get principal from the script.
02157         JSScript *script = JS_GetFrameScript(cx, fp);
02158         return GetScriptPrincipal(cx, script, rv);
02159     }
02160 
02161     nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
02162 
02163 #ifdef DEBUG
02164     if (NS_SUCCEEDED(*rv) && !result)
02165     {
02166         JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
02167         JSScript *script = JS_GetFunctionScript(cx, fun);
02168 
02169         NS_ASSERTION(!script, "Null principal for non-native function!");
02170     }
02171 #endif
02172 
02173     return result;
02174 }
02175 
02176 // static
02177 nsIPrincipal*
02178 nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
02179                                               JSStackFrame **frameResult,
02180                                               nsresult* rv)
02181 {
02182     NS_PRECONDITION(rv, "Null out param");    
02183     //-- If there's no principal on the stack, look at the global object
02184     //   and return the innermost frame for annotations.
02185     *rv = NS_OK;
02186     if (cx)
02187     {
02188         // Get principals from innermost frame of JavaScript or Java.
02189         JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
02190         for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
02191         {
02192             nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
02193             if (result)
02194             {
02195                 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
02196                 *frameResult = fp;
02197                 return result;
02198             }
02199         }
02200 
02201         nsIScriptContext *scriptContext = GetScriptContext(cx);
02202         if (scriptContext)
02203         {
02204             nsCOMPtr<nsIScriptObjectPrincipal> globalData =
02205                 do_QueryInterface(scriptContext->GetGlobalObject());
02206             if (!globalData)
02207             {
02208                 *rv = NS_ERROR_FAILURE;
02209                 return nsnull;
02210             }
02211 
02212             // Note that we're not in a loop or anything, and nothing comes
02213             // after this point in the function, so we can just return here.
02214             nsIPrincipal* result = globalData->GetPrincipal();
02215             if (result)
02216             {
02217                 JSStackFrame *inner = nsnull;
02218                 *frameResult = JS_FrameIterator(cx, &inner);
02219                 return result;
02220             }
02221         }
02222     }
02223 
02224     return nsnull;
02225 }
02226 
02227 // static
02228 nsIPrincipal*
02229 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
02230                                              nsresult* rv)
02231 {
02232     NS_PRECONDITION(rv, "Null out param");
02233     JSStackFrame *fp;
02234     return GetPrincipalAndFrame(cx, &fp, rv);
02235 }
02236 
02237 NS_IMETHODIMP
02238 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
02239                                             nsIPrincipal **result)
02240 {
02241     *result = doGetObjectPrincipal(aCx, aObj);
02242     if (!*result)
02243         return NS_ERROR_FAILURE;
02244     NS_ADDREF(*result);
02245     return NS_OK;
02246 }
02247 
02248 // static
02249 nsIPrincipal*
02250 nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj)
02251 {
02252     NS_ASSERTION(aCx && aObj, "Bad call to doGetObjectPrincipal()!");
02253     nsIPrincipal* result = nsnull;
02254 
02255     do
02256     {
02257         const JSClass *jsClass = JS_GetClass(aCx, aObj);
02258 
02259         if (jsClass && !(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
02260                                             JSCLASS_PRIVATE_IS_NSISUPPORTS)))
02261         {
02262             // No need to refcount |priv| here.
02263             nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
02264             nsCOMPtr<nsIScriptObjectPrincipal> objPrin;
02265 
02266             /*
02267              * If it's a wrapped native (as most
02268              * JSCLASS_PRIVATE_IS_NSISUPPORTS objects are in mozilla),
02269              * check the underlying native instead.
02270              */
02271             nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
02272                 do_QueryInterface(priv);
02273 
02274             if (xpcWrapper)
02275             {
02276                 objPrin = do_QueryWrappedNative(xpcWrapper);
02277             }
02278             else
02279             {
02280                 objPrin = do_QueryInterface(priv);
02281             }
02282 
02283             if (objPrin && (result = objPrin->GetPrincipal()))
02284             {
02285                 break;
02286             }
02287         }
02288 
02289         aObj = JS_GetParent(aCx, aObj);
02290     } while (aObj);
02291 
02292     return result;
02293 }
02294 
02295 nsresult
02296 nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
02297 {
02298     //-- Save to mPrincipals
02299     mPrincipals.Put(aToSave, aToSave);
02300 
02301     //-- Save to prefs
02302     nsXPIDLCString idPrefName;
02303     nsXPIDLCString id;
02304     nsXPIDLCString subjectName;
02305     nsXPIDLCString grantedList;
02306     nsXPIDLCString deniedList;
02307     nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName),
02308                                           getter_Copies(id),
02309                                           getter_Copies(subjectName),
02310                                           getter_Copies(grantedList),
02311                                           getter_Copies(deniedList));
02312     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02313 
02314     nsCAutoString grantedPrefName;
02315     nsCAutoString deniedPrefName;
02316     nsCAutoString subjectNamePrefName;
02317     rv = GetPrincipalPrefNames( idPrefName,
02318                                 grantedPrefName,
02319                                 deniedPrefName,
02320                                 subjectNamePrefName );
02321     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02322 
02323     mIsWritingPrefs = PR_TRUE;
02324     if (grantedList)
02325         mSecurityPref->SecuritySetCharPref(grantedPrefName.get(), grantedList);
02326     else
02327         mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
02328 
02329     if (deniedList)
02330         mSecurityPref->SecuritySetCharPref(deniedPrefName.get(), deniedList);
02331     else
02332         mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
02333 
02334     if (grantedList || deniedList) {
02335         mSecurityPref->SecuritySetCharPref(idPrefName, id);
02336         mSecurityPref->SecuritySetCharPref(subjectNamePrefName.get(),
02337                                            subjectName);
02338     }
02339     else {
02340         mSecurityPref->SecurityClearUserPref(idPrefName);
02341         mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
02342     }
02343 
02344     mIsWritingPrefs = PR_FALSE;
02345 
02346     nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
02347     NS_ENSURE_SUCCESS(rv, rv);
02348     return prefService->SavePrefFile(nsnull);
02349 }
02350 
02352 NS_IMETHODIMP
02353 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
02354                                              PRBool *result)
02355 {
02356     nsresult rv;
02357     JSStackFrame *fp = nsnull;
02358     JSContext *cx = GetCurrentJSContext();
02359     fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
02360     if (!fp)
02361     {
02362         // No script code on stack. Allow execution.
02363         *result = PR_TRUE;
02364         return NS_OK;
02365     }
02366     *result = PR_FALSE;
02367     nsIPrincipal* previousPrincipal = nsnull;
02368     do
02369     {
02370         nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
02371         if (NS_FAILED(rv))
02372             return rv;
02373         if (!principal)
02374             continue;
02375         // If caller has a different principal, stop looking up the stack.
02376         if(previousPrincipal)
02377         {
02378             PRBool isEqual = PR_FALSE;
02379             if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
02380                 break;
02381         }
02382         else
02383             previousPrincipal = principal;
02384 
02385         // First check if the principal is even able to enable the
02386         // given capability. If not, don't look any further.
02387         PRInt16 canEnable;
02388         rv = principal->CanEnableCapability(capability, &canEnable);
02389         if (NS_FAILED(rv)) return rv;
02390         if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
02391             canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
02392             return NS_OK;
02393 
02394         // Now see if the capability is enabled.
02395         void *annotation = JS_GetFrameAnnotation(cx, fp);
02396         rv = principal->IsCapabilityEnabled(capability, annotation, result);
02397         if (NS_FAILED(rv)) return rv;
02398         if (*result)
02399             return NS_OK;
02400     } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
02401 
02402     if (!previousPrincipal)
02403     {
02404         // No principals on the stack, all native code.  Allow
02405         // execution if the subject principal is the system principal.
02406 
02407         return SubjectPrincipalIsSystem(result);
02408     }
02409 
02410     return NS_OK;
02411 }
02412 
02413 void
02414 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
02415 {
02416     nsAutoString newcaps;
02417     nsAutoString rawcap;
02418     NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
02419     PRInt32 pos;
02420     PRInt32 index = kNotFound;
02421     nsresult rv;
02422 
02423     NS_ASSERTION(kNotFound == -1, "Basic constant changed, algorithm broken!");
02424 
02425     do {
02426         pos = index+1;
02427         index = aCapability.FindChar(' ', pos);
02428         rawcap = Substring(aCapability, pos,
02429                            (index == kNotFound) ? index : index - pos);
02430 
02431         nsXPIDLString capstr;
02432         rv = sStrBundle->GetStringFromName(
02433                             nsPromiseFlatString(capdesc+rawcap).get(),
02434                             getter_Copies(capstr));
02435         if (NS_SUCCEEDED(rv))
02436             newcaps += capstr;
02437         else
02438         {
02439             nsXPIDLString extensionCap;
02440             const PRUnichar* formatArgs[] = { rawcap.get() };
02441             rv = sStrBundle->FormatStringFromName(
02442                                 NS_LITERAL_STRING("ExtensionCapability").get(),
02443                                 formatArgs,
02444                                 NS_ARRAY_LENGTH(formatArgs),
02445                                 getter_Copies(extensionCap));
02446             if (NS_SUCCEEDED(rv))
02447                 newcaps += extensionCap;
02448             else
02449                 newcaps += rawcap;
02450         }
02451 
02452         newcaps += NS_LITERAL_STRING("\n");
02453     } while (index != kNotFound);
02454 
02455     aCapability = newcaps;
02456 }
02457 
02458 PRBool
02459 nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
02460                                             const char* aCapability, PRBool *checkValue)
02461 {
02462     nsresult rv;
02463     *checkValue = PR_FALSE;
02464 
02465     //-- Get a prompter for the current window.
02466     nsCOMPtr<nsIPrompt> prompter;
02467     if (cx)
02468     {
02469         nsIScriptContext *scriptContext = GetScriptContext(cx);
02470         if (scriptContext)
02471         {
02472             nsCOMPtr<nsIDOMWindowInternal> domWin =
02473                 do_QueryInterface(scriptContext->GetGlobalObject());
02474             if (domWin)
02475                 domWin->GetPrompter(getter_AddRefs(prompter));
02476         }
02477     }
02478 
02479     if (!prompter)
02480     {
02481         //-- Couldn't get prompter from the current window, so get the prompt service.
02482         nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
02483         if (wwatch)
02484           wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
02485         if (!prompter)
02486             return PR_FALSE;
02487     }
02488 
02489     //-- Localize the dialog text
02490     nsXPIDLString check;
02491     rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
02492                                        getter_Copies(check));
02493     if (NS_FAILED(rv))
02494         return PR_FALSE;
02495 
02496     nsXPIDLString title;
02497     rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
02498                                        getter_Copies(title));
02499     if (NS_FAILED(rv))
02500         return PR_FALSE;
02501 
02502     nsXPIDLString yesStr;
02503     rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
02504                                        getter_Copies(yesStr));
02505     if (NS_FAILED(rv))
02506         return PR_FALSE;
02507 
02508     nsXPIDLString noStr;
02509     rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(),
02510                                        getter_Copies(noStr));
02511     if (NS_FAILED(rv))
02512         return PR_FALSE;
02513 
02514     nsCAutoString val;
02515     PRBool hasCert;
02516     aPrincipal->GetHasCertificate(&hasCert);
02517     if (hasCert)
02518         rv = aPrincipal->GetPrettyName(val);
02519     else
02520         rv = GetPrincipalDomainOrigin(aPrincipal, val);
02521 
02522     if (NS_FAILED(rv))
02523         return PR_FALSE;
02524 
02525     NS_ConvertUTF8toUTF16 location(val);
02526     NS_ConvertASCIItoUTF16 capability(aCapability);
02527     FormatCapabilityString(capability);
02528     const PRUnichar *formatStrings[] = { location.get(), capability.get() };
02529 
02530     nsXPIDLString message;
02531     rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
02532                                           formatStrings,
02533                                           NS_ARRAY_LENGTH(formatStrings),
02534                                           getter_Copies(message));
02535     if (NS_FAILED(rv))
02536         return PR_FALSE;
02537 
02538     PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
02539     rv = prompter->ConfirmEx(title.get(), message.get(),
02540                              (nsIPrompt::BUTTON_DELAY_ENABLE) +
02541                              (nsIPrompt::BUTTON_POS_1_DEFAULT) +
02542                              (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
02543                              (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1),
02544                              yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed);
02545 
02546     if (NS_FAILED(rv))
02547         *checkValue = PR_FALSE;
02548     return (buttonPressed == 0);
02549 }
02550 
02551 NS_IMETHODIMP
02552 nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal,
02553                                            const char *capability, PRInt16* canEnable)
02554 {
02555     if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
02556         return NS_ERROR_FAILURE;
02557     if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
02558     {
02559         // Prompt user for permission to enable capability.
02560         JSContext* cx = GetCurrentJSContext();
02561         PRBool remember;
02562         if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
02563             *canEnable = nsIPrincipal::ENABLE_GRANTED;
02564         else
02565             *canEnable = nsIPrincipal::ENABLE_DENIED;
02566         if (remember)
02567         {
02568             //-- Save principal to prefs and to mPrincipals
02569             if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
02570                 return NS_ERROR_FAILURE;
02571             if (NS_FAILED(SavePrincipal(aPrincipal)))
02572                 return NS_ERROR_FAILURE;
02573         }
02574     }
02575     return NS_OK;
02576 }
02577 
02578 NS_IMETHODIMP
02579 nsScriptSecurityManager::EnableCapability(const char *capability)
02580 {
02581     JSContext *cx = GetCurrentJSContext();
02582     JSStackFrame *fp;
02583 
02584     //-- Error checks for capability string length (200)
02585     if(PL_strlen(capability)>200)
02586     {
02587         static const char msg[] = "Capability name too long";
02588         SetPendingException(cx, msg);
02589         return NS_ERROR_FAILURE;
02590     }
02591 
02592     //-- Check capability string for valid characters
02593     //
02594     //   Logically we might have wanted this in nsPrincipal, but performance
02595     //   worries dictate it can't go in IsCapabilityEnabled() and we may have
02596     //   to show the capability on a dialog before we call the principal's
02597     //   EnableCapability().
02598     //
02599     //   We don't need to validate the capability string on the other APIs
02600     //   available to web content. Without the ability to enable junk then
02601     //   isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
02602     //   the right thing (effectively nothing) when passed unallowed chars.
02603     for (const char *ch = capability; *ch; ++ch)
02604     {
02605         if (!NS_IS_ALPHA(*ch) && *ch != ' ' && !NS_IS_DIGIT(*ch)
02606             && *ch != '_' && *ch != '-' && *ch != '.')
02607         {
02608             static const char msg[] = "Invalid character in capability name";
02609             SetPendingException(cx, msg);
02610             return NS_ERROR_FAILURE;
02611         }
02612     }
02613 
02614     nsresult rv;
02615     nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
02616     if (NS_FAILED(rv))
02617         return rv;
02618     if (!principal)
02619         return NS_ERROR_NOT_AVAILABLE;
02620 
02621     void *annotation = JS_GetFrameAnnotation(cx, fp);
02622     PRBool enabled;
02623     if (NS_FAILED(principal->IsCapabilityEnabled(capability, annotation,
02624                                                  &enabled)))
02625         return NS_ERROR_FAILURE;
02626     if (enabled)
02627         return NS_OK;
02628 
02629     PRInt16 canEnable;
02630     if (NS_FAILED(RequestCapability(principal, capability, &canEnable)))
02631         return NS_ERROR_FAILURE;
02632 
02633     if (canEnable != nsIPrincipal::ENABLE_GRANTED)
02634     {
02635         nsCAutoString val;
02636         PRBool hasCert;
02637         nsresult rv;
02638         principal->GetHasCertificate(&hasCert);
02639         if (hasCert)
02640             rv = principal->GetPrettyName(val);
02641         else
02642             rv = GetPrincipalDomainOrigin(principal, val);
02643 
02644         if (NS_FAILED(rv))
02645             return rv;
02646 
02647         NS_ConvertUTF8toUTF16 location(val);
02648         NS_ConvertUTF8toUTF16 cap(capability);
02649         const PRUnichar *formatStrings[] = { location.get(), cap.get() };
02650 
02651         nsXPIDLString message;
02652         rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
02653                                               formatStrings,
02654                                               NS_ARRAY_LENGTH(formatStrings),
02655                                               getter_Copies(message));
02656         if (NS_FAILED(rv))
02657             return rv;
02658 
02659         SetPendingException(cx, message.get());
02660 
02661         return NS_ERROR_FAILURE; // XXX better error code?
02662     }
02663     if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
02664         return NS_ERROR_FAILURE;
02665     JS_SetFrameAnnotation(cx, fp, annotation);
02666     return NS_OK;
02667 }
02668 
02669 NS_IMETHODIMP
02670 nsScriptSecurityManager::RevertCapability(const char *capability)
02671 {
02672     JSContext *cx = GetCurrentJSContext();
02673     JSStackFrame *fp;
02674     nsresult rv;
02675     nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
02676     if (NS_FAILED(rv))
02677         return rv;
02678     if (!principal)
02679         return NS_ERROR_NOT_AVAILABLE;
02680     void *annotation = JS_GetFrameAnnotation(cx, fp);
02681     principal->RevertCapability(capability, &annotation);
02682     JS_SetFrameAnnotation(cx, fp, annotation);
02683     return NS_OK;
02684 }
02685 
02686 NS_IMETHODIMP
02687 nsScriptSecurityManager::DisableCapability(const char *capability)
02688 {
02689     JSContext *cx = GetCurrentJSContext();
02690     JSStackFrame *fp;
02691     nsresult rv;
02692     nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
02693     if (NS_FAILED(rv))
02694         return rv;
02695     if (!principal)
02696         return NS_ERROR_NOT_AVAILABLE;
02697     void *annotation = JS_GetFrameAnnotation(cx, fp);
02698     principal->DisableCapability(capability, &annotation);
02699     JS_SetFrameAnnotation(cx, fp, annotation);
02700     return NS_OK;
02701 }
02702 
02704 NS_IMETHODIMP
02705 nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint,
02706                                                 const char* capability,
02707                                                 PRInt16 canEnable)
02708 {
02709     NS_ENSURE_ARG(!certFingerprint.IsEmpty());
02710     
02711     nsresult rv;
02712     nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv);
02713     if (NS_FAILED(rv))
02714         return rv;
02715 
02716     //-- Get the system certificate
02717     if (!mSystemCertificate)
02718     {
02719         nsCOMPtr<nsIFile> systemCertFile;
02720         nsCOMPtr<nsIProperties> directoryService =
02721                  do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
02722         if (!directoryService) return NS_ERROR_FAILURE;
02723         rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
02724                               getter_AddRefs(systemCertFile));
02725         if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02726 #ifdef XP_MAC
02727         // On Mac, this file will be located in the Essential Files folder
02728         systemCertFile->AppendNative(NS_LITERAL_CSTRING("Essential Files"));
02729         if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02730 #endif
02731         systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
02732         if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02733         nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv);
02734         if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02735         systemCertZip->Init(systemCertFile);
02736         rv = systemCertZip->Open();
02737         if (NS_SUCCEEDED(rv))
02738         {
02739             nsCOMPtr<nsIJAR> systemCertJar(do_QueryInterface(systemCertZip, &rv));
02740             if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02741             rv = systemCertJar->GetCertificatePrincipal(nsnull,
02742                                                         getter_AddRefs(mSystemCertificate));
02743             if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02744         }
02745     }
02746 
02747     //-- Make sure the caller's principal is the system certificate
02748     PRBool isEqual = PR_FALSE;
02749     if (mSystemCertificate)
02750     {
02751         rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual);
02752         if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02753     }
02754     if (!isEqual)
02755     {
02756         JSContext* cx = GetCurrentJSContext();
02757         if (!cx) return NS_ERROR_FAILURE;
02758         static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
02759         static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
02760         SetPendingException(cx, mSystemCertificate ? msg1 : msg2);
02761         return NS_ERROR_FAILURE;
02762     }
02763 
02764     //-- Get the target principal
02765     nsCOMPtr<nsIPrincipal> objectPrincipal;
02766     rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(),
02767                                    EmptyCString(), nsnull,
02768                                    nsnull, PR_FALSE,
02769                                    getter_AddRefs(objectPrincipal));
02770     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02771     rv = objectPrincipal->SetCanEnableCapability(capability, canEnable);
02772     if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
02773     return SavePrincipal(objectPrincipal);
02774 }
02775 
02777 // Methods implementing nsIXPCSecurityManager //
02779 
02780 NS_IMETHODIMP
02781 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
02782                                           const nsIID &aIID,
02783                                           nsISupports *aObj,
02784                                           nsIClassInfo *aClassInfo,
02785                                           void **aPolicy)
02786 {
02787 #ifdef DEBUG_CAPS_CanCreateWrapper
02788     char* iidStr = aIID.ToString();
02789     printf("### CanCreateWrapper(%s) ", iidStr);
02790     nsCRT::free(iidStr);
02791 #endif
02792 // XXX Special case for nsIXPCException ?
02793     ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nsnull);
02794     if (objClassInfo.IsDOMClass())
02795     {
02796 #ifdef DEBUG_CAPS_CanCreateWrapper
02797         printf("DOM class - GRANTED.\n");
02798 #endif
02799         return NS_OK;
02800     }
02801 
02802     //--See if the object advertises a non-default level of access
02803     //  using nsISecurityCheckedComponent
02804     nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
02805         do_QueryInterface(aObj);
02806 
02807     nsXPIDLCString objectSecurityLevel;
02808     if (checkedComponent)
02809         checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
02810 
02811     nsresult rv = CheckXPCPermissions(aObj, objectSecurityLevel);
02812     if (NS_FAILED(rv))
02813     {
02814         //-- Access denied, report an error
02815 
02816         NS_NAMED_LITERAL_STRING(strName, "CreateWrapperDenied");
02817         NS_ConvertUTF8toUTF16 className(objClassInfo.GetName());
02818         const PRUnichar* formatStrings[] = { className.get() };
02819         nsXPIDLString errorMsg;
02820         // We need to keep our existing failure rv and not override it
02821         // with a likely success code from the following string bundle
02822         // call in order to throw the correct security exception later.
02823         nsresult rv2 =
02824             sStrBundle->FormatStringFromName(strName.get(),
02825                                              formatStrings,
02826                                              NS_ARRAY_LENGTH(formatStrings),
02827                                              getter_Copies(errorMsg));
02828         NS_ENSURE_SUCCESS(rv2, rv2);
02829 
02830         SetPendingException(cx, errorMsg.get());
02831 
02832 #ifdef DEBUG_CAPS_CanCreateWrapper
02833         printf("DENIED.\n");
02834     }
02835     else
02836     {
02837         printf("GRANTED.\n");
02838 #endif
02839     }
02840 
02841     return rv;
02842 }
02843 
02844 #ifdef XPC_IDISPATCH_SUPPORT
02845 nsresult
02846 nsScriptSecurityManager::CheckComponentPermissions(JSContext *cx,
02847                                                    const nsCID &aCID)
02848 {
02849     nsresult rv;
02850     nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
02851     if (NS_FAILED(rv))
02852         return rv;
02853 
02854     // Reformat the CID string so it's suitable for prefs
02855     nsXPIDLCString cidTemp;
02856     cidTemp.Adopt(aCID.ToString());
02857     nsCAutoString cid(NS_LITERAL_CSTRING("CID") +
02858                       Substring(cidTemp, 1, cidTemp.Length() - 2));
02859     ToUpperCase(cid);
02860 
02861 #ifdef DEBUG_CAPS_CheckComponentPermissions
02862     printf("### CheckComponentPermissions(ClassID.%s) ",cid.get());
02863 #endif
02864 
02865     // Look up the policy for this class.
02866     // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD
02867     jsval cidVal = STRING_TO_JSVAL(::JS_InternString(cx, cid.get()));
02868 
02869     SecurityLevel securityLevel;
02870     rv = LookupPolicy(subjectPrincipal, "ClassID", cidVal,
02871                       nsIXPCSecurityManager::ACCESS_CALL_METHOD, 
02872                       nsnull, &securityLevel);
02873     if (NS_FAILED(rv))
02874         return rv;
02875 
02876     // If there's no policy stored, use the "security.classID.allowByDefault" pref 
02877     if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
02878         securityLevel.level = mXPCDefaultGrantAll ? SCRIPT_SECURITY_ALL_ACCESS :
02879                                                     SCRIPT_SECURITY_NO_ACCESS;
02880 
02881     if (securityLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
02882     {
02883 #ifdef DEBUG_CAPS_CheckComponentPermissions
02884         printf(" GRANTED.\n");
02885 #endif
02886         return NS_OK;
02887     }
02888 
02889 #ifdef DEBUG_CAPS_CheckComponentPermissions
02890     printf(" DENIED.\n");
02891 #endif
02892     return NS_ERROR_DOM_PROP_ACCESS_DENIED;
02893 }
02894 #endif
02895 
02896 NS_IMETHODIMP
02897 nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
02898                                            const nsCID &aCID)
02899 {
02900 #ifdef DEBUG_CAPS_CanCreateInstance
02901     char* cidStr = aCID.ToString();
02902     printf("### CanCreateInstance(%s) ", cidStr);
02903     nsCRT::free(cidStr);
02904 #endif
02905 
02906     nsresult rv = CheckXPCPermissions(nsnull, nsnull);
02907     if (NS_FAILED(rv))
02908 #ifdef XPC_IDISPATCH_SUPPORT
02909     {
02910         rv = CheckComponentPermissions(cx, aCID);
02911     }
02912     if (NS_FAILED(rv))
02913 #endif
02914     {
02915         //-- Access denied, report an error
02916         nsCAutoString errorMsg("Permission denied to create instance of class. CID=");
02917         nsXPIDLCString cidStr;
02918         cidStr += aCID.ToString();
02919         errorMsg.Append(cidStr);
02920         SetPendingException(cx, errorMsg.get());
02921 
02922 #ifdef DEBUG_CAPS_CanCreateInstance
02923         printf("DENIED\n");
02924     }
02925     else
02926     {
02927         printf("GRANTED\n");
02928 #endif
02929     }
02930     return rv;
02931 }
02932 
02933 NS_IMETHODIMP
02934 nsScriptSecurityManager::CanGetService(JSContext *cx,
02935                                        const nsCID &aCID)
02936 {
02937 #ifdef DEBUG_CAPS_CanGetService
02938     char* cidStr = aCID.ToString();
02939     printf("### CanGetService(%s) ", cidStr);
02940     nsCRT::free(cidStr);
02941 #endif
02942 
02943     nsresult rv = CheckXPCPermissions(nsnull, nsnull);
02944     if (NS_FAILED(rv))
02945     {
02946         //-- Access denied, report an error
02947         nsCAutoString errorMsg("Permission denied to get service. CID=");
02948         nsXPIDLCString cidStr;
02949         cidStr += aCID.ToString();
02950         errorMsg.Append(cidStr);
02951         SetPendingException(cx, errorMsg.get());
02952 
02953 #ifdef DEBUG_CAPS_CanGetService
02954         printf("DENIED\n");
02955     }
02956     else
02957     {
02958         printf("GRANTED\n");
02959 #endif
02960     }
02961 
02962     return rv;
02963 }
02964 
02965 
02966 NS_IMETHODIMP
02967 nsScriptSecurityManager::CanAccess(PRUint32 aAction,
02968                                    nsIXPCNativeCallContext* aCallContext,
02969                                    JSContext* cx,
02970                                    JSObject* aJSObject,
02971                                    nsISupports* aObj,
02972                                    nsIClassInfo* aClassInfo,
02973                                    jsval aPropertyName,
02974                                    void** aPolicy)
02975 {
02976     return CheckPropertyAccessImpl(aAction, aCallContext, cx,
02977                                    aJSObject, aObj, nsnull, aClassInfo,
02978                                    nsnull, aPropertyName, aPolicy);
02979 }
02980 
02981 nsresult
02982 nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj,
02983                                              const char* aObjectSecurityLevel)
02984 {
02985     //-- Check for the all-powerful UniversalXPConnect privilege
02986     PRBool ok = PR_FALSE;
02987     if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok)) && ok)
02988         return NS_OK;
02989 
02990     //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
02991     if (aObjectSecurityLevel)
02992     {
02993         if (PL_strcasecmp(aObjectSecurityLevel, "AllAccess") == 0)
02994             return NS_OK;
02995         else if (PL_strcasecmp(aObjectSecurityLevel, "NoAccess") != 0)
02996         {
02997             PRBool canAccess = PR_FALSE;
02998             if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel, &canAccess)) &&
02999                 canAccess)
03000                 return NS_OK;
03001         }
03002     }
03003 
03004     //-- If user allows scripting of plugins by untrusted scripts,
03005     //   and the target object is a plugin, allow the access.
03006     if(aObj)
03007     {
03008         nsresult rv;
03009         nsCOMPtr<nsIPluginInstance> plugin(do_QueryInterface(aObj, &rv));
03010         if (NS_SUCCEEDED(rv))
03011         {
03012             static PRBool prefSet = PR_FALSE;
03013             static PRBool allowPluginAccess = PR_FALSE;
03014             if (!prefSet)
03015             {
03016                 rv = mSecurityPref->SecurityGetBoolPref("security.xpconnect.plugin.unrestricted",
03017                                                        &allowPluginAccess);
03018                 prefSet = PR_TRUE;
03019             }
03020             if (allowPluginAccess)
03021                 return NS_OK;
03022         }
03023     }
03024 
03025     //-- Access tests failed
03026     return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
03027 }
03028 
03030 // Method implementing nsIPrefSecurityCheck //
03032 
03033 NS_IMETHODIMP
03034 nsScriptSecurityManager::CanAccessSecurityPreferences(PRBool* _retval)
03035 {
03036     return IsCapabilityEnabled("CapabilityPreferencesAccess", _retval);  
03037 }
03038 
03039 
03041 // Method implementing nsIObserver //
03043 static const char sPrincipalPrefix[] = "capability.principal";
03044 static const char sPolicyPrefix[] = "capability.policy.";
03045 
03046 NS_IMETHODIMP
03047 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
03048                                  const PRUnichar* aMessage)
03049 {
03050     nsresult rv = NS_OK;
03051     NS_ConvertUCS2toUTF8 messageStr(aMessage);
03052     const char *message = messageStr.get();
03053 
03054     static const char jsPrefix[] = "javascript.";
03055     if((PL_strncmp(message, jsPrefix, sizeof(jsPrefix)-1) == 0)
03056 #ifdef XPC_IDISPATCH_SUPPORT
03057         || (PL_strcmp(message, sXPCDefaultGrantAllName) == 0)
03058 #endif
03059         )
03060         JSEnabledPrefChanged(mSecurityPref);
03061     if(PL_strncmp(message, sPolicyPrefix, sizeof(sPolicyPrefix)-1) == 0)
03062         mPolicyPrefsChanged = PR_TRUE; // This will force re-initialization of the pref table
03063     else if((PL_strncmp(message, sPrincipalPrefix, sizeof(sPrincipalPrefix)-1) == 0) &&
03064             !mIsWritingPrefs)
03065     {
03066         static const char id[] = "id";
03067         char* lastDot = PL_strrchr(message, '.');
03068         //-- This check makes sure the string copy below doesn't overwrite its bounds
03069         if(PL_strlen(lastDot) >= sizeof(id))
03070         {
03071             PL_strcpy(lastDot + 1, id);
03072             const char** idPrefArray = (const char**)&message;
03073             rv = InitPrincipals(1, idPrefArray, mSecurityPref);
03074         }
03075     }
03076     return rv;
03077 }
03078 
03080 // Constructor, Destructor, Initialization //
03082 nsScriptSecurityManager::nsScriptSecurityManager(void)
03083     : mOriginToPolicyMap(nsnull),
03084       mDefaultPolicy(nsnull),
03085       mCapabilities(nsnull),
03086       mIsJavaScriptEnabled(PR_FALSE),
03087       mIsMailJavaScriptEnabled(PR_FALSE),
03088       mIsWritingPrefs(PR_FALSE),
03089       mPolicyPrefsChanged(PR_TRUE)
03090 #ifdef XPC_IDISPATCH_SUPPORT
03091       ,mXPCDefaultGrantAll(PR_FALSE)
03092 #endif
03093 {
03094     NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
03095     mPrincipals.Init(31);
03096 }
03097 
03098 
03099 nsresult nsScriptSecurityManager::Init()
03100 {
03101     JSContext* cx = GetSafeJSContext();
03102     if (!cx) return NS_ERROR_FAILURE;   // this can happen of xpt loading fails
03103     
03104     ::JS_BeginRequest(cx);
03105     if (sEnabledID == JSVAL_VOID)
03106         sEnabledID = STRING_TO_JSVAL(::JS_InternString(cx, "enabled"));
03107     ::JS_EndRequest(cx);
03108 
03109     nsresult rv = InitPrefs();
03110     NS_ENSURE_SUCCESS(rv, rv);
03111 
03112     rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
03113     NS_ENSURE_SUCCESS(rv, rv);
03114 
03115     rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
03116     NS_ENSURE_SUCCESS(rv, rv);
03117 
03118     nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
03119     NS_ENSURE_SUCCESS(rv, rv);
03120 
03121     rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
03122     NS_ENSURE_SUCCESS(rv, rv);
03123 
03124     //-- Register security check callback in the JS engine
03125     //   Currently this is used to control access to function.caller
03126     nsCOMPtr<nsIJSRuntimeService> runtimeService =
03127         do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv);
03128     NS_ENSURE_SUCCESS(rv, rv);
03129 
03130     rv = runtimeService->GetRuntime(&sRuntime);
03131     NS_ENSURE_SUCCESS(rv, rv);
03132 
03133 #ifdef DEBUG
03134     JSCheckAccessOp oldCallback =
03135 #endif
03136         JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);
03137 
03138     // For now, assert that no callback was set previously
03139     NS_ASSERTION(!oldCallback, "Someone already set a JS CheckObjectAccess callback");
03140     return NS_OK;
03141 }
03142 
03143 static nsScriptSecurityManager *gScriptSecMan = nsnull;
03144 
03145 jsval nsScriptSecurityManager::sEnabledID   = JSVAL_VOID;
03146 
03147 nsScriptSecurityManager::~nsScriptSecurityManager(void)
03148 {
03149     delete mOriginToPolicyMap;
03150     if(mDefaultPolicy)
03151         mDefaultPolicy->Drop();
03152     delete mCapabilities;
03153     gScriptSecMan = nsnull;
03154 }
03155 
03156 void
03157 nsScriptSecurityManager::Shutdown()
03158 {
03159     if (sRuntime) {
03160 #ifdef DEBUG
03161         JSCheckAccessOp oldCallback =
03162 #endif
03163             JS_SetCheckObjectAccessCallback(sRuntime, nsnull);
03164         NS_ASSERTION(oldCallback == CheckObjectAccess, "Oops, we just clobbered someone else, oh well.");
03165         sRuntime = nsnull;
03166     }
03167     sEnabledID = JSVAL_VOID;
03168 
03169     NS_IF_RELEASE(sIOService);
03170     NS_IF_RELEASE(sXPConnect);
03171     NS_IF_RELEASE(sStrBundle);
03172 }
03173 
03174 nsScriptSecurityManager *
03175 nsScriptSecurityManager::GetScriptSecurityManager()
03176 {
03177     if (!gScriptSecMan)
03178     {
03179         nsScriptSecurityManager* ssManager = new nsScriptSecurityManager();
03180         if (!ssManager)
03181             return nsnull;
03182         nsresult rv;
03183         rv = ssManager->Init();
03184         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
03185         if (NS_FAILED(rv)) {
03186             delete ssManager;
03187             return nsnull;
03188         }
03189  
03190         rv = nsJSPrincipals::Startup();
03191         if (NS_FAILED(rv)) {
03192             NS_WARNING("can't initialize JS engine security protocol glue!");
03193             delete ssManager;
03194             return nsnull;
03195         }
03196  
03197         rv = sXPConnect->SetDefaultSecurityManager(ssManager,
03198                                                    nsIXPCSecurityManager::HOOK_ALL);
03199         if (NS_FAILED(rv)) {
03200             NS_WARNING("Failed to install xpconnect security manager!");
03201             delete ssManager;
03202             return nsnull;
03203         }
03204 
03205         gScriptSecMan = ssManager;
03206     }
03207     return gScriptSecMan;
03208 }
03209 
03210 // Currently this nsGenericFactory constructor is used only from FastLoad
03211 // (XPCOM object deserialization) code, when "creating" the system principal
03212 // singleton.
03213 nsSystemPrincipal *
03214 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
03215 {
03216     nsIPrincipal *sysprin = nsnull;
03217     if (gScriptSecMan)
03218         gScriptSecMan->GetSystemPrincipal(&sysprin);
03219     return NS_STATIC_CAST(nsSystemPrincipal*, sysprin);
03220 }
03221 
03222 nsresult
03223 nsScriptSecurityManager::InitPolicies()
03224 {
03225     // Clear any policies cached on XPConnect wrappers
03226     NS_ENSURE_STATE(sXPConnect);
03227     nsresult rv = sXPConnect->ClearAllWrappedNativeSecurityPolicies();
03228     if (NS_FAILED(rv)) return rv;
03229 
03230     //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
03231     //-- whose dtor decrements refcount of stored DomainPolicy object
03232     delete mOriginToPolicyMap;
03233     
03234     //-- Marks all the survivor DomainPolicy objects (those cached
03235     //-- by nsPrincipal objects) as invalid: they will be released
03236     //-- on first nsPrincipal::GetSecurityPolicy() attempt.
03237     DomainPolicy::InvalidateAll();
03238     
03239     //-- Release old default policy
03240     if(mDefaultPolicy) {
03241         mDefaultPolicy->Drop();
03242         mDefaultPolicy = nsnull;
03243     }
03244     
03245     //-- Initialize a new mOriginToPolicyMap
03246     mOriginToPolicyMap =
03247       new nsObjectHashtable(nsnull, nsnull, DeleteDomainEntry, nsnull);
03248     if (!mOriginToPolicyMap)
03249         return NS_ERROR_OUT_OF_MEMORY;
03250 
03251     //-- Create, refcount and initialize a new default policy 
03252     mDefaultPolicy = new DomainPolicy();
03253     if (!mDefaultPolicy)
03254         return NS_ERROR_OUT_OF_MEMORY;
03255 
03256     mDefaultPolicy->Hold();
03257     if (!mDefaultPolicy->Init())
03258         return NS_ERROR_UNEXPECTED;
03259 
03260     //-- Initialize the table of security levels
03261     if (!mCapabilities)
03262     {
03263         mCapabilities = 
03264           new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
03265         if (!mCapabilities)
03266             return NS_ERROR_OUT_OF_MEMORY;
03267     }
03268 
03269     // Get a JS context - we need it to create internalized strings later.
03270     JSContext* cx = GetSafeJSContext();
03271     NS_ASSERTION(cx, "failed to get JS context");
03272     rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
03273     NS_ENSURE_SUCCESS(rv, rv);
03274 
03275     nsXPIDLCString policyNames;
03276     rv = mSecurityPref->SecurityGetCharPref("capability.policy.policynames",
03277                                             getter_Copies(policyNames));
03278 
03279     nsXPIDLCString defaultPolicyNames;
03280     rv = mSecurityPref->SecurityGetCharPref("capability.policy.default_policynames",
03281                                             getter_Copies(defaultPolicyNames));
03282     policyNames += NS_LITERAL_CSTRING(" ") + defaultPolicyNames;
03283 
03284     //-- Initialize domain policies
03285     char* policyCurrent = policyNames.BeginWriting();
03286     PRBool morePolicies = PR_TRUE;
03287     while (morePolicies)
03288     {
03289         while(*policyCurrent == ' ' || *policyCurrent == ',')
03290             policyCurrent++;
03291         if (*policyCurrent == '\0')
03292             break;
03293         char* nameBegin = policyCurrent;
03294 
03295         while(*policyCurrent != '\0' && *policyCurrent != ' ' && *policyCurrent != ',')
03296             policyCurrent++;
03297 
03298         morePolicies = (*policyCurrent != '\0');
03299         *policyCurrent = '\0';
03300         policyCurrent++;
03301 
03302         nsCAutoString sitesPrefName(
03303             NS_LITERAL_CSTRING(sPolicyPrefix) +
03304                                 nsDependentCString(nameBegin) +
03305                                 NS_LITERAL_CSTRING(".sites"));
03306         nsXPIDLCString domainList;
03307         rv = mSecurityPref->SecurityGetCharPref(sitesPrefName.get(),
03308                                                 getter_Copies(domainList));
03309         if (NS_FAILED(rv))
03310             continue;
03311 
03312         DomainPolicy* domainPolicy = new DomainPolicy();
03313         if (!domainPolicy)
03314             return NS_ERROR_OUT_OF_MEMORY;
03315 
03316         if (!domainPolicy->Init())
03317         {
03318             delete domainPolicy;
03319             return NS_ERROR_UNEXPECTED;
03320         }
03321         domainPolicy->Hold();
03322         //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
03323         char* domainStart = domainList.BeginWriting();
03324         char* domainCurrent = domainStart;
03325         char* lastDot = nsnull;
03326         char* nextToLastDot = nsnull;
03327         PRBool moreDomains = PR_TRUE;
03328         while (moreDomains)
03329         {
03330             if (*domainCurrent == ' ' || *domainCurrent == '\0')
03331             {
03332                 moreDomains = (*domainCurrent != '\0');
03333                 *domainCurrent = '\0';
03334                 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : domainStart);
03335                 DomainEntry *newEntry = new DomainEntry(domainStart, domainPolicy);
03336                 if (!newEntry)
03337                 {
03338                     domainPolicy->Drop();
03339                     return NS_ERROR_OUT_OF_MEMORY;
03340                 }
03341 #ifdef DEBUG
03342                 newEntry->mPolicyName_DEBUG = nameBegin;
03343 #endif
03344                 DomainEntry *existingEntry = (DomainEntry *)
03345                     mOriginToPolicyMap->Get(&key);
03346                 if (!existingEntry)
03347                     mOriginToPolicyMap->Put(&key, newEntry);
03348                 else
03349                 {
03350                     if (existingEntry->Matches(domainStart))
03351                     {
03352                         newEntry->mNext = existingEntry;
03353                         mOriginToPolicyMap->Put(&key, newEntry);
03354                     }
03355                     else
03356                     {
03357                         while (existingEntry->mNext)
03358                         {
03359                             if (existingEntry->mNext->Matches(domainStart))
03360                             {
03361                                 newEntry->mNext = existingEntry->mNext;
03362                                 existingEntry->mNext = newEntry;
03363                                 break;
03364                             }
03365                             existingEntry = existingEntry->mNext;
03366                         }
03367                         if (!existingEntry->mNext)
03368                             existingEntry->mNext = newEntry;
03369                     }
03370                 }
03371                 domainStart = domainCurrent + 1;
03372                 lastDot = nextToLastDot = nsnull;
03373             }
03374             else if (*domainCurrent == '.')
03375             {
03376                 nextToLastDot = lastDot;
03377                 lastDot = domainCurrent;
03378             }
03379             domainCurrent++;
03380         }
03381 
03382         rv = InitDomainPolicy(cx, nameBegin, domainPolicy);
03383         domainPolicy->Drop();
03384         if (NS_FAILED(rv))
03385             return rv;
03386     }
03387 
03388     // Reset the "dirty" flag
03389     mPolicyPrefsChanged = PR_FALSE;
03390 
03391 #ifdef DEBUG_CAPS_HACKER
03392     PrintPolicyDB();
03393 #endif
03394     return NS_OK;
03395 }
03396 
03397 
03398 nsresult
03399 nsScriptSecurityManager::InitDomainPolicy(JSContext* cx,
03400                                           const char* aPolicyName,
03401                                           DomainPolicy* aDomainPolicy)
03402 {
03403     nsresult rv;
03404     nsCAutoString policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix) +
03405                                nsDependentCString(aPolicyName) +
03406                                NS_LITERAL_CSTRING("."));
03407     PRUint32 prefixLength = policyPrefix.Length() - 1; // subtract the '.'
03408 
03409     PRUint32 prefCount;
03410     char** prefNames;
03411     rv = mPrefBranch->GetChildList(policyPrefix.get(),
03412                                    &prefCount, &prefNames);
03413     if (NS_FAILED(rv)) return rv;
03414     if (prefCount == 0)
03415         return NS_OK;
03416 
03417     //-- Populate the policy
03418     PRUint32 currentPref = 0;
03419     for (; currentPref < prefCount; currentPref++)
03420     {
03421         // Get the class name
03422         const char* start = prefNames[currentPref] + prefixLength + 1;
03423         char* end = PL_strchr(start, '.');
03424         if (!end) // malformed pref, bail on this one
03425             continue;
03426         static const char sitesStr[] = "sites";
03427 
03428         // We dealt with "sites" in InitPolicies(), so no need to do
03429         // that again...
03430         if (PL_strncmp(start, sitesStr, sizeof(sitesStr)-1) == 0)
03431             continue;
03432 
03433         // Get the pref value
03434         nsXPIDLCString prefValue;
03435         rv = mSecurityPref->SecurityGetCharPref(prefNames[currentPref],
03436                                                 getter_Copies(prefValue));
03437         if (NS_FAILED(rv) || !prefValue)
03438             continue;
03439 
03440         SecurityLevel secLevel;
03441         if (PL_strcasecmp(prefValue, "noAccess") == 0)
03442             secLevel.level = SCRIPT_SECURITY_NO_ACCESS;
03443         else if (PL_strcasecmp(prefValue, "allAccess") == 0)
03444             secLevel.level = SCRIPT_SECURITY_ALL_ACCESS;
03445         else if (PL_strcasecmp(prefValue, "sameOrigin") == 0)
03446             secLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
03447         else 
03448         {  //-- pref value is the name of a capability
03449             nsCStringKey secLevelKey(prefValue);
03450             secLevel.capability =
03451                 NS_REINTERPRET_CAST(char*, mCapabilities->Get(&secLevelKey));
03452             if (!secLevel.capability)
03453             {
03454                 secLevel.capability = nsCRT::strdup(prefValue);
03455                 if (!secLevel.capability)
03456                     break;
03457                 mCapabilities->Put(&secLevelKey, 
03458                                    secLevel.capability);
03459             }
03460         }
03461 
03462         *end = '\0';
03463         // Find or store this class in the classes table
03464         ClassPolicy* cpolicy = 
03465           NS_STATIC_CAST(ClassPolicy*,
03466                          PL_DHashTableOperate(aDomainPolicy, start,
03467                                               PL_DHASH_ADD));
03468         if (!cpolicy)
03469             break;
03470 
03471         // If this is the wildcard class (class '*'), save it in mWildcardPolicy
03472         // (we leave it stored in the hashtable too to take care of the cleanup)
03473         if ((*start == '*') && (end == start + 1)) {
03474             aDomainPolicy->mWildcardPolicy = cpolicy;
03475 
03476             // Make sure that cpolicy knows about aDomainPolicy so it can reset
03477             // the mWildcardPolicy pointer as needed if it gets moved in the
03478             // hashtable.
03479             cpolicy->mDomainWeAreWildcardFor = aDomainPolicy;
03480         }
03481 
03482         // Get the property name
03483         start = end + 1;
03484         end = PL_strchr(start, '.');
03485         if (end)
03486             *end = '\0';
03487 
03488         JSString* propertyKey = ::JS_InternString(cx, start);
03489         if (!propertyKey)
03490             return NS_ERROR_OUT_OF_MEMORY;
03491 
03492         // Store this property in the class policy
03493         const void* ppkey =
03494           NS_REINTERPRET_CAST(const void*, STRING_TO_JSVAL(propertyKey));
03495         PropertyPolicy* ppolicy = 
03496           NS_STATIC_CAST(PropertyPolicy*,
03497                          PL_DHashTableOperate(cpolicy->mPolicy, ppkey,
03498                                               PL_DHASH_ADD));
03499         if (!ppolicy)
03500             break;
03501 
03502         if (end) // The pref specifies an access mode
03503         {
03504             start = end + 1;
03505             if (PL_strcasecmp(start, "set") == 0)
03506                 ppolicy->mSet = secLevel;
03507             else
03508                 ppolicy->mGet = secLevel;
03509         }
03510         else
03511         {
03512             if (ppolicy->mGet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
03513                 ppolicy->mGet = secLevel;
03514             if (ppolicy->mSet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
03515                 ppolicy->mSet = secLevel;
03516         }
03517     }
03518 
03519     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
03520     if (currentPref < prefCount) // Loop exited early because of out-of-memory error
03521         return NS_ERROR_OUT_OF_MEMORY;
03522     return NS_OK;
03523 }
03524 
03525 
03526 // XXXbz We should really just get a prefbranch to handle this...
03527 nsresult
03528 nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase,
03529                                                nsCString& grantedPref,
03530                                                nsCString& deniedPref,
03531                                                nsCString& subjectNamePref)
03532 {
03533     char* lastDot = PL_strrchr(prefBase, '.');
03534     if (!lastDot) return NS_ERROR_FAILURE;
03535     PRInt32 prefLen = lastDot - prefBase + 1;
03536 
03537     grantedPref.Assign(prefBase, prefLen);
03538     deniedPref.Assign(prefBase, prefLen);
03539     subjectNamePref.Assign(prefBase, prefLen);
03540 
03541 #define GRANTED "granted"
03542 #define DENIED "denied"
03543 #define SUBJECTNAME "subjectName"
03544 
03545     grantedPref.AppendLiteral(GRANTED);
03546     if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) {
03547         return NS_ERROR_OUT_OF_MEMORY;
03548     }
03549 
03550     deniedPref.AppendLiteral(DENIED);
03551     if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) {
03552         return NS_ERROR_OUT_OF_MEMORY;
03553     }
03554 
03555     subjectNamePref.AppendLiteral(SUBJECTNAME);
03556     if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) {
03557         return NS_ERROR_OUT_OF_MEMORY;
03558     }
03559 
03560 #undef SUBJECTNAME
03561 #undef DENIED
03562 #undef GRANTED
03563     
03564     return NS_OK;
03565 }
03566 
03567 nsresult
03568 nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefNames,
03569                                         nsISecurityPref* aSecurityPref)
03570 {
03571     /* This is the principal preference syntax:
03572      * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
03573      * For example:
03574      * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
03575      * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
03576      * user_pref("capability.principal.certificate.p1.denied","Capability3");
03577      */
03578 
03579     /* codebaseTrusted means a codebase principal that can enable capabilities even if
03580      * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
03581      * URLs such as HTTPS URLs.
03582      */
03583 
03584     static const char idSuffix[] = ".id";
03585     for (PRUint32 c = 0; c < aPrefCount; c++)
03586     {
03587         PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) - 
03588             (NS_ARRAY_LENGTH(idSuffix) - 1);
03589         if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0)
03590             continue;
03591 
03592         nsXPIDLCString id;
03593         if (NS_FAILED(mSecurityPref->SecurityGetCharPref(aPrefNames[c], getter_Copies(id))))
03594             return NS_ERROR_FAILURE;
03595 
03596         nsCAutoString grantedPrefName;
03597         nsCAutoString deniedPrefName;
03598         nsCAutoString subjectNamePrefName;
03599         nsresult rv = GetPrincipalPrefNames(aPrefNames[c],
03600                                             grantedPrefName,
03601                                             deniedPrefName,
03602                                             subjectNamePrefName);
03603         if (rv == NS_ERROR_OUT_OF_MEMORY)
03604             return rv;
03605         if (NS_FAILED(rv))
03606             continue;
03607 
03608         nsXPIDLCString grantedList;
03609         mSecurityPref->SecurityGetCharPref(grantedPrefName.get(),
03610                                            getter_Copies(grantedList));
03611         nsXPIDLCString deniedList;
03612         mSecurityPref->SecurityGetCharPref(deniedPrefName.get(),
03613                                            getter_Copies(deniedList));
03614         nsXPIDLCString subjectName;
03615         mSecurityPref->SecurityGetCharPref(subjectNamePrefName.get(),
03616                                            getter_Copies(subjectName));
03617 
03618         //-- Delete prefs if their value is the empty string
03619         if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty()))
03620         {
03621             mSecurityPref->SecurityClearUserPref(aPrefNames[c]);
03622             mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
03623             mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
03624             mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
03625             continue;
03626         }
03627 
03628         //-- Create a principal based on the prefs
03629         static const char certificateName[] = "capability.principal.certificate";
03630         static const char codebaseName[] = "capability.principal.codebase";
03631         static const char codebaseTrustedName[] = "capability.principal.codebaseTrusted";
03632 
03633         PRBool isCert = PR_FALSE;
03634         PRBool isTrusted = PR_FALSE;
03635         
03636         if (PL_strncmp(aPrefNames[c], certificateName,
03637                        sizeof(certificateName) - 1) == 0)
03638         {
03639             isCert = PR_TRUE;
03640         }
03641         else if (PL_strncmp(aPrefNames[c], codebaseName,
03642                             sizeof(codebaseName) - 1) == 0)
03643         {
03644             isTrusted = (PL_strncmp(aPrefNames[c], codebaseTrustedName,
03645                                     sizeof(codebaseTrustedName) - 1) == 0);
03646         }
03647         else
03648         {
03649           NS_ERROR("Not a codebase or a certificate?!");
03650         }
03651 
03652         nsRefPtr<nsPrincipal> newPrincipal = new nsPrincipal();
03653         if (!newPrincipal)
03654             return NS_ERROR_OUT_OF_MEMORY;
03655 
03656         rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
03657                                               EmptyCString(),
03658                                               grantedList, deniedList, nsnull, 
03659                                               isCert, isTrusted);
03660         if (NS_SUCCEEDED(rv))
03661             mPrincipals.Put(newPrincipal, newPrincipal);
03662     }
03663     return NS_OK;
03664 }
03665 
03666 const char nsScriptSecurityManager::sJSEnabledPrefName[] =
03667     "javascript.enabled";
03668 const char nsScriptSecurityManager::sJSMailEnabledPrefName[] =
03669     "javascript.allow.mailnews";
03670 #ifdef XPC_IDISPATCH_SUPPORT
03671 const char nsScriptSecurityManager::sXPCDefaultGrantAllName[] =
03672     "security.classID.allowByDefault";
03673 #endif
03674 
03675 inline void
03676 nsScriptSecurityManager::JSEnabledPrefChanged(nsISecurityPref* aSecurityPref)
03677 {
03678     PRBool temp;
03679     nsresult rv = mSecurityPref->SecurityGetBoolPref(sJSEnabledPrefName, &temp);
03680     // JavaScript defaults to enabled in failure cases.
03681     mIsJavaScriptEnabled = NS_FAILED(rv) || temp;
03682 
03683     rv = mSecurityPref->SecurityGetBoolPref(sJSMailEnabledPrefName, &temp);
03684     // JavaScript in Mail defaults to enabled in failure cases.
03685     mIsMailJavaScriptEnabled = NS_FAILED(rv) || temp;
03686 
03687 #ifdef XPC_IDISPATCH_SUPPORT
03688     rv = mSecurityPref->SecurityGetBoolPref(sXPCDefaultGrantAllName, &temp);
03689     // Granting XPC Priveleges defaults to disabled in failure cases.
03690     mXPCDefaultGrantAll = NS_SUCCEEDED(rv) && temp;
03691 #endif
03692 }
03693 
03694 nsresult
03695 nsScriptSecurityManager::InitPrefs()
03696 {
03697     nsresult rv;
03698     nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
03699     NS_ENSURE_SUCCESS(rv, rv);
03700     rv = prefService->GetBranch(nsnull, getter_AddRefs(mPrefBranch));
03701     NS_ENSURE_SUCCESS(rv, rv);
03702     nsCOMPtr<nsIPrefBranch2> prefBranchInternal(do_QueryInterface(mPrefBranch, &rv));
03703     NS_ENSURE_SUCCESS(rv, rv);
03704     mSecurityPref = do_QueryInterface(mPrefBranch, &rv);
03705     NS_ENSURE_SUCCESS(rv, rv);
03706 
03707     // Set the initial value of the "javascript.enabled" prefs
03708     JSEnabledPrefChanged(mSecurityPref);
03709     // set observer callbacks in case the value of the prefs change
03710     prefBranchInternal->AddObserver(sJSEnabledPrefName, this, PR_FALSE);
03711     prefBranchInternal->AddObserver(sJSMailEnabledPrefName, this, PR_FALSE);
03712 #ifdef XPC_IDISPATCH_SUPPORT
03713     prefBranchInternal->AddObserver(sXPCDefaultGrantAllName, this, PR_FALSE);
03714 #endif
03715     PRUint32 prefCount;
03716     char** prefNames;
03717 
03718     // Set a callback for policy pref changes
03719     prefBranchInternal->AddObserver(sPolicyPrefix, this, PR_FALSE);
03720 
03721     //-- Initialize the principals database from prefs
03722     rv = mPrefBranch->GetChildList(sPrincipalPrefix, &prefCount, &prefNames);
03723     if (NS_SUCCEEDED(rv) && prefCount > 0)
03724     {
03725         rv = InitPrincipals(prefCount, (const char**)prefNames, mSecurityPref);
03726         NS_ENSURE_SUCCESS(rv, rv);
03727         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
03728     }
03729     //-- Set a callback for principal changes
03730     prefBranchInternal->AddObserver(sPrincipalPrefix, this, PR_FALSE);
03731 
03732     return NS_OK;
03733 }
03734 
03736 // The following code prints the contents of the policy DB to the console.
03737 #ifdef DEBUG_CAPS_HACKER
03738 
03739 //typedef PLDHashOperator
03740 //(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
03741 //                                      PRUint32 number, void *arg);
03742 PR_STATIC_CALLBACK(PLDHashOperator)
03743 PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
03744                     PRUint32 number, void *arg)
03745 {
03746     PropertyPolicy* pp = (PropertyPolicy*)entry;
03747     nsCAutoString prop("        ");
03748     JSContext* cx = (JSContext*)arg;
03749     prop.AppendInt((PRUint32)pp->key);
03750     prop += ' ';
03751     prop.AppendWithConversion((PRUnichar*)JSValIDToString(cx, pp->key));
03752     prop += ": Get=";
03753     if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet))
03754         prop.AppendInt(pp->mGet.level);
03755     else
03756         prop += pp->mGet.capability;
03757 
03758     prop += " Set=";
03759     if (SECURITY_ACCESS_LEVEL_FLAG(pp->mSet))
03760         prop.AppendInt(pp->mSet.level);
03761     else
03762         prop += pp->mSet.capability;
03763         
03764     printf("%s.\n", prop.get());
03765     return PL_DHASH_NEXT;
03766 }
03767 
03768 PR_STATIC_CALLBACK(PLDHashOperator)
03769 PrintClassPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
03770                  PRUint32 number, void *arg)
03771 {
03772     ClassPolicy* cp = (ClassPolicy*)entry;
03773     printf("    %s\n", cp->key);
03774 
03775     PL_DHashTableEnumerate(cp->mPolicy, PrintPropertyPolicy, arg);
03776     return PL_DHASH_NEXT;
03777 }
03778 
03779 // typedef PRBool
03780 // (*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
03781 PR_STATIC_CALLBACK(PRBool)
03782 PrintDomainPolicy(nsHashKey *aKey, void *aData, void* aClosure)
03783 {
03784     DomainEntry* de = (DomainEntry*)aData;
03785     printf("----------------------------\n");
03786     printf("Domain: %s Policy Name: %s.\n", de->mOrigin.get(),
03787            de->mPolicyName_DEBUG.get());
03788     PL_DHashTableEnumerate(de->mDomainPolicy, PrintClassPolicy, aClosure);
03789     return PR_TRUE;
03790 }
03791 
03792 PR_STATIC_CALLBACK(PRBool)
03793 PrintCapability(nsHashKey *aKey, void *aData, void* aClosure)
03794 {
03795     char* cap = (char*)aData;
03796     printf("    %s.\n", cap);
03797     return PR_TRUE;
03798 }
03799 
03800 void
03801 nsScriptSecurityManager::PrintPolicyDB()
03802 {
03803     printf("############## Security Policies ###############\n");
03804     if(mOriginToPolicyMap)
03805     {
03806         JSContext* cx = GetCurrentJSContext();
03807         printf("----------------------------\n");
03808         printf("Domain: Default.\n");
03809         PL_DHashTableEnumerate(mDefaultPolicy, PrintClassPolicy, (void*)cx);
03810         mOriginToPolicyMap->Enumerate(PrintDomainPolicy, (void*)cx);
03811     }
03812     printf("############ End Security Policies #############\n\n");
03813     printf("############## Capabilities ###############\n");
03814     mCapabilities->Enumerate(PrintCapability);
03815     printf("############## End Capabilities ###############\n");
03816 }
03817 #endif
03818