caps/src/nsScriptSecurityManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/caps/src/nsScriptSecurityManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1663 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set ts=4 et sw=4 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "nsScriptSecurityManager.h"
    1.11 +
    1.12 +#include "mozilla/ArrayUtils.h"
    1.13 +
    1.14 +#include "js/OldDebugAPI.h"
    1.15 +#include "xpcprivate.h"
    1.16 +#include "XPCWrapper.h"
    1.17 +#include "nsIServiceManager.h"
    1.18 +#include "nsIScriptObjectPrincipal.h"
    1.19 +#include "nsIScriptContext.h"
    1.20 +#include "nsIURL.h"
    1.21 +#include "nsINestedURI.h"
    1.22 +#include "nspr.h"
    1.23 +#include "nsJSPrincipals.h"
    1.24 +#include "nsSystemPrincipal.h"
    1.25 +#include "nsPrincipal.h"
    1.26 +#include "nsNullPrincipal.h"
    1.27 +#include "DomainPolicy.h"
    1.28 +#include "nsXPIDLString.h"
    1.29 +#include "nsCRT.h"
    1.30 +#include "nsCRTGlue.h"
    1.31 +#include "nsError.h"
    1.32 +#include "nsDOMCID.h"
    1.33 +#include "nsIXPConnect.h"
    1.34 +#include "nsIXPCSecurityManager.h"
    1.35 +#include "nsTextFormatter.h"
    1.36 +#include "nsIStringBundle.h"
    1.37 +#include "nsNetUtil.h"
    1.38 +#include "nsIEffectiveTLDService.h"
    1.39 +#include "nsIProperties.h"
    1.40 +#include "nsDirectoryServiceDefs.h"
    1.41 +#include "nsIFile.h"
    1.42 +#include "nsIFileURL.h"
    1.43 +#include "nsIZipReader.h"
    1.44 +#include "nsIXPConnect.h"
    1.45 +#include "nsIScriptGlobalObject.h"
    1.46 +#include "nsPIDOMWindow.h"
    1.47 +#include "nsIDocShell.h"
    1.48 +#include "nsIPrompt.h"
    1.49 +#include "nsIWindowWatcher.h"
    1.50 +#include "nsIConsoleService.h"
    1.51 +#include "nsIJSRuntimeService.h"
    1.52 +#include "nsIObserverService.h"
    1.53 +#include "nsIContent.h"
    1.54 +#include "nsAutoPtr.h"
    1.55 +#include "nsDOMJSUtils.h"
    1.56 +#include "nsAboutProtocolUtils.h"
    1.57 +#include "nsIClassInfo.h"
    1.58 +#include "nsIURIFixup.h"
    1.59 +#include "nsCDefaultURIFixup.h"
    1.60 +#include "nsIChromeRegistry.h"
    1.61 +#include "nsIContentSecurityPolicy.h"
    1.62 +#include "nsIAsyncVerifyRedirectCallback.h"
    1.63 +#include "mozilla/Preferences.h"
    1.64 +#include "mozilla/dom/BindingUtils.h"
    1.65 +#include <stdint.h>
    1.66 +#include "mozilla/ClearOnShutdown.h"
    1.67 +#include "mozilla/StaticPtr.h"
    1.68 +#include "nsContentUtils.h"
    1.69 +#include "nsCxPusher.h"
    1.70 +#include "nsJSUtils.h"
    1.71 +
    1.72 +// This should be probably defined on some other place... but I couldn't find it
    1.73 +#define WEBAPPS_PERM_NAME "webapps-manage"
    1.74 +
    1.75 +using namespace mozilla;
    1.76 +using namespace mozilla::dom;
    1.77 +
    1.78 +static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
    1.79 +
    1.80 +nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
    1.81 +nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr;
    1.82 +JSRuntime       *nsScriptSecurityManager::sRuntime   = 0;
    1.83 +bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
    1.84 +
    1.85 +bool
    1.86 +nsScriptSecurityManager::SubjectIsPrivileged()
    1.87 +{
    1.88 +    JSContext *cx = GetCurrentJSContext();
    1.89 +    if (cx && xpc::IsUniversalXPConnectEnabled(cx))
    1.90 +        return true;
    1.91 +    bool isSystem = false;
    1.92 +    return NS_SUCCEEDED(SubjectPrincipalIsSystem(&isSystem)) && isSystem;
    1.93 +}
    1.94 +
    1.95 +///////////////////////////
    1.96 +// Convenience Functions //
    1.97 +///////////////////////////
    1.98 +// Result of this function should not be freed.
    1.99 +static inline const char16_t *
   1.100 +IDToString(JSContext *cx, jsid id_)
   1.101 +{
   1.102 +    JS::RootedId id(cx, id_);
   1.103 +    if (JSID_IS_STRING(id))
   1.104 +        return JS_GetInternedStringChars(JSID_TO_STRING(id));
   1.105 +
   1.106 +    JS::Rooted<JS::Value> idval(cx);
   1.107 +    if (!JS_IdToValue(cx, id, &idval))
   1.108 +        return nullptr;
   1.109 +    JSString *str = JS::ToString(cx, idval);
   1.110 +    if(!str)
   1.111 +        return nullptr;
   1.112 +    return JS_GetStringCharsZ(cx, str);
   1.113 +}
   1.114 +
   1.115 +class nsAutoInPrincipalDomainOriginSetter {
   1.116 +public:
   1.117 +    nsAutoInPrincipalDomainOriginSetter() {
   1.118 +        ++sInPrincipalDomainOrigin;
   1.119 +    }
   1.120 +    ~nsAutoInPrincipalDomainOriginSetter() {
   1.121 +        --sInPrincipalDomainOrigin;
   1.122 +    }
   1.123 +    static uint32_t sInPrincipalDomainOrigin;
   1.124 +};
   1.125 +uint32_t nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
   1.126 +
   1.127 +static
   1.128 +nsresult
   1.129 +GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin)
   1.130 +{
   1.131 +  if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
   1.132 +      // Allow a single recursive call to GetPrincipalDomainOrigin, since that
   1.133 +      // might be happening on a different principal from the first call.  But
   1.134 +      // after that, cut off the recursion; it just indicates that something
   1.135 +      // we're doing in this method causes us to reenter a security check here.
   1.136 +      return NS_ERROR_NOT_AVAILABLE;
   1.137 +  }
   1.138 +
   1.139 +  nsAutoInPrincipalDomainOriginSetter autoSetter;
   1.140 +
   1.141 +  nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
   1.142 +  NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
   1.143 +
   1.144 +  nsAutoCString hostPort;
   1.145 +
   1.146 +  nsresult rv = uri->GetHostPort(hostPort);
   1.147 +  if (NS_SUCCEEDED(rv)) {
   1.148 +    nsAutoCString scheme;
   1.149 +    rv = uri->GetScheme(scheme);
   1.150 +    NS_ENSURE_SUCCESS(rv, rv);
   1.151 +    aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
   1.152 +  }
   1.153 +  else {
   1.154 +    // Some URIs (e.g., nsSimpleURI) don't support host. Just
   1.155 +    // get the full spec.
   1.156 +    rv = uri->GetSpec(aOrigin);
   1.157 +    NS_ENSURE_SUCCESS(rv, rv);
   1.158 +  }
   1.159 +
   1.160 +  return NS_OK;
   1.161 +}
   1.162 +
   1.163 +static
   1.164 +nsresult
   1.165 +GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
   1.166 +                         nsACString& aOrigin)
   1.167 +{
   1.168 +
   1.169 +  nsCOMPtr<nsIURI> uri;
   1.170 +  aPrincipal->GetDomain(getter_AddRefs(uri));
   1.171 +  if (!uri) {
   1.172 +    aPrincipal->GetURI(getter_AddRefs(uri));
   1.173 +  }
   1.174 +  NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
   1.175 +
   1.176 +  return GetOriginFromURI(uri, aOrigin);
   1.177 +}
   1.178 +
   1.179 +inline void SetPendingException(JSContext *cx, const char *aMsg)
   1.180 +{
   1.181 +    JS_ReportError(cx, "%s", aMsg);
   1.182 +}
   1.183 +
   1.184 +inline void SetPendingException(JSContext *cx, const char16_t *aMsg)
   1.185 +{
   1.186 +    JS_ReportError(cx, "%hs", aMsg);
   1.187 +}
   1.188 +
   1.189 +// Helper class to get stuff from the ClassInfo and not waste extra time with
   1.190 +// virtual method calls for things it has already gotten
   1.191 +class ClassInfoData
   1.192 +{
   1.193 +public:
   1.194 +    ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
   1.195 +        : mClassInfo(aClassInfo),
   1.196 +          mName(const_cast<char *>(aName)),
   1.197 +          mDidGetFlags(false),
   1.198 +          mMustFreeName(false)
   1.199 +    {
   1.200 +    }
   1.201 +
   1.202 +    ~ClassInfoData()
   1.203 +    {
   1.204 +        if (mMustFreeName)
   1.205 +            nsMemory::Free(mName);
   1.206 +    }
   1.207 +
   1.208 +    uint32_t GetFlags()
   1.209 +    {
   1.210 +        if (!mDidGetFlags) {
   1.211 +            if (mClassInfo) {
   1.212 +                nsresult rv = mClassInfo->GetFlags(&mFlags);
   1.213 +                if (NS_FAILED(rv)) {
   1.214 +                    mFlags = 0;
   1.215 +                }
   1.216 +            } else {
   1.217 +                mFlags = 0;
   1.218 +            }
   1.219 +
   1.220 +            mDidGetFlags = true;
   1.221 +        }
   1.222 +
   1.223 +        return mFlags;
   1.224 +    }
   1.225 +
   1.226 +    bool IsDOMClass()
   1.227 +    {
   1.228 +        return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
   1.229 +    }
   1.230 +
   1.231 +    const char* GetName()
   1.232 +    {
   1.233 +        if (!mName) {
   1.234 +            if (mClassInfo) {
   1.235 +                mClassInfo->GetClassDescription(&mName);
   1.236 +            }
   1.237 +
   1.238 +            if (mName) {
   1.239 +                mMustFreeName = true;
   1.240 +            } else {
   1.241 +                mName = const_cast<char *>("UnnamedClass");
   1.242 +            }
   1.243 +        }
   1.244 +
   1.245 +        return mName;
   1.246 +    }
   1.247 +
   1.248 +private:
   1.249 +    nsIClassInfo *mClassInfo; // WEAK
   1.250 +    uint32_t mFlags;
   1.251 +    char *mName;
   1.252 +    bool mDidGetFlags;
   1.253 +    bool mMustFreeName;
   1.254 +};
   1.255 +
   1.256 +JSContext *
   1.257 +nsScriptSecurityManager::GetCurrentJSContext()
   1.258 +{
   1.259 +    // Get JSContext from stack.
   1.260 +    return nsXPConnect::XPConnect()->GetCurrentJSContext();
   1.261 +}
   1.262 +
   1.263 +JSContext *
   1.264 +nsScriptSecurityManager::GetSafeJSContext()
   1.265 +{
   1.266 +    // Get JSContext from stack.
   1.267 +    return nsXPConnect::XPConnect()->GetSafeJSContext();
   1.268 +}
   1.269 +
   1.270 +/* static */
   1.271 +bool
   1.272 +nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
   1.273 +                                             nsIURI* aTargetURI)
   1.274 +{
   1.275 +    return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
   1.276 +}
   1.277 +
   1.278 +// SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
   1.279 +// is consistent with NS_SecurityCompareURIs.  See nsNetUtil.h.
   1.280 +uint32_t
   1.281 +nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
   1.282 +{
   1.283 +    return NS_SecurityHashURI(aURI);
   1.284 +}
   1.285 +
   1.286 +NS_IMETHODIMP
   1.287 +nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
   1.288 +                                             nsIPrincipal** aPrincipal)
   1.289 +{
   1.290 +    NS_PRECONDITION(aChannel, "Must have channel!");
   1.291 +    nsCOMPtr<nsISupports> owner;
   1.292 +    aChannel->GetOwner(getter_AddRefs(owner));
   1.293 +    if (owner) {
   1.294 +        CallQueryInterface(owner, aPrincipal);
   1.295 +        if (*aPrincipal) {
   1.296 +            return NS_OK;
   1.297 +        }
   1.298 +    }
   1.299 +
   1.300 +    // OK, get the principal from the URI.  Make sure this does the same thing
   1.301 +    // as nsDocument::Reset and XULDocument::StartDocumentLoad.
   1.302 +    nsCOMPtr<nsIURI> uri;
   1.303 +    nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   1.304 +    NS_ENSURE_SUCCESS(rv, rv);
   1.305 +
   1.306 +    nsCOMPtr<nsIDocShell> docShell;
   1.307 +    NS_QueryNotificationCallbacks(aChannel, docShell);
   1.308 +
   1.309 +    if (docShell) {
   1.310 +        return GetDocShellCodebasePrincipal(uri, docShell, aPrincipal);
   1.311 +    }
   1.312 +
   1.313 +    return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID,
   1.314 +        /* isInBrowserElement */ false, aPrincipal);
   1.315 +}
   1.316 +
   1.317 +NS_IMETHODIMP
   1.318 +nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
   1.319 +                                           bool* aIsSystem)
   1.320 +{
   1.321 +    *aIsSystem = (aPrincipal == mSystemPrincipal);
   1.322 +    return NS_OK;
   1.323 +}
   1.324 +
   1.325 +NS_IMETHODIMP_(nsIPrincipal *)
   1.326 +nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
   1.327 +{
   1.328 +    NS_ASSERTION(cx == GetCurrentJSContext(),
   1.329 +                 "Uh, cx is not the current JS context!");
   1.330 +
   1.331 +    nsresult rv = NS_ERROR_FAILURE;
   1.332 +    nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
   1.333 +    if (NS_FAILED(rv))
   1.334 +        return nullptr;
   1.335 +
   1.336 +    return principal;
   1.337 +}
   1.338 +
   1.339 +/////////////////////////////
   1.340 +// nsScriptSecurityManager //
   1.341 +/////////////////////////////
   1.342 +
   1.343 +////////////////////////////////////
   1.344 +// Methods implementing ISupports //
   1.345 +////////////////////////////////////
   1.346 +NS_IMPL_ISUPPORTS(nsScriptSecurityManager,
   1.347 +                  nsIScriptSecurityManager,
   1.348 +                  nsIXPCSecurityManager,
   1.349 +                  nsIChannelEventSink,
   1.350 +                  nsIObserver)
   1.351 +
   1.352 +///////////////////////////////////////////////////
   1.353 +// Methods implementing nsIScriptSecurityManager //
   1.354 +///////////////////////////////////////////////////
   1.355 +
   1.356 +///////////////// Security Checks /////////////////
   1.357 +
   1.358 +bool
   1.359 +nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
   1.360 +{
   1.361 +    // Get the security manager
   1.362 +    nsScriptSecurityManager *ssm =
   1.363 +        nsScriptSecurityManager::GetScriptSecurityManager();
   1.364 +
   1.365 +    NS_ASSERTION(ssm, "Failed to get security manager service");
   1.366 +    if (!ssm)
   1.367 +        return false;
   1.368 +
   1.369 +    nsresult rv;
   1.370 +    nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
   1.371 +
   1.372 +    NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
   1.373 +    if (NS_FAILED(rv))
   1.374 +        return false; // Not just absence of principal, but failure.
   1.375 +
   1.376 +    if (!subjectPrincipal)
   1.377 +        return true;
   1.378 +
   1.379 +    nsCOMPtr<nsIContentSecurityPolicy> csp;
   1.380 +    rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
   1.381 +    NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
   1.382 +
   1.383 +    // don't do anything unless there's a CSP
   1.384 +    if (!csp)
   1.385 +        return true;
   1.386 +
   1.387 +    bool evalOK = true;
   1.388 +    bool reportViolation = false;
   1.389 +    rv = csp->GetAllowsEval(&reportViolation, &evalOK);
   1.390 +
   1.391 +    if (NS_FAILED(rv))
   1.392 +    {
   1.393 +        NS_WARNING("CSP: failed to get allowsEval");
   1.394 +        return true; // fail open to not break sites.
   1.395 +    }
   1.396 +
   1.397 +    if (reportViolation) {
   1.398 +        nsAutoString fileName;
   1.399 +        unsigned lineNum = 0;
   1.400 +        NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
   1.401 +
   1.402 +        JS::AutoFilename scriptFilename;
   1.403 +        if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
   1.404 +            if (const char *file = scriptFilename.get()) {
   1.405 +                CopyUTF8toUTF16(nsDependentCString(file), fileName);
   1.406 +            }
   1.407 +        }
   1.408 +        csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
   1.409 +                                 fileName,
   1.410 +                                 scriptSample,
   1.411 +                                 lineNum,
   1.412 +                                 EmptyString(),
   1.413 +                                 EmptyString());
   1.414 +    }
   1.415 +
   1.416 +    return evalOK;
   1.417 +}
   1.418 +
   1.419 +// static
   1.420 +bool
   1.421 +nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first,
   1.422 +                                             JSPrincipals *second)
   1.423 +{
   1.424 +    return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
   1.425 +}
   1.426 +
   1.427 +NS_IMETHODIMP
   1.428 +nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
   1.429 +                                         nsIURI* aTargetURI)
   1.430 +{
   1.431 +    nsresult rv;
   1.432 +
   1.433 +    // Get a context if necessary
   1.434 +    if (!cx)
   1.435 +    {
   1.436 +        cx = GetCurrentJSContext();
   1.437 +        if (!cx)
   1.438 +            return NS_OK; // No JS context, so allow access
   1.439 +    }
   1.440 +
   1.441 +    // Get a principal from the context
   1.442 +    nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
   1.443 +    if (NS_FAILED(rv))
   1.444 +        return rv;
   1.445 +
   1.446 +    if (!sourcePrincipal)
   1.447 +    {
   1.448 +        NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
   1.449 +        return NS_OK;
   1.450 +    }
   1.451 +
   1.452 +    if (sourcePrincipal == mSystemPrincipal)
   1.453 +    {
   1.454 +        // This is a system (chrome) script, so allow access
   1.455 +        return NS_OK;
   1.456 +    }
   1.457 +
   1.458 +    // Get the original URI from the source principal.
   1.459 +    // This has the effect of ignoring any change to document.domain
   1.460 +    // which must be done to avoid DNS spoofing (bug 154930)
   1.461 +    nsCOMPtr<nsIURI> sourceURI;
   1.462 +    sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
   1.463 +    if (!sourceURI) {
   1.464 +      sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
   1.465 +      NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
   1.466 +    }
   1.467 +
   1.468 +    // Compare origins
   1.469 +    if (!SecurityCompareURIs(sourceURI, aTargetURI))
   1.470 +    {
   1.471 +         ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
   1.472 +         return NS_ERROR_DOM_BAD_URI;
   1.473 +    }
   1.474 +    return NS_OK;
   1.475 +}
   1.476 +
   1.477 +NS_IMETHODIMP
   1.478 +nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
   1.479 +                                            nsIURI* aTargetURI,
   1.480 +                                            bool reportError)
   1.481 +{
   1.482 +    if (!SecurityCompareURIs(aSourceURI, aTargetURI))
   1.483 +    {
   1.484 +         if (reportError) {
   1.485 +            ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"),
   1.486 +                     aSourceURI, aTargetURI);
   1.487 +         }
   1.488 +         return NS_ERROR_DOM_BAD_URI;
   1.489 +    }
   1.490 +    return NS_OK;
   1.491 +}
   1.492 +
   1.493 +/*static*/ uint32_t
   1.494 +nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
   1.495 +{
   1.496 +    nsCOMPtr<nsIURI> uri;
   1.497 +    aPrincipal->GetDomain(getter_AddRefs(uri));
   1.498 +    if (!uri)
   1.499 +        aPrincipal->GetURI(getter_AddRefs(uri));
   1.500 +    return SecurityHashURI(uri);
   1.501 +}
   1.502 +
   1.503 +/* static */ bool
   1.504 +nsScriptSecurityManager::AppAttributesEqual(nsIPrincipal* aFirst,
   1.505 +                                            nsIPrincipal* aSecond)
   1.506 +{
   1.507 +    MOZ_ASSERT(aFirst && aSecond, "Don't pass null pointers!");
   1.508 +
   1.509 +    uint32_t firstAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   1.510 +    if (!aFirst->GetUnknownAppId()) {
   1.511 +        firstAppId = aFirst->GetAppId();
   1.512 +    }
   1.513 +
   1.514 +    uint32_t secondAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   1.515 +    if (!aSecond->GetUnknownAppId()) {
   1.516 +        secondAppId = aSecond->GetAppId();
   1.517 +    }
   1.518 +
   1.519 +    return ((firstAppId == secondAppId) &&
   1.520 +            (aFirst->GetIsInBrowserElement() == aSecond->GetIsInBrowserElement()));
   1.521 +}
   1.522 +
   1.523 +NS_IMETHODIMP
   1.524 +nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
   1.525 +{
   1.526 +    // Get principal of currently executing script.
   1.527 +    nsresult rv;
   1.528 +    nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
   1.529 +    if (NS_FAILED(rv))
   1.530 +        return rv;
   1.531 +
   1.532 +    // Native code can load all URIs.
   1.533 +    if (!principal)
   1.534 +        return NS_OK;
   1.535 +
   1.536 +    rv = CheckLoadURIWithPrincipal(principal, aURI,
   1.537 +                                   nsIScriptSecurityManager::STANDARD);
   1.538 +    if (NS_SUCCEEDED(rv)) {
   1.539 +        // OK to load
   1.540 +        return NS_OK;
   1.541 +    }
   1.542 +
   1.543 +    // See if we're attempting to load a file: URI. If so, let a
   1.544 +    // UniversalXPConnect capability trump the above check.
   1.545 +    bool isFile = false;
   1.546 +    bool isRes = false;
   1.547 +    if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
   1.548 +        NS_FAILED(aURI->SchemeIs("resource", &isRes)))
   1.549 +        return NS_ERROR_FAILURE;
   1.550 +    if (isFile || isRes)
   1.551 +    {
   1.552 +        if (SubjectIsPrivileged())
   1.553 +            return NS_OK;
   1.554 +    }
   1.555 +
   1.556 +    // Report error.
   1.557 +    nsAutoCString spec;
   1.558 +    if (NS_FAILED(aURI->GetAsciiSpec(spec)))
   1.559 +        return NS_ERROR_FAILURE;
   1.560 +    nsAutoCString msg("Access to '");
   1.561 +    msg.Append(spec);
   1.562 +    msg.AppendLiteral("' from script denied");
   1.563 +    SetPendingException(cx, msg.get());
   1.564 +    return NS_ERROR_DOM_BAD_URI;
   1.565 +}
   1.566 +
   1.567 +/**
   1.568 + * Helper method to handle cases where a flag passed to
   1.569 + * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
   1.570 + * nsIProtocolHandler flags set.
   1.571 + * @return if success, access is allowed. Otherwise, deny access
   1.572 + */
   1.573 +static nsresult
   1.574 +DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
   1.575 +{
   1.576 +    NS_PRECONDITION(aURI, "Must have URI!");
   1.577 +    
   1.578 +    bool uriHasFlags;
   1.579 +    nsresult rv =
   1.580 +        NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
   1.581 +    NS_ENSURE_SUCCESS(rv, rv);
   1.582 +
   1.583 +    if (uriHasFlags) {
   1.584 +        return NS_ERROR_DOM_BAD_URI;
   1.585 +    }
   1.586 +
   1.587 +    return NS_OK;
   1.588 +}
   1.589 +
   1.590 +static bool
   1.591 +EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase)
   1.592 +{
   1.593 +    // Make a clone of the incoming URI, because we're going to mutate it.
   1.594 +    nsCOMPtr<nsIURI> probe;
   1.595 +    nsresult rv = aProbeArg->Clone(getter_AddRefs(probe));
   1.596 +    NS_ENSURE_SUCCESS(rv, false);
   1.597 +
   1.598 +    nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
   1.599 +    NS_ENSURE_TRUE(tldService, false);
   1.600 +    while (true) {
   1.601 +        if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) {
   1.602 +            return true;
   1.603 +        }
   1.604 +
   1.605 +        nsAutoCString host, newHost;
   1.606 +        nsresult rv = probe->GetHost(host);
   1.607 +        NS_ENSURE_SUCCESS(rv, false);
   1.608 +
   1.609 +        rv = tldService->GetNextSubDomain(host, newHost);
   1.610 +        if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
   1.611 +            return false;
   1.612 +        }
   1.613 +        NS_ENSURE_SUCCESS(rv, false);
   1.614 +        rv = probe->SetHost(newHost);
   1.615 +        NS_ENSURE_SUCCESS(rv, false);
   1.616 +    }
   1.617 +}
   1.618 +
   1.619 +NS_IMETHODIMP
   1.620 +nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
   1.621 +                                                   nsIURI *aTargetURI,
   1.622 +                                                   uint32_t aFlags)
   1.623 +{
   1.624 +    NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
   1.625 +    // If someone passes a flag that we don't understand, we should
   1.626 +    // fail, because they may need a security check that we don't
   1.627 +    // provide.
   1.628 +    NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
   1.629 +                               nsIScriptSecurityManager::ALLOW_CHROME |
   1.630 +                               nsIScriptSecurityManager::DISALLOW_SCRIPT |
   1.631 +                               nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL |
   1.632 +                               nsIScriptSecurityManager::DONT_REPORT_ERRORS),
   1.633 +                    NS_ERROR_UNEXPECTED);
   1.634 +    NS_ENSURE_ARG_POINTER(aPrincipal);
   1.635 +    NS_ENSURE_ARG_POINTER(aTargetURI);
   1.636 +
   1.637 +    // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
   1.638 +    // would do such inheriting. That would be URIs that do not have their own
   1.639 +    // security context. We do this even for the system principal.
   1.640 +    if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
   1.641 +        nsresult rv =
   1.642 +            DenyAccessIfURIHasFlags(aTargetURI,
   1.643 +                                    nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
   1.644 +        NS_ENSURE_SUCCESS(rv, rv);
   1.645 +    }
   1.646 +
   1.647 +    if (aPrincipal == mSystemPrincipal) {
   1.648 +        // Allow access
   1.649 +        return NS_OK;
   1.650 +    }
   1.651 +
   1.652 +    nsCOMPtr<nsIURI> sourceURI;
   1.653 +    aPrincipal->GetURI(getter_AddRefs(sourceURI));
   1.654 +    if (!sourceURI) {
   1.655 +        nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aPrincipal);
   1.656 +        if (expanded) {
   1.657 +            nsTArray< nsCOMPtr<nsIPrincipal> > *whiteList;
   1.658 +            expanded->GetWhiteList(&whiteList);
   1.659 +            for (uint32_t i = 0; i < whiteList->Length(); ++i) {
   1.660 +                nsresult rv = CheckLoadURIWithPrincipal((*whiteList)[i],
   1.661 +                                                        aTargetURI,
   1.662 +                                                        aFlags);
   1.663 +                if (NS_SUCCEEDED(rv)) {
   1.664 +                    // Allow access if it succeeded with one of the white listed principals
   1.665 +                    return NS_OK;
   1.666 +                }
   1.667 +            }
   1.668 +            // None of our whitelisted principals worked.
   1.669 +            return NS_ERROR_DOM_BAD_URI;
   1.670 +        }
   1.671 +        NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal "
   1.672 +                 "must have a URI!");
   1.673 +        return NS_ERROR_UNEXPECTED;
   1.674 +    }
   1.675 +    
   1.676 +    // Automatic loads are not allowed from certain protocols.
   1.677 +    if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
   1.678 +        nsresult rv =
   1.679 +            DenyAccessIfURIHasFlags(sourceURI,
   1.680 +                                    nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
   1.681 +        NS_ENSURE_SUCCESS(rv, rv);
   1.682 +    }
   1.683 +
   1.684 +    // If either URI is a nested URI, get the base URI
   1.685 +    nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
   1.686 +    nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
   1.687 +
   1.688 +    //-- get the target scheme
   1.689 +    nsAutoCString targetScheme;
   1.690 +    nsresult rv = targetBaseURI->GetScheme(targetScheme);
   1.691 +    if (NS_FAILED(rv)) return rv;
   1.692 +
   1.693 +    //-- Some callers do not allow loading javascript:
   1.694 +    if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
   1.695 +         targetScheme.EqualsLiteral("javascript"))
   1.696 +    {
   1.697 +       return NS_ERROR_DOM_BAD_URI;
   1.698 +    }
   1.699 +
   1.700 +    NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
   1.701 +    bool reportErrors = !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS);
   1.702 +
   1.703 +    // Check for uris that are only loadable by principals that subsume them
   1.704 +    bool hasFlags;
   1.705 +    rv = NS_URIChainHasFlags(targetBaseURI,
   1.706 +                             nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
   1.707 +                             &hasFlags);
   1.708 +    NS_ENSURE_SUCCESS(rv, rv);
   1.709 +
   1.710 +    if (hasFlags) {
   1.711 +        return aPrincipal->CheckMayLoad(targetBaseURI, true, false);
   1.712 +    }
   1.713 +
   1.714 +    //-- get the source scheme
   1.715 +    nsAutoCString sourceScheme;
   1.716 +    rv = sourceBaseURI->GetScheme(sourceScheme);
   1.717 +    if (NS_FAILED(rv)) return rv;
   1.718 +
   1.719 +    if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
   1.720 +        // A null principal can target its own URI.
   1.721 +        if (sourceURI == aTargetURI) {
   1.722 +            return NS_OK;
   1.723 +        }
   1.724 +    }
   1.725 +    else if (targetScheme.Equals(sourceScheme,
   1.726 +                                 nsCaseInsensitiveCStringComparator()))
   1.727 +    {
   1.728 +        // every scheme can access another URI from the same scheme,
   1.729 +        // as long as they don't represent null principals...
   1.730 +        // Or they don't require an special permission to do so
   1.731 +        // See bug#773886
   1.732 +
   1.733 +        bool hasFlags;
   1.734 +        rv = NS_URIChainHasFlags(targetBaseURI,
   1.735 +                                 nsIProtocolHandler::URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM,
   1.736 +                                 &hasFlags);
   1.737 +        NS_ENSURE_SUCCESS(rv, rv);
   1.738 +
   1.739 +        if (hasFlags) {
   1.740 +            // In this case, we allow opening only if the source and target URIS
   1.741 +            // are on the same domain, or the opening URI has the webapps
   1.742 +            // permision granted
   1.743 +            if (!SecurityCompareURIs(sourceBaseURI,targetBaseURI) &&
   1.744 +                !nsContentUtils::IsExactSitePermAllow(aPrincipal,WEBAPPS_PERM_NAME)){
   1.745 +                return NS_ERROR_DOM_BAD_URI;
   1.746 +            }
   1.747 +        }
   1.748 +        return NS_OK;
   1.749 +    }
   1.750 +
   1.751 +    // If the schemes don't match, the policy is specified by the protocol
   1.752 +    // flags on the target URI.  Note that the order of policy checks here is
   1.753 +    // very important!  We start from most restrictive and work our way down.
   1.754 +    // Note that since we're working with the innermost URI, we can just use
   1.755 +    // the methods that work on chains of nested URIs and they will only look
   1.756 +    // at the flags for our one URI.
   1.757 +
   1.758 +    // Check for system target URI
   1.759 +    rv = DenyAccessIfURIHasFlags(targetBaseURI,
   1.760 +                                 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
   1.761 +    if (NS_FAILED(rv)) {
   1.762 +        // Deny access, since the origin principal is not system
   1.763 +        if (reportErrors) {
   1.764 +            ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   1.765 +        }
   1.766 +        return rv;
   1.767 +    }
   1.768 +
   1.769 +    // Check for chrome target URI
   1.770 +    rv = NS_URIChainHasFlags(targetBaseURI,
   1.771 +                             nsIProtocolHandler::URI_IS_UI_RESOURCE,
   1.772 +                             &hasFlags);
   1.773 +    NS_ENSURE_SUCCESS(rv, rv);
   1.774 +    if (hasFlags) {
   1.775 +        if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
   1.776 +            if (!targetScheme.EqualsLiteral("chrome")) {
   1.777 +                // for now don't change behavior for resource: or moz-icon:
   1.778 +                return NS_OK;
   1.779 +            }
   1.780 +
   1.781 +            // allow load only if chrome package is whitelisted
   1.782 +            nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
   1.783 +                                                 NS_CHROMEREGISTRY_CONTRACTID));
   1.784 +            if (reg) {
   1.785 +                bool accessAllowed = false;
   1.786 +                reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
   1.787 +                if (accessAllowed) {
   1.788 +                    return NS_OK;
   1.789 +                }
   1.790 +            }
   1.791 +        }
   1.792 +
   1.793 +        // resource: and chrome: are equivalent, securitywise
   1.794 +        // That's bogus!!  Fix this.  But watch out for
   1.795 +        // the view-source stylesheet?
   1.796 +        bool sourceIsChrome;
   1.797 +        rv = NS_URIChainHasFlags(sourceBaseURI,
   1.798 +                                 nsIProtocolHandler::URI_IS_UI_RESOURCE,
   1.799 +                                 &sourceIsChrome);
   1.800 +        NS_ENSURE_SUCCESS(rv, rv);
   1.801 +        if (sourceIsChrome) {
   1.802 +            return NS_OK;
   1.803 +        }
   1.804 +        if (reportErrors) {
   1.805 +            ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   1.806 +        }
   1.807 +        return NS_ERROR_DOM_BAD_URI;
   1.808 +    }
   1.809 +
   1.810 +    // Check for target URI pointing to a file
   1.811 +    rv = NS_URIChainHasFlags(targetBaseURI,
   1.812 +                             nsIProtocolHandler::URI_IS_LOCAL_FILE,
   1.813 +                             &hasFlags);
   1.814 +    NS_ENSURE_SUCCESS(rv, rv);
   1.815 +    if (hasFlags) {
   1.816 +        // Allow domains that were whitelisted in the prefs. In 99.9% of cases,
   1.817 +        // this array is empty.
   1.818 +        for (size_t i = 0; i < mFileURIWhitelist.Length(); ++i) {
   1.819 +            if (EqualOrSubdomain(sourceURI, mFileURIWhitelist[i])) {
   1.820 +                return NS_OK;
   1.821 +            }
   1.822 +        }
   1.823 +
   1.824 +        // resource: and chrome: are equivalent, securitywise
   1.825 +        // That's bogus!!  Fix this.  But watch out for
   1.826 +        // the view-source stylesheet?
   1.827 +        bool sourceIsChrome;
   1.828 +        rv = NS_URIChainHasFlags(sourceURI,
   1.829 +                                 nsIProtocolHandler::URI_IS_UI_RESOURCE,
   1.830 +                                 &sourceIsChrome);
   1.831 +        NS_ENSURE_SUCCESS(rv, rv);
   1.832 +        if (sourceIsChrome) {
   1.833 +            return NS_OK;
   1.834 +        }
   1.835 +
   1.836 +        if (reportErrors) {
   1.837 +            ReportError(nullptr, errorTag, sourceURI, aTargetURI);
   1.838 +        }
   1.839 +        return NS_ERROR_DOM_BAD_URI;
   1.840 +    }
   1.841 +
   1.842 +    // OK, everyone is allowed to load this, since unflagged handlers are
   1.843 +    // deprecated but treated as URI_LOADABLE_BY_ANYONE.  But check whether we
   1.844 +    // need to warn.  At some point we'll want to make this warning into an
   1.845 +    // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
   1.846 +    rv = NS_URIChainHasFlags(targetBaseURI,
   1.847 +                             nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
   1.848 +                             &hasFlags);
   1.849 +    NS_ENSURE_SUCCESS(rv, rv);
   1.850 +    if (!hasFlags) {
   1.851 +        nsXPIDLString message;
   1.852 +        NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
   1.853 +        const char16_t* formatStrings[] = { ucsTargetScheme.get() };
   1.854 +        rv = sStrBundle->
   1.855 +            FormatStringFromName(MOZ_UTF16("ProtocolFlagError"),
   1.856 +                                 formatStrings,
   1.857 +                                 ArrayLength(formatStrings),
   1.858 +                                 getter_Copies(message));
   1.859 +        if (NS_SUCCEEDED(rv)) {
   1.860 +            nsCOMPtr<nsIConsoleService> console(
   1.861 +              do_GetService("@mozilla.org/consoleservice;1"));
   1.862 +            NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
   1.863 +
   1.864 +            console->LogStringMessage(message.get());
   1.865 +        }
   1.866 +    }
   1.867 +    
   1.868 +    return NS_OK;
   1.869 +}
   1.870 +
   1.871 +nsresult
   1.872 +nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
   1.873 +                                     nsIURI* aSource, nsIURI* aTarget)
   1.874 +{
   1.875 +    nsresult rv;
   1.876 +    NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
   1.877 +
   1.878 +    // Get the source URL spec
   1.879 +    nsAutoCString sourceSpec;
   1.880 +    rv = aSource->GetAsciiSpec(sourceSpec);
   1.881 +    NS_ENSURE_SUCCESS(rv, rv);
   1.882 +
   1.883 +    // Get the target URL spec
   1.884 +    nsAutoCString targetSpec;
   1.885 +    rv = aTarget->GetAsciiSpec(targetSpec);
   1.886 +    NS_ENSURE_SUCCESS(rv, rv);
   1.887 +
   1.888 +    // Localize the error message
   1.889 +    nsXPIDLString message;
   1.890 +    NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
   1.891 +    NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
   1.892 +    const char16_t *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
   1.893 +    rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
   1.894 +                                          formatStrings,
   1.895 +                                          ArrayLength(formatStrings),
   1.896 +                                          getter_Copies(message));
   1.897 +    NS_ENSURE_SUCCESS(rv, rv);
   1.898 +
   1.899 +    // If a JS context was passed in, set a JS exception.
   1.900 +    // Otherwise, print the error message directly to the JS console
   1.901 +    // and to standard output
   1.902 +    if (cx)
   1.903 +    {
   1.904 +        SetPendingException(cx, message.get());
   1.905 +    }
   1.906 +    else // Print directly to the console
   1.907 +    {
   1.908 +        nsCOMPtr<nsIConsoleService> console(
   1.909 +            do_GetService("@mozilla.org/consoleservice;1"));
   1.910 +        NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
   1.911 +
   1.912 +        console->LogStringMessage(message.get());
   1.913 +    }
   1.914 +    return NS_OK;
   1.915 +}
   1.916 +
   1.917 +NS_IMETHODIMP
   1.918 +nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
   1.919 +                                                      const nsACString& aTargetURIStr,
   1.920 +                                                      uint32_t aFlags)
   1.921 +{
   1.922 +    nsresult rv;
   1.923 +    nsCOMPtr<nsIURI> target;
   1.924 +    rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
   1.925 +                   nullptr, nullptr, sIOService);
   1.926 +    NS_ENSURE_SUCCESS(rv, rv);
   1.927 +
   1.928 +    rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
   1.929 +    if (rv == NS_ERROR_DOM_BAD_URI) {
   1.930 +        // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   1.931 +        // return values.
   1.932 +        return rv;
   1.933 +    }
   1.934 +    NS_ENSURE_SUCCESS(rv, rv);
   1.935 +
   1.936 +    // Now start testing fixup -- since aTargetURIStr is a string, not
   1.937 +    // an nsIURI, we may well end up fixing it up before loading.
   1.938 +    // Note: This needs to stay in sync with the nsIURIFixup api.
   1.939 +    nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
   1.940 +    if (!fixup) {
   1.941 +        return rv;
   1.942 +    }
   1.943 +
   1.944 +    uint32_t flags[] = {
   1.945 +        nsIURIFixup::FIXUP_FLAG_NONE,
   1.946 +        nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS,
   1.947 +        nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
   1.948 +        nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
   1.949 +        nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
   1.950 +        nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
   1.951 +    };
   1.952 +
   1.953 +    for (uint32_t i = 0; i < ArrayLength(flags); ++i) {
   1.954 +        rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr,
   1.955 +                                   getter_AddRefs(target));
   1.956 +        NS_ENSURE_SUCCESS(rv, rv);
   1.957 +
   1.958 +        rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
   1.959 +        if (rv == NS_ERROR_DOM_BAD_URI) {
   1.960 +            // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
   1.961 +            // return values.
   1.962 +            return rv;
   1.963 +        }
   1.964 +        NS_ENSURE_SUCCESS(rv, rv);
   1.965 +    }
   1.966 +
   1.967 +    return rv;
   1.968 +}
   1.969 +
   1.970 +bool
   1.971 +nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal)
   1.972 +{
   1.973 +    MOZ_ASSERT(aGlobal);
   1.974 +    MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal));
   1.975 +    AutoJSContext cx;
   1.976 +    JS::RootedObject global(cx, js::UncheckedUnwrap(aGlobal, /* stopAtOuter = */ false));
   1.977 +
   1.978 +    // Check the bits on the compartment private.
   1.979 +    return xpc::Scriptability::Get(aGlobal).Allowed();
   1.980 +}
   1.981 +
   1.982 +///////////////// Principals ///////////////////////
   1.983 +NS_IMETHODIMP
   1.984 +nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
   1.985 +{
   1.986 +    nsresult rv;
   1.987 +    *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
   1.988 +    if (NS_SUCCEEDED(rv))
   1.989 +        NS_IF_ADDREF(*aSubjectPrincipal);
   1.990 +    return rv;
   1.991 +}
   1.992 +
   1.993 +nsIPrincipal*
   1.994 +nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
   1.995 +{
   1.996 +    NS_PRECONDITION(rv, "Null out param");
   1.997 +    JSContext *cx = GetCurrentJSContext();
   1.998 +    if (!cx)
   1.999 +    {
  1.1000 +        *rv = NS_OK;
  1.1001 +        return nullptr;
  1.1002 +    }
  1.1003 +    return GetSubjectPrincipal(cx, rv);
  1.1004 +}
  1.1005 +
  1.1006 +NS_IMETHODIMP
  1.1007 +nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
  1.1008 +{
  1.1009 +    NS_ADDREF(*result = mSystemPrincipal);
  1.1010 +
  1.1011 +    return NS_OK;
  1.1012 +}
  1.1013 +
  1.1014 +NS_IMETHODIMP
  1.1015 +nsScriptSecurityManager::SubjectPrincipalIsSystem(bool* aIsSystem)
  1.1016 +{
  1.1017 +    NS_ENSURE_ARG_POINTER(aIsSystem);
  1.1018 +    *aIsSystem = false;
  1.1019 +
  1.1020 +    if (!mSystemPrincipal)
  1.1021 +        return NS_OK;
  1.1022 +
  1.1023 +    nsCOMPtr<nsIPrincipal> subject;
  1.1024 +    nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
  1.1025 +    if (NS_FAILED(rv))
  1.1026 +        return rv;
  1.1027 +
  1.1028 +    if(!subject)
  1.1029 +    {
  1.1030 +        // No subject principal means no JS is running;
  1.1031 +        // this is the equivalent of system principal code
  1.1032 +        *aIsSystem = true;
  1.1033 +        return NS_OK;
  1.1034 +    }
  1.1035 +
  1.1036 +    return mSystemPrincipal->Equals(subject, aIsSystem);
  1.1037 +}
  1.1038 +
  1.1039 +nsresult
  1.1040 +nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId,
  1.1041 +                                                 bool aInMozBrowser,
  1.1042 +                                                 nsIPrincipal **result)
  1.1043 +{
  1.1044 +    // I _think_ it's safe to not create null principals here based on aURI.
  1.1045 +    // At least all the callers would do the right thing in those cases, as far
  1.1046 +    // as I can tell.  --bz
  1.1047 +
  1.1048 +    nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
  1.1049 +    if (uriPrinc) {
  1.1050 +        nsCOMPtr<nsIPrincipal> principal;
  1.1051 +        uriPrinc->GetPrincipal(getter_AddRefs(principal));
  1.1052 +        if (!principal || principal == mSystemPrincipal) {
  1.1053 +            return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
  1.1054 +        }
  1.1055 +
  1.1056 +        principal.forget(result);
  1.1057 +
  1.1058 +        return NS_OK;
  1.1059 +    }
  1.1060 +
  1.1061 +    nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
  1.1062 +    if (!codebase)
  1.1063 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1064 +
  1.1065 +    nsresult rv = codebase->Init(aURI, aAppId, aInMozBrowser);
  1.1066 +    if (NS_FAILED(rv))
  1.1067 +        return rv;
  1.1068 +
  1.1069 +    NS_ADDREF(*result = codebase);
  1.1070 +
  1.1071 +    return NS_OK;
  1.1072 +}
  1.1073 +
  1.1074 +NS_IMETHODIMP
  1.1075 +nsScriptSecurityManager::GetSimpleCodebasePrincipal(nsIURI* aURI,
  1.1076 +                                                    nsIPrincipal** aPrincipal)
  1.1077 +{
  1.1078 +  return GetCodebasePrincipalInternal(aURI,
  1.1079 +                                      nsIScriptSecurityManager::UNKNOWN_APP_ID,
  1.1080 +                                      false, aPrincipal);
  1.1081 +}
  1.1082 +
  1.1083 +NS_IMETHODIMP
  1.1084 +nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI,
  1.1085 +                                                   nsIPrincipal** aPrincipal)
  1.1086 +{
  1.1087 +  return GetCodebasePrincipalInternal(aURI,  nsIScriptSecurityManager::NO_APP_ID,
  1.1088 +                                      false, aPrincipal);
  1.1089 +}
  1.1090 +
  1.1091 +NS_IMETHODIMP
  1.1092 +nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI,
  1.1093 +                                              nsIPrincipal** aPrincipal)
  1.1094 +{
  1.1095 +  return GetNoAppCodebasePrincipal(aURI, aPrincipal);
  1.1096 +}
  1.1097 +
  1.1098 +NS_IMETHODIMP
  1.1099 +nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
  1.1100 +                                                 uint32_t aAppId,
  1.1101 +                                                 bool aInMozBrowser,
  1.1102 +                                                 nsIPrincipal** aPrincipal)
  1.1103 +{
  1.1104 +  NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
  1.1105 +                 NS_ERROR_INVALID_ARG);
  1.1106 +
  1.1107 +  return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal);
  1.1108 +}
  1.1109 +
  1.1110 +NS_IMETHODIMP
  1.1111 +nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI,
  1.1112 +                                                      nsIDocShell* aDocShell,
  1.1113 +                                                      nsIPrincipal** aPrincipal)
  1.1114 +{
  1.1115 +  return GetCodebasePrincipalInternal(aURI,
  1.1116 +                                      aDocShell->GetAppId(),
  1.1117 +                                      aDocShell->GetIsInBrowserElement(),
  1.1118 +                                      aPrincipal);
  1.1119 +}
  1.1120 +
  1.1121 +nsresult
  1.1122 +nsScriptSecurityManager::GetCodebasePrincipalInternal(nsIURI *aURI,
  1.1123 +                                                      uint32_t aAppId,
  1.1124 +                                                      bool aInMozBrowser,
  1.1125 +                                                      nsIPrincipal **result)
  1.1126 +{
  1.1127 +    NS_ENSURE_ARG(aURI);
  1.1128 +
  1.1129 +    bool inheritsPrincipal;
  1.1130 +    nsresult rv =
  1.1131 +        NS_URIChainHasFlags(aURI,
  1.1132 +                            nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
  1.1133 +                            &inheritsPrincipal);
  1.1134 +    if (NS_FAILED(rv) || inheritsPrincipal) {
  1.1135 +        return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
  1.1136 +    }
  1.1137 +
  1.1138 +    nsCOMPtr<nsIPrincipal> principal;
  1.1139 +    rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser,
  1.1140 +                                 getter_AddRefs(principal));
  1.1141 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1142 +    NS_IF_ADDREF(*result = principal);
  1.1143 +
  1.1144 +    return NS_OK;
  1.1145 +}
  1.1146 +
  1.1147 +nsIPrincipal*
  1.1148 +nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
  1.1149 +                                             nsresult* rv)
  1.1150 +{
  1.1151 +    *rv = NS_OK;
  1.1152 +    JSCompartment *compartment = js::GetContextCompartment(cx);
  1.1153 +
  1.1154 +    // The context should always be in a compartment, either one it has entered
  1.1155 +    // or the one associated with its global.
  1.1156 +    MOZ_ASSERT(!!compartment);
  1.1157 +
  1.1158 +    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
  1.1159 +    return nsJSPrincipals::get(principals);
  1.1160 +}
  1.1161 +
  1.1162 +// static
  1.1163 +nsIPrincipal*
  1.1164 +nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
  1.1165 +{
  1.1166 +    JSCompartment *compartment = js::GetObjectCompartment(aObj);
  1.1167 +    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
  1.1168 +    return nsJSPrincipals::get(principals);
  1.1169 +}
  1.1170 +
  1.1171 +////////////////////////////////////////////////
  1.1172 +// Methods implementing nsIXPCSecurityManager //
  1.1173 +////////////////////////////////////////////////
  1.1174 +
  1.1175 +NS_IMETHODIMP
  1.1176 +nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
  1.1177 +                                          const nsIID &aIID,
  1.1178 +                                          nsISupports *aObj,
  1.1179 +                                          nsIClassInfo *aClassInfo)
  1.1180 +{
  1.1181 +// XXX Special case for nsIXPCException ?
  1.1182 +    ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nullptr);
  1.1183 +    if (objClassInfo.IsDOMClass())
  1.1184 +    {
  1.1185 +        return NS_OK;
  1.1186 +    }
  1.1187 +
  1.1188 +    // We give remote-XUL whitelisted domains a free pass here. See bug 932906.
  1.1189 +    if (!xpc::AllowXBLScope(js::GetContextCompartment(cx)))
  1.1190 +    {
  1.1191 +        return NS_OK;
  1.1192 +    }
  1.1193 +
  1.1194 +    if (SubjectIsPrivileged())
  1.1195 +    {
  1.1196 +        return NS_OK;
  1.1197 +    }
  1.1198 +
  1.1199 +    //-- Access denied, report an error
  1.1200 +    NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
  1.1201 +    nsAutoCString origin;
  1.1202 +    nsresult rv2;
  1.1203 +    nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2);
  1.1204 +    if (NS_SUCCEEDED(rv2) && subjectPrincipal) {
  1.1205 +        GetPrincipalDomainOrigin(subjectPrincipal, origin);
  1.1206 +    }
  1.1207 +    NS_ConvertUTF8toUTF16 originUnicode(origin);
  1.1208 +    NS_ConvertUTF8toUTF16 classInfoName(objClassInfo.GetName());
  1.1209 +    const char16_t* formatStrings[] = {
  1.1210 +        classInfoName.get(),
  1.1211 +        originUnicode.get()
  1.1212 +    };
  1.1213 +    uint32_t length = ArrayLength(formatStrings);
  1.1214 +    if (originUnicode.IsEmpty()) {
  1.1215 +        --length;
  1.1216 +    } else {
  1.1217 +        strName.AppendLiteral("ForOrigin");
  1.1218 +    }
  1.1219 +    nsXPIDLString errorMsg;
  1.1220 +    // We need to keep our existing failure rv and not override it
  1.1221 +    // with a likely success code from the following string bundle
  1.1222 +    // call in order to throw the correct security exception later.
  1.1223 +    rv2 = sStrBundle->FormatStringFromName(strName.get(),
  1.1224 +                                           formatStrings,
  1.1225 +                                           length,
  1.1226 +                                           getter_Copies(errorMsg));
  1.1227 +    NS_ENSURE_SUCCESS(rv2, rv2);
  1.1228 +
  1.1229 +    SetPendingException(cx, errorMsg.get());
  1.1230 +    return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1.1231 +}
  1.1232 +
  1.1233 +NS_IMETHODIMP
  1.1234 +nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
  1.1235 +                                           const nsCID &aCID)
  1.1236 +{
  1.1237 +    if (SubjectIsPrivileged()) {
  1.1238 +        return NS_OK;
  1.1239 +    }
  1.1240 +
  1.1241 +    //-- Access denied, report an error
  1.1242 +    nsAutoCString errorMsg("Permission denied to create instance of class. CID=");
  1.1243 +    char cidStr[NSID_LENGTH];
  1.1244 +    aCID.ToProvidedString(cidStr);
  1.1245 +    errorMsg.Append(cidStr);
  1.1246 +    SetPendingException(cx, errorMsg.get());
  1.1247 +    return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1.1248 +}
  1.1249 +
  1.1250 +NS_IMETHODIMP
  1.1251 +nsScriptSecurityManager::CanGetService(JSContext *cx,
  1.1252 +                                       const nsCID &aCID)
  1.1253 +{
  1.1254 +    if (SubjectIsPrivileged()) {
  1.1255 +        return NS_OK;
  1.1256 +    }
  1.1257 +
  1.1258 +    //-- Access denied, report an error
  1.1259 +    nsAutoCString errorMsg("Permission denied to get service. CID=");
  1.1260 +    char cidStr[NSID_LENGTH];
  1.1261 +    aCID.ToProvidedString(cidStr);
  1.1262 +    errorMsg.Append(cidStr);
  1.1263 +    SetPendingException(cx, errorMsg.get());
  1.1264 +    return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
  1.1265 +}
  1.1266 +
  1.1267 +/////////////////////////////////////////////
  1.1268 +// Method implementing nsIChannelEventSink //
  1.1269 +/////////////////////////////////////////////
  1.1270 +NS_IMETHODIMP
  1.1271 +nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel, 
  1.1272 +                                                nsIChannel* newChannel,
  1.1273 +                                                uint32_t redirFlags,
  1.1274 +                                                nsIAsyncVerifyRedirectCallback *cb)
  1.1275 +{
  1.1276 +    nsCOMPtr<nsIPrincipal> oldPrincipal;
  1.1277 +    GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
  1.1278 +
  1.1279 +    nsCOMPtr<nsIURI> newURI;
  1.1280 +    newChannel->GetURI(getter_AddRefs(newURI));
  1.1281 +    nsCOMPtr<nsIURI> newOriginalURI;
  1.1282 +    newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
  1.1283 +
  1.1284 +    NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
  1.1285 +
  1.1286 +    const uint32_t flags =
  1.1287 +        nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
  1.1288 +        nsIScriptSecurityManager::DISALLOW_SCRIPT;
  1.1289 +    nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
  1.1290 +    if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
  1.1291 +        rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
  1.1292 +    }
  1.1293 +
  1.1294 +    if (NS_FAILED(rv))
  1.1295 +        return rv;
  1.1296 +
  1.1297 +    cb->OnRedirectVerifyCallback(NS_OK);
  1.1298 +    return NS_OK;
  1.1299 +}
  1.1300 +
  1.1301 +
  1.1302 +/////////////////////////////////////
  1.1303 +// Method implementing nsIObserver //
  1.1304 +/////////////////////////////////////
  1.1305 +const char sJSEnabledPrefName[] = "javascript.enabled";
  1.1306 +const char sFileOriginPolicyPrefName[] =
  1.1307 +    "security.fileuri.strict_origin_policy";
  1.1308 +
  1.1309 +static const char* kObservedPrefs[] = {
  1.1310 +  sJSEnabledPrefName,
  1.1311 +  sFileOriginPolicyPrefName,
  1.1312 +  "capability.policy.",
  1.1313 +  nullptr
  1.1314 +};
  1.1315 +
  1.1316 +
  1.1317 +NS_IMETHODIMP
  1.1318 +nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
  1.1319 +                                 const char16_t* aMessage)
  1.1320 +{
  1.1321 +    ScriptSecurityPrefChanged();
  1.1322 +    return NS_OK;
  1.1323 +}
  1.1324 +
  1.1325 +/////////////////////////////////////////////
  1.1326 +// Constructor, Destructor, Initialization //
  1.1327 +/////////////////////////////////////////////
  1.1328 +nsScriptSecurityManager::nsScriptSecurityManager(void)
  1.1329 +    : mPrefInitialized(false)
  1.1330 +    , mIsJavaScriptEnabled(false)
  1.1331 +{
  1.1332 +    static_assert(sizeof(intptr_t) == sizeof(void*),
  1.1333 +                  "intptr_t and void* have different lengths on this platform. "
  1.1334 +                  "This may cause a security failure with the SecurityLevel union.");
  1.1335 +}
  1.1336 +
  1.1337 +nsresult nsScriptSecurityManager::Init()
  1.1338 +{
  1.1339 +    nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
  1.1340 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1341 +
  1.1342 +    InitPrefs();
  1.1343 +
  1.1344 +    nsCOMPtr<nsIStringBundleService> bundleService =
  1.1345 +        mozilla::services::GetStringBundleService();
  1.1346 +    if (!bundleService)
  1.1347 +        return NS_ERROR_FAILURE;
  1.1348 +
  1.1349 +    rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
  1.1350 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1351 +
  1.1352 +    // Create our system principal singleton
  1.1353 +    nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
  1.1354 +    NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
  1.1355 +
  1.1356 +    mSystemPrincipal = system;
  1.1357 +
  1.1358 +    //-- Register security check callback in the JS engine
  1.1359 +    //   Currently this is used to control access to function.caller
  1.1360 +    rv = nsXPConnect::XPConnect()->GetRuntime(&sRuntime);
  1.1361 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1362 +
  1.1363 +    static const JSSecurityCallbacks securityCallbacks = {
  1.1364 +        ContentSecurityPolicyPermitsJSAction,
  1.1365 +        JSPrincipalsSubsume,
  1.1366 +    };
  1.1367 +
  1.1368 +    MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
  1.1369 +    JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
  1.1370 +    JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
  1.1371 +
  1.1372 +    JS_SetTrustedPrincipals(sRuntime, system);
  1.1373 +
  1.1374 +    return NS_OK;
  1.1375 +}
  1.1376 +
  1.1377 +static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan;
  1.1378 +
  1.1379 +nsScriptSecurityManager::~nsScriptSecurityManager(void)
  1.1380 +{
  1.1381 +    Preferences::RemoveObservers(this, kObservedPrefs);
  1.1382 +    if (mDomainPolicy)
  1.1383 +        mDomainPolicy->Deactivate();
  1.1384 +    MOZ_ASSERT(!mDomainPolicy);
  1.1385 +}
  1.1386 +
  1.1387 +void
  1.1388 +nsScriptSecurityManager::Shutdown()
  1.1389 +{
  1.1390 +    if (sRuntime) {
  1.1391 +        JS_SetSecurityCallbacks(sRuntime, nullptr);
  1.1392 +        JS_SetTrustedPrincipals(sRuntime, nullptr);
  1.1393 +        sRuntime = nullptr;
  1.1394 +    }
  1.1395 +
  1.1396 +    NS_IF_RELEASE(sIOService);
  1.1397 +    NS_IF_RELEASE(sStrBundle);
  1.1398 +}
  1.1399 +
  1.1400 +nsScriptSecurityManager *
  1.1401 +nsScriptSecurityManager::GetScriptSecurityManager()
  1.1402 +{
  1.1403 +    if (!gScriptSecMan && nsXPConnect::XPConnect())
  1.1404 +    {
  1.1405 +        nsRefPtr<nsScriptSecurityManager> ssManager = new nsScriptSecurityManager();
  1.1406 +
  1.1407 +        nsresult rv;
  1.1408 +        rv = ssManager->Init();
  1.1409 +        if (NS_FAILED(rv)) {
  1.1410 +            return nullptr;
  1.1411 +        }
  1.1412 + 
  1.1413 +        rv = nsXPConnect::XPConnect()->
  1.1414 +            SetDefaultSecurityManager(ssManager);
  1.1415 +        if (NS_FAILED(rv)) {
  1.1416 +            NS_WARNING("Failed to install xpconnect security manager!");
  1.1417 +            return nullptr;
  1.1418 +        }
  1.1419 +
  1.1420 +        ClearOnShutdown(&gScriptSecMan);
  1.1421 +        gScriptSecMan = ssManager;
  1.1422 +    }
  1.1423 +    return gScriptSecMan;
  1.1424 +}
  1.1425 +
  1.1426 +// Currently this nsGenericFactory constructor is used only from FastLoad
  1.1427 +// (XPCOM object deserialization) code, when "creating" the system principal
  1.1428 +// singleton.
  1.1429 +nsSystemPrincipal *
  1.1430 +nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
  1.1431 +{
  1.1432 +    nsIPrincipal *sysprin = nullptr;
  1.1433 +    if (gScriptSecMan)
  1.1434 +        NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
  1.1435 +    return static_cast<nsSystemPrincipal*>(sysprin);
  1.1436 +}
  1.1437 +
  1.1438 +struct IsWhitespace {
  1.1439 +    static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); };
  1.1440 +};
  1.1441 +struct IsWhitespaceOrComma {
  1.1442 +    static bool Test(char aChar) { return aChar == ',' || NS_IsAsciiWhitespace(aChar); };
  1.1443 +};
  1.1444 +
  1.1445 +template <typename Predicate>
  1.1446 +uint32_t SkipPast(const nsCString& str, uint32_t base)
  1.1447 +{
  1.1448 +    while (base < str.Length() && Predicate::Test(str[base])) {
  1.1449 +        ++base;
  1.1450 +    }
  1.1451 +    return base;
  1.1452 +}
  1.1453 +
  1.1454 +template <typename Predicate>
  1.1455 +uint32_t SkipUntil(const nsCString& str, uint32_t base)
  1.1456 +{
  1.1457 +    while (base < str.Length() && !Predicate::Test(str[base])) {
  1.1458 +        ++base;
  1.1459 +    }
  1.1460 +    return base;
  1.1461 +}
  1.1462 +
  1.1463 +inline void
  1.1464 +nsScriptSecurityManager::ScriptSecurityPrefChanged()
  1.1465 +{
  1.1466 +    MOZ_ASSERT(mPrefInitialized);
  1.1467 +    mIsJavaScriptEnabled =
  1.1468 +        Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled);
  1.1469 +    sStrictFileOriginPolicy =
  1.1470 +        Preferences::GetBool(sFileOriginPolicyPrefName, false);
  1.1471 +
  1.1472 +    //
  1.1473 +    // Rebuild the set of principals for which we allow file:// URI loads. This
  1.1474 +    // implements a small subset of an old pref-based CAPS people that people
  1.1475 +    // have come to depend on. See bug 995943.
  1.1476 +    //
  1.1477 +
  1.1478 +    mFileURIWhitelist.Clear();
  1.1479 +    auto policies = mozilla::Preferences::GetCString("capability.policy.policynames");
  1.1480 +    for (uint32_t base = SkipPast<IsWhitespaceOrComma>(policies, 0), bound = 0;
  1.1481 +         base < policies.Length();
  1.1482 +         base = SkipPast<IsWhitespaceOrComma>(policies, bound))
  1.1483 +    {
  1.1484 +        // Grab the current policy name.
  1.1485 +        bound = SkipUntil<IsWhitespaceOrComma>(policies, base);
  1.1486 +        auto policyName = Substring(policies, base, bound - base);
  1.1487 +
  1.1488 +        // Figure out if this policy allows loading file:// URIs. If not, we can skip it.
  1.1489 +        nsCString checkLoadURIPrefName = NS_LITERAL_CSTRING("capability.policy.") +
  1.1490 +                                         policyName +
  1.1491 +                                         NS_LITERAL_CSTRING(".checkloaduri.enabled");
  1.1492 +        if (!Preferences::GetString(checkLoadURIPrefName.get()).LowerCaseEqualsLiteral("allaccess")) {
  1.1493 +            continue;
  1.1494 +        }
  1.1495 +
  1.1496 +        // Grab the list of domains associated with this policy.
  1.1497 +        nsCString domainPrefName = NS_LITERAL_CSTRING("capability.policy.") +
  1.1498 +                                   policyName +
  1.1499 +                                   NS_LITERAL_CSTRING(".sites");
  1.1500 +        auto siteList = Preferences::GetCString(domainPrefName.get());
  1.1501 +        AddSitesToFileURIWhitelist(siteList);
  1.1502 +    }
  1.1503 +}
  1.1504 +
  1.1505 +void
  1.1506 +nsScriptSecurityManager::AddSitesToFileURIWhitelist(const nsCString& aSiteList)
  1.1507 +{
  1.1508 +    for (uint32_t base = SkipPast<IsWhitespace>(aSiteList, 0), bound = 0;
  1.1509 +         base < aSiteList.Length();
  1.1510 +         base = SkipPast<IsWhitespace>(aSiteList, bound))
  1.1511 +    {
  1.1512 +        // Grab the current site.
  1.1513 +        bound = SkipUntil<IsWhitespace>(aSiteList, base);
  1.1514 +        nsAutoCString site(Substring(aSiteList, base, bound - base));
  1.1515 +
  1.1516 +        // Check if the URI is schemeless. If so, add both http and https.
  1.1517 +        nsAutoCString unused;
  1.1518 +        if (NS_FAILED(sIOService->ExtractScheme(site, unused))) {
  1.1519 +            AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("http://") + site);
  1.1520 +            AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("https://") + site);
  1.1521 +            continue;
  1.1522 +        }
  1.1523 +
  1.1524 +        // Convert it to a URI and add it to our list.
  1.1525 +        nsCOMPtr<nsIURI> uri;
  1.1526 +        nsresult rv = NS_NewURI(getter_AddRefs(uri), site, nullptr, nullptr, sIOService);
  1.1527 +        if (NS_SUCCEEDED(rv)) {
  1.1528 +            mFileURIWhitelist.AppendElement(uri);
  1.1529 +        } else {
  1.1530 +            nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1"));
  1.1531 +            if (console) {
  1.1532 +                nsAutoString msg = NS_LITERAL_STRING("Unable to to add site to file:// URI whitelist: ") +
  1.1533 +                                   NS_ConvertASCIItoUTF16(site);
  1.1534 +                console->LogStringMessage(msg.get());
  1.1535 +            }
  1.1536 +        }
  1.1537 +    }
  1.1538 +}
  1.1539 +
  1.1540 +nsresult
  1.1541 +nsScriptSecurityManager::InitPrefs()
  1.1542 +{
  1.1543 +    nsIPrefBranch* branch = Preferences::GetRootBranch();
  1.1544 +    NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE);
  1.1545 +
  1.1546 +    mPrefInitialized = true;
  1.1547 +
  1.1548 +    // Set the initial value of the "javascript.enabled" prefs
  1.1549 +    ScriptSecurityPrefChanged();
  1.1550 +
  1.1551 +    // set observer callbacks in case the value of the prefs change
  1.1552 +    Preferences::AddStrongObservers(this, kObservedPrefs);
  1.1553 +
  1.1554 +    return NS_OK;
  1.1555 +}
  1.1556 +
  1.1557 +namespace mozilla {
  1.1558 +
  1.1559 +void
  1.1560 +GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
  1.1561 +{
  1.1562 +  MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1.1563 +
  1.1564 +  if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  1.1565 +    aAppId = nsIScriptSecurityManager::NO_APP_ID;
  1.1566 +  }
  1.1567 +
  1.1568 +  aJarPrefix.Truncate();
  1.1569 +
  1.1570 +  // Fallback.
  1.1571 +  if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
  1.1572 +    return;
  1.1573 +  }
  1.1574 +
  1.1575 +  // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
  1.1576 +  aJarPrefix.AppendInt(aAppId);
  1.1577 +  aJarPrefix.Append('+');
  1.1578 +  aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
  1.1579 +  aJarPrefix.Append('+');
  1.1580 +
  1.1581 +  return;
  1.1582 +}
  1.1583 +
  1.1584 +} // namespace mozilla
  1.1585 +
  1.1586 +NS_IMETHODIMP
  1.1587 +nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
  1.1588 +                                      bool aInMozBrowser,
  1.1589 +                                      nsACString& aJarPrefix)
  1.1590 +{
  1.1591 +  MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1.1592 +
  1.1593 +  mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
  1.1594 +  return NS_OK;
  1.1595 +}
  1.1596 +
  1.1597 +NS_IMETHODIMP
  1.1598 +nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv)
  1.1599 +{
  1.1600 +    *aRv = !!mDomainPolicy;
  1.1601 +    return NS_OK;
  1.1602 +}
  1.1603 +
  1.1604 +NS_IMETHODIMP
  1.1605 +nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv)
  1.1606 +{
  1.1607 +    // We only allow one domain policy at a time. The holder of the previous
  1.1608 +    // policy must explicitly deactivate it first.
  1.1609 +    if (mDomainPolicy) {
  1.1610 +        return NS_ERROR_SERVICE_NOT_AVAILABLE;
  1.1611 +    }
  1.1612 +
  1.1613 +    mDomainPolicy = new DomainPolicy();
  1.1614 +    nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy;
  1.1615 +    ptr.forget(aRv);
  1.1616 +    return NS_OK;
  1.1617 +}
  1.1618 +
  1.1619 +// Intentionally non-scriptable. Script must have a reference to the
  1.1620 +// nsIDomainPolicy to deactivate it.
  1.1621 +void
  1.1622 +nsScriptSecurityManager::DeactivateDomainPolicy()
  1.1623 +{
  1.1624 +    mDomainPolicy = nullptr;
  1.1625 +}
  1.1626 +
  1.1627 +NS_IMETHODIMP
  1.1628 +nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
  1.1629 +{
  1.1630 +    nsresult rv;
  1.1631 +
  1.1632 +    // Compute our rule. If we don't have any domain policy set up that might
  1.1633 +    // provide exceptions to this rule, we're done.
  1.1634 +    *aRv = mIsJavaScriptEnabled;
  1.1635 +    if (!mDomainPolicy) {
  1.1636 +        return NS_OK;
  1.1637 +    }
  1.1638 +
  1.1639 +    // We have a domain policy. Grab the appropriate set of exceptions to the
  1.1640 +    // rule (either the blacklist or the whitelist, depending on whether script
  1.1641 +    // is enabled or disabled by default).
  1.1642 +    nsCOMPtr<nsIDomainSet> exceptions;
  1.1643 +    nsCOMPtr<nsIDomainSet> superExceptions;
  1.1644 +    if (*aRv) {
  1.1645 +        mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions));
  1.1646 +        mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions));
  1.1647 +    } else {
  1.1648 +        mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions));
  1.1649 +        mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions));
  1.1650 +    }
  1.1651 +
  1.1652 +    bool contains;
  1.1653 +    rv = exceptions->Contains(aURI, &contains);
  1.1654 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1655 +    if (contains) {
  1.1656 +        *aRv = !*aRv;
  1.1657 +        return NS_OK;
  1.1658 +    }
  1.1659 +    rv = superExceptions->ContainsSuperDomain(aURI, &contains);
  1.1660 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1661 +    if (contains) {
  1.1662 +        *aRv = !*aRv;
  1.1663 +    }
  1.1664 +
  1.1665 +    return NS_OK;
  1.1666 +}

mercurial