policy_watcher.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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:
6//   src/chrome/browser/policy/asynchronous_policy_loader.{h,cc}
7
8#include "remoting/host/policy_hack/policy_watcher.h"
9
10#include "base/bind.h"
11#include "base/compiler_specific.h"
12#include "base/location.h"
13#include "base/memory/weak_ptr.h"
14#include "base/single_thread_task_runner.h"
15#include "base/synchronization/waitable_event.h"
16#include "base/time.h"
17#include "base/values.h"
18#include "remoting/host/dns_blackhole_checker.h"
19
20#if !defined(NDEBUG)
21#include "base/json/json_reader.h"
22#endif
23
24namespace remoting {
25namespace policy_hack {
26
27namespace {
28
29// The time interval for rechecking policy. This is our fallback in case the
30// delegate never reports a change to the ReloadObserver.
31const int kFallbackReloadDelayMinutes = 15;
32
33// Copies all policy values from one dictionary to another, using values from
34// |default| if they are not set in |from|, or values from |bad_type_values| if
35// the value in |from| has the wrong type.
36scoped_ptr<base::DictionaryValue> CopyGoodValuesAndAddDefaults(
37    const base::DictionaryValue* from,
38    const base::DictionaryValue* default_values,
39    const base::DictionaryValue* bad_type_values) {
40  scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy());
41  for (base::DictionaryValue::Iterator i(*default_values);
42       !i.IsAtEnd(); i.Advance()) {
43
44    const base::Value* value = NULL;
45
46    // If the policy isn't in |from|, use the default.
47    if (!from->Get(i.key(), &value)) {
48      continue;
49    }
50
51    // If the policy is the wrong type, use the value from |bad_type_values|.
52    if (!value->IsType(i.value().GetType())) {
53      CHECK(bad_type_values->Get(i.key(), &value));
54    }
55
56    to->Set(i.key(), value->DeepCopy());
57  }
58
59#if !defined(NDEBUG)
60  // Replace values with those specified in DebugOverridePolicies, if present.
61  std::string policy_overrides;
62  if (from->GetString(PolicyWatcher::kHostDebugOverridePoliciesName,
63                      &policy_overrides)) {
64    scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides));
65    const base::DictionaryValue* override_values;
66    if (value && value->GetAsDictionary(&override_values)) {
67      to->MergeDictionary(override_values);
68    }
69  }
70#endif // defined(NDEBUG)
71
72  return to.Pass();
73}
74
75}  // namespace
76
77const char PolicyWatcher::kNatPolicyName[] =
78    "RemoteAccessHostFirewallTraversal";
79
80const char PolicyWatcher::kHostRequireTwoFactorPolicyName[] =
81    "RemoteAccessHostRequireTwoFactor";
82
83const char PolicyWatcher::kHostDomainPolicyName[] =
84    "RemoteAccessHostDomain";
85
86const char PolicyWatcher::kHostMatchUsernamePolicyName[] =
87    "RemoteAccessHostMatchUsername";
88
89const char PolicyWatcher::kHostTalkGadgetPrefixPolicyName[] =
90    "RemoteAccessHostTalkGadgetPrefix";
91
92const char PolicyWatcher::kHostRequireCurtainPolicyName[] =
93    "RemoteAccessHostRequireCurtain";
94
95const char PolicyWatcher::kHostTokenUrlPolicyName[] =
96    "RemoteAccessHostTokenUrl";
97
98const char PolicyWatcher::kHostTokenValidationUrlPolicyName[] =
99    "RemoteAccessHostTokenValidationUrl";
100
101const char PolicyWatcher::kHostDebugOverridePoliciesName[] =
102    "RemoteAccessHostDebugOverridePolicies";
103
104PolicyWatcher::PolicyWatcher(
105    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
106    : task_runner_(task_runner),
107      old_policies_(new base::DictionaryValue()),
108      default_values_(new base::DictionaryValue()),
109      weak_factory_(this) {
110  // Initialize the default values for each policy.
111  default_values_->SetBoolean(kNatPolicyName, true);
112  default_values_->SetBoolean(kHostRequireTwoFactorPolicyName, false);
113  default_values_->SetBoolean(kHostRequireCurtainPolicyName, false);
114  default_values_->SetBoolean(kHostMatchUsernamePolicyName, false);
115  default_values_->SetString(kHostDomainPolicyName, std::string());
116  default_values_->SetString(kHostTalkGadgetPrefixPolicyName,
117                               kDefaultHostTalkGadgetPrefix);
118  default_values_->SetString(kHostTokenUrlPolicyName, std::string());
119  default_values_->SetString(kHostTokenValidationUrlPolicyName, std::string());
120#if !defined(NDEBUG)
121  default_values_->SetString(kHostDebugOverridePoliciesName, std::string());
122#endif
123
124  // Initialize the fall-back values to use for unreadable policies.
125  // For most policies these match the defaults.
126  bad_type_values_.reset(default_values_->DeepCopy());
127  bad_type_values_->SetBoolean(kNatPolicyName, false);
128}
129
130PolicyWatcher::~PolicyWatcher() {
131}
132
133void PolicyWatcher::StartWatching(const PolicyCallback& policy_callback) {
134  if (!OnPolicyWatcherThread()) {
135    task_runner_->PostTask(FROM_HERE,
136                           base::Bind(&PolicyWatcher::StartWatching,
137                                      base::Unretained(this),
138                                      policy_callback));
139    return;
140  }
141
142  policy_callback_ = policy_callback;
143  StartWatchingInternal();
144}
145
146void PolicyWatcher::StopWatching(base::WaitableEvent* done) {
147  if (!OnPolicyWatcherThread()) {
148    task_runner_->PostTask(FROM_HERE,
149                           base::Bind(&PolicyWatcher::StopWatching,
150                                      base::Unretained(this), done));
151    return;
152  }
153
154  StopWatchingInternal();
155  weak_factory_.InvalidateWeakPtrs();
156  policy_callback_.Reset();
157
158  done->Signal();
159}
160
161void PolicyWatcher::ScheduleFallbackReloadTask() {
162  DCHECK(OnPolicyWatcherThread());
163  ScheduleReloadTask(
164      base::TimeDelta::FromMinutes(kFallbackReloadDelayMinutes));
165}
166
167void PolicyWatcher::ScheduleReloadTask(const base::TimeDelta& delay) {
168  DCHECK(OnPolicyWatcherThread());
169  task_runner_->PostDelayedTask(
170      FROM_HERE,
171      base::Bind(&PolicyWatcher::Reload, weak_factory_.GetWeakPtr()),
172      delay);
173}
174
175const base::DictionaryValue& PolicyWatcher::Defaults() const {
176  return *default_values_;
177}
178
179bool PolicyWatcher::OnPolicyWatcherThread() const {
180  return task_runner_->BelongsToCurrentThread();
181}
182
183void PolicyWatcher::UpdatePolicies(
184    const base::DictionaryValue* new_policies_raw) {
185  DCHECK(OnPolicyWatcherThread());
186
187  // Use default values for any missing policies.
188  scoped_ptr<base::DictionaryValue> new_policies =
189      CopyGoodValuesAndAddDefaults(
190          new_policies_raw, default_values_.get(), bad_type_values_.get());
191
192  // Find the changed policies.
193  scoped_ptr<base::DictionaryValue> changed_policies(
194      new base::DictionaryValue());
195  base::DictionaryValue::Iterator iter(*new_policies);
196  while (!iter.IsAtEnd()) {
197    base::Value* old_policy;
198    if (!(old_policies_->Get(iter.key(), &old_policy) &&
199          old_policy->Equals(&iter.value()))) {
200      changed_policies->Set(iter.key(), iter.value().DeepCopy());
201    }
202    iter.Advance();
203  }
204
205  // Save the new policies.
206  old_policies_.swap(new_policies);
207
208  // Notify our client of the changed policies.
209  if (!changed_policies->empty()) {
210    policy_callback_.Run(changed_policies.Pass());
211  }
212}
213
214}  // namespace policy_hack
215}  // namespace remoting
216