Follow up to bug 451392, add hgToolsTag to older configs
[mozilla-1.9.git] / caps / src / nsScriptSecurityManager.cpp
blob09a83136405ff2a8eb50788640ab4926706ae008
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Norris Boyd
24 * Mitch Stoltz
25 * Steve Morse
26 * Christopher A. Aillon
27 * Giorgio Maone
28 * Daniel Veditz
30 * Alternatively, the contents of this file may be used under the terms of
31 * either of the GNU General Public License Version 2 or later (the "GPL"),
32 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
43 #include "nsScriptSecurityManager.h"
44 #include "nsIServiceManager.h"
45 #include "nsIScriptObjectPrincipal.h"
46 #include "nsIScriptContext.h"
47 #include "nsIURL.h"
48 #include "nsINestedURI.h"
49 #include "nspr.h"
50 #include "nsJSPrincipals.h"
51 #include "nsSystemPrincipal.h"
52 #include "nsPrincipal.h"
53 #include "nsNullPrincipal.h"
54 #include "nsXPIDLString.h"
55 #include "nsCRT.h"
56 #include "nsCRTGlue.h"
57 #include "nsIJSContextStack.h"
58 #include "nsDOMError.h"
59 #include "nsDOMCID.h"
60 #include "jsdbgapi.h"
61 #include "jsarena.h"
62 #include "jsfun.h"
63 #include "jsobj.h"
64 #include "nsIXPConnect.h"
65 #include "nsIXPCSecurityManager.h"
66 #include "nsTextFormatter.h"
67 #include "nsIStringBundle.h"
68 #include "nsNetUtil.h"
69 #include "nsIProperties.h"
70 #include "nsDirectoryServiceDefs.h"
71 #include "nsIFile.h"
72 #include "nsIFileURL.h"
73 #include "nsIZipReader.h"
74 #include "nsIJAR.h"
75 #include "nsIPluginInstance.h"
76 #include "nsIXPConnect.h"
77 #include "nsIScriptGlobalObject.h"
78 #include "nsPIDOMWindow.h"
79 #include "nsIDocShell.h"
80 #include "nsIDocShellTreeItem.h"
81 #include "nsIPrompt.h"
82 #include "nsIWindowWatcher.h"
83 #include "nsIConsoleService.h"
84 #include "nsISecurityCheckedComponent.h"
85 #include "nsIPrefBranch2.h"
86 #include "nsIJSRuntimeService.h"
87 #include "nsIObserverService.h"
88 #include "nsIContent.h"
89 #include "nsAutoPtr.h"
90 #include "nsDOMJSUtils.h"
91 #include "nsAboutProtocolUtils.h"
92 #include "nsIClassInfo.h"
93 #include "nsIURIFixup.h"
94 #include "nsCDefaultURIFixup.h"
95 #include "nsIChromeRegistry.h"
97 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
99 nsIIOService *nsScriptSecurityManager::sIOService = nsnull;
100 nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
101 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
102 JSRuntime *nsScriptSecurityManager::sRuntime = 0;
103 PRBool nsScriptSecurityManager::sStrictFileOriginPolicy = PR_TRUE;
105 // Info we need about the JSClasses used by XPConnects wrapped
106 // natives, to avoid having to QI to nsIXPConnectWrappedNative all the
107 // time when doing security checks.
108 static const JSClass *sXPCWrappedNativeJSClass;
109 static JSGetObjectOps sXPCWrappedNativeGetObjOps1;
110 static JSGetObjectOps sXPCWrappedNativeGetObjOps2;
113 ///////////////////////////
114 // Convenience Functions //
115 ///////////////////////////
116 // Result of this function should not be freed.
117 static inline const PRUnichar *
118 JSValIDToString(JSContext *cx, const jsval idval)
120 JSAutoRequest ar(cx);
121 JSString *str = JS_ValueToString(cx, idval);
122 if(!str)
123 return nsnull;
124 return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
127 // Inline copy of JS_GetPrivate() for better inlining and optimization
128 // possibilities. Also doesn't take a cx argument as it's not
129 // needed. We access the private data only on objects whose private
130 // data is not expected to change during the lifetime of the object,
131 // so thus we won't worry about locking and holding on to slot values
132 // etc while referencing private data.
133 inline void *
134 caps_GetJSPrivate(JSObject *obj)
136 jsval v;
138 JS_ASSERT(STOBJ_GET_CLASS(obj)->flags & JSCLASS_HAS_PRIVATE);
139 v = obj->fslots[JSSLOT_PRIVATE];
140 if (!JSVAL_IS_INT(v))
141 return NULL;
142 return JSVAL_TO_PRIVATE(v);
145 static nsIScriptContext *
146 GetScriptContext(JSContext *cx)
148 return GetScriptContextFromJSContext(cx);
151 inline void SetPendingException(JSContext *cx, const char *aMsg)
153 JSAutoRequest ar(cx);
154 JS_ReportError(cx, "%s", aMsg);
157 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
159 JSAutoRequest ar(cx);
160 JS_ReportError(cx, "%hs", aMsg);
163 // DomainPolicy members
164 #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
165 PRUint32 DomainPolicy::sObjects=0;
166 void DomainPolicy::_printPopulationInfo()
168 printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
169 sGeneration, sObjects);
171 #endif
172 PRUint32 DomainPolicy::sGeneration = 0;
174 // Helper class to get stuff from the ClassInfo and not waste extra time with
175 // virtual method calls for things it has already gotten
176 class ClassInfoData
178 public:
179 ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
180 : mClassInfo(aClassInfo),
181 mName(const_cast<char *>(aName)),
182 mDidGetFlags(PR_FALSE),
183 mMustFreeName(PR_FALSE)
187 ~ClassInfoData()
189 if (mMustFreeName)
190 nsMemory::Free(mName);
193 PRUint32 GetFlags()
195 if (!mDidGetFlags) {
196 if (mClassInfo) {
197 nsresult rv = mClassInfo->GetFlags(&mFlags);
198 if (NS_FAILED(rv)) {
199 mFlags = 0;
201 } else {
202 mFlags = 0;
205 mDidGetFlags = PR_TRUE;
208 return mFlags;
211 PRBool IsDOMClass()
213 return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
216 PRBool IsContentNode()
218 return !!(GetFlags() & nsIClassInfo::CONTENT_NODE);
221 const char* GetName()
223 if (!mName) {
224 if (mClassInfo) {
225 mClassInfo->GetClassDescription(&mName);
228 if (mName) {
229 mMustFreeName = PR_TRUE;
230 } else {
231 mName = const_cast<char *>("UnnamedClass");
235 return mName;
238 private:
239 nsIClassInfo *mClassInfo; // WEAK
240 PRUint32 mFlags;
241 char *mName;
242 PRPackedBool mDidGetFlags;
243 PRPackedBool mMustFreeName;
246 JSContext *
247 nsScriptSecurityManager::GetCurrentJSContext()
249 // Get JSContext from stack.
250 if (!mJSContextStack)
252 mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
253 if (!mJSContextStack)
254 return nsnull;
256 JSContext *cx;
257 if (NS_FAILED(mJSContextStack->Peek(&cx)))
258 return nsnull;
259 return cx;
262 JSContext *
263 nsScriptSecurityManager::GetSafeJSContext()
265 // Get JSContext from stack.
266 if (!mJSContextStack) {
267 mJSContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
268 if (!mJSContextStack)
269 return nsnull;
272 JSContext *cx;
273 if (NS_FAILED(mJSContextStack->GetSafeJSContext(&cx)))
274 return nsnull;
275 return cx;
278 /* static */
279 PRBool
280 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
281 nsIURI* aTargetURI)
283 // Note that this is not an Equals() test on purpose -- for URIs that don't
284 // support host/port, we want equality to basically be object identity, for
285 // security purposes. Otherwise, for example, two javascript: URIs that
286 // are otherwise unrelated could end up "same origin", which would be
287 // unfortunate.
288 if (aSourceURI && aSourceURI == aTargetURI)
290 return PR_TRUE;
293 if (!aTargetURI || !aSourceURI)
295 return PR_FALSE;
298 // If either URI is a nested URI, get the base URI
299 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI);
300 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
302 if (!sourceBaseURI || !targetBaseURI)
303 return PR_FALSE;
305 // Compare schemes
306 nsCAutoString targetScheme;
307 PRBool sameScheme = PR_FALSE;
308 if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) ||
309 NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) ||
310 !sameScheme)
312 // Not same-origin if schemes differ
313 return PR_FALSE;
316 // special handling for file: URIs
317 if (targetScheme.EqualsLiteral("file"))
319 // in traditional unsafe behavior all files are the same origin
320 if (!sStrictFileOriginPolicy)
321 return PR_TRUE;
323 nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI));
324 nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI));
326 if (!sourceFileURL || !targetFileURL)
327 return PR_FALSE;
329 nsCOMPtr<nsIFile> sourceFile, targetFile;
331 sourceFileURL->GetFile(getter_AddRefs(sourceFile));
332 targetFileURL->GetFile(getter_AddRefs(targetFile));
334 if (!sourceFile || !targetFile)
335 return PR_FALSE;
337 // Otherwise they had better match
338 PRBool filesAreEqual = PR_FALSE;
339 nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual);
340 return NS_SUCCEEDED(rv) && filesAreEqual;
343 // Special handling for mailnews schemes
344 if (targetScheme.EqualsLiteral("imap") ||
345 targetScheme.EqualsLiteral("mailbox") ||
346 targetScheme.EqualsLiteral("news"))
348 // Each message is a distinct trust domain; use the
349 // whole spec for comparison
350 nsCAutoString targetSpec;
351 nsCAutoString sourceSpec;
352 return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) &&
353 NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) &&
354 targetSpec.Equals(sourceSpec) );
357 // Compare hosts
358 nsCAutoString targetHost;
359 nsCAutoString sourceHost;
360 if (NS_FAILED( targetBaseURI->GetHost(targetHost) ) ||
361 NS_FAILED( sourceBaseURI->GetHost(sourceHost) ) ||
362 !targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator()))
364 // Not same-origin if hosts differ
365 return PR_FALSE;
368 // Compare ports
369 PRInt32 targetPort;
370 nsresult rv = targetBaseURI->GetPort(&targetPort);
371 PRInt32 sourcePort;
372 if (NS_SUCCEEDED(rv))
373 rv = sourceBaseURI->GetPort(&sourcePort);
374 PRBool result = NS_SUCCEEDED(rv) && targetPort == sourcePort;
375 // If the port comparison failed, see if either URL has a
376 // port of -1. If so, replace -1 with the default port
377 // for that scheme.
378 if (NS_SUCCEEDED(rv) && !result &&
379 (sourcePort == -1 || targetPort == -1))
381 NS_ENSURE_TRUE(sIOService, PR_FALSE);
383 PRInt32 defaultPort = NS_GetDefaultPort(targetScheme.get());
384 if (defaultPort == -1)
385 return PR_FALSE; // No default port for this scheme
387 if (sourcePort == -1)
388 sourcePort = defaultPort;
389 else if (targetPort == -1)
390 targetPort = defaultPort;
391 result = targetPort == sourcePort;
394 return result;
397 NS_IMETHODIMP
398 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
399 nsIPrincipal** aPrincipal)
401 NS_PRECONDITION(aChannel, "Must have channel!");
402 nsCOMPtr<nsISupports> owner;
403 aChannel->GetOwner(getter_AddRefs(owner));
404 if (owner) {
405 CallQueryInterface(owner, aPrincipal);
406 if (*aPrincipal) {
407 return NS_OK;
411 // OK, get the principal from the URI. Make sure this does the same thing
412 // as nsDocument::Reset and nsXULDocument::StartDocumentLoad.
413 nsCOMPtr<nsIURI> uri;
414 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
415 NS_ENSURE_SUCCESS(rv, rv);
417 return GetCodebasePrincipal(uri, aPrincipal);
420 NS_IMETHODIMP
421 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
422 PRBool* aIsSystem)
424 *aIsSystem = (aPrincipal == mSystemPrincipal);
425 return NS_OK;
428 NS_IMETHODIMP_(nsIPrincipal *)
429 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
431 NS_ASSERTION(cx == GetCurrentJSContext(),
432 "Uh, cx is not the current JS context!");
434 nsresult rv = NS_ERROR_FAILURE;
435 nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
436 if (NS_FAILED(rv))
437 return nsnull;
439 return principal;
442 ////////////////////
443 // Policy Storage //
444 ////////////////////
446 // Table of security levels
447 PR_STATIC_CALLBACK(PRBool)
448 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
450 NS_Free(aData);
451 return PR_TRUE;
454 //-- Per-Domain Policy - applies to one or more protocols or hosts
455 struct DomainEntry
457 DomainEntry(const char* aOrigin,
458 DomainPolicy* aDomainPolicy) : mOrigin(aOrigin),
459 mDomainPolicy(aDomainPolicy),
460 mNext(nsnull)
462 mDomainPolicy->Hold();
465 ~DomainEntry()
467 mDomainPolicy->Drop();
470 PRBool Matches(const char *anOrigin)
472 int len = strlen(anOrigin);
473 int thisLen = mOrigin.Length();
474 if (len < thisLen)
475 return PR_FALSE;
476 if (mOrigin.RFindChar(':', thisLen-1, 1) != -1)
477 //-- Policy applies to all URLs of this scheme, compare scheme only
478 return mOrigin.EqualsIgnoreCase(anOrigin, thisLen);
480 //-- Policy applies to a particular host; compare domains
481 if (!mOrigin.Equals(anOrigin + (len - thisLen)))
482 return PR_FALSE;
483 if (len == thisLen)
484 return PR_TRUE;
485 char charBefore = anOrigin[len-thisLen-1];
486 return (charBefore == '.' || charBefore == ':' || charBefore == '/');
489 nsCString mOrigin;
490 DomainPolicy* mDomainPolicy;
491 DomainEntry* mNext;
492 #if defined(DEBUG) || defined(DEBUG_CAPS_HACKER)
493 nsCString mPolicyName_DEBUG;
494 #endif
497 PR_STATIC_CALLBACK(PRBool)
498 DeleteDomainEntry(nsHashKey *aKey, void *aData, void* closure)
500 DomainEntry *entry = (DomainEntry*) aData;
503 DomainEntry *next = entry->mNext;
504 delete entry;
505 entry = next;
506 } while (entry);
507 return PR_TRUE;
510 /////////////////////////////
511 // nsScriptSecurityManager //
512 /////////////////////////////
514 ////////////////////////////////////
515 // Methods implementing ISupports //
516 ////////////////////////////////////
517 NS_IMPL_ISUPPORTS5(nsScriptSecurityManager,
518 nsIScriptSecurityManager,
519 nsIXPCSecurityManager,
520 nsIPrefSecurityCheck,
521 nsIChannelEventSink,
522 nsIObserver)
524 ///////////////////////////////////////////////////
525 // Methods implementing nsIScriptSecurityManager //
526 ///////////////////////////////////////////////////
528 ///////////////// Security Checks /////////////////
529 JSBool JS_DLL_CALLBACK
530 nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
531 jsval id, JSAccessMode mode,
532 jsval *vp)
534 // Get the security manager
535 nsScriptSecurityManager *ssm =
536 nsScriptSecurityManager::GetScriptSecurityManager();
538 NS_ASSERTION(ssm, "Failed to get security manager service");
539 if (!ssm)
540 return JS_FALSE;
542 // Get the object being accessed. We protect these cases:
543 // 1. The Function.prototype.caller property's value, which might lead
544 // an attacker up a call-stack to a function or another object from
545 // a different trust domain.
546 // 2. A user-defined getter or setter function accessible on another
547 // trust domain's window or document object.
548 // *vp can be a primitive, in that case, we use obj as the target
549 // object.
550 JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
552 // Do the same-origin check -- this sets a JS exception if the check fails.
553 // Pass the parent object's class name, as we have no class-info for it.
554 nsresult rv =
555 ssm->CheckPropertyAccess(cx, target, STOBJ_GET_CLASS(obj)->name, id,
556 (mode & JSACC_WRITE) ?
557 nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
558 nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
560 if (NS_FAILED(rv))
561 return JS_FALSE; // Security check failed (XXX was an error reported?)
563 return JS_TRUE;
566 NS_IMETHODIMP
567 nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
568 JSObject* aJSObject,
569 const char* aClassName,
570 jsval aProperty,
571 PRUint32 aAction)
573 return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
574 nsnull, nsnull, nsnull,
575 aClassName, aProperty, nsnull);
578 NS_IMETHODIMP
579 nsScriptSecurityManager::CheckConnect(JSContext* cx,
580 nsIURI* aTargetURI,
581 const char* aClassName,
582 const char* aPropertyName)
584 // Get a context if necessary
585 if (!cx)
587 cx = GetCurrentJSContext();
588 if (!cx)
589 return NS_OK; // No JS context, so allow the load
592 nsresult rv = CheckLoadURIFromScript(cx, aTargetURI);
593 if (NS_FAILED(rv)) return rv;
595 JSAutoRequest ar(cx);
597 JSString* propertyName = ::JS_InternString(cx, aPropertyName);
598 if (!propertyName)
599 return NS_ERROR_OUT_OF_MEMORY;
601 return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull,
602 cx, nsnull, nsnull, aTargetURI,
603 nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull);
606 NS_IMETHODIMP
607 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
608 nsIURI* aTargetURI)
610 nsresult rv;
612 // Get a context if necessary
613 if (!cx)
615 cx = GetCurrentJSContext();
616 if (!cx)
617 return NS_OK; // No JS context, so allow access
620 // Get a principal from the context
621 nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
622 if (NS_FAILED(rv))
623 return rv;
625 if (!sourcePrincipal)
627 NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
628 return NS_OK;
631 if (sourcePrincipal == mSystemPrincipal)
633 // This is a system (chrome) script, so allow access
634 return NS_OK;
637 // Get the original URI from the source principal.
638 // This has the effect of ignoring any change to document.domain
639 // which must be done to avoid DNS spoofing (bug 154930)
640 nsCOMPtr<nsIURI> sourceURI;
641 sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
642 if (!sourceURI) {
643 sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
644 NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
647 // Compare origins
648 if (!SecurityCompareURIs(sourceURI, aTargetURI))
650 ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
651 return NS_ERROR_DOM_BAD_URI;
653 return NS_OK;
656 NS_IMETHODIMP
657 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
658 nsIURI* aTargetURI,
659 PRBool reportError)
661 if (!SecurityCompareURIs(aSourceURI, aTargetURI))
663 if (reportError) {
664 ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"),
665 aSourceURI, aTargetURI);
667 return NS_ERROR_DOM_BAD_URI;
669 return NS_OK;
672 nsresult
673 nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
674 nsAXPCNativeCallContext* aCallContext,
675 JSContext* cx, JSObject* aJSObject,
676 nsISupports* aObj, nsIURI* aTargetURI,
677 nsIClassInfo* aClassInfo,
678 const char* aClassName, jsval aProperty,
679 void** aCachedClassPolicy)
681 nsresult rv;
682 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
683 if (NS_FAILED(rv))
684 return rv;
686 if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
687 // We have native code or the system principal: just allow access
688 return NS_OK;
690 // Hold the class info data here so we don't have to go back to virtual
691 // methods all the time
692 ClassInfoData classInfoData(aClassInfo, aClassName);
693 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
694 nsCAutoString propertyName;
695 propertyName.AssignWithConversion((PRUnichar*)JSValIDToString(cx, aProperty));
696 printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(),
697 propertyName.get(), aAction);
698 #endif
700 //-- Look up the security policy for this class and subject domain
701 SecurityLevel securityLevel;
702 rv = LookupPolicy(subjectPrincipal, classInfoData, aProperty, aAction,
703 (ClassPolicy**)aCachedClassPolicy, &securityLevel);
704 if (NS_FAILED(rv))
705 return rv;
707 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
709 // No policy found for this property so use the default of last resort.
710 // If we were called from somewhere other than XPConnect
711 // (no XPC call context), assume this is a DOM class. Otherwise,
712 // ask the ClassInfo.
713 if (!aCallContext || classInfoData.IsDOMClass())
714 securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
715 else
716 securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
719 if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
720 // This flag means securityLevel is allAccess, noAccess, or sameOrigin
722 switch (securityLevel.level)
724 case SCRIPT_SECURITY_NO_ACCESS:
725 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
726 printf("noAccess ");
727 #endif
728 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
729 break;
731 case SCRIPT_SECURITY_ALL_ACCESS:
732 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
733 printf("allAccess ");
734 #endif
735 rv = NS_OK;
736 break;
738 case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS:
740 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
741 printf("sameOrigin ");
742 #endif
743 nsCOMPtr<nsIPrincipal> principalHolder;
744 nsIPrincipal *objectPrincipal;
745 if(aJSObject)
747 objectPrincipal = doGetObjectPrincipal(aJSObject);
748 if (!objectPrincipal)
749 rv = NS_ERROR_DOM_SECURITY_ERR;
751 else if(aTargetURI)
753 if (NS_FAILED(GetCodebasePrincipal(
754 aTargetURI, getter_AddRefs(principalHolder))))
755 return NS_ERROR_FAILURE;
757 objectPrincipal = principalHolder;
759 else
761 NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
762 return NS_ERROR_FAILURE;
764 if(NS_SUCCEEDED(rv))
765 rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
766 aAction, aTargetURI != nsnull);
767 break;
769 default:
770 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
771 printf("ERROR ");
772 #endif
773 NS_ERROR("Bad Security Level Value");
774 return NS_ERROR_FAILURE;
777 else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
779 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
780 printf("Cap:%s ", securityLevel.capability);
781 #endif
782 PRBool capabilityEnabled = PR_FALSE;
783 rv = IsCapabilityEnabled(securityLevel.capability, &capabilityEnabled);
784 if (NS_FAILED(rv) || !capabilityEnabled)
785 rv = NS_ERROR_DOM_SECURITY_ERR;
786 else
787 rv = NS_OK;
790 if (NS_SUCCEEDED(rv) && classInfoData.IsContentNode())
792 // No access to anonymous content from the web! (bug 164086)
793 nsIContent *content = static_cast<nsIContent*>(aObj);
794 if (content->IsInNativeAnonymousSubtree()) {
795 rv = NS_ERROR_DOM_SECURITY_ERR;
799 if (NS_SUCCEEDED(rv))
801 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
802 printf(" GRANTED.\n");
803 #endif
804 return rv;
807 //--See if the object advertises a non-default level of access
808 // using nsISecurityCheckedComponent
809 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
810 do_QueryInterface(aObj);
812 nsXPIDLCString objectSecurityLevel;
813 if (checkedComponent)
815 nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
816 nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
817 const nsIID* objIID;
818 rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
819 if (NS_SUCCEEDED(rv))
820 rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
821 if (NS_SUCCEEDED(rv))
822 rv = interfaceInfo->GetIIDShared(&objIID);
823 if (NS_SUCCEEDED(rv))
825 switch (aAction)
827 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
828 checkedComponent->CanGetProperty(objIID,
829 JSValIDToString(cx, aProperty),
830 getter_Copies(objectSecurityLevel));
831 break;
832 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
833 checkedComponent->CanSetProperty(objIID,
834 JSValIDToString(cx, aProperty),
835 getter_Copies(objectSecurityLevel));
836 break;
837 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
838 checkedComponent->CanCallMethod(objIID,
839 JSValIDToString(cx, aProperty),
840 getter_Copies(objectSecurityLevel));
844 rv = CheckXPCPermissions(aObj, objectSecurityLevel);
845 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
846 if(NS_SUCCEEDED(rv))
847 printf("CheckXPCPerms GRANTED.\n");
848 else
849 printf("CheckXPCPerms DENIED.\n");
850 #endif
852 if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
854 nsAutoString stringName;
855 switch(aAction)
857 case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
858 stringName.AssignLiteral("GetPropertyDenied");
859 break;
860 case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
861 stringName.AssignLiteral("SetPropertyDenied");
862 break;
863 case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
864 stringName.AssignLiteral("CallMethodDenied");
867 NS_ConvertUTF8toUTF16 className(classInfoData.GetName());
868 const PRUnichar *formatStrings[] =
870 className.get(),
871 JSValIDToString(cx, aProperty)
874 nsXPIDLString errorMsg;
875 // We need to keep our existing failure rv and not override it
876 // with a likely success code from the following string bundle
877 // call in order to throw the correct security exception later.
878 nsresult rv2 = sStrBundle->FormatStringFromName(stringName.get(),
879 formatStrings,
880 NS_ARRAY_LENGTH(formatStrings),
881 getter_Copies(errorMsg));
882 NS_ENSURE_SUCCESS(rv2, rv2);
884 SetPendingException(cx, errorMsg.get());
886 if (sXPConnect)
888 nsAXPCNativeCallContext *xpcCallContext = nsnull;
889 sXPConnect->GetCurrentNativeCallContext(&xpcCallContext);
890 if (xpcCallContext)
891 xpcCallContext->SetExceptionWasThrown(PR_TRUE);
895 return rv;
898 /* static */
899 nsresult
900 nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
901 nsIPrincipal* aObject,
902 PRBool aIsCheckConnect)
905 ** Get origin of subject and object and compare.
907 if (aSubject == aObject)
908 return NS_OK;
910 // These booleans are only used when !aIsCheckConnect. Default
911 // them to false, and change if that turns out wrong.
912 PRBool subjectSetDomain = PR_FALSE;
913 PRBool objectSetDomain = PR_FALSE;
915 nsCOMPtr<nsIURI> subjectURI;
916 nsCOMPtr<nsIURI> objectURI;
918 if (aIsCheckConnect)
920 // Don't use domain for CheckConnect calls, since that's called for
921 // data-only load checks like XMLHTTPRequest (bug 290100).
922 aSubject->GetURI(getter_AddRefs(subjectURI));
923 aObject->GetURI(getter_AddRefs(objectURI));
925 else
927 aSubject->GetDomain(getter_AddRefs(subjectURI));
928 if (!subjectURI) {
929 aSubject->GetURI(getter_AddRefs(subjectURI));
930 } else {
931 subjectSetDomain = PR_TRUE;
934 aObject->GetDomain(getter_AddRefs(objectURI));
935 if (!objectURI) {
936 aObject->GetURI(getter_AddRefs(objectURI));
937 } else {
938 objectSetDomain = PR_TRUE;
942 if (SecurityCompareURIs(subjectURI, objectURI))
943 { // If either the subject or the object has changed its principal by
944 // explicitly setting document.domain then the other must also have
945 // done so in order to be considered the same origin. This prevents
946 // DNS spoofing based on document.domain (154930)
948 // But this restriction does not apply to CheckConnect calls, since
949 // that's called for data-only load checks like XMLHTTPRequest where
950 // we ignore domain (bug 290100).
951 if (aIsCheckConnect)
952 return NS_OK;
954 // If both or neither explicitly set their domain, allow the access
955 if (subjectSetDomain == objectSetDomain)
956 return NS_OK;
960 ** Access tests failed, so now report error.
962 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
966 nsresult
967 nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
968 nsIPrincipal* aObject,
969 PRUint32 aAction,
970 PRBool aIsCheckConnect)
972 nsresult rv;
973 if (aIsCheckConnect) {
974 // Don't do equality compares, just do a same-origin compare,
975 // since the object principal isn't a real principal, just a
976 // GetCodebasePrincipal() on whatever URI we started with.
977 rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
978 } else {
979 PRBool subsumes;
980 rv = aSubject->Subsumes(aObject, &subsumes);
981 if (NS_SUCCEEDED(rv) && !subsumes) {
982 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
986 if (NS_SUCCEEDED(rv))
987 return NS_OK;
990 * Content can't ever touch chrome (we check for UniversalXPConnect later)
992 if (aObject == mSystemPrincipal)
993 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
996 * If we failed the origin tests it still might be the case that we
997 * are a signed script and have permissions to do this operation.
998 * Check for that here.
1000 PRBool capabilityEnabled = PR_FALSE;
1001 const char* cap = aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY ?
1002 "UniversalBrowserWrite" : "UniversalBrowserRead";
1003 rv = IsCapabilityEnabled(cap, &capabilityEnabled);
1004 NS_ENSURE_SUCCESS(rv, rv);
1005 if (capabilityEnabled)
1006 return NS_OK;
1009 ** Access tests failed, so now report error.
1011 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1014 static
1015 nsresult
1016 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
1017 nsACString& aOrigin)
1019 aOrigin.Truncate();
1021 nsCOMPtr<nsIURI> uri;
1022 aPrincipal->GetDomain(getter_AddRefs(uri));
1023 if (!uri) {
1024 aPrincipal->GetURI(getter_AddRefs(uri));
1027 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
1029 nsCAutoString hostPort;
1031 nsresult rv = uri->GetHostPort(hostPort);
1032 if (NS_SUCCEEDED(rv)) {
1033 nsCAutoString scheme;
1034 rv = uri->GetScheme(scheme);
1035 NS_ENSURE_SUCCESS(rv, rv);
1036 aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
1038 else {
1039 // Some URIs (e.g., nsSimpleURI) don't support host. Just
1040 // get the full spec.
1041 rv = uri->GetSpec(aOrigin);
1042 NS_ENSURE_SUCCESS(rv, rv);
1045 return NS_OK;
1048 nsresult
1049 nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal,
1050 ClassInfoData& aClassData,
1051 jsval aProperty,
1052 PRUint32 aAction,
1053 ClassPolicy** aCachedClassPolicy,
1054 SecurityLevel* result)
1056 nsresult rv;
1057 result->level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
1059 DomainPolicy* dpolicy = nsnull;
1060 //-- Initialize policies if necessary
1061 if (mPolicyPrefsChanged)
1063 rv = InitPolicies();
1064 if (NS_FAILED(rv))
1065 return rv;
1067 else
1069 aPrincipal->GetSecurityPolicy((void**)&dpolicy);
1072 if (!dpolicy && mOriginToPolicyMap)
1074 //-- Look up the relevant domain policy, if any
1075 #ifdef DEBUG_CAPS_LookupPolicy
1076 printf("DomainLookup ");
1077 #endif
1079 nsCAutoString origin;
1080 rv = GetPrincipalDomainOrigin(aPrincipal, origin);
1081 NS_ENSURE_SUCCESS(rv, rv);
1083 char *start = origin.BeginWriting();
1084 const char *nextToLastDot = nsnull;
1085 const char *lastDot = nsnull;
1086 const char *colon = nsnull;
1087 char *p = start;
1089 //-- search domain (stop at the end of the string or at the 3rd slash)
1090 for (PRUint32 slashes=0; *p; p++)
1092 if (*p == '/' && ++slashes == 3)
1094 *p = '\0'; // truncate at 3rd slash
1095 break;
1097 if (*p == '.')
1099 nextToLastDot = lastDot;
1100 lastDot = p;
1102 else if (!colon && *p == ':')
1103 colon = p;
1106 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : start);
1107 DomainEntry *de = (DomainEntry*) mOriginToPolicyMap->Get(&key);
1108 if (!de)
1110 nsCAutoString scheme(start, colon-start+1);
1111 nsCStringKey schemeKey(scheme);
1112 de = (DomainEntry*) mOriginToPolicyMap->Get(&schemeKey);
1115 while (de)
1117 if (de->Matches(start))
1119 dpolicy = de->mDomainPolicy;
1120 break;
1122 de = de->mNext;
1125 if (!dpolicy)
1126 dpolicy = mDefaultPolicy;
1128 aPrincipal->SetSecurityPolicy((void*)dpolicy);
1131 ClassPolicy* cpolicy = nsnull;
1133 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1135 // No per-domain policy for this principal (the more common case)
1136 // so look for a cached class policy from the object wrapper
1137 cpolicy = *aCachedClassPolicy;
1140 if (!cpolicy)
1141 { //-- No cached policy for this class, need to look it up
1142 #ifdef DEBUG_CAPS_LookupPolicy
1143 printf("ClassLookup ");
1144 #endif
1146 cpolicy = static_cast<ClassPolicy*>
1147 (PL_DHashTableOperate(dpolicy,
1148 aClassData.GetName(),
1149 PL_DHASH_LOOKUP));
1151 if (PL_DHASH_ENTRY_IS_FREE(cpolicy))
1152 cpolicy = NO_POLICY_FOR_CLASS;
1154 if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1155 *aCachedClassPolicy = cpolicy;
1158 // We look for a PropertyPolicy in the following places:
1159 // 1) The ClassPolicy for our class we got from our DomainPolicy
1160 // 2) The mWildcardPolicy of our DomainPolicy
1161 // 3) The ClassPolicy for our class we got from mDefaultPolicy
1162 // 4) The mWildcardPolicy of our mDefaultPolicy
1163 PropertyPolicy* ppolicy = nsnull;
1164 if (cpolicy != NO_POLICY_FOR_CLASS)
1166 ppolicy = static_cast<PropertyPolicy*>
1167 (PL_DHashTableOperate(cpolicy->mPolicy,
1168 (void*)aProperty,
1169 PL_DHASH_LOOKUP));
1172 // If there is no class policy for this property, and we have a wildcard
1173 // policy, try that.
1174 if (dpolicy->mWildcardPolicy &&
1175 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1177 ppolicy =
1178 static_cast<PropertyPolicy*>
1179 (PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy,
1180 (void*)aProperty,
1181 PL_DHASH_LOOKUP));
1184 // If dpolicy is not the defauly policy and there's no class or wildcard
1185 // policy for this property, check the default policy for this class and
1186 // the default wildcard policy
1187 if (dpolicy != mDefaultPolicy &&
1188 (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1190 cpolicy = static_cast<ClassPolicy*>
1191 (PL_DHashTableOperate(mDefaultPolicy,
1192 aClassData.GetName(),
1193 PL_DHASH_LOOKUP));
1195 if (PL_DHASH_ENTRY_IS_BUSY(cpolicy))
1197 ppolicy =
1198 static_cast<PropertyPolicy*>
1199 (PL_DHashTableOperate(cpolicy->mPolicy,
1200 (void*)aProperty,
1201 PL_DHASH_LOOKUP));
1204 if ((!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)) &&
1205 mDefaultPolicy->mWildcardPolicy)
1207 ppolicy =
1208 static_cast<PropertyPolicy*>
1209 (PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy,
1210 (void*)aProperty,
1211 PL_DHASH_LOOKUP));
1215 if (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy))
1216 return NS_OK;
1218 // Get the correct security level from the property policy
1219 if (aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY)
1220 *result = ppolicy->mSet;
1221 else
1222 *result = ppolicy->mGet;
1224 return NS_OK;
1228 NS_IMETHODIMP
1229 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
1231 // Get principal of currently executing script.
1232 nsresult rv;
1233 nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
1234 if (NS_FAILED(rv))
1235 return rv;
1237 // Native code can load all URIs.
1238 if (!principal)
1239 return NS_OK;
1241 rv = CheckLoadURIWithPrincipal(principal, aURI,
1242 nsIScriptSecurityManager::STANDARD);
1243 if (NS_SUCCEEDED(rv)) {
1244 // OK to load
1245 return NS_OK;
1248 // See if we're attempting to load a file: URI. If so, let a
1249 // UniversalFileRead capability trump the above check.
1250 PRBool isFile = PR_FALSE;
1251 PRBool isRes = PR_FALSE;
1252 if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
1253 NS_FAILED(aURI->SchemeIs("resource", &isRes)))
1254 return NS_ERROR_FAILURE;
1255 if (isFile || isRes)
1257 PRBool enabled;
1258 if (NS_FAILED(IsCapabilityEnabled("UniversalFileRead", &enabled)))
1259 return NS_ERROR_FAILURE;
1260 if (enabled)
1261 return NS_OK;
1264 // Report error.
1265 nsCAutoString spec;
1266 if (NS_FAILED(aURI->GetAsciiSpec(spec)))
1267 return NS_ERROR_FAILURE;
1268 JS_ReportError(cx, "Access to '%s' from script denied", spec.get());
1269 return NS_ERROR_DOM_BAD_URI;
1272 NS_IMETHODIMP
1273 nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1274 PRUint32 aFlags)
1276 // FIXME: bug 327244 -- this function should really die... Really truly.
1277 NS_PRECONDITION(aSourceURI, "CheckLoadURI called with null source URI");
1278 NS_ENSURE_ARG_POINTER(aSourceURI);
1280 // Note: this is not _quite_ right if aSourceURI has
1281 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1282 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1283 // really needs to go away....
1284 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1285 nsresult rv = CreateCodebasePrincipal(aSourceURI,
1286 getter_AddRefs(sourcePrincipal));
1287 NS_ENSURE_SUCCESS(rv, rv);
1288 return CheckLoadURIWithPrincipal(sourcePrincipal, aTargetURI, aFlags);
1292 * Helper method to handle cases where a flag passed to
1293 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
1294 * nsIProtocolHandler flags set.
1295 * @return if success, access is allowed. Otherwise, deny access
1297 static nsresult
1298 DenyAccessIfURIHasFlags(nsIURI* aURI, PRUint32 aURIFlags)
1300 NS_PRECONDITION(aURI, "Must have URI!");
1302 PRBool uriHasFlags;
1303 nsresult rv =
1304 NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
1305 NS_ENSURE_SUCCESS(rv, rv);
1307 if (uriHasFlags) {
1308 return NS_ERROR_DOM_BAD_URI;
1311 return NS_OK;
1314 NS_IMETHODIMP
1315 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
1316 nsIURI *aTargetURI,
1317 PRUint32 aFlags)
1319 NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
1320 // If someone passes a flag that we don't understand, we should
1321 // fail, because they may need a security check that we don't
1322 // provide.
1323 NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
1324 nsIScriptSecurityManager::ALLOW_CHROME |
1325 nsIScriptSecurityManager::DISALLOW_SCRIPT |
1326 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL),
1327 NS_ERROR_UNEXPECTED);
1328 NS_ENSURE_ARG_POINTER(aPrincipal);
1330 if (aPrincipal == mSystemPrincipal) {
1331 // Allow access
1332 return NS_OK;
1335 nsCOMPtr<nsIURI> sourceURI;
1336 aPrincipal->GetURI(getter_AddRefs(sourceURI));
1337 if (!sourceURI) {
1338 NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
1339 "must have a URI!");
1340 return NS_ERROR_UNEXPECTED;
1343 // Automatic loads are not allowed from certain protocols.
1344 if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
1345 nsresult rv =
1346 DenyAccessIfURIHasFlags(sourceURI,
1347 nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
1348 NS_ENSURE_SUCCESS(rv, rv);
1351 // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
1352 // would do such inheriting. That would be URIs that do not have their own
1353 // security context.
1354 if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
1355 nsresult rv =
1356 DenyAccessIfURIHasFlags(aTargetURI,
1357 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
1358 NS_ENSURE_SUCCESS(rv, rv);
1361 // If either URI is a nested URI, get the base URI
1362 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
1363 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
1365 //-- get the target scheme
1366 nsCAutoString targetScheme;
1367 nsresult rv = targetBaseURI->GetScheme(targetScheme);
1368 if (NS_FAILED(rv)) return rv;
1370 //-- Some callers do not allow loading javascript:
1371 if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
1372 targetScheme.EqualsLiteral("javascript"))
1374 return NS_ERROR_DOM_BAD_URI;
1377 //-- get the source scheme
1378 nsCAutoString sourceScheme;
1379 rv = sourceBaseURI->GetScheme(sourceScheme);
1380 if (NS_FAILED(rv)) return rv;
1382 if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
1383 // A null principal can target its own URI.
1384 if (sourceURI == aTargetURI) {
1385 return NS_OK;
1388 else if (targetScheme.Equals(sourceScheme,
1389 nsCaseInsensitiveCStringComparator()))
1391 // every scheme can access another URI from the same scheme,
1392 // as long as they don't represent null principals.
1393 return NS_OK;
1396 NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
1398 // If the schemes don't match, the policy is specified by the protocol
1399 // flags on the target URI. Note that the order of policy checks here is
1400 // very important! We start from most restrictive and work our way down.
1401 // Note that since we're working with the innermost URI, we can just use
1402 // the methods that work on chains of nested URIs and they will only look
1403 // at the flags for our one URI.
1405 // Check for system target URI
1406 rv = DenyAccessIfURIHasFlags(targetBaseURI,
1407 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
1408 if (NS_FAILED(rv)) {
1409 // Deny access, since the origin principal is not system
1410 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1411 return rv;
1414 // Check for chrome target URI
1415 PRBool hasFlags;
1416 rv = NS_URIChainHasFlags(targetBaseURI,
1417 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1418 &hasFlags);
1419 NS_ENSURE_SUCCESS(rv, rv);
1420 if (hasFlags) {
1421 if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
1422 if (!targetScheme.EqualsLiteral("chrome")) {
1423 // for now don't change behavior for resource: or moz-icon:
1424 return NS_OK;
1427 // allow load only if chrome package is whitelisted
1428 nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
1429 NS_CHROMEREGISTRY_CONTRACTID));
1430 if (reg) {
1431 PRBool accessAllowed = PR_FALSE;
1432 reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
1433 if (accessAllowed) {
1434 return NS_OK;
1439 // resource: and chrome: are equivalent, securitywise
1440 // That's bogus!! Fix this. But watch out for
1441 // the view-source stylesheet?
1442 PRBool sourceIsChrome;
1443 rv = NS_URIChainHasFlags(sourceBaseURI,
1444 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1445 &sourceIsChrome);
1446 NS_ENSURE_SUCCESS(rv, rv);
1447 if (sourceIsChrome) {
1448 return NS_OK;
1450 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1451 return NS_ERROR_DOM_BAD_URI;
1454 // Check for target URI pointing to a file
1455 rv = NS_URIChainHasFlags(targetBaseURI,
1456 nsIProtocolHandler::URI_IS_LOCAL_FILE,
1457 &hasFlags);
1458 NS_ENSURE_SUCCESS(rv, rv);
1459 if (hasFlags) {
1460 // resource: and chrome: are equivalent, securitywise
1461 // That's bogus!! Fix this. But watch out for
1462 // the view-source stylesheet?
1463 PRBool sourceIsChrome;
1464 rv = NS_URIChainHasFlags(sourceURI,
1465 nsIProtocolHandler::URI_IS_UI_RESOURCE,
1466 &sourceIsChrome);
1467 NS_ENSURE_SUCCESS(rv, rv);
1468 if (sourceIsChrome) {
1469 return NS_OK;
1472 // Now check capability policies
1473 static const char loadURIPrefGroup[] = "checkloaduri";
1474 ClassInfoData nameData(nsnull, loadURIPrefGroup);
1476 SecurityLevel secLevel;
1477 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1478 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1479 nsnull, &secLevel);
1480 if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
1482 // OK for this site!
1483 return NS_OK;
1486 ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1487 return NS_ERROR_DOM_BAD_URI;
1490 // OK, everyone is allowed to load this, since unflagged handlers are
1491 // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
1492 // need to warn. At some point we'll want to make this warning into an
1493 // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
1494 rv = NS_URIChainHasFlags(targetBaseURI,
1495 nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
1496 &hasFlags);
1497 NS_ENSURE_SUCCESS(rv, rv);
1498 if (!hasFlags) {
1499 nsXPIDLString message;
1500 NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
1501 const PRUnichar* formatStrings[] = { ucsTargetScheme.get() };
1502 rv = sStrBundle->
1503 FormatStringFromName(NS_LITERAL_STRING("ProtocolFlagError").get(),
1504 formatStrings,
1505 NS_ARRAY_LENGTH(formatStrings),
1506 getter_Copies(message));
1507 if (NS_SUCCEEDED(rv)) {
1508 nsCOMPtr<nsIConsoleService> console(
1509 do_GetService("@mozilla.org/consoleservice;1"));
1510 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1512 console->LogStringMessage(message.get());
1513 #ifdef DEBUG
1514 fprintf(stderr, "%s\n", NS_ConvertUTF16toUTF8(message).get());
1515 #endif
1519 return NS_OK;
1522 nsresult
1523 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
1524 nsIURI* aSource, nsIURI* aTarget)
1526 nsresult rv;
1527 NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
1529 // Get the source URL spec
1530 nsCAutoString sourceSpec;
1531 rv = aSource->GetAsciiSpec(sourceSpec);
1532 NS_ENSURE_SUCCESS(rv, rv);
1534 // Get the target URL spec
1535 nsCAutoString targetSpec;
1536 rv = aTarget->GetAsciiSpec(targetSpec);
1537 NS_ENSURE_SUCCESS(rv, rv);
1539 // Localize the error message
1540 nsXPIDLString message;
1541 NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
1542 NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
1543 const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
1544 rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
1545 formatStrings,
1546 NS_ARRAY_LENGTH(formatStrings),
1547 getter_Copies(message));
1548 NS_ENSURE_SUCCESS(rv, rv);
1550 // If a JS context was passed in, set a JS exception.
1551 // Otherwise, print the error message directly to the JS console
1552 // and to standard output
1553 if (cx)
1555 SetPendingException(cx, message.get());
1556 // Tell XPConnect that an exception was thrown, if appropriate
1557 if (sXPConnect)
1559 nsAXPCNativeCallContext* xpcCallContext = nsnull;
1560 sXPConnect->GetCurrentNativeCallContext(&xpcCallContext);
1561 if (xpcCallContext)
1562 xpcCallContext->SetExceptionWasThrown(PR_TRUE);
1565 else // Print directly to the console
1567 nsCOMPtr<nsIConsoleService> console(
1568 do_GetService("@mozilla.org/consoleservice;1"));
1569 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1571 console->LogStringMessage(message.get());
1572 #ifdef DEBUG
1573 fprintf(stderr, "%s\n", NS_LossyConvertUTF16toASCII(message).get());
1574 #endif
1576 return NS_OK;
1579 NS_IMETHODIMP
1580 nsScriptSecurityManager::CheckLoadURIStr(const nsACString& aSourceURIStr,
1581 const nsACString& aTargetURIStr,
1582 PRUint32 aFlags)
1584 // FIXME: bug 327244 -- this function should really die... Really truly.
1585 nsCOMPtr<nsIURI> source;
1586 nsresult rv = NS_NewURI(getter_AddRefs(source), aSourceURIStr,
1587 nsnull, nsnull, sIOService);
1588 NS_ENSURE_SUCCESS(rv, rv);
1590 // Note: this is not _quite_ right if aSourceURI has
1591 // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1592 // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1593 // really needs to go away....
1594 nsCOMPtr<nsIPrincipal> sourcePrincipal;
1595 rv = CreateCodebasePrincipal(source,
1596 getter_AddRefs(sourcePrincipal));
1597 NS_ENSURE_SUCCESS(rv, rv);
1599 return CheckLoadURIStrWithPrincipal(sourcePrincipal, aTargetURIStr,
1600 aFlags);
1603 NS_IMETHODIMP
1604 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
1605 const nsACString& aTargetURIStr,
1606 PRUint32 aFlags)
1608 nsresult rv;
1609 nsCOMPtr<nsIURI> target;
1610 rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
1611 nsnull, nsnull, sIOService);
1612 NS_ENSURE_SUCCESS(rv, rv);
1614 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1615 NS_ENSURE_SUCCESS(rv, rv);
1617 // Now start testing fixup -- since aTargetURIStr is a string, not
1618 // an nsIURI, we may well end up fixing it up before loading.
1619 // Note: This needs to stay in sync with the nsIURIFixup api.
1620 nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
1621 if (!fixup) {
1622 return rv;
1625 PRUint32 flags[] = {
1626 nsIURIFixup::FIXUP_FLAG_NONE,
1627 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
1628 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
1629 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
1630 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
1633 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(flags); ++i) {
1634 rv = fixup->CreateFixupURI(aTargetURIStr, flags[i],
1635 getter_AddRefs(target));
1636 NS_ENSURE_SUCCESS(rv, rv);
1638 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1639 NS_ENSURE_SUCCESS(rv, rv);
1642 return rv;
1645 NS_IMETHODIMP
1646 nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
1647 void *aTargetObj)
1649 // This check is called for event handlers
1650 nsresult rv;
1651 nsIPrincipal* subject =
1652 GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
1654 // If subject is null, get a principal from the function object's scope.
1655 if (NS_SUCCEEDED(rv) && !subject)
1657 #ifdef DEBUG
1659 JSFunction *fun =
1660 (JSFunction *)caps_GetJSPrivate((JSObject *)aFunObj);
1661 JSScript *script = JS_GetFunctionScript(aCx, fun);
1663 NS_ASSERTION(!script, "Null principal for non-native function!");
1665 #endif
1667 subject = doGetObjectPrincipal((JSObject*)aFunObj);
1670 if (!subject)
1671 return NS_ERROR_FAILURE;
1673 if (subject == mSystemPrincipal)
1674 // This is the system principal: just allow access
1675 return NS_OK;
1677 // Check if the principal the function was compiled under is
1678 // allowed to execute scripts.
1680 PRBool result;
1681 rv = CanExecuteScripts(aCx, subject, &result);
1682 if (NS_FAILED(rv))
1683 return rv;
1685 if (!result)
1686 return NS_ERROR_DOM_SECURITY_ERR;
1689 ** Get origin of subject and object and compare.
1691 JSObject* obj = (JSObject*)aTargetObj;
1692 nsIPrincipal* object = doGetObjectPrincipal(obj);
1694 if (!object)
1695 return NS_ERROR_FAILURE;
1697 PRBool subsumes;
1698 rv = subject->Subsumes(object, &subsumes);
1699 if (NS_SUCCEEDED(rv) && !subsumes) {
1700 rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1702 return rv;
1705 NS_IMETHODIMP
1706 nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
1707 nsIPrincipal *aPrincipal,
1708 PRBool *result)
1710 *result = PR_FALSE;
1712 if (aPrincipal == mSystemPrincipal)
1714 // Even if JavaScript is disabled, we must still execute system scripts
1715 *result = PR_TRUE;
1716 return NS_OK;
1719 //-- See if the current window allows JS execution
1720 nsIScriptContext *scriptContext = GetScriptContext(cx);
1721 if (!scriptContext) return NS_ERROR_FAILURE;
1723 if (!scriptContext->GetScriptsEnabled()) {
1724 // No scripting on this context, folks
1725 *result = PR_FALSE;
1726 return NS_OK;
1729 nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
1731 if (!sgo) {
1732 return NS_ERROR_FAILURE;
1735 // window can be null here if we're running with a non-DOM window
1736 // as the script global (i.e. a XUL prototype document).
1737 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
1738 nsCOMPtr<nsIDocShell> docshell;
1739 nsresult rv;
1741 if (window) {
1742 docshell = window->GetDocShell();
1745 nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
1746 do_QueryInterface(docshell);
1748 if (globalObjTreeItem)
1750 nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
1751 nsCOMPtr<nsIDocShellTreeItem> parentItem;
1753 // Walk up the docshell tree to see if any containing docshell disallows scripts
1756 rv = docshell->GetAllowJavascript(result);
1757 if (NS_FAILED(rv)) return rv;
1758 if (!*result)
1759 return NS_OK; // Do not run scripts
1760 treeItem->GetParent(getter_AddRefs(parentItem));
1761 treeItem.swap(parentItem);
1762 docshell = do_QueryInterface(treeItem);
1763 #ifdef DEBUG
1764 if (treeItem && !docshell) {
1765 NS_ERROR("cannot get a docshell from a treeItem!");
1767 #endif // DEBUG
1768 } while (treeItem && docshell);
1771 // OK, the docshell doesn't have script execution explicitly disabled.
1772 // Check whether our URI is an "about:" URI that allows scripts. If it is,
1773 // we need to allow JS to run. In this case, don't apply the JS enabled
1774 // pref or policies. On failures, just press on and don't do this special
1775 // case.
1776 nsCOMPtr<nsIURI> principalURI;
1777 aPrincipal->GetURI(getter_AddRefs(principalURI));
1778 if (!principalURI) {
1779 // Broken principal of some sort. Disallow.
1780 *result = PR_FALSE;
1781 return NS_ERROR_UNEXPECTED;
1784 PRBool isAbout;
1785 rv = principalURI->SchemeIs("about", &isAbout);
1786 if (NS_SUCCEEDED(rv) && isAbout) {
1787 nsCOMPtr<nsIAboutModule> module;
1788 rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
1789 if (NS_SUCCEEDED(rv)) {
1790 PRUint32 flags;
1791 rv = module->GetURIFlags(principalURI, &flags);
1792 if (NS_SUCCEEDED(rv) &&
1793 (flags & nsIAboutModule::ALLOW_SCRIPT)) {
1794 *result = PR_TRUE;
1795 return NS_OK;
1800 //-- See if JS is disabled globally (via prefs)
1801 *result = mIsJavaScriptEnabled;
1802 if (mIsJavaScriptEnabled != mIsMailJavaScriptEnabled && globalObjTreeItem)
1804 nsCOMPtr<nsIDocShellTreeItem> rootItem;
1805 globalObjTreeItem->GetRootTreeItem(getter_AddRefs(rootItem));
1806 docshell = do_QueryInterface(rootItem);
1807 if (docshell)
1809 // Is this script running from mail?
1810 PRUint32 appType;
1811 rv = docshell->GetAppType(&appType);
1812 if (NS_FAILED(rv)) return rv;
1813 if (appType == nsIDocShell::APP_TYPE_MAIL)
1815 *result = mIsMailJavaScriptEnabled;
1820 if (!*result)
1821 return NS_OK; // Do not run scripts
1823 //-- Check for a per-site policy
1824 static const char jsPrefGroupName[] = "javascript";
1825 ClassInfoData nameData(nsnull, jsPrefGroupName);
1827 SecurityLevel secLevel;
1828 rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1829 nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1830 nsnull, &secLevel);
1831 if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
1833 *result = PR_FALSE;
1834 return rv;
1837 //-- Nobody vetoed, so allow the JS to run.
1838 *result = PR_TRUE;
1839 return NS_OK;
1842 ///////////////// Principals ///////////////////////
1843 NS_IMETHODIMP
1844 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
1846 nsresult rv;
1847 *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
1848 if (NS_SUCCEEDED(rv))
1849 NS_IF_ADDREF(*aSubjectPrincipal);
1850 return rv;
1853 nsIPrincipal*
1854 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
1856 NS_PRECONDITION(rv, "Null out param");
1857 JSContext *cx = GetCurrentJSContext();
1858 if (!cx)
1860 *rv = NS_OK;
1861 return nsnull;
1863 return GetSubjectPrincipal(cx, rv);
1866 NS_IMETHODIMP
1867 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
1869 NS_ADDREF(*result = mSystemPrincipal);
1871 return NS_OK;
1874 NS_IMETHODIMP
1875 nsScriptSecurityManager::SubjectPrincipalIsSystem(PRBool* aIsSystem)
1877 NS_ENSURE_ARG_POINTER(aIsSystem);
1878 *aIsSystem = PR_FALSE;
1880 if (!mSystemPrincipal)
1881 return NS_OK;
1883 nsCOMPtr<nsIPrincipal> subject;
1884 nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
1885 if (NS_FAILED(rv))
1886 return rv;
1888 if(!subject)
1890 // No subject principal means no JS is running;
1891 // this is the equivalent of system principal code
1892 *aIsSystem = PR_TRUE;
1893 return NS_OK;
1896 return mSystemPrincipal->Equals(subject, aIsSystem);
1899 NS_IMETHODIMP
1900 nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint,
1901 const nsACString& aSubjectName,
1902 const nsACString& aPrettyName,
1903 nsISupports* aCertificate,
1904 nsIURI* aURI,
1905 nsIPrincipal **result)
1907 *result = nsnull;
1909 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() &&
1910 !aSubjectName.IsEmpty() &&
1911 aCertificate);
1913 return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName,
1914 aPrettyName, aCertificate, aURI, PR_TRUE,
1915 result);
1918 nsresult
1919 nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
1920 const nsACString& aSubjectName,
1921 const nsACString& aPrettyName,
1922 nsISupports* aCertificate,
1923 nsIURI* aURI,
1924 PRBool aModifyTable,
1925 nsIPrincipal **result)
1927 NS_ENSURE_ARG(!aCertFingerprint.IsEmpty());
1929 // Create a certificate principal out of the certificate ID
1930 // and URI given to us. We will use this principal to test
1931 // equality when doing our hashtable lookups below.
1932 nsRefPtr<nsPrincipal> certificate = new nsPrincipal();
1933 if (!certificate)
1934 return NS_ERROR_OUT_OF_MEMORY;
1936 nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
1937 aPrettyName, aCertificate, aURI);
1938 NS_ENSURE_SUCCESS(rv, rv);
1940 // Check to see if we already have this principal.
1941 nsCOMPtr<nsIPrincipal> fromTable;
1942 mPrincipals.Get(certificate, getter_AddRefs(fromTable));
1943 if (fromTable) {
1944 // Bingo. We found the certificate in the table, which means
1945 // that it has escalated privileges.
1947 if (aModifyTable) {
1948 // Make sure this principal has names, so if we ever go to save it
1949 // we'll save them. If we get a name mismatch here we'll throw,
1950 // but that's desirable.
1951 rv = static_cast<nsPrincipal*>
1952 (static_cast<nsIPrincipal*>(fromTable))
1953 ->EnsureCertData(aSubjectName, aPrettyName, aCertificate);
1954 if (NS_FAILED(rv)) {
1955 // We have a subject name mismatch for the same cert id.
1956 // Hand back the |certificate| object we created and don't give
1957 // it any rights from the table.
1958 NS_ADDREF(*result = certificate);
1959 return NS_OK;
1963 if (!aURI) {
1964 // We were asked to just get the base certificate, so output
1965 // what we have in the table.
1966 certificate = static_cast<nsPrincipal*>
1967 (static_cast<nsIPrincipal*>
1968 (fromTable));
1969 } else {
1970 // We found a certificate and now need to install a codebase
1971 // on it. We don't want to modify the principal in the hash
1972 // table, so create a new principal and clone the pertinent
1973 // things.
1974 nsXPIDLCString prefName;
1975 nsXPIDLCString id;
1976 nsXPIDLCString subjectName;
1977 nsXPIDLCString granted;
1978 nsXPIDLCString denied;
1979 PRBool isTrusted;
1980 rv = fromTable->GetPreferences(getter_Copies(prefName),
1981 getter_Copies(id),
1982 getter_Copies(subjectName),
1983 getter_Copies(granted),
1984 getter_Copies(denied),
1985 &isTrusted);
1986 // XXXbz assert something about subjectName and aSubjectName here?
1987 if (NS_SUCCEEDED(rv)) {
1988 NS_ASSERTION(!isTrusted, "Shouldn't have isTrusted true here");
1990 certificate = new nsPrincipal();
1991 if (!certificate)
1992 return NS_ERROR_OUT_OF_MEMORY;
1994 rv = certificate->InitFromPersistent(prefName, id,
1995 subjectName, aPrettyName,
1996 granted, denied,
1997 aCertificate,
1998 PR_TRUE, PR_FALSE);
1999 if (NS_FAILED(rv))
2000 return rv;
2002 certificate->SetURI(aURI);
2007 NS_ADDREF(*result = certificate);
2009 return rv;
2012 nsresult
2013 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **result)
2015 // I _think_ it's safe to not create null principals here based on aURI.
2016 // At least all the callers would do the right thing in those cases, as far
2017 // as I can tell. --bz
2018 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2019 if (!codebase)
2020 return NS_ERROR_OUT_OF_MEMORY;
2022 nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
2023 EmptyCString(), nsnull, aURI);
2024 if (NS_FAILED(rv))
2025 return rv;
2027 NS_ADDREF(*result = codebase);
2029 return NS_OK;
2032 NS_IMETHODIMP
2033 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
2034 nsIPrincipal **result)
2036 NS_ENSURE_ARG(aURI);
2038 PRBool inheritsPrincipal;
2039 nsresult rv =
2040 NS_URIChainHasFlags(aURI,
2041 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
2042 &inheritsPrincipal);
2043 if (NS_FAILED(rv) || inheritsPrincipal) {
2044 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
2047 nsCOMPtr<nsIPrincipal> principal;
2048 rv = CreateCodebasePrincipal(aURI, getter_AddRefs(principal));
2049 if (NS_FAILED(rv)) return rv;
2051 if (mPrincipals.Count() > 0)
2053 //-- Check to see if we already have this principal.
2054 nsCOMPtr<nsIPrincipal> fromTable;
2055 mPrincipals.Get(principal, getter_AddRefs(fromTable));
2056 if (!fromTable)
2058 //-- Check to see if we have a more general principal
2060 // XXXbz if only GetOrigin returned a URI! Or better yet if the
2061 // HashKey function on principals were smarter. As it is, we can
2062 // have cases where two principals will have different hashkeys but
2063 // test equal via KeyEquals, which is absolutely silly. That's
2064 // what we're working around here.
2065 nsXPIDLCString originUrl;
2066 rv = principal->GetOrigin(getter_Copies(originUrl));
2067 if (NS_FAILED(rv)) return rv;
2068 nsCOMPtr<nsIURI> newURI;
2069 rv = NS_NewURI(getter_AddRefs(newURI), originUrl, nsnull, sIOService);
2070 if (NS_FAILED(rv)) return rv;
2071 nsCOMPtr<nsIPrincipal> principal2;
2072 rv = CreateCodebasePrincipal(newURI, getter_AddRefs(principal2));
2073 if (NS_FAILED(rv)) return rv;
2074 mPrincipals.Get(principal2, getter_AddRefs(fromTable));
2077 if (fromTable) {
2078 // We found an existing codebase principal. But it might have a
2079 // generic codebase for this origin on it. Install our particular
2080 // codebase.
2081 // XXXbz this is kinda similar to the code in
2082 // GetCertificatePrincipal, but just ever so slightly different.
2083 // Oh, well.
2084 nsXPIDLCString prefName;
2085 nsXPIDLCString id;
2086 nsXPIDLCString subjectName;
2087 nsXPIDLCString granted;
2088 nsXPIDLCString denied;
2089 PRBool isTrusted;
2090 rv = fromTable->GetPreferences(getter_Copies(prefName),
2091 getter_Copies(id),
2092 getter_Copies(subjectName),
2093 getter_Copies(granted),
2094 getter_Copies(denied),
2095 &isTrusted);
2096 if (NS_SUCCEEDED(rv)) {
2097 nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2098 if (!codebase)
2099 return NS_ERROR_OUT_OF_MEMORY;
2101 rv = codebase->InitFromPersistent(prefName, id,
2102 subjectName, EmptyCString(),
2103 granted, denied,
2104 nsnull, PR_FALSE,
2105 isTrusted);
2106 if (NS_FAILED(rv))
2107 return rv;
2109 codebase->SetURI(aURI);
2110 principal = codebase;
2116 NS_IF_ADDREF(*result = principal);
2118 return NS_OK;
2121 NS_IMETHODIMP
2122 nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
2123 nsIPrincipal **result)
2125 *result = nsnull;
2127 nsIScriptContext *scriptContext = GetScriptContext(cx);
2129 if (!scriptContext)
2131 return NS_ERROR_FAILURE;
2134 nsCOMPtr<nsIScriptObjectPrincipal> globalData =
2135 do_QueryInterface(scriptContext->GetGlobalObject());
2136 if (globalData)
2137 NS_IF_ADDREF(*result = globalData->GetPrincipal());
2139 return NS_OK;
2142 // static
2143 nsIPrincipal*
2144 nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
2145 JSScript *script,
2146 nsresult* rv)
2148 NS_PRECONDITION(rv, "Null out param");
2149 *rv = NS_OK;
2150 if (!script)
2152 return nsnull;
2154 JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
2155 if (!jsp) {
2156 *rv = NS_ERROR_FAILURE;
2157 // Script didn't have principals -- shouldn't happen.
2158 return nsnull;
2160 nsJSPrincipals *nsJSPrin = static_cast<nsJSPrincipals *>(jsp);
2161 nsIPrincipal* result = nsJSPrin->nsIPrincipalPtr;
2162 if (!result)
2163 *rv = NS_ERROR_FAILURE;
2164 return result;
2167 // static
2168 nsIPrincipal*
2169 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
2170 JSObject *obj,
2171 JSStackFrame *fp,
2172 nsresult *rv)
2174 NS_PRECONDITION(rv, "Null out param");
2175 JSFunction *fun = (JSFunction *) caps_GetJSPrivate(obj);
2176 JSScript *script = JS_GetFunctionScript(cx, fun);
2178 *rv = NS_OK;
2180 if (!script)
2182 // A native function: skip it in order to find its scripted caller.
2183 return nsnull;
2186 JSScript *frameScript = fp ? JS_GetFrameScript(cx, fp) : nsnull;
2188 if (frameScript && frameScript != script)
2190 // There is a frame script, and it's different from the
2191 // function script. In this case we're dealing with either
2192 // an eval or a Script object, and in these cases the
2193 // principal we want is in the frame's script, not in the
2194 // function's script. The function's script is where the
2195 // eval-calling code came from, not where the eval or new
2196 // Script object came from, and we want the principal of
2197 // the eval function object or new Script object.
2199 script = frameScript;
2201 else if (JS_GetFunctionObject(fun) != obj)
2203 // Here, obj is a cloned function object. In this case, the
2204 // clone's prototype may have been precompiled from brutally
2205 // shared chrome, or else it is a lambda or nested function.
2206 // The general case here is a function compiled against a
2207 // different scope than the one it is parented by at runtime,
2208 // hence the creation of a clone to carry the correct scope
2209 // chain linkage.
2211 // Since principals follow scope, we must get the object
2212 // principal from the clone's scope chain. There are no
2213 // reliable principals compiled into the function itself.
2215 nsIPrincipal *result = doGetObjectPrincipal(obj);
2216 if (!result)
2217 *rv = NS_ERROR_FAILURE;
2218 return result;
2221 return GetScriptPrincipal(cx, script, rv);
2224 // static
2225 nsIPrincipal*
2226 nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
2227 JSStackFrame *fp,
2228 nsresult *rv)
2230 NS_PRECONDITION(rv, "Null out param");
2231 JSObject *obj = JS_GetFrameFunctionObject(cx, fp);
2232 if (!obj)
2234 // Must be in a top-level script. Get principal from the script.
2235 JSScript *script = JS_GetFrameScript(cx, fp);
2236 return GetScriptPrincipal(cx, script, rv);
2239 nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
2241 #ifdef DEBUG
2242 if (NS_SUCCEEDED(*rv) && !result)
2244 JSFunction *fun = (JSFunction *)caps_GetJSPrivate(obj);
2245 JSScript *script = JS_GetFunctionScript(cx, fun);
2247 NS_ASSERTION(!script, "Null principal for non-native function!");
2249 #endif
2251 return result;
2254 // static
2255 nsIPrincipal*
2256 nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
2257 JSStackFrame **frameResult,
2258 nsresult* rv)
2260 NS_PRECONDITION(rv, "Null out param");
2261 //-- If there's no principal on the stack, look at the global object
2262 // and return the innermost frame for annotations.
2263 *rv = NS_OK;
2264 if (cx)
2266 // Get principals from innermost frame of JavaScript or Java.
2267 JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
2268 for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
2270 nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
2271 if (result)
2273 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
2274 *frameResult = fp;
2275 return result;
2279 nsIScriptContext *scriptContext = GetScriptContext(cx);
2280 if (scriptContext)
2282 nsCOMPtr<nsIScriptObjectPrincipal> globalData =
2283 do_QueryInterface(scriptContext->GetGlobalObject());
2284 if (!globalData)
2286 *rv = NS_ERROR_FAILURE;
2287 return nsnull;
2290 // Note that we're not in a loop or anything, and nothing comes
2291 // after this point in the function, so we can just return here.
2292 nsIPrincipal* result = globalData->GetPrincipal();
2293 if (result)
2295 JSStackFrame *inner = nsnull;
2296 *frameResult = JS_FrameIterator(cx, &inner);
2297 return result;
2302 return nsnull;
2305 // static
2306 nsIPrincipal*
2307 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
2308 nsresult* rv)
2310 NS_PRECONDITION(rv, "Null out param");
2311 JSStackFrame *fp;
2312 return GetPrincipalAndFrame(cx, &fp, rv);
2315 NS_IMETHODIMP
2316 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
2317 nsIPrincipal **result)
2319 *result = doGetObjectPrincipal(aObj);
2320 if (!*result)
2321 return NS_ERROR_FAILURE;
2322 NS_ADDREF(*result);
2323 return NS_OK;
2326 // static
2327 nsIPrincipal*
2328 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
2329 #ifdef DEBUG
2330 , PRBool aAllowShortCircuit
2331 #endif
2334 NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
2335 nsIPrincipal* result = nsnull;
2337 #ifdef DEBUG
2338 JSObject* origObj = aObj;
2339 #endif
2341 const JSClass *jsClass = STOBJ_GET_CLASS(aObj);
2343 // A common case seen in this code is that we enter this function
2344 // with aObj being a Function object, whose parent is a Call
2345 // object. Neither of those have object principals, so we can skip
2346 // those objects here before we enter the below loop. That way we
2347 // avoid wasting time checking properties of their classes etc in
2348 // the loop.
2350 if (jsClass == &js_FunctionClass) {
2351 aObj = STOBJ_GET_PARENT(aObj);
2353 if (!aObj)
2354 return nsnull;
2356 jsClass = STOBJ_GET_CLASS(aObj);
2358 if (jsClass == &js_CallClass) {
2359 aObj = STOBJ_GET_PARENT(aObj);
2361 if (!aObj)
2362 return nsnull;
2364 jsClass = STOBJ_GET_CLASS(aObj);
2368 do {
2369 // Note: jsClass is set before this loop, and also at the
2370 // *end* of this loop.
2372 // NOTE: These class and getObjectOps hook checks better match
2373 // what IS_WRAPPER_CLASS() does in xpconnect!
2374 if (jsClass == sXPCWrappedNativeJSClass ||
2375 jsClass->getObjectOps == sXPCWrappedNativeGetObjOps1 ||
2376 jsClass->getObjectOps == sXPCWrappedNativeGetObjOps2) {
2377 nsIXPConnectWrappedNative *xpcWrapper =
2378 (nsIXPConnectWrappedNative *)caps_GetJSPrivate(aObj);
2380 if (xpcWrapper) {
2381 #ifdef DEBUG
2382 if (aAllowShortCircuit) {
2383 #endif
2384 result = xpcWrapper->GetObjectPrincipal();
2386 if (result) {
2387 break;
2389 #ifdef DEBUG
2391 #endif
2393 // If not, check if it points to an
2394 // nsIScriptObjectPrincipal
2395 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2396 do_QueryWrappedNative(xpcWrapper);
2397 if (objPrin) {
2398 result = objPrin->GetPrincipal();
2400 if (result) {
2401 break;
2405 } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
2406 JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
2407 nsISupports *priv = (nsISupports *)caps_GetJSPrivate(aObj);
2409 #ifdef DEBUG
2410 if (aAllowShortCircuit) {
2411 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
2412 do_QueryInterface(priv);
2414 NS_ASSERTION(!xpcWrapper ||
2415 !strcmp(jsClass->name, "XPCNativeWrapper"),
2416 "Uh, an nsIXPConnectWrappedNative with the "
2417 "wrong JSClass or getObjectOps hooks!");
2419 #endif
2421 nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2422 do_QueryInterface(priv);
2424 if (objPrin) {
2425 result = objPrin->GetPrincipal();
2427 if (result) {
2428 break;
2433 aObj = STOBJ_GET_PARENT(aObj);
2435 if (!aObj)
2436 break;
2438 jsClass = STOBJ_GET_CLASS(aObj);
2439 } while (1);
2441 NS_ASSERTION(!aAllowShortCircuit ||
2442 result == doGetObjectPrincipal(origObj, PR_FALSE),
2443 "Principal mismatch. Not good");
2445 return result;
2448 nsresult
2449 nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
2451 //-- Save to mPrincipals
2452 mPrincipals.Put(aToSave, aToSave);
2454 //-- Save to prefs
2455 nsXPIDLCString idPrefName;
2456 nsXPIDLCString id;
2457 nsXPIDLCString subjectName;
2458 nsXPIDLCString grantedList;
2459 nsXPIDLCString deniedList;
2460 PRBool isTrusted;
2461 nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName),
2462 getter_Copies(id),
2463 getter_Copies(subjectName),
2464 getter_Copies(grantedList),
2465 getter_Copies(deniedList),
2466 &isTrusted);
2467 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2469 nsCAutoString grantedPrefName;
2470 nsCAutoString deniedPrefName;
2471 nsCAutoString subjectNamePrefName;
2472 rv = GetPrincipalPrefNames( idPrefName,
2473 grantedPrefName,
2474 deniedPrefName,
2475 subjectNamePrefName );
2476 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2478 mIsWritingPrefs = PR_TRUE;
2479 if (grantedList)
2480 mSecurityPref->SecuritySetCharPref(grantedPrefName.get(), grantedList);
2481 else
2482 mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
2484 if (deniedList)
2485 mSecurityPref->SecuritySetCharPref(deniedPrefName.get(), deniedList);
2486 else
2487 mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
2489 if (grantedList || deniedList) {
2490 mSecurityPref->SecuritySetCharPref(idPrefName, id);
2491 mSecurityPref->SecuritySetCharPref(subjectNamePrefName.get(),
2492 subjectName);
2494 else {
2495 mSecurityPref->SecurityClearUserPref(idPrefName);
2496 mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
2499 mIsWritingPrefs = PR_FALSE;
2501 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
2502 NS_ENSURE_SUCCESS(rv, rv);
2503 return prefService->SavePrefFile(nsnull);
2506 ///////////////// Capabilities API /////////////////////
2507 NS_IMETHODIMP
2508 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
2509 PRBool *result)
2511 nsresult rv;
2512 JSStackFrame *fp = nsnull;
2513 JSContext *cx = GetCurrentJSContext();
2514 fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
2515 if (!fp)
2517 // No script code on stack. Allow execution.
2518 *result = PR_TRUE;
2519 return NS_OK;
2521 *result = PR_FALSE;
2522 nsIPrincipal* previousPrincipal = nsnull;
2525 nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
2526 if (NS_FAILED(rv))
2527 return rv;
2528 if (!principal)
2529 continue;
2530 // If caller has a different principal, stop looking up the stack.
2531 if(previousPrincipal)
2533 PRBool isEqual = PR_FALSE;
2534 if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
2535 break;
2537 else
2538 previousPrincipal = principal;
2540 // First check if the principal is even able to enable the
2541 // given capability. If not, don't look any further.
2542 PRInt16 canEnable;
2543 rv = principal->CanEnableCapability(capability, &canEnable);
2544 if (NS_FAILED(rv)) return rv;
2545 if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
2546 canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2547 return NS_OK;
2549 // Now see if the capability is enabled.
2550 void *annotation = JS_GetFrameAnnotation(cx, fp);
2551 rv = principal->IsCapabilityEnabled(capability, annotation, result);
2552 if (NS_FAILED(rv)) return rv;
2553 if (*result)
2554 return NS_OK;
2555 } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
2557 if (!previousPrincipal)
2559 // No principals on the stack, all native code. Allow
2560 // execution if the subject principal is the system principal.
2562 return SubjectPrincipalIsSystem(result);
2565 return NS_OK;
2568 void
2569 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
2571 nsAutoString newcaps;
2572 nsAutoString rawcap;
2573 NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
2574 PRInt32 pos;
2575 PRInt32 index = kNotFound;
2576 nsresult rv;
2578 NS_ASSERTION(kNotFound == -1, "Basic constant changed, algorithm broken!");
2580 do {
2581 pos = index+1;
2582 index = aCapability.FindChar(' ', pos);
2583 rawcap = Substring(aCapability, pos,
2584 (index == kNotFound) ? index : index - pos);
2586 nsXPIDLString capstr;
2587 rv = sStrBundle->GetStringFromName(
2588 nsPromiseFlatString(capdesc+rawcap).get(),
2589 getter_Copies(capstr));
2590 if (NS_SUCCEEDED(rv))
2591 newcaps += capstr;
2592 else
2594 nsXPIDLString extensionCap;
2595 const PRUnichar* formatArgs[] = { rawcap.get() };
2596 rv = sStrBundle->FormatStringFromName(
2597 NS_LITERAL_STRING("ExtensionCapability").get(),
2598 formatArgs,
2599 NS_ARRAY_LENGTH(formatArgs),
2600 getter_Copies(extensionCap));
2601 if (NS_SUCCEEDED(rv))
2602 newcaps += extensionCap;
2603 else
2604 newcaps += rawcap;
2607 newcaps += NS_LITERAL_STRING("\n");
2608 } while (index != kNotFound);
2610 aCapability = newcaps;
2613 PRBool
2614 nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
2615 const char* aCapability, PRBool *checkValue)
2617 nsresult rv;
2618 *checkValue = PR_FALSE;
2620 //-- Get a prompter for the current window.
2621 nsCOMPtr<nsIPrompt> prompter;
2622 if (cx)
2624 nsIScriptContext *scriptContext = GetScriptContext(cx);
2625 if (scriptContext)
2627 nsCOMPtr<nsIDOMWindowInternal> domWin =
2628 do_QueryInterface(scriptContext->GetGlobalObject());
2629 if (domWin)
2630 domWin->GetPrompter(getter_AddRefs(prompter));
2634 if (!prompter)
2636 //-- Couldn't get prompter from the current window, so get the prompt service.
2637 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2638 if (wwatch)
2639 wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
2640 if (!prompter)
2641 return PR_FALSE;
2644 //-- Localize the dialog text
2645 nsXPIDLString check;
2646 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
2647 getter_Copies(check));
2648 if (NS_FAILED(rv))
2649 return PR_FALSE;
2651 nsXPIDLString title;
2652 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
2653 getter_Copies(title));
2654 if (NS_FAILED(rv))
2655 return PR_FALSE;
2657 nsXPIDLString yesStr;
2658 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
2659 getter_Copies(yesStr));
2660 if (NS_FAILED(rv))
2661 return PR_FALSE;
2663 nsXPIDLString noStr;
2664 rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(),
2665 getter_Copies(noStr));
2666 if (NS_FAILED(rv))
2667 return PR_FALSE;
2669 nsCAutoString val;
2670 PRBool hasCert;
2671 aPrincipal->GetHasCertificate(&hasCert);
2672 if (hasCert)
2673 rv = aPrincipal->GetPrettyName(val);
2674 else
2675 rv = GetPrincipalDomainOrigin(aPrincipal, val);
2677 if (NS_FAILED(rv))
2678 return PR_FALSE;
2680 NS_ConvertUTF8toUTF16 location(val);
2681 NS_ConvertASCIItoUTF16 capability(aCapability);
2682 FormatCapabilityString(capability);
2683 const PRUnichar *formatStrings[] = { location.get(), capability.get() };
2685 nsXPIDLString message;
2686 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
2687 formatStrings,
2688 NS_ARRAY_LENGTH(formatStrings),
2689 getter_Copies(message));
2690 if (NS_FAILED(rv))
2691 return PR_FALSE;
2693 PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
2694 rv = prompter->ConfirmEx(title.get(), message.get(),
2695 (nsIPrompt::BUTTON_DELAY_ENABLE) +
2696 (nsIPrompt::BUTTON_POS_1_DEFAULT) +
2697 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
2698 (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1),
2699 yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed);
2701 if (NS_FAILED(rv))
2702 *checkValue = PR_FALSE;
2703 return (buttonPressed == 0);
2706 NS_IMETHODIMP
2707 nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal,
2708 const char *capability, PRInt16* canEnable)
2710 if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
2711 return NS_ERROR_FAILURE;
2712 if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2714 // Prompt user for permission to enable capability.
2715 JSContext* cx = GetCurrentJSContext();
2716 PRBool remember;
2717 if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
2718 *canEnable = nsIPrincipal::ENABLE_GRANTED;
2719 else
2720 *canEnable = nsIPrincipal::ENABLE_DENIED;
2721 if (remember)
2723 //-- Save principal to prefs and to mPrincipals
2724 if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
2725 return NS_ERROR_FAILURE;
2726 if (NS_FAILED(SavePrincipal(aPrincipal)))
2727 return NS_ERROR_FAILURE;
2730 return NS_OK;
2733 NS_IMETHODIMP
2734 nsScriptSecurityManager::EnableCapability(const char *capability)
2736 JSContext *cx = GetCurrentJSContext();
2737 JSStackFrame *fp;
2739 //-- Error checks for capability string length (200)
2740 if(PL_strlen(capability)>200)
2742 static const char msg[] = "Capability name too long";
2743 SetPendingException(cx, msg);
2744 return NS_ERROR_FAILURE;
2747 //-- Check capability string for valid characters
2749 // Logically we might have wanted this in nsPrincipal, but performance
2750 // worries dictate it can't go in IsCapabilityEnabled() and we may have
2751 // to show the capability on a dialog before we call the principal's
2752 // EnableCapability().
2754 // We don't need to validate the capability string on the other APIs
2755 // available to web content. Without the ability to enable junk then
2756 // isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
2757 // the right thing (effectively nothing) when passed unallowed chars.
2758 for (const char *ch = capability; *ch; ++ch)
2760 if (!NS_IS_ALPHA(*ch) && *ch != ' ' && !NS_IS_DIGIT(*ch)
2761 && *ch != '_' && *ch != '-' && *ch != '.')
2763 static const char msg[] = "Invalid character in capability name";
2764 SetPendingException(cx, msg);
2765 return NS_ERROR_FAILURE;
2769 nsresult rv;
2770 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2771 if (NS_FAILED(rv))
2772 return rv;
2773 if (!principal)
2774 return NS_ERROR_NOT_AVAILABLE;
2776 void *annotation = JS_GetFrameAnnotation(cx, fp);
2777 PRBool enabled;
2778 if (NS_FAILED(principal->IsCapabilityEnabled(capability, annotation,
2779 &enabled)))
2780 return NS_ERROR_FAILURE;
2781 if (enabled)
2782 return NS_OK;
2784 PRInt16 canEnable;
2785 if (NS_FAILED(RequestCapability(principal, capability, &canEnable)))
2786 return NS_ERROR_FAILURE;
2788 if (canEnable != nsIPrincipal::ENABLE_GRANTED)
2790 nsCAutoString val;
2791 PRBool hasCert;
2792 nsresult rv;
2793 principal->GetHasCertificate(&hasCert);
2794 if (hasCert)
2795 rv = principal->GetPrettyName(val);
2796 else
2797 rv = GetPrincipalDomainOrigin(principal, val);
2799 if (NS_FAILED(rv))
2800 return rv;
2802 NS_ConvertUTF8toUTF16 location(val);
2803 NS_ConvertUTF8toUTF16 cap(capability);
2804 const PRUnichar *formatStrings[] = { location.get(), cap.get() };
2806 nsXPIDLString message;
2807 rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
2808 formatStrings,
2809 NS_ARRAY_LENGTH(formatStrings),
2810 getter_Copies(message));
2811 if (NS_FAILED(rv))
2812 return rv;
2814 SetPendingException(cx, message.get());
2816 return NS_ERROR_FAILURE; // XXX better error code?
2818 if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
2819 return NS_ERROR_FAILURE;
2820 JS_SetFrameAnnotation(cx, fp, annotation);
2821 return NS_OK;
2824 NS_IMETHODIMP
2825 nsScriptSecurityManager::RevertCapability(const char *capability)
2827 JSContext *cx = GetCurrentJSContext();
2828 JSStackFrame *fp;
2829 nsresult rv;
2830 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2831 if (NS_FAILED(rv))
2832 return rv;
2833 if (!principal)
2834 return NS_ERROR_NOT_AVAILABLE;
2835 void *annotation = JS_GetFrameAnnotation(cx, fp);
2836 principal->RevertCapability(capability, &annotation);
2837 JS_SetFrameAnnotation(cx, fp, annotation);
2838 return NS_OK;
2841 NS_IMETHODIMP
2842 nsScriptSecurityManager::DisableCapability(const char *capability)
2844 JSContext *cx = GetCurrentJSContext();
2845 JSStackFrame *fp;
2846 nsresult rv;
2847 nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2848 if (NS_FAILED(rv))
2849 return rv;
2850 if (!principal)
2851 return NS_ERROR_NOT_AVAILABLE;
2852 void *annotation = JS_GetFrameAnnotation(cx, fp);
2853 principal->DisableCapability(capability, &annotation);
2854 JS_SetFrameAnnotation(cx, fp, annotation);
2855 return NS_OK;
2858 //////////////// Master Certificate Functions ///////////////////////////////////////
2859 NS_IMETHODIMP
2860 nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint,
2861 const char* capability,
2862 PRInt16 canEnable)
2864 NS_ENSURE_ARG(!certFingerprint.IsEmpty());
2866 nsresult rv;
2867 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv);
2868 if (NS_FAILED(rv))
2869 return rv;
2871 //-- Get the system certificate
2872 if (!mSystemCertificate)
2874 nsCOMPtr<nsIFile> systemCertFile;
2875 nsCOMPtr<nsIProperties> directoryService =
2876 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
2877 if (!directoryService) return NS_ERROR_FAILURE;
2878 rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
2879 getter_AddRefs(systemCertFile));
2880 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2881 systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
2882 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2883 nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv);
2884 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2885 rv = systemCertZip->Open(systemCertFile);
2886 if (NS_SUCCEEDED(rv))
2888 nsCOMPtr<nsIJAR> systemCertJar(do_QueryInterface(systemCertZip, &rv));
2889 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2890 rv = systemCertJar->GetCertificatePrincipal(nsnull,
2891 getter_AddRefs(mSystemCertificate));
2892 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2896 //-- Make sure the caller's principal is the system certificate
2897 PRBool isEqual = PR_FALSE;
2898 if (mSystemCertificate)
2900 rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual);
2901 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2903 if (!isEqual)
2905 JSContext* cx = GetCurrentJSContext();
2906 if (!cx) return NS_ERROR_FAILURE;
2907 static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
2908 static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
2909 SetPendingException(cx, mSystemCertificate ? msg1 : msg2);
2910 return NS_ERROR_FAILURE;
2913 //-- Get the target principal
2914 nsCOMPtr<nsIPrincipal> objectPrincipal;
2915 rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(),
2916 EmptyCString(), nsnull,
2917 nsnull, PR_FALSE,
2918 getter_AddRefs(objectPrincipal));
2919 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2920 rv = objectPrincipal->SetCanEnableCapability(capability, canEnable);
2921 if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2922 return SavePrincipal(objectPrincipal);
2925 ////////////////////////////////////////////////
2926 // Methods implementing nsIXPCSecurityManager //
2927 ////////////////////////////////////////////////
2929 NS_IMETHODIMP
2930 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
2931 const nsIID &aIID,
2932 nsISupports *aObj,
2933 nsIClassInfo *aClassInfo,
2934 void **aPolicy)
2936 #ifdef DEBUG_CAPS_CanCreateWrapper
2937 char* iidStr = aIID.ToString();
2938 printf("### CanCreateWrapper(%s) ", iidStr);
2939 nsCRT::free(iidStr);
2940 #endif
2941 // XXX Special case for nsIXPCException ?
2942 ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nsnull);
2943 if (objClassInfo.IsDOMClass())
2945 #ifdef DEBUG_CAPS_CanCreateWrapper
2946 printf("DOM class - GRANTED.\n");
2947 #endif
2948 return NS_OK;
2951 //--See if the object advertises a non-default level of access
2952 // using nsISecurityCheckedComponent
2953 nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
2954 do_QueryInterface(aObj);
2956 nsXPIDLCString objectSecurityLevel;
2957 if (checkedComponent)
2958 checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
2960 nsresult rv = CheckXPCPermissions(aObj, objectSecurityLevel);
2961 if (NS_FAILED(rv))
2963 //-- Access denied, report an error
2965 NS_NAMED_LITERAL_STRING(strName, "CreateWrapperDenied");
2966 NS_ConvertUTF8toUTF16 className(objClassInfo.GetName());
2967 const PRUnichar* formatStrings[] = { className.get() };
2968 nsXPIDLString errorMsg;
2969 // We need to keep our existing failure rv and not override it
2970 // with a likely success code from the following string bundle
2971 // call in order to throw the correct security exception later.
2972 nsresult rv2 =
2973 sStrBundle->FormatStringFromName(strName.get(),
2974 formatStrings,
2975 NS_ARRAY_LENGTH(formatStrings),
2976 getter_Copies(errorMsg));
2977 NS_ENSURE_SUCCESS(rv2, rv2);
2979 SetPendingException(cx, errorMsg.get());
2981 #ifdef DEBUG_CAPS_CanCreateWrapper
2982 printf("DENIED.\n");
2984 else
2986 printf("GRANTED.\n");
2987 #endif
2990 return rv;
2993 #ifdef XPC_IDISPATCH_SUPPORT
2994 nsresult
2995 nsScriptSecurityManager::CheckComponentPermissions(JSContext *cx,
2996 const nsCID &aCID)
2998 nsresult rv;
2999 nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
3000 if (NS_FAILED(rv))
3001 return rv;
3003 // Reformat the CID string so it's suitable for prefs
3004 nsXPIDLCString cidTemp;
3005 cidTemp.Adopt(aCID.ToString());
3006 nsCAutoString cid(NS_LITERAL_CSTRING("CID") +
3007 Substring(cidTemp, 1, cidTemp.Length() - 2));
3008 ToUpperCase(cid);
3010 #ifdef DEBUG_CAPS_CheckComponentPermissions
3011 printf("### CheckComponentPermissions(ClassID.%s) ",cid.get());
3012 #endif
3014 // Look up the policy for this class.
3015 // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD
3016 JSAutoRequest ar(cx);
3017 jsval cidVal = STRING_TO_JSVAL(::JS_InternString(cx, cid.get()));
3019 ClassInfoData nameData(nsnull, "ClassID");
3020 SecurityLevel securityLevel;
3021 rv = LookupPolicy(subjectPrincipal, nameData, cidVal,
3022 nsIXPCSecurityManager::ACCESS_CALL_METHOD,
3023 nsnull, &securityLevel);
3024 if (NS_FAILED(rv))
3025 return rv;
3027 // If there's no policy stored, use the "security.classID.allowByDefault" pref
3028 if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3029 securityLevel.level = mXPCDefaultGrantAll ? SCRIPT_SECURITY_ALL_ACCESS :
3030 SCRIPT_SECURITY_NO_ACCESS;
3032 if (securityLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
3034 #ifdef DEBUG_CAPS_CheckComponentPermissions
3035 printf(" GRANTED.\n");
3036 #endif
3037 return NS_OK;
3040 #ifdef DEBUG_CAPS_CheckComponentPermissions
3041 printf(" DENIED.\n");
3042 #endif
3043 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
3045 #endif
3047 NS_IMETHODIMP
3048 nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
3049 const nsCID &aCID)
3051 #ifdef DEBUG_CAPS_CanCreateInstance
3052 char* cidStr = aCID.ToString();
3053 printf("### CanCreateInstance(%s) ", cidStr);
3054 nsCRT::free(cidStr);
3055 #endif
3057 nsresult rv = CheckXPCPermissions(nsnull, nsnull);
3058 if (NS_FAILED(rv))
3059 #ifdef XPC_IDISPATCH_SUPPORT
3061 rv = CheckComponentPermissions(cx, aCID);
3063 if (NS_FAILED(rv))
3064 #endif
3066 //-- Access denied, report an error
3067 nsCAutoString errorMsg("Permission denied to create instance of class. CID=");
3068 char cidStr[NSID_LENGTH];
3069 aCID.ToProvidedString(cidStr);
3070 errorMsg.Append(cidStr);
3071 SetPendingException(cx, errorMsg.get());
3073 #ifdef DEBUG_CAPS_CanCreateInstance
3074 printf("DENIED\n");
3076 else
3078 printf("GRANTED\n");
3079 #endif
3081 return rv;
3084 NS_IMETHODIMP
3085 nsScriptSecurityManager::CanGetService(JSContext *cx,
3086 const nsCID &aCID)
3088 #ifdef DEBUG_CAPS_CanGetService
3089 char* cidStr = aCID.ToString();
3090 printf("### CanGetService(%s) ", cidStr);
3091 nsCRT::free(cidStr);
3092 #endif
3094 nsresult rv = CheckXPCPermissions(nsnull, nsnull);
3095 if (NS_FAILED(rv))
3097 //-- Access denied, report an error
3098 nsCAutoString errorMsg("Permission denied to get service. CID=");
3099 char cidStr[NSID_LENGTH];
3100 aCID.ToProvidedString(cidStr);
3101 errorMsg.Append(cidStr);
3102 SetPendingException(cx, errorMsg.get());
3104 #ifdef DEBUG_CAPS_CanGetService
3105 printf("DENIED\n");
3107 else
3109 printf("GRANTED\n");
3110 #endif
3113 return rv;
3117 NS_IMETHODIMP
3118 nsScriptSecurityManager::CanAccess(PRUint32 aAction,
3119 nsAXPCNativeCallContext* aCallContext,
3120 JSContext* cx,
3121 JSObject* aJSObject,
3122 nsISupports* aObj,
3123 nsIClassInfo* aClassInfo,
3124 jsval aPropertyName,
3125 void** aPolicy)
3127 return CheckPropertyAccessImpl(aAction, aCallContext, cx,
3128 aJSObject, aObj, nsnull, aClassInfo,
3129 nsnull, aPropertyName, aPolicy);
3132 nsresult
3133 nsScriptSecurityManager::CheckXPCPermissions(nsISupports* aObj,
3134 const char* aObjectSecurityLevel)
3136 //-- Check for the all-powerful UniversalXPConnect privilege
3137 PRBool ok = PR_FALSE;
3138 if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok)) && ok)
3139 return NS_OK;
3141 //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
3142 if (aObjectSecurityLevel)
3144 if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
3145 return NS_OK;
3146 else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
3148 PRBool canAccess = PR_FALSE;
3149 if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel, &canAccess)) &&
3150 canAccess)
3151 return NS_OK;
3155 //-- If user allows scripting of plugins by untrusted scripts,
3156 // and the target object is a plugin, allow the access.
3157 if(aObj)
3159 nsresult rv;
3160 nsCOMPtr<nsIPluginInstance> plugin(do_QueryInterface(aObj, &rv));
3161 if (NS_SUCCEEDED(rv))
3163 static PRBool prefSet = PR_FALSE;
3164 static PRBool allowPluginAccess = PR_FALSE;
3165 if (!prefSet)
3167 rv = mSecurityPref->SecurityGetBoolPref("security.xpconnect.plugin.unrestricted",
3168 &allowPluginAccess);
3169 prefSet = PR_TRUE;
3171 if (allowPluginAccess)
3172 return NS_OK;
3176 //-- Access tests failed
3177 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
3180 //////////////////////////////////////////////
3181 // Method implementing nsIPrefSecurityCheck //
3182 //////////////////////////////////////////////
3184 NS_IMETHODIMP
3185 nsScriptSecurityManager::CanAccessSecurityPreferences(PRBool* _retval)
3187 return IsCapabilityEnabled("CapabilityPreferencesAccess", _retval);
3190 /////////////////////////////////////////////
3191 // Method implementing nsIChannelEventSink //
3192 /////////////////////////////////////////////
3193 NS_IMETHODIMP
3194 nsScriptSecurityManager::OnChannelRedirect(nsIChannel* oldChannel,
3195 nsIChannel* newChannel,
3196 PRUint32 redirFlags)
3198 nsCOMPtr<nsIPrincipal> oldPrincipal;
3199 GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
3201 nsCOMPtr<nsIURI> newURI;
3202 newChannel->GetURI(getter_AddRefs(newURI));
3203 nsCOMPtr<nsIURI> newOriginalURI;
3204 newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
3206 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
3208 const PRUint32 flags =
3209 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
3210 nsIScriptSecurityManager::DISALLOW_SCRIPT;
3211 nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
3212 if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
3213 rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
3215 return rv;
3219 /////////////////////////////////////
3220 // Method implementing nsIObserver //
3221 /////////////////////////////////////
3222 static const char sPrincipalPrefix[] = "capability.principal";
3223 static const char sPolicyPrefix[] = "capability.policy.";
3225 NS_IMETHODIMP
3226 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
3227 const PRUnichar* aMessage)
3229 nsresult rv = NS_OK;
3230 NS_ConvertUTF16toUTF8 messageStr(aMessage);
3231 const char *message = messageStr.get();
3233 static const char jsPrefix[] = "javascript.";
3234 static const char securityPrefix[] = "security.";
3235 if ((PL_strncmp(message, jsPrefix, sizeof(jsPrefix)-1) == 0) ||
3236 (PL_strncmp(message, securityPrefix, sizeof(securityPrefix)-1) == 0) )
3238 ScriptSecurityPrefChanged();
3240 else if (PL_strncmp(message, sPolicyPrefix, sizeof(sPolicyPrefix)-1) == 0)
3242 // This will force re-initialization of the pref table
3243 mPolicyPrefsChanged = PR_TRUE;
3245 else if ((PL_strncmp(message, sPrincipalPrefix, sizeof(sPrincipalPrefix)-1) == 0) &&
3246 !mIsWritingPrefs)
3248 static const char id[] = "id";
3249 char* lastDot = PL_strrchr(message, '.');
3250 //-- This check makes sure the string copy below doesn't overwrite its bounds
3251 if(PL_strlen(lastDot) >= sizeof(id))
3253 PL_strcpy(lastDot + 1, id);
3254 const char** idPrefArray = (const char**)&message;
3255 rv = InitPrincipals(1, idPrefArray, mSecurityPref);
3258 return rv;
3261 /////////////////////////////////////////////
3262 // Constructor, Destructor, Initialization //
3263 /////////////////////////////////////////////
3264 nsScriptSecurityManager::nsScriptSecurityManager(void)
3265 : mOriginToPolicyMap(nsnull),
3266 mDefaultPolicy(nsnull),
3267 mCapabilities(nsnull),
3268 mIsJavaScriptEnabled(PR_FALSE),
3269 mIsMailJavaScriptEnabled(PR_FALSE),
3270 mIsWritingPrefs(PR_FALSE),
3271 mPolicyPrefsChanged(PR_TRUE)
3272 #ifdef XPC_IDISPATCH_SUPPORT
3273 , mXPCDefaultGrantAll(PR_FALSE)
3274 #endif
3276 NS_ASSERTION(sizeof(long) == sizeof(void*), "long and void* have different lengths on this platform. This may cause a security failure.");
3277 mPrincipals.Init(31);
3281 nsresult nsScriptSecurityManager::Init()
3283 JSContext* cx = GetSafeJSContext();
3284 if (!cx) return NS_ERROR_FAILURE; // this can happen of xpt loading fails
3286 ::JS_BeginRequest(cx);
3287 if (sEnabledID == JSVAL_VOID)
3288 sEnabledID = STRING_TO_JSVAL(::JS_InternString(cx, "enabled"));
3289 ::JS_EndRequest(cx);
3291 nsresult rv = InitPrefs();
3292 NS_ENSURE_SUCCESS(rv, rv);
3294 rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
3295 NS_ENSURE_SUCCESS(rv, rv);
3297 rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
3298 NS_ENSURE_SUCCESS(rv, rv);
3300 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
3301 NS_ENSURE_SUCCESS(rv, rv);
3303 rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
3304 NS_ENSURE_SUCCESS(rv, rv);
3306 // Create our system principal singleton
3307 nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
3308 NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
3310 rv = system->Init();
3311 NS_ENSURE_SUCCESS(rv, rv);
3313 mSystemPrincipal = system;
3315 //-- Register security check callback in the JS engine
3316 // Currently this is used to control access to function.caller
3317 nsCOMPtr<nsIJSRuntimeService> runtimeService =
3318 do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv);
3319 NS_ENSURE_SUCCESS(rv, rv);
3321 rv = runtimeService->GetRuntime(&sRuntime);
3322 NS_ENSURE_SUCCESS(rv, rv);
3324 #ifdef DEBUG
3325 JSCheckAccessOp oldCallback =
3326 #endif
3327 JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);
3329 sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
3330 &sXPCWrappedNativeGetObjOps1,
3331 &sXPCWrappedNativeGetObjOps2);
3333 // For now, assert that no callback was set previously
3334 NS_ASSERTION(!oldCallback, "Someone already set a JS CheckObjectAccess callback");
3335 return NS_OK;
3338 static nsScriptSecurityManager *gScriptSecMan = nsnull;
3340 jsval nsScriptSecurityManager::sEnabledID = JSVAL_VOID;
3342 nsScriptSecurityManager::~nsScriptSecurityManager(void)
3344 delete mOriginToPolicyMap;
3345 if(mDefaultPolicy)
3346 mDefaultPolicy->Drop();
3347 delete mCapabilities;
3348 gScriptSecMan = nsnull;
3351 void
3352 nsScriptSecurityManager::Shutdown()
3354 if (sRuntime) {
3355 #ifdef DEBUG
3356 JSCheckAccessOp oldCallback =
3357 #endif
3358 JS_SetCheckObjectAccessCallback(sRuntime, nsnull);
3359 NS_ASSERTION(oldCallback == CheckObjectAccess, "Oops, we just clobbered someone else, oh well.");
3360 sRuntime = nsnull;
3362 sEnabledID = JSVAL_VOID;
3364 NS_IF_RELEASE(sIOService);
3365 NS_IF_RELEASE(sXPConnect);
3366 NS_IF_RELEASE(sStrBundle);
3369 nsScriptSecurityManager *
3370 nsScriptSecurityManager::GetScriptSecurityManager()
3372 if (!gScriptSecMan)
3374 nsScriptSecurityManager* ssManager = new nsScriptSecurityManager();
3375 if (!ssManager)
3376 return nsnull;
3377 nsresult rv;
3378 rv = ssManager->Init();
3379 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
3380 if (NS_FAILED(rv)) {
3381 delete ssManager;
3382 return nsnull;
3385 rv = nsJSPrincipals::Startup();
3386 if (NS_FAILED(rv)) {
3387 NS_WARNING("can't initialize JS engine security protocol glue!");
3388 delete ssManager;
3389 return nsnull;
3392 rv = sXPConnect->SetDefaultSecurityManager(ssManager,
3393 nsIXPCSecurityManager::HOOK_ALL);
3394 if (NS_FAILED(rv)) {
3395 NS_WARNING("Failed to install xpconnect security manager!");
3396 delete ssManager;
3397 return nsnull;
3400 gScriptSecMan = ssManager;
3402 return gScriptSecMan;
3405 // Currently this nsGenericFactory constructor is used only from FastLoad
3406 // (XPCOM object deserialization) code, when "creating" the system principal
3407 // singleton.
3408 nsSystemPrincipal *
3409 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
3411 nsIPrincipal *sysprin = nsnull;
3412 if (gScriptSecMan)
3413 NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
3414 return static_cast<nsSystemPrincipal*>(sysprin);
3417 nsresult
3418 nsScriptSecurityManager::InitPolicies()
3420 // Clear any policies cached on XPConnect wrappers
3421 NS_ENSURE_STATE(sXPConnect);
3422 nsresult rv = sXPConnect->ClearAllWrappedNativeSecurityPolicies();
3423 if (NS_FAILED(rv)) return rv;
3425 //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
3426 //-- whose dtor decrements refcount of stored DomainPolicy object
3427 delete mOriginToPolicyMap;
3429 //-- Marks all the survivor DomainPolicy objects (those cached
3430 //-- by nsPrincipal objects) as invalid: they will be released
3431 //-- on first nsPrincipal::GetSecurityPolicy() attempt.
3432 DomainPolicy::InvalidateAll();
3434 //-- Release old default policy
3435 if(mDefaultPolicy) {
3436 mDefaultPolicy->Drop();
3437 mDefaultPolicy = nsnull;
3440 //-- Initialize a new mOriginToPolicyMap
3441 mOriginToPolicyMap =
3442 new nsObjectHashtable(nsnull, nsnull, DeleteDomainEntry, nsnull);
3443 if (!mOriginToPolicyMap)
3444 return NS_ERROR_OUT_OF_MEMORY;
3446 //-- Create, refcount and initialize a new default policy
3447 mDefaultPolicy = new DomainPolicy();
3448 if (!mDefaultPolicy)
3449 return NS_ERROR_OUT_OF_MEMORY;
3451 mDefaultPolicy->Hold();
3452 if (!mDefaultPolicy->Init())
3453 return NS_ERROR_UNEXPECTED;
3455 //-- Initialize the table of security levels
3456 if (!mCapabilities)
3458 mCapabilities =
3459 new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
3460 if (!mCapabilities)
3461 return NS_ERROR_OUT_OF_MEMORY;
3464 // Get a JS context - we need it to create internalized strings later.
3465 JSContext* cx = GetSafeJSContext();
3466 NS_ASSERTION(cx, "failed to get JS context");
3467 rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
3468 NS_ENSURE_SUCCESS(rv, rv);
3470 nsXPIDLCString policyNames;
3471 rv = mSecurityPref->SecurityGetCharPref("capability.policy.policynames",
3472 getter_Copies(policyNames));
3474 nsXPIDLCString defaultPolicyNames;
3475 rv = mSecurityPref->SecurityGetCharPref("capability.policy.default_policynames",
3476 getter_Copies(defaultPolicyNames));
3477 policyNames += NS_LITERAL_CSTRING(" ") + defaultPolicyNames;
3479 //-- Initialize domain policies
3480 char* policyCurrent = policyNames.BeginWriting();
3481 PRBool morePolicies = PR_TRUE;
3482 while (morePolicies)
3484 while(*policyCurrent == ' ' || *policyCurrent == ',')
3485 policyCurrent++;
3486 if (*policyCurrent == '\0')
3487 break;
3488 char* nameBegin = policyCurrent;
3490 while(*policyCurrent != '\0' && *policyCurrent != ' ' && *policyCurrent != ',')
3491 policyCurrent++;
3493 morePolicies = (*policyCurrent != '\0');
3494 *policyCurrent = '\0';
3495 policyCurrent++;
3497 nsCAutoString sitesPrefName(
3498 NS_LITERAL_CSTRING(sPolicyPrefix) +
3499 nsDependentCString(nameBegin) +
3500 NS_LITERAL_CSTRING(".sites"));
3501 nsXPIDLCString domainList;
3502 rv = mSecurityPref->SecurityGetCharPref(sitesPrefName.get(),
3503 getter_Copies(domainList));
3504 if (NS_FAILED(rv))
3505 continue;
3507 DomainPolicy* domainPolicy = new DomainPolicy();
3508 if (!domainPolicy)
3509 return NS_ERROR_OUT_OF_MEMORY;
3511 if (!domainPolicy->Init())
3513 delete domainPolicy;
3514 return NS_ERROR_UNEXPECTED;
3516 domainPolicy->Hold();
3517 //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
3518 char* domainStart = domainList.BeginWriting();
3519 char* domainCurrent = domainStart;
3520 char* lastDot = nsnull;
3521 char* nextToLastDot = nsnull;
3522 PRBool moreDomains = PR_TRUE;
3523 while (moreDomains)
3525 if (*domainCurrent == ' ' || *domainCurrent == '\0')
3527 moreDomains = (*domainCurrent != '\0');
3528 *domainCurrent = '\0';
3529 nsCStringKey key(nextToLastDot ? nextToLastDot+1 : domainStart);
3530 DomainEntry *newEntry = new DomainEntry(domainStart, domainPolicy);
3531 if (!newEntry)
3533 domainPolicy->Drop();
3534 return NS_ERROR_OUT_OF_MEMORY;
3536 #ifdef DEBUG
3537 newEntry->mPolicyName_DEBUG = nameBegin;
3538 #endif
3539 DomainEntry *existingEntry = (DomainEntry *)
3540 mOriginToPolicyMap->Get(&key);
3541 if (!existingEntry)
3542 mOriginToPolicyMap->Put(&key, newEntry);
3543 else
3545 if (existingEntry->Matches(domainStart))
3547 newEntry->mNext = existingEntry;
3548 mOriginToPolicyMap->Put(&key, newEntry);
3550 else
3552 while (existingEntry->mNext)
3554 if (existingEntry->mNext->Matches(domainStart))
3556 newEntry->mNext = existingEntry->mNext;
3557 existingEntry->mNext = newEntry;
3558 break;
3560 existingEntry = existingEntry->mNext;
3562 if (!existingEntry->mNext)
3563 existingEntry->mNext = newEntry;
3566 domainStart = domainCurrent + 1;
3567 lastDot = nextToLastDot = nsnull;
3569 else if (*domainCurrent == '.')
3571 nextToLastDot = lastDot;
3572 lastDot = domainCurrent;
3574 domainCurrent++;
3577 rv = InitDomainPolicy(cx, nameBegin, domainPolicy);
3578 domainPolicy->Drop();
3579 if (NS_FAILED(rv))
3580 return rv;
3583 // Reset the "dirty" flag
3584 mPolicyPrefsChanged = PR_FALSE;
3586 #ifdef DEBUG_CAPS_HACKER
3587 PrintPolicyDB();
3588 #endif
3589 return NS_OK;
3593 nsresult
3594 nsScriptSecurityManager::InitDomainPolicy(JSContext* cx,
3595 const char* aPolicyName,
3596 DomainPolicy* aDomainPolicy)
3598 nsresult rv;
3599 nsCAutoString policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix) +
3600 nsDependentCString(aPolicyName) +
3601 NS_LITERAL_CSTRING("."));
3602 PRUint32 prefixLength = policyPrefix.Length() - 1; // subtract the '.'
3604 PRUint32 prefCount;
3605 char** prefNames;
3606 rv = mPrefBranch->GetChildList(policyPrefix.get(),
3607 &prefCount, &prefNames);
3608 if (NS_FAILED(rv)) return rv;
3609 if (prefCount == 0)
3610 return NS_OK;
3612 //-- Populate the policy
3613 PRUint32 currentPref = 0;
3614 for (; currentPref < prefCount; currentPref++)
3616 // Get the class name
3617 const char* start = prefNames[currentPref] + prefixLength + 1;
3618 char* end = PL_strchr(start, '.');
3619 if (!end) // malformed pref, bail on this one
3620 continue;
3621 static const char sitesStr[] = "sites";
3623 // We dealt with "sites" in InitPolicies(), so no need to do
3624 // that again...
3625 if (PL_strncmp(start, sitesStr, sizeof(sitesStr)-1) == 0)
3626 continue;
3628 // Get the pref value
3629 nsXPIDLCString prefValue;
3630 rv = mSecurityPref->SecurityGetCharPref(prefNames[currentPref],
3631 getter_Copies(prefValue));
3632 if (NS_FAILED(rv) || !prefValue)
3633 continue;
3635 SecurityLevel secLevel;
3636 if (PL_strcasecmp(prefValue, "noAccess") == 0)
3637 secLevel.level = SCRIPT_SECURITY_NO_ACCESS;
3638 else if (PL_strcasecmp(prefValue, "allAccess") == 0)
3639 secLevel.level = SCRIPT_SECURITY_ALL_ACCESS;
3640 else if (PL_strcasecmp(prefValue, "sameOrigin") == 0)
3641 secLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
3642 else
3643 { //-- pref value is the name of a capability
3644 nsCStringKey secLevelKey(prefValue);
3645 secLevel.capability =
3646 reinterpret_cast<char*>(mCapabilities->Get(&secLevelKey));
3647 if (!secLevel.capability)
3649 secLevel.capability = NS_strdup(prefValue);
3650 if (!secLevel.capability)
3651 break;
3652 mCapabilities->Put(&secLevelKey,
3653 secLevel.capability);
3657 *end = '\0';
3658 // Find or store this class in the classes table
3659 ClassPolicy* cpolicy =
3660 static_cast<ClassPolicy*>
3661 (PL_DHashTableOperate(aDomainPolicy, start,
3662 PL_DHASH_ADD));
3663 if (!cpolicy)
3664 break;
3666 // If this is the wildcard class (class '*'), save it in mWildcardPolicy
3667 // (we leave it stored in the hashtable too to take care of the cleanup)
3668 if ((*start == '*') && (end == start + 1)) {
3669 aDomainPolicy->mWildcardPolicy = cpolicy;
3671 // Make sure that cpolicy knows about aDomainPolicy so it can reset
3672 // the mWildcardPolicy pointer as needed if it gets moved in the
3673 // hashtable.
3674 cpolicy->mDomainWeAreWildcardFor = aDomainPolicy;
3677 // Get the property name
3678 start = end + 1;
3679 end = PL_strchr(start, '.');
3680 if (end)
3681 *end = '\0';
3683 JSAutoRequest ar(cx);
3685 JSString* propertyKey = ::JS_InternString(cx, start);
3686 if (!propertyKey)
3687 return NS_ERROR_OUT_OF_MEMORY;
3689 // Store this property in the class policy
3690 const void* ppkey =
3691 reinterpret_cast<const void*>(STRING_TO_JSVAL(propertyKey));
3692 PropertyPolicy* ppolicy =
3693 static_cast<PropertyPolicy*>
3694 (PL_DHashTableOperate(cpolicy->mPolicy, ppkey,
3695 PL_DHASH_ADD));
3696 if (!ppolicy)
3697 break;
3699 if (end) // The pref specifies an access mode
3701 start = end + 1;
3702 if (PL_strcasecmp(start, "set") == 0)
3703 ppolicy->mSet = secLevel;
3704 else
3705 ppolicy->mGet = secLevel;
3707 else
3709 if (ppolicy->mGet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3710 ppolicy->mGet = secLevel;
3711 if (ppolicy->mSet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3712 ppolicy->mSet = secLevel;
3716 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3717 if (currentPref < prefCount) // Loop exited early because of out-of-memory error
3718 return NS_ERROR_OUT_OF_MEMORY;
3719 return NS_OK;
3723 // XXXbz We should really just get a prefbranch to handle this...
3724 nsresult
3725 nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase,
3726 nsCString& grantedPref,
3727 nsCString& deniedPref,
3728 nsCString& subjectNamePref)
3730 char* lastDot = PL_strrchr(prefBase, '.');
3731 if (!lastDot) return NS_ERROR_FAILURE;
3732 PRInt32 prefLen = lastDot - prefBase + 1;
3734 grantedPref.Assign(prefBase, prefLen);
3735 deniedPref.Assign(prefBase, prefLen);
3736 subjectNamePref.Assign(prefBase, prefLen);
3738 #define GRANTED "granted"
3739 #define DENIED "denied"
3740 #define SUBJECTNAME "subjectName"
3742 grantedPref.AppendLiteral(GRANTED);
3743 if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) {
3744 return NS_ERROR_OUT_OF_MEMORY;
3747 deniedPref.AppendLiteral(DENIED);
3748 if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) {
3749 return NS_ERROR_OUT_OF_MEMORY;
3752 subjectNamePref.AppendLiteral(SUBJECTNAME);
3753 if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) {
3754 return NS_ERROR_OUT_OF_MEMORY;
3757 #undef SUBJECTNAME
3758 #undef DENIED
3759 #undef GRANTED
3761 return NS_OK;
3764 nsresult
3765 nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefNames,
3766 nsISecurityPref* aSecurityPref)
3768 /* This is the principal preference syntax:
3769 * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
3770 * For example:
3771 * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
3772 * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
3773 * user_pref("capability.principal.certificate.p1.denied","Capability3");
3776 /* codebaseTrusted means a codebase principal that can enable capabilities even if
3777 * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
3778 * URLs such as HTTPS URLs.
3781 static const char idSuffix[] = ".id";
3782 for (PRUint32 c = 0; c < aPrefCount; c++)
3784 PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) -
3785 (NS_ARRAY_LENGTH(idSuffix) - 1);
3786 if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0)
3787 continue;
3789 nsXPIDLCString id;
3790 if (NS_FAILED(mSecurityPref->SecurityGetCharPref(aPrefNames[c], getter_Copies(id))))
3791 return NS_ERROR_FAILURE;
3793 nsCAutoString grantedPrefName;
3794 nsCAutoString deniedPrefName;
3795 nsCAutoString subjectNamePrefName;
3796 nsresult rv = GetPrincipalPrefNames(aPrefNames[c],
3797 grantedPrefName,
3798 deniedPrefName,
3799 subjectNamePrefName);
3800 if (rv == NS_ERROR_OUT_OF_MEMORY)
3801 return rv;
3802 if (NS_FAILED(rv))
3803 continue;
3805 nsXPIDLCString grantedList;
3806 mSecurityPref->SecurityGetCharPref(grantedPrefName.get(),
3807 getter_Copies(grantedList));
3808 nsXPIDLCString deniedList;
3809 mSecurityPref->SecurityGetCharPref(deniedPrefName.get(),
3810 getter_Copies(deniedList));
3811 nsXPIDLCString subjectName;
3812 mSecurityPref->SecurityGetCharPref(subjectNamePrefName.get(),
3813 getter_Copies(subjectName));
3815 //-- Delete prefs if their value is the empty string
3816 if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty()))
3818 mSecurityPref->SecurityClearUserPref(aPrefNames[c]);
3819 mSecurityPref->SecurityClearUserPref(grantedPrefName.get());
3820 mSecurityPref->SecurityClearUserPref(deniedPrefName.get());
3821 mSecurityPref->SecurityClearUserPref(subjectNamePrefName.get());
3822 continue;
3825 //-- Create a principal based on the prefs
3826 static const char certificateName[] = "capability.principal.certificate";
3827 static const char codebaseName[] = "capability.principal.codebase";
3828 static const char codebaseTrustedName[] = "capability.principal.codebaseTrusted";
3830 PRBool isCert = PR_FALSE;
3831 PRBool isTrusted = PR_FALSE;
3833 if (PL_strncmp(aPrefNames[c], certificateName,
3834 sizeof(certificateName) - 1) == 0)
3836 isCert = PR_TRUE;
3838 else if (PL_strncmp(aPrefNames[c], codebaseName,
3839 sizeof(codebaseName) - 1) == 0)
3841 isTrusted = (PL_strncmp(aPrefNames[c], codebaseTrustedName,
3842 sizeof(codebaseTrustedName) - 1) == 0);
3844 else
3846 NS_ERROR("Not a codebase or a certificate?!");
3849 nsRefPtr<nsPrincipal> newPrincipal = new nsPrincipal();
3850 if (!newPrincipal)
3851 return NS_ERROR_OUT_OF_MEMORY;
3853 rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
3854 EmptyCString(),
3855 grantedList, deniedList, nsnull,
3856 isCert, isTrusted);
3857 if (NS_SUCCEEDED(rv))
3858 mPrincipals.Put(newPrincipal, newPrincipal);
3860 return NS_OK;
3863 const char nsScriptSecurityManager::sJSEnabledPrefName[] =
3864 "javascript.enabled";
3865 const char nsScriptSecurityManager::sJSMailEnabledPrefName[] =
3866 "javascript.allow.mailnews";
3867 const char nsScriptSecurityManager::sFileOriginPolicyPrefName[] =
3868 "security.fileuri.strict_origin_policy";
3869 #ifdef XPC_IDISPATCH_SUPPORT
3870 const char nsScriptSecurityManager::sXPCDefaultGrantAllName[] =
3871 "security.classID.allowByDefault";
3872 #endif
3874 inline void
3875 nsScriptSecurityManager::ScriptSecurityPrefChanged()
3877 PRBool temp;
3878 nsresult rv = mSecurityPref->SecurityGetBoolPref(sJSEnabledPrefName, &temp);
3879 // JavaScript defaults to enabled in failure cases.
3880 mIsJavaScriptEnabled = NS_FAILED(rv) || temp;
3882 rv = mSecurityPref->SecurityGetBoolPref(sJSMailEnabledPrefName, &temp);
3883 // JavaScript in Mail defaults to disabled in failure cases.
3884 mIsMailJavaScriptEnabled = NS_SUCCEEDED(rv) && temp;
3886 rv = mSecurityPref->SecurityGetBoolPref(sFileOriginPolicyPrefName, &temp);
3887 sStrictFileOriginPolicy = NS_SUCCEEDED(rv) && temp;
3889 #ifdef XPC_IDISPATCH_SUPPORT
3890 rv = mSecurityPref->SecurityGetBoolPref(sXPCDefaultGrantAllName, &temp);
3891 // Granting XPC Priveleges defaults to disabled in failure cases.
3892 mXPCDefaultGrantAll = NS_SUCCEEDED(rv) && temp;
3893 #endif
3896 nsresult
3897 nsScriptSecurityManager::InitPrefs()
3899 nsresult rv;
3900 nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
3901 NS_ENSURE_SUCCESS(rv, rv);
3902 rv = prefService->GetBranch(nsnull, getter_AddRefs(mPrefBranch));
3903 NS_ENSURE_SUCCESS(rv, rv);
3904 nsCOMPtr<nsIPrefBranch2> prefBranchInternal(do_QueryInterface(mPrefBranch, &rv));
3905 NS_ENSURE_SUCCESS(rv, rv);
3906 mSecurityPref = do_QueryInterface(mPrefBranch, &rv);
3907 NS_ENSURE_SUCCESS(rv, rv);
3909 // Set the initial value of the "javascript.enabled" prefs
3910 ScriptSecurityPrefChanged();
3911 // set observer callbacks in case the value of the prefs change
3912 prefBranchInternal->AddObserver(sJSEnabledPrefName, this, PR_FALSE);
3913 prefBranchInternal->AddObserver(sJSMailEnabledPrefName, this, PR_FALSE);
3914 prefBranchInternal->AddObserver(sFileOriginPolicyPrefName, this, PR_FALSE);
3915 #ifdef XPC_IDISPATCH_SUPPORT
3916 prefBranchInternal->AddObserver(sXPCDefaultGrantAllName, this, PR_FALSE);
3917 #endif
3918 PRUint32 prefCount;
3919 char** prefNames;
3921 // Set a callback for policy pref changes
3922 prefBranchInternal->AddObserver(sPolicyPrefix, this, PR_FALSE);
3924 //-- Initialize the principals database from prefs
3925 rv = mPrefBranch->GetChildList(sPrincipalPrefix, &prefCount, &prefNames);
3926 if (NS_SUCCEEDED(rv) && prefCount > 0)
3928 rv = InitPrincipals(prefCount, (const char**)prefNames, mSecurityPref);
3929 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3930 NS_ENSURE_SUCCESS(rv, rv);
3932 //-- Set a callback for principal changes
3933 prefBranchInternal->AddObserver(sPrincipalPrefix, this, PR_FALSE);
3935 return NS_OK;
3938 ///////////////////////////////////////////////////////////////////////////////
3939 // The following code prints the contents of the policy DB to the console.
3940 #ifdef DEBUG_CAPS_HACKER
3942 //typedef PLDHashOperator
3943 //(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
3944 // PRUint32 number, void *arg);
3945 PR_STATIC_CALLBACK(PLDHashOperator)
3946 PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3947 PRUint32 number, void *arg)
3949 PropertyPolicy* pp = (PropertyPolicy*)entry;
3950 nsCAutoString prop(" ");
3951 JSContext* cx = (JSContext*)arg;
3952 prop.AppendInt((PRUint32)pp->key);
3953 prop += ' ';
3954 prop.AppendWithConversion((PRUnichar*)JSValIDToString(cx, pp->key));
3955 prop += ": Get=";
3956 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet))
3957 prop.AppendInt(pp->mGet.level);
3958 else
3959 prop += pp->mGet.capability;
3961 prop += " Set=";
3962 if (SECURITY_ACCESS_LEVEL_FLAG(pp->mSet))
3963 prop.AppendInt(pp->mSet.level);
3964 else
3965 prop += pp->mSet.capability;
3967 printf("%s.\n", prop.get());
3968 return PL_DHASH_NEXT;
3971 PR_STATIC_CALLBACK(PLDHashOperator)
3972 PrintClassPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3973 PRUint32 number, void *arg)
3975 ClassPolicy* cp = (ClassPolicy*)entry;
3976 printf(" %s\n", cp->key);
3978 PL_DHashTableEnumerate(cp->mPolicy, PrintPropertyPolicy, arg);
3979 return PL_DHASH_NEXT;
3982 // typedef PRBool
3983 // (*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
3984 PR_STATIC_CALLBACK(PRBool)
3985 PrintDomainPolicy(nsHashKey *aKey, void *aData, void* aClosure)
3987 DomainEntry* de = (DomainEntry*)aData;
3988 printf("----------------------------\n");
3989 printf("Domain: %s Policy Name: %s.\n", de->mOrigin.get(),
3990 de->mPolicyName_DEBUG.get());
3991 PL_DHashTableEnumerate(de->mDomainPolicy, PrintClassPolicy, aClosure);
3992 return PR_TRUE;
3995 PR_STATIC_CALLBACK(PRBool)
3996 PrintCapability(nsHashKey *aKey, void *aData, void* aClosure)
3998 char* cap = (char*)aData;
3999 printf(" %s.\n", cap);
4000 return PR_TRUE;
4003 void
4004 nsScriptSecurityManager::PrintPolicyDB()
4006 printf("############## Security Policies ###############\n");
4007 if(mOriginToPolicyMap)
4009 JSContext* cx = GetCurrentJSContext();
4010 if (!cx)
4011 cx = GetSafeJSContext();
4012 printf("----------------------------\n");
4013 printf("Domain: Default.\n");
4014 PL_DHashTableEnumerate(mDefaultPolicy, PrintClassPolicy, (void*)cx);
4015 mOriginToPolicyMap->Enumerate(PrintDomainPolicy, (void*)cx);
4017 printf("############ End Security Policies #############\n\n");
4018 printf("############## Capabilities ###############\n");
4019 mCapabilities->Enumerate(PrintCapability);
4020 printf("############## End Capabilities ###############\n");
4022 #endif