Source code

Revision control

Copy as Markdown

Other Tools

/* 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 "EnterprisePolicies.h"
#include <filesystem>
#include <format>
#include <fstream>
#include <string_view>
#include <string>
#include <Windows.h>
#include <json/json.h>
namespace fs = std::filesystem;
namespace {
static fs::path GetDistributionPoliciesFilePath(const fs::path& aDir) noexcept {
const fs::path kRelativeFilePath{"distribution/policies.json"};
return aDir / kRelativeFilePath;
}
static bool EnterprisePoliciesInRegistry(HKEY aHive, std::wstring_view aBrand) {
std::wstring keyPath{std::format(LR"(SOFTWARE\Policies\Mozilla\{})", aBrand)};
HKEY key{};
if (RegOpenKeyExW(aHive, keyPath.c_str(), 0, KEY_READ, &key) !=
ERROR_SUCCESS) {
return false;
}
DWORD numSubkeys{0};
DWORD numValues{0};
LONG rv{RegQueryInfoKeyW(key, nullptr, nullptr, nullptr, &numSubkeys, nullptr,
nullptr, &numValues, nullptr, nullptr, nullptr,
nullptr)};
if (rv != ERROR_SUCCESS) {
RegCloseKey(key);
return false;
}
// If there is any value, it's enterprise managed
if (numValues > 0) {
RegCloseKey(key);
return true;
}
// If there are no subkeys, it's not enterprise managed
if (numSubkeys == 0) {
RegCloseKey(key);
return false;
}
// If there's more than one subkey, it's enterprise managed
if (numSubkeys > 1) {
RegCloseKey(key);
return true;
}
// If the only subkey isn't Certificates, it's enterprise managed
wchar_t subkeyName[MAX_PATH + 1]{};
DWORD subkeyNameLen{MAX_PATH + 1};
rv = RegEnumKeyExW(key, 0, subkeyName, &subkeyNameLen, nullptr, nullptr,
nullptr, nullptr);
RegCloseKey(key);
if (rv != ERROR_SUCCESS || _wcsicmp(subkeyName, L"Certificates") != 0) {
return true;
}
std::wstring certsPath{std::format(L"{}\\Certificates", keyPath)};
HKEY certsKey{};
if (RegOpenKeyExW(aHive, certsPath.c_str(), 0, KEY_READ, &certsKey) !=
ERROR_SUCCESS) {
return true;
}
DWORD certsNumSubkeys{0};
DWORD certsNumValues{0};
rv = RegQueryInfoKeyW(certsKey, nullptr, nullptr, nullptr, &certsNumSubkeys,
nullptr, nullptr, &certsNumValues, nullptr, nullptr,
nullptr, nullptr);
if (rv != ERROR_SUCCESS) {
RegCloseKey(certsKey);
return true;
}
// If Certificates has additional values, it's enterprise managed
if (certsNumValues > 1) {
RegCloseKey(certsKey);
return true;
}
// If Certificates has subkeys, it's enterprise managed
if (certsNumSubkeys > 0) {
RegCloseKey(certsKey);
return true;
}
// Read ImportEnterpriseRoots, try as DWORD first, then as string
bool importEnterpriseRootsEnabled{false};
DWORD type{};
DWORD dwordValue{};
DWORD dataSize{sizeof(dwordValue)};
rv = RegQueryValueExW(certsKey, L"ImportEnterpriseRoots", nullptr, &type,
reinterpret_cast<BYTE*>(&dwordValue), &dataSize);
if (rv == ERROR_SUCCESS && type == REG_DWORD) {
importEnterpriseRootsEnabled = (dwordValue == 1);
} else {
wchar_t strValue[64]{};
dataSize = sizeof(strValue);
rv = RegQueryValueExW(certsKey, L"ImportEnterpriseRoots", nullptr, &type,
reinterpret_cast<BYTE*>(strValue), &dataSize);
if (rv == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ)) {
importEnterpriseRootsEnabled =
_wcsicmp(strValue, L"1") == 0 || _wcsicmp(strValue, L"true") == 0;
}
}
RegCloseKey(certsKey);
return !importEnterpriseRootsEnabled;
}
} // namespace
namespace EnterprisePolicies {
bool InDistribution(const std::filesystem::path& aDir) {
Json::CharReaderBuilder builder;
std::ifstream file(GetDistributionPoliciesFilePath(aDir));
Json::Value root;
std::string errors;
if (!Json::parseFromStream(builder, file, &root, &errors)) {
return false;
}
if (!root.isObject() || !root.isMember("policies")) {
return false;
}
const Json::Value& policies = root["policies"];
return !(!policies.isObject() || policies.empty());
}
bool InRegistry(std::wstring_view aBrand) {
return EnterprisePoliciesInRegistry(HKEY_LOCAL_MACHINE, aBrand) ||
EnterprisePoliciesInRegistry(HKEY_CURRENT_USER, aBrand);
}
} // namespace EnterprisePolicies