/* 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 #include #include #include #include #include #include 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(&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(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