Home | History | Annotate | Download | only in policy_hack
      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 PolicyWatcher* PolicyWatcher::Create(
    220     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
    221   return new PolicyWatcherWin(task_runner);
    222 }
    223 
    224 }  // namespace policy_hack
    225 }  // namespace remoting
    226