aw: Move SharedRendererState out of AwContents
[chromium-blink-merge.git] / chromeos / network / policy_applicator.cc
blob334c106149afe63b49a09069bb6548c1a2959d07
1 // Copyright 2013 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 #include "chromeos/network/policy_applicator.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/stl_util.h"
14 #include "base/values.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "chromeos/dbus/shill_profile_client.h"
17 #include "chromeos/network/network_type_pattern.h"
18 #include "chromeos/network/network_ui_data.h"
19 #include "chromeos/network/onc/onc_signature.h"
20 #include "chromeos/network/onc/onc_translator.h"
21 #include "chromeos/network/policy_util.h"
22 #include "chromeos/network/shill_property_util.h"
23 #include "components/onc/onc_constants.h"
24 #include "dbus/object_path.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
27 namespace chromeos {
29 namespace {
31 void LogErrorMessage(const tracked_objects::Location& from_where,
32 const std::string& error_name,
33 const std::string& error_message) {
34 LOG(ERROR) << from_where.ToString() << ": " << error_message;
37 const base::DictionaryValue* GetByGUID(
38 const PolicyApplicator::GuidToPolicyMap& policies,
39 const std::string& guid) {
40 PolicyApplicator::GuidToPolicyMap::const_iterator it = policies.find(guid);
41 if (it == policies.end())
42 return NULL;
43 return it->second;
46 } // namespace
48 PolicyApplicator::PolicyApplicator(
49 const NetworkProfile& profile,
50 const GuidToPolicyMap& all_policies,
51 const base::DictionaryValue& global_network_config,
52 ConfigurationHandler* handler,
53 std::set<std::string>* modified_policies)
54 : handler_(handler), profile_(profile), weak_ptr_factory_(this) {
55 global_network_config_.MergeDictionary(&global_network_config);
56 remaining_policies_.swap(*modified_policies);
57 for (GuidToPolicyMap::const_iterator it = all_policies.begin();
58 it != all_policies.end(); ++it) {
59 all_policies_.insert(std::make_pair(it->first, it->second->DeepCopy()));
63 PolicyApplicator::~PolicyApplicator() {
64 STLDeleteValues(&all_policies_);
65 VLOG(1) << "Destroying PolicyApplicator for " << profile_.userhash;
68 void PolicyApplicator::Run() {
69 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
70 dbus::ObjectPath(profile_.path),
71 base::Bind(&PolicyApplicator::GetProfilePropertiesCallback,
72 weak_ptr_factory_.GetWeakPtr()),
73 base::Bind(&PolicyApplicator::GetProfilePropertiesError,
74 weak_ptr_factory_.GetWeakPtr()));
77 void PolicyApplicator::ProfileEntryFinished(const std::string& entry) {
78 pending_get_entry_calls_.erase(entry);
79 if (pending_get_entry_calls_.empty()) {
80 ApplyRemainingPolicies();
81 NotifyConfigurationHandlerAndFinish();
85 void PolicyApplicator::GetProfilePropertiesCallback(
86 const base::DictionaryValue& profile_properties) {
87 VLOG(2) << "Received properties for profile " << profile_.ToDebugString();
88 const base::ListValue* entries = NULL;
89 if (!profile_properties.GetListWithoutPathExpansion(
90 shill::kEntriesProperty, &entries)) {
91 LOG(ERROR) << "Profile " << profile_.ToDebugString()
92 << " doesn't contain the property "
93 << shill::kEntriesProperty;
94 NotifyConfigurationHandlerAndFinish();
95 return;
98 for (base::ListValue::const_iterator it = entries->begin();
99 it != entries->end(); ++it) {
100 std::string entry;
101 (*it)->GetAsString(&entry);
103 pending_get_entry_calls_.insert(entry);
104 DBusThreadManager::Get()->GetShillProfileClient()->GetEntry(
105 dbus::ObjectPath(profile_.path),
106 entry,
107 base::Bind(&PolicyApplicator::GetEntryCallback,
108 weak_ptr_factory_.GetWeakPtr(),
109 entry),
110 base::Bind(&PolicyApplicator::GetEntryError,
111 weak_ptr_factory_.GetWeakPtr(),
112 entry));
114 if (pending_get_entry_calls_.empty()) {
115 ApplyRemainingPolicies();
116 NotifyConfigurationHandlerAndFinish();
120 void PolicyApplicator::GetProfilePropertiesError(
121 const std::string& error_name,
122 const std::string& error_message) {
123 LOG(ERROR) << "Could not retrieve properties of profile " << profile_.path
124 << ": " << error_message;
125 NotifyConfigurationHandlerAndFinish();
128 void PolicyApplicator::GetEntryCallback(
129 const std::string& entry,
130 const base::DictionaryValue& entry_properties) {
131 VLOG(2) << "Received properties for entry " << entry << " of profile "
132 << profile_.ToDebugString();
134 scoped_ptr<base::DictionaryValue> onc_part(
135 onc::TranslateShillServiceToONCPart(entry_properties,
136 ::onc::ONC_SOURCE_UNKNOWN,
137 &onc::kNetworkWithStateSignature));
139 std::string old_guid;
140 if (!onc_part->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
141 &old_guid)) {
142 VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
143 << " doesn't contain a GUID.";
144 // This might be an entry of an older ChromeOS version. Assume it to be
145 // unmanaged.
148 scoped_ptr<NetworkUIData> ui_data =
149 shill_property_util::GetUIDataFromProperties(entry_properties);
150 if (!ui_data) {
151 VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
152 << " contains no or no valid UIData.";
153 // This might be an entry of an older ChromeOS version. Assume it to be
154 // unmanaged. It's an inconsistency if there is a GUID but no UIData, thus
155 // clear the GUID just in case.
156 old_guid.clear();
159 bool was_managed = !old_guid.empty() && ui_data &&
160 (ui_data->onc_source() ==
161 ::onc::ONC_SOURCE_DEVICE_POLICY ||
162 ui_data->onc_source() == ::onc::ONC_SOURCE_USER_POLICY);
164 const base::DictionaryValue* new_policy = NULL;
165 if (was_managed) {
166 // If we have a GUID that might match a current policy, do a lookup using
167 // that GUID at first. In particular this is necessary, as some networks
168 // can't be matched to policies by properties (e.g. VPN).
169 new_policy = GetByGUID(all_policies_, old_guid);
172 if (!new_policy) {
173 // If we didn't find a policy by GUID, still a new policy might match.
174 new_policy = policy_util::FindMatchingPolicy(all_policies_, *onc_part);
177 if (new_policy) {
178 std::string new_guid;
179 new_policy->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
180 &new_guid);
182 VLOG_IF(1, was_managed && old_guid != new_guid)
183 << "Updating configuration previously managed by policy " << old_guid
184 << " with new policy " << new_guid << ".";
185 VLOG_IF(1, !was_managed) << "Applying policy " << new_guid
186 << " to previously unmanaged "
187 << "configuration.";
189 if (old_guid == new_guid &&
190 remaining_policies_.find(new_guid) == remaining_policies_.end()) {
191 VLOG(1) << "Not updating existing managed configuration with guid "
192 << new_guid << " because the policy didn't change.";
193 } else {
194 const base::DictionaryValue* user_settings =
195 ui_data ? ui_data->user_settings() : NULL;
196 scoped_ptr<base::DictionaryValue> new_shill_properties =
197 policy_util::CreateShillConfiguration(profile_,
198 new_guid,
199 &global_network_config_,
200 new_policy,
201 user_settings);
202 // A new policy has to be applied to this profile entry. In order to keep
203 // implicit state of Shill like "connected successfully before", keep the
204 // entry if a policy is reapplied (e.g. after reboot) or is updated.
205 // However, some Shill properties are used to identify the network and
206 // cannot be modified after initial configuration, so we have to delete
207 // the profile entry in these cases. Also, keeping Shill's state if the
208 // SSID changed might not be a good idea anyways. If the policy GUID
209 // changed, or there was no policy before, we delete the entry at first to
210 // ensure that no old configuration remains.
211 if (old_guid == new_guid &&
212 shill_property_util::DoIdentifyingPropertiesMatch(
213 *new_shill_properties, entry_properties)) {
214 VLOG(1) << "Updating previously managed configuration with the "
215 << "updated policy " << new_guid << ".";
216 } else {
217 VLOG(1) << "Deleting profile entry before writing new policy "
218 << new_guid << " because of identifying properties changed.";
219 DeleteEntry(entry);
222 // In general, old entries should at first be deleted before new
223 // configurations are written to prevent inconsistencies. Therefore, we
224 // delay the writing of the new config here until ~PolicyApplicator.
225 // E.g. one problematic case is if a policy { {GUID=X, SSID=Y} } is
226 // applied to the profile entries
227 // { ENTRY1 = {GUID=X, SSID=X, USER_SETTINGS=X},
228 // ENTRY2 = {SSID=Y, ... } }.
229 // At first ENTRY1 and ENTRY2 should be removed, then the new config be
230 // written and the result should be:
231 // { {GUID=X, SSID=Y, USER_SETTINGS=X} }
232 WriteNewShillConfiguration(
233 *new_shill_properties, *new_policy, true /* write later */);
234 remaining_policies_.erase(new_guid);
236 } else if (was_managed) {
237 VLOG(1) << "Removing configuration previously managed by policy "
238 << old_guid << ", because the policy was removed.";
240 // Remove the entry, because the network was managed but isn't anymore.
241 // Note: An alternative might be to preserve the user settings, but it's
242 // unclear which values originating the policy should be removed.
243 DeleteEntry(entry);
244 } else {
245 // The entry wasn't managed and doesn't match any current policy. Global
246 // network settings have to be applied.
247 base::DictionaryValue shill_properties_to_update;
248 policy_util::SetShillPropertiesForGlobalPolicy(
249 entry_properties, global_network_config_, &shill_properties_to_update);
250 if (shill_properties_to_update.empty()) {
251 VLOG(2) << "Ignore unmanaged entry.";
252 // Calling a SetProperties of Shill with an empty dictionary is a no op.
253 } else {
254 VLOG(2) << "Apply global network config to unmanaged entry.";
255 handler_->UpdateExistingConfigurationWithPropertiesFromPolicy(
256 entry_properties, shill_properties_to_update);
260 ProfileEntryFinished(entry);
263 void PolicyApplicator::GetEntryError(const std::string& entry,
264 const std::string& error_name,
265 const std::string& error_message) {
266 LOG(ERROR) << "Could not retrieve entry " << entry << " of profile "
267 << profile_.path << ": " << error_message;
268 ProfileEntryFinished(entry);
271 void PolicyApplicator::DeleteEntry(const std::string& entry) {
272 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
273 dbus::ObjectPath(profile_.path),
274 entry,
275 base::Bind(&base::DoNothing),
276 base::Bind(&LogErrorMessage, FROM_HERE));
279 void PolicyApplicator::WriteNewShillConfiguration(
280 const base::DictionaryValue& shill_dictionary,
281 const base::DictionaryValue& policy,
282 bool write_later) {
283 // Ethernet (non EAP) settings, like GUID or UIData, cannot be stored per
284 // user. Abort in that case.
285 std::string type;
286 policy.GetStringWithoutPathExpansion(::onc::network_config::kType, &type);
287 if (type == ::onc::network_type::kEthernet &&
288 profile_.type() == NetworkProfile::TYPE_USER) {
289 const base::DictionaryValue* ethernet = NULL;
290 policy.GetDictionaryWithoutPathExpansion(::onc::network_config::kEthernet,
291 &ethernet);
292 std::string auth;
293 ethernet->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
294 &auth);
295 if (auth == ::onc::ethernet::kAuthenticationNone)
296 return;
299 if (write_later)
300 new_shill_configurations_.push_back(shill_dictionary.DeepCopy());
301 else
302 handler_->CreateConfigurationFromPolicy(shill_dictionary);
305 void PolicyApplicator::ApplyRemainingPolicies() {
306 DCHECK(pending_get_entry_calls_.empty());
308 // Write all queued configurations now.
309 for (ScopedVector<base::DictionaryValue>::const_iterator it =
310 new_shill_configurations_.begin();
311 it != new_shill_configurations_.end();
312 ++it) {
313 handler_->CreateConfigurationFromPolicy(**it);
315 new_shill_configurations_.clear();
317 VLOG_IF(2, !remaining_policies_.empty())
318 << "Create new managed network configurations in profile"
319 << profile_.ToDebugString() << ".";
321 // All profile entries were compared to policies. |remaining_policies_|
322 // contains all modified policies that didn't match any entry. For these
323 // remaining policies, new configurations have to be created.
324 for (std::set<std::string>::iterator it = remaining_policies_.begin();
325 it != remaining_policies_.end(); ++it) {
326 const base::DictionaryValue* network_policy = GetByGUID(all_policies_, *it);
327 DCHECK(network_policy);
329 VLOG(1) << "Creating new configuration managed by policy " << *it
330 << " in profile " << profile_.ToDebugString() << ".";
332 scoped_ptr<base::DictionaryValue> shill_dictionary =
333 policy_util::CreateShillConfiguration(profile_,
334 *it,
335 &global_network_config_,
336 network_policy,
337 NULL /* no user settings */);
338 WriteNewShillConfiguration(
339 *shill_dictionary, *network_policy, false /* write now */);
341 remaining_policies_.clear();
344 void PolicyApplicator::NotifyConfigurationHandlerAndFinish() {
345 weak_ptr_factory_.InvalidateWeakPtrs();
346 handler_->OnPoliciesApplied(profile_);
349 } // namespace chromeos