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.
5 #include "chromeos/network/network_configuration_handler.h"
10 #include "base/bind.h"
11 #include "base/format_macros.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_manager_client.h"
21 #include "chromeos/dbus/shill_profile_client.h"
22 #include "chromeos/dbus/shill_service_client.h"
23 #include "chromeos/network/network_event_log.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "chromeos/network/shill_property_util.h"
26 #include "dbus/object_path.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
33 // Strip surrounding "" from keys (if present).
34 std::string
StripQuotations(const std::string
& in_str
) {
35 size_t len
= in_str
.length();
36 if (len
>= 2 && in_str
[0] == '"' && in_str
[len
-1] == '"')
37 return in_str
.substr(1, len
-2);
41 void InvokeErrorCallback(const std::string
& service_path
,
42 const network_handler::ErrorCallback
& error_callback
,
43 const std::string
& error_name
) {
44 std::string error_msg
= "Config Error: " + error_name
;
45 NET_LOG_ERROR(error_msg
, service_path
);
46 network_handler::RunErrorCallback(
47 error_callback
, service_path
, error_name
, error_msg
);
50 void GetPropertiesCallback(
51 const network_handler::DictionaryResultCallback
& callback
,
52 const network_handler::ErrorCallback
& error_callback
,
53 const std::string
& service_path
,
54 DBusMethodCallStatus call_status
,
55 const base::DictionaryValue
& properties
) {
56 // Get the correct name from WifiHex if necessary.
57 scoped_ptr
<base::DictionaryValue
> properties_copy(properties
.DeepCopy());
59 shill_property_util::GetNameFromProperties(service_path
, properties
);
61 properties_copy
->SetStringWithoutPathExpansion(shill::kNameProperty
, name
);
63 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
64 // Because network services are added and removed frequently, we will see
65 // failures regularly, so don't log these.
66 network_handler::RunErrorCallback(error_callback
,
68 network_handler::kDBusFailedError
,
69 network_handler::kDBusFailedErrorMessage
);
70 } else if (!callback
.is_null()) {
71 callback
.Run(service_path
, *properties_copy
.get());
75 void SetNetworkProfileErrorCallback(
76 const std::string
& service_path
,
77 const std::string
& profile_path
,
78 const network_handler::ErrorCallback
& error_callback
,
79 const std::string
& dbus_error_name
,
80 const std::string
& dbus_error_message
) {
81 network_handler::ShillErrorCallbackFunction(
82 "Config.SetNetworkProfile Failed: " + profile_path
,
83 service_path
, error_callback
,
84 dbus_error_name
, dbus_error_message
);
87 bool IsPassphrase(const std::string
& key
) {
88 return key
== shill::kEapPrivateKeyPasswordProperty
||
89 key
== shill::kEapPasswordProperty
||
90 key
== shill::kL2tpIpsecPasswordProperty
||
91 key
== shill::kOpenVPNPasswordProperty
||
92 key
== shill::kPassphraseProperty
||
93 key
== shill::kOpenVPNOTPProperty
||
94 key
== shill::kEapPrivateKeyProperty
||
95 key
== shill::kEapPinProperty
||
96 key
== shill::kApnPasswordProperty
;
99 void LogConfigProperties(const std::string
& desc
,
100 const std::string
& path
,
101 const base::DictionaryValue
& properties
) {
102 for (base::DictionaryValue::Iterator
iter(properties
);
103 !iter
.IsAtEnd(); iter
.Advance()) {
104 std::string v
= "******";
105 if (!IsPassphrase(iter
.key()))
106 base::JSONWriter::Write(&iter
.value(), &v
);
107 NET_LOG_DEBUG(desc
, path
+ "." + iter
.key() + "=" + v
);
113 // Helper class to request from Shill the profile entries associated with a
114 // Service and delete the service from each profile. Triggers either
115 // |callback| on success or |error_callback| on failure, and calls
116 // |handler|->ProfileEntryDeleterCompleted() on completion to delete itself.
117 class NetworkConfigurationHandler::ProfileEntryDeleter
118 : public base::SupportsWeakPtr
<ProfileEntryDeleter
> {
120 ProfileEntryDeleter(NetworkConfigurationHandler
* handler
,
121 const std::string
& service_path
,
122 const base::Closure
& callback
,
123 const network_handler::ErrorCallback
& error_callback
)
125 service_path_(service_path
),
127 error_callback_(error_callback
) {
131 DBusThreadManager::Get()->GetShillServiceClient()->
132 GetLoadableProfileEntries(
133 dbus::ObjectPath(service_path_
),
134 base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback
,
139 void GetProfileEntriesToDeleteCallback(
140 DBusMethodCallStatus call_status
,
141 const base::DictionaryValue
& profile_entries
) {
142 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
144 service_path_
, error_callback_
, "GetLoadableProfileEntriesFailed");
145 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
149 for (base::DictionaryValue::Iterator
iter(profile_entries
);
150 !iter
.IsAtEnd(); iter
.Advance()) {
151 std::string profile_path
= StripQuotations(iter
.key());
152 std::string entry_path
;
153 iter
.value().GetAsString(&entry_path
);
154 if (profile_path
.empty() || entry_path
.empty()) {
155 NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf(
156 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
159 if (profile_delete_entries_
.count(profile_path
) != 0) {
160 NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf(
161 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
164 NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf(
165 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
166 profile_delete_entries_
[profile_path
] = entry_path
;
167 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
168 dbus::ObjectPath(profile_path
),
170 base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback
,
171 AsWeakPtr(), profile_path
, entry_path
),
172 base::Bind(&ProfileEntryDeleter::ShillErrorCallback
,
173 AsWeakPtr(), profile_path
, entry_path
));
177 void ProfileEntryDeletedCallback(const std::string
& profile_path
,
178 const std::string
& entry
) {
179 NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf(
180 "%s: %s", profile_path
.c_str(), entry
.c_str()));
181 profile_delete_entries_
.erase(profile_path
);
182 if (!profile_delete_entries_
.empty())
184 // Run the callback if this is the last pending deletion.
185 if (!callback_
.is_null())
187 // Request NetworkStateHandler manager update to update ServiceCompleteList.
188 owner_
->network_state_handler_
->UpdateManagerProperties();
189 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
192 void ShillErrorCallback(const std::string
& profile_path
,
193 const std::string
& entry
,
194 const std::string
& dbus_error_name
,
195 const std::string
& dbus_error_message
) {
196 // Any Shill Error triggers a failure / error.
197 network_handler::ShillErrorCallbackFunction(
198 "GetLoadableProfileEntries Failed", profile_path
, error_callback_
,
199 dbus_error_name
, dbus_error_message
);
200 // Delete this even if there are pending deletions; any callbacks will
201 // safely become no-ops (by invalidating the WeakPtrs).
202 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
205 NetworkConfigurationHandler
* owner_
; // Unowned
206 std::string service_path_
;
207 base::Closure callback_
;
208 network_handler::ErrorCallback error_callback_
;
210 // Map of pending profile entry deletions, indexed by profile path.
211 std::map
<std::string
, std::string
> profile_delete_entries_
;
213 DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter
);
216 // NetworkConfigurationHandler
218 void NetworkConfigurationHandler::GetProperties(
219 const std::string
& service_path
,
220 const network_handler::DictionaryResultCallback
& callback
,
221 const network_handler::ErrorCallback
& error_callback
) const {
222 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
223 dbus::ObjectPath(service_path
),
224 base::Bind(&GetPropertiesCallback
,
225 callback
, error_callback
, service_path
));
228 void NetworkConfigurationHandler::SetProperties(
229 const std::string
& service_path
,
230 const base::DictionaryValue
& properties
,
231 const base::Closure
& callback
,
232 const network_handler::ErrorCallback
& error_callback
) {
233 if (properties
.empty()) {
234 if (!callback
.is_null())
238 NET_LOG_USER("SetProperties", service_path
);
239 LogConfigProperties("SetProperty", service_path
, properties
);
241 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
242 dbus::ObjectPath(service_path
),
244 base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback
,
245 AsWeakPtr(), service_path
, callback
),
246 base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback
,
247 AsWeakPtr(), service_path
, error_callback
));
250 void NetworkConfigurationHandler::ClearProperties(
251 const std::string
& service_path
,
252 const std::vector
<std::string
>& names
,
253 const base::Closure
& callback
,
254 const network_handler::ErrorCallback
& error_callback
) {
256 if (!callback
.is_null())
260 NET_LOG_USER("ClearProperties", service_path
);
261 for (std::vector
<std::string
>::const_iterator iter
= names
.begin();
262 iter
!= names
.end(); ++iter
) {
263 NET_LOG_DEBUG("ClearProperty", service_path
+ "." + *iter
);
265 DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
266 dbus::ObjectPath(service_path
),
268 base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback
,
269 AsWeakPtr(), service_path
, names
, callback
, error_callback
),
270 base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback
,
271 AsWeakPtr(), service_path
, error_callback
));
274 void NetworkConfigurationHandler::CreateConfiguration(
275 const base::DictionaryValue
& properties
,
276 const network_handler::StringResultCallback
& callback
,
277 const network_handler::ErrorCallback
& error_callback
) {
278 ShillManagerClient
* manager
=
279 DBusThreadManager::Get()->GetShillManagerClient();
281 properties
.GetStringWithoutPathExpansion(shill::kTypeProperty
, &type
);
282 if (NetworkTypePattern::Ethernet().MatchesType(type
)) {
284 "" /* no service path */,
286 "ConfigureServiceForProfile is not implemented for Ethernet");
290 NET_LOG_USER("CreateConfiguration", type
);
291 LogConfigProperties("Configure", type
, properties
);
294 properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
296 DCHECK(!profile
.empty());
297 manager
->ConfigureServiceForProfile(
298 dbus::ObjectPath(profile
),
300 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback
,
303 base::Bind(&network_handler::ShillErrorCallbackFunction
,
304 "Config.CreateConfiguration Failed",
309 void NetworkConfigurationHandler::RemoveConfiguration(
310 const std::string
& service_path
,
311 const base::Closure
& callback
,
312 const network_handler::ErrorCallback
& error_callback
) {
313 // Service.Remove is not reliable. Instead, request the profile entries
314 // for the service and remove each entry.
315 if (ContainsKey(profile_entry_deleters_
,service_path
)) {
317 service_path
, error_callback
, "RemoveConfigurationInProgress");
320 NET_LOG_USER("Remove Configuration", service_path
);
321 ProfileEntryDeleter
* deleter
=
322 new ProfileEntryDeleter(this, service_path
, callback
, error_callback
);
323 profile_entry_deleters_
[service_path
] = deleter
;
327 void NetworkConfigurationHandler::SetNetworkProfile(
328 const std::string
& service_path
,
329 const std::string
& profile_path
,
330 const base::Closure
& callback
,
331 const network_handler::ErrorCallback
& error_callback
) {
332 NET_LOG_USER("SetNetworkProfile", service_path
+ ": " + profile_path
);
333 base::StringValue
profile_path_value(profile_path
);
334 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
335 dbus::ObjectPath(service_path
),
336 shill::kProfileProperty
,
339 base::Bind(&SetNetworkProfileErrorCallback
,
340 service_path
, profile_path
, error_callback
));
343 // NetworkConfigurationHandler Private methods
345 NetworkConfigurationHandler::NetworkConfigurationHandler()
346 : network_state_handler_(NULL
) {
349 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
350 STLDeleteContainerPairSecondPointers(
351 profile_entry_deleters_
.begin(), profile_entry_deleters_
.end());
354 void NetworkConfigurationHandler::Init(
355 NetworkStateHandler
* network_state_handler
) {
356 network_state_handler_
= network_state_handler
;
359 void NetworkConfigurationHandler::RunCreateNetworkCallback(
360 const network_handler::StringResultCallback
& callback
,
361 const dbus::ObjectPath
& service_path
) {
362 if (!callback
.is_null())
363 callback
.Run(service_path
.value());
364 // This may also get called when CreateConfiguration is used to update an
365 // existing configuration, so request a service update just in case.
366 // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
367 // this on an update.
368 network_state_handler_
->RequestUpdateForNetwork(service_path
.value());
371 void NetworkConfigurationHandler::ProfileEntryDeleterCompleted(
372 const std::string
& service_path
) {
373 std::map
<std::string
, ProfileEntryDeleter
*>::iterator iter
=
374 profile_entry_deleters_
.find(service_path
);
375 DCHECK(iter
!= profile_entry_deleters_
.end());
377 profile_entry_deleters_
.erase(iter
);
380 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
381 const std::string
& service_path
,
382 const base::Closure
& callback
) {
383 if (!callback
.is_null())
385 network_state_handler_
->RequestUpdateForNetwork(service_path
);
388 void NetworkConfigurationHandler::SetPropertiesErrorCallback(
389 const std::string
& service_path
,
390 const network_handler::ErrorCallback
& error_callback
,
391 const std::string
& dbus_error_name
,
392 const std::string
& dbus_error_message
) {
393 network_handler::ShillErrorCallbackFunction(
394 "Config.SetProperties Failed",
395 service_path
, error_callback
,
396 dbus_error_name
, dbus_error_message
);
397 // Some properties may have changed so request an update regardless.
398 network_state_handler_
->RequestUpdateForNetwork(service_path
);
401 void NetworkConfigurationHandler::ClearPropertiesSuccessCallback(
402 const std::string
& service_path
,
403 const std::vector
<std::string
>& names
,
404 const base::Closure
& callback
,
405 const network_handler::ErrorCallback
& error_callback
,
406 const base::ListValue
& result
) {
407 const std::string
kClearPropertiesFailedError("Error.ClearPropertiesFailed");
408 DCHECK(names
.size() == result
.GetSize())
409 << "Incorrect result size from ClearProperties.";
411 bool some_failed
= false;
412 for (size_t i
= 0; i
< result
.GetSize(); ++i
) {
413 bool success
= false;
414 result
.GetBoolean(i
, &success
);
416 NET_LOG_ERROR("ClearProperties Failed: " + names
[i
], service_path
);
422 if (!error_callback
.is_null()) {
423 scoped_ptr
<base::DictionaryValue
> error_data(
424 network_handler::CreateErrorData(
425 service_path
, kClearPropertiesFailedError
,
426 base::StringPrintf("Errors: %" PRIuS
, result
.GetSize())));
427 error_data
->Set("errors", result
.DeepCopy());
428 scoped_ptr
<base::ListValue
> name_list(new base::ListValue
);
429 name_list
->AppendStrings(names
);
430 error_data
->Set("names", name_list
.release());
431 error_callback
.Run(kClearPropertiesFailedError
, error_data
.Pass());
433 } else if (!callback
.is_null()) {
436 network_state_handler_
->RequestUpdateForNetwork(service_path
);
439 void NetworkConfigurationHandler::ClearPropertiesErrorCallback(
440 const std::string
& service_path
,
441 const network_handler::ErrorCallback
& error_callback
,
442 const std::string
& dbus_error_name
,
443 const std::string
& dbus_error_message
) {
444 network_handler::ShillErrorCallbackFunction(
445 "Config.ClearProperties Failed",
446 service_path
, error_callback
,
447 dbus_error_name
, dbus_error_message
);
448 // Some properties may have changed so request an update regardless.
449 network_state_handler_
->RequestUpdateForNetwork(service_path
);
453 NetworkConfigurationHandler
* NetworkConfigurationHandler::InitializeForTest(
454 NetworkStateHandler
* network_state_handler
) {
455 NetworkConfigurationHandler
* handler
= new NetworkConfigurationHandler();
456 handler
->Init(network_state_handler
);
460 } // namespace chromeos