1 // Copyright 2014 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 "extensions/browser/api/vpn_provider/vpn_service.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/guid.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "chromeos/dbus/shill_third_party_vpn_driver_client.h"
20 #include "chromeos/dbus/shill_third_party_vpn_observer.h"
21 #include "chromeos/network/network_configuration_handler.h"
22 #include "chromeos/network/network_profile.h"
23 #include "chromeos/network/network_profile_handler.h"
24 #include "chromeos/network/network_state.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/network_type_pattern.h"
27 #include "crypto/sha2.h"
28 #include "extensions/browser/event_router.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "third_party/cros_system_api/dbus/service_constants.h"
36 namespace api_vpn
= extensions::core_api::vpn_provider
;
38 std::string
GetKey(const std::string
& extension_id
, const std::string
& name
) {
39 const std::string key
= crypto::SHA256HashString(extension_id
+ name
);
40 return base::HexEncode(key
.data(), key
.size());
43 std::string
GetCombinedName(const std::string
& extension_name
,
44 const std::string
& configuration_name
) {
45 // TODO(kaliamoorthi): (crbug.com/434711) Sort out the dependencies and
46 // replace the string concatenation with internationalized version.
47 return extension_name
+ ": " + configuration_name
;
50 void DoNothingFailureCallback(const std::string
& error_name
,
51 const std::string
& error_message
) {
52 LOG(ERROR
) << error_name
<< ": " << error_message
;
57 class VpnService::VpnConfiguration
: public ShillThirdPartyVpnObserver
{
59 VpnConfiguration(const std::string
& extension_id
,
60 const std::string
& configuration_name
,
61 const std::string
& key
,
62 base::WeakPtr
<VpnService
> vpn_service
);
63 ~VpnConfiguration() override
;
65 const std::string
& extension_id() const { return extension_id_
; }
66 const std::string
& configuration_name() const { return configuration_name_
; }
67 const std::string
& key() const { return key_
; }
68 const std::string
& service_path() const { return service_path_
; }
69 void set_service_path(const std::string
& service_path
) {
70 service_path_
= service_path
;
72 const std::string
& object_path() const { return object_path_
; }
74 // ShillThirdPartyVpnObserver:
75 void OnPacketReceived(const std::vector
<char>& data
) override
;
76 void OnPlatformMessage(uint32_t message
) override
;
79 const std::string extension_id_
;
80 const std::string configuration_name_
;
81 const std::string key_
;
82 const std::string object_path_
;
84 std::string service_path_
;
86 base::WeakPtr
<VpnService
> vpn_service_
;
88 DISALLOW_COPY_AND_ASSIGN(VpnConfiguration
);
91 VpnService::VpnConfiguration::VpnConfiguration(
92 const std::string
& extension_id
,
93 const std::string
& configuration_name
,
94 const std::string
& key
,
95 base::WeakPtr
<VpnService
> vpn_service
)
96 : extension_id_(extension_id
),
97 configuration_name_(configuration_name
),
99 object_path_(shill::kObjectPathBase
+ key_
),
100 vpn_service_(vpn_service
) {
103 VpnService::VpnConfiguration::~VpnConfiguration() {
106 void VpnService::VpnConfiguration::OnPacketReceived(
107 const std::vector
<char>& data
) {
111 scoped_ptr
<base::ListValue
> event_args
=
112 api_vpn::OnPacketReceived::Create(data
);
113 vpn_service_
->SendSignalToExtension(
114 extension_id_
, api_vpn::OnPacketReceived::kEventName
, event_args
.Pass());
117 void VpnService::VpnConfiguration::OnPlatformMessage(uint32_t message
) {
121 DCHECK_GE(api_vpn::PLATFORM_MESSAGE_LAST
, message
);
123 api_vpn::PlatformMessage platform_message
=
124 static_cast<api_vpn::PlatformMessage
>(message
);
125 vpn_service_
->SetActiveConfiguration(
126 platform_message
== api_vpn::PLATFORM_MESSAGE_CONNECTED
? this : nullptr);
128 // TODO(kaliamoorthi): Update the lower layers to get the error message and
129 // pass in the error instead of std::string().
130 scoped_ptr
<base::ListValue
> event_args
= api_vpn::OnPlatformMessage::Create(
131 configuration_name_
, platform_message
, std::string());
133 vpn_service_
->SendSignalToExtension(
134 extension_id_
, api_vpn::OnPlatformMessage::kEventName
, event_args
.Pass());
137 VpnService::VpnService(
138 content::BrowserContext
* browser_context
,
139 const std::string
& userid_hash
,
140 extensions::ExtensionRegistry
* extension_registry
,
141 extensions::EventRouter
* event_router
,
142 ShillThirdPartyVpnDriverClient
* shill_client
,
143 NetworkConfigurationHandler
* network_configuration_handler
,
144 NetworkProfileHandler
* network_profile_handler
,
145 NetworkStateHandler
* network_state_handler
)
146 : browser_context_(browser_context
),
147 userid_hash_(userid_hash
),
148 extension_registry_(extension_registry
),
149 event_router_(event_router
),
150 shill_client_(shill_client
),
151 network_configuration_handler_(network_configuration_handler
),
152 network_profile_handler_(network_profile_handler
),
153 network_state_handler_(network_state_handler
),
154 active_configuration_(nullptr),
155 weak_factory_(this) {
156 extension_registry_
->AddObserver(this);
157 network_state_handler_
->AddObserver(this, FROM_HERE
);
158 network_configuration_handler_
->AddObserver(this);
161 VpnService::~VpnService() {
162 network_configuration_handler_
->RemoveObserver(this);
163 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
164 extension_registry_
->RemoveObserver(this);
165 STLDeleteContainerPairSecondPointers(key_to_configuration_map_
.begin(),
166 key_to_configuration_map_
.end());
169 void VpnService::OnConfigurationCreated(const std::string
& service_path
,
170 const std::string
& profile_path
,
171 const base::DictionaryValue
& properties
,
175 void VpnService::OnConfigurationRemoved(const std::string
& service_path
,
176 const std::string
& guid
,
178 if (source
== SOURCE_EXTENSION_INSTALL
) {
179 // No need to process if the configuration was removed using an extension
180 // API since the API would have already done the cleanup.
184 if (service_path_to_configuration_map_
.find(service_path
) ==
185 service_path_to_configuration_map_
.end()) {
186 // Ignore removal of a configuration unknown to VPN service, which means the
187 // configuration was created internally by the platform.
191 VpnConfiguration
* configuration
=
192 service_path_to_configuration_map_
[service_path
];
193 scoped_ptr
<base::ListValue
> event_args
=
194 api_vpn::OnConfigRemoved::Create(configuration
->configuration_name());
195 SendSignalToExtension(configuration
->extension_id(),
196 api_vpn::OnConfigRemoved::kEventName
,
199 DestroyConfigurationInternal(configuration
);
202 void VpnService::OnPropertiesSet(const std::string
& service_path
,
203 const std::string
& guid
,
204 const base::DictionaryValue
& set_properties
,
208 void VpnService::OnConfigurationProfileChanged(const std::string
& service_path
,
209 const std::string
& profile_path
,
213 void VpnService::OnGetPropertiesSuccess(
214 const std::string
& service_path
,
215 const base::DictionaryValue
& dictionary
) {
216 if (service_path_to_configuration_map_
.find(service_path
) !=
217 service_path_to_configuration_map_
.end()) {
220 const base::DictionaryValue
* provider
= nullptr;
221 std::string vpn_type
;
222 std::string extension_id
;
225 std::string configuration_name
;
226 if (!dictionary
.GetDictionary(shill::kProviderProperty
, &provider
) ||
227 !dictionary
.GetString(shill::kProviderTypeProperty
, &vpn_type
) ||
228 !dictionary
.GetString(shill::kProviderHostProperty
, &extension_id
) ||
229 !dictionary
.GetString(shill::kTypeProperty
, &type
) ||
230 !dictionary
.GetString(shill::kNameProperty
, &name
) ||
231 !provider
->GetString(shill::kConfigurationNameProperty
,
232 &configuration_name
) ||
233 vpn_type
!= shill::kProviderThirdPartyVpn
|| type
!= shill::kTypeVPN
) {
237 if (!extension_registry_
->GetExtensionById(
238 extension_id
, extensions::ExtensionRegistry::ENABLED
)) {
239 // Does not belong to this instance of VpnService.
243 const std::string key
= GetKey(extension_id
, configuration_name
);
244 VpnConfiguration
* configuration
=
245 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
246 configuration
->set_service_path(service_path
);
247 service_path_to_configuration_map_
[service_path
] = configuration
;
248 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
252 void VpnService::OnGetPropertiesFailure(
253 const std::string
& error_name
,
254 scoped_ptr
<base::DictionaryValue
> error_data
) {
257 void VpnService::NetworkListChanged() {
258 NetworkStateHandler::NetworkStateList network_list
;
259 network_state_handler_
->GetVisibleNetworkListByType(NetworkTypePattern::VPN(),
261 for (auto& iter
: network_list
) {
262 if (service_path_to_configuration_map_
.find(iter
->path()) !=
263 service_path_to_configuration_map_
.end()) {
267 network_configuration_handler_
->GetShillProperties(
268 iter
->path(), base::Bind(&VpnService::OnGetPropertiesSuccess
,
269 weak_factory_
.GetWeakPtr()),
270 base::Bind(&VpnService::OnGetPropertiesFailure
,
271 weak_factory_
.GetWeakPtr()));
275 void VpnService::CreateConfiguration(const std::string
& extension_id
,
276 const std::string
& extension_name
,
277 const std::string
& configuration_name
,
278 const SuccessCallback
& success
,
279 const FailureCallback
& failure
) {
280 if (configuration_name
.empty()) {
281 failure
.Run(std::string(), std::string("Empty name not supported."));
285 const std::string key
= GetKey(extension_id
, configuration_name
);
286 if (ContainsKey(key_to_configuration_map_
, key
)) {
287 failure
.Run(std::string(), std::string("Name not unique."));
291 const NetworkProfile
* profile
=
292 network_profile_handler_
->GetProfileForUserhash(userid_hash_
);
296 std::string("No user profile for unshared network configuration."));
300 VpnConfiguration
* configuration
=
301 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
303 base::DictionaryValue properties
;
304 properties
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
306 properties
.SetStringWithoutPathExpansion(
307 shill::kNameProperty
, // This value is shown to the user in native UI.
308 GetCombinedName(extension_name
, configuration_name
));
309 properties
.SetStringWithoutPathExpansion(shill::kProviderHostProperty
,
311 properties
.SetStringWithoutPathExpansion(shill::kObjectPathSuffixProperty
,
312 configuration
->key());
313 properties
.SetStringWithoutPathExpansion(shill::kProviderTypeProperty
,
314 shill::kProviderThirdPartyVpn
);
315 properties
.SetStringWithoutPathExpansion(shill::kProfileProperty
,
317 properties
.SetStringWithoutPathExpansion(shill::kConfigurationNameProperty
,
320 // Note: This will not create an entry in |policy_util|. TODO(pneubeck):
321 // Determine the correct thing to do here, crbug.com/459278.
322 std::string guid
= base::GenerateGUID();
323 properties
.SetStringWithoutPathExpansion(shill::kGuidProperty
, guid
);
325 network_configuration_handler_
->CreateShillConfiguration(
326 properties
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
327 base::Bind(&VpnService::OnCreateConfigurationSuccess
,
328 weak_factory_
.GetWeakPtr(), success
, configuration
),
329 base::Bind(&VpnService::OnCreateConfigurationFailure
,
330 weak_factory_
.GetWeakPtr(), failure
, configuration
));
333 void VpnService::DestroyConfiguration(const std::string
& extension_id
,
334 const std::string
& configuration_name
,
335 const SuccessCallback
& success
,
336 const FailureCallback
& failure
) {
337 const std::string key
= GetKey(extension_id
, configuration_name
);
338 if (!ContainsKey(key_to_configuration_map_
, key
)) {
339 failure
.Run(std::string(), std::string("Unauthorized access."));
343 VpnConfiguration
* configuration
= key_to_configuration_map_
[key
];
344 const std::string service_path
= configuration
->service_path();
345 DestroyConfigurationInternal(configuration
);
347 network_configuration_handler_
->RemoveConfiguration(
348 service_path
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
349 base::Bind(&VpnService::OnRemoveConfigurationSuccess
,
350 weak_factory_
.GetWeakPtr(), success
),
351 base::Bind(&VpnService::OnRemoveConfigurationFailure
,
352 weak_factory_
.GetWeakPtr(), failure
));
355 void VpnService::SetParameters(const std::string
& extension_id
,
356 const base::DictionaryValue
& parameters
,
357 const SuccessCallback
& success
,
358 const FailureCallback
& failure
) {
359 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
360 failure
.Run(std::string(), std::string("Unauthorized access."));
364 shill_client_
->SetParameters(active_configuration_
->object_path(), parameters
,
368 void VpnService::SendPacket(const std::string
& extension_id
,
369 const std::vector
<char>& data
,
370 const SuccessCallback
& success
,
371 const FailureCallback
& failure
) {
372 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
373 failure
.Run(std::string(), std::string("Unauthorized access."));
378 failure
.Run(std::string(), std::string("Can't send an empty packet."));
382 shill_client_
->SendPacket(active_configuration_
->object_path(), data
, success
,
386 void VpnService::NotifyConnectionStateChanged(const std::string
& extension_id
,
387 api_vpn::VpnConnectionState state
,
388 const SuccessCallback
& success
,
389 const FailureCallback
& failure
) {
390 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
391 failure
.Run(std::string(), std::string("Unauthorized access."));
395 shill_client_
->UpdateConnectionState(active_configuration_
->object_path(),
396 static_cast<uint32_t>(state
), success
,
400 void VpnService::OnExtensionUninstalled(
401 content::BrowserContext
* browser_context
,
402 const extensions::Extension
* extension
,
403 extensions::UninstallReason reason
) {
404 if (browser_context
!= browser_context_
) {
409 std::vector
<VpnConfiguration
*> to_be_destroyed
;
410 for (const auto& iter
: key_to_configuration_map_
) {
411 if (iter
.second
->extension_id() == extension
->id()) {
412 to_be_destroyed
.push_back(iter
.second
);
416 for (auto& iter
: to_be_destroyed
) {
417 DestroyConfiguration(extension
->id(), // Extension ID
418 iter
->configuration_name(), // Configuration name
419 base::Bind(base::DoNothing
),
420 base::Bind(DoNothingFailureCallback
));
424 void VpnService::OnCreateConfigurationSuccess(
425 const VpnService::SuccessCallback
& callback
,
426 VpnConfiguration
* configuration
,
427 const std::string
& service_path
) {
428 configuration
->set_service_path(service_path
);
429 service_path_to_configuration_map_
[service_path
] = configuration
;
430 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
435 void VpnService::OnCreateConfigurationFailure(
436 const VpnService::FailureCallback
& callback
,
437 VpnConfiguration
* configuration
,
438 const std::string
& error_name
,
439 scoped_ptr
<base::DictionaryValue
> error_data
) {
440 DestroyConfigurationInternal(configuration
);
441 callback
.Run(error_name
, std::string());
444 void VpnService::OnRemoveConfigurationSuccess(
445 const VpnService::SuccessCallback
& callback
) {
449 void VpnService::OnRemoveConfigurationFailure(
450 const VpnService::FailureCallback
& callback
,
451 const std::string
& error_name
,
452 scoped_ptr
<base::DictionaryValue
> error_data
) {
453 callback
.Run(error_name
, std::string());
456 void VpnService::SendSignalToExtension(const std::string
& extension_id
,
457 const std::string
& event_name
,
458 scoped_ptr
<base::ListValue
> event_args
) {
459 scoped_ptr
<extensions::Event
> event(
460 new extensions::Event(event_name
, event_args
.Pass(), browser_context_
));
462 event_router_
->DispatchEventToExtension(extension_id
, event
.Pass());
465 void VpnService::SetActiveConfiguration(
466 VpnService::VpnConfiguration
* configuration
) {
467 active_configuration_
= configuration
;
470 VpnService::VpnConfiguration
* VpnService::CreateConfigurationInternal(
471 const std::string
& extension_id
,
472 const std::string
& configuration_name
,
473 const std::string
& key
) {
474 VpnConfiguration
* configuration
= new VpnConfiguration(
475 extension_id
, configuration_name
, key
, weak_factory_
.GetWeakPtr());
476 // The object is owned by key_to_configuration_map_ henceforth.
477 key_to_configuration_map_
[key
] = configuration
;
478 return configuration
;
481 void VpnService::DestroyConfigurationInternal(VpnConfiguration
* configuration
) {
482 key_to_configuration_map_
.erase(configuration
->key());
483 if (active_configuration_
== configuration
) {
484 active_configuration_
= nullptr;
486 if (!configuration
->service_path().empty()) {
487 shill_client_
->RemoveShillThirdPartyVpnObserver(
488 configuration
->object_path());
489 service_path_to_configuration_map_
.erase(configuration
->service_path());
491 delete configuration
;
494 bool VpnService::DoesActiveConfigurationExistAndIsAccessAuthorized(
495 const std::string
& extension_id
) {
496 return active_configuration_
&&
497 active_configuration_
->extension_id() == extension_id
;
500 } // namespace chromeos