// 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. // Most of this code is copied from: // src/chrome/browser/policy/asynchronous_policy_loader.{h,cc} #include "remoting/host/policy_hack/policy_watcher.h" #include "base/bind.h" #include "base/compiler_specific.h" #include "base/location.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" #include "base/time/time.h" #include "base/values.h" #include "remoting/host/dns_blackhole_checker.h" #if !defined(NDEBUG) #include "base/json/json_reader.h" #endif namespace remoting { namespace policy_hack { namespace { // The time interval for rechecking policy. This is our fallback in case the // delegate never reports a change to the ReloadObserver. const int kFallbackReloadDelayMinutes = 15; // Copies all policy values from one dictionary to another, using values from // |default| if they are not set in |from|, or values from |bad_type_values| if // the value in |from| has the wrong type. scoped_ptr<base::DictionaryValue> CopyGoodValuesAndAddDefaults( const base::DictionaryValue* from, const base::DictionaryValue* default_values, const base::DictionaryValue* bad_type_values) { scoped_ptr<base::DictionaryValue> to(default_values->DeepCopy()); for (base::DictionaryValue::Iterator i(*default_values); !i.IsAtEnd(); i.Advance()) { const base::Value* value = NULL; // If the policy isn't in |from|, use the default. if (!from->Get(i.key(), &value)) { continue; } // If the policy is the wrong type, use the value from |bad_type_values|. if (!value->IsType(i.value().GetType())) { CHECK(bad_type_values->Get(i.key(), &value)); } to->Set(i.key(), value->DeepCopy()); } #if !defined(NDEBUG) // Replace values with those specified in DebugOverridePolicies, if present. std::string policy_overrides; if (from->GetString(PolicyWatcher::kHostDebugOverridePoliciesName, &policy_overrides)) { scoped_ptr<base::Value> value(base::JSONReader::Read(policy_overrides)); const base::DictionaryValue* override_values; if (value && value->GetAsDictionary(&override_values)) { to->MergeDictionary(override_values); } } #endif // defined(NDEBUG) return to.Pass(); } } // namespace const char PolicyWatcher::kNatPolicyName[] = "RemoteAccessHostFirewallTraversal"; const char PolicyWatcher::kHostRequireTwoFactorPolicyName[] = "RemoteAccessHostRequireTwoFactor"; const char PolicyWatcher::kHostDomainPolicyName[] = "RemoteAccessHostDomain"; const char PolicyWatcher::kHostMatchUsernamePolicyName[] = "RemoteAccessHostMatchUsername"; const char PolicyWatcher::kHostTalkGadgetPrefixPolicyName[] = "RemoteAccessHostTalkGadgetPrefix"; const char PolicyWatcher::kHostRequireCurtainPolicyName[] = "RemoteAccessHostRequireCurtain"; const char PolicyWatcher::kHostTokenUrlPolicyName[] = "RemoteAccessHostTokenUrl"; const char PolicyWatcher::kHostTokenValidationUrlPolicyName[] = "RemoteAccessHostTokenValidationUrl"; const char PolicyWatcher::kHostTokenValidationCertIssuerPolicyName[] = "RemoteAccessHostTokenValidationCertificateIssuer"; const char PolicyWatcher::kHostAllowClientPairing[] = "RemoteAccessHostAllowClientPairing"; const char PolicyWatcher::kHostAllowGnubbyAuthPolicyName[] = "RemoteAccessHostAllowGnubbyAuth"; const char PolicyWatcher::kRelayPolicyName[] = "RemoteAccessHostAllowRelayedConnection"; const char PolicyWatcher::kUdpPortRangePolicyName[] = "RemoteAccessHostUdpPortRange"; const char PolicyWatcher::kHostDebugOverridePoliciesName[] = "RemoteAccessHostDebugOverridePolicies"; PolicyWatcher::PolicyWatcher( scoped_refptr<base::SingleThreadTaskRunner> task_runner) : task_runner_(task_runner), old_policies_(new base::DictionaryValue()), default_values_(new base::DictionaryValue()), weak_factory_(this) { // Initialize the default values for each policy. default_values_->SetBoolean(kNatPolicyName, true); default_values_->SetBoolean(kHostRequireTwoFactorPolicyName, false); default_values_->SetBoolean(kHostRequireCurtainPolicyName, false); default_values_->SetBoolean(kHostMatchUsernamePolicyName, false); default_values_->SetString(kHostDomainPolicyName, std::string()); default_values_->SetString(kHostTalkGadgetPrefixPolicyName, kDefaultHostTalkGadgetPrefix); default_values_->SetString(kHostTokenUrlPolicyName, std::string()); default_values_->SetString(kHostTokenValidationUrlPolicyName, std::string()); default_values_->SetString(kHostTokenValidationCertIssuerPolicyName, std::string()); default_values_->SetBoolean(kHostAllowClientPairing, true); default_values_->SetBoolean(kHostAllowGnubbyAuthPolicyName, true); default_values_->SetBoolean(kRelayPolicyName, true); default_values_->SetString(kUdpPortRangePolicyName, ""); #if !defined(NDEBUG) default_values_->SetString(kHostDebugOverridePoliciesName, std::string()); #endif // Initialize the fall-back values to use for unreadable policies. // For most policies these match the defaults. bad_type_values_.reset(default_values_->DeepCopy()); bad_type_values_->SetBoolean(kNatPolicyName, false); bad_type_values_->SetBoolean(kRelayPolicyName, false); } PolicyWatcher::~PolicyWatcher() { } void PolicyWatcher::StartWatching(const PolicyCallback& policy_callback) { if (!OnPolicyWatcherThread()) { task_runner_->PostTask(FROM_HERE, base::Bind(&PolicyWatcher::StartWatching, base::Unretained(this), policy_callback)); return; } policy_callback_ = policy_callback; StartWatchingInternal(); } void PolicyWatcher::StopWatching(base::WaitableEvent* done) { if (!OnPolicyWatcherThread()) { task_runner_->PostTask(FROM_HERE, base::Bind(&PolicyWatcher::StopWatching, base::Unretained(this), done)); return; } StopWatchingInternal(); weak_factory_.InvalidateWeakPtrs(); policy_callback_.Reset(); done->Signal(); } void PolicyWatcher::ScheduleFallbackReloadTask() { DCHECK(OnPolicyWatcherThread()); ScheduleReloadTask( base::TimeDelta::FromMinutes(kFallbackReloadDelayMinutes)); } void PolicyWatcher::ScheduleReloadTask(const base::TimeDelta& delay) { DCHECK(OnPolicyWatcherThread()); task_runner_->PostDelayedTask( FROM_HERE, base::Bind(&PolicyWatcher::Reload, weak_factory_.GetWeakPtr()), delay); } const base::DictionaryValue& PolicyWatcher::Defaults() const { return *default_values_; } bool PolicyWatcher::OnPolicyWatcherThread() const { return task_runner_->BelongsToCurrentThread(); } void PolicyWatcher::UpdatePolicies( const base::DictionaryValue* new_policies_raw) { DCHECK(OnPolicyWatcherThread()); // Use default values for any missing policies. scoped_ptr<base::DictionaryValue> new_policies = CopyGoodValuesAndAddDefaults( new_policies_raw, default_values_.get(), bad_type_values_.get()); // Find the changed policies. scoped_ptr<base::DictionaryValue> changed_policies( new base::DictionaryValue()); base::DictionaryValue::Iterator iter(*new_policies); while (!iter.IsAtEnd()) { base::Value* old_policy; if (!(old_policies_->Get(iter.key(), &old_policy) && old_policy->Equals(&iter.value()))) { changed_policies->Set(iter.key(), iter.value().DeepCopy()); } iter.Advance(); } // Save the new policies. old_policies_.swap(new_policies); // Notify our client of the changed policies. if (!changed_policies->empty()) { policy_callback_.Run(changed_policies.Pass()); } } } // namespace policy_hack } // namespace remoting