michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_LOGGING michael@0: // sorry, this has to be before the pre-compiled header michael@0: #define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: #endif michael@0: #include "nsReadConfig.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsIAppStartup.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsIAutoConfig.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIPrefBranch.h" michael@0: #include "nsIPrefService.h" michael@0: #include "nsIPromptService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIStringBundle.h" michael@0: #include "nsToolkitCompsCID.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsNetUtil.h" michael@0: #include "prmem.h" michael@0: #include "nsString.h" michael@0: #include "nsCRT.h" michael@0: #include "nspr.h" michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: extern PRLogModuleInfo *MCD; michael@0: michael@0: extern nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, michael@0: const char *filename, michael@0: bool bGlobalContext, michael@0: bool bCallbacks, michael@0: bool skipFirstLine); michael@0: extern nsresult CentralizedAdminPrefManagerInit(); michael@0: extern nsresult CentralizedAdminPrefManagerFinish(); michael@0: michael@0: michael@0: static void DisplayError(void) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr promptService = do_GetService("@mozilla.org/embedcomp/prompt-service;1"); michael@0: if (!promptService) michael@0: return; michael@0: michael@0: nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID); michael@0: if (!bundleService) michael@0: return; michael@0: michael@0: nsCOMPtr bundle; michael@0: bundleService->CreateBundle("chrome://autoconfig/locale/autoconfig.properties", michael@0: getter_AddRefs(bundle)); michael@0: if (!bundle) michael@0: return; michael@0: michael@0: nsXPIDLString title; michael@0: rv = bundle->GetStringFromName(MOZ_UTF16("readConfigTitle"), getter_Copies(title)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: nsXPIDLString err; michael@0: rv = bundle->GetStringFromName(MOZ_UTF16("readConfigMsg"), getter_Copies(err)); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: promptService->Alert(nullptr, title.get(), err.get()); michael@0: } michael@0: michael@0: // nsISupports Implementation michael@0: michael@0: NS_IMPL_ISUPPORTS(nsReadConfig, nsIReadConfig, nsIObserver) michael@0: michael@0: nsReadConfig::nsReadConfig() : michael@0: mRead(false) michael@0: { michael@0: if (!MCD) michael@0: MCD = PR_NewLogModule("MCD"); michael@0: } michael@0: michael@0: nsresult nsReadConfig::Init() michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr observerService = michael@0: do_GetService("@mozilla.org/observer-service;1", &rv); michael@0: michael@0: if (observerService) { michael@0: rv = observerService->AddObserver(this, NS_PREFSERVICE_READ_TOPIC_ID, false); michael@0: } michael@0: return(rv); michael@0: } michael@0: michael@0: nsReadConfig::~nsReadConfig() michael@0: { michael@0: CentralizedAdminPrefManagerFinish(); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsReadConfig::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (!nsCRT::strcmp(aTopic, NS_PREFSERVICE_READ_TOPIC_ID)) { michael@0: rv = readConfigFile(); michael@0: if (NS_FAILED(rv)) { michael@0: DisplayError(); michael@0: michael@0: nsCOMPtr appStartup = michael@0: do_GetService(NS_APPSTARTUP_CONTRACTID); michael@0: if (appStartup) michael@0: appStartup->Quit(nsIAppStartup::eAttemptQuit); michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: nsresult nsReadConfig::readConfigFile() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: nsXPIDLCString lockFileName; michael@0: nsXPIDLCString lockVendor; michael@0: uint32_t fileNameLen = 0; michael@0: michael@0: nsCOMPtr defaultPrefBranch; michael@0: nsCOMPtr prefService = michael@0: do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = prefService->GetDefaultBranch(nullptr, getter_AddRefs(defaultPrefBranch)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // This preference is set in the all.js or all-ns.js (depending whether michael@0: // running mozilla or netscp6) michael@0: michael@0: rv = defaultPrefBranch->GetCharPref("general.config.filename", michael@0: getter_Copies(lockFileName)); michael@0: michael@0: michael@0: PR_LOG(MCD, PR_LOG_DEBUG, ("general.config.filename = %s\n", lockFileName.get())); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // This needs to be read only once. michael@0: // michael@0: if (!mRead) { michael@0: // Initiate the new JS Context for Preference management michael@0: michael@0: rv = CentralizedAdminPrefManagerInit(); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Open and evaluate function calls to set/lock/unlock prefs michael@0: rv = openAndEvaluateJSFile("prefcalls.js", 0, false, false); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Evaluate platform specific directives michael@0: rv = openAndEvaluateJSFile("platform.js", 0, false, false); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: mRead = true; michael@0: } michael@0: // If the lockFileName is nullptr return ok, because no lockFile will be used michael@0: michael@0: michael@0: // Once the config file is read, we should check that the vendor name michael@0: // is consistent By checking for the vendor name after reading the config michael@0: // file we allow for the preference to be set (and locked) by the creator michael@0: // of the cfg file meaning the file can not be renamed (successfully). michael@0: michael@0: nsCOMPtr prefBranch; michael@0: rv = prefService->GetBranch(nullptr, getter_AddRefs(prefBranch)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: int32_t obscureValue = 0; michael@0: (void) defaultPrefBranch->GetIntPref("general.config.obscure_value", &obscureValue); michael@0: PR_LOG(MCD, PR_LOG_DEBUG, ("evaluating .cfg file %s with obscureValue %d\n", lockFileName.get(), obscureValue)); michael@0: rv = openAndEvaluateJSFile(lockFileName.get(), obscureValue, true, true); michael@0: if (NS_FAILED(rv)) michael@0: { michael@0: PR_LOG(MCD, PR_LOG_DEBUG, ("error evaluating .cfg file %s %x\n", lockFileName.get(), rv)); michael@0: return rv; michael@0: } michael@0: michael@0: rv = prefBranch->GetCharPref("general.config.filename", michael@0: getter_Copies(lockFileName)); michael@0: if (NS_FAILED(rv)) michael@0: // There is NO REASON we should ever get here. This is POST reading michael@0: // of the config file. michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: michael@0: rv = prefBranch->GetCharPref("general.config.vendor", michael@0: getter_Copies(lockVendor)); michael@0: // If vendor is not nullptr, do this check michael@0: if (NS_SUCCEEDED(rv)) { michael@0: michael@0: fileNameLen = strlen(lockFileName); michael@0: michael@0: // lockVendor and lockFileName should be the same with the addtion of michael@0: // .cfg to the filename by checking this post reading of the cfg file michael@0: // this value can be set within the cfg file adding a level of security. michael@0: michael@0: if (PL_strncmp(lockFileName, lockVendor, fileNameLen - 4) != 0) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // get the value of the autoconfig url michael@0: nsXPIDLCString urlName; michael@0: rv = prefBranch->GetCharPref("autoadmin.global_config_url", michael@0: getter_Copies(urlName)); michael@0: if (NS_SUCCEEDED(rv) && !urlName.IsEmpty()) { michael@0: michael@0: // Instantiating nsAutoConfig object if the pref is present michael@0: mAutoConfig = do_CreateInstance(NS_AUTOCONFIG_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = mAutoConfig->SetConfigURL(urlName); michael@0: if (NS_FAILED(rv)) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: } michael@0: michael@0: return NS_OK; michael@0: } // ReadConfigFile michael@0: michael@0: michael@0: nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obscureValue, michael@0: bool isEncoded, michael@0: bool isBinDir) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr inStr; michael@0: if (isBinDir) { michael@0: nsCOMPtr jsFile; michael@0: rv = NS_GetSpecialDirectory(XRE_EXECUTABLE_FILE, michael@0: getter_AddRefs(jsFile)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = jsFile->SetNativeLeafName(nsDependentCString(aFileName)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: } else { michael@0: nsCOMPtr ioService = do_GetIOService(&rv); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsAutoCString location("resource://gre/defaults/autoconfig/"); michael@0: location += aFileName; michael@0: michael@0: nsCOMPtr uri; michael@0: rv = ioService->NewURI(location, nullptr, nullptr, getter_AddRefs(uri)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr channel; michael@0: rv = ioService->NewChannelFromURI(uri, getter_AddRefs(channel)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = channel->Open(getter_AddRefs(inStr)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: uint64_t fs64; michael@0: uint32_t amt = 0; michael@0: rv = inStr->Available(&fs64); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: // PR_Malloc dones't support over 4GB michael@0: if (fs64 > UINT32_MAX) michael@0: return NS_ERROR_FILE_TOO_BIG; michael@0: uint32_t fs = (uint32_t)fs64; michael@0: michael@0: char *buf = (char *)PR_Malloc(fs * sizeof(char)); michael@0: if (!buf) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = inStr->Read(buf, (uint32_t)fs, &amt); michael@0: NS_ASSERTION((amt == fs), "failed to read the entire configuration file!!"); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (obscureValue > 0) { michael@0: michael@0: // Unobscure file by subtracting some value from every char. michael@0: for (uint32_t i = 0; i < amt; i++) michael@0: buf[i] -= obscureValue; michael@0: } michael@0: rv = EvaluateAdminConfigScript(buf, amt, aFileName, michael@0: false, true, michael@0: isEncoded ? true:false); michael@0: } michael@0: inStr->Close(); michael@0: PR_Free(buf); michael@0: michael@0: return rv; michael@0: }