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/message_loop/message_loop.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/values.h"
20 #include "chromeos/dbus/shill_third_party_vpn_driver_client.h"
21 #include "chromeos/dbus/shill_third_party_vpn_observer.h"
22 #include "chromeos/network/network_configuration_handler.h"
23 #include "chromeos/network/network_profile.h"
24 #include "chromeos/network/network_profile_handler.h"
25 #include "chromeos/network/network_state.h"
26 #include "chromeos/network/network_state_handler.h"
27 #include "chromeos/network/network_type_pattern.h"
28 #include "crypto/sha2.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "third_party/cros_system_api/dbus/service_constants.h"
37 namespace api_vpn
= extensions::api::vpn_provider
;
39 void DoNothingFailureCallback(const std::string
& error_name
,
40 const std::string
& error_message
) {
41 LOG(ERROR
) << error_name
<< ": " << error_message
;
46 class VpnService::VpnConfiguration
: public ShillThirdPartyVpnObserver
{
48 VpnConfiguration(const std::string
& extension_id
,
49 const std::string
& configuration_name
,
50 const std::string
& key
,
51 base::WeakPtr
<VpnService
> vpn_service
);
52 ~VpnConfiguration() override
;
54 const std::string
& extension_id() const { return extension_id_
; }
55 const std::string
& configuration_name() const { return configuration_name_
; }
56 const std::string
& key() const { return key_
; }
57 const std::string
& service_path() const { return service_path_
; }
58 void set_service_path(const std::string
& service_path
) {
59 service_path_
= service_path
;
61 const std::string
& object_path() const { return object_path_
; }
63 // ShillThirdPartyVpnObserver:
64 void OnPacketReceived(const std::vector
<char>& data
) override
;
65 void OnPlatformMessage(uint32_t message
) override
;
68 const std::string extension_id_
;
69 const std::string configuration_name_
;
70 const std::string key_
;
71 const std::string object_path_
;
73 std::string service_path_
;
75 base::WeakPtr
<VpnService
> vpn_service_
;
77 DISALLOW_COPY_AND_ASSIGN(VpnConfiguration
);
80 VpnService::VpnConfiguration::VpnConfiguration(
81 const std::string
& extension_id
,
82 const std::string
& configuration_name
,
83 const std::string
& key
,
84 base::WeakPtr
<VpnService
> vpn_service
)
85 : extension_id_(extension_id
),
86 configuration_name_(configuration_name
),
88 object_path_(shill::kObjectPathBase
+ key_
),
89 vpn_service_(vpn_service
) {
92 VpnService::VpnConfiguration::~VpnConfiguration() {
95 void VpnService::VpnConfiguration::OnPacketReceived(
96 const std::vector
<char>& data
) {
100 scoped_ptr
<base::ListValue
> event_args
=
101 api_vpn::OnPacketReceived::Create(data
);
102 vpn_service_
->SendSignalToExtension(
103 extension_id_
, extensions::events::VPN_PROVIDER_ON_PACKET_RECEIVED
,
104 api_vpn::OnPacketReceived::kEventName
, event_args
.Pass());
107 void VpnService::VpnConfiguration::OnPlatformMessage(uint32_t message
) {
111 DCHECK_GE(api_vpn::PLATFORM_MESSAGE_LAST
, message
);
113 api_vpn::PlatformMessage platform_message
=
114 static_cast<api_vpn::PlatformMessage
>(message
);
115 vpn_service_
->SetActiveConfiguration(
116 platform_message
== api_vpn::PLATFORM_MESSAGE_CONNECTED
? this : nullptr);
118 // TODO(kaliamoorthi): Update the lower layers to get the error message and
119 // pass in the error instead of std::string().
120 scoped_ptr
<base::ListValue
> event_args
= api_vpn::OnPlatformMessage::Create(
121 configuration_name_
, platform_message
, std::string());
123 vpn_service_
->SendSignalToExtension(
124 extension_id_
, extensions::events::VPN_PROVIDER_ON_PLATFORM_MESSAGE
,
125 api_vpn::OnPlatformMessage::kEventName
, event_args
.Pass());
128 VpnService::VpnService(
129 content::BrowserContext
* browser_context
,
130 const std::string
& userid_hash
,
131 extensions::ExtensionRegistry
* extension_registry
,
132 extensions::EventRouter
* event_router
,
133 ShillThirdPartyVpnDriverClient
* shill_client
,
134 NetworkConfigurationHandler
* network_configuration_handler
,
135 NetworkProfileHandler
* network_profile_handler
,
136 NetworkStateHandler
* network_state_handler
)
137 : browser_context_(browser_context
),
138 userid_hash_(userid_hash
),
139 extension_registry_(extension_registry
),
140 event_router_(event_router
),
141 shill_client_(shill_client
),
142 network_configuration_handler_(network_configuration_handler
),
143 network_profile_handler_(network_profile_handler
),
144 network_state_handler_(network_state_handler
),
145 active_configuration_(nullptr),
146 weak_factory_(this) {
147 extension_registry_
->AddObserver(this);
148 network_state_handler_
->AddObserver(this, FROM_HERE
);
149 network_configuration_handler_
->AddObserver(this);
150 base::MessageLoop::current()->PostTask(
152 base::Bind(&VpnService::NetworkListChanged
, weak_factory_
.GetWeakPtr()));
155 VpnService::~VpnService() {
156 network_configuration_handler_
->RemoveObserver(this);
157 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
158 extension_registry_
->RemoveObserver(this);
159 STLDeleteContainerPairSecondPointers(key_to_configuration_map_
.begin(),
160 key_to_configuration_map_
.end());
163 void VpnService::SendShowAddDialogToExtension(const std::string
& extension_id
) {
164 SendSignalToExtension(extension_id
,
165 extensions::events::VPN_PROVIDER_ON_UI_EVENT
,
166 api_vpn::OnUIEvent::kEventName
,
167 api_vpn::OnUIEvent::Create(
168 api_vpn::UI_EVENT_SHOWADDDIALOG
, std::string()));
171 void VpnService::SendShowConfigureDialogToExtension(
172 const std::string
& extension_id
,
173 const std::string
& configuration_id
) {
174 SendSignalToExtension(
175 extension_id
, extensions::events::VPN_PROVIDER_ON_UI_EVENT
,
176 api_vpn::OnUIEvent::kEventName
,
177 api_vpn::OnUIEvent::Create(api_vpn::UI_EVENT_SHOWCONFIGUREDIALOG
,
181 void VpnService::SendPlatformError(const std::string
& extension_id
,
182 const std::string
& configuration_id
,
183 const std::string
& error_message
) {
184 SendSignalToExtension(
185 extension_id
, extensions::events::VPN_PROVIDER_ON_PLATFORM_MESSAGE
,
186 api_vpn::OnPlatformMessage::kEventName
,
187 api_vpn::OnPlatformMessage::Create(
188 configuration_id
, api_vpn::PLATFORM_MESSAGE_ERROR
, error_message
));
191 std::string
VpnService::GetKey(const std::string
& extension_id
,
192 const std::string
& name
) {
193 const std::string key
= crypto::SHA256HashString(extension_id
+ name
);
194 return base::HexEncode(key
.data(), key
.size());
197 void VpnService::OnConfigurationCreated(const std::string
& service_path
,
198 const std::string
& profile_path
,
199 const base::DictionaryValue
& properties
,
203 void VpnService::OnConfigurationRemoved(const std::string
& service_path
,
204 const std::string
& guid
,
206 if (source
== SOURCE_EXTENSION_INSTALL
) {
207 // No need to process if the configuration was removed using an extension
208 // API since the API would have already done the cleanup.
212 if (service_path_to_configuration_map_
.find(service_path
) ==
213 service_path_to_configuration_map_
.end()) {
214 // Ignore removal of a configuration unknown to VPN service, which means the
215 // configuration was created internally by the platform.
219 VpnConfiguration
* configuration
=
220 service_path_to_configuration_map_
[service_path
];
221 scoped_ptr
<base::ListValue
> event_args
=
222 api_vpn::OnConfigRemoved::Create(configuration
->configuration_name());
223 SendSignalToExtension(configuration
->extension_id(),
224 extensions::events::VPN_PROVIDER_ON_CONFIG_REMOVED
,
225 api_vpn::OnConfigRemoved::kEventName
,
228 DestroyConfigurationInternal(configuration
);
231 void VpnService::OnPropertiesSet(const std::string
& service_path
,
232 const std::string
& guid
,
233 const base::DictionaryValue
& set_properties
,
237 void VpnService::OnConfigurationProfileChanged(const std::string
& service_path
,
238 const std::string
& profile_path
,
242 void VpnService::OnGetPropertiesSuccess(
243 const std::string
& service_path
,
244 const base::DictionaryValue
& dictionary
) {
245 if (service_path_to_configuration_map_
.find(service_path
) !=
246 service_path_to_configuration_map_
.end()) {
249 std::string vpn_type
;
250 std::string extension_id
;
252 std::string configuration_name
;
253 if (!dictionary
.GetString(shill::kProviderTypeProperty
, &vpn_type
) ||
254 !dictionary
.GetString(shill::kProviderHostProperty
, &extension_id
) ||
255 !dictionary
.GetString(shill::kTypeProperty
, &type
) ||
256 !dictionary
.GetString(shill::kNameProperty
, &configuration_name
) ||
257 vpn_type
!= shill::kProviderThirdPartyVpn
|| type
!= shill::kTypeVPN
) {
261 if (!extension_registry_
->GetExtensionById(
262 extension_id
, extensions::ExtensionRegistry::ENABLED
)) {
263 // Does not belong to this instance of VpnService.
267 const std::string key
= GetKey(extension_id
, configuration_name
);
268 VpnConfiguration
* configuration
=
269 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
270 configuration
->set_service_path(service_path
);
271 service_path_to_configuration_map_
[service_path
] = configuration
;
272 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
276 void VpnService::OnGetPropertiesFailure(
277 const std::string
& error_name
,
278 scoped_ptr
<base::DictionaryValue
> error_data
) {
281 void VpnService::NetworkListChanged() {
282 NetworkStateHandler::NetworkStateList network_list
;
283 network_state_handler_
->GetVisibleNetworkListByType(NetworkTypePattern::VPN(),
285 for (auto& iter
: network_list
) {
286 if (service_path_to_configuration_map_
.find(iter
->path()) !=
287 service_path_to_configuration_map_
.end()) {
291 network_configuration_handler_
->GetShillProperties(
292 iter
->path(), base::Bind(&VpnService::OnGetPropertiesSuccess
,
293 weak_factory_
.GetWeakPtr()),
294 base::Bind(&VpnService::OnGetPropertiesFailure
,
295 weak_factory_
.GetWeakPtr()));
299 void VpnService::CreateConfiguration(const std::string
& extension_id
,
300 const std::string
& extension_name
,
301 const std::string
& configuration_name
,
302 const SuccessCallback
& success
,
303 const FailureCallback
& failure
) {
304 if (configuration_name
.empty()) {
305 failure
.Run(std::string(), std::string("Empty name not supported."));
309 const std::string key
= GetKey(extension_id
, configuration_name
);
310 if (ContainsKey(key_to_configuration_map_
, key
)) {
311 failure
.Run(std::string(), std::string("Name not unique."));
315 const NetworkProfile
* profile
=
316 network_profile_handler_
->GetProfileForUserhash(userid_hash_
);
320 std::string("No user profile for unshared network configuration."));
324 VpnConfiguration
* configuration
=
325 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
327 base::DictionaryValue properties
;
328 properties
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
330 properties
.SetStringWithoutPathExpansion(shill::kNameProperty
,
332 properties
.SetStringWithoutPathExpansion(shill::kProviderHostProperty
,
334 properties
.SetStringWithoutPathExpansion(shill::kObjectPathSuffixProperty
,
335 configuration
->key());
336 properties
.SetStringWithoutPathExpansion(shill::kProviderTypeProperty
,
337 shill::kProviderThirdPartyVpn
);
338 properties
.SetStringWithoutPathExpansion(shill::kProfileProperty
,
341 // Note: This will not create an entry in |policy_util|. TODO(pneubeck):
342 // Determine the correct thing to do here, crbug.com/459278.
343 std::string guid
= base::GenerateGUID();
344 properties
.SetStringWithoutPathExpansion(shill::kGuidProperty
, guid
);
346 network_configuration_handler_
->CreateShillConfiguration(
347 properties
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
348 base::Bind(&VpnService::OnCreateConfigurationSuccess
,
349 weak_factory_
.GetWeakPtr(), success
, configuration
),
350 base::Bind(&VpnService::OnCreateConfigurationFailure
,
351 weak_factory_
.GetWeakPtr(), failure
, configuration
));
354 void VpnService::DestroyConfiguration(const std::string
& extension_id
,
355 const std::string
& configuration_id
,
356 const SuccessCallback
& success
,
357 const FailureCallback
& failure
) {
358 // The ID is the configuration name for now. This may change in the future.
359 const std::string key
= GetKey(extension_id
, configuration_id
);
360 if (!ContainsKey(key_to_configuration_map_
, key
)) {
361 failure
.Run(std::string(), std::string("Unauthorized access."));
365 VpnConfiguration
* configuration
= key_to_configuration_map_
[key
];
366 const std::string service_path
= configuration
->service_path();
367 if (service_path
.empty()) {
368 failure
.Run(std::string(), std::string("Pending create."));
371 if (active_configuration_
== configuration
) {
372 configuration
->OnPlatformMessage(api_vpn::PLATFORM_MESSAGE_DISCONNECTED
);
374 DestroyConfigurationInternal(configuration
);
376 network_configuration_handler_
->RemoveConfiguration(
377 service_path
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
378 base::Bind(&VpnService::OnRemoveConfigurationSuccess
,
379 weak_factory_
.GetWeakPtr(), success
),
380 base::Bind(&VpnService::OnRemoveConfigurationFailure
,
381 weak_factory_
.GetWeakPtr(), failure
));
384 void VpnService::SetParameters(const std::string
& extension_id
,
385 const base::DictionaryValue
& parameters
,
386 const StringCallback
& success
,
387 const FailureCallback
& failure
) {
388 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
389 failure
.Run(std::string(), std::string("Unauthorized access."));
393 shill_client_
->SetParameters(active_configuration_
->object_path(), parameters
,
397 void VpnService::SendPacket(const std::string
& extension_id
,
398 const std::vector
<char>& data
,
399 const SuccessCallback
& success
,
400 const FailureCallback
& failure
) {
401 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
402 failure
.Run(std::string(), std::string("Unauthorized access."));
407 failure
.Run(std::string(), std::string("Can't send an empty packet."));
411 shill_client_
->SendPacket(active_configuration_
->object_path(), data
, success
,
415 void VpnService::NotifyConnectionStateChanged(const std::string
& extension_id
,
416 api_vpn::VpnConnectionState state
,
417 const SuccessCallback
& success
,
418 const FailureCallback
& failure
) {
419 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
420 failure
.Run(std::string(), std::string("Unauthorized access."));
424 shill_client_
->UpdateConnectionState(active_configuration_
->object_path(),
425 static_cast<uint32_t>(state
), success
,
429 bool VpnService::VerifyConfigExistsForTesting(
430 const std::string
& extension_id
,
431 const std::string
& configuration_name
) {
432 const std::string key
= GetKey(extension_id
, configuration_name
);
433 return ContainsKey(key_to_configuration_map_
, key
);
436 bool VpnService::VerifyConfigIsConnectedForTesting(
437 const std::string
& extension_id
) {
438 return DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
);
441 void VpnService::DestroyConfigurationsForExtension(
442 const extensions::Extension
* extension
) {
443 std::vector
<VpnConfiguration
*> to_be_destroyed
;
444 for (const auto& iter
: key_to_configuration_map_
) {
445 if (iter
.second
->extension_id() == extension
->id()) {
446 to_be_destroyed
.push_back(iter
.second
);
450 for (auto& iter
: to_be_destroyed
) {
451 DestroyConfiguration(extension
->id(), // Extension ID
452 iter
->configuration_name(), // Configuration name
453 base::Bind(base::DoNothing
),
454 base::Bind(DoNothingFailureCallback
));
458 void VpnService::OnExtensionUninstalled(
459 content::BrowserContext
* browser_context
,
460 const extensions::Extension
* extension
,
461 extensions::UninstallReason reason
) {
462 if (browser_context
!= browser_context_
) {
467 DestroyConfigurationsForExtension(extension
);
470 void VpnService::OnExtensionUnloaded(
471 content::BrowserContext
* browser_context
,
472 const extensions::Extension
* extension
,
473 extensions::UnloadedExtensionInfo::Reason reason
) {
474 if (browser_context
!= browser_context_
) {
479 if (active_configuration_
&&
480 active_configuration_
->extension_id() == extension
->id()) {
481 shill_client_
->UpdateConnectionState(
482 active_configuration_
->object_path(),
483 static_cast<uint32_t>(api_vpn::VPN_CONNECTION_STATE_FAILURE
),
484 base::Bind(base::DoNothing
), base::Bind(DoNothingFailureCallback
));
486 if (reason
== extensions::UnloadedExtensionInfo::REASON_DISABLE
||
487 reason
== extensions::UnloadedExtensionInfo::REASON_BLACKLIST
) {
488 DestroyConfigurationsForExtension(extension
);
492 void VpnService::OnCreateConfigurationSuccess(
493 const VpnService::SuccessCallback
& callback
,
494 VpnConfiguration
* configuration
,
495 const std::string
& service_path
) {
496 configuration
->set_service_path(service_path
);
497 service_path_to_configuration_map_
[service_path
] = configuration
;
498 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
503 void VpnService::OnCreateConfigurationFailure(
504 const VpnService::FailureCallback
& callback
,
505 VpnConfiguration
* configuration
,
506 const std::string
& error_name
,
507 scoped_ptr
<base::DictionaryValue
> error_data
) {
508 DestroyConfigurationInternal(configuration
);
509 callback
.Run(error_name
, std::string());
512 void VpnService::OnRemoveConfigurationSuccess(
513 const VpnService::SuccessCallback
& callback
) {
517 void VpnService::OnRemoveConfigurationFailure(
518 const VpnService::FailureCallback
& callback
,
519 const std::string
& error_name
,
520 scoped_ptr
<base::DictionaryValue
> error_data
) {
521 callback
.Run(error_name
, std::string());
524 void VpnService::SendSignalToExtension(
525 const std::string
& extension_id
,
526 extensions::events::HistogramValue histogram_value
,
527 const std::string
& event_name
,
528 scoped_ptr
<base::ListValue
> event_args
) {
529 scoped_ptr
<extensions::Event
> event(new extensions::Event(
530 histogram_value
, event_name
, event_args
.Pass(), browser_context_
));
532 event_router_
->DispatchEventToExtension(extension_id
, event
.Pass());
535 void VpnService::SetActiveConfiguration(
536 VpnService::VpnConfiguration
* configuration
) {
537 active_configuration_
= configuration
;
540 VpnService::VpnConfiguration
* VpnService::CreateConfigurationInternal(
541 const std::string
& extension_id
,
542 const std::string
& configuration_name
,
543 const std::string
& key
) {
544 VpnConfiguration
* configuration
= new VpnConfiguration(
545 extension_id
, configuration_name
, key
, weak_factory_
.GetWeakPtr());
546 // The object is owned by key_to_configuration_map_ henceforth.
547 key_to_configuration_map_
[key
] = configuration
;
548 return configuration
;
551 void VpnService::DestroyConfigurationInternal(VpnConfiguration
* configuration
) {
552 key_to_configuration_map_
.erase(configuration
->key());
553 if (active_configuration_
== configuration
) {
554 active_configuration_
= nullptr;
556 if (!configuration
->service_path().empty()) {
557 shill_client_
->RemoveShillThirdPartyVpnObserver(
558 configuration
->object_path());
559 service_path_to_configuration_map_
.erase(configuration
->service_path());
561 delete configuration
;
564 bool VpnService::DoesActiveConfigurationExistAndIsAccessAuthorized(
565 const std::string
& extension_id
) {
566 return active_configuration_
&&
567 active_configuration_
->extension_id() == extension_id
;
570 } // namespace chromeos