1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsJSConfigTriggers.h"
7
8 #include "jsapi.h"
9 #include "nsIXPConnect.h"
10 #include "nsCOMPtr.h"
11 #include "nsString.h"
12 #include "nspr.h"
13 #include "mozilla/Attributes.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/NullPrincipal.h"
16 #include "nsContentUtils.h"
17 #include "nsJSPrincipals.h"
18 #include "nsIScriptError.h"
19 #include "js/Wrapper.h"
20 #include "mozilla/Utf8.h"
21
22 extern mozilla::LazyLogModule MCD;
23 using mozilla::AutoSafeJSContext;
24 using mozilla::IsUtf8;
25 using mozilla::NullPrincipal;
26 using mozilla::dom::AutoJSAPI;
27
28 //*****************************************************************************
29
30 static JS::PersistentRooted<JSObject*> autoconfigSystemSb;
31 static JS::PersistentRooted<JSObject*> autoconfigSb;
32 static bool sandboxEnabled;
33
CentralizedAdminPrefManagerInit(bool aSandboxEnabled)34 nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled) {
35 // If the sandbox is already created, no need to create it again.
36 if (autoconfigSb.initialized()) return NS_OK;
37
38 sandboxEnabled = aSandboxEnabled;
39
40 // Grab XPConnect.
41 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
42
43 // Grab the system principal.
44 nsCOMPtr<nsIPrincipal> principal;
45 nsContentUtils::GetSecurityManager()->GetSystemPrincipal(
46 getter_AddRefs(principal));
47
48 // Create a sandbox.
49 AutoSafeJSContext cx;
50 JS::Rooted<JSObject*> sandbox(cx);
51 nsresult rv = xpc->CreateSandbox(cx, principal, sandbox.address());
52 NS_ENSURE_SUCCESS(rv, rv);
53
54 // Unwrap, store and root the sandbox.
55 NS_ENSURE_STATE(sandbox);
56 autoconfigSystemSb.init(cx, js::UncheckedUnwrap(sandbox));
57
58 // Create an unprivileged sandbox.
59 principal = NullPrincipal::CreateWithoutOriginAttributes();
60 rv = xpc->CreateSandbox(cx, principal, sandbox.address());
61 NS_ENSURE_SUCCESS(rv, rv);
62
63 autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox));
64
65 // Define gSandbox on system sandbox.
66 JSAutoRealm ar(cx, autoconfigSystemSb);
67
68 JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*sandbox));
69
70 if (!JS_WrapValue(cx, &value) ||
71 !JS_DefineProperty(cx, autoconfigSystemSb, "gSandbox", value,
72 JSPROP_ENUMERATE)) {
73 return NS_ERROR_FAILURE;
74 }
75
76 return NS_OK;
77 }
78
CentralizedAdminPrefManagerFinish()79 nsresult CentralizedAdminPrefManagerFinish() {
80 if (autoconfigSb.initialized()) {
81 AutoSafeJSContext cx;
82 autoconfigSb.reset();
83 autoconfigSystemSb.reset();
84 JS_MaybeGC(cx);
85 }
86 return NS_OK;
87 }
88
EvaluateAdminConfigScript(const char * js_buffer,size_t length,const char * filename,bool globalContext,bool callbacks,bool skipFirstLine,bool isPrivileged)89 nsresult EvaluateAdminConfigScript(const char* js_buffer, size_t length,
90 const char* filename, bool globalContext,
91 bool callbacks, bool skipFirstLine,
92 bool isPrivileged) {
93 if (!sandboxEnabled) {
94 isPrivileged = true;
95 }
96 return EvaluateAdminConfigScript(
97 isPrivileged ? autoconfigSystemSb : autoconfigSb, js_buffer, length,
98 filename, globalContext, callbacks, skipFirstLine);
99 }
100
EvaluateAdminConfigScript(JS::HandleObject sandbox,const char * js_buffer,size_t length,const char * filename,bool globalContext,bool callbacks,bool skipFirstLine)101 nsresult EvaluateAdminConfigScript(JS::HandleObject sandbox,
102 const char* js_buffer, size_t length,
103 const char* filename, bool globalContext,
104 bool callbacks, bool skipFirstLine) {
105 if (skipFirstLine) {
106 /* In order to protect the privacy of the JavaScript preferences file
107 * from loading by the browser, we make the first line unparseable
108 * by JavaScript. We must skip that line here before executing
109 * the JavaScript code.
110 */
111 unsigned int i = 0;
112 while (i < length) {
113 char c = js_buffer[i++];
114 if (c == '\r') {
115 if (js_buffer[i] == '\n') i++;
116 break;
117 }
118 if (c == '\n') break;
119 }
120
121 length -= i;
122 js_buffer += i;
123 }
124
125 // Grab XPConnect.
126 nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
127
128 AutoJSAPI jsapi;
129 if (!jsapi.Init(sandbox)) {
130 return NS_ERROR_UNEXPECTED;
131 }
132 JSContext* cx = jsapi.cx();
133
134 nsAutoCString script(js_buffer, length);
135 JS::RootedValue v(cx);
136
137 nsString convertedScript;
138 bool isUTF8 = IsUtf8(script);
139 if (isUTF8) {
140 convertedScript = NS_ConvertUTF8toUTF16(script);
141 } else {
142 nsContentUtils::ReportToConsoleNonLocalized(
143 NS_LITERAL_STRING(
144 "Your AutoConfig file is ASCII. Please convert it to UTF-8."),
145 nsIScriptError::warningFlag, NS_LITERAL_CSTRING("autoconfig"), nullptr);
146 /* If the length is 0, the conversion failed. Fallback to ASCII */
147 convertedScript = NS_ConvertASCIItoUTF16(script);
148 }
149 {
150 JSAutoRealm ar(cx, autoconfigSystemSb);
151 JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8));
152 if (!JS_DefineProperty(cx, autoconfigSystemSb, "gIsUTF8", value,
153 JSPROP_ENUMERATE)) {
154 return NS_ERROR_UNEXPECTED;
155 }
156 }
157 nsresult rv =
158 xpc->EvalInSandboxObject(convertedScript, filename, cx, sandbox, &v);
159 NS_ENSURE_SUCCESS(rv, rv);
160
161 return NS_OK;
162 }
163