/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BackgroundUtils.h" #include "MainThreadUtils.h" #include "mozilla/Assertions.h" #include "mozilla/BasePrincipal.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/net/NeckoChannelParams.h" #include "nsPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "mozilla/LoadInfo.h" #include "nsNullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsTArray.h" namespace mozilla { namespace net { class OptionalLoadInfoArgs; } using mozilla::BasePrincipal; using namespace mozilla::net; namespace ipc { already_AddRefed PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo, nsresult* aOptionalResult) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None); nsresult stackResult; nsresult& rv = aOptionalResult ? *aOptionalResult : stackResult; nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } nsCOMPtr principal; switch (aPrincipalInfo.type()) { case PrincipalInfo::TSystemPrincipalInfo: { rv = secMan->GetSystemPrincipal(getter_AddRefs(principal)); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } return principal.forget(); } case PrincipalInfo::TNullPrincipalInfo: { principal = do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } return principal.forget(); } case PrincipalInfo::TContentPrincipalInfo: { const ContentPrincipalInfo& info = aPrincipalInfo.get_ContentPrincipalInfo(); nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), info.spec()); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } if (info.attrs().mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { rv = secMan->GetSimpleCodebasePrincipal(uri, getter_AddRefs(principal)); } else { principal = BasePrincipal::CreateCodebasePrincipal(uri, info.attrs()); rv = principal ? NS_OK : NS_ERROR_FAILURE; } if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } return principal.forget(); } case PrincipalInfo::TExpandedPrincipalInfo: { const ExpandedPrincipalInfo& info = aPrincipalInfo.get_ExpandedPrincipalInfo(); nsTArray< nsCOMPtr > whitelist; nsCOMPtr wlPrincipal; for (uint32_t i = 0; i < info.whitelist().Length(); i++) { wlPrincipal = PrincipalInfoToPrincipal(info.whitelist()[i], &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } // append that principal to the whitelist whitelist.AppendElement(wlPrincipal); } RefPtr expandedPrincipal = new nsExpandedPrincipal(whitelist); if (!expandedPrincipal) { NS_WARNING("could not instantiate expanded principal"); return nullptr; } principal = expandedPrincipal; return principal.forget(); } default: MOZ_CRASH("Unknown PrincipalInfo type!"); } MOZ_CRASH("Should never get here!"); } nsresult PrincipalToPrincipalInfo(nsIPrincipal* aPrincipal, PrincipalInfo* aPrincipalInfo) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aPrincipalInfo); bool isNullPointer; nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPointer); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (isNullPointer) { *aPrincipalInfo = NullPrincipalInfo(); return NS_OK; } nsCOMPtr secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } bool isSystemPrincipal; rv = secMan->IsSystemPrincipal(aPrincipal, &isSystemPrincipal); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (isSystemPrincipal) { *aPrincipalInfo = SystemPrincipalInfo(); return NS_OK; } // might be an expanded principal nsCOMPtr expanded = do_QueryInterface(aPrincipal); if (expanded) { nsTArray whitelistInfo; PrincipalInfo info; nsTArray< nsCOMPtr >* whitelist; MOZ_ALWAYS_TRUE(NS_SUCCEEDED(expanded->GetWhiteList(&whitelist))); for (uint32_t i = 0; i < whitelist->Length(); i++) { rv = PrincipalToPrincipalInfo((*whitelist)[i], &info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // append that spec to the whitelist whitelistInfo.AppendElement(info); } *aPrincipalInfo = ExpandedPrincipalInfo(Move(whitelistInfo)); return NS_OK; } // must be a content principal nsCOMPtr uri; rv = aPrincipal->GetURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (NS_WARN_IF(!uri)) { return NS_ERROR_FAILURE; } nsCString spec; rv = uri->GetSpec(spec); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } *aPrincipalInfo = ContentPrincipalInfo(BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(), spec); return NS_OK; } nsresult LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, OptionalLoadInfoArgs* aOptionalLoadInfoArgs) { if (!aLoadInfo) { // if there is no loadInfo, then there is nothing to serialize *aOptionalLoadInfoArgs = void_t(); return NS_OK; } nsresult rv = NS_OK; PrincipalInfo requestingPrincipalInfo; rv = PrincipalToPrincipalInfo(aLoadInfo->LoadingPrincipal(), &requestingPrincipalInfo); NS_ENSURE_SUCCESS(rv, rv); PrincipalInfo triggeringPrincipalInfo; rv = PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(), &triggeringPrincipalInfo); nsTArray redirectChainIncludingInternalRedirects; for (const nsCOMPtr& principal : aLoadInfo->RedirectChainIncludingInternalRedirects()) { rv = PrincipalToPrincipalInfo(principal, redirectChainIncludingInternalRedirects.AppendElement()); NS_ENSURE_SUCCESS(rv, rv); } nsTArray redirectChain; for (const nsCOMPtr& principal : aLoadInfo->RedirectChain()) { rv = PrincipalToPrincipalInfo(principal, redirectChain.AppendElement()); NS_ENSURE_SUCCESS(rv, rv); } *aOptionalLoadInfoArgs = LoadInfoArgs( requestingPrincipalInfo, triggeringPrincipalInfo, aLoadInfo->GetSecurityFlags(), aLoadInfo->InternalContentPolicyType(), aLoadInfo->GetUpgradeInsecureRequests(), aLoadInfo->GetInnerWindowID(), aLoadInfo->GetOuterWindowID(), aLoadInfo->GetParentOuterWindowID(), aLoadInfo->GetEnforceSecurity(), aLoadInfo->GetInitialSecurityCheckDone(), aLoadInfo->GetOriginAttributes(), redirectChainIncludingInternalRedirects, redirectChain); return NS_OK; } nsresult LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, nsILoadInfo** outLoadInfo) { if (aOptionalLoadInfoArgs.type() == OptionalLoadInfoArgs::Tvoid_t) { *outLoadInfo = nullptr; return NS_OK; } const LoadInfoArgs& loadInfoArgs = aOptionalLoadInfoArgs.get_LoadInfoArgs(); nsresult rv = NS_OK; nsCOMPtr requestingPrincipal = PrincipalInfoToPrincipal(loadInfoArgs.requestingPrincipalInfo(), &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr triggeringPrincipal = PrincipalInfoToPrincipal(loadInfoArgs.triggeringPrincipalInfo(), &rv); NS_ENSURE_SUCCESS(rv, rv); nsTArray> redirectChainIncludingInternalRedirects; for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChainIncludingInternalRedirects()) { nsCOMPtr redirectedPrincipal = PrincipalInfoToPrincipal(principalInfo, &rv); NS_ENSURE_SUCCESS(rv, rv); redirectChainIncludingInternalRedirects.AppendElement(redirectedPrincipal.forget()); } nsTArray> redirectChain; for (const PrincipalInfo& principalInfo : loadInfoArgs.redirectChain()) { nsCOMPtr redirectedPrincipal = PrincipalInfoToPrincipal(principalInfo, &rv); NS_ENSURE_SUCCESS(rv, rv); redirectChain.AppendElement(redirectedPrincipal.forget()); } nsCOMPtr loadInfo = new mozilla::LoadInfo(requestingPrincipal, triggeringPrincipal, loadInfoArgs.securityFlags(), loadInfoArgs.contentPolicyType(), loadInfoArgs.upgradeInsecureRequests(), loadInfoArgs.innerWindowID(), loadInfoArgs.outerWindowID(), loadInfoArgs.parentOuterWindowID(), loadInfoArgs.enforceSecurity(), loadInfoArgs.initialSecurityCheckDone(), loadInfoArgs.originAttributes(), redirectChainIncludingInternalRedirects, redirectChain); loadInfo.forget(outLoadInfo); return NS_OK; } } // namespace ipc } // namespace mozilla