|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 sw=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 #include "nsPrincipal.h" |
|
8 |
|
9 #include "mozIThirdPartyUtil.h" |
|
10 #include "nscore.h" |
|
11 #include "nsScriptSecurityManager.h" |
|
12 #include "nsString.h" |
|
13 #include "nsReadableUtils.h" |
|
14 #include "pratom.h" |
|
15 #include "nsIURI.h" |
|
16 #include "nsJSPrincipals.h" |
|
17 #include "nsIObjectInputStream.h" |
|
18 #include "nsIObjectOutputStream.h" |
|
19 #include "nsIClassInfoImpl.h" |
|
20 #include "nsError.h" |
|
21 #include "nsIContentSecurityPolicy.h" |
|
22 #include "nsCxPusher.h" |
|
23 #include "jswrapper.h" |
|
24 |
|
25 #include "mozilla/Preferences.h" |
|
26 #include "mozilla/HashFunctions.h" |
|
27 |
|
28 #include "nsIAppsService.h" |
|
29 #include "mozIApplication.h" |
|
30 |
|
31 using namespace mozilla; |
|
32 |
|
33 static bool gCodeBasePrincipalSupport = false; |
|
34 static bool gIsObservingCodeBasePrincipalSupport = false; |
|
35 |
|
36 static bool URIIsImmutable(nsIURI* aURI) |
|
37 { |
|
38 nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(aURI)); |
|
39 bool isMutable; |
|
40 return |
|
41 mutableObj && |
|
42 NS_SUCCEEDED(mutableObj->GetMutable(&isMutable)) && |
|
43 !isMutable; |
|
44 } |
|
45 |
|
46 // Static member variables |
|
47 const char nsBasePrincipal::sInvalid[] = "Invalid"; |
|
48 |
|
49 NS_IMETHODIMP_(MozExternalRefCountType) |
|
50 nsBasePrincipal::AddRef() |
|
51 { |
|
52 NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt"); |
|
53 // XXXcaa does this need to be threadsafe? See bug 143559. |
|
54 nsrefcnt count = ++refcount; |
|
55 NS_LOG_ADDREF(this, count, "nsBasePrincipal", sizeof(*this)); |
|
56 return count; |
|
57 } |
|
58 |
|
59 NS_IMETHODIMP_(MozExternalRefCountType) |
|
60 nsBasePrincipal::Release() |
|
61 { |
|
62 NS_PRECONDITION(0 != refcount, "dup release"); |
|
63 nsrefcnt count = --refcount; |
|
64 NS_LOG_RELEASE(this, count, "nsBasePrincipal"); |
|
65 if (count == 0) { |
|
66 delete this; |
|
67 } |
|
68 |
|
69 return count; |
|
70 } |
|
71 |
|
72 nsBasePrincipal::nsBasePrincipal() |
|
73 { |
|
74 if (!gIsObservingCodeBasePrincipalSupport) { |
|
75 nsresult rv = |
|
76 Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport, |
|
77 "signed.applets.codebase_principal_support", |
|
78 false); |
|
79 gIsObservingCodeBasePrincipalSupport = NS_SUCCEEDED(rv); |
|
80 NS_WARN_IF_FALSE(gIsObservingCodeBasePrincipalSupport, |
|
81 "Installing gCodeBasePrincipalSupport failed!"); |
|
82 } |
|
83 } |
|
84 |
|
85 nsBasePrincipal::~nsBasePrincipal(void) |
|
86 { |
|
87 } |
|
88 |
|
89 NS_IMETHODIMP |
|
90 nsBasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) |
|
91 { |
|
92 NS_IF_ADDREF(*aCsp = mCSP); |
|
93 return NS_OK; |
|
94 } |
|
95 |
|
96 NS_IMETHODIMP |
|
97 nsBasePrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) |
|
98 { |
|
99 // If CSP was already set, it should not be destroyed! Instead, it should |
|
100 // get set anew when a new principal is created. |
|
101 if (mCSP) |
|
102 return NS_ERROR_ALREADY_INITIALIZED; |
|
103 |
|
104 mCSP = aCsp; |
|
105 return NS_OK; |
|
106 } |
|
107 |
|
108 #ifdef DEBUG |
|
109 void nsPrincipal::dumpImpl() |
|
110 { |
|
111 nsAutoCString str; |
|
112 GetScriptLocation(str); |
|
113 fprintf(stderr, "nsPrincipal (%p) = %s\n", static_cast<void*>(this), str.get()); |
|
114 } |
|
115 #endif |
|
116 |
|
117 NS_IMPL_CLASSINFO(nsPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, |
|
118 NS_PRINCIPAL_CID) |
|
119 NS_IMPL_QUERY_INTERFACE_CI(nsPrincipal, |
|
120 nsIPrincipal, |
|
121 nsISerializable) |
|
122 NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal, |
|
123 nsIPrincipal, |
|
124 nsISerializable) |
|
125 NS_IMPL_ADDREF_INHERITED(nsPrincipal, nsBasePrincipal) |
|
126 NS_IMPL_RELEASE_INHERITED(nsPrincipal, nsBasePrincipal) |
|
127 |
|
128 nsPrincipal::nsPrincipal() |
|
129 : mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID) |
|
130 , mInMozBrowser(false) |
|
131 , mCodebaseImmutable(false) |
|
132 , mDomainImmutable(false) |
|
133 , mInitialized(false) |
|
134 { } |
|
135 |
|
136 nsPrincipal::~nsPrincipal() |
|
137 { } |
|
138 |
|
139 nsresult |
|
140 nsPrincipal::Init(nsIURI *aCodebase, |
|
141 uint32_t aAppId, |
|
142 bool aInMozBrowser) |
|
143 { |
|
144 NS_ENSURE_STATE(!mInitialized); |
|
145 NS_ENSURE_ARG(aCodebase); |
|
146 |
|
147 mInitialized = true; |
|
148 |
|
149 mCodebase = NS_TryToMakeImmutable(aCodebase); |
|
150 mCodebaseImmutable = URIIsImmutable(mCodebase); |
|
151 |
|
152 mAppId = aAppId; |
|
153 mInMozBrowser = aInMozBrowser; |
|
154 |
|
155 return NS_OK; |
|
156 } |
|
157 |
|
158 void |
|
159 nsPrincipal::GetScriptLocation(nsACString &aStr) |
|
160 { |
|
161 mCodebase->GetSpec(aStr); |
|
162 } |
|
163 |
|
164 /* static */ nsresult |
|
165 nsPrincipal::GetOriginForURI(nsIURI* aURI, char **aOrigin) |
|
166 { |
|
167 if (!aURI) { |
|
168 return NS_ERROR_FAILURE; |
|
169 } |
|
170 |
|
171 *aOrigin = nullptr; |
|
172 |
|
173 nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI); |
|
174 if (!origin) { |
|
175 return NS_ERROR_FAILURE; |
|
176 } |
|
177 |
|
178 nsAutoCString hostPort; |
|
179 |
|
180 // chrome: URLs don't have a meaningful origin, so make |
|
181 // sure we just get the full spec for them. |
|
182 // XXX this should be removed in favor of the solution in |
|
183 // bug 160042. |
|
184 bool isChrome; |
|
185 nsresult rv = origin->SchemeIs("chrome", &isChrome); |
|
186 if (NS_SUCCEEDED(rv) && !isChrome) { |
|
187 rv = origin->GetAsciiHost(hostPort); |
|
188 // Some implementations return an empty string, treat it as no support |
|
189 // for asciiHost by that implementation. |
|
190 if (hostPort.IsEmpty()) { |
|
191 rv = NS_ERROR_FAILURE; |
|
192 } |
|
193 } |
|
194 |
|
195 int32_t port; |
|
196 if (NS_SUCCEEDED(rv) && !isChrome) { |
|
197 rv = origin->GetPort(&port); |
|
198 } |
|
199 |
|
200 if (NS_SUCCEEDED(rv) && !isChrome) { |
|
201 if (port != -1) { |
|
202 hostPort.AppendLiteral(":"); |
|
203 hostPort.AppendInt(port, 10); |
|
204 } |
|
205 |
|
206 nsAutoCString scheme; |
|
207 rv = origin->GetScheme(scheme); |
|
208 NS_ENSURE_SUCCESS(rv, rv); |
|
209 |
|
210 *aOrigin = ToNewCString(scheme + NS_LITERAL_CSTRING("://") + hostPort); |
|
211 } |
|
212 else { |
|
213 // Some URIs (e.g., nsSimpleURI) don't support asciiHost. Just |
|
214 // get the full spec. |
|
215 nsAutoCString spec; |
|
216 // XXX nsMozIconURI and nsJARURI don't implement this correctly, they |
|
217 // both fall back to GetSpec. That needs to be fixed. |
|
218 rv = origin->GetAsciiSpec(spec); |
|
219 NS_ENSURE_SUCCESS(rv, rv); |
|
220 |
|
221 *aOrigin = ToNewCString(spec); |
|
222 } |
|
223 |
|
224 return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
225 } |
|
226 |
|
227 NS_IMETHODIMP |
|
228 nsPrincipal::GetOrigin(char **aOrigin) |
|
229 { |
|
230 return GetOriginForURI(mCodebase, aOrigin); |
|
231 } |
|
232 |
|
233 NS_IMETHODIMP |
|
234 nsPrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult) |
|
235 { |
|
236 *aResult = false; |
|
237 |
|
238 if (!aOther) { |
|
239 NS_WARNING("Need a principal to compare this to!"); |
|
240 return NS_OK; |
|
241 } |
|
242 |
|
243 if (aOther == this) { |
|
244 *aResult = true; |
|
245 return NS_OK; |
|
246 } |
|
247 |
|
248 if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther)) { |
|
249 return NS_OK; |
|
250 } |
|
251 |
|
252 // If either the subject or the object has changed its principal by |
|
253 // explicitly setting document.domain then the other must also have |
|
254 // done so in order to be considered the same origin. This prevents |
|
255 // DNS spoofing based on document.domain (154930) |
|
256 |
|
257 nsCOMPtr<nsIURI> thisURI; |
|
258 this->GetDomain(getter_AddRefs(thisURI)); |
|
259 bool thisSetDomain = !!thisURI; |
|
260 if (!thisURI) { |
|
261 this->GetURI(getter_AddRefs(thisURI)); |
|
262 } |
|
263 |
|
264 nsCOMPtr<nsIURI> otherURI; |
|
265 aOther->GetDomain(getter_AddRefs(otherURI)); |
|
266 bool otherSetDomain = !!otherURI; |
|
267 if (!otherURI) { |
|
268 aOther->GetURI(getter_AddRefs(otherURI)); |
|
269 } |
|
270 |
|
271 *aResult = thisSetDomain == otherSetDomain && |
|
272 nsScriptSecurityManager::SecurityCompareURIs(thisURI, otherURI); |
|
273 return NS_OK; |
|
274 } |
|
275 |
|
276 NS_IMETHODIMP |
|
277 nsPrincipal::Equals(nsIPrincipal *aOther, bool *aResult) |
|
278 { |
|
279 *aResult = false; |
|
280 |
|
281 if (!aOther) { |
|
282 NS_WARNING("Need a principal to compare this to!"); |
|
283 return NS_OK; |
|
284 } |
|
285 |
|
286 if (aOther == this) { |
|
287 *aResult = true; |
|
288 return NS_OK; |
|
289 } |
|
290 |
|
291 if (!nsScriptSecurityManager::AppAttributesEqual(this, aOther)) { |
|
292 return NS_OK; |
|
293 } |
|
294 |
|
295 nsCOMPtr<nsIURI> otherURI; |
|
296 nsresult rv = aOther->GetURI(getter_AddRefs(otherURI)); |
|
297 if (NS_FAILED(rv)) { |
|
298 return rv; |
|
299 } |
|
300 |
|
301 NS_ASSERTION(mCodebase, |
|
302 "shouldn't be calling this on principals from preferences"); |
|
303 |
|
304 // Compare codebases. |
|
305 *aResult = nsScriptSecurityManager::SecurityCompareURIs(mCodebase, |
|
306 otherURI); |
|
307 return NS_OK; |
|
308 } |
|
309 |
|
310 NS_IMETHODIMP |
|
311 nsPrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult) |
|
312 { |
|
313 return Equals(aOther, aResult); |
|
314 } |
|
315 |
|
316 NS_IMETHODIMP |
|
317 nsPrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult) |
|
318 { |
|
319 return EqualsConsideringDomain(aOther, aResult); |
|
320 } |
|
321 |
|
322 NS_IMETHODIMP |
|
323 nsPrincipal::GetURI(nsIURI** aURI) |
|
324 { |
|
325 if (mCodebaseImmutable) { |
|
326 NS_ADDREF(*aURI = mCodebase); |
|
327 return NS_OK; |
|
328 } |
|
329 |
|
330 if (!mCodebase) { |
|
331 *aURI = nullptr; |
|
332 return NS_OK; |
|
333 } |
|
334 |
|
335 return NS_EnsureSafeToReturn(mCodebase, aURI); |
|
336 } |
|
337 |
|
338 NS_IMETHODIMP |
|
339 nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrincipal) |
|
340 { |
|
341 if (aAllowIfInheritsPrincipal) { |
|
342 // If the caller specified to allow loads of URIs that inherit |
|
343 // our principal, allow the load if this URI inherits its principal |
|
344 if (nsPrincipal::IsPrincipalInherited(aURI)) { |
|
345 return NS_OK; |
|
346 } |
|
347 } |
|
348 |
|
349 if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) { |
|
350 return NS_OK; |
|
351 } |
|
352 |
|
353 // If strict file origin policy is in effect, local files will always fail |
|
354 // SecurityCompareURIs unless they are identical. Explicitly check file origin |
|
355 // policy, in that case. |
|
356 if (nsScriptSecurityManager::GetStrictFileOriginPolicy() && |
|
357 NS_URIIsLocalFile(aURI) && |
|
358 NS_RelaxStrictFileOriginPolicy(aURI, mCodebase)) { |
|
359 return NS_OK; |
|
360 } |
|
361 |
|
362 if (aReport) { |
|
363 nsScriptSecurityManager::ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI); |
|
364 } |
|
365 return NS_ERROR_DOM_BAD_URI; |
|
366 } |
|
367 |
|
368 void |
|
369 nsPrincipal::SetURI(nsIURI* aURI) |
|
370 { |
|
371 mCodebase = NS_TryToMakeImmutable(aURI); |
|
372 mCodebaseImmutable = URIIsImmutable(mCodebase); |
|
373 } |
|
374 |
|
375 NS_IMETHODIMP |
|
376 nsPrincipal::GetHashValue(uint32_t* aValue) |
|
377 { |
|
378 NS_PRECONDITION(mCodebase, "Need a codebase"); |
|
379 |
|
380 *aValue = nsScriptSecurityManager::HashPrincipalByOrigin(this); |
|
381 return NS_OK; |
|
382 } |
|
383 |
|
384 NS_IMETHODIMP |
|
385 nsPrincipal::GetDomain(nsIURI** aDomain) |
|
386 { |
|
387 if (!mDomain) { |
|
388 *aDomain = nullptr; |
|
389 return NS_OK; |
|
390 } |
|
391 |
|
392 if (mDomainImmutable) { |
|
393 NS_ADDREF(*aDomain = mDomain); |
|
394 return NS_OK; |
|
395 } |
|
396 |
|
397 return NS_EnsureSafeToReturn(mDomain, aDomain); |
|
398 } |
|
399 |
|
400 NS_IMETHODIMP |
|
401 nsPrincipal::SetDomain(nsIURI* aDomain) |
|
402 { |
|
403 mDomain = NS_TryToMakeImmutable(aDomain); |
|
404 mDomainImmutable = URIIsImmutable(mDomain); |
|
405 |
|
406 // Recompute all wrappers between compartments using this principal and other |
|
407 // non-chrome compartments. |
|
408 AutoSafeJSContext cx; |
|
409 JSPrincipals *principals = nsJSPrincipals::get(static_cast<nsIPrincipal*>(this)); |
|
410 bool success = js::RecomputeWrappers(cx, js::ContentCompartmentsOnly(), |
|
411 js::CompartmentsWithPrincipals(principals)); |
|
412 NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); |
|
413 success = js::RecomputeWrappers(cx, js::CompartmentsWithPrincipals(principals), |
|
414 js::ContentCompartmentsOnly()); |
|
415 NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); |
|
416 |
|
417 return NS_OK; |
|
418 } |
|
419 |
|
420 NS_IMETHODIMP |
|
421 nsPrincipal::GetJarPrefix(nsACString& aJarPrefix) |
|
422 { |
|
423 MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); |
|
424 |
|
425 mozilla::GetJarPrefix(mAppId, mInMozBrowser, aJarPrefix); |
|
426 return NS_OK; |
|
427 } |
|
428 |
|
429 NS_IMETHODIMP |
|
430 nsPrincipal::GetAppStatus(uint16_t* aAppStatus) |
|
431 { |
|
432 *aAppStatus = GetAppStatus(); |
|
433 return NS_OK; |
|
434 } |
|
435 |
|
436 NS_IMETHODIMP |
|
437 nsPrincipal::GetAppId(uint32_t* aAppId) |
|
438 { |
|
439 if (mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
440 MOZ_ASSERT(false); |
|
441 *aAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
442 return NS_OK; |
|
443 } |
|
444 |
|
445 *aAppId = mAppId; |
|
446 return NS_OK; |
|
447 } |
|
448 |
|
449 NS_IMETHODIMP |
|
450 nsPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement) |
|
451 { |
|
452 *aIsInBrowserElement = mInMozBrowser; |
|
453 return NS_OK; |
|
454 } |
|
455 |
|
456 NS_IMETHODIMP |
|
457 nsPrincipal::GetUnknownAppId(bool* aUnknownAppId) |
|
458 { |
|
459 *aUnknownAppId = mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID; |
|
460 return NS_OK; |
|
461 } |
|
462 |
|
463 NS_IMETHODIMP |
|
464 nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) |
|
465 { |
|
466 *aIsNullPrincipal = false; |
|
467 return NS_OK; |
|
468 } |
|
469 |
|
470 NS_IMETHODIMP |
|
471 nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) |
|
472 { |
|
473 // For a file URI, we return the file path. |
|
474 if (NS_URIIsLocalFile(mCodebase)) { |
|
475 nsCOMPtr<nsIURL> url = do_QueryInterface(mCodebase); |
|
476 |
|
477 if (url) { |
|
478 return url->GetFilePath(aBaseDomain); |
|
479 } |
|
480 } |
|
481 |
|
482 // For everything else, we ask the TLD service via |
|
483 // the ThirdPartyUtil. |
|
484 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = |
|
485 do_GetService(THIRDPARTYUTIL_CONTRACTID); |
|
486 if (thirdPartyUtil) { |
|
487 return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain); |
|
488 } |
|
489 |
|
490 return NS_OK; |
|
491 } |
|
492 |
|
493 NS_IMETHODIMP |
|
494 nsPrincipal::Read(nsIObjectInputStream* aStream) |
|
495 { |
|
496 nsCOMPtr<nsISupports> supports; |
|
497 nsCOMPtr<nsIURI> codebase; |
|
498 nsresult rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); |
|
499 if (NS_FAILED(rv)) { |
|
500 return rv; |
|
501 } |
|
502 |
|
503 codebase = do_QueryInterface(supports); |
|
504 |
|
505 nsCOMPtr<nsIURI> domain; |
|
506 rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); |
|
507 if (NS_FAILED(rv)) { |
|
508 return rv; |
|
509 } |
|
510 |
|
511 domain = do_QueryInterface(supports); |
|
512 |
|
513 uint32_t appId; |
|
514 rv = aStream->Read32(&appId); |
|
515 NS_ENSURE_SUCCESS(rv, rv); |
|
516 |
|
517 bool inMozBrowser; |
|
518 rv = aStream->ReadBoolean(&inMozBrowser); |
|
519 NS_ENSURE_SUCCESS(rv, rv); |
|
520 |
|
521 rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports)); |
|
522 NS_ENSURE_SUCCESS(rv, rv); |
|
523 |
|
524 // This may be null. |
|
525 nsCOMPtr<nsIContentSecurityPolicy> csp = do_QueryInterface(supports, &rv); |
|
526 |
|
527 rv = Init(codebase, appId, inMozBrowser); |
|
528 NS_ENSURE_SUCCESS(rv, rv); |
|
529 |
|
530 rv = SetCsp(csp); |
|
531 NS_ENSURE_SUCCESS(rv, rv); |
|
532 |
|
533 // need to link in the CSP context here (link in a reference to this |
|
534 // nsIPrincipal and to the URI of the protected resource). |
|
535 if (csp) { |
|
536 csp->SetRequestContext(codebase, nullptr, this, nullptr); |
|
537 } |
|
538 |
|
539 SetDomain(domain); |
|
540 |
|
541 return NS_OK; |
|
542 } |
|
543 |
|
544 NS_IMETHODIMP |
|
545 nsPrincipal::Write(nsIObjectOutputStream* aStream) |
|
546 { |
|
547 NS_ENSURE_STATE(mCodebase); |
|
548 |
|
549 nsresult rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI), |
|
550 true); |
|
551 if (NS_FAILED(rv)) { |
|
552 return rv; |
|
553 } |
|
554 |
|
555 rv = NS_WriteOptionalCompoundObject(aStream, mDomain, NS_GET_IID(nsIURI), |
|
556 true); |
|
557 if (NS_FAILED(rv)) { |
|
558 return rv; |
|
559 } |
|
560 |
|
561 aStream->Write32(mAppId); |
|
562 aStream->WriteBoolean(mInMozBrowser); |
|
563 |
|
564 rv = NS_WriteOptionalCompoundObject(aStream, mCSP, |
|
565 NS_GET_IID(nsIContentSecurityPolicy), |
|
566 true); |
|
567 if (NS_FAILED(rv)) { |
|
568 return rv; |
|
569 } |
|
570 |
|
571 // mCodebaseImmutable and mDomainImmutable will be recomputed based |
|
572 // on the deserialized URIs in Read(). |
|
573 |
|
574 return NS_OK; |
|
575 } |
|
576 |
|
577 uint16_t |
|
578 nsPrincipal::GetAppStatus() |
|
579 { |
|
580 NS_WARN_IF_FALSE(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID, |
|
581 "Asking for app status on a principal with an unknown app id"); |
|
582 // Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID) |
|
583 // and they are not inside a mozbrowser. |
|
584 if (mAppId == nsIScriptSecurityManager::NO_APP_ID || |
|
585 mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID || mInMozBrowser) { |
|
586 return nsIPrincipal::APP_STATUS_NOT_INSTALLED; |
|
587 } |
|
588 |
|
589 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); |
|
590 NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
591 |
|
592 nsCOMPtr<mozIApplication> app; |
|
593 appsService->GetAppByLocalId(mAppId, getter_AddRefs(app)); |
|
594 NS_ENSURE_TRUE(app, nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
595 |
|
596 uint16_t status = nsIPrincipal::APP_STATUS_INSTALLED; |
|
597 NS_ENSURE_SUCCESS(app->GetAppStatus(&status), |
|
598 nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
599 |
|
600 nsAutoCString origin; |
|
601 NS_ENSURE_SUCCESS(GetOrigin(getter_Copies(origin)), |
|
602 nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
603 nsString appOrigin; |
|
604 NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin), |
|
605 nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
606 |
|
607 // We go from string -> nsIURI -> origin to be sure we |
|
608 // compare two punny-encoded origins. |
|
609 nsCOMPtr<nsIURI> appURI; |
|
610 NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin), |
|
611 nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
612 |
|
613 nsAutoCString appOriginPunned; |
|
614 NS_ENSURE_SUCCESS(GetOriginForURI(appURI, getter_Copies(appOriginPunned)), |
|
615 nsIPrincipal::APP_STATUS_NOT_INSTALLED); |
|
616 |
|
617 if (!appOriginPunned.Equals(origin)) { |
|
618 return nsIPrincipal::APP_STATUS_NOT_INSTALLED; |
|
619 } |
|
620 |
|
621 return status; |
|
622 } |
|
623 |
|
624 /************************************************************************************************************************/ |
|
625 |
|
626 static const char EXPANDED_PRINCIPAL_SPEC[] = "[Expanded Principal]"; |
|
627 |
|
628 NS_IMPL_CLASSINFO(nsExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, |
|
629 NS_EXPANDEDPRINCIPAL_CID) |
|
630 NS_IMPL_QUERY_INTERFACE_CI(nsExpandedPrincipal, |
|
631 nsIPrincipal, |
|
632 nsIExpandedPrincipal) |
|
633 NS_IMPL_CI_INTERFACE_GETTER(nsExpandedPrincipal, |
|
634 nsIPrincipal, |
|
635 nsIExpandedPrincipal) |
|
636 NS_IMPL_ADDREF_INHERITED(nsExpandedPrincipal, nsBasePrincipal) |
|
637 NS_IMPL_RELEASE_INHERITED(nsExpandedPrincipal, nsBasePrincipal) |
|
638 |
|
639 nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList) |
|
640 { |
|
641 mPrincipals.AppendElements(aWhiteList); |
|
642 } |
|
643 |
|
644 nsExpandedPrincipal::~nsExpandedPrincipal() |
|
645 { } |
|
646 |
|
647 NS_IMETHODIMP |
|
648 nsExpandedPrincipal::GetDomain(nsIURI** aDomain) |
|
649 { |
|
650 *aDomain = nullptr; |
|
651 return NS_OK; |
|
652 } |
|
653 |
|
654 NS_IMETHODIMP |
|
655 nsExpandedPrincipal::SetDomain(nsIURI* aDomain) |
|
656 { |
|
657 return NS_OK; |
|
658 } |
|
659 |
|
660 NS_IMETHODIMP |
|
661 nsExpandedPrincipal::GetOrigin(char** aOrigin) |
|
662 { |
|
663 *aOrigin = ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC)); |
|
664 return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY; |
|
665 } |
|
666 |
|
667 typedef nsresult (NS_STDCALL nsIPrincipal::*nsIPrincipalMemFn)(nsIPrincipal* aOther, |
|
668 bool* aResult); |
|
669 #define CALL_MEMBER_FUNCTION(THIS,MEM_FN) ((THIS)->*(MEM_FN)) |
|
670 |
|
671 // nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsConsideringDomain |
|
672 // shares the same logic. The difference only that Equals requires 'this' |
|
673 // and 'aOther' to Subsume each other while EqualsConsideringDomain requires |
|
674 // bidirectional SubsumesConsideringDomain. |
|
675 static nsresult |
|
676 Equals(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, |
|
677 bool* aResult) |
|
678 { |
|
679 // If (and only if) 'aThis' and 'aOther' both Subsume/SubsumesConsideringDomain |
|
680 // each other, then they are Equal. |
|
681 *aResult = false; |
|
682 // Calling the corresponding subsume function on this (aFn). |
|
683 nsresult rv = CALL_MEMBER_FUNCTION(aThis, aFn)(aOther, aResult); |
|
684 NS_ENSURE_SUCCESS(rv, rv); |
|
685 if (!*aResult) |
|
686 return NS_OK; |
|
687 |
|
688 // Calling the corresponding subsume function on aOther (aFn). |
|
689 rv = CALL_MEMBER_FUNCTION(aOther, aFn)(aThis, aResult); |
|
690 NS_ENSURE_SUCCESS(rv, rv); |
|
691 return NS_OK; |
|
692 } |
|
693 |
|
694 NS_IMETHODIMP |
|
695 nsExpandedPrincipal::Equals(nsIPrincipal* aOther, bool* aResult) |
|
696 { |
|
697 return ::Equals(this, &nsIPrincipal::Subsumes, aOther, aResult); |
|
698 } |
|
699 |
|
700 NS_IMETHODIMP |
|
701 nsExpandedPrincipal::EqualsConsideringDomain(nsIPrincipal* aOther, bool* aResult) |
|
702 { |
|
703 return ::Equals(this, &nsIPrincipal::SubsumesConsideringDomain, aOther, aResult); |
|
704 } |
|
705 |
|
706 // nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesConsideringDomain |
|
707 // shares the same logic. The difference only that Subsumes calls are replaced |
|
708 //with SubsumesConsideringDomain calls in the second case. |
|
709 static nsresult |
|
710 Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, |
|
711 bool* aResult) |
|
712 { |
|
713 nsresult rv; |
|
714 nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aOther); |
|
715 if (expanded) { |
|
716 // If aOther is an ExpandedPrincipal too, check if all of its |
|
717 // principals are subsumed. |
|
718 nsTArray< nsCOMPtr<nsIPrincipal> >* otherList; |
|
719 expanded->GetWhiteList(&otherList); |
|
720 for (uint32_t i = 0; i < otherList->Length(); ++i){ |
|
721 rv = CALL_MEMBER_FUNCTION(aThis, aFn)((*otherList)[i], aResult); |
|
722 NS_ENSURE_SUCCESS(rv, rv); |
|
723 if (!*aResult) { |
|
724 // If we don't subsume at least one principal of aOther, return false. |
|
725 return NS_OK; |
|
726 } |
|
727 } |
|
728 } else { |
|
729 // For a regular aOther, one of our principals must subsume it. |
|
730 nsTArray< nsCOMPtr<nsIPrincipal> >* list; |
|
731 aThis->GetWhiteList(&list); |
|
732 for (uint32_t i = 0; i < list->Length(); ++i){ |
|
733 rv = CALL_MEMBER_FUNCTION((*list)[i], aFn)(aOther, aResult); |
|
734 NS_ENSURE_SUCCESS(rv, rv); |
|
735 if (*aResult) { |
|
736 // If one of our principal subsumes it, return true. |
|
737 return NS_OK; |
|
738 } |
|
739 } |
|
740 } |
|
741 return NS_OK; |
|
742 } |
|
743 |
|
744 #undef CALL_MEMBER_FUNCTION |
|
745 |
|
746 NS_IMETHODIMP |
|
747 nsExpandedPrincipal::Subsumes(nsIPrincipal* aOther, bool* aResult) |
|
748 { |
|
749 return ::Subsumes(this, &nsIPrincipal::Subsumes, aOther, aResult); |
|
750 } |
|
751 |
|
752 NS_IMETHODIMP |
|
753 nsExpandedPrincipal::SubsumesConsideringDomain(nsIPrincipal* aOther, bool* aResult) |
|
754 { |
|
755 return ::Subsumes(this, &nsIPrincipal::SubsumesConsideringDomain, aOther, aResult); |
|
756 } |
|
757 |
|
758 NS_IMETHODIMP |
|
759 nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport, bool aAllowIfInheritsPrincipal) |
|
760 { |
|
761 nsresult rv; |
|
762 for (uint32_t i = 0; i < mPrincipals.Length(); ++i){ |
|
763 rv = mPrincipals[i]->CheckMayLoad(uri, aReport, aAllowIfInheritsPrincipal); |
|
764 if (NS_SUCCEEDED(rv)) |
|
765 return rv; |
|
766 } |
|
767 |
|
768 return NS_ERROR_DOM_BAD_URI; |
|
769 } |
|
770 |
|
771 NS_IMETHODIMP |
|
772 nsExpandedPrincipal::GetHashValue(uint32_t* result) |
|
773 { |
|
774 MOZ_CRASH("extended principal should never be used as key in a hash map"); |
|
775 } |
|
776 |
|
777 NS_IMETHODIMP |
|
778 nsExpandedPrincipal::GetURI(nsIURI** aURI) |
|
779 { |
|
780 *aURI = nullptr; |
|
781 return NS_OK; |
|
782 } |
|
783 |
|
784 NS_IMETHODIMP |
|
785 nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList) |
|
786 { |
|
787 *aWhiteList = &mPrincipals; |
|
788 return NS_OK; |
|
789 } |
|
790 |
|
791 NS_IMETHODIMP |
|
792 nsExpandedPrincipal::GetJarPrefix(nsACString& aJarPrefix) |
|
793 { |
|
794 aJarPrefix.Truncate(); |
|
795 return NS_OK; |
|
796 } |
|
797 |
|
798 NS_IMETHODIMP |
|
799 nsExpandedPrincipal::GetAppStatus(uint16_t* aAppStatus) |
|
800 { |
|
801 *aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED; |
|
802 return NS_OK; |
|
803 } |
|
804 |
|
805 NS_IMETHODIMP |
|
806 nsExpandedPrincipal::GetAppId(uint32_t* aAppId) |
|
807 { |
|
808 *aAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
809 return NS_OK; |
|
810 } |
|
811 |
|
812 NS_IMETHODIMP |
|
813 nsExpandedPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement) |
|
814 { |
|
815 *aIsInBrowserElement = false; |
|
816 return NS_OK; |
|
817 } |
|
818 |
|
819 NS_IMETHODIMP |
|
820 nsExpandedPrincipal::GetUnknownAppId(bool* aUnknownAppId) |
|
821 { |
|
822 *aUnknownAppId = false; |
|
823 return NS_OK; |
|
824 } |
|
825 |
|
826 NS_IMETHODIMP |
|
827 nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) |
|
828 { |
|
829 *aIsNullPrincipal = false; |
|
830 return NS_OK; |
|
831 } |
|
832 |
|
833 NS_IMETHODIMP |
|
834 nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) |
|
835 { |
|
836 return NS_ERROR_NOT_AVAILABLE; |
|
837 } |
|
838 |
|
839 void |
|
840 nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) |
|
841 { |
|
842 // Is that a good idea to list it's principals? |
|
843 aStr.Assign(EXPANDED_PRINCIPAL_SPEC); |
|
844 } |
|
845 |
|
846 #ifdef DEBUG |
|
847 void nsExpandedPrincipal::dumpImpl() |
|
848 { |
|
849 fprintf(stderr, "nsExpandedPrincipal (%p)\n", static_cast<void*>(this)); |
|
850 } |
|
851 #endif |
|
852 |
|
853 ////////////////////////////////////////// |
|
854 // Methods implementing nsISerializable // |
|
855 ////////////////////////////////////////// |
|
856 |
|
857 NS_IMETHODIMP |
|
858 nsExpandedPrincipal::Read(nsIObjectInputStream* aStream) |
|
859 { |
|
860 return NS_ERROR_NOT_IMPLEMENTED; |
|
861 } |
|
862 |
|
863 NS_IMETHODIMP |
|
864 nsExpandedPrincipal::Write(nsIObjectOutputStream* aStream) |
|
865 { |
|
866 return NS_ERROR_NOT_IMPLEMENTED; |
|
867 } |