diff options
Diffstat (limited to 'system/security/script/DomainPolicy.cpp')
-rw-r--r-- | system/security/script/DomainPolicy.cpp | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/system/security/script/DomainPolicy.cpp b/system/security/script/DomainPolicy.cpp new file mode 100644 index 000000000..5296d6751 --- /dev/null +++ b/system/security/script/DomainPolicy.cpp @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "DomainPolicy.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/ipc/URIUtils.h" +#include "mozilla/Unused.h" +#include "nsIMessageManager.h" +#include "nsScriptSecurityManager.h" + +namespace mozilla { + +using namespace ipc; +using namespace dom; + +NS_IMPL_ISUPPORTS(DomainPolicy, nsIDomainPolicy) + +static nsresult +BroadcastDomainSetChange(DomainSetType aSetType, DomainSetChangeType aChangeType, + nsIURI* aDomain = nullptr) +{ + MOZ_ASSERT(XRE_IsParentProcess(), + "DomainPolicy should only be exposed to the chrome process."); + + nsTArray<ContentParent*> parents; + ContentParent::GetAll(parents); + if (!parents.Length()) { + return NS_OK; + } + + OptionalURIParams uri; + SerializeURI(aDomain, uri); + + for (uint32_t i = 0; i < parents.Length(); i++) { + Unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, uri); + } + return NS_OK; +} + +DomainPolicy::DomainPolicy() : mBlacklist(new DomainSet(BLACKLIST)) + , mSuperBlacklist(new DomainSet(SUPER_BLACKLIST)) + , mWhitelist(new DomainSet(WHITELIST)) + , mSuperWhitelist(new DomainSet(SUPER_WHITELIST)) +{ + if (XRE_IsParentProcess()) { + BroadcastDomainSetChange(NO_TYPE, ACTIVATE_POLICY); + } +} + +DomainPolicy::~DomainPolicy() +{ + // The SSM holds a strong ref to the DomainPolicy until Deactivate() is + // invoked, so we should never hit the destructor until that happens. + MOZ_ASSERT(!mBlacklist && !mSuperBlacklist && + !mWhitelist && !mSuperWhitelist); +} + + +NS_IMETHODIMP +DomainPolicy::GetBlacklist(nsIDomainSet** aSet) +{ + nsCOMPtr<nsIDomainSet> set = mBlacklist.get(); + set.forget(aSet); + return NS_OK; +} + +NS_IMETHODIMP +DomainPolicy::GetSuperBlacklist(nsIDomainSet** aSet) +{ + nsCOMPtr<nsIDomainSet> set = mSuperBlacklist.get(); + set.forget(aSet); + return NS_OK; +} + +NS_IMETHODIMP +DomainPolicy::GetWhitelist(nsIDomainSet** aSet) +{ + nsCOMPtr<nsIDomainSet> set = mWhitelist.get(); + set.forget(aSet); + return NS_OK; +} + +NS_IMETHODIMP +DomainPolicy::GetSuperWhitelist(nsIDomainSet** aSet) +{ + nsCOMPtr<nsIDomainSet> set = mSuperWhitelist.get(); + set.forget(aSet); + return NS_OK; +} + +NS_IMETHODIMP +DomainPolicy::Deactivate() +{ + // Clear the hashtables first to free up memory, since script might + // hold the doomed sets alive indefinitely. + mBlacklist->Clear(); + mSuperBlacklist->Clear(); + mWhitelist->Clear(); + mSuperWhitelist->Clear(); + + // Null them out. + mBlacklist = nullptr; + mSuperBlacklist = nullptr; + mWhitelist = nullptr; + mSuperWhitelist = nullptr; + + // Inform the SSM. + nsScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager(); + if (ssm) { + ssm->DeactivateDomainPolicy(); + } + if (XRE_IsParentProcess()) { + BroadcastDomainSetChange(NO_TYPE, DEACTIVATE_POLICY); + } + return NS_OK; +} + +void +DomainPolicy::CloneDomainPolicy(DomainPolicyClone* aClone) +{ + aClone->active() = true; + mBlacklist->CloneSet(&aClone->blacklist()); + mSuperBlacklist->CloneSet(&aClone->superBlacklist()); + mWhitelist->CloneSet(&aClone->whitelist()); + mSuperWhitelist->CloneSet(&aClone->superWhitelist()); +} + +static +void +CopyURIs(const InfallibleTArray<URIParams>& aDomains, nsIDomainSet* aSet) +{ + for (uint32_t i = 0; i < aDomains.Length(); i++) { + nsCOMPtr<nsIURI> uri = DeserializeURI(aDomains[i]); + aSet->Add(uri); + } +} + +void +DomainPolicy::ApplyClone(DomainPolicyClone* aClone) +{ + CopyURIs(aClone->blacklist(), mBlacklist); + CopyURIs(aClone->whitelist(), mWhitelist); + CopyURIs(aClone->superBlacklist(), mSuperBlacklist); + CopyURIs(aClone->superWhitelist(), mSuperWhitelist); +} + +static already_AddRefed<nsIURI> +GetCanonicalClone(nsIURI* aURI) +{ + nsCOMPtr<nsIURI> clone; + nsresult rv = aURI->Clone(getter_AddRefs(clone)); + NS_ENSURE_SUCCESS(rv, nullptr); + rv = clone->SetUserPass(EmptyCString()); + NS_ENSURE_SUCCESS(rv, nullptr); + rv = clone->SetPath(EmptyCString()); + NS_ENSURE_SUCCESS(rv, nullptr); + return clone.forget(); +} + +NS_IMPL_ISUPPORTS(DomainSet, nsIDomainSet) + +NS_IMETHODIMP +DomainSet::Add(nsIURI* aDomain) +{ + nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); + NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); + mHashTable.PutEntry(clone); + if (XRE_IsParentProcess()) + return BroadcastDomainSetChange(mType, ADD_DOMAIN, aDomain); + + return NS_OK; +} + +NS_IMETHODIMP +DomainSet::Remove(nsIURI* aDomain) +{ + nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); + NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); + mHashTable.RemoveEntry(clone); + if (XRE_IsParentProcess()) + return BroadcastDomainSetChange(mType, REMOVE_DOMAIN, aDomain); + + return NS_OK; +} + +NS_IMETHODIMP +DomainSet::Clear() +{ + mHashTable.Clear(); + if (XRE_IsParentProcess()) + return BroadcastDomainSetChange(mType, CLEAR_DOMAINS); + + return NS_OK; +} + +NS_IMETHODIMP +DomainSet::Contains(nsIURI* aDomain, bool* aContains) +{ + *aContains = false; + nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); + NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); + *aContains = mHashTable.Contains(clone); + return NS_OK; +} + +NS_IMETHODIMP +DomainSet::ContainsSuperDomain(nsIURI* aDomain, bool* aContains) +{ + *aContains = false; + nsCOMPtr<nsIURI> clone = GetCanonicalClone(aDomain); + NS_ENSURE_TRUE(clone, NS_ERROR_FAILURE); + nsAutoCString domain; + nsresult rv = clone->GetHost(domain); + NS_ENSURE_SUCCESS(rv, rv); + while (true) { + // Check the current domain. + if (mHashTable.Contains(clone)) { + *aContains = true; + return NS_OK; + } + + // Chop off everything before the first dot, or break if there are no + // dots left. + int32_t index = domain.Find("."); + if (index == kNotFound) + break; + domain.Assign(Substring(domain, index + 1)); + rv = clone->SetHost(domain); + NS_ENSURE_SUCCESS(rv, rv); + } + + // No match. + return NS_OK; + +} + +NS_IMETHODIMP +DomainSet::GetType(uint32_t* aType) +{ + *aType = mType; + return NS_OK; +} + +void +DomainSet::CloneSet(InfallibleTArray<URIParams>* aDomains) +{ + for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) { + nsIURI* key = iter.Get()->GetKey(); + + URIParams uri; + SerializeURI(key, uri); + + aDomains->AppendElement(uri); + } +} + +} /* namespace mozilla */ |