diff options
author | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-12 17:55:13 +0000 |
---|---|---|
committer | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-12 17:55:13 +0000 |
commit | e54c7925e3f99aa2a618c9e5e4bcb396ef70bd33 (patch) | |
tree | 6fa622d24edad2618f57f70561acd4642bb1196c | |
parent | cdac5151b6c8590f74e797cd58161ef67017958f (diff) | |
download | chromium_src-e54c7925e3f99aa2a618c9e5e4bcb396ef70bd33.zip chromium_src-e54c7925e3f99aa2a618c9e5e4bcb396ef70bd33.tar.gz chromium_src-e54c7925e3f99aa2a618c9e5e4bcb396ef70bd33.tar.bz2 |
Change PolicyLoaderWin to load PReg files if possible.
We now query whether GPO is present and read directly from the corresponding
PReg files. The registry is used only as a fallback source for policy values.
To accomplish this, PolicyLoaderWin now works in two steps: It first converts
the GPO input into base::Value representation and then maps that to proper
policy values. This also unifies the handling for Chrome policy and 3rd-party
policy.
BUG=
TEST=unit tests
TBR=grt@chromium.org, cpu@chromium.org, ben@chromium.org
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=193649
Review URL: https://codereview.chromium.org/13619014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193961 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/breakpad_win.cc | 10 | ||||
-rw-r--r-- | chrome/browser/policy/browser_policy_connector.cc | 2 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win.cc | 970 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win.h | 88 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win_unittest.cc | 265 | ||||
-rw-r--r-- | chrome/browser/policy/policy_path_parser_win.cc | 2 | ||||
-rwxr-xr-x | chrome/tools/build/generate_policy_source.py | 25 | ||||
-rw-r--r-- | chrome_frame/chrome_launcher.cc | 2 | ||||
-rw-r--r-- | chrome_frame/policy_settings.cc | 6 | ||||
-rw-r--r-- | chrome_frame/test/policy_settings_unittest.cc | 6 |
10 files changed, 904 insertions, 472 deletions
diff --git a/chrome/app/breakpad_win.cc b/chrome/app/breakpad_win.cc index 8296eba..681dd88 100644 --- a/chrome/app/breakpad_win.cc +++ b/chrome/app/breakpad_win.cc @@ -4,10 +4,10 @@ #include "chrome/app/breakpad_win.h" -#include <windows.h> #include <shellapi.h> #include <tchar.h> #include <userenv.h> +#include <windows.h> #include <algorithm> #include <vector> @@ -19,8 +19,8 @@ #include "base/file_util.h" #include "base/file_version_info.h" #include "base/memory/scoped_ptr.h" -#include "base/string_util.h" #include "base/string16.h" +#include "base/string_util.h" #include "base/stringprintf.h" #include "base/strings/string_split.h" #include "base/utf_string_conversions.h" @@ -57,9 +57,9 @@ bool g_deferred_crash_uploads = false; } // namespace breakpad_win using breakpad_win::g_custom_entries; +using breakpad_win::g_deferred_crash_uploads; using breakpad_win::g_experiment_chunks_offset; using breakpad_win::g_num_of_experiments_offset; -using breakpad_win::g_deferred_crash_uploads; namespace { @@ -288,14 +288,14 @@ static bool MetricsReportingControlledByPolicy(bool* result) { string16 key_name = UTF8ToUTF16(policy::key::kMetricsReportingEnabled); DWORD value = 0; base::win::RegKey hklm_policy_key(HKEY_LOCAL_MACHINE, - policy::kRegistryMandatorySubKey, KEY_READ); + policy::kRegistryChromePolicyKey, KEY_READ); if (hklm_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { *result = value != 0; return true; } base::win::RegKey hkcu_policy_key(HKEY_CURRENT_USER, - policy::kRegistryMandatorySubKey, KEY_READ); + policy::kRegistryChromePolicyKey, KEY_READ); if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { *result = value != 0; return true; diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc index 45cf305..cafe4c5 100644 --- a/chrome/browser/policy/browser_policy_connector.cc +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -567,7 +567,7 @@ scoped_ptr<PolicyService> ConfigurationPolicyProvider* BrowserPolicyConnector::CreatePlatformProvider() { #if defined(OS_WIN) const PolicyDefinitionList* policy_list = GetChromePolicyDefinitionList(); - scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(policy_list)); + scoped_ptr<AsyncPolicyLoader> loader(PolicyLoaderWin::Create(policy_list)); return new AsyncPolicyProvider(loader.Pass()); #elif defined(OS_MACOSX) const PolicyDefinitionList* policy_list = GetChromePolicyDefinitionList(); diff --git a/chrome/browser/policy/policy_loader_win.cc b/chrome/browser/policy/policy_loader_win.cc index b527308..2abbeeb 100644 --- a/chrome/browser/policy/policy_loader_win.cc +++ b/chrome/browser/policy/policy_loader_win.cc @@ -5,25 +5,35 @@ #include "chrome/browser/policy/policy_loader_win.h" #include <string> +#include <vector> -#include <string.h> +#include <rpc.h> // For struct GUID +#include <shlwapi.h> // For PathIsUNC() +#include <userenv.h> // For GPO functions +#include <windows.h> -#include <userenv.h> - -// userenv.dll is required for RegisterGPNotification(). +// shlwapi.dll is required for PathIsUNC(). +#pragma comment(lib, "shlwapi.lib") +// userenv.dll is required for various GPO functions. #pragma comment(lib, "userenv.lib") #include "base/basictypes.h" +#include "base/file_util.h" +#include "base/files/file_path.h" #include "base/json/json_reader.h" +#include "base/lazy_instance.h" #include "base/logging.h" -#include "base/memory/scoped_ptr.h" +#include "base/scoped_native_library.h" +#include "base/stl_util.h" #include "base/string16.h" +#include "base/string_util.h" #include "base/strings/string_number_conversions.h" +#include "base/sys_byteorder.h" #include "base/utf_string_conversions.h" -#include "base/values.h" #include "base/win/registry.h" #include "chrome/browser/policy/policy_bundle.h" #include "chrome/browser/policy/policy_map.h" +#include "chrome/browser/policy/preg_parser_win.h" #include "chrome/common/json_schema/json_schema_constants.h" #include "policy/policy_constants.h" @@ -32,70 +42,183 @@ namespace schema = json_schema_constants; using base::win::RegKey; using base::win::RegistryKeyIterator; using base::win::RegistryValueIterator; -using namespace policy::registry_constants; namespace policy { -namespace registry_constants { - const wchar_t kPathSep[] = L"\\"; - const wchar_t kThirdParty[] = L"3rdparty"; - const wchar_t kMandatory[] = L"policy"; - const wchar_t kRecommended[] = L"recommended"; - const wchar_t kSchema[] = L"schema"; -} // namespace registry_constants - namespace { -// Map of registry hives to their corresponding policy scope, in decreasing -// order of priority. -const struct { - HKEY hive; - PolicyScope scope; -} kHives[] = { - { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, - { HKEY_CURRENT_USER, POLICY_SCOPE_USER }, +const char kKeyMandatory[] = "policy"; +const char kKeyRecommended[] = "recommended"; +const char kKeySchema[] = "schema"; +const char kKeyThirdParty[] = "3rdparty"; + +// The GUID of the registry settings group policy extension. +GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID; + +// The PReg file name. +const base::FilePath::CharType kPRegFileName[] = + FILE_PATH_LITERAL("Registry.pol"); + +// A helper class encapsulating run-time-linked function calls to Wow64 APIs. +class Wow64Functions { + public: + Wow64Functions() + : kernel32_lib_(base::FilePath(L"kernel32")), + is_wow_64_process_(NULL), + wow_64_disable_wow_64_fs_redirection_(NULL), + wow_64_revert_wow_64_fs_redirection_(NULL) { + if (kernel32_lib_.is_valid()) { + is_wow_64_process_ = static_cast<IsWow64Process>( + kernel32_lib_.GetFunctionPointer("IsWow64Process")); + wow_64_disable_wow_64_fs_redirection_ = + static_cast<Wow64DisableWow64FSRedirection>( + kernel32_lib_.GetFunctionPointer( + "Wow64DisableWow64FsRedirection")); + wow_64_revert_wow_64_fs_redirection_ = + static_cast<Wow64RevertWow64FSRedirection>( + kernel32_lib_.GetFunctionPointer( + "Wow64RevertWow64FsRedirection")); + } + } + + bool is_valid() { + return is_wow_64_process_ && + wow_64_disable_wow_64_fs_redirection_ && + wow_64_revert_wow_64_fs_redirection_; + } + + bool IsWow64() { + BOOL result = 0; + if (!is_wow_64_process_(GetCurrentProcess(), &result)) + PLOG(WARNING) << "IsWow64ProcFailed"; + return !!result; + } + + bool DisableFsRedirection(PVOID* previous_state) { + return !!wow_64_disable_wow_64_fs_redirection_(previous_state); + } + + bool RevertFsRedirection(PVOID previous_state) { + return !!wow_64_revert_wow_64_fs_redirection_(previous_state); + } + + private: + typedef BOOL (WINAPI* IsWow64Process)(HANDLE, PBOOL); + typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*); + typedef BOOL (WINAPI* Wow64RevertWow64FSRedirection)(PVOID); + + base::ScopedNativeLibrary kernel32_lib_; + + IsWow64Process is_wow_64_process_; + Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection_; + Wow64RevertWow64FSRedirection wow_64_revert_wow_64_fs_redirection_; + + DISALLOW_COPY_AND_ASSIGN(Wow64Functions); }; -// Reads a REG_SZ string at |key| named |name| into |result|. Returns false if -// the string could not be read. -bool ReadRegistryString(RegKey* key, - const string16& name, - string16* result) { - DWORD value_size = 0; - DWORD key_type = 0; - scoped_array<uint8> buffer; +// Global Wow64Function instance used by ScopedDisableWow64Redirection below. +static base::LazyInstance<Wow64Functions> g_wow_64_functions = + LAZY_INSTANCE_INITIALIZER; + +// Scoper that switches off Wow64 File System Redirection during its lifetime. +class ScopedDisableWow64Redirection { + public: + ScopedDisableWow64Redirection() + : active_(false), + previous_state_(NULL) { + Wow64Functions* wow64 = g_wow_64_functions.Pointer(); + if (wow64->is_valid() && wow64->IsWow64()) { + if (wow64->DisableFsRedirection(&previous_state_)) + active_ = true; + else + PLOG(WARNING) << "Wow64DisableWow64FSRedirection"; + } + } - if (key->ReadValue(name.c_str(), 0, &value_size, &key_type) != ERROR_SUCCESS) - return false; - if (key_type != REG_SZ) - return false; + ~ScopedDisableWow64Redirection() { + if (active_) + CHECK(g_wow_64_functions.Get().RevertFsRedirection(previous_state_)); + } - // According to the Microsoft documentation, the string - // buffer may not be explicitly 0-terminated. Allocate a - // slightly larger buffer and pre-fill to zeros to guarantee - // the 0-termination. - buffer.reset(new uint8[value_size + 2]); - memset(buffer.get(), 0, value_size + 2); - key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL); - result->assign(reinterpret_cast<const wchar_t*>(buffer.get())); - return true; + bool is_active() { return active_; } + + private: + bool active_; + PVOID previous_state_; + + DISALLOW_COPY_AND_ASSIGN(ScopedDisableWow64Redirection); +}; + +// AppliedGPOListProvider implementation that calls actual Windows APIs. +class WinGPOListProvider : public AppliedGPOListProvider { + public: + virtual ~WinGPOListProvider() {} + + // AppliedGPOListProvider: + virtual DWORD GetAppliedGPOList(DWORD flags, + LPCTSTR machine_name, + PSID sid_user, + GUID* extension_guid, + PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE { + return ::GetAppliedGPOList(flags, machine_name, sid_user, extension_guid, + gpo_list); + } + + virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE { + return ::FreeGPOList(gpo_list); + } +}; + +// The default windows GPO list provider used for PolicyLoaderWin. +static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider = + LAZY_INSTANCE_INITIALIZER; + +// Returns the entry with key |name| in |dictionary| (can be NULL), or NULL. +const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary, + const std::string& name) { + if (!dictionary) + return NULL; + const base::DictionaryValue* entry = NULL; + dictionary->GetDictionaryWithoutPathExpansion(name, &entry); + return entry; } -// Reads a REG_DWORD integer at |key| named |name| into |result|. Returns false -// if the value could no be read. -bool ReadRegistryInteger(RegKey* key, - const string16& name, - uint32* result) { - DWORD dword; - if (key->ReadValueDW(name.c_str(), &dword) != ERROR_SUCCESS) - return false; - *result = dword; - return true; +// Tries to extract the dictionary at |key| in |dict| and returns it. +scoped_ptr<base::DictionaryValue> RemoveDict(base::DictionaryValue* dict, + const std::string& key) { + base::Value* entry = NULL; + base::DictionaryValue* result_dict = NULL; + if (dict && dict->RemoveWithoutPathExpansion(key, &entry) && entry) { + if (!entry->GetAsDictionary(&result_dict)) + delete entry; + } + + return make_scoped_ptr(result_dict); +} + +std::string GetSchemaTypeForValueType(base::Value::Type value_type) { + switch (value_type) { + case base::Value::TYPE_DICTIONARY: + return json_schema_constants::kObject; + case base::Value::TYPE_INTEGER: + return json_schema_constants::kInteger; + case base::Value::TYPE_LIST: + return json_schema_constants::kArray; + case base::Value::TYPE_BOOLEAN: + return json_schema_constants::kBoolean; + case base::Value::TYPE_STRING: + return json_schema_constants::kString; + default: + break; + } + + NOTREACHED() << "Unsupported policy value type " << value_type; + return json_schema_constants::kNull; } // Returns the Value type described in |schema|, or |default_type| if not found. -base::Value::Type GetType(const base::DictionaryValue* schema, - base::Value::Type default_type) { +base::Value::Type GetValueTypeForSchema(const base::DictionaryValue* schema, + base::Value::Type default_type) { // JSON-schema types to base::Value::Type mapping. static const struct { // JSON schema type. @@ -115,7 +238,7 @@ base::Value::Type GetType(const base::DictionaryValue* schema, if (!schema) return default_type; std::string type; - if (!schema->GetString(schema::kType, &type)) + if (!schema->GetStringWithoutPathExpansion(schema::kType, &type)) return default_type; for (size_t i = 0; i < arraysize(kSchemaToValueTypeMap); ++i) { if (type == kSchemaToValueTypeMap[i].schema_type) @@ -124,28 +247,11 @@ base::Value::Type GetType(const base::DictionaryValue* schema, return default_type; } -// Returns the default type for registry entries of |reg_type|, when there is -// no schema defined type for a policy. -base::Value::Type GetDefaultFor(DWORD reg_type) { - return reg_type == REG_DWORD ? base::Value::TYPE_INTEGER : - base::Value::TYPE_STRING; -} - -// Returns the entry with key |name| in |dictionary| (can be NULL), or NULL. -const base::DictionaryValue* GetEntry(const base::DictionaryValue* dictionary, - const std::string& name) { - if (!dictionary) - return NULL; - const base::DictionaryValue* entry = NULL; - dictionary->GetDictionary(name, &entry); - return entry; -} - // Returns the schema for property |name| given the |schema| of an object. // Returns the "additionalProperties" schema if no specific schema for // |name| is present. Returns NULL if no schema is found. const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, - const std::string& name) { + const std::string& name) { const base::DictionaryValue* properties = GetEntry(schema, schema::kProperties); const base::DictionaryValue* sub_schema = GetEntry(properties, name); @@ -155,241 +261,201 @@ const base::DictionaryValue* GetSchemaFor(const base::DictionaryValue* schema, return GetEntry(schema, schema::kAdditionalProperties); } -// Converts string |value| to another |type|, if possible. -base::Value* ConvertStringValue(const string16& value, base::Value::Type type) { - switch (type) { - case base::Value::TYPE_NULL: - return base::Value::CreateNullValue(); - - case base::Value::TYPE_BOOLEAN: { - int int_value; - if (base::StringToInt(value, &int_value)) - return base::Value::CreateBooleanValue(int_value != 0); - return NULL; +// Reads the subtree of the Windows registry at |root| into the passed |dict|. +void ReadRegistry(HKEY hive, + const string16& root, + base::DictionaryValue* dict) { + // First, read all the values of the key. + for (RegistryValueIterator it(hive, root.c_str()); it.Valid(); ++it) { + const std::string name = UTF16ToUTF8(it.Name()); + switch (it.Type()) { + case REG_SZ: + case REG_EXPAND_SZ: + dict->SetStringWithoutPathExpansion(name, UTF16ToUTF8(it.Value())); + continue; + case REG_DWORD_LITTLE_ENDIAN: + case REG_DWORD_BIG_ENDIAN: + if (it.ValueSize() == sizeof(DWORD)) { + DWORD dword_value = *(reinterpret_cast<const DWORD*>(it.Value())); + if (it.Type() == REG_DWORD_BIG_ENDIAN) + dword_value = base::NetToHost32(dword_value); + else + dword_value = base::ByteSwapToLE32(dword_value); + dict->SetIntegerWithoutPathExpansion(name, dword_value); + continue; + } + case REG_NONE: + case REG_LINK: + case REG_MULTI_SZ: + case REG_RESOURCE_LIST: + case REG_FULL_RESOURCE_DESCRIPTOR: + case REG_RESOURCE_REQUIREMENTS_LIST: + case REG_QWORD_LITTLE_ENDIAN: + // Unsupported type, message gets logged below. + break; } - case base::Value::TYPE_INTEGER: { - int int_value; - if (base::StringToInt(value, &int_value)) - return base::Value::CreateIntegerValue(int_value); - return NULL; - } + LOG(WARNING) << "Failed to read hive " << hive << " at " + << root << "\\" << name + << " type " << it.Type(); + } - case base::Value::TYPE_DOUBLE: { - double double_value; - if (base::StringToDouble(UTF16ToUTF8(value), &double_value)) - return base::Value::CreateDoubleValue(double_value); - DLOG(WARNING) << "Failed to read policy value as double: " << value; - return NULL; + // Recurse for all subkeys. + for (RegistryKeyIterator it(hive, root.c_str()); it.Valid(); ++it) { + std::string name(UTF16ToUTF8(it.Name())); + if (dict->HasKey(name)) { + DLOG(WARNING) << "Ignoring registry key because a value exists with the " + "same name: " << root << "\\" << name; + } else { + scoped_ptr<base::DictionaryValue> subdict(new base::DictionaryValue()); + ReadRegistry(hive, root + L"\\" + it.Name(), subdict.get()); + dict->SetWithoutPathExpansion(name, subdict.release()); } - - case base::Value::TYPE_STRING: - return base::Value::CreateStringValue(value); - - case base::Value::TYPE_DICTIONARY: - case base::Value::TYPE_LIST: - return base::JSONReader::Read(UTF16ToUTF8(value)); - - case base::Value::TYPE_BINARY: - DLOG(WARNING) << "Cannot convert REG_SZ entry to type " << type; - return NULL; } - NOTREACHED(); - return NULL; } -// Converts an integer |value| to another |type|, if possible. -base::Value* ConvertIntegerValue(uint32 value, base::Value::Type type) { - switch (type) { - case base::Value::TYPE_BOOLEAN: - return base::Value::CreateBooleanValue(value != 0); - - case base::Value::TYPE_INTEGER: - return base::Value::CreateIntegerValue(value); - - case base::Value::TYPE_DOUBLE: - return base::Value::CreateDoubleValue(value); - - case base::Value::TYPE_NULL: - case base::Value::TYPE_STRING: - case base::Value::TYPE_BINARY: - case base::Value::TYPE_DICTIONARY: - case base::Value::TYPE_LIST: - DLOG(WARNING) << "Cannot convert REG_DWORD entry to type " << type; - return NULL; +// Converts |value| in raw GPO representation to the internal policy value, as +// described by |schema|. This maps the ambiguous GPO data types to the +// internal policy value representations. +scoped_ptr<base::Value> ConvertPolicyValue( + const base::Value& value, + const base::DictionaryValue* schema) { + // Figure out the type to convert to from the schema. + const base::Value::Type result_type( + GetValueTypeForSchema(schema, value.GetType())); + + // If the type is good already, go with it. + if (value.IsType(result_type)) { + // Recurse for complex types if there is a schema. + if (schema) { + const base::DictionaryValue* dict = NULL; + const base::ListValue* list = NULL; + if (value.GetAsDictionary(&dict)) { + scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + for (base::DictionaryValue::Iterator entry(*dict); !entry.IsAtEnd(); + entry.Advance()) { + scoped_ptr<base::Value> converted_value( + ConvertPolicyValue(entry.value(), + GetSchemaFor(schema, entry.key()))); + result->SetWithoutPathExpansion(entry.key(), + converted_value.release()); + } + return result.Pass(); + } else if (value.GetAsList(&list)) { + scoped_ptr<base::ListValue> result(new base::ListValue()); + const base::DictionaryValue* item_schema = + GetEntry(schema, schema::kItems); + for (base::ListValue::const_iterator entry(list->begin()); + entry != list->end(); ++entry) { + result->Append(ConvertPolicyValue(**entry, item_schema).release()); + } + return result.Pass(); + } + } + return make_scoped_ptr(value.DeepCopy()); } - NOTREACHED(); - return NULL; -} -// Reads a value from the registry |key| named |name| with registry type -// |registry_type| as a value of type |type|. -// Returns NULL if the value could not be loaded or converted. -base::Value* ReadPolicyValue(RegKey* key, - const string16& name, - DWORD registry_type, - base::Value::Type type) { - switch (registry_type) { - case REG_SZ: { - string16 value; - if (ReadRegistryString(key, name, &value)) - return ConvertStringValue(value, type); - break; + // Else, do some conversions to map windows registry data types to JSON types. + std::string string_value; + int int_value = 0; + switch (result_type) { + case base::Value::TYPE_NULL: { + return make_scoped_ptr(base::Value::CreateNullValue()); } - - case REG_DWORD: { - uint32 value; - if (ReadRegistryInteger(key, name, &value)) - return ConvertIntegerValue(value, type); + case base::Value::TYPE_BOOLEAN: { + // Accept booleans encoded as either string or integer. + if (value.GetAsInteger(&int_value) || + (value.GetAsString(&string_value) && + base::StringToInt(string_value, &int_value))) { + return make_scoped_ptr(Value::CreateBooleanValue(int_value != 0)); + } break; } - - default: - DLOG(WARNING) << "Registry type not supported for key " << name; + case base::Value::TYPE_INTEGER: { + // Integers may be string-encoded. + if (value.GetAsString(&string_value) && + base::StringToInt(string_value, &int_value)) { + return make_scoped_ptr(base::Value::CreateIntegerValue(int_value)); + } break; - } - return NULL; -} - -// Forward declaration for ReadComponentListValue(). -base::DictionaryValue* ReadComponentDictionaryValue( - HKEY hive, - const string16& path, - const base::DictionaryValue* schema); - -// Loads the list at |path| in the given |hive|. |schema| is a JSON schema -// (http://json-schema.org/) that describes the expected type of the list. -// Ownership of the result is transferred to the caller. -base::ListValue* ReadComponentListValue(HKEY hive, - const string16& path, - const base::DictionaryValue* schema) { - // The sub-elements are indexed from 1 to N. They can be represented as - // registry values or registry keys though; use |schema| first to try to - // determine the right type, and if that fails default to STRING. - - RegKey key(hive, path.c_str(), KEY_READ); - if (!key.Valid()) - return NULL; - - // Get the schema for list items. - schema = GetEntry(schema, schema::kItems); - base::Value::Type type = GetType(schema, base::Value::TYPE_STRING); - base::ListValue* list = new base::ListValue(); - for (int i = 1; ; ++i) { - string16 name = base::IntToString16(i); - base::Value* value = NULL; - if (type == base::Value::TYPE_DICTIONARY) { - value = - ReadComponentDictionaryValue(hive, path + kPathSep + name, schema); - } else if (type == base::Value::TYPE_LIST) { - value = ReadComponentListValue(hive, path + kPathSep + name, schema); - } else { - DWORD reg_type; - key.ReadValue(name.c_str(), NULL, NULL, ®_type); - if (reg_type != REG_NONE) - value = ReadPolicyValue(&key, name, reg_type, type); } - if (value) - list->Append(value); - else + case base::Value::TYPE_DOUBLE: { + // Doubles may be string-encoded or integer-encoded. + double double_value = 0; + if (value.GetAsInteger(&int_value)) { + return make_scoped_ptr(base::Value::CreateDoubleValue(int_value)); + } else if (value.GetAsString(&string_value) && + base::StringToDouble(string_value, &double_value)) { + return make_scoped_ptr(base::Value::CreateDoubleValue(double_value)); + } break; - } - return list; -} - -// Loads the dictionary at |path| in the given |hive|. |schema| is a JSON -// schema (http://json-schema.org/) that describes the expected types for the -// dictionary entries. When the type for a certain entry isn't described in the -// schema, a default conversion takes place. |schema| can be NULL. -// Ownership of the result is transferred to the caller. -base::DictionaryValue* ReadComponentDictionaryValue( - HKEY hive, - const string16& path, - const base::DictionaryValue* schema) { - // A "value" in the registry is like a file in a filesystem, and a "key" is - // like a directory, that contains other "values" and "keys". - // Unfortunately it is possible to have a name both as a "value" and a "key". - // In those cases, the sub "key" will be ignored; this choice is arbitrary. - - // First iterate over all the "values" in |path| and convert them; then - // recurse into each "key" in |path| and convert them as dictionaries. - - RegKey key(hive, path.c_str(), KEY_READ); - if (!key.Valid()) - return NULL; - - base::DictionaryValue* dict = new base::DictionaryValue(); - for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { - string16 name16(it.Name()); - std::string name(UTF16ToUTF8(name16)); - const base::DictionaryValue* sub_schema = GetSchemaFor(schema, name); - base::Value::Type type = GetType(sub_schema, GetDefaultFor(it.Type())); - base::Value* value = ReadPolicyValue(&key, name16, it.Type(), type); - if (value) - dict->Set(name, value); - } - - for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { - string16 name16(it.Name()); - std::string name(UTF16ToUTF8(name16)); - if (dict->HasKey(name)) { - DLOG(WARNING) << "Ignoring registry key because a value exists with the " - "same name: " << path << kPathSep << name; - continue; } - - const base::DictionaryValue* sub_schema = GetSchemaFor(schema, name); - base::Value::Type type = GetType(sub_schema, base::Value::TYPE_DICTIONARY); - base::Value* value = NULL; - const string16 sub_path = path + kPathSep + name16; - if (type == base::Value::TYPE_DICTIONARY) { - value = ReadComponentDictionaryValue(hive, sub_path, sub_schema); - } else if (type == base::Value::TYPE_LIST) { - value = ReadComponentListValue(hive, sub_path, sub_schema); - } else { - DLOG(WARNING) << "Can't read a simple type in registry key at " << path; + case base::Value::TYPE_LIST: { + // Lists are encoded as subkeys with numbered value in the registry. + const base::DictionaryValue* dict = NULL; + if (value.GetAsDictionary(&dict)) { + scoped_ptr<base::ListValue> result(new base::ListValue()); + const base::DictionaryValue* item_schema = + GetEntry(schema, schema::kItems); + for (int i = 1; ; ++i) { + const base::Value* entry = NULL; + if (!dict->Get(base::IntToString(i), &entry)) + break; + result->Append(ConvertPolicyValue(*entry, item_schema).release()); + } + return result.Pass(); + } + // Fall through in order to accept lists encoded as JSON strings. } - if (value) - dict->Set(name, value); + case base::Value::TYPE_DICTIONARY: { + // Dictionaries may be encoded as JSON strings. + if (value.GetAsString(&string_value)) { + scoped_ptr<base::Value> result(base::JSONReader::Read(string_value)); + if (result && result->IsType(result_type)) + return result.Pass(); + } + break; + } + case base::Value::TYPE_STRING: + case base::Value::TYPE_BINARY: + // No conversion possible. + break; } - return dict; + LOG(WARNING) << "Failed to convert " << value.GetType() + << " to " << result_type; + return make_scoped_ptr(base::Value::CreateNullValue()); } -// Reads a JSON schema from the given |registry_value|, at the given -// |registry_key| in |hive|. |registry_value| must be a string (REG_SZ), and -// is decoded as JSON data. Returns NULL on failure. Ownership is transferred -// to the caller. -base::DictionaryValue* ReadRegistrySchema(HKEY hive, - const string16& registry_key, - const string16& registry_value) { - RegKey key(hive, registry_key.c_str(), KEY_READ); - string16 schema; - if (!ReadRegistryString(&key, registry_value, &schema)) - return NULL; - // A JSON schema is represented in JSON too. - scoped_ptr<base::Value> value(base::JSONReader::Read(UTF16ToUTF8(schema))); - if (!value.get()) - return NULL; - base::DictionaryValue* dict = NULL; - if (!value->GetAsDictionary(&dict)) - return NULL; - // The top-level entry must be an object, and each of its properties maps - // a policy name to its schema. - if (GetType(dict, base::Value::TYPE_DICTIONARY) != - base::Value::TYPE_DICTIONARY) { - DLOG(WARNING) << "schema top-level type isn't \"object\""; - return NULL; +// Parses |gpo_dict| according to |schema| and writes the resulting policy +// settings to |policy| for the given |scope| and |level|. +void ParsePolicy(const base::DictionaryValue* gpo_dict, + PolicyLevel level, + PolicyScope scope, + const base::DictionaryValue* schema, + PolicyMap* policy) { + if (!gpo_dict) + return; + + scoped_ptr<base::Value> policy_value(ConvertPolicyValue(*gpo_dict, schema)); + const base::DictionaryValue* policy_dict = NULL; + if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) { + LOG(WARNING) << "Root policy object is not a dictionary!"; + return; } - value.release(); - return dict; + + policy->LoadFrom(policy_dict, level, scope); } } // namespace -PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) +PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list, + const string16& chrome_policy_key, + AppliedGPOListProvider* gpo_provider) : is_initialized_(false), policy_list_(policy_list), + chrome_policy_key_(chrome_policy_key), + gpo_provider_(gpo_provider), user_policy_changed_event_(false, false), machine_policy_changed_event_(false, false), user_policy_watcher_failed_(false), @@ -409,155 +475,259 @@ PolicyLoaderWin::~PolicyLoaderWin() { machine_policy_watcher_.StopWatching(); } +// static +scoped_ptr<PolicyLoaderWin> PolicyLoaderWin::Create( + const PolicyDefinitionList* policy_list) { + return make_scoped_ptr( + new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey, + g_win_gpo_list_provider.Pointer())); +} + void PolicyLoaderWin::InitOnFile() { is_initialized_ = true; SetupWatches(); } scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { - scoped_ptr<PolicyBundle> bundle(new PolicyBundle()); - LoadChromePolicy( - &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))); - Load3rdPartyPolicies(bundle.get()); - return bundle.Pass(); -} - -void PolicyLoaderWin::LoadChromePolicy(PolicyMap* chrome_policies) { // Reset the watches BEFORE reading the individual policies to avoid // missing a change notification. if (is_initialized_) SetupWatches(); - // |kKeyPaths| is in decreasing order of priority. + if (chrome_policy_schema_.empty()) + BuildChromePolicySchema(); + + // Policy scope and corresponding hive. static const struct { - const wchar_t* path; - PolicyLevel level; - } kKeyPaths[] = { - { kRegistryMandatorySubKey, POLICY_LEVEL_MANDATORY }, - { kRegistryRecommendedSubKey, POLICY_LEVEL_RECOMMENDED }, + PolicyScope scope; + HKEY hive; + } kScopes[] = { + { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, + { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, }; - // Lookup at the mandatory path for both user and machine policies first, and - // then at the recommended path. - for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { - for (size_t h = 0; h < arraysize(kHives); ++h) { - // Iterate over keys and values at this hive and path. - HKEY hive = kHives[h].hive; - string16 path(kKeyPaths[k].path); - RegKey key; - if (key.Open(hive, path.c_str(), KEY_READ) != ERROR_SUCCESS || - !key.Valid()) { - continue; - } + // Load policy data for the different scopes/levels and merge them. + scoped_ptr<PolicyBundle> bundle(new PolicyBundle()); + PolicyMap* chrome_policy = + &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); + for (size_t i = 0; i < arraysize(kScopes); ++i) { + PolicyScope scope = kScopes[i].scope; + base::DictionaryValue gpo_dict; + + HANDLE policy_lock = + EnterCriticalPolicySection(scope == POLICY_SCOPE_MACHINE); + if (policy_lock == NULL) + PLOG(ERROR) << "EnterCriticalPolicySection"; + + if (!ReadPolicyFromGPO(scope, &gpo_dict)) { + VLOG(1) << "Failed to read GPO files for " << scope + << " falling back to registry."; + ReadRegistry(kScopes[i].hive, chrome_policy_key_, &gpo_dict); + } - // Iterate over values for most policies. - for (RegistryValueIterator it(hive, path.c_str()); it.Valid(); ++it) { - std::string name(UTF16ToUTF8(it.Name())); - // Skip if a higher-priority policy value was already inserted, or - // if this is the default value (empty string). - if (chrome_policies->Get(name) || name.empty()) - continue; - // Get the expected policy type, if this is a known policy. - base::Value::Type type = GetDefaultFor(it.Type()); - for (const PolicyDefinitionList::Entry* e = policy_list_->begin; - e != policy_list_->end; ++e) { - if (name == e->name) { - type = e->value_type; - break; - } - } - base::Value* value = ReadPolicyValue(&key, it.Name(), it.Type(), type); - if (!value) - value = base::Value::CreateNullValue(); - chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, value); - } + if (!LeaveCriticalPolicySection(policy_lock)) + PLOG(ERROR) << "LeaveCriticalPolicySection"; - // Iterate over keys for policies of type string-list. - for (RegistryKeyIterator it(hive, path.c_str()); it.Valid(); ++it) { - std::string name(UTF16ToUTF8(it.Name())); - // Skip if a higher-priority policy value was already inserted, or - // if this is the 3rd party policy subkey. - const string16 kThirdParty16(kThirdParty); - if (chrome_policies->Get(name) || it.Name() == kThirdParty16) - continue; - string16 list_path = path + kPathSep + it.Name(); - RegKey key; - if (key.Open(hive, list_path.c_str(), KEY_READ) != ERROR_SUCCESS || - !key.Valid()) { - continue; - } - base::ListValue* result = new base::ListValue(); - string16 value; - int index = 0; - while (ReadRegistryString(&key, base::IntToString16(++index), &value)) - result->Append(base::Value::CreateStringValue(value)); - chrome_policies->Set(name, kKeyPaths[k].level, kHives[h].scope, result); - } + // Remove special-cased entries from the GPO dictionary. + base::DictionaryValue* temp_dict = NULL; + scoped_ptr<base::DictionaryValue> recommended_dict( + RemoveDict(&gpo_dict, kKeyRecommended)); + scoped_ptr<base::DictionaryValue> third_party_dict( + RemoveDict(&gpo_dict, kKeyThirdParty)); + + // Load Chrome policy. + LoadChromePolicy(&gpo_dict, POLICY_LEVEL_MANDATORY, scope, chrome_policy); + LoadChromePolicy(recommended_dict.get(), POLICY_LEVEL_RECOMMENDED, scope, + chrome_policy); + + // Load 3rd-party policy. + if (third_party_dict) + Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get()); + } + + return bundle.Pass(); +} + +void PolicyLoaderWin::BuildChromePolicySchema() { + scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue()); + for (const PolicyDefinitionList::Entry* e = policy_list_->begin; + e != policy_list_->end; ++e) { + const std::string schema_type = GetSchemaTypeForValueType(e->value_type); + scoped_ptr<base::DictionaryValue> entry_schema(new base::DictionaryValue()); + entry_schema->SetStringWithoutPathExpansion(json_schema_constants::kType, + schema_type); + + if (e->value_type == base::Value::TYPE_LIST) { + scoped_ptr<base::DictionaryValue> items_schema( + new base::DictionaryValue()); + items_schema->SetStringWithoutPathExpansion( + json_schema_constants::kType, json_schema_constants::kString); + entry_schema->SetWithoutPathExpansion(json_schema_constants::kItems, + items_schema.release()); } + properties->SetWithoutPathExpansion(e->name, entry_schema.release()); } + chrome_policy_schema_.SetStringWithoutPathExpansion( + json_schema_constants::kType, json_schema_constants::kObject); + chrome_policy_schema_.SetWithoutPathExpansion( + json_schema_constants::kProperties, properties.release()); } -void PolicyLoaderWin::Load3rdPartyPolicies(PolicyBundle* bundle) { - // Each 3rd party namespace can have policies on both HKLM and HKCU. They - // should be merged, giving priority to HKLM for policies with the same name. +bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file, + base::DictionaryValue* policy) { + // The following deals with the minor annoyance that Wow64 FS redirection + // might need to be turned off: This is the case if running as a 32-bit + // process on a 64-bit system, in which case Wow64 FS redirection redirects + // access to the %WINDIR%/System32/GroupPolicy directory to + // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the + // system-native directory. + if (file_util::PathExists(preg_file)) { + return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy); + } else { + // Try with redirection switched off. + ScopedDisableWow64Redirection redirection_disable; + if (redirection_disable.is_active() && file_util::PathExists(preg_file)) + return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy); + } + + // Report the error. + LOG(ERROR) << "PReg file doesn't exist: " << preg_file.value(); + return false; +} + +bool PolicyLoaderWin::LoadGPOPolicy(PolicyScope scope, + PGROUP_POLICY_OBJECT policy_object_list, + base::DictionaryValue* policy) { + base::DictionaryValue parsed_policy; + base::DictionaryValue forced_policy; + for (GROUP_POLICY_OBJECT* policy_object = policy_object_list; + policy_object; policy_object = policy_object->pNext) { + if (policy_object->dwOptions & GPO_FLAG_DISABLE) + continue; + + if (PathIsUNC(policy_object->lpFileSysPath)) { + // UNC path: Assume this is an AD-managed machine, which updates the + // registry via GPO's standard registry CSE periodically. Fall back to + // reading from the registry in this case. + return false; + } + + base::FilePath preg_file_path( + base::FilePath(policy_object->lpFileSysPath).Append(kPRegFileName)); + if (policy_object->dwOptions & GPO_FLAG_FORCE) { + base::DictionaryValue new_forced_policy; + if (!ReadPRegFile(preg_file_path, &new_forced_policy)) + return false; + + // Merge with existing forced policy, giving precedence to the existing + // forced policy. + new_forced_policy.MergeDictionary(&forced_policy); + forced_policy.Swap(&new_forced_policy); + } else { + if (!ReadPRegFile(preg_file_path, &parsed_policy)) + return false; + } + } + + // Merge, give precedence to forced policy. + parsed_policy.MergeDictionary(&forced_policy); + policy->Swap(&parsed_policy); - // Map of known domain name to their enum values. + return true; +} + + +bool PolicyLoaderWin::ReadPolicyFromGPO(PolicyScope scope, + base::DictionaryValue* policy) { + PGROUP_POLICY_OBJECT policy_object_list = NULL; + DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0; + if (gpo_provider_->GetAppliedGPOList( + flags, NULL, NULL, &kRegistrySettingsCSEGUID, + &policy_object_list) != ERROR_SUCCESS) { + PLOG(ERROR) << "GetAppliedGPOList scope " << scope; + return false; + } + + bool result = LoadGPOPolicy(scope, policy_object_list, policy); + if (!gpo_provider_->FreeGPOList(policy_object_list)) + LOG(WARNING) << "FreeGPOList"; + + return result; +} + +void PolicyLoaderWin::LoadChromePolicy(const base::DictionaryValue* gpo_dict, + PolicyLevel level, + PolicyScope scope, + PolicyMap* chrome_policy_map) { + PolicyMap policy; + ParsePolicy(gpo_dict, level, scope, &chrome_policy_schema_, &policy); + chrome_policy_map->MergeFrom(policy); +} + +void PolicyLoaderWin::Load3rdPartyPolicy( + const DictionaryValue* gpo_dict, + PolicyScope scope, + PolicyBundle* bundle) { + // Map of known 3rd party policy domain name to their enum values. static const struct { const char* name; PolicyDomain domain; - } kDomains[] = { - { "extensions", POLICY_DOMAIN_EXTENSIONS }, + } k3rdPartyDomains[] = { + { "extensions", POLICY_DOMAIN_EXTENSIONS }, }; - // Map of policy paths to their corresponding policy level, in decreasing - // order of priority. + // Policy level and corresponding path. static const struct { - const char* path; PolicyLevel level; - } kKeyPaths[] = { - { "policy", POLICY_LEVEL_MANDATORY }, - { "recommended", POLICY_LEVEL_RECOMMENDED }, + const char* path; + } kLevels[] = { + { POLICY_LEVEL_MANDATORY, kKeyMandatory }, + { POLICY_LEVEL_RECOMMENDED, kKeyRecommended }, }; - // Path where policies for components are stored. - const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep + - kThirdParty + kPathSep; - - for (size_t h = 0; h < arraysize(kHives); ++h) { - HKEY hkey = kHives[h].hive; - - for (size_t d = 0; d < arraysize(kDomains); ++d) { - // Each subkey under this domain is a component of that domain. - // |domain_path| == SOFTWARE\Policies\Chromium\3rdparty\<domain> - string16 domain_path = kPathPrefix + ASCIIToUTF16(kDomains[d].name); - - for (RegistryKeyIterator domain_iterator(hkey, domain_path.c_str()); - domain_iterator.Valid(); ++domain_iterator) { - string16 component(domain_iterator.Name()); - string16 component_path = domain_path + kPathSep + component; - - // Load the schema for this component's policy, if present. - scoped_ptr<base::DictionaryValue> schema( - ReadRegistrySchema(hkey, component_path, kSchema)); - - for (size_t k = 0; k < arraysize(kKeyPaths); ++k) { - string16 path = - component_path + kPathSep + ASCIIToUTF16(kKeyPaths[k].path); - - scoped_ptr<base::DictionaryValue> dictionary( - ReadComponentDictionaryValue(hkey, path, schema.get())); - if (dictionary.get()) { - PolicyMap policies; - policies.LoadFrom( - dictionary.get(), kKeyPaths[k].level, kHives[h].scope); - // LoadFrom() overwrites any existing values. Use a temporary map - // and then use MergeFrom(), that only overwrites values with lower - // priority. - bundle->Get(PolicyNamespace(kDomains[d].domain, - UTF16ToUTF8(component))) - .MergeFrom(policies); - } + for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) { + const char* name = k3rdPartyDomains[i].name; + const PolicyDomain domain = k3rdPartyDomains[i].domain; + const base::DictionaryValue* domain_dict = NULL; + if (!gpo_dict->GetDictionaryWithoutPathExpansion(name, &domain_dict) || + !domain_dict) { + continue; + } + + for (base::DictionaryValue::Iterator component(*domain_dict); + !component.IsAtEnd(); component.Advance()) { + const base::DictionaryValue* component_dict = NULL; + if (!component.value().GetAsDictionary(&component_dict) || + !component_dict) { + continue; + } + + // Load the schema. + scoped_ptr<base::Value> schema; + const base::DictionaryValue* schema_dict = NULL; + std::string schema_json; + if (component_dict->GetStringWithoutPathExpansion(kKeySchema, + &schema_json)) { + schema.reset(base::JSONReader::Read(schema_json)); + if (!schema || !schema->GetAsDictionary(&schema_dict)) { + LOG(WARNING) << "Failed to parse 3rd-part policy schema for " + << domain << "/" << component.key(); + } + } + + // Parse policy. + for (size_t j = 0; j < arraysize(kLevels); j++) { + const base::DictionaryValue* policy_dict = NULL; + if (!component_dict->GetDictionaryWithoutPathExpansion( + kLevels[j].path, &policy_dict) || + !policy_dict) { + continue; } + + PolicyMap policy; + ParsePolicy(policy_dict, kLevels[j].level, scope, schema_dict, &policy); + PolicyNamespace policy_namespace(domain, component.key()); + bundle->Get(policy_namespace).MergeFrom(policy); } } } diff --git a/chrome/browser/policy/policy_loader_win.h b/chrome/browser/policy/policy_loader_win.h index 4156ffe..096e420 100644 --- a/chrome/browser/policy/policy_loader_win.h +++ b/chrome/browser/policy/policy_loader_win.h @@ -5,30 +5,90 @@ #ifndef CHROME_BROWSER_POLICY_POLICY_LOADER_WIN_H_ #define CHROME_BROWSER_POLICY_POLICY_LOADER_WIN_H_ +#include <userenv.h> +#include <windows.h> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "base/synchronization/waitable_event.h" +#include "base/values.h" #include "base/win/object_watcher.h" #include "chrome/browser/policy/async_policy_loader.h" +#include "chrome/browser/policy/policy_types.h" + +namespace base { +class FilePath; +} namespace policy { -struct PolicyDefinitionList; +class AppliedGPOListProvider; class PolicyMap; +struct PolicyDefinitionList; + +// Interface for mocking out GPO enumeration in tests. +class AppliedGPOListProvider { + public: + virtual ~AppliedGPOListProvider() {} + virtual DWORD GetAppliedGPOList(DWORD flags, + LPCTSTR machine_name, + PSID sid_user, + GUID* extension_guid, + PGROUP_POLICY_OBJECT* gpo_list) = 0; + virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) = 0; +}; // Loads policies from the Windows registry, and watches for Group Policy // notifications to trigger reloads. class PolicyLoaderWin : public AsyncPolicyLoader, public base::win::ObjectWatcher::Delegate { public: - explicit PolicyLoaderWin(const PolicyDefinitionList* policy_list); + explicit PolicyLoaderWin(const PolicyDefinitionList* policy_list, + const string16& chrome_policy_key, + AppliedGPOListProvider* gpo_provider); virtual ~PolicyLoaderWin(); + // Creates a policy loader that uses the Win API to access GPO. + static scoped_ptr<PolicyLoaderWin> Create( + const PolicyDefinitionList* policy_list); + // AsyncPolicyLoader implementation. virtual void InitOnFile() OVERRIDE; virtual scoped_ptr<PolicyBundle> Load() OVERRIDE; private: - void LoadChromePolicy(PolicyMap* chrome_policies); - void Load3rdPartyPolicies(PolicyBundle* bundle); + // Builds the Chrome policy schema in |chrome_policy_schema_|. + void BuildChromePolicySchema(); + + // Reads Chrome Policy from a PReg file at the given path and stores the + // result in |policy|. + bool ReadPRegFile(const base::FilePath& preg_file, + base::DictionaryValue* policy); + + // Loads and parses GPO policy in |policy_object_list| for scope |scope|. If + // successful, stores the result in |policy| and returns true. Returns false + // on failure reading the policy, indicating that policy loading should fall + // back to reading the registry. + bool LoadGPOPolicy(PolicyScope scope, + PGROUP_POLICY_OBJECT policy_object_list, + base::DictionaryValue* policy); + + // Queries Windows for applied group policy and writes the result to |policy|. + // This is the preferred way to obtain GPO data, there are reports of abuse + // of the registry GPO keys by 3rd-party software. + bool ReadPolicyFromGPO(PolicyScope scope, base::DictionaryValue* policy); + + // Parses Chrome policy from |gpo_dict| for the given |scope| and |level| and + // merges it into |chrome_policy_map|. + void LoadChromePolicy(const base::DictionaryValue* gpo_dict, + PolicyLevel level, + PolicyScope scope, + PolicyMap* chrome_policy_map); + + // Loads 3rd-party policy from |gpo_dict| and merges it into |bundle|. + void Load3rdPartyPolicy(const base::DictionaryValue* gpo_dict, + PolicyScope scope, + PolicyBundle* bundle); // Installs the watchers for the Group Policy update events. void SetupWatches(); @@ -38,6 +98,9 @@ class PolicyLoaderWin : public AsyncPolicyLoader, bool is_initialized_; const PolicyDefinitionList* policy_list_; + const string16 chrome_policy_key_; + class AppliedGPOListProvider* gpo_provider_; + base::DictionaryValue chrome_policy_schema_; base::WaitableEvent user_policy_changed_event_; base::WaitableEvent machine_policy_changed_event_; @@ -49,23 +112,6 @@ class PolicyLoaderWin : public AsyncPolicyLoader, DISALLOW_COPY_AND_ASSIGN(PolicyLoaderWin); }; -// Constants shared with tests. -namespace registry_constants { - // Path separator for registry keys. - extern const wchar_t kPathSep[]; - // Registry key within Chrome's key that contains 3rd party policy. - extern const wchar_t kThirdParty[]; - // Registry key within an extension's namespace that contains mandatory - // policy. - extern const wchar_t kMandatory[]; - // Registry key within an extension's namespace that contains recommended - // policy. - extern const wchar_t kRecommended[]; - // Registry key within an extension's namespace that contains the policy - // schema. - extern const wchar_t kSchema[]; -} // namespace registry_constants - } // namespace policy #endif // CHROME_BROWSER_POLICY_POLICY_LOADER_WIN_H_ diff --git a/chrome/browser/policy/policy_loader_win_unittest.cc b/chrome/browser/policy/policy_loader_win_unittest.cc index 5193063..c2481bc 100644 --- a/chrome/browser/policy/policy_loader_win_unittest.cc +++ b/chrome/browser/policy/policy_loader_win_unittest.cc @@ -4,9 +4,15 @@ #include "chrome/browser/policy/policy_loader_win.h" +#include <userenv.h> #include <windows.h> +#include <cstring> + +#include "base/file_util.h" +#include "base/files/file_path.h" #include "base/json/json_writer.h" +#include "base/path_service.h" #include "base/process.h" #include "base/string16.h" #include "base/string_util.h" @@ -18,6 +24,7 @@ #include "chrome/browser/policy/configuration_policy_provider_test.h" #include "chrome/browser/policy/policy_bundle.h" #include "chrome/browser/policy/policy_map.h" +#include "chrome/common/chrome_paths.h" #include "chrome/common/json_schema/json_schema_constants.h" #include "policy/policy_constants.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,12 +32,18 @@ namespace schema = json_schema_constants; using base::win::RegKey; -using namespace policy::registry_constants; namespace policy { namespace { +// Constants for registry key names. +const wchar_t kPathSep[] = L"\\"; +const wchar_t kThirdParty[] = L"3rdparty"; +const wchar_t kMandatory[] = L"policy"; +const wchar_t kRecommended[] = L"recommended"; +const wchar_t kSchema[] = L"schema"; + // Installs |value| in the given registry |path| and |hive|, under the key // |name|. Returns false on errors. // Some of the possible Value types are stored after a conversion (e.g. doubles @@ -219,13 +232,15 @@ class ScopedGroupPolicyRegistrySandbox { DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox); }; -class TestHarness : public PolicyProviderTestHarness { +class TestHarness : public PolicyProviderTestHarness, + public AppliedGPOListProvider { public: explicit TestHarness(HKEY hive, PolicyScope scope); virtual ~TestHarness(); virtual void SetUp() OVERRIDE; + // PolicyProviderTestHarness: virtual ConfigurationPolicyProvider* CreateProvider( const PolicyDefinitionList* policy_definition_list) OVERRIDE; @@ -245,6 +260,14 @@ class TestHarness : public PolicyProviderTestHarness { virtual void Install3rdPartyPolicy( const base::DictionaryValue* policies) OVERRIDE; + // AppliedGPOListProvider: + virtual DWORD GetAppliedGPOList(DWORD flags, + LPCTSTR machine_name, + PSID sid_user, + GUID* extension_guid, + PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE; + virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE; + // Creates a harness instance that will install policy in HKCU or HKLM, // respectively. static PolicyProviderTestHarness* CreateHKCU(); @@ -310,9 +333,23 @@ TestHarness::~TestHarness() {} void TestHarness::SetUp() {} +DWORD TestHarness::GetAppliedGPOList(DWORD flags, + LPCTSTR machine_name, + PSID sid_user, + GUID* extension_guid, + PGROUP_POLICY_OBJECT* gpo_list) { + *gpo_list = NULL; + return ERROR_ACCESS_DENIED; +} + +BOOL TestHarness::FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) { + return TRUE; +} + ConfigurationPolicyProvider* TestHarness::CreateProvider( const PolicyDefinitionList* policy_list) { - scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(policy_list)); + scoped_ptr<AsyncPolicyLoader> loader( + new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey, this)); return new AsyncPolicyProvider(loader.Pass()); } @@ -320,7 +357,7 @@ void TestHarness::InstallEmptyPolicy() {} void TestHarness::InstallStringPolicy(const std::string& policy_name, const std::string& policy_value) { - RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); ASSERT_HRESULT_SUCCEEDED(key.WriteValue(UTF8ToUTF16(policy_name).c_str(), UTF8ToUTF16(policy_value).c_str())); @@ -328,7 +365,7 @@ void TestHarness::InstallStringPolicy(const std::string& policy_name, void TestHarness::InstallIntegerPolicy(const std::string& policy_name, int policy_value) { - RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); key.WriteValue(UTF8ToUTF16(policy_name).c_str(), static_cast<DWORD>(policy_value)); @@ -336,7 +373,7 @@ void TestHarness::InstallIntegerPolicy(const std::string& policy_name, void TestHarness::InstallBooleanPolicy(const std::string& policy_name, bool policy_value) { - RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); key.WriteValue(UTF8ToUTF16(policy_name).c_str(), static_cast<DWORD>(policy_value)); @@ -345,7 +382,7 @@ void TestHarness::InstallBooleanPolicy(const std::string& policy_name, void TestHarness::InstallStringListPolicy(const std::string& policy_name, const base::ListValue* policy_value) { RegKey key(hive_, - (string16(kRegistryMandatorySubKey) + ASCIIToUTF16("\\") + + (string16(kRegistryChromePolicyKey) + ASCIIToUTF16("\\") + UTF8ToUTF16(policy_name)).c_str(), KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); @@ -367,7 +404,7 @@ void TestHarness::InstallDictionaryPolicy( const base::DictionaryValue* policy_value) { std::string json; base::JSONWriter::Write(policy_value, &json); - RegKey key(hive_, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey key(hive_, kRegistryChromePolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(key.Valid()); key.WriteValue(UTF8ToUTF16(policy_name).c_str(), UTF8ToUTF16(json).c_str()); @@ -376,7 +413,7 @@ void TestHarness::InstallDictionaryPolicy( void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) { // The first level entries are domains, and the second level entries map // components to their policy. - const string16 kPathPrefix = string16(kRegistryMandatorySubKey) + kPathSep + + const string16 kPathPrefix = string16(kRegistryChromePolicyKey) + kPathSep + kThirdParty + kPathSep; for (base::DictionaryValue::Iterator domain(*policies); !domain.IsAtEnd(); domain.Advance()) { @@ -387,7 +424,7 @@ void TestHarness::Install3rdPartyPolicy(const base::DictionaryValue* policies) { } for (base::DictionaryValue::Iterator component(*components); !component.IsAtEnd(); component.Advance()) { - const string16 path = string16(kRegistryMandatorySubKey) + kPathSep + + const string16 path = string16(kRegistryChromePolicyKey) + kPathSep + kThirdParty + kPathSep + UTF8ToUTF16(domain.key()) + kPathSep + UTF8ToUTF16(component.key()); @@ -422,26 +459,104 @@ INSTANTIATE_TEST_CASE_P( testing::Values(TestHarness::CreateHKCU, TestHarness::CreateHKLM)); // Test cases for windows policy provider specific functionality. -class PolicyLoaderWinTest : public PolicyTestBase { +class PolicyLoaderWinTest : public PolicyTestBase, + public AppliedGPOListProvider { protected: - PolicyLoaderWinTest() {} + // The policy key this tests places data under. This must match the data + // files in chrome/test/data/policy/gpo. + static const char16 kTestPolicyKey[]; + + PolicyLoaderWinTest() + : gpo_list_(NULL), + gpo_list_status_(ERROR_ACCESS_DENIED) {} virtual ~PolicyLoaderWinTest() {} + virtual void SetUp() OVERRIDE { + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_)); + test_data_dir_ = test_data_dir_.AppendASCII("policy").AppendASCII("gpo"); + } + + // AppliedGPOListProvider: + virtual DWORD GetAppliedGPOList(DWORD flags, + LPCTSTR machine_name, + PSID sid_user, + GUID* extension_guid, + PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE { + *gpo_list = gpo_list_; + return gpo_list_status_; + } + virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE { + return TRUE; + } + + void InitGPO(GROUP_POLICY_OBJECT* gpo, + DWORD options, + const base::FilePath& path, + GROUP_POLICY_OBJECT* next, + GROUP_POLICY_OBJECT* prev) { + memset(gpo, 0, sizeof(GROUP_POLICY_OBJECT)); + gpo->dwOptions = options; + gpo->lpFileSysPath = const_cast<wchar_t*>(path.value().c_str()); + gpo->pNext = next; + gpo->pPrev = prev; + } + bool Matches(const PolicyBundle& expected) { - PolicyLoaderWin loader(&test_policy_definitions::kList); + PolicyLoaderWin loader(&test_policy_definitions::kList, kTestPolicyKey, + this); scoped_ptr<PolicyBundle> loaded(loader.Load()); return loaded->Equals(expected); } + void InstallRegistrySentinel() { + RegKey hklm_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS); + ASSERT_TRUE(hklm_key.Valid()); + hklm_key.WriteValue( + UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), + UTF8ToUTF16("registry").c_str()); + } + + bool MatchesRegistrySentinel() { + base::DictionaryValue expected_policy; + expected_policy.SetString(test_policy_definitions::kKeyString, "registry"); + PolicyBundle expected; + expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); + return Matches(expected); + } + + bool MatchesTestBundle() { + base::DictionaryValue expected_policy; + expected_policy.SetBoolean(test_policy_definitions::kKeyBoolean, true); + expected_policy.SetString(test_policy_definitions::kKeyString, "GPO"); + expected_policy.SetInteger(test_policy_definitions::kKeyInteger, 42); + scoped_ptr<base::ListValue> list(new base::ListValue()); + list->AppendString("GPO 1"); + list->AppendString("GPO 2"); + expected_policy.Set(test_policy_definitions::kKeyStringList, + list.release()); + PolicyBundle expected; + expected.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())) + .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE); + return Matches(expected); + } + ScopedGroupPolicyRegistrySandbox registry_sandbox_; + PGROUP_POLICY_OBJECT gpo_list_; + DWORD gpo_list_status_; + base::FilePath test_data_dir_; }; +const char16 PolicyLoaderWinTest::kTestPolicyKey[] = + L"SOFTWARE\\Policies\\Chromium"; + TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) { - RegKey hklm_key(HKEY_LOCAL_MACHINE, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey hklm_key(HKEY_LOCAL_MACHINE, kTestPolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(hklm_key.Valid()); hklm_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), UTF8ToUTF16("hklm").c_str()); - RegKey hkcu_key(HKEY_CURRENT_USER, kRegistryMandatorySubKey, KEY_ALL_ACCESS); + RegKey hkcu_key(HKEY_CURRENT_USER, kTestPolicyKey, KEY_ALL_ACCESS); ASSERT_TRUE(hkcu_key.Valid()); hkcu_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), UTF8ToUTF16("hkcu").c_str()); @@ -469,7 +584,7 @@ TEST_F(PolicyLoaderWinTest, Load3rdPartyWithoutSchema) { policy_dict.Set("extensions.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.policy", dict.DeepCopy()); EXPECT_TRUE(InstallValue(policy_dict, HKEY_LOCAL_MACHINE, - kRegistryMandatorySubKey, kThirdParty)); + kTestPolicyKey, kThirdParty)); PolicyBundle expected; expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, @@ -486,7 +601,7 @@ TEST_F(PolicyLoaderWinTest, Merge3rdPartyPolicies) { // combinations, to verify that they overlap as expected. const string16 kPathSuffix = - kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge"); + kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\merge"); const char kUserMandatory[] = "user-mandatory"; const char kUserRecommended[] = "user-recommended"; @@ -558,7 +673,7 @@ TEST_F(PolicyLoaderWinTest, LoadStringEncodedValues) { encoded_policy.SetString("dict", encoded_dict); const string16 kPathSuffix = - kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\string"); + kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\string"); EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema)); EXPECT_TRUE( InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory)); @@ -581,7 +696,7 @@ TEST_F(PolicyLoaderWinTest, LoadIntegerEncodedValues) { encoded_policy.SetInteger("double", 456); const string16 kPathSuffix = - kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\int"); + kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\int"); EXPECT_TRUE(InstallSchema(policy, HKEY_CURRENT_USER, kPathSuffix, kSchema)); EXPECT_TRUE( InstallValue(encoded_policy, HKEY_CURRENT_USER, kPathSuffix, kMandatory)); @@ -607,7 +722,7 @@ TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) { schema.Set(schema::kAdditionalProperties, default_schema.DeepCopy()); const string16 kPathSuffix = - kRegistryMandatorySubKey + ASCIIToUTF16("\\3rdparty\\extensions\\test"); + kTestPolicyKey + ASCIIToUTF16("\\3rdparty\\extensions\\test"); EXPECT_TRUE(WriteSchema(schema, HKEY_CURRENT_USER, kPathSuffix, kSchema)); // Write some test values. @@ -626,10 +741,120 @@ TEST_F(PolicyLoaderWinTest, DefaultPropertySchemaType) { expected_policy.SetInteger("special-int2", -456); expected_policy.SetDouble("double1", 789.0); expected_policy.SetDouble("double2", 123.456e7); + expected_policy.Set("invalid", base::Value::CreateNullValue()); PolicyBundle expected; expected.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "test")) .LoadFrom(&expected_policy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); EXPECT_TRUE(Matches(expected)); } +TEST_F(PolicyLoaderWinTest, AppliedPolicyNotPresent) { + InstallRegistrySentinel(); + gpo_list_ = NULL; + gpo_list_status_ = ERROR_SUCCESS; + + PolicyBundle empty; + EXPECT_TRUE(Matches(empty)); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyEmpty) { + InstallRegistrySentinel(); + base::FilePath gpo_dir(test_data_dir_.AppendASCII("empty")); + GROUP_POLICY_OBJECT gpo; + InitGPO(&gpo, 0, gpo_dir, NULL, NULL); + gpo_list_ = &gpo; + gpo_list_status_ = ERROR_SUCCESS; + + PolicyBundle empty; + EXPECT_TRUE(Matches(empty)); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyNonExistingFile) { + InstallRegistrySentinel(); + GROUP_POLICY_OBJECT gpo; + InitGPO(&gpo, 0, test_data_dir_, NULL, NULL); + gpo_list_ = &gpo; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesRegistrySentinel()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyBadPath) { + InstallRegistrySentinel(); + base::FilePath gpo_dir(test_data_dir_.AppendASCII("bad")); + GROUP_POLICY_OBJECT gpo; + InitGPO(&gpo, 0, gpo_dir, NULL, NULL); + gpo_list_ = &gpo; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesRegistrySentinel()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyPresent) { + InstallRegistrySentinel(); + base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1")); + GROUP_POLICY_OBJECT gpo; + InitGPO(&gpo, 0, gpo_dir, NULL, NULL); + gpo_list_ = &gpo; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesTestBundle()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyMerged) { + InstallRegistrySentinel(); + base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test2")); + base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test1")); + GROUP_POLICY_OBJECT gpo1; + GROUP_POLICY_OBJECT gpo2; + InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL); + InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1); + gpo_list_ = &gpo1; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesTestBundle()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyDisabled) { + InstallRegistrySentinel(); + base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1")); + base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2")); + GROUP_POLICY_OBJECT gpo1; + GROUP_POLICY_OBJECT gpo2; + InitGPO(&gpo1, 0, gpo1_dir, &gpo2, NULL); + InitGPO(&gpo2, GPO_FLAG_DISABLE, gpo2_dir, NULL, &gpo1); + gpo_list_ = &gpo1; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesTestBundle()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyForcedPolicy) { + InstallRegistrySentinel(); + base::FilePath gpo1_dir(test_data_dir_.AppendASCII("test1")); + base::FilePath gpo2_dir(test_data_dir_.AppendASCII("test2")); + GROUP_POLICY_OBJECT gpo1; + GROUP_POLICY_OBJECT gpo2; + InitGPO(&gpo1, GPO_FLAG_FORCE, gpo1_dir, &gpo2, NULL); + InitGPO(&gpo2, 0, gpo2_dir, NULL, &gpo1); + gpo_list_ = &gpo1; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesTestBundle()); +} + +TEST_F(PolicyLoaderWinTest, AppliedPolicyUNCPath) { + InstallRegistrySentinel(); + base::FilePath gpo_dir(test_data_dir_.AppendASCII("test1")); + base::FilePath unc_path(L"\\\\some_share\\GPO"); + GROUP_POLICY_OBJECT gpo1; + GROUP_POLICY_OBJECT gpo2; + InitGPO(&gpo1, 0, gpo_dir, &gpo2, NULL); + InitGPO(&gpo2, 0, unc_path, NULL, &gpo1); + gpo_list_ = &gpo1; + gpo_list_status_ = ERROR_SUCCESS; + + EXPECT_TRUE(MatchesRegistrySentinel()); +} + } // namespace policy diff --git a/chrome/browser/policy/policy_path_parser_win.cc b/chrome/browser/policy/policy_path_parser_win.cc index c6c5ed9..b8216bc 100644 --- a/chrome/browser/policy/policy_path_parser_win.cc +++ b/chrome/browser/policy/policy_path_parser_win.cc @@ -25,7 +25,7 @@ bool LoadUserDataDirPolicyFromRegistry(HKEY hive, std::wstring value; base::win::RegKey policy_key(hive, - policy::kRegistryMandatorySubKey, + policy::kRegistryChromePolicyKey, KEY_READ); if (policy_key.ReadValue(key_name.c_str(), &value) == ERROR_SUCCESS) { *user_data_dir = diff --git a/chrome/tools/build/generate_policy_source.py b/chrome/tools/build/generate_policy_source.py index 5809e84..0892933 100755 --- a/chrome/tools/build/generate_policy_source.py +++ b/chrome/tools/build/generate_policy_source.py @@ -17,10 +17,8 @@ import sys import textwrap -CHROME_MANDATORY_SUBKEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' -CHROME_RECOMMENDED_SUBKEY = CHROME_MANDATORY_SUBKEY + '\\\\Recommended' -CHROMIUM_MANDATORY_SUBKEY = 'SOFTWARE\\\\Policies\\\\Chromium' -CHROMIUM_RECOMMENDED_SUBKEY = CHROMIUM_MANDATORY_SUBKEY + '\\\\Recommended' +CHROME_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Google\\\\Chrome' +CHROMIUM_POLICY_KEY = 'SOFTWARE\\\\Policies\\\\Chromium' class PolicyDetails: @@ -193,12 +191,9 @@ def _WritePolicyConstantHeader(policies, os, f): 'namespace policy {\n\n') if os == 'win': - f.write('// The windows registry path where mandatory policy ' + f.write('// The windows registry path where Chrome policy ' 'configuration resides.\n' - 'extern const wchar_t kRegistryMandatorySubKey[];\n' - '// The windows registry path where recommended policy ' - 'configuration resides.\n' - 'extern const wchar_t kRegistryRecommendedSubKey[];\n\n') + 'extern const wchar_t kRegistryChromePolicyKey[];\n') f.write('// Lists policy types mapped to their names and expected types.\n' '// Used to initialize ConfigurationPolicyProviders.\n' @@ -267,15 +262,11 @@ def _WritePolicyConstantSource(policies, os, f): if os == 'win': f.write('#if defined(GOOGLE_CHROME_BUILD)\n' - 'const wchar_t kRegistryMandatorySubKey[] = ' - 'L"' + CHROME_MANDATORY_SUBKEY + '";\n' - 'const wchar_t kRegistryRecommendedSubKey[] = ' - 'L"' + CHROME_RECOMMENDED_SUBKEY + '";\n' + 'const wchar_t kRegistryChromePolicyKey[] = ' + 'L"' + CHROME_POLICY_KEY + '";\n' '#else\n' - 'const wchar_t kRegistryMandatorySubKey[] = ' - 'L"' + CHROMIUM_MANDATORY_SUBKEY + '";\n' - 'const wchar_t kRegistryRecommendedSubKey[] = ' - 'L"' + CHROMIUM_RECOMMENDED_SUBKEY + '";\n' + 'const wchar_t kRegistryChromePolicyKey[] = ' + 'L"' + CHROMIUM_POLICY_KEY + '";\n' '#endif\n\n') f.write('bool IsDeprecatedPolicy(const std::string& policy) {\n' diff --git a/chrome_frame/chrome_launcher.cc b/chrome_frame/chrome_launcher.cc index 88fc0da..28613f4 100644 --- a/chrome_frame/chrome_launcher.cc +++ b/chrome_frame/chrome_launcher.cc @@ -164,7 +164,7 @@ void AppendAdditionalLaunchParameters(std::wstring* command_line) { LONG result; bool found = false; for (int i = 0; !found && i < arraysize(kRootKeys); ++i) { - result = ::RegOpenKeyExW(kRootKeys[i], policy::kRegistryMandatorySubKey, 0, + result = ::RegOpenKeyExW(kRootKeys[i], policy::kRegistryChromePolicyKey, 0, KEY_QUERY_VALUE, &key); if (result == ERROR_SUCCESS) { DWORD size = 0; diff --git a/chrome_frame/policy_settings.cc b/chrome_frame/policy_settings.cc index bc873e8..846fd99 100644 --- a/chrome_frame/policy_settings.cc +++ b/chrome_frame/policy_settings.cc @@ -74,7 +74,7 @@ void PolicySettings::ReadUrlSettings( std::wstring settings_value( ASCIIToWide(policy::key::kChromeFrameRendererSettings)); for (int i = 0; i < arraysize(kRootKeys); ++i) { - if ((config_key.Open(kRootKeys[i], policy::kRegistryMandatorySubKey, + if ((config_key.Open(kRootKeys[i], policy::kRegistryChromePolicyKey, KEY_READ) == ERROR_SUCCESS) && (config_key.ReadValueDW(settings_value.c_str(), &value) == ERROR_SUCCESS)) { @@ -109,7 +109,7 @@ void PolicySettings::ReadContentTypeSetting( std::vector<std::wstring>* content_type_list) { DCHECK(content_type_list); - std::wstring sub_key(policy::kRegistryMandatorySubKey); + std::wstring sub_key(policy::kRegistryChromePolicyKey); sub_key += L"\\"; sub_key += ASCIIToWide(policy::key::kChromeFrameContentTypes); @@ -128,7 +128,7 @@ void PolicySettings::ReadStringSetting(const char* value_name, base::win::RegKey config_key; std::wstring value_name_str(ASCIIToWide(value_name)); for (int i = 0; i < arraysize(kRootKeys); ++i) { - if ((config_key.Open(kRootKeys[i], policy::kRegistryMandatorySubKey, + if ((config_key.Open(kRootKeys[i], policy::kRegistryChromePolicyKey, KEY_READ) == ERROR_SUCCESS) && (config_key.ReadValue(value_name_str.c_str(), value) == ERROR_SUCCESS)) { diff --git a/chrome_frame/test/policy_settings_unittest.cc b/chrome_frame/test/policy_settings_unittest.cc index e13af50..343b426 100644 --- a/chrome_frame/test/policy_settings_unittest.cc +++ b/chrome_frame/test/policy_settings_unittest.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/basictypes.h" #include "base/at_exit.h" +#include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/stringprintf.h" @@ -23,7 +23,7 @@ namespace { // A best effort way to zap CF policy entries that may be in the registry. void DeleteChromeFramePolicyEntries(HKEY root) { RegKey key; - if (key.Open(root, policy::kRegistryMandatorySubKey, + if (key.Open(root, policy::kRegistryChromePolicyKey, KEY_ALL_ACCESS) == ERROR_SUCCESS) { key.DeleteValue( ASCIIToWide(policy::key::kChromeFrameRendererSettings).c_str()); @@ -36,7 +36,7 @@ void DeleteChromeFramePolicyEntries(HKEY root) { bool InitializePolicyKey(HKEY policy_root, RegKey* policy_key) { EXPECT_EQ(ERROR_SUCCESS, policy_key->Create(policy_root, - policy::kRegistryMandatorySubKey, KEY_ALL_ACCESS)); + policy::kRegistryChromePolicyKey, KEY_ALL_ACCESS)); return policy_key->Valid(); } |