tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsReadConfig.cpp (10037B)


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