forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			222 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=4 et sw=2 tw=80: */
 | |
| /* 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 "nsIURIMutator.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;
 | |
|   }
 | |
| 
 | |
|   for (uint32_t i = 0; i < parents.Length(); i++) {
 | |
|     Unused << parents[i]->SendDomainSetChanged(aSetType, aChangeType, aDomain);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| DomainPolicy::DomainPolicy()
 | |
|     : mBlocklist(new DomainSet(BLOCKLIST)),
 | |
|       mSuperBlocklist(new DomainSet(SUPER_BLOCKLIST)),
 | |
|       mAllowlist(new DomainSet(ALLOWLIST)),
 | |
|       mSuperAllowlist(new DomainSet(SUPER_ALLOWLIST)) {
 | |
|   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(!mBlocklist && !mSuperBlocklist && !mAllowlist &&
 | |
|              !mSuperAllowlist);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DomainPolicy::GetBlocklist(nsIDomainSet** aSet) {
 | |
|   nsCOMPtr<nsIDomainSet> set = mBlocklist.get();
 | |
|   set.forget(aSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DomainPolicy::GetSuperBlocklist(nsIDomainSet** aSet) {
 | |
|   nsCOMPtr<nsIDomainSet> set = mSuperBlocklist.get();
 | |
|   set.forget(aSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DomainPolicy::GetAllowlist(nsIDomainSet** aSet) {
 | |
|   nsCOMPtr<nsIDomainSet> set = mAllowlist.get();
 | |
|   set.forget(aSet);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| DomainPolicy::GetSuperAllowlist(nsIDomainSet** aSet) {
 | |
|   nsCOMPtr<nsIDomainSet> set = mSuperAllowlist.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.
 | |
|   mBlocklist->Clear();
 | |
|   mSuperBlocklist->Clear();
 | |
|   mAllowlist->Clear();
 | |
|   mSuperAllowlist->Clear();
 | |
| 
 | |
|   // Null them out.
 | |
|   mBlocklist = nullptr;
 | |
|   mSuperBlocklist = nullptr;
 | |
|   mAllowlist = nullptr;
 | |
|   mSuperAllowlist = 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;
 | |
|   mBlocklist->CloneSet(&aClone->blocklist());
 | |
|   mSuperBlocklist->CloneSet(&aClone->superBlocklist());
 | |
|   mAllowlist->CloneSet(&aClone->allowlist());
 | |
|   mSuperAllowlist->CloneSet(&aClone->superAllowlist());
 | |
| }
 | |
| 
 | |
| static void CopyURIs(const nsTArray<RefPtr<nsIURI>>& aDomains,
 | |
|                      nsIDomainSet* aSet) {
 | |
|   for (uint32_t i = 0; i < aDomains.Length(); i++) {
 | |
|     if (NS_WARN_IF(!aDomains[i])) {
 | |
|       continue;
 | |
|     }
 | |
|     aSet->Add(aDomains[i]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void DomainPolicy::ApplyClone(const DomainPolicyClone* aClone) {
 | |
|   CopyURIs(aClone->blocklist(), mBlocklist);
 | |
|   CopyURIs(aClone->allowlist(), mAllowlist);
 | |
|   CopyURIs(aClone->superBlocklist(), mSuperBlocklist);
 | |
|   CopyURIs(aClone->superAllowlist(), mSuperAllowlist);
 | |
| }
 | |
| 
 | |
| static already_AddRefed<nsIURI> GetCanonicalClone(nsIURI* aURI) {
 | |
|   nsCOMPtr<nsIURI> clone;
 | |
|   nsresult rv =
 | |
|       NS_MutateURI(aURI).SetUserPass(""_ns).SetPathQueryRef(""_ns).Finalize(
 | |
|           clone);
 | |
|   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.Insert(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.Remove(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 = NS_MutateURI(clone).SetHost(domain).Finalize(clone);
 | |
|     NS_ENSURE_SUCCESS(rv, rv);
 | |
|   }
 | |
| 
 | |
|   // No match.
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void DomainSet::CloneSet(nsTArray<RefPtr<nsIURI>>* aDomains) {
 | |
|   AppendToArray(*aDomains, mHashTable);
 | |
| }
 | |
| 
 | |
| } /* namespace mozilla */
 | 
