summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-06 15:51:50 +0000
committerjoaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-06 15:51:50 +0000
commit326cf715e5e1ea9d012782ae3b18458cf9cf26cc (patch)
tree4e1dc6c379acabb4608d58f6213433edee6467e9
parent0f6e6627eb5fa4fdf7a1764be83e4372f24ca105 (diff)
downloadchromium_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.cc5
-rw-r--r--chrome/browser/policy/configuration_policy_loader_win.cc89
-rw-r--r--chrome/browser/policy/configuration_policy_loader_win.h53
-rw-r--r--chrome/browser/policy/configuration_policy_provider_delegate_win.h32
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.cc28
-rw-r--r--chrome/browser/policy/configuration_policy_provider_win.h31
-rw-r--r--chrome/browser/policy/policy_loader_win.cc313
-rw-r--r--chrome/browser/policy/policy_loader_win.h51
-rw-r--r--chrome/browser/policy/policy_loader_win_unittest.cc251
-rw-r--r--chrome/chrome_browser.gypi8
-rw-r--r--chrome/chrome_tests.gypi2
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',