Source code

Revision control

Other Tools

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 "nsReadConfig.h"
7
#include "nsJSConfigTriggers.h"
8
9
#include "mozilla/Components.h"
10
#include "nsAppDirectoryServiceDefs.h"
11
#include "nsIAppStartup.h"
12
#include "nsContentUtils.h"
13
#include "nsDirectoryServiceDefs.h"
14
#include "nsIFile.h"
15
#include "nsIObserverService.h"
16
#include "nsIPrefBranch.h"
17
#include "nsIPrefService.h"
18
#include "nsIPromptService.h"
19
#include "nsIStringBundle.h"
20
#include "nsNetUtil.h"
21
#include "nsString.h"
22
#include "nsCRT.h"
23
#include "nspr.h"
24
#include "nsXULAppAPI.h"
25
26
using namespace mozilla;
27
28
extern bool sandboxEnabled;
29
30
extern mozilla::LazyLogModule MCD;
31
32
extern nsresult CentralizedAdminPrefManagerInit(bool aSandboxEnabled);
33
extern nsresult CentralizedAdminPrefManagerFinish();
34
35
static nsresult DisplayError(void) {
36
nsresult rv;
37
38
nsCOMPtr<nsIPromptService> promptService =
39
do_GetService("@mozilla.org/embedcomp/prompt-service;1");
40
if (!promptService) return NS_ERROR_FAILURE;
41
42
nsCOMPtr<nsIStringBundleService> bundleService =
43
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
44
if (!bundleService) return NS_ERROR_FAILURE;
45
46
nsCOMPtr<nsIStringBundle> bundle;
47
bundleService->CreateBundle(
49
getter_AddRefs(bundle));
50
if (!bundle) return NS_ERROR_FAILURE;
51
52
nsAutoString title;
53
rv = bundle->GetStringFromName("readConfigTitle", title);
54
if (NS_FAILED(rv)) return rv;
55
56
nsAutoString err;
57
rv = bundle->GetStringFromName("readConfigMsg", err);
58
if (NS_FAILED(rv)) return rv;
59
60
return promptService->Alert(nullptr, title.get(), err.get());
61
}
62
63
// nsISupports Implementation
64
65
NS_IMPL_ISUPPORTS(nsReadConfig, nsIObserver)
66
67
nsReadConfig::nsReadConfig() : mRead(false) {}
68
69
nsresult nsReadConfig::Init() {
70
nsresult rv;
71
72
nsCOMPtr<nsIObserverService> observerService =
73
do_GetService("@mozilla.org/observer-service;1", &rv);
74
75
if (observerService) {
76
rv =
77
observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, false);
78
}
79
return (rv);
80
}
81
82
nsReadConfig::~nsReadConfig() { CentralizedAdminPrefManagerFinish(); }
83
84
NS_IMETHODIMP nsReadConfig::Observe(nsISupports* aSubject, const char* aTopic,
85
const char16_t* someData) {
86
nsresult rv = NS_OK;
87
88
if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) {
89
rv = readConfigFile();
90
// Don't show error alerts if the sandbox is enabled, just show
91
// sandbox warning.
92
if (NS_FAILED(rv)) {
93
if (sandboxEnabled) {
94
nsContentUtils::ReportToConsoleNonLocalized(
95
NS_LITERAL_STRING("Autoconfig is sandboxed by default. See "
97
"firefox-enterprise for more information."),
98
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("autoconfig"),
99
nullptr);
100
} else {
101
rv = DisplayError();
102
if (NS_FAILED(rv)) {
103
nsCOMPtr<nsIAppStartup> appStartup =
104
components::AppStartup::Service();
105
if (appStartup) appStartup->Quit(nsIAppStartup::eAttemptQuit);
106
}
107
}
108
}
109
}
110
return rv;
111
}
112
113
/**
114
* This is the blocklist for known bad autoconfig files.
115
*/
116
static const char* gBlockedConfigs[] = {"dsengine.cfg"};
117
118
nsresult nsReadConfig::readConfigFile() {
119
nsresult rv = NS_OK;
120
nsAutoCString lockFileName;
121
nsAutoCString lockVendor;
122
uint32_t fileNameLen = 0;
123
124
nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
125
nsCOMPtr<nsIPrefService> prefService =
126
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
127
if (NS_FAILED(rv)) return rv;
128
129
rv =
130
prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch));
131
if (NS_FAILED(rv)) return rv;
132
133
NS_NAMED_LITERAL_CSTRING(channel, MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
134
135
bool sandboxEnabled =
136
channel.EqualsLiteral("beta") || channel.EqualsLiteral("release");
137
138
mozilla::Unused << defaultPrefBranch->GetBoolPref(
139
"general.config.sandbox_enabled", &sandboxEnabled);
140
141
rv = defaultPrefBranch->GetCharPref("general.config.filename", lockFileName);
142
143
if (NS_FAILED(rv)) return rv;
144
145
MOZ_LOG(MCD, LogLevel::Debug,
146
("general.config.filename = %s\n", lockFileName.get()));
147
148
for (size_t index = 0, len = mozilla::ArrayLength(gBlockedConfigs);
149
index < len; ++index) {
150
if (lockFileName == gBlockedConfigs[index]) {
151
// This is NS_OK because we don't want to show an error to the user
152
return rv;
153
}
154
}
155
156
// This needs to be read only once.
157
//
158
if (!mRead) {
159
// Initiate the new JS Context for Preference management
160
161
rv = CentralizedAdminPrefManagerInit(sandboxEnabled);
162
if (NS_FAILED(rv)) return rv;
163
164
// Open and evaluate function calls to set/lock/unlock prefs
165
rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false);
166
if (NS_FAILED(rv)) return rv;
167
168
mRead = true;
169
}
170
// If the lockFileName is nullptr return ok, because no lockFile will be used
171
172
// Once the config file is read, we should check that the vendor name
173
// is consistent By checking for the vendor name after reading the config
174
// file we allow for the preference to be set (and locked) by the creator
175
// of the cfg file meaning the file can not be renamed (successfully).
176
177
nsCOMPtr<nsIPrefBranch> prefBranch;
178
rv = prefService->GetBranch(nullptr, getter_AddRefs(prefBranch));
179
NS_ENSURE_SUCCESS(rv, rv);
180
181
int32_t obscureValue = 0;
182
(void)defaultPrefBranch->GetIntPref("general.config.obscure_value",
183
&obscureValue);
184
MOZ_LOG(MCD, LogLevel::Debug,
185
("evaluating .cfg file %s with obscureValue %d\n", lockFileName.get(),
186
obscureValue));
187
rv = openAndEvaluateJSFile(lockFileName.get(), obscureValue, true, true);
188
if (NS_FAILED(rv)) {
189
MOZ_LOG(MCD, LogLevel::Debug,
190
("error evaluating .cfg file %s %" PRIx32 "\n", lockFileName.get(),
191
static_cast<uint32_t>(rv)));
192
return rv;
193
}
194
195
rv = prefBranch->GetCharPref("general.config.filename", lockFileName);
196
if (NS_FAILED(rv))
197
// There is NO REASON we should ever get here. This is POST reading
198
// of the config file.
199
return NS_ERROR_FAILURE;
200
201
rv = prefBranch->GetCharPref("general.config.vendor", lockVendor);
202
// If vendor is not nullptr, do this check
203
if (NS_SUCCEEDED(rv)) {
204
fileNameLen = strlen(lockFileName.get());
205
206
// lockVendor and lockFileName should be the same with the addtion of
207
// .cfg to the filename by checking this post reading of the cfg file
208
// this value can be set within the cfg file adding a level of security.
209
210
if (PL_strncmp(lockFileName.get(), lockVendor.get(), fileNameLen - 4) != 0)
211
return NS_ERROR_FAILURE;
212
}
213
214
// get the value of the autoconfig url
215
nsAutoCString urlName;
216
rv = prefBranch->GetCharPref("autoadmin.global_config_url", urlName);
217
if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) {
218
// Instantiating nsAutoConfig object if the pref is present
219
mAutoConfig = new nsAutoConfig();
220
221
rv = mAutoConfig->Init();
222
if (NS_WARN_IF(NS_FAILED(rv))) {
223
return rv;
224
}
225
226
mAutoConfig->SetConfigURL(urlName.get());
227
}
228
229
return NS_OK;
230
} // ReadConfigFile
231
232
nsresult nsReadConfig::openAndEvaluateJSFile(const char* aFileName,
233
int32_t obscureValue,
234
bool isEncoded, bool isBinDir) {
235
nsresult rv;
236
237
nsCOMPtr<nsIInputStream> inStr;
238
if (isBinDir) {
239
nsCOMPtr<nsIFile> jsFile;
240
rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(jsFile));
241
if (NS_FAILED(rv)) return rv;
242
243
rv = jsFile->AppendNative(nsDependentCString(aFileName));
244
if (NS_FAILED(rv)) return rv;
245
246
rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
247
if (NS_FAILED(rv)) return rv;
248
249
} else {
250
nsAutoCString location("resource://gre/defaults/autoconfig/");
251
location += aFileName;
252
253
nsCOMPtr<nsIURI> uri;
254
rv = NS_NewURI(getter_AddRefs(uri), location);
255
NS_ENSURE_SUCCESS(rv, rv);
256
257
nsCOMPtr<nsIChannel> channel;
258
rv = NS_NewChannel(getter_AddRefs(channel), uri,
259
nsContentUtils::GetSystemPrincipal(),
260
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
261
nsIContentPolicy::TYPE_OTHER);
262
NS_ENSURE_SUCCESS(rv, rv);
263
264
rv = channel->Open(getter_AddRefs(inStr));
265
NS_ENSURE_SUCCESS(rv, rv);
266
}
267
268
uint64_t fs64;
269
uint32_t amt = 0;
270
rv = inStr->Available(&fs64);
271
if (NS_FAILED(rv)) return rv;
272
// This used to use PR_Malloc(), which doesn't support over 4GB.
273
if (fs64 > UINT32_MAX) return NS_ERROR_FILE_TOO_BIG;
274
uint32_t fs = (uint32_t)fs64;
275
276
char* buf = (char*)malloc(fs * sizeof(char));
277
if (!buf) return NS_ERROR_OUT_OF_MEMORY;
278
279
rv = inStr->Read(buf, (uint32_t)fs, &amt);
280
NS_ASSERTION((amt == fs), "failed to read the entire configuration file!!");
281
if (NS_SUCCEEDED(rv)) {
282
if (obscureValue > 0) {
283
// Unobscure file by subtracting some value from every char.
284
for (uint32_t i = 0; i < amt; i++) buf[i] -= obscureValue;
285
}
286
rv = EvaluateAdminConfigScript(buf, amt, aFileName, false, true, isEncoded,
287
!isBinDir);
288
}
289
inStr->Close();
290
free(buf);
291
292
return rv;
293
}