1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Norris Boyd
24 : * Mitch Stoltz
25 : * Steve Morse
26 : * Christopher A. Aillon
27 : * Giorgio Maone
28 : * Daniel Veditz
29 : *
30 : * Alternatively, the contents of this file may be used under the terms of
31 : * either of the GNU General Public License Version 2 or later (the "GPL"),
32 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 : * in which case the provisions of the GPL or the LGPL are applicable instead
34 : * of those above. If you wish to allow use of your version of this file only
35 : * under the terms of either the GPL or the LGPL, and not to allow others to
36 : * use your version of this file under the terms of the MPL, indicate your
37 : * decision by deleting the provisions above and replace them with the notice
38 : * and other provisions required by the GPL or the LGPL. If you do not delete
39 : * the provisions above, a recipient may use your version of this file under
40 : * the terms of any one of the MPL, the GPL or the LGPL.
41 : *
42 : * ***** END LICENSE BLOCK ***** */
43 :
44 : #include "mozilla/Util.h"
45 :
46 : #include "xpcprivate.h"
47 : #include "nsScriptSecurityManager.h"
48 : #include "nsIServiceManager.h"
49 : #include "nsIScriptObjectPrincipal.h"
50 : #include "nsIScriptContext.h"
51 : #include "nsIURL.h"
52 : #include "nsINestedURI.h"
53 : #include "nspr.h"
54 : #include "nsJSPrincipals.h"
55 : #include "nsSystemPrincipal.h"
56 : #include "nsPrincipal.h"
57 : #include "nsNullPrincipal.h"
58 : #include "nsXPIDLString.h"
59 : #include "nsCRT.h"
60 : #include "nsCRTGlue.h"
61 : #include "nsIJSContextStack.h"
62 : #include "nsDOMError.h"
63 : #include "nsDOMCID.h"
64 : #include "jsdbgapi.h"
65 : #include "nsIXPConnect.h"
66 : #include "nsIXPCSecurityManager.h"
67 : #include "nsTextFormatter.h"
68 : #include "nsIStringBundle.h"
69 : #include "nsNetUtil.h"
70 : #include "nsIProperties.h"
71 : #include "nsDirectoryServiceDefs.h"
72 : #include "nsIFile.h"
73 : #include "nsIFileURL.h"
74 : #include "nsIZipReader.h"
75 : #include "nsIXPConnect.h"
76 : #include "nsIScriptGlobalObject.h"
77 : #include "nsPIDOMWindow.h"
78 : #include "nsIDocShell.h"
79 : #include "nsIDocShellTreeItem.h"
80 : #include "nsIPrompt.h"
81 : #include "nsIWindowWatcher.h"
82 : #include "nsIConsoleService.h"
83 : #include "nsISecurityCheckedComponent.h"
84 : #include "nsIJSRuntimeService.h"
85 : #include "nsIObserverService.h"
86 : #include "nsIContent.h"
87 : #include "nsAutoPtr.h"
88 : #include "nsDOMJSUtils.h"
89 : #include "nsAboutProtocolUtils.h"
90 : #include "nsIClassInfo.h"
91 : #include "nsIURIFixup.h"
92 : #include "nsCDefaultURIFixup.h"
93 : #include "nsIChromeRegistry.h"
94 : #include "nsIContentSecurityPolicy.h"
95 : #include "nsIAsyncVerifyRedirectCallback.h"
96 : #include "mozilla/Preferences.h"
97 :
98 : using namespace mozilla;
99 :
100 : static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
101 :
102 : nsIIOService *nsScriptSecurityManager::sIOService = nsnull;
103 : nsIXPConnect *nsScriptSecurityManager::sXPConnect = nsnull;
104 : nsIThreadJSContextStack *nsScriptSecurityManager::sJSContextStack = nsnull;
105 : nsIStringBundle *nsScriptSecurityManager::sStrBundle = nsnull;
106 : JSRuntime *nsScriptSecurityManager::sRuntime = 0;
107 : bool nsScriptSecurityManager::sStrictFileOriginPolicy = true;
108 :
109 : ///////////////////////////
110 : // Convenience Functions //
111 : ///////////////////////////
112 : // Result of this function should not be freed.
113 : static inline const PRUnichar *
114 0 : IDToString(JSContext *cx, jsid id)
115 : {
116 0 : if (JSID_IS_STRING(id))
117 0 : return JS_GetInternedStringChars(JSID_TO_STRING(id));
118 :
119 0 : JSAutoRequest ar(cx);
120 : jsval idval;
121 0 : if (!JS_IdToValue(cx, id, &idval))
122 0 : return nsnull;
123 0 : JSString *str = JS_ValueToString(cx, idval);
124 0 : if(!str)
125 0 : return nsnull;
126 0 : return JS_GetStringCharsZ(cx, str);
127 : }
128 :
129 : class nsAutoInPrincipalDomainOriginSetter {
130 : public:
131 1 : nsAutoInPrincipalDomainOriginSetter() {
132 1 : ++sInPrincipalDomainOrigin;
133 1 : }
134 1 : ~nsAutoInPrincipalDomainOriginSetter() {
135 1 : --sInPrincipalDomainOrigin;
136 1 : }
137 : static PRUint32 sInPrincipalDomainOrigin;
138 : };
139 : PRUint32 nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin;
140 :
141 : static
142 : nsresult
143 1 : GetOriginFromURI(nsIURI* aURI, nsACString& aOrigin)
144 : {
145 1 : if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin > 1) {
146 : // Allow a single recursive call to GetPrincipalDomainOrigin, since that
147 : // might be happening on a different principal from the first call. But
148 : // after that, cut off the recursion; it just indicates that something
149 : // we're doing in this method causes us to reenter a security check here.
150 0 : return NS_ERROR_NOT_AVAILABLE;
151 : }
152 :
153 2 : nsAutoInPrincipalDomainOriginSetter autoSetter;
154 :
155 2 : nsCOMPtr<nsIURI> uri = NS_GetInnermostURI(aURI);
156 1 : NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
157 :
158 2 : nsCAutoString hostPort;
159 :
160 1 : nsresult rv = uri->GetHostPort(hostPort);
161 1 : if (NS_SUCCEEDED(rv)) {
162 2 : nsCAutoString scheme;
163 1 : rv = uri->GetScheme(scheme);
164 1 : NS_ENSURE_SUCCESS(rv, rv);
165 2 : aOrigin = scheme + NS_LITERAL_CSTRING("://") + hostPort;
166 : }
167 : else {
168 : // Some URIs (e.g., nsSimpleURI) don't support host. Just
169 : // get the full spec.
170 0 : rv = uri->GetSpec(aOrigin);
171 0 : NS_ENSURE_SUCCESS(rv, rv);
172 : }
173 :
174 1 : return NS_OK;
175 : }
176 :
177 : static
178 : nsresult
179 1 : GetPrincipalDomainOrigin(nsIPrincipal* aPrincipal,
180 : nsACString& aOrigin)
181 : {
182 :
183 2 : nsCOMPtr<nsIURI> uri;
184 1 : aPrincipal->GetDomain(getter_AddRefs(uri));
185 1 : if (!uri) {
186 1 : aPrincipal->GetURI(getter_AddRefs(uri));
187 : }
188 1 : NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
189 :
190 1 : return GetOriginFromURI(uri, aOrigin);
191 : }
192 :
193 : static nsIScriptContext *
194 0 : GetScriptContext(JSContext *cx)
195 : {
196 0 : return GetScriptContextFromJSContext(cx);
197 : }
198 :
199 0 : inline void SetPendingException(JSContext *cx, const char *aMsg)
200 : {
201 0 : JSAutoRequest ar(cx);
202 0 : JS_ReportError(cx, "%s", aMsg);
203 0 : }
204 :
205 0 : inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
206 : {
207 0 : JSAutoRequest ar(cx);
208 0 : JS_ReportError(cx, "%hs", aMsg);
209 0 : }
210 :
211 : // DomainPolicy members
212 : #ifdef DEBUG_CAPS_DomainPolicyLifeCycle
213 : PRUint32 DomainPolicy::sObjects=0;
214 : void DomainPolicy::_printPopulationInfo()
215 : {
216 : printf("CAPS.DomainPolicy: Gen. %d, %d DomainPolicy objects.\n",
217 : sGeneration, sObjects);
218 : }
219 : #endif
220 : PRUint32 DomainPolicy::sGeneration = 0;
221 :
222 : // Helper class to get stuff from the ClassInfo and not waste extra time with
223 : // virtual method calls for things it has already gotten
224 : class ClassInfoData
225 : {
226 : public:
227 343428 : ClassInfoData(nsIClassInfo *aClassInfo, const char *aName)
228 : : mClassInfo(aClassInfo),
229 : mName(const_cast<char *>(aName)),
230 : mDidGetFlags(false),
231 343428 : mMustFreeName(false)
232 : {
233 343428 : }
234 :
235 343428 : ~ClassInfoData()
236 : {
237 343428 : if (mMustFreeName)
238 0 : nsMemory::Free(mName);
239 343428 : }
240 :
241 343427 : PRUint32 GetFlags()
242 : {
243 343427 : if (!mDidGetFlags) {
244 343427 : if (mClassInfo) {
245 100038 : nsresult rv = mClassInfo->GetFlags(&mFlags);
246 100038 : if (NS_FAILED(rv)) {
247 0 : mFlags = 0;
248 : }
249 : } else {
250 243389 : mFlags = 0;
251 : }
252 :
253 343427 : mDidGetFlags = true;
254 : }
255 :
256 343427 : return mFlags;
257 : }
258 :
259 343427 : bool IsDOMClass()
260 : {
261 343427 : return !!(GetFlags() & nsIClassInfo::DOM_OBJECT);
262 : }
263 :
264 1 : const char* GetName()
265 : {
266 1 : if (!mName) {
267 0 : if (mClassInfo) {
268 0 : mClassInfo->GetClassDescription(&mName);
269 : }
270 :
271 0 : if (mName) {
272 0 : mMustFreeName = true;
273 : } else {
274 0 : mName = const_cast<char *>("UnnamedClass");
275 : }
276 : }
277 :
278 1 : return mName;
279 : }
280 :
281 : private:
282 : nsIClassInfo *mClassInfo; // WEAK
283 : PRUint32 mFlags;
284 : char *mName;
285 : bool mDidGetFlags;
286 : bool mMustFreeName;
287 : };
288 :
289 : class AutoCxPusher {
290 : public:
291 1 : AutoCxPusher(nsIJSContextStack *aStack, JSContext *cx)
292 1 : : mStack(aStack), mContext(cx)
293 : {
294 1 : if (NS_FAILED(mStack->Push(mContext))) {
295 0 : mStack = nsnull;
296 : }
297 1 : }
298 :
299 1 : ~AutoCxPusher()
300 1 : {
301 1 : if (mStack) {
302 1 : mStack->Pop(nsnull);
303 : }
304 1 : }
305 :
306 : private:
307 : nsCOMPtr<nsIJSContextStack> mStack;
308 : JSContext *mContext;
309 : };
310 :
311 : JSContext *
312 452532 : nsScriptSecurityManager::GetCurrentJSContext()
313 : {
314 : // Get JSContext from stack.
315 : JSContext *cx;
316 452532 : if (NS_FAILED(sJSContextStack->Peek(&cx)))
317 0 : return nsnull;
318 452532 : return cx;
319 : }
320 :
321 : JSContext *
322 1405 : nsScriptSecurityManager::GetSafeJSContext()
323 : {
324 : // Get JSContext from stack.
325 : JSContext *cx;
326 1405 : if (NS_FAILED(sJSContextStack->GetSafeJSContext(&cx)))
327 0 : return nsnull;
328 1405 : return cx;
329 : }
330 :
331 : /* static */
332 : bool
333 19 : nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI,
334 : nsIURI* aTargetURI)
335 : {
336 19 : return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
337 : }
338 :
339 : // SecurityHashURI is consistent with SecurityCompareURIs because NS_SecurityHashURI
340 : // is consistent with NS_SecurityCompareURIs. See nsNetUtil.h.
341 : PRUint32
342 0 : nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
343 : {
344 0 : return NS_SecurityHashURI(aURI);
345 : }
346 :
347 : NS_IMETHODIMP
348 634 : nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
349 : nsIPrincipal** aPrincipal)
350 : {
351 634 : NS_PRECONDITION(aChannel, "Must have channel!");
352 1268 : nsCOMPtr<nsISupports> owner;
353 634 : aChannel->GetOwner(getter_AddRefs(owner));
354 634 : if (owner) {
355 469 : CallQueryInterface(owner, aPrincipal);
356 469 : if (*aPrincipal) {
357 469 : return NS_OK;
358 : }
359 : }
360 :
361 : // OK, get the principal from the URI. Make sure this does the same thing
362 : // as nsDocument::Reset and nsXULDocument::StartDocumentLoad.
363 330 : nsCOMPtr<nsIURI> uri;
364 165 : nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
365 165 : NS_ENSURE_SUCCESS(rv, rv);
366 :
367 165 : return GetCodebasePrincipal(uri, aPrincipal);
368 : }
369 :
370 : NS_IMETHODIMP
371 361723 : nsScriptSecurityManager::IsSystemPrincipal(nsIPrincipal* aPrincipal,
372 : bool* aIsSystem)
373 : {
374 361723 : *aIsSystem = (aPrincipal == mSystemPrincipal);
375 361723 : return NS_OK;
376 : }
377 :
378 : NS_IMETHODIMP_(nsIPrincipal *)
379 0 : nsScriptSecurityManager::GetCxSubjectPrincipal(JSContext *cx)
380 : {
381 0 : NS_ASSERTION(cx == GetCurrentJSContext(),
382 : "Uh, cx is not the current JS context!");
383 :
384 0 : nsresult rv = NS_ERROR_FAILURE;
385 0 : nsIPrincipal *principal = GetSubjectPrincipal(cx, &rv);
386 0 : if (NS_FAILED(rv))
387 0 : return nsnull;
388 :
389 0 : return principal;
390 : }
391 :
392 : NS_IMETHODIMP_(nsIPrincipal *)
393 591 : nsScriptSecurityManager::GetCxSubjectPrincipalAndFrame(JSContext *cx, JSStackFrame **fp)
394 : {
395 591 : NS_ASSERTION(cx == GetCurrentJSContext(),
396 : "Uh, cx is not the current JS context!");
397 :
398 591 : nsresult rv = NS_ERROR_FAILURE;
399 591 : nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
400 591 : if (NS_FAILED(rv))
401 0 : return nsnull;
402 :
403 591 : return principal;
404 : }
405 :
406 : NS_IMETHODIMP
407 1225909 : nsScriptSecurityManager::PushContextPrincipal(JSContext *cx,
408 : JSStackFrame *fp,
409 : nsIPrincipal *principal)
410 : {
411 1225909 : NS_ASSERTION(principal, "Must pass a non-null principal");
412 :
413 : ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp,
414 1225909 : principal);
415 1225909 : if (!cp)
416 0 : return NS_ERROR_OUT_OF_MEMORY;
417 :
418 1225909 : mContextPrincipals = cp;
419 1225909 : return NS_OK;
420 : }
421 :
422 : NS_IMETHODIMP
423 1225909 : nsScriptSecurityManager::PopContextPrincipal(JSContext *cx)
424 : {
425 1225909 : NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop");
426 :
427 1225909 : ContextPrincipal *next = mContextPrincipals->mNext;
428 1225909 : delete mContextPrincipals;
429 1225909 : mContextPrincipals = next;
430 :
431 1225909 : return NS_OK;
432 : }
433 :
434 : ////////////////////
435 : // Policy Storage //
436 : ////////////////////
437 :
438 : // Table of security levels
439 : static bool
440 1 : DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
441 : {
442 1 : NS_Free(aData);
443 1 : return true;
444 : }
445 :
446 : //-- Per-Domain Policy - applies to one or more protocols or hosts
447 : struct DomainEntry
448 : {
449 3 : DomainEntry(const char* aOrigin,
450 : DomainPolicy* aDomainPolicy) : mOrigin(aOrigin),
451 : mDomainPolicy(aDomainPolicy),
452 3 : mNext(nsnull)
453 : {
454 3 : mDomainPolicy->Hold();
455 3 : }
456 :
457 3 : ~DomainEntry()
458 3 : {
459 3 : mDomainPolicy->Drop();
460 3 : }
461 :
462 0 : bool Matches(const char *anOrigin)
463 : {
464 0 : int len = strlen(anOrigin);
465 0 : int thisLen = mOrigin.Length();
466 0 : if (len < thisLen)
467 0 : return false;
468 0 : if (mOrigin.RFindChar(':', thisLen-1, 1) != -1)
469 : //-- Policy applies to all URLs of this scheme, compare scheme only
470 0 : return mOrigin.EqualsIgnoreCase(anOrigin, thisLen);
471 :
472 : //-- Policy applies to a particular host; compare domains
473 0 : if (!mOrigin.Equals(anOrigin + (len - thisLen)))
474 0 : return false;
475 0 : if (len == thisLen)
476 0 : return true;
477 0 : char charBefore = anOrigin[len-thisLen-1];
478 0 : return (charBefore == '.' || charBefore == ':' || charBefore == '/');
479 : }
480 :
481 : nsCString mOrigin;
482 : DomainPolicy* mDomainPolicy;
483 : DomainEntry* mNext;
484 : #if defined(DEBUG) || defined(DEBUG_CAPS_HACKER)
485 : nsCString mPolicyName_DEBUG;
486 : #endif
487 : };
488 :
489 : static bool
490 3 : DeleteDomainEntry(nsHashKey *aKey, void *aData, void* closure)
491 : {
492 3 : DomainEntry *entry = (DomainEntry*) aData;
493 3 : do
494 : {
495 3 : DomainEntry *next = entry->mNext;
496 3 : delete entry;
497 3 : entry = next;
498 : } while (entry);
499 3 : return true;
500 : }
501 :
502 : /////////////////////////////
503 : // nsScriptSecurityManager //
504 : /////////////////////////////
505 :
506 : ////////////////////////////////////
507 : // Methods implementing ISupports //
508 : ////////////////////////////////////
509 296450 : NS_IMPL_ISUPPORTS4(nsScriptSecurityManager,
510 : nsIScriptSecurityManager,
511 : nsIXPCSecurityManager,
512 : nsIChannelEventSink,
513 : nsIObserver)
514 :
515 : ///////////////////////////////////////////////////
516 : // Methods implementing nsIScriptSecurityManager //
517 : ///////////////////////////////////////////////////
518 :
519 : ///////////////// Security Checks /////////////////
520 :
521 : /* static */ JSPrincipals *
522 0 : nsScriptSecurityManager::ObjectPrincipalFinder(JSObject *aObj)
523 : {
524 0 : return nsJSPrincipals::get(doGetObjectPrincipal(aObj));
525 : }
526 :
527 : JSBool
528 54 : nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
529 : {
530 : // Get the security manager
531 : nsScriptSecurityManager *ssm =
532 54 : nsScriptSecurityManager::GetScriptSecurityManager();
533 :
534 54 : NS_ASSERTION(ssm, "Failed to get security manager service");
535 54 : if (!ssm)
536 0 : return JS_FALSE;
537 :
538 : nsresult rv;
539 54 : nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
540 :
541 54 : NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
542 54 : if (NS_FAILED(rv))
543 0 : return JS_FALSE; // Not just absence of principal, but failure.
544 :
545 54 : if (!subjectPrincipal) {
546 : // See bug 553448 for discussion of this case.
547 0 : NS_ASSERTION(!JS_GetSecurityCallbacks(js::GetRuntime(cx))->findObjectPrincipals,
548 : "CSP: Should have been able to find subject principal. "
549 : "Reluctantly granting access.");
550 0 : return JS_TRUE;
551 : }
552 :
553 108 : nsCOMPtr<nsIContentSecurityPolicy> csp;
554 54 : rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
555 54 : NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
556 :
557 : // don't do anything unless there's a CSP
558 54 : if (!csp)
559 54 : return JS_TRUE;
560 :
561 0 : bool evalOK = true;
562 0 : rv = csp->GetAllowsEval(&evalOK);
563 :
564 0 : if (NS_FAILED(rv))
565 : {
566 0 : NS_WARNING("CSP: failed to get allowsEval");
567 0 : return JS_TRUE; // fail open to not break sites.
568 : }
569 :
570 0 : if (!evalOK) {
571 : // get the script filename, script sample, and line number
572 : // to log with the violation
573 0 : JSStackFrame *fp = nsnull;
574 0 : nsAutoString fileName;
575 0 : PRUint32 lineNum = 0;
576 0 : NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
577 :
578 0 : fp = JS_FrameIterator(cx, &fp);
579 0 : if (fp) {
580 0 : JSScript *script = JS_GetFrameScript(cx, fp);
581 0 : if (script) {
582 0 : const char *file = JS_GetScriptFilename(cx, script);
583 0 : if (file) {
584 0 : CopyUTF8toUTF16(nsDependentCString(file), fileName);
585 : }
586 0 : jsbytecode *pc = JS_GetFramePC(cx, fp);
587 0 : if (pc) {
588 0 : lineNum = JS_PCToLineNumber(cx, script, pc);
589 : }
590 : }
591 : }
592 :
593 0 : csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
594 : fileName,
595 : scriptSample,
596 0 : lineNum);
597 : }
598 :
599 0 : return evalOK;
600 : }
601 :
602 :
603 : JSBool
604 404087 : nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
605 : jsid id, JSAccessMode mode,
606 : jsval *vp)
607 : {
608 : // Get the security manager
609 : nsScriptSecurityManager *ssm =
610 404087 : nsScriptSecurityManager::GetScriptSecurityManager();
611 :
612 404087 : NS_ASSERTION(ssm, "Failed to get security manager service");
613 404087 : if (!ssm)
614 0 : return JS_FALSE;
615 :
616 : // Get the object being accessed. We protect these cases:
617 : // 1. The Function.prototype.caller property's value, which might lead
618 : // an attacker up a call-stack to a function or another object from
619 : // a different trust domain.
620 : // 2. A user-defined getter or setter function accessible on another
621 : // trust domain's window or document object.
622 : // *vp can be a primitive, in that case, we use obj as the target
623 : // object.
624 404087 : JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
625 :
626 : // Do the same-origin check -- this sets a JS exception if the check fails.
627 : // Pass the parent object's class name, as we have no class-info for it.
628 : nsresult rv =
629 404087 : ssm->CheckPropertyAccess(cx, target, js::GetObjectClass(obj)->name, id,
630 : (mode & JSACC_WRITE) ?
631 : (PRInt32)nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
632 808174 : (PRInt32)nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
633 :
634 404087 : if (NS_FAILED(rv))
635 0 : return JS_FALSE; // Security check failed (XXX was an error reported?)
636 :
637 404087 : return JS_TRUE;
638 : }
639 :
640 : NS_IMETHODIMP
641 404087 : nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
642 : JSObject* aJSObject,
643 : const char* aClassName,
644 : jsid aProperty,
645 : PRUint32 aAction)
646 : {
647 : return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject,
648 : nsnull, nsnull, nsnull,
649 404087 : aClassName, aProperty, nsnull);
650 : }
651 :
652 : NS_IMETHODIMP
653 0 : nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
654 : nsIURI* aTargetURI)
655 : {
656 : nsresult rv;
657 :
658 : // Get a context if necessary
659 0 : if (!cx)
660 : {
661 0 : cx = GetCurrentJSContext();
662 0 : if (!cx)
663 0 : return NS_OK; // No JS context, so allow access
664 : }
665 :
666 : // Get a principal from the context
667 0 : nsIPrincipal* sourcePrincipal = GetSubjectPrincipal(cx, &rv);
668 0 : if (NS_FAILED(rv))
669 0 : return rv;
670 :
671 0 : if (!sourcePrincipal)
672 : {
673 0 : NS_WARNING("CheckSameOrigin called on script w/o principals; should this happen?");
674 0 : return NS_OK;
675 : }
676 :
677 0 : if (sourcePrincipal == mSystemPrincipal)
678 : {
679 : // This is a system (chrome) script, so allow access
680 0 : return NS_OK;
681 : }
682 :
683 : // Get the original URI from the source principal.
684 : // This has the effect of ignoring any change to document.domain
685 : // which must be done to avoid DNS spoofing (bug 154930)
686 0 : nsCOMPtr<nsIURI> sourceURI;
687 0 : sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
688 0 : if (!sourceURI) {
689 0 : sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
690 0 : NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
691 : }
692 :
693 : // Compare origins
694 0 : if (!SecurityCompareURIs(sourceURI, aTargetURI))
695 : {
696 0 : ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
697 0 : return NS_ERROR_DOM_BAD_URI;
698 : }
699 0 : return NS_OK;
700 : }
701 :
702 : NS_IMETHODIMP
703 17 : nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
704 : nsIURI* aTargetURI,
705 : bool reportError)
706 : {
707 17 : if (!SecurityCompareURIs(aSourceURI, aTargetURI))
708 : {
709 11 : if (reportError) {
710 0 : ReportError(nsnull, NS_LITERAL_STRING("CheckSameOriginError"),
711 0 : aSourceURI, aTargetURI);
712 : }
713 11 : return NS_ERROR_DOM_BAD_URI;
714 : }
715 6 : return NS_OK;
716 : }
717 :
718 : nsresult
719 1646942 : nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
720 : nsAXPCNativeCallContext* aCallContext,
721 : JSContext* cx, JSObject* aJSObject,
722 : nsISupports* aObj, nsIURI* aTargetURI,
723 : nsIClassInfo* aClassInfo,
724 : const char* aClassName, jsid aProperty,
725 : void** aCachedClassPolicy)
726 : {
727 : nsresult rv;
728 1646942 : nsIPrincipal* subjectPrincipal = GetSubjectPrincipal(cx, &rv);
729 1646942 : if (NS_FAILED(rv))
730 0 : return rv;
731 :
732 1646942 : if (!subjectPrincipal || subjectPrincipal == mSystemPrincipal)
733 : // We have native code or the system principal: just allow access
734 1646942 : return NS_OK;
735 :
736 0 : nsCOMPtr<nsIPrincipal> objectPrincipal;
737 :
738 : // Hold the class info data here so we don't have to go back to virtual
739 : // methods all the time
740 0 : ClassInfoData classInfoData(aClassInfo, aClassName);
741 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
742 : nsCAutoString propertyName;
743 : propertyName.AssignWithConversion((PRUnichar*)IDToString(cx, aProperty));
744 : printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(),
745 : propertyName.get(), aAction);
746 : #endif
747 :
748 : //-- Look up the security policy for this class and subject domain
749 : SecurityLevel securityLevel;
750 : rv = LookupPolicy(subjectPrincipal, classInfoData, aProperty, aAction,
751 0 : (ClassPolicy**)aCachedClassPolicy, &securityLevel);
752 0 : if (NS_FAILED(rv))
753 0 : return rv;
754 :
755 0 : if (securityLevel.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
756 : {
757 : // No policy found for this property so use the default of last resort.
758 : // If we were called from somewhere other than XPConnect
759 : // (no XPC call context), assume this is a DOM class. Otherwise,
760 : // ask the ClassInfo.
761 0 : if (!aCallContext || classInfoData.IsDOMClass())
762 0 : securityLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
763 : else
764 0 : securityLevel.level = SCRIPT_SECURITY_NO_ACCESS;
765 : }
766 :
767 0 : if (SECURITY_ACCESS_LEVEL_FLAG(securityLevel))
768 : // This flag means securityLevel is allAccess, noAccess, or sameOrigin
769 : {
770 0 : switch (securityLevel.level)
771 : {
772 : case SCRIPT_SECURITY_NO_ACCESS:
773 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
774 : printf("noAccess ");
775 : #endif
776 0 : rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
777 0 : break;
778 :
779 : case SCRIPT_SECURITY_ALL_ACCESS:
780 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
781 : printf("allAccess ");
782 : #endif
783 0 : rv = NS_OK;
784 0 : break;
785 :
786 : case SCRIPT_SECURITY_SAME_ORIGIN_ACCESS:
787 : {
788 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
789 : printf("sameOrigin ");
790 : #endif
791 0 : nsCOMPtr<nsIPrincipal> principalHolder;
792 0 : if(aJSObject)
793 : {
794 0 : objectPrincipal = doGetObjectPrincipal(aJSObject);
795 0 : if (!objectPrincipal)
796 0 : rv = NS_ERROR_DOM_SECURITY_ERR;
797 : }
798 0 : else if(aTargetURI)
799 : {
800 0 : if (NS_FAILED(GetCodebasePrincipal(
801 : aTargetURI, getter_AddRefs(objectPrincipal))))
802 0 : return NS_ERROR_FAILURE;
803 : }
804 : else
805 : {
806 0 : NS_ERROR("CheckPropertyAccessImpl called without a target object or URL");
807 0 : return NS_ERROR_FAILURE;
808 : }
809 0 : if(NS_SUCCEEDED(rv))
810 : rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
811 0 : aAction);
812 0 : break;
813 : }
814 : default:
815 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
816 : printf("ERROR ");
817 : #endif
818 0 : NS_ERROR("Bad Security Level Value");
819 0 : return NS_ERROR_FAILURE;
820 0 : }
821 : }
822 : else // if SECURITY_ACCESS_LEVEL_FLAG is false, securityLevel is a capability
823 : {
824 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
825 : printf("Cap:%s ", securityLevel.capability);
826 : #endif
827 0 : bool capabilityEnabled = false;
828 0 : rv = IsCapabilityEnabled(securityLevel.capability, &capabilityEnabled);
829 0 : if (NS_FAILED(rv) || !capabilityEnabled)
830 0 : rv = NS_ERROR_DOM_SECURITY_ERR;
831 : else
832 0 : rv = NS_OK;
833 : }
834 :
835 0 : if (NS_SUCCEEDED(rv))
836 : {
837 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
838 : printf(" GRANTED.\n");
839 : #endif
840 0 : return rv;
841 : }
842 :
843 : //--See if the object advertises a non-default level of access
844 : // using nsISecurityCheckedComponent
845 : nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
846 0 : do_QueryInterface(aObj);
847 :
848 0 : nsXPIDLCString objectSecurityLevel;
849 0 : if (checkedComponent)
850 : {
851 0 : nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
852 0 : nsCOMPtr<nsIInterfaceInfo> interfaceInfo;
853 0 : const nsIID* objIID = nsnull;
854 0 : rv = aCallContext->GetCalleeWrapper(getter_AddRefs(wrapper));
855 0 : if (NS_SUCCEEDED(rv) && wrapper)
856 0 : rv = wrapper->FindInterfaceWithMember(aProperty, getter_AddRefs(interfaceInfo));
857 0 : if (NS_SUCCEEDED(rv) && interfaceInfo)
858 0 : rv = interfaceInfo->GetIIDShared(&objIID);
859 0 : if (NS_SUCCEEDED(rv) && objIID)
860 : {
861 0 : switch (aAction)
862 : {
863 : case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
864 0 : checkedComponent->CanGetProperty(objIID,
865 : IDToString(cx, aProperty),
866 0 : getter_Copies(objectSecurityLevel));
867 0 : break;
868 : case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
869 0 : checkedComponent->CanSetProperty(objIID,
870 : IDToString(cx, aProperty),
871 0 : getter_Copies(objectSecurityLevel));
872 0 : break;
873 : case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
874 0 : checkedComponent->CanCallMethod(objIID,
875 : IDToString(cx, aProperty),
876 0 : getter_Copies(objectSecurityLevel));
877 : }
878 : }
879 : }
880 : rv = CheckXPCPermissions(cx, aObj, aJSObject, subjectPrincipal,
881 0 : objectSecurityLevel);
882 : #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
883 : if(NS_SUCCEEDED(rv))
884 : printf("CheckXPCPerms GRANTED.\n");
885 : else
886 : printf("CheckXPCPerms DENIED.\n");
887 : #endif
888 :
889 0 : if (NS_FAILED(rv)) //-- Security tests failed, access is denied, report error
890 : {
891 0 : nsAutoString stringName;
892 0 : switch(aAction)
893 : {
894 : case nsIXPCSecurityManager::ACCESS_GET_PROPERTY:
895 0 : stringName.AssignLiteral("GetPropertyDeniedOrigins");
896 0 : break;
897 : case nsIXPCSecurityManager::ACCESS_SET_PROPERTY:
898 0 : stringName.AssignLiteral("SetPropertyDeniedOrigins");
899 0 : break;
900 : case nsIXPCSecurityManager::ACCESS_CALL_METHOD:
901 0 : stringName.AssignLiteral("CallMethodDeniedOrigins");
902 : }
903 :
904 : // Null out objectPrincipal for now, so we don't leak information about
905 : // it. Whenever we can report different error strings to content and
906 : // the UI we can take this out again.
907 0 : objectPrincipal = nsnull;
908 :
909 0 : NS_ConvertUTF8toUTF16 className(classInfoData.GetName());
910 0 : nsCAutoString subjectOrigin;
911 0 : nsCAutoString subjectDomain;
912 0 : if (!nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin) {
913 0 : nsCOMPtr<nsIURI> uri, domain;
914 0 : subjectPrincipal->GetURI(getter_AddRefs(uri));
915 : // Subject can't be system if we failed the security
916 : // check, so |uri| is non-null.
917 0 : NS_ASSERTION(uri, "How did that happen?");
918 0 : GetOriginFromURI(uri, subjectOrigin);
919 0 : subjectPrincipal->GetDomain(getter_AddRefs(domain));
920 0 : if (domain) {
921 0 : GetOriginFromURI(domain, subjectDomain);
922 : }
923 : } else {
924 0 : subjectOrigin.AssignLiteral("the security manager");
925 : }
926 0 : NS_ConvertUTF8toUTF16 subjectOriginUnicode(subjectOrigin);
927 0 : NS_ConvertUTF8toUTF16 subjectDomainUnicode(subjectDomain);
928 :
929 0 : nsCAutoString objectOrigin;
930 0 : nsCAutoString objectDomain;
931 0 : if (!nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin &&
932 0 : objectPrincipal) {
933 0 : nsCOMPtr<nsIURI> uri, domain;
934 0 : objectPrincipal->GetURI(getter_AddRefs(uri));
935 0 : if (uri) { // Object principal might be system
936 0 : GetOriginFromURI(uri, objectOrigin);
937 : }
938 0 : objectPrincipal->GetDomain(getter_AddRefs(domain));
939 0 : if (domain) {
940 0 : GetOriginFromURI(domain, objectDomain);
941 : }
942 : }
943 0 : NS_ConvertUTF8toUTF16 objectOriginUnicode(objectOrigin);
944 0 : NS_ConvertUTF8toUTF16 objectDomainUnicode(objectDomain);
945 :
946 0 : nsXPIDLString errorMsg;
947 : const PRUnichar *formatStrings[] =
948 : {
949 0 : subjectOriginUnicode.get(),
950 0 : className.get(),
951 0 : IDToString(cx, aProperty),
952 0 : objectOriginUnicode.get(),
953 0 : subjectDomainUnicode.get(),
954 0 : objectDomainUnicode.get()
955 0 : };
956 :
957 0 : PRUint32 length = ArrayLength(formatStrings);
958 :
959 : // XXXbz Our localization system is stupid and can't handle not showing
960 : // some strings that get passed in. Which means that we have to get
961 : // our length precisely right: it has to be exactly the number of
962 : // strings our format string wants. This means we'll have to move
963 : // strings in the array as needed, sadly...
964 0 : if (nsAutoInPrincipalDomainOriginSetter::sInPrincipalDomainOrigin ||
965 0 : !objectPrincipal) {
966 0 : stringName.AppendLiteral("OnlySubject");
967 0 : length -= 3;
968 : } else {
969 : // default to a length that doesn't include the domains, then
970 : // increase it as needed.
971 0 : length -= 2;
972 0 : if (!subjectDomainUnicode.IsEmpty()) {
973 0 : stringName.AppendLiteral("SubjectDomain");
974 0 : length += 1;
975 : }
976 0 : if (!objectDomainUnicode.IsEmpty()) {
977 0 : stringName.AppendLiteral("ObjectDomain");
978 0 : length += 1;
979 0 : if (length != ArrayLength(formatStrings)) {
980 : // We have an object domain but not a subject domain.
981 : // Scoot our string over one slot. See the XXX comment
982 : // above for why we need to do this.
983 0 : formatStrings[length-1] = formatStrings[length];
984 : }
985 : }
986 : }
987 :
988 : // We need to keep our existing failure rv and not override it
989 : // with a likely success code from the following string bundle
990 : // call in order to throw the correct security exception later.
991 : nsresult rv2 = sStrBundle->FormatStringFromName(stringName.get(),
992 : formatStrings,
993 : length,
994 0 : getter_Copies(errorMsg));
995 0 : if (NS_FAILED(rv2)) {
996 : // Might just be missing the string... Do our best
997 0 : errorMsg = stringName;
998 : }
999 :
1000 0 : SetPendingException(cx, errorMsg.get());
1001 : }
1002 :
1003 0 : return rv;
1004 : }
1005 :
1006 : /* static */
1007 : nsresult
1008 1869541 : nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
1009 : nsIPrincipal* aObject)
1010 : {
1011 : /*
1012 : ** Get origin of subject and object and compare.
1013 : */
1014 1869541 : if (aSubject == aObject)
1015 1869541 : return NS_OK;
1016 :
1017 : // Default to false, and change if that turns out wrong.
1018 0 : bool subjectSetDomain = false;
1019 0 : bool objectSetDomain = false;
1020 :
1021 0 : nsCOMPtr<nsIURI> subjectURI;
1022 0 : nsCOMPtr<nsIURI> objectURI;
1023 :
1024 0 : aSubject->GetDomain(getter_AddRefs(subjectURI));
1025 0 : if (!subjectURI) {
1026 0 : aSubject->GetURI(getter_AddRefs(subjectURI));
1027 : } else {
1028 0 : subjectSetDomain = true;
1029 : }
1030 :
1031 0 : aObject->GetDomain(getter_AddRefs(objectURI));
1032 0 : if (!objectURI) {
1033 0 : aObject->GetURI(getter_AddRefs(objectURI));
1034 : } else {
1035 0 : objectSetDomain = true;
1036 : }
1037 :
1038 0 : if (SecurityCompareURIs(subjectURI, objectURI))
1039 : { // If either the subject or the object has changed its principal by
1040 : // explicitly setting document.domain then the other must also have
1041 : // done so in order to be considered the same origin. This prevents
1042 : // DNS spoofing based on document.domain (154930)
1043 :
1044 : // If both or neither explicitly set their domain, allow the access
1045 0 : if (subjectSetDomain == objectSetDomain)
1046 0 : return NS_OK;
1047 : }
1048 :
1049 : /*
1050 : ** Access tests failed, so now report error.
1051 : */
1052 0 : return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1053 : }
1054 :
1055 : // It's important that
1056 : //
1057 : // CheckSameOriginPrincipal(A, B) == NS_OK
1058 : //
1059 : // imply
1060 : //
1061 : // HashPrincipalByOrigin(A) == HashPrincipalByOrigin(B)
1062 : //
1063 : // if principals A and B could ever be used as keys in a hashtable.
1064 : // Violation of this invariant leads to spurious failures of hashtable
1065 : // lookups. See bug 454850.
1066 :
1067 : /*static*/ PRUint32
1068 0 : nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
1069 : {
1070 0 : nsCOMPtr<nsIURI> uri;
1071 0 : aPrincipal->GetDomain(getter_AddRefs(uri));
1072 0 : if (!uri)
1073 0 : aPrincipal->GetURI(getter_AddRefs(uri));
1074 0 : return SecurityHashURI(uri);
1075 : }
1076 :
1077 : nsresult
1078 0 : nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
1079 : nsIPrincipal* aObject,
1080 : PRUint32 aAction)
1081 : {
1082 : nsresult rv;
1083 : bool subsumes;
1084 0 : rv = aSubject->Subsumes(aObject, &subsumes);
1085 0 : if (NS_SUCCEEDED(rv) && !subsumes) {
1086 0 : rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1087 : }
1088 :
1089 0 : if (NS_SUCCEEDED(rv))
1090 0 : return NS_OK;
1091 :
1092 : /*
1093 : * Content can't ever touch chrome (we check for UniversalXPConnect later)
1094 : */
1095 0 : if (aObject == mSystemPrincipal)
1096 0 : return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1097 :
1098 : /*
1099 : ** Access tests failed, so now report error.
1100 : */
1101 0 : return NS_ERROR_DOM_PROP_ACCESS_DENIED;
1102 : }
1103 :
1104 : nsresult
1105 1 : nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal,
1106 : ClassInfoData& aClassData,
1107 : jsid aProperty,
1108 : PRUint32 aAction,
1109 : ClassPolicy** aCachedClassPolicy,
1110 : SecurityLevel* result)
1111 : {
1112 : nsresult rv;
1113 1 : result->level = SCRIPT_SECURITY_UNDEFINED_ACCESS;
1114 :
1115 1 : DomainPolicy* dpolicy = nsnull;
1116 : //-- Initialize policies if necessary
1117 1 : if (mPolicyPrefsChanged)
1118 : {
1119 1 : if (!mPrefInitialized) {
1120 0 : rv = InitPrefs();
1121 0 : NS_ENSURE_SUCCESS(rv, rv);
1122 : }
1123 1 : rv = InitPolicies();
1124 1 : if (NS_FAILED(rv))
1125 0 : return rv;
1126 : }
1127 : else
1128 : {
1129 0 : aPrincipal->GetSecurityPolicy((void**)&dpolicy);
1130 : }
1131 :
1132 1 : if (!dpolicy && mOriginToPolicyMap)
1133 : {
1134 : //-- Look up the relevant domain policy, if any
1135 : #ifdef DEBUG_CAPS_LookupPolicy
1136 : printf("DomainLookup ");
1137 : #endif
1138 :
1139 2 : nsCAutoString origin;
1140 1 : rv = GetPrincipalDomainOrigin(aPrincipal, origin);
1141 1 : NS_ENSURE_SUCCESS(rv, rv);
1142 :
1143 1 : char *start = origin.BeginWriting();
1144 1 : const char *nextToLastDot = nsnull;
1145 1 : const char *lastDot = nsnull;
1146 1 : const char *colon = nsnull;
1147 1 : char *p = start;
1148 :
1149 : //-- search domain (stop at the end of the string or at the 3rd slash)
1150 22 : for (PRUint32 slashes=0; *p; p++)
1151 : {
1152 21 : if (*p == '/' && ++slashes == 3)
1153 : {
1154 0 : *p = '\0'; // truncate at 3rd slash
1155 0 : break;
1156 : }
1157 21 : if (*p == '.')
1158 : {
1159 0 : nextToLastDot = lastDot;
1160 0 : lastDot = p;
1161 : }
1162 21 : else if (!colon && *p == ':')
1163 1 : colon = p;
1164 : }
1165 :
1166 3 : nsCStringKey key(nextToLastDot ? nextToLastDot+1 : start);
1167 1 : DomainEntry *de = (DomainEntry*) mOriginToPolicyMap->Get(&key);
1168 1 : if (!de)
1169 : {
1170 2 : nsCAutoString scheme(start, colon-start+1);
1171 2 : nsCStringKey schemeKey(scheme);
1172 1 : de = (DomainEntry*) mOriginToPolicyMap->Get(&schemeKey);
1173 : }
1174 :
1175 2 : while (de)
1176 : {
1177 0 : if (de->Matches(start))
1178 : {
1179 0 : dpolicy = de->mDomainPolicy;
1180 0 : break;
1181 : }
1182 0 : de = de->mNext;
1183 : }
1184 :
1185 1 : if (!dpolicy)
1186 1 : dpolicy = mDefaultPolicy;
1187 :
1188 1 : aPrincipal->SetSecurityPolicy((void*)dpolicy);
1189 : }
1190 :
1191 1 : ClassPolicy* cpolicy = nsnull;
1192 :
1193 1 : if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1194 : {
1195 : // No per-domain policy for this principal (the more common case)
1196 : // so look for a cached class policy from the object wrapper
1197 0 : cpolicy = *aCachedClassPolicy;
1198 : }
1199 :
1200 1 : if (!cpolicy)
1201 : { //-- No cached policy for this class, need to look it up
1202 : #ifdef DEBUG_CAPS_LookupPolicy
1203 : printf("ClassLookup ");
1204 : #endif
1205 :
1206 : cpolicy = static_cast<ClassPolicy*>
1207 : (PL_DHashTableOperate(dpolicy,
1208 1 : aClassData.GetName(),
1209 1 : PL_DHASH_LOOKUP));
1210 :
1211 1 : if (PL_DHASH_ENTRY_IS_FREE(cpolicy))
1212 1 : cpolicy = NO_POLICY_FOR_CLASS;
1213 :
1214 1 : if ((dpolicy == mDefaultPolicy) && aCachedClassPolicy)
1215 0 : *aCachedClassPolicy = cpolicy;
1216 : }
1217 :
1218 1 : NS_ASSERTION(JSID_IS_INT(aProperty) || JSID_IS_OBJECT(aProperty) ||
1219 : JSID_IS_STRING(aProperty), "Property must be a valid id");
1220 :
1221 : // Only atomized strings are stored in the policies' hash tables.
1222 1 : if (!JSID_IS_STRING(aProperty))
1223 0 : return NS_OK;
1224 :
1225 1 : JSString *propertyKey = JSID_TO_STRING(aProperty);
1226 :
1227 : // We look for a PropertyPolicy in the following places:
1228 : // 1) The ClassPolicy for our class we got from our DomainPolicy
1229 : // 2) The mWildcardPolicy of our DomainPolicy
1230 : // 3) The ClassPolicy for our class we got from mDefaultPolicy
1231 : // 4) The mWildcardPolicy of our mDefaultPolicy
1232 1 : PropertyPolicy* ppolicy = nsnull;
1233 1 : if (cpolicy != NO_POLICY_FOR_CLASS)
1234 : {
1235 : ppolicy = static_cast<PropertyPolicy*>
1236 : (PL_DHashTableOperate(cpolicy->mPolicy,
1237 : propertyKey,
1238 0 : PL_DHASH_LOOKUP));
1239 : }
1240 :
1241 : // If there is no class policy for this property, and we have a wildcard
1242 : // policy, try that.
1243 1 : if (dpolicy->mWildcardPolicy &&
1244 : (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1245 : {
1246 : ppolicy =
1247 : static_cast<PropertyPolicy*>
1248 : (PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy,
1249 : propertyKey,
1250 0 : PL_DHASH_LOOKUP));
1251 : }
1252 :
1253 : // If dpolicy is not the defauly policy and there's no class or wildcard
1254 : // policy for this property, check the default policy for this class and
1255 : // the default wildcard policy
1256 1 : if (dpolicy != mDefaultPolicy &&
1257 : (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)))
1258 : {
1259 : cpolicy = static_cast<ClassPolicy*>
1260 : (PL_DHashTableOperate(mDefaultPolicy,
1261 0 : aClassData.GetName(),
1262 0 : PL_DHASH_LOOKUP));
1263 :
1264 0 : if (PL_DHASH_ENTRY_IS_BUSY(cpolicy))
1265 : {
1266 : ppolicy =
1267 : static_cast<PropertyPolicy*>
1268 : (PL_DHashTableOperate(cpolicy->mPolicy,
1269 : propertyKey,
1270 0 : PL_DHASH_LOOKUP));
1271 : }
1272 :
1273 0 : if ((!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy)) &&
1274 : mDefaultPolicy->mWildcardPolicy)
1275 : {
1276 : ppolicy =
1277 : static_cast<PropertyPolicy*>
1278 : (PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy,
1279 : propertyKey,
1280 0 : PL_DHASH_LOOKUP));
1281 : }
1282 : }
1283 :
1284 1 : if (!ppolicy || PL_DHASH_ENTRY_IS_FREE(ppolicy))
1285 1 : return NS_OK;
1286 :
1287 : // Get the correct security level from the property policy
1288 0 : if (aAction == nsIXPCSecurityManager::ACCESS_SET_PROPERTY)
1289 0 : *result = ppolicy->mSet;
1290 : else
1291 0 : *result = ppolicy->mGet;
1292 :
1293 0 : return NS_OK;
1294 : }
1295 :
1296 :
1297 : NS_IMETHODIMP
1298 0 : nsScriptSecurityManager::CheckLoadURIFromScript(JSContext *cx, nsIURI *aURI)
1299 : {
1300 : // Get principal of currently executing script.
1301 : nsresult rv;
1302 0 : nsIPrincipal* principal = GetSubjectPrincipal(cx, &rv);
1303 0 : if (NS_FAILED(rv))
1304 0 : return rv;
1305 :
1306 : // Native code can load all URIs.
1307 0 : if (!principal)
1308 0 : return NS_OK;
1309 :
1310 : rv = CheckLoadURIWithPrincipal(principal, aURI,
1311 0 : nsIScriptSecurityManager::STANDARD);
1312 0 : if (NS_SUCCEEDED(rv)) {
1313 : // OK to load
1314 0 : return NS_OK;
1315 : }
1316 :
1317 : // See if we're attempting to load a file: URI. If so, let a
1318 : // UniversalXPConnect capability trump the above check.
1319 0 : bool isFile = false;
1320 0 : bool isRes = false;
1321 0 : if (NS_FAILED(aURI->SchemeIs("file", &isFile)) ||
1322 0 : NS_FAILED(aURI->SchemeIs("resource", &isRes)))
1323 0 : return NS_ERROR_FAILURE;
1324 0 : if (isFile || isRes)
1325 : {
1326 : bool enabled;
1327 0 : if (NS_FAILED(IsCapabilityEnabled("UniversalXPConnect", &enabled)))
1328 0 : return NS_ERROR_FAILURE;
1329 0 : if (enabled)
1330 0 : return NS_OK;
1331 : }
1332 :
1333 : // Report error.
1334 0 : nsCAutoString spec;
1335 0 : if (NS_FAILED(aURI->GetAsciiSpec(spec)))
1336 0 : return NS_ERROR_FAILURE;
1337 0 : nsCAutoString msg("Access to '");
1338 0 : msg.Append(spec);
1339 0 : msg.AppendLiteral("' from script denied");
1340 0 : SetPendingException(cx, msg.get());
1341 0 : return NS_ERROR_DOM_BAD_URI;
1342 : }
1343 :
1344 : NS_IMETHODIMP
1345 0 : nsScriptSecurityManager::CheckLoadURI(nsIURI *aSourceURI, nsIURI *aTargetURI,
1346 : PRUint32 aFlags)
1347 : {
1348 : // FIXME: bug 327244 -- this function should really die... Really truly.
1349 0 : NS_PRECONDITION(aSourceURI, "CheckLoadURI called with null source URI");
1350 0 : NS_ENSURE_ARG_POINTER(aSourceURI);
1351 :
1352 : // Note: this is not _quite_ right if aSourceURI has
1353 : // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1354 : // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1355 : // really needs to go away....
1356 0 : nsCOMPtr<nsIPrincipal> sourcePrincipal;
1357 : nsresult rv = CreateCodebasePrincipal(aSourceURI,
1358 0 : getter_AddRefs(sourcePrincipal));
1359 0 : NS_ENSURE_SUCCESS(rv, rv);
1360 0 : return CheckLoadURIWithPrincipal(sourcePrincipal, aTargetURI, aFlags);
1361 : }
1362 :
1363 : /**
1364 : * Helper method to handle cases where a flag passed to
1365 : * CheckLoadURIWithPrincipal means denying loading if the given URI has certain
1366 : * nsIProtocolHandler flags set.
1367 : * @return if success, access is allowed. Otherwise, deny access
1368 : */
1369 : static nsresult
1370 192 : DenyAccessIfURIHasFlags(nsIURI* aURI, PRUint32 aURIFlags)
1371 : {
1372 192 : NS_PRECONDITION(aURI, "Must have URI!");
1373 :
1374 : bool uriHasFlags;
1375 : nsresult rv =
1376 192 : NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
1377 192 : NS_ENSURE_SUCCESS(rv, rv);
1378 :
1379 192 : if (uriHasFlags) {
1380 0 : return NS_ERROR_DOM_BAD_URI;
1381 : }
1382 :
1383 192 : return NS_OK;
1384 : }
1385 :
1386 : NS_IMETHODIMP
1387 184 : nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
1388 : nsIURI *aTargetURI,
1389 : PRUint32 aFlags)
1390 : {
1391 184 : NS_PRECONDITION(aPrincipal, "CheckLoadURIWithPrincipal must have a principal");
1392 : // If someone passes a flag that we don't understand, we should
1393 : // fail, because they may need a security check that we don't
1394 : // provide.
1395 184 : NS_ENSURE_FALSE(aFlags & ~(nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
1396 : nsIScriptSecurityManager::ALLOW_CHROME |
1397 : nsIScriptSecurityManager::DISALLOW_SCRIPT |
1398 : nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL),
1399 : NS_ERROR_UNEXPECTED);
1400 184 : NS_ENSURE_ARG_POINTER(aPrincipal);
1401 184 : NS_ENSURE_ARG_POINTER(aTargetURI);
1402 :
1403 184 : if (aPrincipal == mSystemPrincipal) {
1404 : // Allow access
1405 0 : return NS_OK;
1406 : }
1407 :
1408 368 : nsCOMPtr<nsIURI> sourceURI;
1409 184 : aPrincipal->GetURI(getter_AddRefs(sourceURI));
1410 184 : if (!sourceURI) {
1411 : NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
1412 0 : "must have a URI!");
1413 0 : return NS_ERROR_UNEXPECTED;
1414 : }
1415 :
1416 : // Automatic loads are not allowed from certain protocols.
1417 184 : if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
1418 : nsresult rv =
1419 : DenyAccessIfURIHasFlags(sourceURI,
1420 155 : nsIProtocolHandler::URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT);
1421 155 : NS_ENSURE_SUCCESS(rv, rv);
1422 : }
1423 :
1424 : // If DISALLOW_INHERIT_PRINCIPAL is set, we prevent loading of URIs which
1425 : // would do such inheriting. That would be URIs that do not have their own
1426 : // security context.
1427 184 : if (aFlags & nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL) {
1428 : nsresult rv =
1429 : DenyAccessIfURIHasFlags(aTargetURI,
1430 29 : nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT);
1431 29 : NS_ENSURE_SUCCESS(rv, rv);
1432 : }
1433 :
1434 : // If either URI is a nested URI, get the base URI
1435 368 : nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(sourceURI);
1436 368 : nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI);
1437 :
1438 : //-- get the target scheme
1439 368 : nsCAutoString targetScheme;
1440 184 : nsresult rv = targetBaseURI->GetScheme(targetScheme);
1441 184 : if (NS_FAILED(rv)) return rv;
1442 :
1443 : //-- Some callers do not allow loading javascript:
1444 339 : if ((aFlags & nsIScriptSecurityManager::DISALLOW_SCRIPT) &&
1445 155 : targetScheme.EqualsLiteral("javascript"))
1446 : {
1447 1 : return NS_ERROR_DOM_BAD_URI;
1448 : }
1449 :
1450 366 : NS_NAMED_LITERAL_STRING(errorTag, "CheckLoadURIError");
1451 :
1452 : // Check for uris that are only loadable by principals that subsume them
1453 : bool hasFlags;
1454 : rv = NS_URIChainHasFlags(targetBaseURI,
1455 : nsIProtocolHandler::URI_LOADABLE_BY_SUBSUMERS,
1456 183 : &hasFlags);
1457 183 : NS_ENSURE_SUCCESS(rv, rv);
1458 :
1459 183 : if (hasFlags) {
1460 0 : return aPrincipal->CheckMayLoad(targetBaseURI, true);
1461 : }
1462 :
1463 : //-- get the source scheme
1464 366 : nsCAutoString sourceScheme;
1465 183 : rv = sourceBaseURI->GetScheme(sourceScheme);
1466 183 : if (NS_FAILED(rv)) return rv;
1467 :
1468 183 : if (sourceScheme.LowerCaseEqualsLiteral(NS_NULLPRINCIPAL_SCHEME)) {
1469 : // A null principal can target its own URI.
1470 7 : if (sourceURI == aTargetURI) {
1471 0 : return NS_OK;
1472 : }
1473 : }
1474 176 : else if (targetScheme.Equals(sourceScheme,
1475 176 : nsCaseInsensitiveCStringComparator()))
1476 : {
1477 : // every scheme can access another URI from the same scheme,
1478 : // as long as they don't represent null principals.
1479 175 : return NS_OK;
1480 : }
1481 :
1482 : // If the schemes don't match, the policy is specified by the protocol
1483 : // flags on the target URI. Note that the order of policy checks here is
1484 : // very important! We start from most restrictive and work our way down.
1485 : // Note that since we're working with the innermost URI, we can just use
1486 : // the methods that work on chains of nested URIs and they will only look
1487 : // at the flags for our one URI.
1488 :
1489 : // Check for system target URI
1490 : rv = DenyAccessIfURIHasFlags(targetBaseURI,
1491 8 : nsIProtocolHandler::URI_DANGEROUS_TO_LOAD);
1492 8 : if (NS_FAILED(rv)) {
1493 : // Deny access, since the origin principal is not system
1494 0 : ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1495 0 : return rv;
1496 : }
1497 :
1498 : // Check for chrome target URI
1499 : rv = NS_URIChainHasFlags(targetBaseURI,
1500 : nsIProtocolHandler::URI_IS_UI_RESOURCE,
1501 8 : &hasFlags);
1502 8 : NS_ENSURE_SUCCESS(rv, rv);
1503 8 : if (hasFlags) {
1504 1 : if (aFlags & nsIScriptSecurityManager::ALLOW_CHROME) {
1505 0 : if (!targetScheme.EqualsLiteral("chrome")) {
1506 : // for now don't change behavior for resource: or moz-icon:
1507 0 : return NS_OK;
1508 : }
1509 :
1510 : // allow load only if chrome package is whitelisted
1511 : nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(
1512 0 : NS_CHROMEREGISTRY_CONTRACTID));
1513 0 : if (reg) {
1514 0 : bool accessAllowed = false;
1515 0 : reg->AllowContentToAccess(targetBaseURI, &accessAllowed);
1516 0 : if (accessAllowed) {
1517 0 : return NS_OK;
1518 : }
1519 : }
1520 : }
1521 :
1522 : // resource: and chrome: are equivalent, securitywise
1523 : // That's bogus!! Fix this. But watch out for
1524 : // the view-source stylesheet?
1525 : bool sourceIsChrome;
1526 : rv = NS_URIChainHasFlags(sourceBaseURI,
1527 : nsIProtocolHandler::URI_IS_UI_RESOURCE,
1528 1 : &sourceIsChrome);
1529 1 : NS_ENSURE_SUCCESS(rv, rv);
1530 1 : if (sourceIsChrome) {
1531 0 : return NS_OK;
1532 : }
1533 1 : ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1534 1 : return NS_ERROR_DOM_BAD_URI;
1535 : }
1536 :
1537 : // Check for target URI pointing to a file
1538 : rv = NS_URIChainHasFlags(targetBaseURI,
1539 : nsIProtocolHandler::URI_IS_LOCAL_FILE,
1540 7 : &hasFlags);
1541 7 : NS_ENSURE_SUCCESS(rv, rv);
1542 7 : if (hasFlags) {
1543 : // resource: and chrome: are equivalent, securitywise
1544 : // That's bogus!! Fix this. But watch out for
1545 : // the view-source stylesheet?
1546 : bool sourceIsChrome;
1547 : rv = NS_URIChainHasFlags(sourceURI,
1548 : nsIProtocolHandler::URI_IS_UI_RESOURCE,
1549 1 : &sourceIsChrome);
1550 1 : NS_ENSURE_SUCCESS(rv, rv);
1551 1 : if (sourceIsChrome) {
1552 0 : return NS_OK;
1553 : }
1554 :
1555 : // Now check capability policies
1556 : static const char loadURIPrefGroup[] = "checkloaduri";
1557 2 : ClassInfoData nameData(nsnull, loadURIPrefGroup);
1558 :
1559 : SecurityLevel secLevel;
1560 : rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1561 : nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1562 1 : nsnull, &secLevel);
1563 1 : if (NS_SUCCEEDED(rv) && secLevel.level == SCRIPT_SECURITY_ALL_ACCESS)
1564 : {
1565 : // OK for this site!
1566 0 : return NS_OK;
1567 : }
1568 :
1569 1 : ReportError(nsnull, errorTag, sourceURI, aTargetURI);
1570 1 : return NS_ERROR_DOM_BAD_URI;
1571 : }
1572 :
1573 : // OK, everyone is allowed to load this, since unflagged handlers are
1574 : // deprecated but treated as URI_LOADABLE_BY_ANYONE. But check whether we
1575 : // need to warn. At some point we'll want to make this warning into an
1576 : // error and treat unflagged handlers as URI_DANGEROUS_TO_LOAD.
1577 : rv = NS_URIChainHasFlags(targetBaseURI,
1578 : nsIProtocolHandler::URI_LOADABLE_BY_ANYONE,
1579 6 : &hasFlags);
1580 6 : NS_ENSURE_SUCCESS(rv, rv);
1581 6 : if (!hasFlags) {
1582 0 : nsXPIDLString message;
1583 0 : NS_ConvertASCIItoUTF16 ucsTargetScheme(targetScheme);
1584 0 : const PRUnichar* formatStrings[] = { ucsTargetScheme.get() };
1585 : rv = sStrBundle->
1586 0 : FormatStringFromName(NS_LITERAL_STRING("ProtocolFlagError").get(),
1587 : formatStrings,
1588 : ArrayLength(formatStrings),
1589 0 : getter_Copies(message));
1590 0 : if (NS_SUCCEEDED(rv)) {
1591 : nsCOMPtr<nsIConsoleService> console(
1592 0 : do_GetService("@mozilla.org/consoleservice;1"));
1593 0 : NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1594 :
1595 0 : console->LogStringMessage(message.get());
1596 : #ifdef DEBUG
1597 0 : fprintf(stderr, "%s\n", NS_ConvertUTF16toUTF8(message).get());
1598 : #endif
1599 : }
1600 : }
1601 :
1602 6 : return NS_OK;
1603 : }
1604 :
1605 : nsresult
1606 2 : nsScriptSecurityManager::ReportError(JSContext* cx, const nsAString& messageTag,
1607 : nsIURI* aSource, nsIURI* aTarget)
1608 : {
1609 : nsresult rv;
1610 2 : NS_ENSURE_TRUE(aSource && aTarget, NS_ERROR_NULL_POINTER);
1611 :
1612 : // Get the source URL spec
1613 4 : nsCAutoString sourceSpec;
1614 2 : rv = aSource->GetAsciiSpec(sourceSpec);
1615 2 : NS_ENSURE_SUCCESS(rv, rv);
1616 :
1617 : // Get the target URL spec
1618 4 : nsCAutoString targetSpec;
1619 2 : rv = aTarget->GetAsciiSpec(targetSpec);
1620 2 : NS_ENSURE_SUCCESS(rv, rv);
1621 :
1622 : // Localize the error message
1623 4 : nsXPIDLString message;
1624 4 : NS_ConvertASCIItoUTF16 ucsSourceSpec(sourceSpec);
1625 4 : NS_ConvertASCIItoUTF16 ucsTargetSpec(targetSpec);
1626 2 : const PRUnichar *formatStrings[] = { ucsSourceSpec.get(), ucsTargetSpec.get() };
1627 2 : rv = sStrBundle->FormatStringFromName(PromiseFlatString(messageTag).get(),
1628 : formatStrings,
1629 : ArrayLength(formatStrings),
1630 4 : getter_Copies(message));
1631 2 : NS_ENSURE_SUCCESS(rv, rv);
1632 :
1633 : // If a JS context was passed in, set a JS exception.
1634 : // Otherwise, print the error message directly to the JS console
1635 : // and to standard output
1636 2 : if (cx)
1637 : {
1638 0 : SetPendingException(cx, message.get());
1639 : }
1640 : else // Print directly to the console
1641 : {
1642 : nsCOMPtr<nsIConsoleService> console(
1643 4 : do_GetService("@mozilla.org/consoleservice;1"));
1644 2 : NS_ENSURE_TRUE(console, NS_ERROR_FAILURE);
1645 :
1646 2 : console->LogStringMessage(message.get());
1647 : #ifdef DEBUG
1648 4 : fprintf(stderr, "%s\n", NS_LossyConvertUTF16toASCII(message).get());
1649 : #endif
1650 : }
1651 2 : return NS_OK;
1652 : }
1653 :
1654 : NS_IMETHODIMP
1655 0 : nsScriptSecurityManager::CheckLoadURIStr(const nsACString& aSourceURIStr,
1656 : const nsACString& aTargetURIStr,
1657 : PRUint32 aFlags)
1658 : {
1659 : // FIXME: bug 327244 -- this function should really die... Really truly.
1660 0 : nsCOMPtr<nsIURI> source;
1661 0 : nsresult rv = NS_NewURI(getter_AddRefs(source), aSourceURIStr,
1662 0 : nsnull, nsnull, sIOService);
1663 0 : NS_ENSURE_SUCCESS(rv, rv);
1664 :
1665 : // Note: this is not _quite_ right if aSourceURI has
1666 : // NS_NULLPRINCIPAL_SCHEME, but we'll just extract the scheme in
1667 : // CheckLoadURIWithPrincipal anyway, so this is good enough. This method
1668 : // really needs to go away....
1669 0 : nsCOMPtr<nsIPrincipal> sourcePrincipal;
1670 : rv = CreateCodebasePrincipal(source,
1671 0 : getter_AddRefs(sourcePrincipal));
1672 0 : NS_ENSURE_SUCCESS(rv, rv);
1673 :
1674 : return CheckLoadURIStrWithPrincipal(sourcePrincipal, aTargetURIStr,
1675 0 : aFlags);
1676 : }
1677 :
1678 : NS_IMETHODIMP
1679 2 : nsScriptSecurityManager::CheckLoadURIStrWithPrincipal(nsIPrincipal* aPrincipal,
1680 : const nsACString& aTargetURIStr,
1681 : PRUint32 aFlags)
1682 : {
1683 : nsresult rv;
1684 4 : nsCOMPtr<nsIURI> target;
1685 2 : rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
1686 2 : nsnull, nsnull, sIOService);
1687 2 : NS_ENSURE_SUCCESS(rv, rv);
1688 :
1689 2 : rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1690 2 : NS_ENSURE_SUCCESS(rv, rv);
1691 :
1692 : // Now start testing fixup -- since aTargetURIStr is a string, not
1693 : // an nsIURI, we may well end up fixing it up before loading.
1694 : // Note: This needs to stay in sync with the nsIURIFixup api.
1695 2 : nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
1696 1 : if (!fixup) {
1697 0 : return rv;
1698 : }
1699 :
1700 : PRUint32 flags[] = {
1701 : nsIURIFixup::FIXUP_FLAG_NONE,
1702 : nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
1703 : nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
1704 : nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
1705 : nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI
1706 1 : };
1707 :
1708 5 : for (PRUint32 i = 0; i < ArrayLength(flags); ++i) {
1709 4 : rv = fixup->CreateFixupURI(aTargetURIStr, flags[i],
1710 4 : getter_AddRefs(target));
1711 4 : NS_ENSURE_SUCCESS(rv, rv);
1712 :
1713 4 : rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
1714 4 : NS_ENSURE_SUCCESS(rv, rv);
1715 : }
1716 :
1717 1 : return rv;
1718 : }
1719 :
1720 : NS_IMETHODIMP
1721 0 : nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
1722 : void *aTargetObj)
1723 : {
1724 : // This check is called for event handlers
1725 : nsresult rv;
1726 : nsIPrincipal* subject =
1727 0 : GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
1728 :
1729 : // If subject is null, get a principal from the function object's scope.
1730 0 : if (NS_SUCCEEDED(rv) && !subject)
1731 : {
1732 : #ifdef DEBUG
1733 : {
1734 0 : JS_ASSERT(JS_ObjectIsFunction(aCx, (JSObject *)aFunObj));
1735 0 : JSFunction *fun = JS_GetObjectFunction((JSObject *)aFunObj);
1736 0 : JSScript *script = JS_GetFunctionScript(aCx, fun);
1737 :
1738 0 : NS_ASSERTION(!script, "Null principal for non-native function!");
1739 : }
1740 : #endif
1741 :
1742 0 : subject = doGetObjectPrincipal((JSObject*)aFunObj);
1743 : }
1744 :
1745 0 : if (!subject)
1746 0 : return NS_ERROR_FAILURE;
1747 :
1748 0 : if (subject == mSystemPrincipal)
1749 : // This is the system principal: just allow access
1750 0 : return NS_OK;
1751 :
1752 : // Check if the principal the function was compiled under is
1753 : // allowed to execute scripts.
1754 :
1755 : bool result;
1756 0 : rv = CanExecuteScripts(aCx, subject, &result);
1757 0 : if (NS_FAILED(rv))
1758 0 : return rv;
1759 :
1760 0 : if (!result)
1761 0 : return NS_ERROR_DOM_SECURITY_ERR;
1762 :
1763 : /*
1764 : ** Get origin of subject and object and compare.
1765 : */
1766 0 : JSObject* obj = (JSObject*)aTargetObj;
1767 0 : nsIPrincipal* object = doGetObjectPrincipal(obj);
1768 :
1769 0 : if (!object)
1770 0 : return NS_ERROR_FAILURE;
1771 :
1772 : bool subsumes;
1773 0 : rv = subject->Subsumes(object, &subsumes);
1774 0 : if (NS_SUCCEEDED(rv) && !subsumes) {
1775 0 : rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
1776 : }
1777 0 : return rv;
1778 : }
1779 :
1780 : NS_IMETHODIMP
1781 0 : nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
1782 : nsIPrincipal *aPrincipal,
1783 : bool *result)
1784 : {
1785 0 : *result = false;
1786 :
1787 0 : if (aPrincipal == mSystemPrincipal)
1788 : {
1789 : // Even if JavaScript is disabled, we must still execute system scripts
1790 0 : *result = true;
1791 0 : return NS_OK;
1792 : }
1793 :
1794 : //-- See if the current window allows JS execution
1795 0 : nsIScriptContext *scriptContext = GetScriptContext(cx);
1796 0 : if (!scriptContext) return NS_ERROR_FAILURE;
1797 :
1798 0 : if (!scriptContext->GetScriptsEnabled()) {
1799 : // No scripting on this context, folks
1800 0 : *result = false;
1801 0 : return NS_OK;
1802 : }
1803 :
1804 0 : nsIScriptGlobalObject *sgo = scriptContext->GetGlobalObject();
1805 :
1806 0 : if (!sgo) {
1807 0 : return NS_ERROR_FAILURE;
1808 : }
1809 :
1810 : // window can be null here if we're running with a non-DOM window
1811 : // as the script global (i.e. a XUL prototype document).
1812 0 : nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
1813 0 : nsCOMPtr<nsIDocShell> docshell;
1814 : nsresult rv;
1815 :
1816 0 : if (window) {
1817 0 : docshell = window->GetDocShell();
1818 : }
1819 :
1820 0 : if (docshell) {
1821 0 : rv = docshell->GetCanExecuteScripts(result);
1822 0 : if (NS_FAILED(rv)) return rv;
1823 0 : if (!*result) return NS_OK;
1824 : }
1825 :
1826 : // OK, the docshell doesn't have script execution explicitly disabled.
1827 : // Check whether our URI is an "about:" URI that allows scripts. If it is,
1828 : // we need to allow JS to run. In this case, don't apply the JS enabled
1829 : // pref or policies. On failures, just press on and don't do this special
1830 : // case.
1831 0 : nsCOMPtr<nsIURI> principalURI;
1832 0 : aPrincipal->GetURI(getter_AddRefs(principalURI));
1833 0 : if (!principalURI) {
1834 : // Broken principal of some sort. Disallow.
1835 0 : *result = false;
1836 0 : return NS_ERROR_UNEXPECTED;
1837 : }
1838 :
1839 : bool isAbout;
1840 0 : rv = principalURI->SchemeIs("about", &isAbout);
1841 0 : if (NS_SUCCEEDED(rv) && isAbout) {
1842 0 : nsCOMPtr<nsIAboutModule> module;
1843 0 : rv = NS_GetAboutModule(principalURI, getter_AddRefs(module));
1844 0 : if (NS_SUCCEEDED(rv)) {
1845 : PRUint32 flags;
1846 0 : rv = module->GetURIFlags(principalURI, &flags);
1847 0 : if (NS_SUCCEEDED(rv) &&
1848 : (flags & nsIAboutModule::ALLOW_SCRIPT)) {
1849 0 : *result = true;
1850 0 : return NS_OK;
1851 : }
1852 : }
1853 : }
1854 :
1855 0 : *result = mIsJavaScriptEnabled;
1856 0 : if (!*result)
1857 0 : return NS_OK; // Do not run scripts
1858 :
1859 : //-- Check for a per-site policy
1860 : static const char jsPrefGroupName[] = "javascript";
1861 0 : ClassInfoData nameData(nsnull, jsPrefGroupName);
1862 :
1863 : SecurityLevel secLevel;
1864 : rv = LookupPolicy(aPrincipal, nameData, sEnabledID,
1865 : nsIXPCSecurityManager::ACCESS_GET_PROPERTY,
1866 0 : nsnull, &secLevel);
1867 0 : if (NS_FAILED(rv) || secLevel.level == SCRIPT_SECURITY_NO_ACCESS)
1868 : {
1869 0 : *result = false;
1870 0 : return rv;
1871 : }
1872 :
1873 : //-- Nobody vetoed, so allow the JS to run.
1874 0 : *result = true;
1875 0 : return NS_OK;
1876 : }
1877 :
1878 : ///////////////// Principals ///////////////////////
1879 : NS_IMETHODIMP
1880 40139 : nsScriptSecurityManager::GetSubjectPrincipal(nsIPrincipal **aSubjectPrincipal)
1881 : {
1882 : nsresult rv;
1883 40139 : *aSubjectPrincipal = doGetSubjectPrincipal(&rv);
1884 40139 : if (NS_SUCCEEDED(rv))
1885 40139 : NS_IF_ADDREF(*aSubjectPrincipal);
1886 40139 : return rv;
1887 : }
1888 :
1889 : nsIPrincipal*
1890 40139 : nsScriptSecurityManager::doGetSubjectPrincipal(nsresult* rv)
1891 : {
1892 40139 : NS_PRECONDITION(rv, "Null out param");
1893 40139 : JSContext *cx = GetCurrentJSContext();
1894 40139 : if (!cx)
1895 : {
1896 0 : *rv = NS_OK;
1897 0 : return nsnull;
1898 : }
1899 40139 : return GetSubjectPrincipal(cx, rv);
1900 : }
1901 :
1902 : NS_IMETHODIMP
1903 4421 : nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
1904 : {
1905 4421 : NS_ADDREF(*result = mSystemPrincipal);
1906 :
1907 4421 : return NS_OK;
1908 : }
1909 :
1910 : NS_IMETHODIMP
1911 38805 : nsScriptSecurityManager::SubjectPrincipalIsSystem(bool* aIsSystem)
1912 : {
1913 38805 : NS_ENSURE_ARG_POINTER(aIsSystem);
1914 38805 : *aIsSystem = false;
1915 :
1916 38805 : if (!mSystemPrincipal)
1917 0 : return NS_OK;
1918 :
1919 77610 : nsCOMPtr<nsIPrincipal> subject;
1920 38805 : nsresult rv = GetSubjectPrincipal(getter_AddRefs(subject));
1921 38805 : if (NS_FAILED(rv))
1922 0 : return rv;
1923 :
1924 38805 : if(!subject)
1925 : {
1926 : // No subject principal means no JS is running;
1927 : // this is the equivalent of system principal code
1928 0 : *aIsSystem = true;
1929 0 : return NS_OK;
1930 : }
1931 :
1932 38805 : return mSystemPrincipal->Equals(subject, aIsSystem);
1933 : }
1934 :
1935 : NS_IMETHODIMP
1936 0 : nsScriptSecurityManager::GetCertificatePrincipal(const nsACString& aCertFingerprint,
1937 : const nsACString& aSubjectName,
1938 : const nsACString& aPrettyName,
1939 : nsISupports* aCertificate,
1940 : nsIURI* aURI,
1941 : nsIPrincipal **result)
1942 : {
1943 0 : *result = nsnull;
1944 :
1945 0 : NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() &&
1946 : !aSubjectName.IsEmpty() &&
1947 : aCertificate);
1948 :
1949 : return DoGetCertificatePrincipal(aCertFingerprint, aSubjectName,
1950 : aPrettyName, aCertificate, aURI, true,
1951 0 : result);
1952 : }
1953 :
1954 : nsresult
1955 0 : nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFingerprint,
1956 : const nsACString& aSubjectName,
1957 : const nsACString& aPrettyName,
1958 : nsISupports* aCertificate,
1959 : nsIURI* aURI,
1960 : bool aModifyTable,
1961 : nsIPrincipal **result)
1962 : {
1963 0 : NS_ENSURE_ARG(!aCertFingerprint.IsEmpty());
1964 :
1965 : // Create a certificate principal out of the certificate ID
1966 : // and URI given to us. We will use this principal to test
1967 : // equality when doing our hashtable lookups below.
1968 0 : nsRefPtr<nsPrincipal> certificate = new nsPrincipal();
1969 0 : if (!certificate)
1970 0 : return NS_ERROR_OUT_OF_MEMORY;
1971 :
1972 : nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
1973 0 : aPrettyName, aCertificate, aURI);
1974 0 : NS_ENSURE_SUCCESS(rv, rv);
1975 :
1976 : // Check to see if we already have this principal.
1977 0 : nsCOMPtr<nsIPrincipal> fromTable;
1978 0 : mPrincipals.Get(certificate, getter_AddRefs(fromTable));
1979 0 : if (fromTable) {
1980 : // Bingo. We found the certificate in the table, which means
1981 : // that it has escalated privileges.
1982 :
1983 0 : if (aModifyTable) {
1984 : // Make sure this principal has names, so if we ever go to save it
1985 : // we'll save them. If we get a name mismatch here we'll throw,
1986 : // but that's desirable.
1987 : rv = static_cast<nsPrincipal*>
1988 0 : (static_cast<nsIPrincipal*>(fromTable))
1989 0 : ->EnsureCertData(aSubjectName, aPrettyName, aCertificate);
1990 0 : if (NS_FAILED(rv)) {
1991 : // We have a subject name mismatch for the same cert id.
1992 : // Hand back the |certificate| object we created and don't give
1993 : // it any rights from the table.
1994 0 : NS_ADDREF(*result = certificate);
1995 0 : return NS_OK;
1996 : }
1997 : }
1998 :
1999 0 : if (!aURI) {
2000 : // We were asked to just get the base certificate, so output
2001 : // what we have in the table.
2002 : certificate = static_cast<nsPrincipal*>
2003 : (static_cast<nsIPrincipal*>
2004 0 : (fromTable));
2005 : } else {
2006 : // We found a certificate and now need to install a codebase
2007 : // on it. We don't want to modify the principal in the hash
2008 : // table, so create a new principal and clone the pertinent
2009 : // things.
2010 0 : nsXPIDLCString prefName;
2011 0 : nsXPIDLCString id;
2012 0 : nsXPIDLCString subjectName;
2013 0 : nsXPIDLCString granted;
2014 0 : nsXPIDLCString denied;
2015 : bool isTrusted;
2016 0 : rv = fromTable->GetPreferences(getter_Copies(prefName),
2017 0 : getter_Copies(id),
2018 0 : getter_Copies(subjectName),
2019 0 : getter_Copies(granted),
2020 0 : getter_Copies(denied),
2021 0 : &isTrusted);
2022 : // XXXbz assert something about subjectName and aSubjectName here?
2023 0 : if (NS_SUCCEEDED(rv)) {
2024 0 : NS_ASSERTION(!isTrusted, "Shouldn't have isTrusted true here");
2025 :
2026 0 : certificate = new nsPrincipal();
2027 0 : if (!certificate)
2028 0 : return NS_ERROR_OUT_OF_MEMORY;
2029 :
2030 : rv = certificate->InitFromPersistent(prefName, id,
2031 : subjectName, aPrettyName,
2032 : granted, denied,
2033 : aCertificate,
2034 0 : true, false);
2035 0 : if (NS_FAILED(rv))
2036 0 : return rv;
2037 :
2038 0 : certificate->SetURI(aURI);
2039 : }
2040 : }
2041 : }
2042 :
2043 0 : NS_ADDREF(*result = certificate);
2044 :
2045 0 : return rv;
2046 : }
2047 :
2048 : nsresult
2049 207 : nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **result)
2050 : {
2051 : // I _think_ it's safe to not create null principals here based on aURI.
2052 : // At least all the callers would do the right thing in those cases, as far
2053 : // as I can tell. --bz
2054 :
2055 414 : nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
2056 207 : if (uriPrinc) {
2057 0 : nsCOMPtr<nsIPrincipal> principal;
2058 0 : uriPrinc->GetPrincipal(getter_AddRefs(principal));
2059 0 : if (!principal || principal == mSystemPrincipal) {
2060 0 : return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
2061 : }
2062 :
2063 0 : principal.forget(result);
2064 :
2065 0 : return NS_OK;
2066 : }
2067 :
2068 414 : nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2069 207 : if (!codebase)
2070 0 : return NS_ERROR_OUT_OF_MEMORY;
2071 :
2072 414 : nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
2073 621 : EmptyCString(), nsnull, aURI);
2074 207 : if (NS_FAILED(rv))
2075 0 : return rv;
2076 :
2077 207 : NS_ADDREF(*result = codebase);
2078 :
2079 207 : return NS_OK;
2080 : }
2081 :
2082 : NS_IMETHODIMP
2083 217 : nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
2084 : nsIPrincipal **result)
2085 : {
2086 217 : NS_ENSURE_ARG(aURI);
2087 :
2088 : bool inheritsPrincipal;
2089 : nsresult rv =
2090 : NS_URIChainHasFlags(aURI,
2091 : nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
2092 217 : &inheritsPrincipal);
2093 217 : if (NS_FAILED(rv) || inheritsPrincipal) {
2094 10 : return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
2095 : }
2096 :
2097 414 : nsCOMPtr<nsIPrincipal> principal;
2098 207 : rv = CreateCodebasePrincipal(aURI, getter_AddRefs(principal));
2099 207 : if (NS_FAILED(rv)) return rv;
2100 :
2101 207 : if (mPrincipals.Count() > 0)
2102 : {
2103 : //-- Check to see if we already have this principal.
2104 0 : nsCOMPtr<nsIPrincipal> fromTable;
2105 0 : mPrincipals.Get(principal, getter_AddRefs(fromTable));
2106 0 : if (fromTable) {
2107 : // We found an existing codebase principal. But it might have a
2108 : // generic codebase for this origin on it. Install our particular
2109 : // codebase.
2110 : // XXXbz this is kinda similar to the code in
2111 : // GetCertificatePrincipal, but just ever so slightly different.
2112 : // Oh, well.
2113 0 : nsXPIDLCString prefName;
2114 0 : nsXPIDLCString id;
2115 0 : nsXPIDLCString subjectName;
2116 0 : nsXPIDLCString granted;
2117 0 : nsXPIDLCString denied;
2118 : bool isTrusted;
2119 0 : rv = fromTable->GetPreferences(getter_Copies(prefName),
2120 0 : getter_Copies(id),
2121 0 : getter_Copies(subjectName),
2122 0 : getter_Copies(granted),
2123 0 : getter_Copies(denied),
2124 0 : &isTrusted);
2125 0 : if (NS_SUCCEEDED(rv)) {
2126 0 : nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
2127 0 : if (!codebase)
2128 0 : return NS_ERROR_OUT_OF_MEMORY;
2129 :
2130 : rv = codebase->InitFromPersistent(prefName, id,
2131 0 : subjectName, EmptyCString(),
2132 : granted, denied,
2133 : nsnull, false,
2134 0 : isTrusted);
2135 0 : if (NS_FAILED(rv))
2136 0 : return rv;
2137 :
2138 0 : codebase->SetURI(aURI);
2139 0 : principal = codebase;
2140 : }
2141 :
2142 : }
2143 : }
2144 :
2145 207 : NS_IF_ADDREF(*result = principal);
2146 :
2147 207 : return NS_OK;
2148 : }
2149 :
2150 : NS_IMETHODIMP
2151 0 : nsScriptSecurityManager::GetPrincipalFromContext(JSContext *cx,
2152 : nsIPrincipal **result)
2153 : {
2154 0 : *result = nsnull;
2155 :
2156 : nsIScriptContextPrincipal* scp =
2157 0 : GetScriptContextPrincipalFromJSContext(cx);
2158 :
2159 0 : if (!scp)
2160 : {
2161 0 : return NS_ERROR_FAILURE;
2162 : }
2163 :
2164 0 : nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
2165 0 : if (globalData)
2166 0 : NS_IF_ADDREF(*result = globalData->GetPrincipal());
2167 :
2168 0 : return NS_OK;
2169 : }
2170 :
2171 : // static
2172 : nsIPrincipal*
2173 231081 : nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
2174 : JSScript *script,
2175 : nsresult* rv)
2176 : {
2177 231081 : NS_PRECONDITION(rv, "Null out param");
2178 231081 : *rv = NS_OK;
2179 231081 : if (!script)
2180 : {
2181 707 : return nsnull;
2182 : }
2183 230374 : JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
2184 230374 : if (!jsp) {
2185 0 : *rv = NS_ERROR_FAILURE;
2186 0 : NS_ERROR("Script compiled without principals!");
2187 0 : return nsnull;
2188 : }
2189 230374 : return nsJSPrincipals::get(jsp);
2190 : }
2191 :
2192 : // static
2193 : nsIPrincipal*
2194 1867628 : nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
2195 : JSObject *obj,
2196 : JSStackFrame *fp,
2197 : nsresult *rv)
2198 : {
2199 1867628 : NS_PRECONDITION(rv, "Null out param");
2200 :
2201 1867628 : *rv = NS_OK;
2202 :
2203 1867628 : if (!JS_ObjectIsFunction(cx, obj))
2204 : {
2205 : // Protect against pseudo-functions (like SJOWs).
2206 0 : nsIPrincipal *result = doGetObjectPrincipal(obj);
2207 0 : if (!result)
2208 0 : *rv = NS_ERROR_FAILURE;
2209 0 : return result;
2210 : }
2211 :
2212 1867628 : JSFunction *fun = JS_GetObjectFunction(obj);
2213 1867628 : JSScript *script = JS_GetFunctionScript(cx, fun);
2214 :
2215 1867628 : if (!script)
2216 : {
2217 : // A native function: skip it in order to find its scripted caller.
2218 0 : return nsnull;
2219 : }
2220 :
2221 1867628 : JSScript *frameScript = fp ? JS_GetFrameScript(cx, fp) : nsnull;
2222 :
2223 1867628 : if (frameScript && frameScript != script)
2224 : {
2225 : // There is a frame script, and it's different from the
2226 : // function script. In this case we're dealing with either
2227 : // an eval or a Script object, and in these cases the
2228 : // principal we want is in the frame's script, not in the
2229 : // function's script. The function's script is where the
2230 : // eval-calling code came from, not where the eval or new
2231 : // Script object came from, and we want the principal of
2232 : // the eval function object or new Script object.
2233 :
2234 3 : script = frameScript;
2235 : }
2236 1867625 : else if (!js::IsOriginalScriptFunction(fun))
2237 : {
2238 : // Here, obj is a cloned function object. In this case, the
2239 : // clone's prototype may have been precompiled from brutally
2240 : // shared chrome, or else it is a lambda or nested function.
2241 : // The general case here is a function compiled against a
2242 : // different scope than the one it is parented by at runtime,
2243 : // hence the creation of a clone to carry the correct scope
2244 : // chain linkage.
2245 : //
2246 : // Since principals follow scope, we must get the object
2247 : // principal from the clone's scope chain. There are no
2248 : // reliable principals compiled into the function itself.
2249 :
2250 1867371 : nsIPrincipal *result = doGetObjectPrincipal(obj);
2251 1867371 : if (!result)
2252 0 : *rv = NS_ERROR_FAILURE;
2253 1867371 : return result;
2254 : }
2255 :
2256 257 : return GetScriptPrincipal(cx, script, rv);
2257 : }
2258 :
2259 : nsIPrincipal*
2260 2098452 : nsScriptSecurityManager::GetFramePrincipal(JSContext *cx,
2261 : JSStackFrame *fp,
2262 : nsresult *rv)
2263 : {
2264 2098452 : NS_PRECONDITION(rv, "Null out param");
2265 2098452 : JSObject *obj = JS_GetFrameFunctionObject(cx, fp);
2266 2098452 : if (!obj)
2267 : {
2268 : // Must be in a top-level script. Get principal from the script.
2269 230824 : JSScript *script = JS_GetFrameScript(cx, fp);
2270 230824 : return GetScriptPrincipal(cx, script, rv);
2271 : }
2272 :
2273 1867628 : nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
2274 :
2275 : #ifdef DEBUG
2276 1867628 : if (NS_SUCCEEDED(*rv) && !result)
2277 : {
2278 0 : JSFunction *fun = JS_GetObjectFunction(obj);
2279 0 : JSScript *script = JS_GetFunctionScript(cx, fun);
2280 :
2281 0 : NS_ASSERTION(!script, "Null principal for non-native function!");
2282 : }
2283 : #endif
2284 :
2285 1867628 : return result;
2286 : }
2287 :
2288 : nsIPrincipal*
2289 1687726 : nsScriptSecurityManager::GetPrincipalAndFrame(JSContext *cx,
2290 : JSStackFrame **frameResult,
2291 : nsresult* rv)
2292 : {
2293 1687726 : NS_PRECONDITION(rv, "Null out param");
2294 : //-- If there's no principal on the stack, look at the global object
2295 : // and return the innermost frame for annotations.
2296 1687726 : *rv = NS_OK;
2297 :
2298 1687726 : if (cx)
2299 : {
2300 1687726 : JSStackFrame *target = nsnull;
2301 1687726 : nsIPrincipal *targetPrincipal = nsnull;
2302 1747249 : for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
2303 : {
2304 1423810 : if (cp->mCx == cx)
2305 : {
2306 1364287 : target = cp->mFp;
2307 1364287 : targetPrincipal = cp->mPrincipal;
2308 1364287 : break;
2309 : }
2310 : }
2311 :
2312 : // Get principals from innermost JavaScript frame.
2313 1687726 : JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
2314 1688409 : for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
2315 : {
2316 1688328 : if (fp == target)
2317 4 : break;
2318 1688324 : nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
2319 1688324 : if (result)
2320 : {
2321 1687641 : NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
2322 1687641 : *frameResult = fp;
2323 1687641 : return result;
2324 : }
2325 : }
2326 :
2327 : // If targetPrincipal is non-null, then it means that someone wants to
2328 : // clamp the principals on this context to this principal. Note that
2329 : // fp might not equal target here (fp might be null) because someone
2330 : // could have set aside the frame chain in the meantime.
2331 85 : if (targetPrincipal)
2332 : {
2333 85 : if (fp && fp == target)
2334 : {
2335 4 : *frameResult = fp;
2336 : }
2337 : else
2338 : {
2339 81 : JSStackFrame *inner = nsnull;
2340 81 : *frameResult = JS_FrameIterator(cx, &inner);
2341 : }
2342 :
2343 85 : return targetPrincipal;
2344 : }
2345 :
2346 : nsIScriptContextPrincipal* scp =
2347 0 : GetScriptContextPrincipalFromJSContext(cx);
2348 0 : if (scp)
2349 : {
2350 0 : nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
2351 0 : if (!globalData)
2352 : {
2353 0 : *rv = NS_ERROR_FAILURE;
2354 0 : return nsnull;
2355 : }
2356 :
2357 : // Note that we're not in a loop or anything, and nothing comes
2358 : // after this point in the function, so we can just return here.
2359 0 : nsIPrincipal* result = globalData->GetPrincipal();
2360 0 : if (result)
2361 : {
2362 0 : JSStackFrame *inner = nsnull;
2363 0 : *frameResult = JS_FrameIterator(cx, &inner);
2364 0 : return result;
2365 : }
2366 : }
2367 : }
2368 :
2369 0 : return nsnull;
2370 : }
2371 :
2372 : nsIPrincipal*
2373 1687135 : nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
2374 : nsresult* rv)
2375 : {
2376 1687135 : NS_PRECONDITION(rv, "Null out param");
2377 : JSStackFrame *fp;
2378 1687135 : return GetPrincipalAndFrame(cx, &fp, rv);
2379 : }
2380 :
2381 : NS_IMETHODIMP
2382 2170 : nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
2383 : nsIPrincipal **result)
2384 : {
2385 2170 : *result = doGetObjectPrincipal(aObj);
2386 2170 : if (!*result)
2387 0 : return NS_ERROR_FAILURE;
2388 2170 : NS_ADDREF(*result);
2389 2170 : return NS_OK;
2390 : }
2391 :
2392 : // static
2393 : nsIPrincipal*
2394 3739082 : nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
2395 : #ifdef DEBUG
2396 : , bool aAllowShortCircuit
2397 : #endif
2398 : )
2399 : {
2400 3739082 : NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
2401 3739082 : nsIPrincipal* result = nsnull;
2402 :
2403 : #ifdef DEBUG
2404 3739082 : JSObject* origObj = aObj;
2405 : #endif
2406 :
2407 3739082 : js::Class *jsClass = js::GetObjectClass(aObj);
2408 :
2409 : // A common case seen in this code is that we enter this function
2410 : // with aObj being a Function object, whose parent is a Call
2411 : // object. Neither of those have object principals, so we can skip
2412 : // those objects here before we enter the below loop. That way we
2413 : // avoid wasting time checking properties of their classes etc in
2414 : // the loop.
2415 :
2416 3739082 : if (jsClass == &js::FunctionClass) {
2417 3734742 : aObj = js::GetObjectParent(aObj);
2418 :
2419 3734742 : if (!aObj)
2420 0 : return nsnull;
2421 :
2422 3734742 : jsClass = js::GetObjectClass(aObj);
2423 :
2424 3734742 : if (jsClass == &js::CallClass) {
2425 0 : aObj = js::GetObjectParentMaybeScope(aObj);
2426 :
2427 0 : if (!aObj)
2428 0 : return nsnull;
2429 :
2430 0 : jsClass = js::GetObjectClass(aObj);
2431 : }
2432 : }
2433 :
2434 5110 : do {
2435 : // Note: jsClass is set before this loop, and also at the
2436 : // *end* of this loop.
2437 :
2438 3744192 : if (IS_WRAPPER_CLASS(jsClass)) {
2439 : result = sXPConnect->GetPrincipal(aObj,
2440 : #ifdef DEBUG
2441 : aAllowShortCircuit
2442 : #else
2443 : true
2444 : #endif
2445 3735290 : );
2446 3735290 : if (result) {
2447 3735290 : break;
2448 : }
2449 8902 : } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
2450 8902 : JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
2451 3792 : nsISupports *priv = (nsISupports *) js::GetObjectPrivate(aObj);
2452 :
2453 : #ifdef DEBUG
2454 3792 : if (aAllowShortCircuit) {
2455 : nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
2456 3792 : do_QueryInterface(priv);
2457 :
2458 1896 : NS_ASSERTION(!xpcWrapper ||
2459 : !strcmp(jsClass->name, "XPCNativeWrapper"),
2460 : "Uh, an nsIXPConnectWrappedNative with the "
2461 : "wrong JSClass or getObjectOps hooks!");
2462 : }
2463 : #endif
2464 :
2465 : nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
2466 7584 : do_QueryInterface(priv);
2467 :
2468 3792 : if (objPrin) {
2469 3792 : result = objPrin->GetPrincipal();
2470 :
2471 3792 : if (result) {
2472 : break;
2473 : }
2474 : }
2475 : }
2476 :
2477 5110 : aObj = js::GetObjectParentMaybeScope(aObj);
2478 :
2479 5110 : if (!aObj)
2480 0 : break;
2481 :
2482 5110 : jsClass = js::GetObjectClass(aObj);
2483 : } while (1);
2484 :
2485 : #ifdef DEBUG
2486 3739082 : if (aAllowShortCircuit) {
2487 1869541 : nsIPrincipal *principal = doGetObjectPrincipal(origObj, false);
2488 :
2489 : // Because of inner window reuse, we can have objects with one principal
2490 : // living in a scope with a different (but same-origin) principal. So
2491 : // just check same-origin here.
2492 1869541 : NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)),
2493 : "Principal mismatch. Not good");
2494 : }
2495 : #endif
2496 :
2497 3739082 : return result;
2498 : }
2499 :
2500 : nsresult
2501 0 : nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
2502 : {
2503 : //-- Save to mPrincipals
2504 0 : mPrincipals.Put(aToSave, aToSave);
2505 :
2506 : //-- Save to prefs
2507 0 : nsXPIDLCString idPrefName;
2508 0 : nsXPIDLCString id;
2509 0 : nsXPIDLCString subjectName;
2510 0 : nsXPIDLCString grantedList;
2511 0 : nsXPIDLCString deniedList;
2512 : bool isTrusted;
2513 0 : nsresult rv = aToSave->GetPreferences(getter_Copies(idPrefName),
2514 0 : getter_Copies(id),
2515 0 : getter_Copies(subjectName),
2516 0 : getter_Copies(grantedList),
2517 0 : getter_Copies(deniedList),
2518 0 : &isTrusted);
2519 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2520 :
2521 0 : nsCAutoString grantedPrefName;
2522 0 : nsCAutoString deniedPrefName;
2523 0 : nsCAutoString subjectNamePrefName;
2524 : rv = GetPrincipalPrefNames( idPrefName,
2525 : grantedPrefName,
2526 : deniedPrefName,
2527 0 : subjectNamePrefName );
2528 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2529 :
2530 0 : mIsWritingPrefs = true;
2531 0 : if (grantedList) {
2532 0 : Preferences::SetCString(grantedPrefName.get(), grantedList);
2533 : } else {
2534 0 : Preferences::ClearUser(grantedPrefName.get());
2535 : }
2536 :
2537 0 : if (deniedList) {
2538 0 : Preferences::SetCString(deniedPrefName.get(), deniedList);
2539 : } else {
2540 0 : Preferences::ClearUser(deniedPrefName.get());
2541 : }
2542 :
2543 0 : if (grantedList || deniedList) {
2544 0 : Preferences::SetCString(idPrefName, id);
2545 0 : Preferences::SetCString(subjectNamePrefName.get(), subjectName);
2546 : } else {
2547 0 : Preferences::ClearUser(idPrefName);
2548 0 : Preferences::ClearUser(subjectNamePrefName.get());
2549 : }
2550 :
2551 0 : mIsWritingPrefs = false;
2552 :
2553 0 : nsIPrefService* prefService = Preferences::GetService();
2554 0 : NS_ENSURE_TRUE(prefService, NS_ERROR_FAILURE);
2555 0 : return prefService->SavePrefFile(nsnull);
2556 : }
2557 :
2558 : ///////////////// Capabilities API /////////////////////
2559 : NS_IMETHODIMP
2560 411802 : nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
2561 : bool *result)
2562 : {
2563 : nsresult rv;
2564 411802 : JSStackFrame *fp = nsnull;
2565 411802 : JSContext *cx = GetCurrentJSContext();
2566 411802 : fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
2567 :
2568 411802 : JSStackFrame *target = nsnull;
2569 411802 : nsIPrincipal *targetPrincipal = nsnull;
2570 429484 : for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
2571 : {
2572 358536 : if (cp->mCx == cx)
2573 : {
2574 340854 : target = cp->mFp;
2575 340854 : targetPrincipal = cp->mPrincipal;
2576 340854 : break;
2577 : }
2578 : }
2579 :
2580 411802 : if (!fp)
2581 : {
2582 : // No script code on stack. If we had a principal pushed for this
2583 : // context and fp is null, then we use that principal. Otherwise, we
2584 : // don't have enough information and have to allow execution.
2585 :
2586 : *result = (targetPrincipal && !target)
2587 0 : ? (targetPrincipal == mSystemPrincipal)
2588 1698 : : true;
2589 :
2590 1698 : return NS_OK;
2591 : }
2592 :
2593 410104 : *result = false;
2594 410104 : nsIPrincipal* previousPrincipal = nsnull;
2595 48 : do
2596 : {
2597 410128 : nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
2598 410128 : if (NS_FAILED(rv))
2599 0 : return rv;
2600 410128 : if (!principal)
2601 24 : continue;
2602 : // If caller has a different principal, stop looking up the stack.
2603 410104 : if(previousPrincipal)
2604 : {
2605 0 : bool isEqual = false;
2606 0 : if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
2607 0 : break;
2608 : }
2609 : else
2610 410104 : previousPrincipal = principal;
2611 :
2612 : // First check if the principal is even able to enable the
2613 : // given capability. If not, don't look any further.
2614 : PRInt16 canEnable;
2615 410104 : rv = principal->CanEnableCapability(capability, &canEnable);
2616 410104 : if (NS_FAILED(rv)) return rv;
2617 410104 : if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
2618 : canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2619 0 : return NS_OK;
2620 :
2621 : // Now see if the capability is enabled.
2622 410104 : void *annotation = JS_GetFrameAnnotation(cx, fp);
2623 410104 : rv = principal->IsCapabilityEnabled(capability, annotation, result);
2624 410104 : if (NS_FAILED(rv)) return rv;
2625 410104 : if (*result)
2626 410104 : return NS_OK;
2627 :
2628 : // Capabilities do not extend to calls into C/C++ and then back into
2629 : // the JS engine via JS_EvaluateScript or similar APIs.
2630 0 : if (JS_IsGlobalFrame(cx, fp))
2631 0 : break;
2632 24 : } while (fp != target && (fp = JS_FrameIterator(cx, &fp)) != nsnull);
2633 :
2634 0 : if (!previousPrincipal)
2635 : {
2636 : // No principals on the stack, all native code. Allow
2637 : // execution if the subject principal is the system principal.
2638 :
2639 0 : return SubjectPrincipalIsSystem(result);
2640 : }
2641 :
2642 0 : return NS_OK;
2643 : }
2644 :
2645 : void
2646 0 : nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
2647 : {
2648 0 : nsAutoString newcaps;
2649 0 : nsAutoString rawcap;
2650 0 : NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
2651 : PRInt32 pos;
2652 0 : PRInt32 index = kNotFound;
2653 : nsresult rv;
2654 :
2655 : NS_ASSERTION(kNotFound == -1, "Basic constant changed, algorithm broken!");
2656 :
2657 0 : do {
2658 0 : pos = index+1;
2659 0 : index = aCapability.FindChar(' ', pos);
2660 : rawcap = Substring(aCapability, pos,
2661 0 : (index == kNotFound) ? index : index - pos);
2662 :
2663 0 : nsXPIDLString capstr;
2664 : rv = sStrBundle->GetStringFromName(
2665 0 : nsPromiseFlatString(capdesc+rawcap).get(),
2666 0 : getter_Copies(capstr));
2667 0 : if (NS_SUCCEEDED(rv))
2668 0 : newcaps += capstr;
2669 : else
2670 : {
2671 0 : nsXPIDLString extensionCap;
2672 0 : const PRUnichar* formatArgs[] = { rawcap.get() };
2673 : rv = sStrBundle->FormatStringFromName(
2674 0 : NS_LITERAL_STRING("ExtensionCapability").get(),
2675 : formatArgs,
2676 : ArrayLength(formatArgs),
2677 0 : getter_Copies(extensionCap));
2678 0 : if (NS_SUCCEEDED(rv))
2679 0 : newcaps += extensionCap;
2680 : else
2681 0 : newcaps += rawcap;
2682 : }
2683 :
2684 0 : newcaps += NS_LITERAL_STRING("\n");
2685 : } while (index != kNotFound);
2686 :
2687 0 : aCapability = newcaps;
2688 0 : }
2689 :
2690 : bool
2691 0 : nsScriptSecurityManager::CheckConfirmDialog(JSContext* cx, nsIPrincipal* aPrincipal,
2692 : const char* aCapability, bool *checkValue)
2693 : {
2694 : nsresult rv;
2695 0 : *checkValue = false;
2696 :
2697 : //-- Get a prompter for the current window.
2698 0 : nsCOMPtr<nsIPrompt> prompter;
2699 0 : if (cx)
2700 : {
2701 0 : nsIScriptContext *scriptContext = GetScriptContext(cx);
2702 0 : if (scriptContext)
2703 : {
2704 : nsCOMPtr<nsIDOMWindow> domWin =
2705 0 : do_QueryInterface(scriptContext->GetGlobalObject());
2706 0 : if (domWin)
2707 0 : domWin->GetPrompter(getter_AddRefs(prompter));
2708 : }
2709 : }
2710 :
2711 0 : if (!prompter)
2712 : {
2713 : //-- Couldn't get prompter from the current window, so get the prompt service.
2714 0 : nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
2715 0 : if (wwatch)
2716 0 : wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
2717 0 : if (!prompter)
2718 0 : return false;
2719 : }
2720 :
2721 : //-- Localize the dialog text
2722 0 : nsXPIDLString check;
2723 0 : rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("CheckMessage").get(),
2724 0 : getter_Copies(check));
2725 0 : if (NS_FAILED(rv))
2726 0 : return false;
2727 :
2728 0 : nsXPIDLString title;
2729 0 : rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Titleline").get(),
2730 0 : getter_Copies(title));
2731 0 : if (NS_FAILED(rv))
2732 0 : return false;
2733 :
2734 0 : nsXPIDLString yesStr;
2735 0 : rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("Yes").get(),
2736 0 : getter_Copies(yesStr));
2737 0 : if (NS_FAILED(rv))
2738 0 : return false;
2739 :
2740 0 : nsXPIDLString noStr;
2741 0 : rv = sStrBundle->GetStringFromName(NS_LITERAL_STRING("No").get(),
2742 0 : getter_Copies(noStr));
2743 0 : if (NS_FAILED(rv))
2744 0 : return false;
2745 :
2746 0 : nsCAutoString val;
2747 : bool hasCert;
2748 0 : aPrincipal->GetHasCertificate(&hasCert);
2749 0 : if (hasCert)
2750 0 : rv = aPrincipal->GetPrettyName(val);
2751 : else
2752 0 : rv = GetPrincipalDomainOrigin(aPrincipal, val);
2753 :
2754 0 : if (NS_FAILED(rv))
2755 0 : return false;
2756 :
2757 0 : NS_ConvertUTF8toUTF16 location(val);
2758 0 : NS_ConvertASCIItoUTF16 capability(aCapability);
2759 0 : FormatCapabilityString(capability);
2760 0 : const PRUnichar *formatStrings[] = { location.get(), capability.get() };
2761 :
2762 0 : nsXPIDLString message;
2763 0 : rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityQuery").get(),
2764 : formatStrings,
2765 : ArrayLength(formatStrings),
2766 0 : getter_Copies(message));
2767 0 : if (NS_FAILED(rv))
2768 0 : return false;
2769 :
2770 0 : PRInt32 buttonPressed = 1; // If the user exits by clicking the close box, assume No (button 1)
2771 0 : rv = prompter->ConfirmEx(title.get(), message.get(),
2772 : (nsIPrompt::BUTTON_DELAY_ENABLE) +
2773 : (nsIPrompt::BUTTON_POS_1_DEFAULT) +
2774 : (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) +
2775 : (nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_1),
2776 0 : yesStr.get(), noStr.get(), nsnull, check.get(), checkValue, &buttonPressed);
2777 :
2778 0 : if (NS_FAILED(rv))
2779 0 : *checkValue = false;
2780 0 : return (buttonPressed == 0);
2781 : }
2782 :
2783 : NS_IMETHODIMP
2784 0 : nsScriptSecurityManager::RequestCapability(nsIPrincipal* aPrincipal,
2785 : const char *capability, PRInt16* canEnable)
2786 : {
2787 0 : if (NS_FAILED(aPrincipal->CanEnableCapability(capability, canEnable)))
2788 0 : return NS_ERROR_FAILURE;
2789 0 : if (*canEnable == nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
2790 : {
2791 : // Prompt user for permission to enable capability.
2792 0 : JSContext* cx = GetCurrentJSContext();
2793 : // The actual value is irrelevant but we shouldn't be handing out
2794 : // malformed JSBools to XPConnect.
2795 0 : bool remember = false;
2796 0 : if (CheckConfirmDialog(cx, aPrincipal, capability, &remember))
2797 0 : *canEnable = nsIPrincipal::ENABLE_GRANTED;
2798 : else
2799 0 : *canEnable = nsIPrincipal::ENABLE_DENIED;
2800 0 : if (remember)
2801 : {
2802 : //-- Save principal to prefs and to mPrincipals
2803 0 : if (NS_FAILED(aPrincipal->SetCanEnableCapability(capability, *canEnable)))
2804 0 : return NS_ERROR_FAILURE;
2805 0 : if (NS_FAILED(SavePrincipal(aPrincipal)))
2806 0 : return NS_ERROR_FAILURE;
2807 : }
2808 : }
2809 0 : return NS_OK;
2810 : }
2811 :
2812 : NS_IMETHODIMP
2813 0 : nsScriptSecurityManager::EnableCapability(const char *capability)
2814 : {
2815 0 : JSContext *cx = GetCurrentJSContext();
2816 : JSStackFrame *fp;
2817 :
2818 : //-- Error checks for capability string length (200)
2819 0 : if(PL_strlen(capability)>200)
2820 : {
2821 : static const char msg[] = "Capability name too long";
2822 0 : SetPendingException(cx, msg);
2823 0 : return NS_ERROR_FAILURE;
2824 : }
2825 :
2826 : //-- Check capability string for valid characters
2827 : //
2828 : // Logically we might have wanted this in nsPrincipal, but performance
2829 : // worries dictate it can't go in IsCapabilityEnabled() and we may have
2830 : // to show the capability on a dialog before we call the principal's
2831 : // EnableCapability().
2832 : //
2833 : // We don't need to validate the capability string on the other APIs
2834 : // available to web content. Without the ability to enable junk then
2835 : // isPrivilegeEnabled, disablePrivilege, and revertPrivilege all do
2836 : // the right thing (effectively nothing) when passed unallowed chars.
2837 0 : for (const char *ch = capability; *ch; ++ch)
2838 : {
2839 0 : if (!NS_IS_ALPHA(*ch) && *ch != ' ' && !NS_IS_DIGIT(*ch)
2840 : && *ch != '_' && *ch != '-' && *ch != '.')
2841 : {
2842 : static const char msg[] = "Invalid character in capability name";
2843 0 : SetPendingException(cx, msg);
2844 0 : return NS_ERROR_FAILURE;
2845 : }
2846 : }
2847 :
2848 : nsresult rv;
2849 0 : nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2850 0 : if (NS_FAILED(rv))
2851 0 : return rv;
2852 0 : if (!principal)
2853 0 : return NS_ERROR_NOT_AVAILABLE;
2854 :
2855 0 : void *annotation = JS_GetFrameAnnotation(cx, fp);
2856 : bool enabled;
2857 0 : if (NS_FAILED(principal->IsCapabilityEnabled(capability, annotation,
2858 : &enabled)))
2859 0 : return NS_ERROR_FAILURE;
2860 0 : if (enabled)
2861 0 : return NS_OK;
2862 :
2863 : PRInt16 canEnable;
2864 0 : if (NS_FAILED(RequestCapability(principal, capability, &canEnable)))
2865 0 : return NS_ERROR_FAILURE;
2866 :
2867 0 : if (canEnable != nsIPrincipal::ENABLE_GRANTED)
2868 : {
2869 0 : nsCAutoString val;
2870 : bool hasCert;
2871 : nsresult rv;
2872 0 : principal->GetHasCertificate(&hasCert);
2873 0 : if (hasCert)
2874 0 : rv = principal->GetPrettyName(val);
2875 : else
2876 0 : rv = GetPrincipalDomainOrigin(principal, val);
2877 :
2878 0 : if (NS_FAILED(rv))
2879 0 : return rv;
2880 :
2881 0 : NS_ConvertUTF8toUTF16 location(val);
2882 0 : NS_ConvertUTF8toUTF16 cap(capability);
2883 0 : const PRUnichar *formatStrings[] = { location.get(), cap.get() };
2884 :
2885 0 : nsXPIDLString message;
2886 0 : rv = sStrBundle->FormatStringFromName(NS_LITERAL_STRING("EnableCapabilityDenied").get(),
2887 : formatStrings,
2888 : ArrayLength(formatStrings),
2889 0 : getter_Copies(message));
2890 0 : if (NS_FAILED(rv))
2891 0 : return rv;
2892 :
2893 0 : SetPendingException(cx, message.get());
2894 :
2895 0 : return NS_ERROR_FAILURE; // XXX better error code?
2896 : }
2897 0 : if (NS_FAILED(principal->EnableCapability(capability, &annotation)))
2898 0 : return NS_ERROR_FAILURE;
2899 0 : JS_SetFrameAnnotation(cx, fp, annotation);
2900 0 : return NS_OK;
2901 : }
2902 :
2903 : NS_IMETHODIMP
2904 0 : nsScriptSecurityManager::RevertCapability(const char *capability)
2905 : {
2906 0 : JSContext *cx = GetCurrentJSContext();
2907 : JSStackFrame *fp;
2908 : nsresult rv;
2909 0 : nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2910 0 : if (NS_FAILED(rv))
2911 0 : return rv;
2912 0 : if (!principal)
2913 0 : return NS_ERROR_NOT_AVAILABLE;
2914 0 : void *annotation = JS_GetFrameAnnotation(cx, fp);
2915 0 : principal->RevertCapability(capability, &annotation);
2916 0 : JS_SetFrameAnnotation(cx, fp, annotation);
2917 0 : return NS_OK;
2918 : }
2919 :
2920 : NS_IMETHODIMP
2921 0 : nsScriptSecurityManager::DisableCapability(const char *capability)
2922 : {
2923 0 : JSContext *cx = GetCurrentJSContext();
2924 : JSStackFrame *fp;
2925 : nsresult rv;
2926 0 : nsIPrincipal* principal = GetPrincipalAndFrame(cx, &fp, &rv);
2927 0 : if (NS_FAILED(rv))
2928 0 : return rv;
2929 0 : if (!principal)
2930 0 : return NS_ERROR_NOT_AVAILABLE;
2931 0 : void *annotation = JS_GetFrameAnnotation(cx, fp);
2932 0 : principal->DisableCapability(capability, &annotation);
2933 0 : JS_SetFrameAnnotation(cx, fp, annotation);
2934 0 : return NS_OK;
2935 : }
2936 :
2937 : //////////////// Master Certificate Functions ///////////////////////////////////////
2938 : NS_IMETHODIMP
2939 0 : nsScriptSecurityManager::SetCanEnableCapability(const nsACString& certFingerprint,
2940 : const char* capability,
2941 : PRInt16 canEnable)
2942 : {
2943 0 : NS_ENSURE_ARG(!certFingerprint.IsEmpty());
2944 :
2945 : nsresult rv;
2946 0 : nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv);
2947 0 : if (NS_FAILED(rv))
2948 0 : return rv;
2949 :
2950 : //-- Get the system certificate
2951 0 : if (!mSystemCertificate)
2952 : {
2953 0 : nsCOMPtr<nsIFile> systemCertFile;
2954 : nsCOMPtr<nsIProperties> directoryService =
2955 0 : do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
2956 0 : if (!directoryService) return NS_ERROR_FAILURE;
2957 0 : rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile),
2958 0 : getter_AddRefs(systemCertFile));
2959 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2960 0 : systemCertFile->AppendNative(NS_LITERAL_CSTRING("systemSignature.jar"));
2961 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2962 0 : nsCOMPtr<nsIZipReader> systemCertZip = do_CreateInstance(kZipReaderCID, &rv);
2963 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2964 0 : rv = systemCertZip->Open(systemCertFile);
2965 0 : if (NS_SUCCEEDED(rv))
2966 : {
2967 0 : rv = systemCertZip->GetCertificatePrincipal(EmptyCString(),
2968 0 : getter_AddRefs(mSystemCertificate));
2969 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2970 : }
2971 : }
2972 :
2973 : //-- Make sure the caller's principal is the system certificate
2974 0 : bool isEqual = false;
2975 0 : if (mSystemCertificate)
2976 : {
2977 0 : rv = mSystemCertificate->Equals(subjectPrincipal, &isEqual);
2978 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2979 : }
2980 0 : if (!isEqual)
2981 : {
2982 0 : JSContext* cx = GetCurrentJSContext();
2983 0 : if (!cx) return NS_ERROR_FAILURE;
2984 : static const char msg1[] = "Only code signed by the system certificate may call SetCanEnableCapability or Invalidate";
2985 : static const char msg2[] = "Attempt to call SetCanEnableCapability or Invalidate when no system certificate has been established";
2986 0 : SetPendingException(cx, mSystemCertificate ? msg1 : msg2);
2987 0 : return NS_ERROR_FAILURE;
2988 : }
2989 :
2990 : //-- Get the target principal
2991 0 : nsCOMPtr<nsIPrincipal> objectPrincipal;
2992 0 : rv = DoGetCertificatePrincipal(certFingerprint, EmptyCString(),
2993 0 : EmptyCString(), nsnull,
2994 : nsnull, false,
2995 0 : getter_AddRefs(objectPrincipal));
2996 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2997 0 : rv = objectPrincipal->SetCanEnableCapability(capability, canEnable);
2998 0 : if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
2999 0 : return SavePrincipal(objectPrincipal);
3000 : }
3001 :
3002 : ////////////////////////////////////////////////
3003 : // Methods implementing nsIXPCSecurityManager //
3004 : ////////////////////////////////////////////////
3005 :
3006 : NS_IMETHODIMP
3007 343427 : nsScriptSecurityManager::CanCreateWrapper(JSContext *cx,
3008 : const nsIID &aIID,
3009 : nsISupports *aObj,
3010 : nsIClassInfo *aClassInfo,
3011 : void **aPolicy)
3012 : {
3013 : #ifdef DEBUG_CAPS_CanCreateWrapper
3014 : char* iidStr = aIID.ToString();
3015 : printf("### CanCreateWrapper(%s) ", iidStr);
3016 : NS_Free(iidStr);
3017 : #endif
3018 : // XXX Special case for nsIXPCException ?
3019 686854 : ClassInfoData objClassInfo = ClassInfoData(aClassInfo, nsnull);
3020 343427 : if (objClassInfo.IsDOMClass())
3021 : {
3022 : #ifdef DEBUG_CAPS_CanCreateWrapper
3023 : printf("DOM class - GRANTED.\n");
3024 : #endif
3025 1934 : return NS_OK;
3026 : }
3027 :
3028 : //--See if the object advertises a non-default level of access
3029 : // using nsISecurityCheckedComponent
3030 : nsCOMPtr<nsISecurityCheckedComponent> checkedComponent =
3031 682986 : do_QueryInterface(aObj);
3032 :
3033 682986 : nsXPIDLCString objectSecurityLevel;
3034 341493 : if (checkedComponent)
3035 46803 : checkedComponent->CanCreateWrapper((nsIID *)&aIID, getter_Copies(objectSecurityLevel));
3036 :
3037 341493 : nsresult rv = CheckXPCPermissions(cx, aObj, nsnull, nsnull, objectSecurityLevel);
3038 341493 : if (NS_FAILED(rv))
3039 : {
3040 : //-- Access denied, report an error
3041 0 : NS_ConvertUTF8toUTF16 strName("CreateWrapperDenied");
3042 0 : nsCAutoString origin;
3043 : nsresult rv2;
3044 0 : nsIPrincipal* subjectPrincipal = doGetSubjectPrincipal(&rv2);
3045 0 : if (NS_SUCCEEDED(rv2) && subjectPrincipal) {
3046 0 : GetPrincipalDomainOrigin(subjectPrincipal, origin);
3047 : }
3048 0 : NS_ConvertUTF8toUTF16 originUnicode(origin);
3049 0 : NS_ConvertUTF8toUTF16 className(objClassInfo.GetName());
3050 : const PRUnichar* formatStrings[] = {
3051 0 : className.get(),
3052 0 : originUnicode.get()
3053 0 : };
3054 0 : PRUint32 length = ArrayLength(formatStrings);
3055 0 : if (originUnicode.IsEmpty()) {
3056 0 : --length;
3057 : } else {
3058 0 : strName.AppendLiteral("ForOrigin");
3059 : }
3060 0 : nsXPIDLString errorMsg;
3061 : // We need to keep our existing failure rv and not override it
3062 : // with a likely success code from the following string bundle
3063 : // call in order to throw the correct security exception later.
3064 : rv2 = sStrBundle->FormatStringFromName(strName.get(),
3065 : formatStrings,
3066 : length,
3067 0 : getter_Copies(errorMsg));
3068 0 : NS_ENSURE_SUCCESS(rv2, rv2);
3069 :
3070 0 : SetPendingException(cx, errorMsg.get());
3071 :
3072 : #ifdef DEBUG_CAPS_CanCreateWrapper
3073 : printf("DENIED.\n");
3074 : }
3075 : else
3076 : {
3077 : printf("GRANTED.\n");
3078 : #endif
3079 : }
3080 :
3081 341493 : return rv;
3082 : }
3083 :
3084 : NS_IMETHODIMP
3085 50617 : nsScriptSecurityManager::CanCreateInstance(JSContext *cx,
3086 : const nsCID &aCID)
3087 : {
3088 : #ifdef DEBUG_CAPS_CanCreateInstance
3089 : char* cidStr = aCID.ToString();
3090 : printf("### CanCreateInstance(%s) ", cidStr);
3091 : NS_Free(cidStr);
3092 : #endif
3093 :
3094 50617 : nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
3095 50617 : if (NS_FAILED(rv))
3096 : {
3097 : //-- Access denied, report an error
3098 0 : nsCAutoString errorMsg("Permission denied to create instance of class. CID=");
3099 : char cidStr[NSID_LENGTH];
3100 0 : aCID.ToProvidedString(cidStr);
3101 0 : errorMsg.Append(cidStr);
3102 0 : SetPendingException(cx, errorMsg.get());
3103 :
3104 : #ifdef DEBUG_CAPS_CanCreateInstance
3105 : printf("DENIED\n");
3106 : }
3107 : else
3108 : {
3109 : printf("GRANTED\n");
3110 : #endif
3111 : }
3112 50617 : return rv;
3113 : }
3114 :
3115 : NS_IMETHODIMP
3116 0 : nsScriptSecurityManager::CanGetService(JSContext *cx,
3117 : const nsCID &aCID)
3118 : {
3119 : #ifdef DEBUG_CAPS_CanGetService
3120 : char* cidStr = aCID.ToString();
3121 : printf("### CanGetService(%s) ", cidStr);
3122 : NS_Free(cidStr);
3123 : #endif
3124 :
3125 0 : nsresult rv = CheckXPCPermissions(nsnull, nsnull, nsnull, nsnull, nsnull);
3126 0 : if (NS_FAILED(rv))
3127 : {
3128 : //-- Access denied, report an error
3129 0 : nsCAutoString errorMsg("Permission denied to get service. CID=");
3130 : char cidStr[NSID_LENGTH];
3131 0 : aCID.ToProvidedString(cidStr);
3132 0 : errorMsg.Append(cidStr);
3133 0 : SetPendingException(cx, errorMsg.get());
3134 :
3135 : #ifdef DEBUG_CAPS_CanGetService
3136 : printf("DENIED\n");
3137 : }
3138 : else
3139 : {
3140 : printf("GRANTED\n");
3141 : #endif
3142 : }
3143 :
3144 0 : return rv;
3145 : }
3146 :
3147 :
3148 : NS_IMETHODIMP
3149 1242855 : nsScriptSecurityManager::CanAccess(PRUint32 aAction,
3150 : nsAXPCNativeCallContext* aCallContext,
3151 : JSContext* cx,
3152 : JSObject* aJSObject,
3153 : nsISupports* aObj,
3154 : nsIClassInfo* aClassInfo,
3155 : jsid aPropertyName,
3156 : void** aPolicy)
3157 : {
3158 : return CheckPropertyAccessImpl(aAction, aCallContext, cx,
3159 : aJSObject, aObj, nsnull, aClassInfo,
3160 1242855 : nsnull, aPropertyName, aPolicy);
3161 : }
3162 :
3163 : nsresult
3164 392110 : nsScriptSecurityManager::CheckXPCPermissions(JSContext* cx,
3165 : nsISupports* aObj, JSObject* aJSObject,
3166 : nsIPrincipal* aSubjectPrincipal,
3167 : const char* aObjectSecurityLevel)
3168 : {
3169 : //-- Check for the all-powerful UniversalXPConnect privilege
3170 392110 : bool ok = false;
3171 392110 : if (NS_SUCCEEDED(IsCapabilityEnabled("UniversalXPConnect", &ok)) && ok)
3172 392110 : return NS_OK;
3173 :
3174 : //-- If the object implements nsISecurityCheckedComponent, it has a non-default policy.
3175 0 : if (aObjectSecurityLevel)
3176 : {
3177 0 : if (PL_strcasecmp(aObjectSecurityLevel, "allAccess") == 0)
3178 0 : return NS_OK;
3179 0 : if (cx && PL_strcasecmp(aObjectSecurityLevel, "sameOrigin") == 0)
3180 : {
3181 : nsresult rv;
3182 0 : if (!aJSObject)
3183 : {
3184 : nsCOMPtr<nsIXPConnectWrappedJS> xpcwrappedjs =
3185 0 : do_QueryInterface(aObj);
3186 0 : if (xpcwrappedjs)
3187 : {
3188 0 : rv = xpcwrappedjs->GetJSObject(&aJSObject);
3189 0 : NS_ENSURE_SUCCESS(rv, rv);
3190 : }
3191 : }
3192 :
3193 0 : if (!aSubjectPrincipal)
3194 : {
3195 : // No subject principal passed in. Compute it.
3196 0 : aSubjectPrincipal = GetSubjectPrincipal(cx, &rv);
3197 0 : NS_ENSURE_SUCCESS(rv, rv);
3198 : }
3199 0 : if (aSubjectPrincipal && aJSObject)
3200 : {
3201 0 : nsIPrincipal* objectPrincipal = doGetObjectPrincipal(aJSObject);
3202 :
3203 : // Only do anything if we have both a subject and object
3204 : // principal.
3205 0 : if (objectPrincipal)
3206 : {
3207 : bool subsumes;
3208 0 : rv = aSubjectPrincipal->Subsumes(objectPrincipal, &subsumes);
3209 0 : NS_ENSURE_SUCCESS(rv, rv);
3210 0 : if (subsumes)
3211 0 : return NS_OK;
3212 : }
3213 : }
3214 : }
3215 0 : else if (PL_strcasecmp(aObjectSecurityLevel, "noAccess") != 0)
3216 : {
3217 0 : bool canAccess = false;
3218 0 : if (NS_SUCCEEDED(IsCapabilityEnabled(aObjectSecurityLevel, &canAccess)) &&
3219 : canAccess)
3220 0 : return NS_OK;
3221 : }
3222 : }
3223 :
3224 : //-- Access tests failed
3225 0 : return NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
3226 : }
3227 :
3228 : /////////////////////////////////////////////
3229 : // Method implementing nsIChannelEventSink //
3230 : /////////////////////////////////////////////
3231 : NS_IMETHODIMP
3232 155 : nsScriptSecurityManager::AsyncOnChannelRedirect(nsIChannel* oldChannel,
3233 : nsIChannel* newChannel,
3234 : PRUint32 redirFlags,
3235 : nsIAsyncVerifyRedirectCallback *cb)
3236 : {
3237 310 : nsCOMPtr<nsIPrincipal> oldPrincipal;
3238 155 : GetChannelPrincipal(oldChannel, getter_AddRefs(oldPrincipal));
3239 :
3240 310 : nsCOMPtr<nsIURI> newURI;
3241 155 : newChannel->GetURI(getter_AddRefs(newURI));
3242 310 : nsCOMPtr<nsIURI> newOriginalURI;
3243 155 : newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
3244 :
3245 155 : NS_ENSURE_STATE(oldPrincipal && newURI && newOriginalURI);
3246 :
3247 : const PRUint32 flags =
3248 : nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
3249 155 : nsIScriptSecurityManager::DISALLOW_SCRIPT;
3250 155 : nsresult rv = CheckLoadURIWithPrincipal(oldPrincipal, newURI, flags);
3251 155 : if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
3252 0 : rv = CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
3253 : }
3254 :
3255 155 : if (NS_FAILED(rv))
3256 2 : return rv;
3257 :
3258 153 : cb->OnRedirectVerifyCallback(NS_OK);
3259 153 : return NS_OK;
3260 : }
3261 :
3262 :
3263 : /////////////////////////////////////
3264 : // Method implementing nsIObserver //
3265 : /////////////////////////////////////
3266 : const char sJSEnabledPrefName[] = "javascript.enabled";
3267 : const char sFileOriginPolicyPrefName[] =
3268 : "security.fileuri.strict_origin_policy";
3269 : static const char sPrincipalPrefix[] = "capability.principal";
3270 : static const char sPolicyPrefix[] = "capability.policy.";
3271 :
3272 : static const char* kObservedPrefs[] = {
3273 : sJSEnabledPrefName,
3274 : sFileOriginPolicyPrefName,
3275 : sPolicyPrefix,
3276 : sPrincipalPrefix,
3277 : nsnull
3278 : };
3279 :
3280 :
3281 : NS_IMETHODIMP
3282 154 : nsScriptSecurityManager::Observe(nsISupports* aObject, const char* aTopic,
3283 : const PRUnichar* aMessage)
3284 : {
3285 154 : nsresult rv = NS_OK;
3286 308 : NS_ConvertUTF16toUTF8 messageStr(aMessage);
3287 154 : const char *message = messageStr.get();
3288 :
3289 : static const char jsPrefix[] = "javascript.";
3290 : static const char securityPrefix[] = "security.";
3291 307 : if ((PL_strncmp(message, jsPrefix, sizeof(jsPrefix)-1) == 0) ||
3292 153 : (PL_strncmp(message, securityPrefix, sizeof(securityPrefix)-1) == 0) )
3293 : {
3294 2 : ScriptSecurityPrefChanged();
3295 : }
3296 152 : else if (PL_strncmp(message, sPolicyPrefix, sizeof(sPolicyPrefix)-1) == 0)
3297 : {
3298 : // This will force re-initialization of the pref table
3299 152 : mPolicyPrefsChanged = true;
3300 : }
3301 0 : else if ((PL_strncmp(message, sPrincipalPrefix, sizeof(sPrincipalPrefix)-1) == 0) &&
3302 0 : !mIsWritingPrefs)
3303 : {
3304 : static const char id[] = "id";
3305 0 : char* lastDot = PL_strrchr(message, '.');
3306 : //-- This check makes sure the string copy below doesn't overwrite its bounds
3307 0 : if(PL_strlen(lastDot) >= sizeof(id))
3308 : {
3309 0 : PL_strcpy(lastDot + 1, id);
3310 0 : const char** idPrefArray = (const char**)&message;
3311 0 : rv = InitPrincipals(1, idPrefArray);
3312 : }
3313 : }
3314 154 : return rv;
3315 : }
3316 :
3317 : /////////////////////////////////////////////
3318 : // Constructor, Destructor, Initialization //
3319 : /////////////////////////////////////////////
3320 1404 : nsScriptSecurityManager::nsScriptSecurityManager(void)
3321 : : mOriginToPolicyMap(nsnull),
3322 : mDefaultPolicy(nsnull),
3323 : mCapabilities(nsnull),
3324 : mContextPrincipals(nsnull),
3325 : mPrefInitialized(false),
3326 : mIsJavaScriptEnabled(false),
3327 : mIsWritingPrefs(false),
3328 1404 : mPolicyPrefsChanged(true)
3329 : {
3330 : NS_ASSERTION(sizeof(PRWord) == sizeof(void*),
3331 : "PRWord and void* have different lengths on this platform. "
3332 : "This may cause a security failure with the SecurityLevel union.");
3333 1404 : mPrincipals.Init(31);
3334 1404 : }
3335 :
3336 1404 : nsresult nsScriptSecurityManager::Init()
3337 : {
3338 1404 : nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
3339 1404 : if (!xpconnect)
3340 0 : return NS_ERROR_FAILURE;
3341 :
3342 1404 : NS_ADDREF(sXPConnect = xpconnect);
3343 1404 : NS_ADDREF(sJSContextStack = xpconnect);
3344 :
3345 1404 : JSContext* cx = GetSafeJSContext();
3346 1404 : if (!cx) return NS_ERROR_FAILURE; // this can happen of xpt loading fails
3347 :
3348 1404 : ::JS_BeginRequest(cx);
3349 1404 : if (sEnabledID == JSID_VOID)
3350 1404 : sEnabledID = INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "enabled"));
3351 1404 : ::JS_EndRequest(cx);
3352 :
3353 1404 : InitPrefs();
3354 :
3355 1404 : nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
3356 1404 : NS_ENSURE_SUCCESS(rv, rv);
3357 :
3358 : nsCOMPtr<nsIStringBundleService> bundleService =
3359 2808 : mozilla::services::GetStringBundleService();
3360 1404 : if (!bundleService)
3361 0 : return NS_ERROR_FAILURE;
3362 :
3363 1404 : rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
3364 1404 : NS_ENSURE_SUCCESS(rv, rv);
3365 :
3366 : // Create our system principal singleton
3367 2808 : nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
3368 1404 : NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
3369 :
3370 1404 : mSystemPrincipal = system;
3371 :
3372 : //-- Register security check callback in the JS engine
3373 : // Currently this is used to control access to function.caller
3374 : nsCOMPtr<nsIJSRuntimeService> runtimeService =
3375 2808 : do_QueryInterface(sXPConnect, &rv);
3376 1404 : NS_ENSURE_SUCCESS(rv, rv);
3377 :
3378 1404 : rv = runtimeService->GetRuntime(&sRuntime);
3379 1404 : NS_ENSURE_SUCCESS(rv, rv);
3380 :
3381 : static const JSSecurityCallbacks securityCallbacks = {
3382 : CheckObjectAccess,
3383 : nsJSPrincipals::Subsume,
3384 : nsJSPrincipals::Transcode,
3385 : ObjectPrincipalFinder,
3386 : ContentSecurityPolicyPermitsJSAction
3387 : };
3388 :
3389 1404 : MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
3390 1404 : JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
3391 1404 : JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
3392 :
3393 1404 : JS_SetTrustedPrincipals(sRuntime, system);
3394 :
3395 1404 : return NS_OK;
3396 : }
3397 :
3398 : static nsScriptSecurityManager *gScriptSecMan = nsnull;
3399 :
3400 1464 : jsid nsScriptSecurityManager::sEnabledID = JSID_VOID;
3401 :
3402 4209 : nsScriptSecurityManager::~nsScriptSecurityManager(void)
3403 : {
3404 1403 : Preferences::RemoveObservers(this, kObservedPrefs);
3405 1403 : NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals");
3406 1403 : delete mOriginToPolicyMap;
3407 1403 : if(mDefaultPolicy)
3408 1 : mDefaultPolicy->Drop();
3409 1403 : delete mCapabilities;
3410 1403 : gScriptSecMan = nsnull;
3411 5612 : }
3412 :
3413 : void
3414 1404 : nsScriptSecurityManager::Shutdown()
3415 : {
3416 1404 : if (sRuntime) {
3417 1404 : JS_SetSecurityCallbacks(sRuntime, NULL);
3418 1404 : JS_SetTrustedPrincipals(sRuntime, NULL);
3419 1404 : sRuntime = nsnull;
3420 : }
3421 1404 : sEnabledID = JSID_VOID;
3422 :
3423 1404 : NS_IF_RELEASE(sIOService);
3424 1404 : NS_IF_RELEASE(sXPConnect);
3425 1404 : NS_IF_RELEASE(sJSContextStack);
3426 1404 : NS_IF_RELEASE(sStrBundle);
3427 1404 : }
3428 :
3429 : nsScriptSecurityManager *
3430 406937 : nsScriptSecurityManager::GetScriptSecurityManager()
3431 : {
3432 406937 : if (!gScriptSecMan)
3433 : {
3434 1404 : nsScriptSecurityManager* ssManager = new nsScriptSecurityManager();
3435 1404 : if (!ssManager)
3436 0 : return nsnull;
3437 : nsresult rv;
3438 1404 : rv = ssManager->Init();
3439 1404 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
3440 1404 : if (NS_FAILED(rv)) {
3441 0 : delete ssManager;
3442 0 : return nsnull;
3443 : }
3444 :
3445 : rv = sXPConnect->SetDefaultSecurityManager(ssManager,
3446 1404 : nsIXPCSecurityManager::HOOK_ALL);
3447 1404 : if (NS_FAILED(rv)) {
3448 0 : NS_WARNING("Failed to install xpconnect security manager!");
3449 0 : delete ssManager;
3450 0 : return nsnull;
3451 : }
3452 :
3453 1404 : gScriptSecMan = ssManager;
3454 : }
3455 406937 : return gScriptSecMan;
3456 : }
3457 :
3458 : // Currently this nsGenericFactory constructor is used only from FastLoad
3459 : // (XPCOM object deserialization) code, when "creating" the system principal
3460 : // singleton.
3461 : nsSystemPrincipal *
3462 934 : nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
3463 : {
3464 934 : nsIPrincipal *sysprin = nsnull;
3465 934 : if (gScriptSecMan)
3466 934 : NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
3467 934 : return static_cast<nsSystemPrincipal*>(sysprin);
3468 : }
3469 :
3470 : nsresult
3471 1 : nsScriptSecurityManager::InitPolicies()
3472 : {
3473 : // Clear any policies cached on XPConnect wrappers
3474 1 : NS_ENSURE_STATE(sXPConnect);
3475 1 : nsresult rv = sXPConnect->ClearAllWrappedNativeSecurityPolicies();
3476 1 : if (NS_FAILED(rv)) return rv;
3477 :
3478 : //-- Clear mOriginToPolicyMap: delete mapped DomainEntry items,
3479 : //-- whose dtor decrements refcount of stored DomainPolicy object
3480 1 : delete mOriginToPolicyMap;
3481 :
3482 : //-- Marks all the survivor DomainPolicy objects (those cached
3483 : //-- by nsPrincipal objects) as invalid: they will be released
3484 : //-- on first nsPrincipal::GetSecurityPolicy() attempt.
3485 1 : DomainPolicy::InvalidateAll();
3486 :
3487 : //-- Release old default policy
3488 1 : if(mDefaultPolicy) {
3489 0 : mDefaultPolicy->Drop();
3490 0 : mDefaultPolicy = nsnull;
3491 : }
3492 :
3493 : //-- Initialize a new mOriginToPolicyMap
3494 : mOriginToPolicyMap =
3495 1 : new nsObjectHashtable(nsnull, nsnull, DeleteDomainEntry, nsnull);
3496 1 : if (!mOriginToPolicyMap)
3497 0 : return NS_ERROR_OUT_OF_MEMORY;
3498 :
3499 : //-- Create, refcount and initialize a new default policy
3500 1 : mDefaultPolicy = new DomainPolicy();
3501 1 : if (!mDefaultPolicy)
3502 0 : return NS_ERROR_OUT_OF_MEMORY;
3503 :
3504 1 : mDefaultPolicy->Hold();
3505 1 : if (!mDefaultPolicy->Init())
3506 0 : return NS_ERROR_UNEXPECTED;
3507 :
3508 : //-- Initialize the table of security levels
3509 1 : if (!mCapabilities)
3510 : {
3511 : mCapabilities =
3512 1 : new nsObjectHashtable(nsnull, nsnull, DeleteCapability, nsnull);
3513 1 : if (!mCapabilities)
3514 0 : return NS_ERROR_OUT_OF_MEMORY;
3515 : }
3516 :
3517 : // Get a JS context - we need it to create internalized strings later.
3518 1 : JSContext* cx = GetSafeJSContext();
3519 1 : NS_ASSERTION(cx, "failed to get JS context");
3520 2 : AutoCxPusher autoPusher(sJSContextStack, cx);
3521 1 : rv = InitDomainPolicy(cx, "default", mDefaultPolicy);
3522 1 : NS_ENSURE_SUCCESS(rv, rv);
3523 :
3524 : nsAdoptingCString policyNames =
3525 2 : Preferences::GetCString("capability.policy.policynames");
3526 :
3527 : nsAdoptingCString defaultPolicyNames =
3528 2 : Preferences::GetCString("capability.policy.default_policynames");
3529 1 : policyNames += NS_LITERAL_CSTRING(" ") + defaultPolicyNames;
3530 :
3531 : //-- Initialize domain policies
3532 1 : char* policyCurrent = policyNames.BeginWriting();
3533 1 : bool morePolicies = true;
3534 3 : while (morePolicies)
3535 : {
3536 3 : while(*policyCurrent == ' ' || *policyCurrent == ',')
3537 1 : policyCurrent++;
3538 1 : if (*policyCurrent == '\0')
3539 0 : break;
3540 1 : char* nameBegin = policyCurrent;
3541 :
3542 10 : while(*policyCurrent != '\0' && *policyCurrent != ' ' && *policyCurrent != ',')
3543 8 : policyCurrent++;
3544 :
3545 1 : morePolicies = (*policyCurrent != '\0');
3546 1 : *policyCurrent = '\0';
3547 1 : policyCurrent++;
3548 :
3549 : nsCAutoString sitesPrefName(
3550 1 : NS_LITERAL_CSTRING(sPolicyPrefix) +
3551 2 : nsDependentCString(nameBegin) +
3552 4 : NS_LITERAL_CSTRING(".sites"));
3553 : nsAdoptingCString domainList =
3554 2 : Preferences::GetCString(sitesPrefName.get());
3555 1 : if (!domainList) {
3556 0 : continue;
3557 : }
3558 :
3559 1 : DomainPolicy* domainPolicy = new DomainPolicy();
3560 1 : if (!domainPolicy)
3561 0 : return NS_ERROR_OUT_OF_MEMORY;
3562 :
3563 1 : if (!domainPolicy->Init())
3564 : {
3565 0 : delete domainPolicy;
3566 0 : return NS_ERROR_UNEXPECTED;
3567 : }
3568 1 : domainPolicy->Hold();
3569 : //-- Parse list of sites and create an entry in mOriginToPolicyMap for each
3570 1 : char* domainStart = domainList.BeginWriting();
3571 1 : char* domainCurrent = domainStart;
3572 1 : char* lastDot = nsnull;
3573 1 : char* nextToLastDot = nsnull;
3574 1 : bool moreDomains = true;
3575 23 : while (moreDomains)
3576 : {
3577 21 : if (*domainCurrent == ' ' || *domainCurrent == '\0')
3578 : {
3579 3 : moreDomains = (*domainCurrent != '\0');
3580 3 : *domainCurrent = '\0';
3581 6 : nsCStringKey key(nextToLastDot ? nextToLastDot+1 : domainStart);
3582 3 : DomainEntry *newEntry = new DomainEntry(domainStart, domainPolicy);
3583 3 : if (!newEntry)
3584 : {
3585 0 : domainPolicy->Drop();
3586 0 : return NS_ERROR_OUT_OF_MEMORY;
3587 : }
3588 : #ifdef DEBUG
3589 3 : newEntry->mPolicyName_DEBUG = nameBegin;
3590 : #endif
3591 : DomainEntry *existingEntry = (DomainEntry *)
3592 3 : mOriginToPolicyMap->Get(&key);
3593 3 : if (!existingEntry)
3594 3 : mOriginToPolicyMap->Put(&key, newEntry);
3595 : else
3596 : {
3597 0 : if (existingEntry->Matches(domainStart))
3598 : {
3599 0 : newEntry->mNext = existingEntry;
3600 0 : mOriginToPolicyMap->Put(&key, newEntry);
3601 : }
3602 : else
3603 : {
3604 0 : while (existingEntry->mNext)
3605 : {
3606 0 : if (existingEntry->mNext->Matches(domainStart))
3607 : {
3608 0 : newEntry->mNext = existingEntry->mNext;
3609 0 : existingEntry->mNext = newEntry;
3610 0 : break;
3611 : }
3612 0 : existingEntry = existingEntry->mNext;
3613 : }
3614 0 : if (!existingEntry->mNext)
3615 0 : existingEntry->mNext = newEntry;
3616 : }
3617 : }
3618 3 : domainStart = domainCurrent + 1;
3619 6 : lastDot = nextToLastDot = nsnull;
3620 : }
3621 18 : else if (*domainCurrent == '.')
3622 : {
3623 0 : nextToLastDot = lastDot;
3624 0 : lastDot = domainCurrent;
3625 : }
3626 21 : domainCurrent++;
3627 : }
3628 :
3629 1 : rv = InitDomainPolicy(cx, nameBegin, domainPolicy);
3630 1 : domainPolicy->Drop();
3631 1 : if (NS_FAILED(rv))
3632 0 : return rv;
3633 : }
3634 :
3635 : // Reset the "dirty" flag
3636 1 : mPolicyPrefsChanged = false;
3637 :
3638 : #ifdef DEBUG_CAPS_HACKER
3639 : PrintPolicyDB();
3640 : #endif
3641 1 : return NS_OK;
3642 : }
3643 :
3644 :
3645 : nsresult
3646 2 : nsScriptSecurityManager::InitDomainPolicy(JSContext* cx,
3647 : const char* aPolicyName,
3648 : DomainPolicy* aDomainPolicy)
3649 : {
3650 : nsresult rv;
3651 2 : nsCAutoString policyPrefix(NS_LITERAL_CSTRING(sPolicyPrefix) +
3652 4 : nsDependentCString(aPolicyName) +
3653 8 : NS_LITERAL_CSTRING("."));
3654 2 : PRUint32 prefixLength = policyPrefix.Length() - 1; // subtract the '.'
3655 :
3656 : PRUint32 prefCount;
3657 : char** prefNames;
3658 2 : nsIPrefBranch* branch = Preferences::GetRootBranch();
3659 2 : NS_ASSERTION(branch, "failed to get the root pref branch");
3660 2 : rv = branch->GetChildList(policyPrefix.get(), &prefCount, &prefNames);
3661 2 : if (NS_FAILED(rv)) return rv;
3662 2 : if (prefCount == 0)
3663 0 : return NS_OK;
3664 :
3665 : //-- Populate the policy
3666 2 : PRUint32 currentPref = 0;
3667 153 : for (; currentPref < prefCount; currentPref++)
3668 : {
3669 : // Get the class name
3670 151 : const char* start = prefNames[currentPref] + prefixLength + 1;
3671 151 : char* end = PL_strchr(start, '.');
3672 151 : if (!end) // malformed pref, bail on this one
3673 2 : continue;
3674 : static const char sitesStr[] = "sites";
3675 :
3676 : // We dealt with "sites" in InitPolicies(), so no need to do
3677 : // that again...
3678 149 : if (PL_strncmp(start, sitesStr, sizeof(sitesStr)-1) == 0)
3679 0 : continue;
3680 :
3681 : // Get the pref value
3682 : nsAdoptingCString prefValue =
3683 298 : Preferences::GetCString(prefNames[currentPref]);
3684 149 : if (!prefValue) {
3685 0 : continue;
3686 : }
3687 :
3688 : SecurityLevel secLevel;
3689 149 : if (PL_strcasecmp(prefValue, "noAccess") == 0)
3690 114 : secLevel.level = SCRIPT_SECURITY_NO_ACCESS;
3691 35 : else if (PL_strcasecmp(prefValue, "allAccess") == 0)
3692 27 : secLevel.level = SCRIPT_SECURITY_ALL_ACCESS;
3693 8 : else if (PL_strcasecmp(prefValue, "sameOrigin") == 0)
3694 1 : secLevel.level = SCRIPT_SECURITY_SAME_ORIGIN_ACCESS;
3695 : else
3696 : { //-- pref value is the name of a capability
3697 14 : nsCStringKey secLevelKey(prefValue);
3698 : secLevel.capability =
3699 7 : reinterpret_cast<char*>(mCapabilities->Get(&secLevelKey));
3700 7 : if (!secLevel.capability)
3701 : {
3702 1 : secLevel.capability = NS_strdup(prefValue);
3703 1 : if (!secLevel.capability)
3704 : break;
3705 : mCapabilities->Put(&secLevelKey,
3706 1 : secLevel.capability);
3707 : }
3708 : }
3709 :
3710 149 : *end = '\0';
3711 : // Find or store this class in the classes table
3712 : ClassPolicy* cpolicy =
3713 : static_cast<ClassPolicy*>
3714 : (PL_DHashTableOperate(aDomainPolicy, start,
3715 149 : PL_DHASH_ADD));
3716 149 : if (!cpolicy)
3717 : break;
3718 :
3719 : // If this is the wildcard class (class '*'), save it in mWildcardPolicy
3720 : // (we leave it stored in the hashtable too to take care of the cleanup)
3721 149 : if ((*start == '*') && (end == start + 1)) {
3722 24 : aDomainPolicy->mWildcardPolicy = cpolicy;
3723 :
3724 : // Make sure that cpolicy knows about aDomainPolicy so it can reset
3725 : // the mWildcardPolicy pointer as needed if it gets moved in the
3726 : // hashtable.
3727 24 : cpolicy->mDomainWeAreWildcardFor = aDomainPolicy;
3728 : }
3729 :
3730 : // Get the property name
3731 149 : start = end + 1;
3732 149 : end = PL_strchr(start, '.');
3733 149 : if (end)
3734 42 : *end = '\0';
3735 :
3736 298 : JSAutoRequest ar(cx);
3737 :
3738 149 : JSString* propertyKey = ::JS_InternString(cx, start);
3739 149 : if (!propertyKey)
3740 0 : return NS_ERROR_OUT_OF_MEMORY;
3741 :
3742 : // Store this property in the class policy
3743 : PropertyPolicy* ppolicy =
3744 : static_cast<PropertyPolicy*>
3745 : (PL_DHashTableOperate(cpolicy->mPolicy, propertyKey,
3746 149 : PL_DHASH_ADD));
3747 149 : if (!ppolicy)
3748 : break;
3749 :
3750 149 : if (end) // The pref specifies an access mode
3751 : {
3752 42 : start = end + 1;
3753 42 : if (PL_strcasecmp(start, "set") == 0)
3754 9 : ppolicy->mSet = secLevel;
3755 : else
3756 33 : ppolicy->mGet = secLevel;
3757 : }
3758 : else
3759 : {
3760 107 : if (ppolicy->mGet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3761 107 : ppolicy->mGet = secLevel;
3762 107 : if (ppolicy->mSet.level == SCRIPT_SECURITY_UNDEFINED_ACCESS)
3763 107 : ppolicy->mSet = secLevel;
3764 : }
3765 : }
3766 :
3767 2 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3768 2 : if (currentPref < prefCount) // Loop exited early because of out-of-memory error
3769 0 : return NS_ERROR_OUT_OF_MEMORY;
3770 2 : return NS_OK;
3771 : }
3772 :
3773 :
3774 : // XXXbz We should really just get a prefbranch to handle this...
3775 : nsresult
3776 0 : nsScriptSecurityManager::GetPrincipalPrefNames(const char* prefBase,
3777 : nsCString& grantedPref,
3778 : nsCString& deniedPref,
3779 : nsCString& subjectNamePref)
3780 : {
3781 0 : char* lastDot = PL_strrchr(prefBase, '.');
3782 0 : if (!lastDot) return NS_ERROR_FAILURE;
3783 0 : PRInt32 prefLen = lastDot - prefBase + 1;
3784 :
3785 0 : grantedPref.Assign(prefBase, prefLen);
3786 0 : deniedPref.Assign(prefBase, prefLen);
3787 0 : subjectNamePref.Assign(prefBase, prefLen);
3788 :
3789 : #define GRANTED "granted"
3790 : #define DENIED "denied"
3791 : #define SUBJECTNAME "subjectName"
3792 :
3793 0 : grantedPref.AppendLiteral(GRANTED);
3794 0 : if (grantedPref.Length() != prefLen + sizeof(GRANTED) - 1) {
3795 0 : return NS_ERROR_OUT_OF_MEMORY;
3796 : }
3797 :
3798 0 : deniedPref.AppendLiteral(DENIED);
3799 0 : if (deniedPref.Length() != prefLen + sizeof(DENIED) - 1) {
3800 0 : return NS_ERROR_OUT_OF_MEMORY;
3801 : }
3802 :
3803 0 : subjectNamePref.AppendLiteral(SUBJECTNAME);
3804 0 : if (subjectNamePref.Length() != prefLen + sizeof(SUBJECTNAME) - 1) {
3805 0 : return NS_ERROR_OUT_OF_MEMORY;
3806 : }
3807 :
3808 : #undef SUBJECTNAME
3809 : #undef DENIED
3810 : #undef GRANTED
3811 :
3812 0 : return NS_OK;
3813 : }
3814 :
3815 : nsresult
3816 0 : nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefNames)
3817 : {
3818 : /* This is the principal preference syntax:
3819 : * capability.principal.[codebase|codebaseTrusted|certificate].<name>.[id|granted|denied]
3820 : * For example:
3821 : * user_pref("capability.principal.certificate.p1.id","12:34:AB:CD");
3822 : * user_pref("capability.principal.certificate.p1.granted","Capability1 Capability2");
3823 : * user_pref("capability.principal.certificate.p1.denied","Capability3");
3824 : */
3825 :
3826 : /* codebaseTrusted means a codebase principal that can enable capabilities even if
3827 : * codebase principals are disabled. Don't use trustedCodebase except with unspoofable
3828 : * URLs such as HTTPS URLs.
3829 : */
3830 :
3831 : static const char idSuffix[] = ".id";
3832 0 : for (PRUint32 c = 0; c < aPrefCount; c++)
3833 : {
3834 0 : PRInt32 prefNameLen = PL_strlen(aPrefNames[c]) -
3835 0 : (ArrayLength(idSuffix) - 1);
3836 0 : if (PL_strcasecmp(aPrefNames[c] + prefNameLen, idSuffix) != 0)
3837 0 : continue;
3838 :
3839 0 : nsAdoptingCString id = Preferences::GetCString(aPrefNames[c]);
3840 0 : if (!id) {
3841 0 : return NS_ERROR_FAILURE;
3842 : }
3843 :
3844 0 : nsCAutoString grantedPrefName;
3845 0 : nsCAutoString deniedPrefName;
3846 0 : nsCAutoString subjectNamePrefName;
3847 0 : nsresult rv = GetPrincipalPrefNames(aPrefNames[c],
3848 : grantedPrefName,
3849 : deniedPrefName,
3850 0 : subjectNamePrefName);
3851 0 : if (rv == NS_ERROR_OUT_OF_MEMORY)
3852 0 : return rv;
3853 0 : if (NS_FAILED(rv))
3854 0 : continue;
3855 :
3856 : nsAdoptingCString grantedList =
3857 0 : Preferences::GetCString(grantedPrefName.get());
3858 : nsAdoptingCString deniedList =
3859 0 : Preferences::GetCString(deniedPrefName.get());
3860 : nsAdoptingCString subjectName =
3861 0 : Preferences::GetCString(subjectNamePrefName.get());
3862 :
3863 : //-- Delete prefs if their value is the empty string
3864 0 : if (id.IsEmpty() || (grantedList.IsEmpty() && deniedList.IsEmpty()))
3865 : {
3866 0 : Preferences::ClearUser(aPrefNames[c]);
3867 0 : Preferences::ClearUser(grantedPrefName.get());
3868 0 : Preferences::ClearUser(deniedPrefName.get());
3869 0 : Preferences::ClearUser(subjectNamePrefName.get());
3870 0 : continue;
3871 : }
3872 :
3873 : //-- Create a principal based on the prefs
3874 : static const char certificateName[] = "capability.principal.certificate";
3875 : static const char codebaseName[] = "capability.principal.codebase";
3876 : static const char codebaseTrustedName[] = "capability.principal.codebaseTrusted";
3877 :
3878 0 : bool isCert = false;
3879 0 : bool isTrusted = false;
3880 :
3881 0 : if (PL_strncmp(aPrefNames[c], certificateName,
3882 0 : sizeof(certificateName) - 1) == 0)
3883 : {
3884 0 : isCert = true;
3885 : }
3886 0 : else if (PL_strncmp(aPrefNames[c], codebaseName,
3887 0 : sizeof(codebaseName) - 1) == 0)
3888 : {
3889 0 : isTrusted = (PL_strncmp(aPrefNames[c], codebaseTrustedName,
3890 0 : sizeof(codebaseTrustedName) - 1) == 0);
3891 : }
3892 : else
3893 : {
3894 0 : NS_ERROR("Not a codebase or a certificate?!");
3895 : }
3896 :
3897 0 : nsRefPtr<nsPrincipal> newPrincipal = new nsPrincipal();
3898 0 : if (!newPrincipal)
3899 0 : return NS_ERROR_OUT_OF_MEMORY;
3900 :
3901 0 : rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
3902 0 : EmptyCString(),
3903 : grantedList, deniedList, nsnull,
3904 0 : isCert, isTrusted);
3905 0 : if (NS_SUCCEEDED(rv))
3906 0 : mPrincipals.Put(newPrincipal, newPrincipal);
3907 : }
3908 0 : return NS_OK;
3909 : }
3910 :
3911 : inline void
3912 1406 : nsScriptSecurityManager::ScriptSecurityPrefChanged()
3913 : {
3914 : // JavaScript defaults to enabled in failure cases.
3915 1406 : mIsJavaScriptEnabled = true;
3916 :
3917 1406 : sStrictFileOriginPolicy = true;
3918 :
3919 : nsresult rv;
3920 1406 : if (!mPrefInitialized) {
3921 0 : rv = InitPrefs();
3922 0 : if (NS_FAILED(rv))
3923 0 : return;
3924 : }
3925 :
3926 : mIsJavaScriptEnabled =
3927 1406 : Preferences::GetBool(sJSEnabledPrefName, mIsJavaScriptEnabled);
3928 :
3929 : sStrictFileOriginPolicy =
3930 1406 : Preferences::GetBool(sFileOriginPolicyPrefName, false);
3931 : }
3932 :
3933 : nsresult
3934 1404 : nsScriptSecurityManager::InitPrefs()
3935 : {
3936 : nsresult rv;
3937 1404 : nsIPrefBranch* branch = Preferences::GetRootBranch();
3938 1404 : NS_ENSURE_TRUE(branch, NS_ERROR_FAILURE);
3939 :
3940 1404 : mPrefInitialized = true;
3941 :
3942 : // Set the initial value of the "javascript.enabled" prefs
3943 1404 : ScriptSecurityPrefChanged();
3944 :
3945 : // set observer callbacks in case the value of the prefs change
3946 1404 : Preferences::AddStrongObservers(this, kObservedPrefs);
3947 :
3948 : PRUint32 prefCount;
3949 : char** prefNames;
3950 : //-- Initialize the principals database from prefs
3951 1404 : rv = branch->GetChildList(sPrincipalPrefix, &prefCount, &prefNames);
3952 1404 : if (NS_SUCCEEDED(rv) && prefCount > 0)
3953 : {
3954 0 : rv = InitPrincipals(prefCount, (const char**)prefNames);
3955 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
3956 0 : NS_ENSURE_SUCCESS(rv, rv);
3957 : }
3958 :
3959 1404 : return NS_OK;
3960 4392 : }
3961 :
3962 : ///////////////////////////////////////////////////////////////////////////////
3963 : // The following code prints the contents of the policy DB to the console.
3964 : #ifdef DEBUG_CAPS_HACKER
3965 :
3966 : //typedef PLDHashOperator
3967 : //(* PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
3968 : // PRUint32 number, void *arg);
3969 : static PLDHashOperator
3970 : PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3971 : PRUint32 number, void *arg)
3972 : {
3973 : PropertyPolicy* pp = (PropertyPolicy*)entry;
3974 : nsCAutoString prop(" ");
3975 : JSContext* cx = (JSContext*)arg;
3976 : prop.AppendInt((PRUint32)pp->key);
3977 : prop += ' ';
3978 : prop.AppendWithConversion((PRUnichar*)JS_GetStringChars(pp->key));
3979 : prop += ": Get=";
3980 : if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet))
3981 : prop.AppendInt(pp->mGet.level);
3982 : else
3983 : prop += pp->mGet.capability;
3984 :
3985 : prop += " Set=";
3986 : if (SECURITY_ACCESS_LEVEL_FLAG(pp->mSet))
3987 : prop.AppendInt(pp->mSet.level);
3988 : else
3989 : prop += pp->mSet.capability;
3990 :
3991 : printf("%s.\n", prop.get());
3992 : return PL_DHASH_NEXT;
3993 : }
3994 :
3995 : static PLDHashOperator
3996 : PrintClassPolicy(PLDHashTable *table, PLDHashEntryHdr *entry,
3997 : PRUint32 number, void *arg)
3998 : {
3999 : ClassPolicy* cp = (ClassPolicy*)entry;
4000 : printf(" %s\n", cp->key);
4001 :
4002 : PL_DHashTableEnumerate(cp->mPolicy, PrintPropertyPolicy, arg);
4003 : return PL_DHASH_NEXT;
4004 : }
4005 :
4006 : // typedef bool
4007 : // (* nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure);
4008 : static bool
4009 : PrintDomainPolicy(nsHashKey *aKey, void *aData, void* aClosure)
4010 : {
4011 : DomainEntry* de = (DomainEntry*)aData;
4012 : printf("----------------------------\n");
4013 : printf("Domain: %s Policy Name: %s.\n", de->mOrigin.get(),
4014 : de->mPolicyName_DEBUG.get());
4015 : PL_DHashTableEnumerate(de->mDomainPolicy, PrintClassPolicy, aClosure);
4016 : return true;
4017 : }
4018 :
4019 : static bool
4020 : PrintCapability(nsHashKey *aKey, void *aData, void* aClosure)
4021 : {
4022 : char* cap = (char*)aData;
4023 : printf(" %s.\n", cap);
4024 : return true;
4025 : }
4026 :
4027 : void
4028 : nsScriptSecurityManager::PrintPolicyDB()
4029 : {
4030 : printf("############## Security Policies ###############\n");
4031 : if(mOriginToPolicyMap)
4032 : {
4033 : JSContext* cx = GetCurrentJSContext();
4034 : if (!cx)
4035 : cx = GetSafeJSContext();
4036 : printf("----------------------------\n");
4037 : printf("Domain: Default.\n");
4038 : PL_DHashTableEnumerate(mDefaultPolicy, PrintClassPolicy, (void*)cx);
4039 : mOriginToPolicyMap->Enumerate(PrintDomainPolicy, (void*)cx);
4040 : }
4041 : printf("############ End Security Policies #############\n\n");
4042 : printf("############## Capabilities ###############\n");
4043 : mCapabilities->Enumerate(PrintCapability);
4044 : printf("############## End Capabilities ###############\n");
4045 : }
4046 : #endif
|