|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
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 #ifdef MOZ_LOGGING |
|
7 // sorry, this has to be before the pre-compiled header |
|
8 #define FORCE_PR_LOG /* Allow logging in the release build */ |
|
9 #endif |
|
10 #include "nsReadConfig.h" |
|
11 #include "nsAppDirectoryServiceDefs.h" |
|
12 #include "nsIAppStartup.h" |
|
13 #include "nsDirectoryServiceDefs.h" |
|
14 #include "nsIAutoConfig.h" |
|
15 #include "nsIComponentManager.h" |
|
16 #include "nsIFile.h" |
|
17 #include "nsIObserverService.h" |
|
18 #include "nsIPrefBranch.h" |
|
19 #include "nsIPrefService.h" |
|
20 #include "nsIPromptService.h" |
|
21 #include "nsIServiceManager.h" |
|
22 #include "nsIStringBundle.h" |
|
23 #include "nsToolkitCompsCID.h" |
|
24 #include "nsXPIDLString.h" |
|
25 #include "nsNetUtil.h" |
|
26 #include "prmem.h" |
|
27 #include "nsString.h" |
|
28 #include "nsCRT.h" |
|
29 #include "nspr.h" |
|
30 #include "nsXULAppAPI.h" |
|
31 |
|
32 extern PRLogModuleInfo *MCD; |
|
33 |
|
34 extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, |
|
35 const char *filename, |
|
36 bool bGlobalContext, |
|
37 bool bCallbacks, |
|
38 bool skipFirstLine); |
|
39 extern nsresult CentralizedAdminPrefManagerInit(); |
|
40 extern nsresult CentralizedAdminPrefManagerFinish(); |
|
41 |
|
42 |
|
43 static void DisplayError(void) |
|
44 { |
|
45 nsresult rv; |
|
46 |
|
47 nsCOMPtr<nsIPromptService> promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1"); |
|
48 if (!promptService) |
|
49 return; |
|
50 |
|
51 nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID); |
|
52 if (!bundleService) |
|
53 return; |
|
54 |
|
55 nsCOMPtr<nsIStringBundle> bundle; |
|
56 bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", |
|
57 getter_AddRefs(bundle)); |
|
58 if (!bundle) |
|
59 return; |
|
60 |
|
61 nsXPIDLString title; |
|
62 rv = bundle->GetStringFromName(MOZ_UTF16("readConfigTitle"), getter_Copies(title)); |
|
63 if (NS_FAILED(rv)) |
|
64 return; |
|
65 |
|
66 nsXPIDLString err; |
|
67 rv = bundle->GetStringFromName(MOZ_UTF16("readConfigMsg"), getter_Copies(err)); |
|
68 if (NS_FAILED(rv)) |
|
69 return; |
|
70 |
|
71 promptService->Alert(nullptr, title.get(), err.get()); |
|
72 } |
|
73 |
|
74 // nsISupports Implementation |
|
75 |
|
76 NS_IMPL_ISUPPORTS(nsReadConfig, nsIReadConfig, nsIObserver) |
|
77 |
|
78 nsReadConfig::nsReadConfig() : |
|
79 mRead(false) |
|
80 { |
|
81 if (!MCD) |
|
82 MCD = PR_NewLogModule("MCD"); |
|
83 } |
|
84 |
|
85 nsresult nsReadConfig::Init() |
|
86 { |
|
87 nsresult rv; |
|
88 |
|
89 nsCOMPtr<nsIObserverService> observerService = |
|
90 do_GetService("@mozilla.org/observer-service;1", &rv); |
|
91 |
|
92 if (observerService) { |
|
93 rv = observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, false); |
|
94 } |
|
95 return(rv); |
|
96 } |
|
97 |
|
98 nsReadConfig::~nsReadConfig() |
|
99 { |
|
100 CentralizedAdminPrefManagerFinish(); |
|
101 } |
|
102 |
|
103 NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) |
|
104 { |
|
105 nsresult rv = NS_OK; |
|
106 |
|
107 if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) { |
|
108 rv = readConfigFile(); |
|
109 if (NS_FAILED(rv)) { |
|
110 DisplayError(); |
|
111 |
|
112 nsCOMPtr<nsIAppStartup> appStartup = |
|
113 do_GetService(NS_APPSTARTUP_CONTRACTID); |
|
114 if (appStartup) |
|
115 appStartup->Quit(nsIAppStartup::eAttemptQuit); |
|
116 } |
|
117 } |
|
118 return rv; |
|
119 } |
|
120 |
|
121 |
|
122 nsresult nsReadConfig::readConfigFile() |
|
123 { |
|
124 nsresult rv = NS_OK; |
|
125 nsXPIDLCString lockFileName; |
|
126 nsXPIDLCString lockVendor; |
|
127 uint32_t fileNameLen = 0; |
|
128 |
|
129 nsCOMPtr<nsIPrefBranch> defaultPrefBranch; |
|
130 nsCOMPtr<nsIPrefService> prefService = |
|
131 do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); |
|
132 if (NS_FAILED(rv)) |
|
133 return rv; |
|
134 |
|
135 rv = prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); |
|
136 if (NS_FAILED(rv)) |
|
137 return rv; |
|
138 |
|
139 // This preference is set in the all.js or all-ns.js (depending whether |
|
140 // running mozilla or netscp6) |
|
141 |
|
142 rv = defaultPrefBranch->GetCharPref("general.config.filename", |
|
143 getter_Copies(lockFileName)); |
|
144 |
|
145 |
|
146 PR_LOG(MCD, PR_LOG_DEBUG, ("general.config.filename = %s\n", lockFileName.get())); |
|
147 if (NS_FAILED(rv)) |
|
148 return rv; |
|
149 |
|
150 // This needs to be read only once. |
|
151 // |
|
152 if (!mRead) { |
|
153 // Initiate the new JS Context for Preference management |
|
154 |
|
155 rv = CentralizedAdminPrefManagerInit(); |
|
156 if (NS_FAILED(rv)) |
|
157 return rv; |
|
158 |
|
159 // Open and evaluate function calls to set/lock/unlock prefs |
|
160 rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false); |
|
161 if (NS_FAILED(rv)) |
|
162 return rv; |
|
163 |
|
164 // Evaluate platform specific directives |
|
165 rv = openAndEvaluateJSFile("platform.js", 0, false, false); |
|
166 if (NS_FAILED(rv)) |
|
167 return rv; |
|
168 |
|
169 mRead = true; |
|
170 } |
|
171 // If the lockFileName is nullptr return ok, because no lockFile will be used |
|
172 |
|
173 |
|
174 // Once the config file is read, we should check that the vendor name |
|
175 // is consistent By checking for the vendor name after reading the config |
|
176 // file we allow for the preference to be set (and locked) by the creator |
|
177 // of the cfg file meaning the file can not be renamed (successfully). |
|
178 |
|
179 nsCOMPtr<nsIPrefBranch> prefBranch; |
|
180 rv = prefService->GetBranch(nullptr, getter_AddRefs(prefBranch)); |
|
181 NS_ENSURE_SUCCESS(rv, rv); |
|
182 |
|
183 int32_t obscureValue = 0; |
|
184 (void) defaultPrefBranch->GetIntPref("general.config.obscure_value", &obscureValue); |
|
185 PR_LOG(MCD, PR_LOG_DEBUG, ("evaluating .cfg file %s with obscureValue %d\n", lockFileName.get(), obscureValue)); |
|
186 rv = openAndEvaluateJSFile(lockFileName.get(), obscureValue, true, true); |
|
187 if (NS_FAILED(rv)) |
|
188 { |
|
189 PR_LOG(MCD, PR_LOG_DEBUG, ("error evaluating .cfg file %s %x\n", lockFileName.get(), rv)); |
|
190 return rv; |
|
191 } |
|
192 |
|
193 rv = prefBranch->GetCharPref("general.config.filename", |
|
194 getter_Copies(lockFileName)); |
|
195 if (NS_FAILED(rv)) |
|
196 // There is NO REASON we should ever get here. This is POST reading |
|
197 // of the config file. |
|
198 return NS_ERROR_FAILURE; |
|
199 |
|
200 |
|
201 rv = prefBranch->GetCharPref("general.config.vendor", |
|
202 getter_Copies(lockVendor)); |
|
203 // If vendor is not nullptr, do this check |
|
204 if (NS_SUCCEEDED(rv)) { |
|
205 |
|
206 fileNameLen = strlen(lockFileName); |
|
207 |
|
208 // lockVendor and lockFileName should be the same with the addtion of |
|
209 // .cfg to the filename by checking this post reading of the cfg file |
|
210 // this value can be set within the cfg file adding a level of security. |
|
211 |
|
212 if (PL_strncmp(lockFileName, lockVendor, fileNameLen - 4) != 0) |
|
213 return NS_ERROR_FAILURE; |
|
214 } |
|
215 |
|
216 // get the value of the autoconfig url |
|
217 nsXPIDLCString urlName; |
|
218 rv = prefBranch->GetCharPref("autoadmin.global_config_url", |
|
219 getter_Copies(urlName)); |
|
220 if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) { |
|
221 |
|
222 // Instantiating nsAutoConfig object if the pref is present |
|
223 mAutoConfig = do_CreateInstance(NS_AUTOCONFIG_CONTRACTID, &rv); |
|
224 if (NS_FAILED(rv)) |
|
225 return NS_ERROR_OUT_OF_MEMORY; |
|
226 |
|
227 rv = mAutoConfig->SetConfigURL(urlName); |
|
228 if (NS_FAILED(rv)) |
|
229 return NS_ERROR_FAILURE; |
|
230 |
|
231 } |
|
232 |
|
233 return NS_OK; |
|
234 } // ReadConfigFile |
|
235 |
|
236 |
|
237 nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue, |
|
238 bool isEncoded, |
|
239 bool isBinDir) |
|
240 { |
|
241 nsresult rv; |
|
242 |
|
243 nsCOMPtr<nsIInputStream> inStr; |
|
244 if (isBinDir) { |
|
245 nsCOMPtr<nsIFile> jsFile; |
|
246 rv = NS_GetSpecialDirectory(XRE_EXECUTABLE_FILE, |
|
247 getter_AddRefs(jsFile)); |
|
248 if (NS_FAILED(rv)) |
|
249 return rv; |
|
250 |
|
251 rv = jsFile->SetNativeLeafName(nsDependentCString(aFileName)); |
|
252 if (NS_FAILED(rv)) |
|
253 return rv; |
|
254 |
|
255 rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile); |
|
256 if (NS_FAILED(rv)) |
|
257 return rv; |
|
258 |
|
259 } else { |
|
260 nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv); |
|
261 if (NS_FAILED(rv)) |
|
262 return rv; |
|
263 |
|
264 nsAutoCString location("resource://gre/defaults/autoconfig/"); |
|
265 location += aFileName; |
|
266 |
|
267 nsCOMPtr<nsIURI> uri; |
|
268 rv = ioService->NewURI(location, nullptr, nullptr, getter_AddRefs(uri)); |
|
269 if (NS_FAILED(rv)) |
|
270 return rv; |
|
271 |
|
272 nsCOMPtr<nsIChannel> channel; |
|
273 rv = ioService->NewChannelFromURI(uri, getter_AddRefs(channel)); |
|
274 if (NS_FAILED(rv)) |
|
275 return rv; |
|
276 |
|
277 rv = channel->Open(getter_AddRefs(inStr)); |
|
278 if (NS_FAILED(rv)) |
|
279 return rv; |
|
280 } |
|
281 |
|
282 uint64_t fs64; |
|
283 uint32_t amt = 0; |
|
284 rv = inStr->Available(&fs64); |
|
285 if (NS_FAILED(rv)) |
|
286 return rv; |
|
287 // PR_Malloc dones't support over 4GB |
|
288 if (fs64 > UINT32_MAX) |
|
289 return NS_ERROR_FILE_TOO_BIG; |
|
290 uint32_t fs = (uint32_t)fs64; |
|
291 |
|
292 char *buf = (char *)PR_Malloc(fs * sizeof(char)); |
|
293 if (!buf) |
|
294 return NS_ERROR_OUT_OF_MEMORY; |
|
295 |
|
296 rv = inStr->Read(buf, (uint32_t)fs, &amt); |
|
297 NS_ASSERTION((amt == fs), "failed to read the entire configuration file!!"); |
|
298 if (NS_SUCCEEDED(rv)) { |
|
299 if (obscureValue > 0) { |
|
300 |
|
301 // Unobscure file by subtracting some value from every char. |
|
302 for (uint32_t i = 0; i < amt; i++) |
|
303 buf[i] -= obscureValue; |
|
304 } |
|
305 rv = EvaluateAdminConfigScript(buf, amt, aFileName, |
|
306 false, true, |
|
307 isEncoded ? true:false); |
|
308 } |
|
309 inStr->Close(); |
|
310 PR_Free(buf); |
|
311 |
|
312 return rv; |
|
313 } |