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