Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / remoting / host / policy_hack / policy_watcher_win.cc
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.
4
5 // Most of this code is copied from various classes in
6 // src/chrome/browser/policy. In particular, look at
7 //
8 //   configuration_policy_provider_delegate_win.{h,cc}
9 //   configuration_policy_loader_win.{h,cc}
10 //
11 // This is a reduction of the functionality in those classes.
12
13 #include "remoting/host/policy_hack/policy_watcher.h"
14
15 #include <userenv.h>
16
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"
26
27 // userenv.dll is required for RegisterGPNotification().
28 #pragma comment(lib, "userenv.lib")
29
30 using base::win::RegKey;
31
32 namespace remoting {
33 namespace policy_hack {
34
35 namespace {
36
37 const wchar_t kRegistrySubKey[] = L"SOFTWARE\\Policies\\Google\\Chrome";
38
39 }  // namespace
40
41 class PolicyWatcherWin :
42   public PolicyWatcher,
43   public base::win::ObjectWatcher::Delegate {
44  public:
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) {
52   }
53
54   virtual ~PolicyWatcherWin() {
55   }
56
57   virtual void StartWatchingInternal() override {
58     DCHECK(OnPolicyWatcherThread());
59
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;
63     }
64
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;
68     }
69
70     Reload();
71   }
72
73   virtual void StopWatchingInternal() override {
74     DCHECK(OnPolicyWatcherThread());
75
76     if (!UnregisterGPNotification(user_policy_changed_event_.handle())) {
77       PLOG(WARNING) << "Failed to unregister user group policy notification";
78     }
79
80     if (!UnregisterGPNotification(machine_policy_changed_event_.handle())) {
81       PLOG(WARNING) <<
82           "Failed to unregister machine group policy notification.";
83     }
84
85     user_policy_watcher_.StopWatching();
86     machine_policy_watcher_.StopWatching();
87   }
88
89  private:
90   // Updates the watchers and schedules the reload task if appropriate.
91   void SetupWatches() {
92     DCHECK(OnPolicyWatcherThread());
93
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;
100     }
101
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;
108      }
109
110     if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) {
111       ScheduleFallbackReloadTask();
112     }
113   }
114
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
120     std::wstring value;
121     RegKey policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
122     if (policy_key.ReadValue(value_name_wide.c_str(), &value) ==
123         ERROR_SUCCESS) {
124       *result = base::WideToUTF8(value);
125       return true;
126     }
127
128     if (policy_key.Open(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ) ==
129       ERROR_SUCCESS) {
130       if (policy_key.ReadValue(value_name_wide.c_str(), &value) ==
131           ERROR_SUCCESS) {
132         *result = base::WideToUTF8(value);
133         return true;
134       }
135     }
136     return false;
137   }
138
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);
143     DWORD value = 0;
144     RegKey policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
145     if (policy_key.ReadValueDW(value_name_wide.c_str(), &value) ==
146         ERROR_SUCCESS) {
147       *result = value;
148       return true;
149     }
150
151     if (policy_key.Open(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ) ==
152         ERROR_SUCCESS) {
153       if (policy_key.ReadValueDW(value_name_wide.c_str(), &value) ==
154           ERROR_SUCCESS) {
155         *result = value;
156         return true;
157       }
158     }
159     return false;
160   }
161
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);
166     if (ret)
167       *result = local_result != 0;
168     return ret;
169   }
170
171   scoped_ptr<base::DictionaryValue> Load() {
172     scoped_ptr<base::DictionaryValue> policy(new base::DictionaryValue());
173
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) {
178         bool bool_value;
179         if (GetRegistryPolicyBoolean(policy_name, &bool_value)) {
180           policy->SetBoolean(policy_name, bool_value);
181         }
182       }
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);
187         }
188       }
189     }
190     return policy.Pass();
191   }
192
193   // Post a reload notification and update the watch machinery.
194   void Reload() {
195     DCHECK(OnPolicyWatcherThread());
196     SetupWatches();
197     scoped_ptr<base::DictionaryValue> new_policy(Load());
198     UpdatePolicies(new_policy.get());
199   }
200
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;
208     Reload();
209   }
210
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_;
217 };
218
219 scoped_ptr<PolicyWatcher> PolicyWatcher::Create(
220     policy::PolicyService* policy_service,
221     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
222   return make_scoped_ptr(new PolicyWatcherWin(task_runner));
223 }
224
225 }  // namespace policy_hack
226 }  // namespace remoting