diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/mozapps/defaultagent/Policy.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | toolkit/mozapps/defaultagent/Policy.cpp | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/toolkit/mozapps/defaultagent/Policy.cpp b/toolkit/mozapps/defaultagent/Policy.cpp new file mode 100644 index 0000000000..56d868866b --- /dev/null +++ b/toolkit/mozapps/defaultagent/Policy.cpp @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Policy.h" + +#include <windows.h> +#include <shlwapi.h> +#include <fstream> + +#include "common.h" +#include "Registry.h" +#include "UtfConvert.h" + +#include "json/json.h" +#include "mozilla/HelperMacros.h" +#include "mozilla/Maybe.h" +#include "mozilla/WinHeaderOnlyUtils.h" + +// There is little logging or error handling in this file, because the file and +// registry values we are reading here are normally absent, so never finding +// anything that we look for at all would not be an error worth generating an +// event log for. + +#define AGENT_POLICY_NAME "DisableDefaultBrowserAgent" +#define TELEMETRY_POLICY_NAME "DisableTelemetry" + +// The Firefox policy engine hardcodes the string "Mozilla" in its registry +// key accesses rather than using the configured vendor name, so we should do +// the same here to be sure we're compatible with it. +#define POLICY_REGKEY_NAME L"SOFTWARE\\Policies\\Mozilla\\" MOZ_APP_BASENAME + +// This enum is the return type for the functions that check policy values. +enum class PolicyState { + Enabled, // There is a policy explicitly set to enabled + Disabled, // There is a policy explicitly set to disabled + NoPolicy, // This policy isn't configured +}; + +static PolicyState FindPolicyInRegistry(HKEY rootKey, + const wchar_t* policyName) { + HKEY rawRegKey = nullptr; + RegOpenKeyExW(rootKey, POLICY_REGKEY_NAME, 0, KEY_READ, &rawRegKey); + + nsAutoRegKey regKey(rawRegKey); + + if (!regKey) { + return PolicyState::NoPolicy; + } + + // If this key is empty and doesn't have any actual policies in it, + // treat that the same as the key not existing and return no result. + DWORD numSubKeys = 0, numValues = 0; + LSTATUS ls = RegQueryInfoKeyW(regKey.get(), nullptr, nullptr, nullptr, + &numSubKeys, nullptr, nullptr, &numValues, + nullptr, nullptr, nullptr, nullptr); + if (ls != ERROR_SUCCESS) { + return PolicyState::NoPolicy; + } + + DWORD policyValue = UINT32_MAX; + DWORD policyValueSize = sizeof(policyValue); + ls = RegGetValueW(regKey.get(), nullptr, policyName, RRF_RT_REG_DWORD, + nullptr, &policyValue, &policyValueSize); + + if (ls != ERROR_SUCCESS) { + return PolicyState::NoPolicy; + } + return policyValue == 0 ? PolicyState::Disabled : PolicyState::Enabled; +} + +static PolicyState FindPolicyInFile(const char* policyName) { + mozilla::UniquePtr<wchar_t[]> thisBinaryPath = mozilla::GetFullBinaryPath(); + if (!PathRemoveFileSpecW(thisBinaryPath.get())) { + return PolicyState::NoPolicy; + } + + wchar_t policiesFilePath[MAX_PATH] = L""; + if (!PathCombineW(policiesFilePath, thisBinaryPath.get(), L"distribution")) { + return PolicyState::NoPolicy; + } + + if (!PathAppendW(policiesFilePath, L"policies.json")) { + return PolicyState::NoPolicy; + } + + // We need a narrow string-based std::ifstream because that's all jsoncpp can + // use; that means we need to supply it the file path as a narrow string. + Utf16ToUtf8Result policiesFilePathToUtf8 = Utf16ToUtf8(policiesFilePath); + if (policiesFilePathToUtf8.isErr()) { + return PolicyState::NoPolicy; + } + std::string policiesFilePathA = policiesFilePathToUtf8.unwrap(); + + Json::Value jsonRoot; + std::ifstream stream(policiesFilePathA); + Json::Reader().parse(stream, jsonRoot); + + if (jsonRoot.isObject() && jsonRoot.isMember("Policies") && + jsonRoot["Policies"].isObject()) { + if (jsonRoot["Policies"].isMember(policyName) && + jsonRoot["Policies"][policyName].isBool()) { + return jsonRoot["Policies"][policyName].asBool() ? PolicyState::Enabled + : PolicyState::Disabled; + } else { + return PolicyState::NoPolicy; + } + } + + return PolicyState::NoPolicy; +} + +static PolicyState IsDisabledByPref(const wchar_t* prefRegValue) { + auto prefValueResult = + RegistryGetValueBool(IsPrefixed::Prefixed, prefRegValue); + + if (prefValueResult.isErr()) { + return PolicyState::NoPolicy; + } + auto prefValue = prefValueResult.unwrap(); + if (prefValue.isNothing()) { + return PolicyState::NoPolicy; + } + return prefValue.value() ? PolicyState::Enabled : PolicyState::Disabled; +} + +// Everything we call from this function wants wide strings, except for jsoncpp, +// which cannot work with them at all, so at some point we need both formats. +// It's awkward to take both formats as individual arguments, but it would be +// more awkward to take one and runtime convert it to the other, or to turn +// this function into a macro so that the preprocessor can trigger the +// conversion for us, so this is what we've got. +static bool IsThingDisabled(const char* thing, const wchar_t* wideThing) { + // The logic here is intended to be the same as that used by Firefox's policy + // engine implementation; they should be kept in sync. We have added the pref + // check at the end though, since that's our own custom mechanism. + PolicyState state = FindPolicyInRegistry(HKEY_LOCAL_MACHINE, wideThing); + if (state == PolicyState::NoPolicy) { + state = FindPolicyInRegistry(HKEY_CURRENT_USER, wideThing); + } + if (state == PolicyState::NoPolicy) { + state = FindPolicyInFile(thing); + } + if (state == PolicyState::NoPolicy) { + state = IsDisabledByPref(wideThing); + } + return state == PolicyState::Enabled ? true : false; +} + +bool IsAgentDisabled() { + return IsThingDisabled(AGENT_POLICY_NAME, L"" AGENT_POLICY_NAME); +} + +bool IsTelemetryDisabled() { + return IsThingDisabled(TELEMETRY_POLICY_NAME, L"" TELEMETRY_POLICY_NAME); +} |