1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 sts=2 ts=2 et tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /**
8  * This is the principal that has no rights and can't be accessed by
9  * anything other than itself and chrome; null principals are not
10  * same-origin with anything but themselves.
11  */
12 
13 #include "mozilla/ArrayUtils.h"
14 
15 #include "mozilla/dom/BlobURLProtocolHandler.h"
16 #include "mozilla/StaticPrefs_network.h"
17 #include "nsDocShell.h"
18 #include "NullPrincipal.h"
19 #include "DefaultURI.h"
20 #include "nsSimpleURI.h"
21 #include "nsMemory.h"
22 #include "nsIClassInfoImpl.h"
23 #include "nsNetCID.h"
24 #include "nsError.h"
25 #include "ContentPrincipal.h"
26 #include "nsScriptSecurityManager.h"
27 #include "pratom.h"
28 #include "nsIObjectInputStream.h"
29 #include "mozilla/GkRustUtils.h"
30 
31 #include "json/json.h"
32 
33 using namespace mozilla;
34 
NS_IMPL_CLASSINFO(NullPrincipal,nullptr,nsIClassInfo::MAIN_THREAD_ONLY,NS_NULLPRINCIPAL_CID)35 NS_IMPL_CLASSINFO(NullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
36                   NS_NULLPRINCIPAL_CID)
37 NS_IMPL_QUERY_INTERFACE_CI(NullPrincipal, nsIPrincipal)
38 NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal, nsIPrincipal)
39 
40 NullPrincipal::NullPrincipal(nsIURI* aURI, const nsACString& aOriginNoSuffix,
41                              const OriginAttributes& aOriginAttributes)
42     : BasePrincipal(eNullPrincipal, aOriginNoSuffix, aOriginAttributes),
43       mURI(aURI) {}
44 
45 /* static */
CreateWithInheritedAttributes(nsIPrincipal * aInheritFrom)46 already_AddRefed<NullPrincipal> NullPrincipal::CreateWithInheritedAttributes(
47     nsIPrincipal* aInheritFrom) {
48   MOZ_ASSERT(aInheritFrom);
49   return CreateWithInheritedAttributes(
50       Cast(aInheritFrom)->OriginAttributesRef(), false);
51 }
52 
53 /* static */
CreateWithInheritedAttributes(nsIDocShell * aDocShell,bool aIsFirstParty)54 already_AddRefed<NullPrincipal> NullPrincipal::CreateWithInheritedAttributes(
55     nsIDocShell* aDocShell, bool aIsFirstParty) {
56   MOZ_ASSERT(aDocShell);
57 
58   OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes();
59   return CreateWithInheritedAttributes(attrs, aIsFirstParty);
60 }
61 
62 /* static */
CreateWithInheritedAttributes(const OriginAttributes & aOriginAttributes,bool aIsFirstParty)63 already_AddRefed<NullPrincipal> NullPrincipal::CreateWithInheritedAttributes(
64     const OriginAttributes& aOriginAttributes, bool aIsFirstParty) {
65   return CreateInternal(aOriginAttributes, aIsFirstParty);
66 }
67 
68 /* static */
Create(const OriginAttributes & aOriginAttributes,nsIURI * aURI)69 already_AddRefed<NullPrincipal> NullPrincipal::Create(
70     const OriginAttributes& aOriginAttributes, nsIURI* aURI) {
71   return CreateInternal(aOriginAttributes, false, aURI);
72 }
73 
74 /* static */
CreateWithoutOriginAttributes()75 already_AddRefed<NullPrincipal> NullPrincipal::CreateWithoutOriginAttributes() {
76   return NullPrincipal::Create(OriginAttributes(), nullptr);
77 }
78 
CreateURI()79 already_AddRefed<nsIURI> NullPrincipal::CreateURI() {
80   nsCOMPtr<nsIURIMutator> mutator;
81   if (StaticPrefs::network_url_useDefaultURI()) {
82     mutator = new mozilla::net::DefaultURI::Mutator();
83   } else {
84     mutator = new mozilla::net::nsSimpleURI::Mutator();
85   }
86 
87   nsAutoCStringN<NSID_LENGTH> uuid;
88   GkRustUtils::GenerateUUID(uuid);
89 
90   nsCOMPtr<nsIURI> uri;
91   MOZ_ALWAYS_SUCCEEDS(NS_MutateURI(mutator)
92                           .SetSpec(NS_NULLPRINCIPAL_SCHEME ":"_ns + uuid)
93                           .Finalize(uri));
94   return uri.forget();
95 }
96 
CreateInternal(const OriginAttributes & aOriginAttributes,bool aIsFirstParty,nsIURI * aURI)97 already_AddRefed<NullPrincipal> NullPrincipal::CreateInternal(
98     const OriginAttributes& aOriginAttributes, bool aIsFirstParty,
99     nsIURI* aURI) {
100   nsCOMPtr<nsIURI> uri = aURI;
101   if (!uri) {
102     uri = NullPrincipal::CreateURI();
103   }
104 
105   MOZ_RELEASE_ASSERT(uri->SchemeIs(NS_NULLPRINCIPAL_SCHEME));
106 
107   nsAutoCString originNoSuffix;
108   DebugOnly<nsresult> rv = uri->GetSpec(originNoSuffix);
109   MOZ_ASSERT(NS_SUCCEEDED(rv));
110 
111   OriginAttributes attrs(aOriginAttributes);
112   if (aIsFirstParty) {
113     nsAutoCString path;
114     rv = uri->GetPathQueryRef(path);
115     MOZ_ASSERT(NS_SUCCEEDED(rv));
116 
117     // remove the '{}' characters from both ends.
118     path.Mid(path, 1, path.Length() - 2);
119     path.AppendLiteral(".mozilla");
120     attrs.SetFirstPartyDomain(true, path);
121   }
122 
123   RefPtr<NullPrincipal> nullPrin =
124       new NullPrincipal(uri, originNoSuffix, attrs);
125   return nullPrin.forget();
126 }
127 
GetScriptLocation(nsACString & aStr)128 nsresult NullPrincipal::GetScriptLocation(nsACString& aStr) {
129   return mURI->GetSpec(aStr);
130 }
131 
132 /**
133  * nsIPrincipal implementation
134  */
135 
GetHashValue()136 uint32_t NullPrincipal::GetHashValue() { return (NS_PTR_TO_INT32(this) >> 2); }
137 
138 NS_IMETHODIMP
GetURI(nsIURI ** aURI)139 NullPrincipal::GetURI(nsIURI** aURI) {
140   nsCOMPtr<nsIURI> uri = mURI;
141   uri.forget(aURI);
142   return NS_OK;
143 }
144 NS_IMETHODIMP
GetIsOriginPotentiallyTrustworthy(bool * aResult)145 NullPrincipal::GetIsOriginPotentiallyTrustworthy(bool* aResult) {
146   *aResult = false;
147   return NS_OK;
148 }
149 
150 NS_IMETHODIMP
GetDomain(nsIURI ** aDomain)151 NullPrincipal::GetDomain(nsIURI** aDomain) {
152   nsCOMPtr<nsIURI> uri = mURI;
153   uri.forget(aDomain);
154   return NS_OK;
155 }
156 
157 NS_IMETHODIMP
SetDomain(nsIURI * aDomain)158 NullPrincipal::SetDomain(nsIURI* aDomain) {
159   // I think the right thing to do here is to just throw...  Silently failing
160   // seems counterproductive.
161   return NS_ERROR_NOT_AVAILABLE;
162 }
163 
MayLoadInternal(nsIURI * aURI)164 bool NullPrincipal::MayLoadInternal(nsIURI* aURI) {
165   // Also allow the load if we are the principal of the URI being checked.
166   nsCOMPtr<nsIPrincipal> blobPrincipal;
167   if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(
168           aURI, getter_AddRefs(blobPrincipal))) {
169     MOZ_ASSERT(blobPrincipal);
170     return SubsumesInternal(blobPrincipal,
171                             BasePrincipal::ConsiderDocumentDomain);
172   }
173 
174   return false;
175 }
176 
177 NS_IMETHODIMP
GetBaseDomain(nsACString & aBaseDomain)178 NullPrincipal::GetBaseDomain(nsACString& aBaseDomain) {
179   // For a null principal, we use our unique uuid as the base domain.
180   return mURI->GetPathQueryRef(aBaseDomain);
181 }
182 
183 NS_IMETHODIMP
GetAddonId(nsAString & aAddonId)184 NullPrincipal::GetAddonId(nsAString& aAddonId) {
185   aAddonId.Truncate();
186   return NS_OK;
187 };
188 
189 /**
190  * nsISerializable implementation
191  */
192 NS_IMETHODIMP
Read(nsIObjectInputStream * aStream)193 NullPrincipal::Deserializer::Read(nsIObjectInputStream* aStream) {
194   nsAutoCString spec;
195   nsresult rv = aStream->ReadCString(spec);
196   NS_ENSURE_SUCCESS(rv, rv);
197 
198   nsCOMPtr<nsIURI> uri;
199   rv = NS_NewURI(getter_AddRefs(uri), spec);
200   NS_ENSURE_SUCCESS(rv, rv);
201 
202   nsAutoCString suffix;
203   rv = aStream->ReadCString(suffix);
204   NS_ENSURE_SUCCESS(rv, rv);
205 
206   OriginAttributes attrs;
207   bool ok = attrs.PopulateFromSuffix(suffix);
208   NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
209 
210   mPrincipal = NullPrincipal::Create(attrs, uri);
211   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
212 
213   return NS_OK;
214 }
215 
PopulateJSONObject(Json::Value & aObject)216 nsresult NullPrincipal::PopulateJSONObject(Json::Value& aObject) {
217   nsAutoCString principalURI;
218   nsresult rv = mURI->GetSpec(principalURI);
219   NS_ENSURE_SUCCESS(rv, rv);
220   MOZ_ASSERT(principalURI.Length() ==
221                  nsLiteralCString(NS_NULLPRINCIPAL_SCHEME ":").Length() +
222                      NSID_LENGTH - 1,
223              "Length of the URI should be: (scheme, uuid, - nullptr)");
224   aObject[std::to_string(eSpec)] = principalURI.get();
225 
226   nsAutoCString suffix;
227   OriginAttributesRef().CreateSuffix(suffix);
228   if (suffix.Length() > 0) {
229     aObject[std::to_string(eSuffix)] = suffix.get();
230   }
231 
232   return NS_OK;
233 }
234 
FromProperties(nsTArray<NullPrincipal::KeyVal> & aFields)235 already_AddRefed<BasePrincipal> NullPrincipal::FromProperties(
236     nsTArray<NullPrincipal::KeyVal>& aFields) {
237   MOZ_ASSERT(aFields.Length() == eMax + 1, "Must have all the keys");
238   nsresult rv;
239   nsCOMPtr<nsIURI> uri;
240   OriginAttributes attrs;
241 
242   // The odd structure here is to make the code to not compile
243   // if all the switch enum cases haven't been codified
244   for (const auto& field : aFields) {
245     switch (field.key) {
246       case NullPrincipal::eSpec:
247         if (!field.valueWasSerialized) {
248           MOZ_ASSERT(false,
249                      "Null principals require a spec URI in serialized JSON");
250           return nullptr;
251         }
252         rv = NS_NewURI(getter_AddRefs(uri), field.value);
253         NS_ENSURE_SUCCESS(rv, nullptr);
254         break;
255       case NullPrincipal::eSuffix:
256         bool ok = attrs.PopulateFromSuffix(field.value);
257         if (!ok) {
258           return nullptr;
259         }
260         break;
261     }
262   }
263 
264   if (!uri) {
265     MOZ_ASSERT(false, "No URI deserialized");
266     return nullptr;
267   }
268 
269   return NullPrincipal::Create(attrs, uri);
270 }
271