1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Most of this code is copied from various classes in
6 // src/chrome/browser/policy. In particular, look at
8 // configuration_policy_provider_delegate_win.{h,cc}
9 // configuration_policy_loader_win.{h,cc}
11 // This is a reduction of the functionality in those classes.
13 #include "remoting/host/policy_hack/policy_watcher.h"
17 #include "base/compiler_specific.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop/message_loop_proxy.h"
20 #include "base/strings/string16.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/synchronization/waitable_event.h"
23 #include "base/values.h"
24 #include "base/win/object_watcher.h"
25 #include "base/win/registry.h"
27 // userenv.dll is required for RegisterGPNotification().
28 #pragma comment(lib, "userenv.lib")
30 using base::win::RegKey
;
33 namespace policy_hack
{
37 const wchar_t kRegistrySubKey
[] = L
"SOFTWARE\\Policies\\Google\\Chrome";
41 class PolicyWatcherWin
:
43 public base::win::ObjectWatcher::Delegate
{
45 explicit PolicyWatcherWin(
46 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
47 : PolicyWatcher(task_runner
),
48 user_policy_changed_event_(false, false),
49 machine_policy_changed_event_(false, false),
50 user_policy_watcher_failed_(false),
51 machine_policy_watcher_failed_(false) {
54 virtual ~PolicyWatcherWin() {
57 virtual void StartWatchingInternal() OVERRIDE
{
58 DCHECK(OnPolicyWatcherThread());
60 if (!RegisterGPNotification(user_policy_changed_event_
.handle(), false)) {
61 PLOG(WARNING
) << "Failed to register user group policy notification";
62 user_policy_watcher_failed_
= true;
65 if (!RegisterGPNotification(machine_policy_changed_event_
.handle(), true)) {
66 PLOG(WARNING
) << "Failed to register machine group policy notification.";
67 machine_policy_watcher_failed_
= true;
73 virtual void StopWatchingInternal() OVERRIDE
{
74 DCHECK(OnPolicyWatcherThread());
76 if (!UnregisterGPNotification(user_policy_changed_event_
.handle())) {
77 PLOG(WARNING
) << "Failed to unregister user group policy notification";
80 if (!UnregisterGPNotification(machine_policy_changed_event_
.handle())) {
82 "Failed to unregister machine group policy notification.";
85 user_policy_watcher_
.StopWatching();
86 machine_policy_watcher_
.StopWatching();
90 // Updates the watchers and schedules the reload task if appropriate.
92 DCHECK(OnPolicyWatcherThread());
94 if (!user_policy_watcher_failed_
&&
95 !user_policy_watcher_
.GetWatchedObject() &&
96 !user_policy_watcher_
.StartWatching(
97 user_policy_changed_event_
.handle(), this)) {
98 LOG(WARNING
) << "Failed to start watch for user policy change event";
99 user_policy_watcher_failed_
= true;
102 if (!machine_policy_watcher_failed_
&&
103 !machine_policy_watcher_
.GetWatchedObject() &&
104 !machine_policy_watcher_
.StartWatching(
105 machine_policy_changed_event_
.handle(), this)) {
106 LOG(WARNING
) << "Failed to start watch for machine policy change event";
107 machine_policy_watcher_failed_
= true;
110 if (user_policy_watcher_failed_
|| machine_policy_watcher_failed_
) {
111 ScheduleFallbackReloadTask();
115 bool GetRegistryPolicyString(const std::string
& value_name
,
116 std::string
* result
) const {
117 // presubmit: allow wstring
118 std::wstring value_name_wide
= base::UTF8ToWide(value_name
);
119 // presubmit: allow wstring
121 RegKey
policy_key(HKEY_LOCAL_MACHINE
, kRegistrySubKey
, KEY_READ
);
122 if (policy_key
.ReadValue(value_name_wide
.c_str(), &value
) ==
124 *result
= base::WideToUTF8(value
);
128 if (policy_key
.Open(HKEY_CURRENT_USER
, kRegistrySubKey
, KEY_READ
) ==
130 if (policy_key
.ReadValue(value_name_wide
.c_str(), &value
) ==
132 *result
= base::WideToUTF8(value
);
139 bool GetRegistryPolicyInteger(const std::string
& value_name
,
140 uint32
* result
) const {
141 // presubmit: allow wstring
142 std::wstring value_name_wide
= base::UTF8ToWide(value_name
);
144 RegKey
policy_key(HKEY_LOCAL_MACHINE
, kRegistrySubKey
, KEY_READ
);
145 if (policy_key
.ReadValueDW(value_name_wide
.c_str(), &value
) ==
151 if (policy_key
.Open(HKEY_CURRENT_USER
, kRegistrySubKey
, KEY_READ
) ==
153 if (policy_key
.ReadValueDW(value_name_wide
.c_str(), &value
) ==
162 bool GetRegistryPolicyBoolean(const std::string
& value_name
,
163 bool* result
) const {
164 uint32 local_result
= 0;
165 bool ret
= GetRegistryPolicyInteger(value_name
, &local_result
);
167 *result
= local_result
!= 0;
171 scoped_ptr
<base::DictionaryValue
> Load() {
172 scoped_ptr
<base::DictionaryValue
> policy(new base::DictionaryValue());
174 for (base::DictionaryValue::Iterator
i(Defaults());
175 !i
.IsAtEnd(); i
.Advance()) {
176 const std::string
& policy_name
= i
.key();
177 if (i
.value().GetType() == base::DictionaryValue::TYPE_BOOLEAN
) {
179 if (GetRegistryPolicyBoolean(policy_name
, &bool_value
)) {
180 policy
->SetBoolean(policy_name
, bool_value
);
183 if (i
.value().GetType() == base::DictionaryValue::TYPE_STRING
) {
184 std::string string_value
;
185 if (GetRegistryPolicyString(policy_name
, &string_value
)) {
186 policy
->SetString(policy_name
, string_value
);
190 return policy
.Pass();
193 // Post a reload notification and update the watch machinery.
195 DCHECK(OnPolicyWatcherThread());
197 scoped_ptr
<base::DictionaryValue
> new_policy(Load());
198 UpdatePolicies(new_policy
.get());
201 // ObjectWatcher::Delegate overrides:
202 virtual void OnObjectSignaled(HANDLE object
) {
203 DCHECK(OnPolicyWatcherThread());
204 DCHECK(object
== user_policy_changed_event_
.handle() ||
205 object
== machine_policy_changed_event_
.handle())
206 << "unexpected object signaled policy reload, obj = "
207 << std::showbase
<< std::hex
<< object
;
211 base::WaitableEvent user_policy_changed_event_
;
212 base::WaitableEvent machine_policy_changed_event_
;
213 base::win::ObjectWatcher user_policy_watcher_
;
214 base::win::ObjectWatcher machine_policy_watcher_
;
215 bool user_policy_watcher_failed_
;
216 bool machine_policy_watcher_failed_
;
219 PolicyWatcher
* PolicyWatcher::Create(
220 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
) {
221 return new PolicyWatcherWin(task_runner
);
224 } // namespace policy_hack
225 } // namespace remoting