|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set ts=4 et sw=4 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 "nsScriptSecurityManager.h" |
|
8 |
|
9 #include "mozilla/ArrayUtils.h" |
|
10 |
|
11 #include "js/OldDebugAPI.h" |
|
12 #include "xpcprivate.h" |
|
13 #include "XPCWrapper.h" |
|
14 #include "nsIServiceManager.h" |
|
15 #include "nsIScriptObjectPrincipal.h" |
|
16 #include "nsIScriptContext.h" |
|
17 #include "nsIURL.h" |
|
18 #include "nsINestedURI.h" |
|
19 #include "nspr.h" |
|
20 #include "nsJSPrincipals.h" |
|
21 #include "nsSystemPrincipal.h" |
|
22 #include "nsPrincipal.h" |
|
23 #include "nsNullPrincipal.h" |
|
24 #include "DomainPolicy.h" |
|
25 #include "nsXPIDLString.h" |
|
26 #include "nsCRT.h" |
|
27 #include "nsCRTGlue.h" |
|
28 #include "nsError.h" |
|
29 #include "nsDOMCID.h" |
|
30 #include "nsIXPConnect.h" |
|
31 #include "nsIXPCSecurityManager.h" |
|
32 #include "nsTextFormatter.h" |
|
33 #include "nsIStringBundle.h" |
|
34 #include "nsNetUtil.h" |
|
35 #include "nsIEffectiveTLDService.h" |
|
36 #include "nsIProperties.h" |
|
37 #include "nsDirectoryServiceDefs.h" |
|
38 #include "nsIFile.h" |
|
39 #include "nsIFileURL.h" |
|
40 #include "nsIZipReader.h" |
|
41 #include "nsIXPConnect.h" |
|
42 #include "nsIScriptGlobalObject.h" |
|
43 #include "nsPIDOMWindow.h" |
|
44 #include "nsIDocShell.h" |
|
45 #include "nsIPrompt.h" |
|
46 #include "nsIWindowWatcher.h" |
|
47 #include "nsIConsoleService.h" |
|
48 #include "nsIJSRuntimeService.h" |
|
49 #include "nsIObserverService.h" |
|
50 #include "nsIContent.h" |
|
51 #include "nsAutoPtr.h" |
|
52 #include "nsDOMJSUtils.h" |
|
53 #include "nsAboutProtocolUtils.h" |
|
54 #include "nsIClassInfo.h" |
|
55 #include "nsIURIFixup.h" |
|
56 #include "nsCDefaultURIFixup.h" |
|
57 #include "nsIChromeRegistry.h" |
|
58 #include "nsIContentSecurityPolicy.h" |
|
59 #include "nsIAsyncVerifyRedirectCallback.h" |
|
60 #include "mozilla/Preferences.h" |
|
61 #include "mozilla/dom/BindingUtils.h" |
|
62 #include <stdint.h> |
|
63 #include "mozilla/ClearOnShutdown.h" |
|
64 #include "mozilla/StaticPtr.h" |
|
65 #include "nsContentUtils.h" |
|
66 #include "nsCxPusher.h" |
|
67 #include "nsJSUtils.h" |
|
68 |
|
69 // This should be probably defined on some other place... but I couldn't find it |
|
70 #define WEBAPPS_PERM_NAME "webapps-manage" |
|
71 |
|
72 using namespace mozilla; |
|
73 using namespace mozilla::dom; |
|
74 |
|
75 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); |
|
76 |
|
77 nsIIOService *nsScriptSecurityManager::sIOService = nullptr; |
|
78 nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr; |
|
79 JSRuntime *nsScriptSecurityManager::sRuntime = 0; |
|
80 bool nsScriptSecurityManager::sStrictFileOriginPolicy = true; |
|
81 |
|
82 bool |
|
83 nsScriptSecurityManager::SubjectIsPrivileged() |
|
84 { |
|
85 JSContext *cx = GetCurrentJSContext(); |
|
86 if (cx && xpc::IsUniversalXPConnectEnabled(cx)) |
|
87 return true; |
|
88 bool isSystem = false; |
|
89 return NS_SUCCEEDED(SubjectPrincipalIsSystem(&isSystem)) && isSystem; |
|
90 } |
|
91 |
|
92 /////////////////////////// |
|
93 // Convenience Functions // |
|
94 /////////////////////////// |
|
95 // Result of this function should not be freed. |
|
96 static inline const char16_t * |
|
97 IDToString(JSContext *cx, jsid id_) |
|
98 { |
|
99 JS::RootedId id(cx, id_); |
|
100 if (JSID_IS_STRING(id)) |
|
101 return JS_GetInternedStringChars(JSID_TO_STRING(id)); |
|
102 |
|
103 JS::Rooted<JS::Value> idval(cx); |
|
104 if (!JS_IdToValue(cx, id, &idval)) |
|
105 return nullptr; |
|
106 JSString *str = JS::ToString(cx, idval); |
|
107 if(!str) |
|
108 return nullptr; |
|
109 return JS_GetStringCharsZ(cx, str); |
|
110 } |
|
111 |
|
112 class nsAutoInPrincipalDomainOriginSetter { |
|
113 public: |
|
114 nsAutoInPrincipalDomainOriginSetter() { |
|
115 ++sInPrincipalDomainOrigin; |
|
116 } |
|
117 ~nsAutoInPrincipalDomainOriginSetter() { |
|
118 --sInPrincipalDomainOrigin; |
|
119 } |
|
120 static uint32_t sInPrincipalDomainOrigin; |
|
121 }; |
|
122 uint32_t nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin; |
|
123 |
|
124 static |
|
125 nsresult |
|
126 GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin) |
|
127 { |
|
128 if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) { |
|
129 // Allow a single recursive call to GetPrincipalDomainOrigin, since that |
|
130 // might be happening on a different principal from the first call. But |
|
131 // after that, cut off the recursion; it just indicates that something |
|
132 // we're doing in this method causes us to reenter a security check here. |
|
133 return NS_ERROR_NOT_AVAILABLE; |
|
134 } |
|
135 |
|
136 nsAutoInPrincipalDomainOriginSetter autoSetter; |
|
137 |
|
138 nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI); |
|
139 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); |
|
140 |
|
141 nsAutoCString hostPort; |
|
142 |
|
143 nsresult rv = uri->GetHostPort(hostPort); |
|
144 if (NS_SUCCEEDED(rv)) { |
|
145 nsAutoCString scheme; |
|
146 rv = uri->GetScheme(scheme); |
|
147 NS_ENSURE_SUCCESS(rv, rv); |
|
148 aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort; |
|
149 } |
|
150 else { |
|
151 // Some URIs (e.g., nsSimpleURI) don't support host. Just |
|
152 // get the full spec. |
|
153 rv = uri->GetSpec(aOrigin); |
|
154 NS_ENSURE_SUCCESS(rv, rv); |
|
155 } |
|
156 |
|
157 return NS_OK; |
|
158 } |
|
159 |
|
160 static |
|
161 nsresult |
|
162 GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal, |
|
163 nsACString& aOrigin) |
|
164 { |
|
165 |
|
166 nsCOMPtr<nsIURI> uri; |
|
167 aPrincipal->GetDomain(getter_AddRefs(uri)); |
|
168 if (!uri) { |
|
169 aPrincipal->GetURI(getter_AddRefs(uri)); |
|
170 } |
|
171 NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); |
|
172 |
|
173 return GetOriginFromURI(uri, aOrigin); |
|
174 } |
|
175 |
|
176 inline void SetPendingException(JSContext *cx, const char *aMsg) |
|
177 { |
|
178 JS_ReportError(cx, "%s", aMsg); |
|
179 } |
|
180 |
|
181 inline void SetPendingException(JSContext *cx, const char16_t *aMsg) |
|
182 { |
|
183 JS_ReportError(cx, "%hs", aMsg); |
|
184 } |
|
185 |
|
186 // Helper class to get stuff from the ClassInfo and not waste extra time with |
|
187 // virtual method calls for things it has already gotten |
|
188 class ClassInfoData |
|
189 { |
|
190 public: |
|
191 ClassInfoData(nsIClassInfo *aClassInfo, const char *aName) |
|
192 : mClassInfo(aClassInfo), |
|
193 mName(const_cast<char *>(aName)), |
|
194 mDidGetFlags(false), |
|
195 mMustFreeName(false) |
|
196 { |
|
197 } |
|
198 |
|
199 ~ClassInfoData() |
|
200 { |
|
201 if (mMustFreeName) |
|
202 nsMemory::Free(mName); |
|
203 } |
|
204 |
|
205 uint32_t GetFlags() |
|
206 { |
|
207 if (!mDidGetFlags) { |
|
208 if (mClassInfo) { |
|
209 nsresult rv = mClassInfo->GetFlags(&mFlags); |
|
210 if (NS_FAILED(rv)) { |
|
211 mFlags = 0; |
|
212 } |
|
213 } else { |
|
214 mFlags = 0; |
|
215 } |
|
216 |
|
217 mDidGetFlags = true; |
|
218 } |
|
219 |
|
220 return mFlags; |
|
221 } |
|
222 |
|
223 bool IsDOMClass() |
|
224 { |
|
225 return !!(GetFlags() & nsIClassInfo::DOM_OBJECT); |
|
226 } |
|
227 |
|
228 const char* GetName() |
|
229 { |
|
230 if (!mName) { |
|
231 if (mClassInfo) { |
|
232 mClassInfo->GetClassDescription(&mName); |
|
233 } |
|
234 |
|
235 if (mName) { |
|
236 mMustFreeName = true; |
|
237 } else { |
|
238 mName = const_cast<char *>("UnnamedClass"); |
|
239 } |
|
240 } |
|
241 |
|
242 return mName; |
|
243 } |
|
244 |
|
245 private: |
|
246 nsIClassInfo *mClassInfo; // WEAK |
|
247 uint32_t mFlags; |
|
248 char *mName; |
|
249 bool mDidGetFlags; |
|
250 bool mMustFreeName; |
|
251 }; |
|
252 |
|
253 JSContext * |
|
254 nsScriptSecurityManager::GetCurrentJSContext() |
|
255 { |
|
256 // Get JSContext from stack. |
|
257 return nsXPConnect::XPConnect()->GetCurrentJSContext(); |
|
258 } |
|
259 |
|
260 JSContext * |
|
261 nsScriptSecurityManager::GetSafeJSContext() |
|
262 { |
|
263 // Get JSContext from stack. |
|
264 return nsXPConnect::XPConnect()->GetSafeJSContext(); |
|
265 } |
|
266 |
|
267 /* static */ |
|
268 bool |
|
269 nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI, |
|
270 nsIURI* aTargetURI) |
|
271 { |
|
272 return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy); |
|
273 } |
|
274 |
|
275 // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI |
|
276 // is consistent with NS_SecurityCompareURIs. See nsNetUtil.h. |
|
277 uint32_t |
|
278 nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI) |
|
279 { |
|
280 return NS_SecurityHashURI(aURI); |
|
281 } |
|
282 |
|
283 NS_IMETHODIMP |
|
284 nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel, |
|
285 nsIPrincipal** aPrincipal) |
|
286 { |
|
287 NS_PRECONDITION(aChannel, "Must have channel!"); |
|
288 nsCOMPtr<nsISupports> owner; |
|
289 aChannel->GetOwner(getter_AddRefs(owner)); |
|
290 if (owner) { |
|
291 CallQueryInterface(owner, aPrincipal); |
|
292 if (*aPrincipal) { |
|
293 return NS_OK; |
|
294 } |
|
295 } |
|
296 |
|
297 // OK, get the principal from the URI. Make sure this does the same thing |
|
298 // as nsDocument::Reset and XULDocument::StartDocumentLoad. |
|
299 nsCOMPtr<nsIURI> uri; |
|
300 nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); |
|
301 NS_ENSURE_SUCCESS(rv, rv); |
|
302 |
|
303 nsCOMPtr<nsIDocShell> docShell; |
|
304 NS_QueryNotificationCallbacks(aChannel, docShell); |
|
305 |
|
306 if (docShell) { |
|
307 return GetDocShellCodebasePrincipal(uri, docShell, aPrincipal); |
|
308 } |
|
309 |
|
310 return GetCodebasePrincipalInternal(uri, UNKNOWN_APP_ID, |
|
311 /* isInBrowserElement */ false, aPrincipal); |
|
312 } |
|
313 |
|
314 NS_IMETHODIMP |
|
315 nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal, |
|
316 bool* aIsSystem) |
|
317 { |
|
318 *aIsSystem = (aPrincipal == mSystemPrincipal); |
|
319 return NS_OK; |
|
320 } |
|
321 |
|
322 NS_IMETHODIMP_(nsIPrincipal *) |
|
323 nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx) |
|
324 { |
|
325 NS_ASSERTION(cx == GetCurrentJSContext(), |
|
326 "Uh, cx is not the current JS context!"); |
|
327 |
|
328 nsresult rv = NS_ERROR_FAILURE; |
|
329 nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv); |
|
330 if (NS_FAILED(rv)) |
|
331 return nullptr; |
|
332 |
|
333 return principal; |
|
334 } |
|
335 |
|
336 ///////////////////////////// |
|
337 // nsScriptSecurityManager // |
|
338 ///////////////////////////// |
|
339 |
|
340 //////////////////////////////////// |
|
341 // Methods implementing ISupports // |
|
342 //////////////////////////////////// |
|
343 NS_IMPL_ISUPPORTS(nsScriptSecurityManager, |
|
344 nsIScriptSecurityManager, |
|
345 nsIXPCSecurityManager, |
|
346 nsIChannelEventSink, |
|
347 nsIObserver) |
|
348 |
|
349 /////////////////////////////////////////////////// |
|
350 // Methods implementing nsIScriptSecurityManager // |
|
351 /////////////////////////////////////////////////// |
|
352 |
|
353 ///////////////// Security Checks ///////////////// |
|
354 |
|
355 bool |
|
356 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx) |
|
357 { |
|
358 // Get the security manager |
|
359 nsScriptSecurityManager *ssm = |
|
360 nsScriptSecurityManager::GetScriptSecurityManager(); |
|
361 |
|
362 NS_ASSERTION(ssm, "Failed to get security manager service"); |
|
363 if (!ssm) |
|
364 return false; |
|
365 |
|
366 nsresult rv; |
|
367 nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv); |
|
368 |
|
369 NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context"); |
|
370 if (NS_FAILED(rv)) |
|
371 return false; // Not just absence of principal, but failure. |
|
372 |
|
373 if (!subjectPrincipal) |
|
374 return true; |
|
375 |
|
376 nsCOMPtr<nsIContentSecurityPolicy> csp; |
|
377 rv = subjectPrincipal->GetCsp(getter_AddRefs(csp)); |
|
378 NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal."); |
|
379 |
|
380 // don't do anything unless there's a CSP |
|
381 if (!csp) |
|
382 return true; |
|
383 |
|
384 bool evalOK = true; |
|
385 bool reportViolation = false; |
|
386 rv = csp->GetAllowsEval(&reportViolation, &evalOK); |
|
387 |
|
388 if (NS_FAILED(rv)) |
|
389 { |
|
390 NS_WARNING("CSP: failed to get allowsEval"); |
|
391 return true; // fail open to not break sites. |
|
392 } |
|
393 |
|
394 if (reportViolation) { |
|
395 nsAutoString fileName; |
|
396 unsigned lineNum = 0; |
|
397 NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP"); |
|
398 |
|
399 JS::AutoFilename scriptFilename; |
|
400 if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) { |
|
401 if (const char *file = scriptFilename.get()) { |
|
402 CopyUTF8toUTF16(nsDependentCString(file), fileName); |
|
403 } |
|
404 } |
|
405 csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, |
|
406 fileName, |
|
407 scriptSample, |
|
408 lineNum, |
|
409 EmptyString(), |
|
410 EmptyString()); |
|
411 } |
|
412 |
|
413 return evalOK; |
|
414 } |
|
415 |
|
416 // static |
|
417 bool |
|
418 nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first, |
|
419 JSPrincipals *second) |
|
420 { |
|
421 return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second)); |
|
422 } |
|
423 |
|
424 NS_IMETHODIMP |
|
425 nsScriptSecurityManager::CheckSameOrigin(JSContext* cx, |
|
426 nsIURI* aTargetURI) |
|
427 { |
|
428 nsresult rv; |
|
429 |
|
430 // Get a context if necessary |
|
431 if (!cx) |
|
432 { |
|
433 cx = GetCurrentJSContext(); |
|
434 if (!cx) |
|
435 return NS_OK; // No JS context, so allow access |
|
436 } |
|
437 |
|
438 // Get a principal from the context |
|
439 nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv); |
|
440 if (NS_FAILED(rv)) |
|
441 return rv; |
|
442 |
|
443 if (!sourcePrincipal) |
|
444 { |
|
445 NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?"); |
|
446 return NS_OK; |
|
447 } |
|
448 |
|
449 if (sourcePrincipal == mSystemPrincipal) |
|
450 { |
|
451 // This is a system (chrome) script, so allow access |
|
452 return NS_OK; |
|
453 } |
|
454 |
|
455 // Get the original URI from the source principal. |
|
456 // This has the effect of ignoring any change to document.domain |
|
457 // which must be done to avoid DNS spoofing (bug 154930) |
|
458 nsCOMPtr<nsIURI> sourceURI; |
|
459 sourcePrincipal->GetDomain(getter_AddRefs(sourceURI)); |
|
460 if (!sourceURI) { |
|
461 sourcePrincipal->GetURI(getter_AddRefs(sourceURI)); |
|
462 NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE); |
|
463 } |
|
464 |
|
465 // Compare origins |
|
466 if (!SecurityCompareURIs(sourceURI, aTargetURI)) |
|
467 { |
|
468 ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI); |
|
469 return NS_ERROR_DOM_BAD_URI; |
|
470 } |
|
471 return NS_OK; |
|
472 } |
|
473 |
|
474 NS_IMETHODIMP |
|
475 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI, |
|
476 nsIURI* aTargetURI, |
|
477 bool reportError) |
|
478 { |
|
479 if (!SecurityCompareURIs(aSourceURI, aTargetURI)) |
|
480 { |
|
481 if (reportError) { |
|
482 ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"), |
|
483 aSourceURI, aTargetURI); |
|
484 } |
|
485 return NS_ERROR_DOM_BAD_URI; |
|
486 } |
|
487 return NS_OK; |
|
488 } |
|
489 |
|
490 /*static*/ uint32_t |
|
491 nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal) |
|
492 { |
|
493 nsCOMPtr<nsIURI> uri; |
|
494 aPrincipal->GetDomain(getter_AddRefs(uri)); |
|
495 if (!uri) |
|
496 aPrincipal->GetURI(getter_AddRefs(uri)); |
|
497 return SecurityHashURI(uri); |
|
498 } |
|
499 |
|
500 /* static */ bool |
|
501 nsScriptSecurityManager::AppAttributesEqual(nsIPrincipal* aFirst, |
|
502 nsIPrincipal* aSecond) |
|
503 { |
|
504 MOZ_ASSERT(aFirst && aSecond, "Don't pass null pointers!"); |
|
505 |
|
506 uint32_t firstAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID; |
|
507 if (!aFirst->GetUnknownAppId()) { |
|
508 firstAppId = aFirst->GetAppId(); |
|
509 } |
|
510 |
|
511 uint32_t secondAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID; |
|
512 if (!aSecond->GetUnknownAppId()) { |
|
513 secondAppId = aSecond->GetAppId(); |
|
514 } |
|
515 |
|
516 return ((firstAppId == secondAppId) && |
|
517 (aFirst->GetIsInBrowserElement() == aSecond->GetIsInBrowserElement())); |
|
518 } |
|
519 |
|
520 NS_IMETHODIMP |
|
521 nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI) |
|
522 { |
|
523 // Get principal of currently executing script. |
|
524 nsresult rv; |
|
525 nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv); |
|
526 if (NS_FAILED(rv)) |
|
527 return rv; |
|
528 |
|
529 // Native code can load all URIs. |
|
530 if (!principal) |
|
531 return NS_OK; |
|
532 |
|
533 rv = CheckLoadURIWithPrincipal(principal, aURI, |
|
534 nsIScriptSecurityManager::STANDARD); |
|
535 if (NS_SUCCEEDED(rv)) { |
|
536 // OK to load |
|
537 return NS_OK; |
|
538 } |
|
539 |
|
540 // See if we're attempting to load a file: URI. If so, let a |
|
541 // UniversalXPConnect capability trump the above check. |
|
542 bool isFile = false; |
|
543 bool isRes = false; |
|
544 if (NS_FAILED(aURI->SchemeIs("file", &isFile)) || |
|
545 NS_FAILED(aURI->SchemeIs("resource", &isRes))) |
|
546 return NS_ERROR_FAILURE; |
|
547 if (isFile || isRes) |
|
548 { |
|
549 if (SubjectIsPrivileged()) |
|
550 return NS_OK; |
|
551 } |
|
552 |
|
553 // Report error. |
|
554 nsAutoCString spec; |
|
555 if (NS_FAILED(aURI->GetAsciiSpec(spec))) |
|
556 return NS_ERROR_FAILURE; |
|
557 nsAutoCString msg("Access to '"); |
|
558 msg.Append(spec); |
|
559 msg.AppendLiteral("' from script denied"); |
|
560 SetPendingException(cx, msg.get()); |
|
561 return NS_ERROR_DOM_BAD_URI; |
|
562 } |
|
563 |
|
564 /** |
|
565 * Helper method to handle cases where a flag passed to |
|
566 * CheckLoadURIWithPrincipal means denying loading if the given URI has certain |
|
567 * nsIProtocolHandler flags set. |
|
568 * @return if success, access is allowed. Otherwise, deny access |
|
569 */ |
|
570 static nsresult |
|
571 DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags) |
|
572 { |
|
573 NS_PRECONDITION(aURI, "Must have URI!"); |
|
574 |
|
575 bool uriHasFlags; |
|
576 nsresult rv = |
|
577 NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags); |
|
578 NS_ENSURE_SUCCESS(rv, rv); |
|
579 |
|
580 if (uriHasFlags) { |
|
581 return NS_ERROR_DOM_BAD_URI; |
|
582 } |
|
583 |
|
584 return NS_OK; |
|
585 } |
|
586 |
|
587 static bool |
|
588 EqualOrSubdomain(nsIURI* aProbeArg, nsIURI* aBase) |
|
589 { |
|
590 // Make a clone of the incoming URI, because we're going to mutate it. |
|
591 nsCOMPtr<nsIURI> probe; |
|
592 nsresult rv = aProbeArg->Clone(getter_AddRefs(probe)); |
|
593 NS_ENSURE_SUCCESS(rv, false); |
|
594 |
|
595 nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); |
|
596 NS_ENSURE_TRUE(tldService, false); |
|
597 while (true) { |
|
598 if (nsScriptSecurityManager::SecurityCompareURIs(probe, aBase)) { |
|
599 return true; |
|
600 } |
|
601 |
|
602 nsAutoCString host, newHost; |
|
603 nsresult rv = probe->GetHost(host); |
|
604 NS_ENSURE_SUCCESS(rv, false); |
|
605 |
|
606 rv = tldService->GetNextSubDomain(host, newHost); |
|
607 if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { |
|
608 return false; |
|
609 } |
|
610 NS_ENSURE_SUCCESS(rv, false); |
|
611 rv = probe->SetHost(newHost); |
|
612 NS_ENSURE_SUCCESS(rv, false); |
|
613 } |
|
614 } |
|
615 |
|
616 NS_IMETHODIMP |
|
617 nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, |
|
618 nsIURI *aTargetURI, |
|
619 uint32_t aFlags) |
|
620 { |
|
621 NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal"); |
|
622 // If someone passes a flag that we don't understand, we should |
|
623 // fail, because they may need a security check that we don't |
|
624 // provide. |
|
625 NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT | |
|
626 nsIScriptSecurityManager::ALLOW_CHROME | |
|
627 nsIScriptSecurityManager::DISALLOW_SCRIPT | |
|
628 nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL | |
|
629 nsIScriptSecurityManager::DONT_REPORT_ERRORS), |
|
630 NS_ERROR_UNEXPECTED); |
|
631 NS_ENSURE_ARG_POINTER(aPrincipal); |
|
632 NS_ENSURE_ARG_POINTER(aTargetURI); |
|
633 |
|
634 // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which |
|
635 // would do such inheriting. That would be URIs that do not have their own |
|
636 // security context. We do this even for the system principal. |
|
637 if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) { |
|
638 nsresult rv = |
|
639 DenyAccessIfURIHasFlags(aTargetURI, |
|
640 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT); |
|
641 NS_ENSURE_SUCCESS(rv, rv); |
|
642 } |
|
643 |
|
644 if (aPrincipal == mSystemPrincipal) { |
|
645 // Allow access |
|
646 return NS_OK; |
|
647 } |
|
648 |
|
649 nsCOMPtr<nsIURI> sourceURI; |
|
650 aPrincipal->GetURI(getter_AddRefs(sourceURI)); |
|
651 if (!sourceURI) { |
|
652 nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aPrincipal); |
|
653 if (expanded) { |
|
654 nsTArray< nsCOMPtr<nsIPrincipal> > *whiteList; |
|
655 expanded->GetWhiteList(&whiteList); |
|
656 for (uint32_t i = 0; i < whiteList->Length(); ++i) { |
|
657 nsresult rv = CheckLoadURIWithPrincipal((*whiteList)[i], |
|
658 aTargetURI, |
|
659 aFlags); |
|
660 if (NS_SUCCEEDED(rv)) { |
|
661 // Allow access if it succeeded with one of the white listed principals |
|
662 return NS_OK; |
|
663 } |
|
664 } |
|
665 // None of our whitelisted principals worked. |
|
666 return NS_ERROR_DOM_BAD_URI; |
|
667 } |
|
668 NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal " |
|
669 "must have a URI!"); |
|
670 return NS_ERROR_UNEXPECTED; |
|
671 } |
|
672 |
|
673 // Automatic loads are not allowed from certain protocols. |
|
674 if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) { |
|
675 nsresult rv = |
|
676 DenyAccessIfURIHasFlags(sourceURI, |
|
677 nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT); |
|
678 NS_ENSURE_SUCCESS(rv, rv); |
|
679 } |
|
680 |
|
681 // If either URI is a nested URI, get the base URI |
|
682 nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI); |
|
683 nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI); |
|
684 |
|
685 //-- get the target scheme |
|
686 nsAutoCString targetScheme; |
|
687 nsresult rv = targetBaseURI->GetScheme(targetScheme); |
|
688 if (NS_FAILED(rv)) return rv; |
|
689 |
|
690 //-- Some callers do not allow loading javascript: |
|
691 if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) && |
|
692 targetScheme.EqualsLiteral("javascript")) |
|
693 { |
|
694 return NS_ERROR_DOM_BAD_URI; |
|
695 } |
|
696 |
|
697 NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError"); |
|
698 bool reportErrors = !(aFlags & nsIScriptSecurityManager::DONT_REPORT_ERRORS); |
|
699 |
|
700 // Check for uris that are only loadable by principals that subsume them |
|
701 bool hasFlags; |
|
702 rv = NS_URIChainHasFlags(targetBaseURI, |
|
703 nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS, |
|
704 &hasFlags); |
|
705 NS_ENSURE_SUCCESS(rv, rv); |
|
706 |
|
707 if (hasFlags) { |
|
708 return aPrincipal->CheckMayLoad(targetBaseURI, true, false); |
|
709 } |
|
710 |
|
711 //-- get the source scheme |
|
712 nsAutoCString sourceScheme; |
|
713 rv = sourceBaseURI->GetScheme(sourceScheme); |
|
714 if (NS_FAILED(rv)) return rv; |
|
715 |
|
716 if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) { |
|
717 // A null principal can target its own URI. |
|
718 if (sourceURI == aTargetURI) { |
|
719 return NS_OK; |
|
720 } |
|
721 } |
|
722 else if (targetScheme.Equals(sourceScheme, |
|
723 nsCaseInsensitiveCStringComparator())) |
|
724 { |
|
725 // every scheme can access another URI from the same scheme, |
|
726 // as long as they don't represent null principals... |
|
727 // Or they don't require an special permission to do so |
|
728 // See bug#773886 |
|
729 |
|
730 bool hasFlags; |
|
731 rv = NS_URIChainHasFlags(targetBaseURI, |
|
732 nsIProtocolHandler::URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM, |
|
733 &hasFlags); |
|
734 NS_ENSURE_SUCCESS(rv, rv); |
|
735 |
|
736 if (hasFlags) { |
|
737 // In this case, we allow opening only if the source and target URIS |
|
738 // are on the same domain, or the opening URI has the webapps |
|
739 // permision granted |
|
740 if (!SecurityCompareURIs(sourceBaseURI,targetBaseURI) && |
|
741 !nsContentUtils::IsExactSitePermAllow(aPrincipal,WEBAPPS_PERM_NAME)){ |
|
742 return NS_ERROR_DOM_BAD_URI; |
|
743 } |
|
744 } |
|
745 return NS_OK; |
|
746 } |
|
747 |
|
748 // If the schemes don't match, the policy is specified by the protocol |
|
749 // flags on the target URI. Note that the order of policy checks here is |
|
750 // very important! We start from most restrictive and work our way down. |
|
751 // Note that since we're working with the innermost URI, we can just use |
|
752 // the methods that work on chains of nested URIs and they will only look |
|
753 // at the flags for our one URI. |
|
754 |
|
755 // Check for system target URI |
|
756 rv = DenyAccessIfURIHasFlags(targetBaseURI, |
|
757 nsIProtocolHandler::URI_DANGEROUS_TO_LOAD); |
|
758 if (NS_FAILED(rv)) { |
|
759 // Deny access, since the origin principal is not system |
|
760 if (reportErrors) { |
|
761 ReportError(nullptr, errorTag, sourceURI, aTargetURI); |
|
762 } |
|
763 return rv; |
|
764 } |
|
765 |
|
766 // Check for chrome target URI |
|
767 rv = NS_URIChainHasFlags(targetBaseURI, |
|
768 nsIProtocolHandler::URI_IS_UI_RESOURCE, |
|
769 &hasFlags); |
|
770 NS_ENSURE_SUCCESS(rv, rv); |
|
771 if (hasFlags) { |
|
772 if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) { |
|
773 if (!targetScheme.EqualsLiteral("chrome")) { |
|
774 // for now don't change behavior for resource: or moz-icon: |
|
775 return NS_OK; |
|
776 } |
|
777 |
|
778 // allow load only if chrome package is whitelisted |
|
779 nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService( |
|
780 NS_CHROMEREGISTRY_CONTRACTID)); |
|
781 if (reg) { |
|
782 bool accessAllowed = false; |
|
783 reg->AllowContentToAccess(targetBaseURI, &accessAllowed); |
|
784 if (accessAllowed) { |
|
785 return NS_OK; |
|
786 } |
|
787 } |
|
788 } |
|
789 |
|
790 // resource: and chrome: are equivalent, securitywise |
|
791 // That's bogus!! Fix this. But watch out for |
|
792 // the view-source stylesheet? |
|
793 bool sourceIsChrome; |
|
794 rv = NS_URIChainHasFlags(sourceBaseURI, |
|
795 nsIProtocolHandler::URI_IS_UI_RESOURCE, |
|
796 &sourceIsChrome); |
|
797 NS_ENSURE_SUCCESS(rv, rv); |
|
798 if (sourceIsChrome) { |
|
799 return NS_OK; |
|
800 } |
|
801 if (reportErrors) { |
|
802 ReportError(nullptr, errorTag, sourceURI, aTargetURI); |
|
803 } |
|
804 return NS_ERROR_DOM_BAD_URI; |
|
805 } |
|
806 |
|
807 // Check for target URI pointing to a file |
|
808 rv = NS_URIChainHasFlags(targetBaseURI, |
|
809 nsIProtocolHandler::URI_IS_LOCAL_FILE, |
|
810 &hasFlags); |
|
811 NS_ENSURE_SUCCESS(rv, rv); |
|
812 if (hasFlags) { |
|
813 // Allow domains that were whitelisted in the prefs. In 99.9% of cases, |
|
814 // this array is empty. |
|
815 for (size_t i = 0; i < mFileURIWhitelist.Length(); ++i) { |
|
816 if (EqualOrSubdomain(sourceURI, mFileURIWhitelist[i])) { |
|
817 return NS_OK; |
|
818 } |
|
819 } |
|
820 |
|
821 // resource: and chrome: are equivalent, securitywise |
|
822 // That's bogus!! Fix this. But watch out for |
|
823 // the view-source stylesheet? |
|
824 bool sourceIsChrome; |
|
825 rv = NS_URIChainHasFlags(sourceURI, |
|
826 nsIProtocolHandler::URI_IS_UI_RESOURCE, |
|
827 &sourceIsChrome); |
|
828 NS_ENSURE_SUCCESS(rv, rv); |
|
829 if (sourceIsChrome) { |
|
830 return NS_OK; |
|
831 } |
|
832 |
|
833 if (reportErrors) { |
|
834 ReportError(nullptr, errorTag, sourceURI, aTargetURI); |
|
835 } |
|
836 return NS_ERROR_DOM_BAD_URI; |
|
837 } |
|
838 |
|
839 // OK, everyone is allowed to load this, since unflagged handlers are |
|
840 // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we |
|
841 // need to warn. At some point we'll want to make this warning into an |
|
842 // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD. |
|
843 rv = NS_URIChainHasFlags(targetBaseURI, |
|
844 nsIProtocolHandler::URI_LOADABLE_BY_ANYONE, |
|
845 &hasFlags); |
|
846 NS_ENSURE_SUCCESS(rv, rv); |
|
847 if (!hasFlags) { |
|
848 nsXPIDLString message; |
|
849 NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme); |
|
850 const char16_t* formatStrings[] = { ucsTargetScheme.get() }; |
|
851 rv = sStrBundle-> |
|
852 FormatStringFromName(MOZ_UTF16("ProtocolFlagError"), |
|
853 formatStrings, |
|
854 ArrayLength(formatStrings), |
|
855 getter_Copies(message)); |
|
856 if (NS_SUCCEEDED(rv)) { |
|
857 nsCOMPtr<nsIConsoleService> console( |
|
858 do_GetService("@mozilla.org/consoleservice;1")); |
|
859 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE); |
|
860 |
|
861 console->LogStringMessage(message.get()); |
|
862 } |
|
863 } |
|
864 |
|
865 return NS_OK; |
|
866 } |
|
867 |
|
868 nsresult |
|
869 nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag, |
|
870 nsIURI* aSource, nsIURI* aTarget) |
|
871 { |
|
872 nsresult rv; |
|
873 NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER); |
|
874 |
|
875 // Get the source URL spec |
|
876 nsAutoCString sourceSpec; |
|
877 rv = aSource->GetAsciiSpec(sourceSpec); |
|
878 NS_ENSURE_SUCCESS(rv, rv); |
|
879 |
|
880 // Get the target URL spec |
|
881 nsAutoCString targetSpec; |
|
882 rv = aTarget->GetAsciiSpec(targetSpec); |
|
883 NS_ENSURE_SUCCESS(rv, rv); |
|
884 |
|
885 // Localize the error message |
|
886 nsXPIDLString message; |
|
887 NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec); |
|
888 NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec); |
|
889 const char16_t *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() }; |
|
890 rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(), |
|
891 formatStrings, |
|
892 ArrayLength(formatStrings), |
|
893 getter_Copies(message)); |
|
894 NS_ENSURE_SUCCESS(rv, rv); |
|
895 |
|
896 // If a JS context was passed in, set a JS exception. |
|
897 // Otherwise, print the error message directly to the JS console |
|
898 // and to standard output |
|
899 if (cx) |
|
900 { |
|
901 SetPendingException(cx, message.get()); |
|
902 } |
|
903 else // Print directly to the console |
|
904 { |
|
905 nsCOMPtr<nsIConsoleService> console( |
|
906 do_GetService("@mozilla.org/consoleservice;1")); |
|
907 NS_ENSURE_TRUE(console, NS_ERROR_FAILURE); |
|
908 |
|
909 console->LogStringMessage(message.get()); |
|
910 } |
|
911 return NS_OK; |
|
912 } |
|
913 |
|
914 NS_IMETHODIMP |
|
915 nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal, |
|
916 const nsACString& aTargetURIStr, |
|
917 uint32_t aFlags) |
|
918 { |
|
919 nsresult rv; |
|
920 nsCOMPtr<nsIURI> target; |
|
921 rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr, |
|
922 nullptr, nullptr, sIOService); |
|
923 NS_ENSURE_SUCCESS(rv, rv); |
|
924 |
|
925 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags); |
|
926 if (rv == NS_ERROR_DOM_BAD_URI) { |
|
927 // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected |
|
928 // return values. |
|
929 return rv; |
|
930 } |
|
931 NS_ENSURE_SUCCESS(rv, rv); |
|
932 |
|
933 // Now start testing fixup -- since aTargetURIStr is a string, not |
|
934 // an nsIURI, we may well end up fixing it up before loading. |
|
935 // Note: This needs to stay in sync with the nsIURIFixup api. |
|
936 nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID); |
|
937 if (!fixup) { |
|
938 return rv; |
|
939 } |
|
940 |
|
941 uint32_t flags[] = { |
|
942 nsIURIFixup::FIXUP_FLAG_NONE, |
|
943 nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS, |
|
944 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP, |
|
945 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI, |
|
946 nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP | |
|
947 nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI |
|
948 }; |
|
949 |
|
950 for (uint32_t i = 0; i < ArrayLength(flags); ++i) { |
|
951 rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr, |
|
952 getter_AddRefs(target)); |
|
953 NS_ENSURE_SUCCESS(rv, rv); |
|
954 |
|
955 rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags); |
|
956 if (rv == NS_ERROR_DOM_BAD_URI) { |
|
957 // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected |
|
958 // return values. |
|
959 return rv; |
|
960 } |
|
961 NS_ENSURE_SUCCESS(rv, rv); |
|
962 } |
|
963 |
|
964 return rv; |
|
965 } |
|
966 |
|
967 bool |
|
968 nsScriptSecurityManager::ScriptAllowed(JSObject *aGlobal) |
|
969 { |
|
970 MOZ_ASSERT(aGlobal); |
|
971 MOZ_ASSERT(JS_IsGlobalObject(aGlobal) || js::IsOuterObject(aGlobal)); |
|
972 AutoJSContext cx; |
|
973 JS::RootedObject global(cx, js::UncheckedUnwrap(aGlobal, /* stopAtOuter = */ false)); |
|
974 |
|
975 // Check the bits on the compartment private. |
|
976 return xpc::Scriptability::Get(aGlobal).Allowed(); |
|
977 } |
|
978 |
|
979 ///////////////// Principals /////////////////////// |
|
980 NS_IMETHODIMP |
|
981 nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal) |
|
982 { |
|
983 nsresult rv; |
|
984 *aSubjectPrincipal = doGetSubjectPrincipal(&rv); |
|
985 if (NS_SUCCEEDED(rv)) |
|
986 NS_IF_ADDREF(*aSubjectPrincipal); |
|
987 return rv; |
|
988 } |
|
989 |
|
990 nsIPrincipal* |
|
991 nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv) |
|
992 { |
|
993 NS_PRECONDITION(rv, "Null out param"); |
|
994 JSContext *cx = GetCurrentJSContext(); |
|
995 if (!cx) |
|
996 { |
|
997 *rv = NS_OK; |
|
998 return nullptr; |
|
999 } |
|
1000 return GetSubjectPrincipal(cx, rv); |
|
1001 } |
|
1002 |
|
1003 NS_IMETHODIMP |
|
1004 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result) |
|
1005 { |
|
1006 NS_ADDREF(*result = mSystemPrincipal); |
|
1007 |
|
1008 return NS_OK; |
|
1009 } |
|
1010 |
|
1011 NS_IMETHODIMP |
|
1012 nsScriptSecurityManager::SubjectPrincipalIsSystem(bool* aIsSystem) |
|
1013 { |
|
1014 NS_ENSURE_ARG_POINTER(aIsSystem); |
|
1015 *aIsSystem = false; |
|
1016 |
|
1017 if (!mSystemPrincipal) |
|
1018 return NS_OK; |
|
1019 |
|
1020 nsCOMPtr<nsIPrincipal> subject; |
|
1021 nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject)); |
|
1022 if (NS_FAILED(rv)) |
|
1023 return rv; |
|
1024 |
|
1025 if(!subject) |
|
1026 { |
|
1027 // No subject principal means no JS is running; |
|
1028 // this is the equivalent of system principal code |
|
1029 *aIsSystem = true; |
|
1030 return NS_OK; |
|
1031 } |
|
1032 |
|
1033 return mSystemPrincipal->Equals(subject, aIsSystem); |
|
1034 } |
|
1035 |
|
1036 nsresult |
|
1037 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, uint32_t aAppId, |
|
1038 bool aInMozBrowser, |
|
1039 nsIPrincipal **result) |
|
1040 { |
|
1041 // I _think_ it's safe to not create null principals here based on aURI. |
|
1042 // At least all the callers would do the right thing in those cases, as far |
|
1043 // as I can tell. --bz |
|
1044 |
|
1045 nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI); |
|
1046 if (uriPrinc) { |
|
1047 nsCOMPtr<nsIPrincipal> principal; |
|
1048 uriPrinc->GetPrincipal(getter_AddRefs(principal)); |
|
1049 if (!principal || principal == mSystemPrincipal) { |
|
1050 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result); |
|
1051 } |
|
1052 |
|
1053 principal.forget(result); |
|
1054 |
|
1055 return NS_OK; |
|
1056 } |
|
1057 |
|
1058 nsRefPtr<nsPrincipal> codebase = new nsPrincipal(); |
|
1059 if (!codebase) |
|
1060 return NS_ERROR_OUT_OF_MEMORY; |
|
1061 |
|
1062 nsresult rv = codebase->Init(aURI, aAppId, aInMozBrowser); |
|
1063 if (NS_FAILED(rv)) |
|
1064 return rv; |
|
1065 |
|
1066 NS_ADDREF(*result = codebase); |
|
1067 |
|
1068 return NS_OK; |
|
1069 } |
|
1070 |
|
1071 NS_IMETHODIMP |
|
1072 nsScriptSecurityManager::GetSimpleCodebasePrincipal(nsIURI* aURI, |
|
1073 nsIPrincipal** aPrincipal) |
|
1074 { |
|
1075 return GetCodebasePrincipalInternal(aURI, |
|
1076 nsIScriptSecurityManager::UNKNOWN_APP_ID, |
|
1077 false, aPrincipal); |
|
1078 } |
|
1079 |
|
1080 NS_IMETHODIMP |
|
1081 nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI, |
|
1082 nsIPrincipal** aPrincipal) |
|
1083 { |
|
1084 return GetCodebasePrincipalInternal(aURI, nsIScriptSecurityManager::NO_APP_ID, |
|
1085 false, aPrincipal); |
|
1086 } |
|
1087 |
|
1088 NS_IMETHODIMP |
|
1089 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI, |
|
1090 nsIPrincipal** aPrincipal) |
|
1091 { |
|
1092 return GetNoAppCodebasePrincipal(aURI, aPrincipal); |
|
1093 } |
|
1094 |
|
1095 NS_IMETHODIMP |
|
1096 nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI, |
|
1097 uint32_t aAppId, |
|
1098 bool aInMozBrowser, |
|
1099 nsIPrincipal** aPrincipal) |
|
1100 { |
|
1101 NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID, |
|
1102 NS_ERROR_INVALID_ARG); |
|
1103 |
|
1104 return GetCodebasePrincipalInternal(aURI, aAppId, aInMozBrowser, aPrincipal); |
|
1105 } |
|
1106 |
|
1107 NS_IMETHODIMP |
|
1108 nsScriptSecurityManager::GetDocShellCodebasePrincipal(nsIURI* aURI, |
|
1109 nsIDocShell* aDocShell, |
|
1110 nsIPrincipal** aPrincipal) |
|
1111 { |
|
1112 return GetCodebasePrincipalInternal(aURI, |
|
1113 aDocShell->GetAppId(), |
|
1114 aDocShell->GetIsInBrowserElement(), |
|
1115 aPrincipal); |
|
1116 } |
|
1117 |
|
1118 nsresult |
|
1119 nsScriptSecurityManager::GetCodebasePrincipalInternal(nsIURI *aURI, |
|
1120 uint32_t aAppId, |
|
1121 bool aInMozBrowser, |
|
1122 nsIPrincipal **result) |
|
1123 { |
|
1124 NS_ENSURE_ARG(aURI); |
|
1125 |
|
1126 bool inheritsPrincipal; |
|
1127 nsresult rv = |
|
1128 NS_URIChainHasFlags(aURI, |
|
1129 nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, |
|
1130 &inheritsPrincipal); |
|
1131 if (NS_FAILED(rv) || inheritsPrincipal) { |
|
1132 return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result); |
|
1133 } |
|
1134 |
|
1135 nsCOMPtr<nsIPrincipal> principal; |
|
1136 rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser, |
|
1137 getter_AddRefs(principal)); |
|
1138 NS_ENSURE_SUCCESS(rv, rv); |
|
1139 NS_IF_ADDREF(*result = principal); |
|
1140 |
|
1141 return NS_OK; |
|
1142 } |
|
1143 |
|
1144 nsIPrincipal* |
|
1145 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx, |
|
1146 nsresult* rv) |
|
1147 { |
|
1148 *rv = NS_OK; |
|
1149 JSCompartment *compartment = js::GetContextCompartment(cx); |
|
1150 |
|
1151 // The context should always be in a compartment, either one it has entered |
|
1152 // or the one associated with its global. |
|
1153 MOZ_ASSERT(!!compartment); |
|
1154 |
|
1155 JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); |
|
1156 return nsJSPrincipals::get(principals); |
|
1157 } |
|
1158 |
|
1159 // static |
|
1160 nsIPrincipal* |
|
1161 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj) |
|
1162 { |
|
1163 JSCompartment *compartment = js::GetObjectCompartment(aObj); |
|
1164 JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment); |
|
1165 return nsJSPrincipals::get(principals); |
|
1166 } |
|
1167 |
|
1168 //////////////////////////////////////////////// |
|
1169 // Methods implementing nsIXPCSecurityManager // |
|
1170 //////////////////////////////////////////////// |
|
1171 |
|
1172 NS_IMETHODIMP |
|
1173 nsScriptSecurityManager::CanCreateWrapper(JSContext *cx, |
|
1174 const nsIID &aIID, |
|
1175 nsISupports *aObj, |
|
1176 nsIClassInfo *aClassInfo) |
|
1177 { |
|
1178 // XXX Special case for nsIXPCException ? |
|
1179 ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nullptr); |
|
1180 if (objClassInfo.IsDOMClass()) |
|
1181 { |
|
1182 return NS_OK; |
|
1183 } |
|
1184 |
|
1185 // We give remote-XUL whitelisted domains a free pass here. See bug 932906. |
|
1186 if (!xpc::AllowXBLScope(js::GetContextCompartment(cx))) |
|
1187 { |
|
1188 return NS_OK; |
|
1189 } |
|
1190 |
|
1191 if (SubjectIsPrivileged()) |
|
1192 { |
|
1193 return NS_OK; |
|
1194 } |
|
1195 |
|
1196 //-- Access denied, report an error |
|
1197 NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied"); |
|
1198 nsAutoCString origin; |
|
1199 nsresult rv2; |
|
1200 nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2); |
|
1201 if (NS_SUCCEEDED(rv2) && subjectPrincipal) { |
|
1202 GetPrincipalDomainOrigin(subjectPrincipal, origin); |
|
1203 } |
|
1204 NS_ConvertUTF8toUTF16 originUnicode(origin); |
|
1205 NS_ConvertUTF8toUTF16 classInfoName(objClassInfo.GetName()); |
|
1206 const char16_t* formatStrings[] = { |
|
1207 classInfoName.get(), |
|
1208 originUnicode.get() |
|
1209 }; |
|
1210 uint32_t length = ArrayLength(formatStrings); |
|
1211 if (originUnicode.IsEmpty()) { |
|
1212 --length; |
|
1213 } else { |
|
1214 strName.AppendLiteral("ForOrigin"); |
|
1215 } |
|
1216 nsXPIDLString errorMsg; |
|
1217 // We need to keep our existing failure rv and not override it |
|
1218 // with a likely success code from the following string bundle |
|
1219 // call in order to throw the correct security exception later. |
|
1220 rv2 = sStrBundle->FormatStringFromName(strName.get(), |
|
1221 formatStrings, |
|
1222 length, |
|
1223 getter_Copies(errorMsg)); |
|
1224 NS_ENSURE_SUCCESS(rv2, rv2); |
|
1225 |
|
1226 SetPendingException(cx, errorMsg.get()); |
|
1227 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; |
|
1228 } |
|
1229 |
|
1230 NS_IMETHODIMP |
|
1231 nsScriptSecurityManager::CanCreateInstance(JSContext *cx, |
|
1232 const nsCID &aCID) |
|
1233 { |
|
1234 if (SubjectIsPrivileged()) { |
|
1235 return NS_OK; |
|
1236 } |
|
1237 |
|
1238 //-- Access denied, report an error |
|
1239 nsAutoCString errorMsg("Permission denied to create instance of class. CID="); |
|
1240 char cidStr[NSID_LENGTH]; |
|
1241 aCID.ToProvidedString(cidStr); |
|
1242 errorMsg.Append(cidStr); |
|
1243 SetPendingException(cx, errorMsg.get()); |
|
1244 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; |
|
1245 } |
|
1246 |
|
1247 NS_IMETHODIMP |
|
1248 nsScriptSecurityManager::CanGetService(JSContext *cx, |
|
1249 const nsCID &aCID) |
|
1250 { |
|
1251 if (SubjectIsPrivileged()) { |
|
1252 return NS_OK; |
|
1253 } |
|
1254 |
|
1255 //-- Access denied, report an error |
|
1256 nsAutoCString errorMsg("Permission denied to get service. CID="); |
|
1257 char cidStr[NSID_LENGTH]; |
|
1258 aCID.ToProvidedString(cidStr); |
|
1259 errorMsg.Append(cidStr); |
|
1260 SetPendingException(cx, errorMsg.get()); |
|
1261 return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED; |
|
1262 } |
|
1263 |
|
1264 ///////////////////////////////////////////// |
|
1265 // Method implementing nsIChannelEventSink // |
|
1266 ///////////////////////////////////////////// |
|
1267 NS_IMETHODIMP |
|
1268 nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel, |
|
1269 nsIChannel* newChannel, |
|
1270 uint32_t redirFlags, |
|
1271 nsIAsyncVerifyRedirectCallback *cb) |
|
1272 { |
|
1273 nsCOMPtr<nsIPrincipal> oldPrincipal; |
|
1274 GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal)); |
|
1275 |
|
1276 nsCOMPtr<nsIURI> newURI; |
|
1277 newChannel->GetURI(getter_AddRefs(newURI)); |
|
1278 nsCOMPtr<nsIURI> newOriginalURI; |
|
1279 newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI)); |
|
1280 |
|
1281 NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI); |
|
1282 |
|
1283 const uint32_t flags = |
|
1284 nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT | |
|
1285 nsIScriptSecurityManager::DISALLOW_SCRIPT; |
|
1286 nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags); |
|
1287 if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) { |
|
1288 rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags); |
|
1289 } |
|
1290 |
|
1291 if (NS_FAILED(rv)) |
|
1292 return rv; |
|
1293 |
|
1294 cb->OnRedirectVerifyCallback(NS_OK); |
|
1295 return NS_OK; |
|
1296 } |
|
1297 |
|
1298 |
|
1299 ///////////////////////////////////// |
|
1300 // Method implementing nsIObserver // |
|
1301 ///////////////////////////////////// |
|
1302 const char sJSEnabledPrefName[] = "javascript.enabled"; |
|
1303 const char sFileOriginPolicyPrefName[] = |
|
1304 "security.fileuri.strict_origin_policy"; |
|
1305 |
|
1306 static const char* kObservedPrefs[] = { |
|
1307 sJSEnabledPrefName, |
|
1308 sFileOriginPolicyPrefName, |
|
1309 "capability.policy.", |
|
1310 nullptr |
|
1311 }; |
|
1312 |
|
1313 |
|
1314 NS_IMETHODIMP |
|
1315 nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic, |
|
1316 const char16_t* aMessage) |
|
1317 { |
|
1318 ScriptSecurityPrefChanged(); |
|
1319 return NS_OK; |
|
1320 } |
|
1321 |
|
1322 ///////////////////////////////////////////// |
|
1323 // Constructor, Destructor, Initialization // |
|
1324 ///////////////////////////////////////////// |
|
1325 nsScriptSecurityManager::nsScriptSecurityManager(void) |
|
1326 : mPrefInitialized(false) |
|
1327 , mIsJavaScriptEnabled(false) |
|
1328 { |
|
1329 static_assert(sizeof(intptr_t) == sizeof(void*), |
|
1330 "intptr_t and void* have different lengths on this platform. " |
|
1331 "This may cause a security failure with the SecurityLevel union."); |
|
1332 } |
|
1333 |
|
1334 nsresult nsScriptSecurityManager::Init() |
|
1335 { |
|
1336 nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); |
|
1337 NS_ENSURE_SUCCESS(rv, rv); |
|
1338 |
|
1339 InitPrefs(); |
|
1340 |
|
1341 nsCOMPtr<nsIStringBundleService> bundleService = |
|
1342 mozilla::services::GetStringBundleService(); |
|
1343 if (!bundleService) |
|
1344 return NS_ERROR_FAILURE; |
|
1345 |
|
1346 rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle); |
|
1347 NS_ENSURE_SUCCESS(rv, rv); |
|
1348 |
|
1349 // Create our system principal singleton |
|
1350 nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal(); |
|
1351 NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY); |
|
1352 |
|
1353 mSystemPrincipal = system; |
|
1354 |
|
1355 //-- Register security check callback in the JS engine |
|
1356 // Currently this is used to control access to function.caller |
|
1357 rv = nsXPConnect::XPConnect()->GetRuntime(&sRuntime); |
|
1358 NS_ENSURE_SUCCESS(rv, rv); |
|
1359 |
|
1360 static const JSSecurityCallbacks securityCallbacks = { |
|
1361 ContentSecurityPolicyPermitsJSAction, |
|
1362 JSPrincipalsSubsume, |
|
1363 }; |
|
1364 |
|
1365 MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime)); |
|
1366 JS_SetSecurityCallbacks(sRuntime, &securityCallbacks); |
|
1367 JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy); |
|
1368 |
|
1369 JS_SetTrustedPrincipals(sRuntime, system); |
|
1370 |
|
1371 return NS_OK; |
|
1372 } |
|
1373 |
|
1374 static StaticRefPtr<nsScriptSecurityManager> gScriptSecMan; |
|
1375 |
|
1376 nsScriptSecurityManager::~nsScriptSecurityManager(void) |
|
1377 { |
|
1378 Preferences::RemoveObservers(this, kObservedPrefs); |
|
1379 if (mDomainPolicy) |
|
1380 mDomainPolicy->Deactivate(); |
|
1381 MOZ_ASSERT(!mDomainPolicy); |
|
1382 } |
|
1383 |
|
1384 void |
|
1385 nsScriptSecurityManager::Shutdown() |
|
1386 { |
|
1387 if (sRuntime) { |
|
1388 JS_SetSecurityCallbacks(sRuntime, nullptr); |
|
1389 JS_SetTrustedPrincipals(sRuntime, nullptr); |
|
1390 sRuntime = nullptr; |
|
1391 } |
|
1392 |
|
1393 NS_IF_RELEASE(sIOService); |
|
1394 NS_IF_RELEASE(sStrBundle); |
|
1395 } |
|
1396 |
|
1397 nsScriptSecurityManager * |
|
1398 nsScriptSecurityManager::GetScriptSecurityManager() |
|
1399 { |
|
1400 if (!gScriptSecMan && nsXPConnect::XPConnect()) |
|
1401 { |
|
1402 nsRefPtr<nsScriptSecurityManager> ssManager = new nsScriptSecurityManager(); |
|
1403 |
|
1404 nsresult rv; |
|
1405 rv = ssManager->Init(); |
|
1406 if (NS_FAILED(rv)) { |
|
1407 return nullptr; |
|
1408 } |
|
1409 |
|
1410 rv = nsXPConnect::XPConnect()-> |
|
1411 SetDefaultSecurityManager(ssManager); |
|
1412 if (NS_FAILED(rv)) { |
|
1413 NS_WARNING("Failed to install xpconnect security manager!"); |
|
1414 return nullptr; |
|
1415 } |
|
1416 |
|
1417 ClearOnShutdown(&gScriptSecMan); |
|
1418 gScriptSecMan = ssManager; |
|
1419 } |
|
1420 return gScriptSecMan; |
|
1421 } |
|
1422 |
|
1423 // Currently this nsGenericFactory constructor is used only from FastLoad |
|
1424 // (XPCOM object deserialization) code, when "creating" the system principal |
|
1425 // singleton. |
|
1426 nsSystemPrincipal * |
|
1427 nsScriptSecurityManager::SystemPrincipalSingletonConstructor() |
|
1428 { |
|
1429 nsIPrincipal *sysprin = nullptr; |
|
1430 if (gScriptSecMan) |
|
1431 NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal); |
|
1432 return static_cast<nsSystemPrincipal*>(sysprin); |
|
1433 } |
|
1434 |
|
1435 struct IsWhitespace { |
|
1436 static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); }; |
|
1437 }; |
|
1438 struct IsWhitespaceOrComma { |
|
1439 static bool Test(char aChar) { return aChar == ',' || NS_IsAsciiWhitespace(aChar); }; |
|
1440 }; |
|
1441 |
|
1442 template <typename Predicate> |
|
1443 uint32_t SkipPast(const nsCString& str, uint32_t base) |
|
1444 { |
|
1445 while (base < str.Length() && Predicate::Test(str[base])) { |
|
1446 ++base; |
|
1447 } |
|
1448 return base; |
|
1449 } |
|
1450 |
|
1451 template <typename Predicate> |
|
1452 uint32_t SkipUntil(const nsCString& str, uint32_t base) |
|
1453 { |
|
1454 while (base < str.Length() && !Predicate::Test(str[base])) { |
|
1455 ++base; |
|
1456 } |
|
1457 return base; |
|
1458 } |
|
1459 |
|
1460 inline void |
|
1461 nsScriptSecurityManager::ScriptSecurityPrefChanged() |
|
1462 { |
|
1463 MOZ_ASSERT(mPrefInitialized); |
|
1464 mIsJavaScriptEnabled = |
|
1465 Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled); |
|
1466 sStrictFileOriginPolicy = |
|
1467 Preferences::GetBool(sFileOriginPolicyPrefName, false); |
|
1468 |
|
1469 // |
|
1470 // Rebuild the set of principals for which we allow file:// URI loads. This |
|
1471 // implements a small subset of an old pref-based CAPS people that people |
|
1472 // have come to depend on. See bug 995943. |
|
1473 // |
|
1474 |
|
1475 mFileURIWhitelist.Clear(); |
|
1476 auto policies = mozilla::Preferences::GetCString("capability.policy.policynames"); |
|
1477 for (uint32_t base = SkipPast<IsWhitespaceOrComma>(policies, 0), bound = 0; |
|
1478 base < policies.Length(); |
|
1479 base = SkipPast<IsWhitespaceOrComma>(policies, bound)) |
|
1480 { |
|
1481 // Grab the current policy name. |
|
1482 bound = SkipUntil<IsWhitespaceOrComma>(policies, base); |
|
1483 auto policyName = Substring(policies, base, bound - base); |
|
1484 |
|
1485 // Figure out if this policy allows loading file:// URIs. If not, we can skip it. |
|
1486 nsCString checkLoadURIPrefName = NS_LITERAL_CSTRING("capability.policy.") + |
|
1487 policyName + |
|
1488 NS_LITERAL_CSTRING(".checkloaduri.enabled"); |
|
1489 if (!Preferences::GetString(checkLoadURIPrefName.get()).LowerCaseEqualsLiteral("allaccess")) { |
|
1490 continue; |
|
1491 } |
|
1492 |
|
1493 // Grab the list of domains associated with this policy. |
|
1494 nsCString domainPrefName = NS_LITERAL_CSTRING("capability.policy.") + |
|
1495 policyName + |
|
1496 NS_LITERAL_CSTRING(".sites"); |
|
1497 auto siteList = Preferences::GetCString(domainPrefName.get()); |
|
1498 AddSitesToFileURIWhitelist(siteList); |
|
1499 } |
|
1500 } |
|
1501 |
|
1502 void |
|
1503 nsScriptSecurityManager::AddSitesToFileURIWhitelist(const nsCString& aSiteList) |
|
1504 { |
|
1505 for (uint32_t base = SkipPast<IsWhitespace>(aSiteList, 0), bound = 0; |
|
1506 base < aSiteList.Length(); |
|
1507 base = SkipPast<IsWhitespace>(aSiteList, bound)) |
|
1508 { |
|
1509 // Grab the current site. |
|
1510 bound = SkipUntil<IsWhitespace>(aSiteList, base); |
|
1511 nsAutoCString site(Substring(aSiteList, base, bound - base)); |
|
1512 |
|
1513 // Check if the URI is schemeless. If so, add both http and https. |
|
1514 nsAutoCString unused; |
|
1515 if (NS_FAILED(sIOService->ExtractScheme(site, unused))) { |
|
1516 AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("http://") + site); |
|
1517 AddSitesToFileURIWhitelist(NS_LITERAL_CSTRING("https://") + site); |
|
1518 continue; |
|
1519 } |
|
1520 |
|
1521 // Convert it to a URI and add it to our list. |
|
1522 nsCOMPtr<nsIURI> uri; |
|
1523 nsresult rv = NS_NewURI(getter_AddRefs(uri), site, nullptr, nullptr, sIOService); |
|
1524 if (NS_SUCCEEDED(rv)) { |
|
1525 mFileURIWhitelist.AppendElement(uri); |
|
1526 } else { |
|
1527 nsCOMPtr<nsIConsoleService> console(do_GetService("@mozilla.org/consoleservice;1")); |
|
1528 if (console) { |
|
1529 nsAutoString msg = NS_LITERAL_STRING("Unable to to add site to file:// URI whitelist: ") + |
|
1530 NS_ConvertASCIItoUTF16(site); |
|
1531 console->LogStringMessage(msg.get()); |
|
1532 } |
|
1533 } |
|
1534 } |
|
1535 } |
|
1536 |
|
1537 nsresult |
|
1538 nsScriptSecurityManager::InitPrefs() |
|
1539 { |
|
1540 nsIPrefBranch* branch = Preferences::GetRootBranch(); |
|
1541 NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE); |
|
1542 |
|
1543 mPrefInitialized = true; |
|
1544 |
|
1545 // Set the initial value of the "javascript.enabled" prefs |
|
1546 ScriptSecurityPrefChanged(); |
|
1547 |
|
1548 // set observer callbacks in case the value of the prefs change |
|
1549 Preferences::AddStrongObservers(this, kObservedPrefs); |
|
1550 |
|
1551 return NS_OK; |
|
1552 } |
|
1553 |
|
1554 namespace mozilla { |
|
1555 |
|
1556 void |
|
1557 GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix) |
|
1558 { |
|
1559 MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); |
|
1560 |
|
1561 if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
1562 aAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
1563 } |
|
1564 |
|
1565 aJarPrefix.Truncate(); |
|
1566 |
|
1567 // Fallback. |
|
1568 if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) { |
|
1569 return; |
|
1570 } |
|
1571 |
|
1572 // aJarPrefix = appId + "+" + { 't', 'f' } + "+"; |
|
1573 aJarPrefix.AppendInt(aAppId); |
|
1574 aJarPrefix.Append('+'); |
|
1575 aJarPrefix.Append(aInMozBrowser ? 't' : 'f'); |
|
1576 aJarPrefix.Append('+'); |
|
1577 |
|
1578 return; |
|
1579 } |
|
1580 |
|
1581 } // namespace mozilla |
|
1582 |
|
1583 NS_IMETHODIMP |
|
1584 nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId, |
|
1585 bool aInMozBrowser, |
|
1586 nsACString& aJarPrefix) |
|
1587 { |
|
1588 MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID); |
|
1589 |
|
1590 mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix); |
|
1591 return NS_OK; |
|
1592 } |
|
1593 |
|
1594 NS_IMETHODIMP |
|
1595 nsScriptSecurityManager::GetDomainPolicyActive(bool *aRv) |
|
1596 { |
|
1597 *aRv = !!mDomainPolicy; |
|
1598 return NS_OK; |
|
1599 } |
|
1600 |
|
1601 NS_IMETHODIMP |
|
1602 nsScriptSecurityManager::ActivateDomainPolicy(nsIDomainPolicy** aRv) |
|
1603 { |
|
1604 // We only allow one domain policy at a time. The holder of the previous |
|
1605 // policy must explicitly deactivate it first. |
|
1606 if (mDomainPolicy) { |
|
1607 return NS_ERROR_SERVICE_NOT_AVAILABLE; |
|
1608 } |
|
1609 |
|
1610 mDomainPolicy = new DomainPolicy(); |
|
1611 nsCOMPtr<nsIDomainPolicy> ptr = mDomainPolicy; |
|
1612 ptr.forget(aRv); |
|
1613 return NS_OK; |
|
1614 } |
|
1615 |
|
1616 // Intentionally non-scriptable. Script must have a reference to the |
|
1617 // nsIDomainPolicy to deactivate it. |
|
1618 void |
|
1619 nsScriptSecurityManager::DeactivateDomainPolicy() |
|
1620 { |
|
1621 mDomainPolicy = nullptr; |
|
1622 } |
|
1623 |
|
1624 NS_IMETHODIMP |
|
1625 nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv) |
|
1626 { |
|
1627 nsresult rv; |
|
1628 |
|
1629 // Compute our rule. If we don't have any domain policy set up that might |
|
1630 // provide exceptions to this rule, we're done. |
|
1631 *aRv = mIsJavaScriptEnabled; |
|
1632 if (!mDomainPolicy) { |
|
1633 return NS_OK; |
|
1634 } |
|
1635 |
|
1636 // We have a domain policy. Grab the appropriate set of exceptions to the |
|
1637 // rule (either the blacklist or the whitelist, depending on whether script |
|
1638 // is enabled or disabled by default). |
|
1639 nsCOMPtr<nsIDomainSet> exceptions; |
|
1640 nsCOMPtr<nsIDomainSet> superExceptions; |
|
1641 if (*aRv) { |
|
1642 mDomainPolicy->GetBlacklist(getter_AddRefs(exceptions)); |
|
1643 mDomainPolicy->GetSuperBlacklist(getter_AddRefs(superExceptions)); |
|
1644 } else { |
|
1645 mDomainPolicy->GetWhitelist(getter_AddRefs(exceptions)); |
|
1646 mDomainPolicy->GetSuperWhitelist(getter_AddRefs(superExceptions)); |
|
1647 } |
|
1648 |
|
1649 bool contains; |
|
1650 rv = exceptions->Contains(aURI, &contains); |
|
1651 NS_ENSURE_SUCCESS(rv, rv); |
|
1652 if (contains) { |
|
1653 *aRv = !*aRv; |
|
1654 return NS_OK; |
|
1655 } |
|
1656 rv = superExceptions->ContainsSuperDomain(aURI, &contains); |
|
1657 NS_ENSURE_SUCCESS(rv, rv); |
|
1658 if (contains) { |
|
1659 *aRv = !*aRv; |
|
1660 } |
|
1661 |
|
1662 return NS_OK; |
|
1663 } |