diff options
author | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 15:51:50 +0000 |
---|---|---|
committer | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 15:51:50 +0000 |
commit | 326cf715e5e1ea9d012782ae3b18458cf9cf26cc (patch) | |
tree | 4e1dc6c379acabb4608d58f6213433edee6467e9 | |
parent | 0f6e6627eb5fa4fdf7a1764be83e4372f24ca105 (diff) | |
download | chromium_src-326cf715e5e1ea9d012782ae3b18458cf9cf26cc.zip chromium_src-326cf715e5e1ea9d012782ae3b18458cf9cf26cc.tar.gz chromium_src-326cf715e5e1ea9d012782ae3b18458cf9cf26cc.tar.bz2 |
Implement the windows policy provider based on the AsyncPolicyLoader.
BUG=130918
TEST=windows policy still works, unit_tests green
Review URL: https://chromiumcodereview.appspot.com/10491013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140770 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/policy/browser_policy_connector.cc | 5 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_loader_win.cc | 89 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_loader_win.h | 53 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_provider_delegate_win.h | 32 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_provider_win.cc | 28 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_provider_win.h | 31 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win.cc | 313 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win.h | 51 | ||||
-rw-r--r-- | chrome/browser/policy/policy_loader_win_unittest.cc | 251 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 8 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 |
11 files changed, 621 insertions, 242 deletions
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc index f6e1a1c..e396545 100644 --- a/chrome/browser/policy/browser_policy_connector.cc +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -33,7 +33,7 @@ #include "policy/policy_constants.h" #if defined(OS_WIN) -#include "chrome/browser/policy/configuration_policy_provider_win.h" +#include "chrome/browser/policy/policy_loader_win.h" #elif defined(OS_MACOSX) #include "chrome/browser/policy/policy_loader_mac.h" #include "chrome/browser/preferences_mac.h" @@ -557,7 +557,8 @@ ConfigurationPolicyProvider* BrowserPolicyConnector::CreatePlatformProvider() { const PolicyDefinitionList* policy_list = GetChromePolicyDefinitionList(); #if defined(OS_WIN) - return new ConfigurationPolicyProviderWin(policy_list); + scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(policy_list)); + return new AsyncPolicyProvider(policy_list, loader.Pass()); #elif defined(OS_MACOSX) scoped_ptr<AsyncPolicyLoader> loader( new PolicyLoaderMac(policy_list, new MacPreferences())); diff --git a/chrome/browser/policy/configuration_policy_loader_win.cc b/chrome/browser/policy/configuration_policy_loader_win.cc deleted file mode 100644 index 03d12d1..0000000 --- a/chrome/browser/policy/configuration_policy_loader_win.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/policy/configuration_policy_loader_win.h" - -#include <userenv.h> - -#include "content/public/browser/browser_thread.h" - -// userenv.dll is required for RegisterGPNotification(). -#pragma comment(lib, "userenv.lib") - -using content::BrowserThread; - -namespace policy { - -ConfigurationPolicyLoaderWin::ConfigurationPolicyLoaderWin( - AsynchronousPolicyProvider::Delegate* delegate, - int reload_interval_minutes) - : AsynchronousPolicyLoader(delegate, reload_interval_minutes), - user_policy_changed_event_(false, false), - machine_policy_changed_event_(false, false), - user_policy_watcher_failed_(false), - machine_policy_watcher_failed_(false) { - if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { - PLOG(WARNING) << "Failed to register user group policy notification"; - user_policy_watcher_failed_ = true; - } - if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { - PLOG(WARNING) << "Failed to register machine group policy notification."; - machine_policy_watcher_failed_ = true; - } -} - -void ConfigurationPolicyLoaderWin::Reload(bool force) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - // Reset the watches BEFORE reading the individual policies to avoid - // missing a change notification. - SetupWatches(); - AsynchronousPolicyLoader::Reload(force); -} - -void ConfigurationPolicyLoaderWin::InitOnFileThread() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - AsynchronousPolicyLoader::InitOnFileThread(); - SetupWatches(); -} - -void ConfigurationPolicyLoaderWin::StopOnFileThread() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - user_policy_watcher_.StopWatching(); - machine_policy_watcher_.StopWatching(); - AsynchronousPolicyLoader::StopOnFileThread(); -} - -void ConfigurationPolicyLoaderWin::SetupWatches() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - CancelReloadTask(); - - if (!user_policy_watcher_failed_ && - !user_policy_watcher_.GetWatchedObject() && - !user_policy_watcher_.StartWatching( - user_policy_changed_event_.handle(), this)) { - LOG(WARNING) << "Failed to start watch for user policy change event"; - user_policy_watcher_failed_ = true; - } - if (!machine_policy_watcher_failed_ && - !machine_policy_watcher_.GetWatchedObject() && - !machine_policy_watcher_.StartWatching( - machine_policy_changed_event_.handle(), this)) { - LOG(WARNING) << "Failed to start watch for machine policy change event"; - machine_policy_watcher_failed_ = true; - } - - if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) - ScheduleFallbackReloadTask(); -} - -void ConfigurationPolicyLoaderWin::OnObjectSignaled(HANDLE object) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(object == user_policy_changed_event_.handle() || - object == machine_policy_changed_event_.handle()) - << "unexpected object signaled policy reload, obj = " - << std::showbase << std::hex << object; - Reload(false); -} - -} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_loader_win.h b/chrome/browser/policy/configuration_policy_loader_win.h deleted file mode 100644 index d0317a9..0000000 --- a/chrome/browser/policy/configuration_policy_loader_win.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ -#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ -#pragma once - -#include "base/synchronization/waitable_event.h" -#include "base/win/object_watcher.h" -#include "chrome/browser/policy/asynchronous_policy_loader.h" - -namespace policy { - -// Keeps watch on Windows Group Policy notification event to trigger a policy -// reload when Group Policy changes. -class ConfigurationPolicyLoaderWin - : public AsynchronousPolicyLoader, - public base::win::ObjectWatcher::Delegate { - public: - ConfigurationPolicyLoaderWin( - AsynchronousPolicyProvider::Delegate* delegate, - int reload_interval_minutes); - virtual ~ConfigurationPolicyLoaderWin() {} - - // AsynchronousPolicyLoader overrides: - virtual void Reload(bool force) OVERRIDE; - - protected: - // AsynchronousPolicyLoader overrides: - virtual void InitOnFileThread() OVERRIDE; - virtual void StopOnFileThread() OVERRIDE; - - private: - // Updates the watchers and schedules the reload task if appropriate. - void SetupWatches(); - - // ObjectWatcher::Delegate overrides: - virtual void OnObjectSignaled(HANDLE object) OVERRIDE; - - base::WaitableEvent user_policy_changed_event_; - base::WaitableEvent machine_policy_changed_event_; - base::win::ObjectWatcher user_policy_watcher_; - base::win::ObjectWatcher machine_policy_watcher_; - bool user_policy_watcher_failed_; - bool machine_policy_watcher_failed_; - - DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyLoaderWin); -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_LOADER_WIN_H_ diff --git a/chrome/browser/policy/configuration_policy_provider_delegate_win.h b/chrome/browser/policy/configuration_policy_provider_delegate_win.h deleted file mode 100644 index a8e41792..0000000 --- a/chrome/browser/policy/configuration_policy_provider_delegate_win.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ -#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ -#pragma once - -#include "base/string16.h" -#include "chrome/browser/policy/asynchronous_policy_provider.h" - -namespace policy { - -class ConfigurationPolicyProviderDelegateWin - : public AsynchronousPolicyProvider::Delegate { - public: - explicit ConfigurationPolicyProviderDelegateWin( - const PolicyDefinitionList* policy_definition_list); - virtual ~ConfigurationPolicyProviderDelegateWin() {} - - // AsynchronousPolicyProvider::Delegate overrides: - virtual scoped_ptr<PolicyBundle> Load() OVERRIDE; - - private: - const PolicyDefinitionList* policy_definition_list_; - - DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderDelegateWin); -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_DELEGATE_WIN_H_ diff --git a/chrome/browser/policy/configuration_policy_provider_win.cc b/chrome/browser/policy/configuration_policy_provider_win.cc deleted file mode 100644 index 1ce4579..0000000 --- a/chrome/browser/policy/configuration_policy_provider_win.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/policy/configuration_policy_provider_win.h" - -#include "chrome/browser/policy/configuration_policy_loader_win.h" -#include "chrome/browser/policy/configuration_policy_provider_delegate_win.h" - -namespace policy { - -namespace { - -// Period at which to run the reload task in case the group policy change -// watchers fail. -const int kReloadIntervalMinutes = 15; - -} // namespace - -ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin( - const PolicyDefinitionList* policy_list) - : AsynchronousPolicyProvider( - policy_list, - new ConfigurationPolicyLoaderWin( - new ConfigurationPolicyProviderDelegateWin(policy_list), - kReloadIntervalMinutes)) {} - -} // namespace policy diff --git a/chrome/browser/policy/configuration_policy_provider_win.h b/chrome/browser/policy/configuration_policy_provider_win.h deleted file mode 100644 index 8d3b67a..0000000 --- a/chrome/browser/policy/configuration_policy_provider_win.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ -#define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ -#pragma once - -#include "chrome/browser/policy/asynchronous_policy_provider.h" - -namespace policy { - -// An implementation of |ConfigurationPolicyProvider| using the -// mechanism provided by Windows Groups Policy. Policy decisions are -// stored as values in a special section of the Windows Registry. -// On a managed machine in a domain, this portion of the registry is -// periodically updated by the Windows Group Policy machinery to contain -// the latest version of the policy set by administrators. -class ConfigurationPolicyProviderWin : public AsynchronousPolicyProvider { - public: - explicit ConfigurationPolicyProviderWin( - const PolicyDefinitionList* policy_list); - virtual ~ConfigurationPolicyProviderWin() {} - - private: - DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyProviderWin); -}; - -} // namespace policy - -#endif // CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_PROVIDER_WIN_H_ diff --git a/chrome/browser/policy/policy_loader_win.cc b/chrome/browser/policy/policy_loader_win.cc new file mode 100644 index 0000000..c1f1351 --- /dev/null +++ b/chrome/browser/policy/policy_loader_win.cc @@ -0,0 +1,313 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/policy_loader_win.h" + +#include <string> + +#include <string.h> + +#include <userenv.h> + +// userenv.dll is required for RegisterGPNotification(). +#pragma comment(lib, "userenv.lib") + +#include "base/basictypes.h" +#include "base/json/json_reader.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/string16.h" +#include "base/string_number_conversions.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 "policy/policy_constants.h" + +using base::win::RegKey; + +namespace policy { + +namespace { + +// Determines the registry key with the highest priority that contains +// the |key_path| key with a |value_name| value inside. +// |key_path| is a suffix to the Chrome mandatory or recommended registry key, +// and can be empty to lookup values directly at that key. +// |value_name| is the name of a value that should exist at that path. If it +// is empty, then only the existence of the path is verified. +// Returns true if |key| was updated to point to a key with a |key_path| suffix +// and optional |value_name| value inside. In that case, |level| and |scope| +// will contain the appropriate values for the key found. +// Returns false otherwise. +bool LoadHighestPriorityKey(const string16& key_path, + const string16& value_name, + RegKey* key, + PolicyLevel* level, + PolicyScope* scope) { + // |path| is in decreasing order of priority. + static const struct { + const wchar_t* path; + PolicyLevel level; + } key_paths[] = { + { kRegistryMandatorySubKey, POLICY_LEVEL_MANDATORY }, + { kRegistryRecommendedSubKey, POLICY_LEVEL_RECOMMENDED }, + }; + + // |hive| is in decreasing order of priority. + static const struct { + HKEY hive; + PolicyScope scope; + } hives[] = { + { HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE }, + { HKEY_CURRENT_USER, POLICY_SCOPE_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(key_paths); ++k) { + for (size_t h = 0; h < arraysize(hives); ++h) { + string16 path(key_paths[k].path); + if (!key_path.empty()) + path += ASCIIToUTF16("\\") + key_path; + key->Open(hives[h].hive, path.c_str(), KEY_READ); + if (!key->Valid()) + continue; + if (value_name.empty() || key->HasValue(value_name.c_str())) { + *level = key_paths[k].level; + *scope = hives[h].scope; + return true; + } + } + } + return false; +} + +// 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; + + if (key->ReadValue(name.c_str(), 0, &value_size, &key_type) != ERROR_SUCCESS) + return false; + if (key_type != REG_SZ) + return false; + + // 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; +} + +// 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; +} + +// Returns the Value for a Chrome string policy named |name|, or NULL if +// it wasn't found. The caller owns the returned value. +base::Value* ReadStringValue(const string16& name, + PolicyLevel* level, + PolicyScope* scope) { + RegKey key; + if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) + return NULL; + string16 value; + if (!ReadRegistryString(&key, name, &value)) + return NULL; + return base::Value::CreateStringValue(value); +} + +// Returns the Value for a Chrome string list policy named |name|, +// or NULL if it wasn't found. The caller owns the returned value. +base::Value* ReadStringListValue(const string16& name, + PolicyLevel* level, + PolicyScope* scope) { + RegKey key; + if (!LoadHighestPriorityKey(name, string16(), &key, level, scope)) + return NULL; + base::ListValue* result = new base::ListValue(); + string16 value; + int index = 0; + while (ReadRegistryString(&key, base::IntToString16(++index), &value)) + result->Append(base::Value::CreateStringValue(value)); + return result; +} + +// Returns the Value for a Chrome boolean policy named |name|, +// or NULL if it wasn't found. The caller owns the returned value. +base::Value* ReadBooleanValue(const string16& name, + PolicyLevel* level, + PolicyScope* scope) { + RegKey key; + if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) + return NULL; + uint32 value; + if (!ReadRegistryInteger(&key, name, &value)) + return NULL; + return base::Value::CreateBooleanValue(value != 0u); +} + +// Returns the Value for a Chrome integer policy named |name|, +// or NULL if it wasn't found. The caller owns the returned value. +base::Value* ReadIntegerValue(const string16& name, + PolicyLevel* level, + PolicyScope* scope) { + RegKey key; + if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) + return NULL; + uint32 value; + if (!ReadRegistryInteger(&key, name, &value)) + return NULL; + return base::Value::CreateIntegerValue(value); +} + +// Returns the Value for a Chrome dictionary policy named |name|, +// or NULL if it wasn't found. The caller owns the returned value. +base::Value* ReadDictionaryValue(const string16& name, + PolicyLevel* level, + PolicyScope* scope) { + // Dictionaries are encoded as JSON strings on Windows. + // + // A dictionary could be stored as a subkey, with each of its entries + // within that subkey. However, it would be impossible to recover the + // type for some of those entries: + // - Booleans are stored as DWORDS and are indistinguishable from + // integers; + // - Lists are stored as a subkey, with entries mapping 0 to N-1 to + // their value. This is indistinguishable from a Dictionary with + // integer keys. + // + // The GPO policy editor also has a limited data entry form that doesn't + // support dictionaries. + RegKey key; + if (!LoadHighestPriorityKey(string16(), name, &key, level, scope)) + return NULL; + string16 value; + if (!ReadRegistryString(&key, name, &value)) + return NULL; + return base::JSONReader::Read(UTF16ToUTF8(value)); +} + +} // namespace + +PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list) + : is_initialized_(false), + policy_list_(policy_list), + user_policy_changed_event_(false, false), + machine_policy_changed_event_(false, false), + user_policy_watcher_failed_(false), + machine_policy_watcher_failed_(false) { + if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) { + DPLOG(WARNING) << "Failed to register user group policy notification"; + user_policy_watcher_failed_ = true; + } + if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) { + DPLOG(WARNING) << "Failed to register machine group policy notification."; + machine_policy_watcher_failed_ = true; + } +} + +PolicyLoaderWin::~PolicyLoaderWin() { + user_policy_watcher_.StopWatching(); + machine_policy_watcher_.StopWatching(); +} + +void PolicyLoaderWin::InitOnFile() { + is_initialized_ = true; + SetupWatches(); +} + +scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { + // Reset the watches BEFORE reading the individual policies to avoid + // missing a change notification. + if (is_initialized_) + SetupWatches(); + + scoped_ptr<PolicyBundle> bundle(new PolicyBundle()); + PolicyMap& chrome_policy = bundle->Get(POLICY_DOMAIN_CHROME, std::string()); + + const PolicyDefinitionList::Entry* current; + for (current = policy_list_->begin; current != policy_list_->end; ++current) { + const string16 name(ASCIIToUTF16(current->name)); + PolicyLevel level = POLICY_LEVEL_MANDATORY; + PolicyScope scope = POLICY_SCOPE_MACHINE; + Value* value = NULL; + + switch (current->value_type) { + case Value::TYPE_STRING: + value = ReadStringValue(name, &level, &scope); + break; + + case Value::TYPE_LIST: + value = ReadStringListValue(name, &level, &scope); + break; + + case Value::TYPE_BOOLEAN: + value = ReadBooleanValue(name, &level, &scope); + break; + + case Value::TYPE_INTEGER: + value = ReadIntegerValue(name, &level, &scope); + break; + + case Value::TYPE_DICTIONARY: + value = ReadDictionaryValue(name, &level, &scope); + break; + + default: + NOTREACHED(); + } + + if (value) + chrome_policy.Set(current->name, level, scope, value); + } + + return bundle.Pass(); +} + +void PolicyLoaderWin::SetupWatches() { + DCHECK(is_initialized_); + if (!user_policy_watcher_failed_ && + !user_policy_watcher_.GetWatchedObject() && + !user_policy_watcher_.StartWatching( + user_policy_changed_event_.handle(), this)) { + DLOG(WARNING) << "Failed to start watch for user policy change event"; + user_policy_watcher_failed_ = true; + } + if (!machine_policy_watcher_failed_ && + !machine_policy_watcher_.GetWatchedObject() && + !machine_policy_watcher_.StartWatching( + machine_policy_changed_event_.handle(), this)) { + DLOG(WARNING) << "Failed to start watch for machine policy change event"; + machine_policy_watcher_failed_ = true; + } +} + +void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { + DCHECK(object == user_policy_changed_event_.handle() || + object == machine_policy_changed_event_.handle()) + << "unexpected object signaled policy reload, obj = " + << std::showbase << std::hex << object; + Reload(false); +} + +} // namespace policy diff --git a/chrome/browser/policy/policy_loader_win.h b/chrome/browser/policy/policy_loader_win.h new file mode 100644 index 0000000..7a5b7f8 --- /dev/null +++ b/chrome/browser/policy/policy_loader_win.h @@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_POLICY_POLICY_LOADER_WIN_H_ +#define CHROME_BROWSER_POLICY_POLICY_LOADER_WIN_H_ +#pragma once + +#include "base/synchronization/waitable_event.h" +#include "base/win/object_watcher.h" +#include "chrome/browser/policy/async_policy_loader.h" + +namespace policy { + +struct PolicyDefinitionList; + +// 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); + virtual ~PolicyLoaderWin(); + + // AsyncPolicyLoader implementation. + virtual void InitOnFile() OVERRIDE; + virtual scoped_ptr<PolicyBundle> Load() OVERRIDE; + + private: + // Installs the watchers for the Group Policy update events. + void SetupWatches(); + + // ObjectWatcher::Delegate overrides: + virtual void OnObjectSignaled(HANDLE object) OVERRIDE; + + bool is_initialized_; + const PolicyDefinitionList* policy_list_; + + base::WaitableEvent user_policy_changed_event_; + base::WaitableEvent machine_policy_changed_event_; + base::win::ObjectWatcher user_policy_watcher_; + base::win::ObjectWatcher machine_policy_watcher_; + bool user_policy_watcher_failed_; + bool machine_policy_watcher_failed_; + + DISALLOW_COPY_AND_ASSIGN(PolicyLoaderWin); +}; + +} // 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 new file mode 100644 index 0000000..949392e --- /dev/null +++ b/chrome/browser/policy/policy_loader_win_unittest.cc @@ -0,0 +1,251 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/policy_loader_win.h" + +#include <windows.h> + +#include "base/json/json_writer.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "base/win/registry.h" +#include "chrome/browser/policy/async_policy_provider.h" +#include "chrome/browser/policy/configuration_policy_provider_test.h" +#include "chrome/browser/policy/policy_bundle.h" +#include "chrome/browser/policy/policy_map.h" +#include "policy/policy_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::win::RegKey; + +namespace policy { + +namespace { + +const wchar_t kUnitTestRegistrySubKey[] = L"SOFTWARE\\Chromium Unit Tests"; +const wchar_t kUnitTestMachineOverrideSubKey[] = + L"SOFTWARE\\Chromium Unit Tests\\HKLM Override"; +const wchar_t kUnitTestUserOverrideSubKey[] = + L"SOFTWARE\\Chromium Unit Tests\\HKCU Override"; + +// This class provides sandboxing and mocking for the parts of the Windows +// Registry implementing Group Policy. It prepares two temporary sandbox keys +// in |kUnitTestRegistrySubKey|, one for HKLM and one for HKCU. A test's calls +// to the registry are redirected by Windows to these sandboxes, allowing the +// tests to manipulate and access policy as if it were active, but without +// actually changing the parts of the Registry that are managed by Group +// Policy. +class ScopedGroupPolicyRegistrySandbox { + public: + ScopedGroupPolicyRegistrySandbox(); + ~ScopedGroupPolicyRegistrySandbox(); + + private: + void ActivateOverrides(); + void RemoveOverrides(); + + // Deletes the sandbox keys. + void DeleteKeys(); + + // Keys are created for the lifetime of a test to contain + // the sandboxed HKCU and HKLM hives, respectively. + RegKey temp_hkcu_hive_key_; + RegKey temp_hklm_hive_key_; + + DISALLOW_COPY_AND_ASSIGN(ScopedGroupPolicyRegistrySandbox); +}; + +class TestHarness : public PolicyProviderTestHarness { + public: + explicit TestHarness(HKEY hive, PolicyScope scope); + virtual ~TestHarness(); + + virtual void SetUp() OVERRIDE; + + virtual ConfigurationPolicyProvider* CreateProvider( + const PolicyDefinitionList* policy_definition_list) OVERRIDE; + + virtual void InstallEmptyPolicy() OVERRIDE; + virtual void InstallStringPolicy(const std::string& policy_name, + const std::string& policy_value) OVERRIDE; + virtual void InstallIntegerPolicy(const std::string& policy_name, + int policy_value) OVERRIDE; + virtual void InstallBooleanPolicy(const std::string& policy_name, + bool policy_value) OVERRIDE; + virtual void InstallStringListPolicy( + const std::string& policy_name, + const base::ListValue* policy_value) OVERRIDE; + virtual void InstallDictionaryPolicy( + const std::string& policy_name, + const base::DictionaryValue* policy_value) OVERRIDE; + + // Creates a harness instance that will install policy in HKCU or HKLM, + // respectively. + static PolicyProviderTestHarness* CreateHKCU(); + static PolicyProviderTestHarness* CreateHKLM(); + + private: + HKEY hive_; + + ScopedGroupPolicyRegistrySandbox registry_sandbox_; + + DISALLOW_COPY_AND_ASSIGN(TestHarness); +}; + +ScopedGroupPolicyRegistrySandbox::ScopedGroupPolicyRegistrySandbox() { + // Cleanup any remnants of previous tests. + DeleteKeys(); + + // Create the subkeys to hold the overridden HKLM and HKCU + // policy settings. + temp_hklm_hive_key_.Create(HKEY_CURRENT_USER, + kUnitTestMachineOverrideSubKey, + KEY_ALL_ACCESS); + temp_hkcu_hive_key_.Create(HKEY_CURRENT_USER, + kUnitTestUserOverrideSubKey, + KEY_ALL_ACCESS); + + ActivateOverrides(); +} + +ScopedGroupPolicyRegistrySandbox::~ScopedGroupPolicyRegistrySandbox() { + RemoveOverrides(); + DeleteKeys(); +} + +void ScopedGroupPolicyRegistrySandbox::ActivateOverrides() { + ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, + temp_hklm_hive_key_.Handle())); + ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, + temp_hkcu_hive_key_.Handle())); +} + +void ScopedGroupPolicyRegistrySandbox::RemoveOverrides() { + ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_LOCAL_MACHINE, 0)); + ASSERT_HRESULT_SUCCEEDED(RegOverridePredefKey(HKEY_CURRENT_USER, 0)); +} + +void ScopedGroupPolicyRegistrySandbox::DeleteKeys() { + RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS); + key.DeleteKey(L""); +} + +TestHarness::TestHarness(HKEY hive, PolicyScope scope) + : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, scope), hive_(hive) {} + +TestHarness::~TestHarness() {} + +void TestHarness::SetUp() {} + +ConfigurationPolicyProvider* TestHarness::CreateProvider( + const PolicyDefinitionList* policy_list) { + scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(policy_list)); + return new AsyncPolicyProvider(policy_list, loader.Pass()); +} + +void TestHarness::InstallEmptyPolicy() {} + +void TestHarness::InstallStringPolicy(const std::string& policy_name, + const std::string& policy_value) { + RegKey key(hive_, policy::kRegistryMandatorySubKey, KEY_ALL_ACCESS); + key.WriteValue(UTF8ToUTF16(policy_name).c_str(), + UTF8ToUTF16(policy_value).c_str()); +} + +void TestHarness::InstallIntegerPolicy(const std::string& policy_name, + int policy_value) { + RegKey key(hive_, policy::kRegistryMandatorySubKey, KEY_ALL_ACCESS); + key.WriteValue(UTF8ToUTF16(policy_name).c_str(), + static_cast<DWORD>(policy_value)); +} + +void TestHarness::InstallBooleanPolicy(const std::string& policy_name, + bool policy_value) { + RegKey key(hive_, policy::kRegistryMandatorySubKey, KEY_ALL_ACCESS); + key.WriteValue(UTF8ToUTF16(policy_name).c_str(), + static_cast<DWORD>(policy_value)); +} + +void TestHarness::InstallStringListPolicy(const std::string& policy_name, + const base::ListValue* policy_value) { + RegKey key(hive_, + (string16(policy::kRegistryMandatorySubKey) + ASCIIToUTF16("\\") + + UTF8ToUTF16(policy_name)).c_str(), + KEY_ALL_ACCESS); + int index = 1; + for (base::ListValue::const_iterator element(policy_value->begin()); + element != policy_value->end(); + ++element) { + std::string element_value; + if (!(*element)->GetAsString(&element_value)) + continue; + std::string name(base::IntToString(index++)); + key.WriteValue(UTF8ToUTF16(name).c_str(), + UTF8ToUTF16(element_value).c_str()); + } +} + +void TestHarness::InstallDictionaryPolicy( + const std::string& policy_name, + const base::DictionaryValue* policy_value) { + std::string json; + base::JSONWriter::Write(policy_value, &json); + RegKey key(hive_, policy::kRegistryMandatorySubKey, KEY_ALL_ACCESS); + key.WriteValue(UTF8ToUTF16(policy_name).c_str(), + UTF8ToUTF16(json).c_str()); +} + +// static +PolicyProviderTestHarness* TestHarness::CreateHKCU() { + return new TestHarness(HKEY_CURRENT_USER, POLICY_SCOPE_USER); +} + +// static +PolicyProviderTestHarness* TestHarness::CreateHKLM() { + return new TestHarness(HKEY_LOCAL_MACHINE, POLICY_SCOPE_MACHINE); +} + +} // namespace + +// Instantiate abstract test case for basic policy reading tests. +INSTANTIATE_TEST_CASE_P( + PolicyProviderWinTest, + ConfigurationPolicyProviderTest, + testing::Values(TestHarness::CreateHKCU, TestHarness::CreateHKLM)); + +// Test cases for windows policy provider specific functionality. +class PolicyLoaderWinTest : public PolicyTestBase { + protected: + PolicyLoaderWinTest() {} + virtual ~PolicyLoaderWinTest() {} + + ScopedGroupPolicyRegistrySandbox registry_sandbox_; +}; + +TEST_F(PolicyLoaderWinTest, HKLMOverHKCU) { + RegKey hklm_key(HKEY_LOCAL_MACHINE, + policy::kRegistryMandatorySubKey, + KEY_ALL_ACCESS); + hklm_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), + UTF8ToUTF16("hklm").c_str()); + RegKey hkcu_key(HKEY_CURRENT_USER, + policy::kRegistryMandatorySubKey, + KEY_ALL_ACCESS); + hkcu_key.WriteValue(UTF8ToUTF16(test_policy_definitions::kKeyString).c_str(), + UTF8ToUTF16("hkcu").c_str()); + + PolicyLoaderWin loader(&test_policy_definitions::kList); + scoped_ptr<PolicyBundle> bundle(loader.Load()); + + PolicyBundle expected_bundle; + expected_bundle.Get(POLICY_DOMAIN_CHROME, "") + .Set(test_policy_definitions::kKeyString, + POLICY_LEVEL_MANDATORY, + POLICY_SCOPE_MACHINE, + base::Value::CreateStringValue("hklm")); + EXPECT_TRUE(bundle->Equals(expected_bundle)); +} + +} // namespace policy diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a959f94..e2dbb8c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1599,16 +1599,10 @@ 'browser/policy/configuration_policy_handler_chromeos.h', 'browser/policy/configuration_policy_handler_list.cc', 'browser/policy/configuration_policy_handler_list.h', - 'browser/policy/configuration_policy_loader_win.cc', - 'browser/policy/configuration_policy_loader_win.h', 'browser/policy/configuration_policy_pref_store.cc', 'browser/policy/configuration_policy_pref_store.h', 'browser/policy/configuration_policy_provider.cc', 'browser/policy/configuration_policy_provider.h', - 'browser/policy/configuration_policy_provider_delegate_win.cc', - 'browser/policy/configuration_policy_provider_delegate_win.h', - 'browser/policy/configuration_policy_provider_win.cc', - 'browser/policy/configuration_policy_provider_win.h', 'browser/policy/cros_user_policy_cache.cc', 'browser/policy/cros_user_policy_cache.h', 'browser/policy/delayed_work_scheduler.cc', @@ -1638,6 +1632,8 @@ 'browser/policy/policy_error_map.h', 'browser/policy/policy_loader_mac.cc', 'browser/policy/policy_loader_mac.h', + 'browser/policy/policy_loader_win.cc', + 'browser/policy/policy_loader_win.h', 'browser/policy/policy_notifier.cc', 'browser/policy/policy_notifier.h', 'browser/policy/policy_path_parser.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 1f4ba20..0258d39 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1370,7 +1370,6 @@ 'browser/policy/configuration_policy_pref_store_unittest.cc', 'browser/policy/configuration_policy_provider_test.cc', 'browser/policy/configuration_policy_provider_test.h', - 'browser/policy/configuration_policy_provider_win_unittest.cc', 'browser/policy/cros_user_policy_cache_unittest.cc', 'browser/policy/device_management_service_unittest.cc', 'browser/policy/device_policy_cache_unittest.cc', @@ -1392,6 +1391,7 @@ 'browser/policy/network_configuration_updater_unittest.cc', 'browser/policy/policy_bundle_unittest.cc', 'browser/policy/policy_loader_mac_unittest.cc', + 'browser/policy/policy_loader_win_unittest.cc', 'browser/policy/policy_map_unittest.cc', 'browser/policy/policy_path_parser_unittest.cc', 'browser/policy/policy_service_impl_unittest.cc', |