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::core_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_
, api_vpn::OnPacketReceived::kEventName
, event_args
.Pass());
106 void VpnService::VpnConfiguration::OnPlatformMessage(uint32_t message
) {
110 DCHECK_GE(api_vpn::PLATFORM_MESSAGE_LAST
, message
);
112 api_vpn::PlatformMessage platform_message
=
113 static_cast<api_vpn::PlatformMessage
>(message
);
114 vpn_service_
->SetActiveConfiguration(
115 platform_message
== api_vpn::PLATFORM_MESSAGE_CONNECTED
? this : nullptr);
117 // TODO(kaliamoorthi): Update the lower layers to get the error message and
118 // pass in the error instead of std::string().
119 scoped_ptr
<base::ListValue
> event_args
= api_vpn::OnPlatformMessage::Create(
120 configuration_name_
, platform_message
, std::string());
122 vpn_service_
->SendSignalToExtension(
123 extension_id_
, api_vpn::OnPlatformMessage::kEventName
, event_args
.Pass());
126 VpnService::VpnService(
127 content::BrowserContext
* browser_context
,
128 const std::string
& userid_hash
,
129 extensions::ExtensionRegistry
* extension_registry
,
130 extensions::EventRouter
* event_router
,
131 ShillThirdPartyVpnDriverClient
* shill_client
,
132 NetworkConfigurationHandler
* network_configuration_handler
,
133 NetworkProfileHandler
* network_profile_handler
,
134 NetworkStateHandler
* network_state_handler
)
135 : browser_context_(browser_context
),
136 userid_hash_(userid_hash
),
137 extension_registry_(extension_registry
),
138 event_router_(event_router
),
139 shill_client_(shill_client
),
140 network_configuration_handler_(network_configuration_handler
),
141 network_profile_handler_(network_profile_handler
),
142 network_state_handler_(network_state_handler
),
143 active_configuration_(nullptr),
144 weak_factory_(this) {
145 extension_registry_
->AddObserver(this);
146 network_state_handler_
->AddObserver(this, FROM_HERE
);
147 network_configuration_handler_
->AddObserver(this);
148 base::MessageLoop::current()->PostTask(
150 base::Bind(&VpnService::NetworkListChanged
, weak_factory_
.GetWeakPtr()));
153 VpnService::~VpnService() {
154 network_configuration_handler_
->RemoveObserver(this);
155 network_state_handler_
->RemoveObserver(this, FROM_HERE
);
156 extension_registry_
->RemoveObserver(this);
157 STLDeleteContainerPairSecondPointers(key_to_configuration_map_
.begin(),
158 key_to_configuration_map_
.end());
161 void VpnService::SendShowAddDialogToExtension(const std::string
& extension_id
) {
162 SendSignalToExtension(extension_id
, api_vpn::OnUIEvent::kEventName
,
163 api_vpn::OnUIEvent::Create(
164 api_vpn::UI_EVENT_SHOWADDDIALOG
, std::string()));
167 void VpnService::SendShowConfigureDialogToExtension(
168 const std::string
& extension_id
,
169 const std::string
& configuration_id
) {
170 SendSignalToExtension(
171 extension_id
, api_vpn::OnUIEvent::kEventName
,
172 api_vpn::OnUIEvent::Create(api_vpn::UI_EVENT_SHOWCONFIGUREDIALOG
,
176 void VpnService::SendPlatformError(const std::string
& extension_id
,
177 const std::string
& configuration_id
,
178 const std::string
& error_message
) {
179 SendSignalToExtension(
180 extension_id
, api_vpn::OnPlatformMessage::kEventName
,
181 api_vpn::OnPlatformMessage::Create(
182 configuration_id
, api_vpn::PLATFORM_MESSAGE_ERROR
, error_message
));
185 std::string
VpnService::GetKey(const std::string
& extension_id
,
186 const std::string
& name
) {
187 const std::string key
= crypto::SHA256HashString(extension_id
+ name
);
188 return base::HexEncode(key
.data(), key
.size());
191 void VpnService::OnConfigurationCreated(const std::string
& service_path
,
192 const std::string
& profile_path
,
193 const base::DictionaryValue
& properties
,
197 void VpnService::OnConfigurationRemoved(const std::string
& service_path
,
198 const std::string
& guid
,
200 if (source
== SOURCE_EXTENSION_INSTALL
) {
201 // No need to process if the configuration was removed using an extension
202 // API since the API would have already done the cleanup.
206 if (service_path_to_configuration_map_
.find(service_path
) ==
207 service_path_to_configuration_map_
.end()) {
208 // Ignore removal of a configuration unknown to VPN service, which means the
209 // configuration was created internally by the platform.
213 VpnConfiguration
* configuration
=
214 service_path_to_configuration_map_
[service_path
];
215 scoped_ptr
<base::ListValue
> event_args
=
216 api_vpn::OnConfigRemoved::Create(configuration
->configuration_name());
217 SendSignalToExtension(configuration
->extension_id(),
218 api_vpn::OnConfigRemoved::kEventName
,
221 DestroyConfigurationInternal(configuration
);
224 void VpnService::OnPropertiesSet(const std::string
& service_path
,
225 const std::string
& guid
,
226 const base::DictionaryValue
& set_properties
,
230 void VpnService::OnConfigurationProfileChanged(const std::string
& service_path
,
231 const std::string
& profile_path
,
235 void VpnService::OnGetPropertiesSuccess(
236 const std::string
& service_path
,
237 const base::DictionaryValue
& dictionary
) {
238 if (service_path_to_configuration_map_
.find(service_path
) !=
239 service_path_to_configuration_map_
.end()) {
242 std::string vpn_type
;
243 std::string extension_id
;
245 std::string configuration_name
;
246 if (!dictionary
.GetString(shill::kProviderTypeProperty
, &vpn_type
) ||
247 !dictionary
.GetString(shill::kProviderHostProperty
, &extension_id
) ||
248 !dictionary
.GetString(shill::kTypeProperty
, &type
) ||
249 !dictionary
.GetString(shill::kNameProperty
, &configuration_name
) ||
250 vpn_type
!= shill::kProviderThirdPartyVpn
|| type
!= shill::kTypeVPN
) {
254 if (!extension_registry_
->GetExtensionById(
255 extension_id
, extensions::ExtensionRegistry::ENABLED
)) {
256 // Does not belong to this instance of VpnService.
260 const std::string key
= GetKey(extension_id
, configuration_name
);
261 VpnConfiguration
* configuration
=
262 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
263 configuration
->set_service_path(service_path
);
264 service_path_to_configuration_map_
[service_path
] = configuration
;
265 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
269 void VpnService::OnGetPropertiesFailure(
270 const std::string
& error_name
,
271 scoped_ptr
<base::DictionaryValue
> error_data
) {
274 void VpnService::NetworkListChanged() {
275 NetworkStateHandler::NetworkStateList network_list
;
276 network_state_handler_
->GetVisibleNetworkListByType(NetworkTypePattern::VPN(),
278 for (auto& iter
: network_list
) {
279 if (service_path_to_configuration_map_
.find(iter
->path()) !=
280 service_path_to_configuration_map_
.end()) {
284 network_configuration_handler_
->GetShillProperties(
285 iter
->path(), base::Bind(&VpnService::OnGetPropertiesSuccess
,
286 weak_factory_
.GetWeakPtr()),
287 base::Bind(&VpnService::OnGetPropertiesFailure
,
288 weak_factory_
.GetWeakPtr()));
292 void VpnService::CreateConfiguration(const std::string
& extension_id
,
293 const std::string
& extension_name
,
294 const std::string
& configuration_name
,
295 const SuccessCallback
& success
,
296 const FailureCallback
& failure
) {
297 if (configuration_name
.empty()) {
298 failure
.Run(std::string(), std::string("Empty name not supported."));
302 const std::string key
= GetKey(extension_id
, configuration_name
);
303 if (ContainsKey(key_to_configuration_map_
, key
)) {
304 failure
.Run(std::string(), std::string("Name not unique."));
308 const NetworkProfile
* profile
=
309 network_profile_handler_
->GetProfileForUserhash(userid_hash_
);
313 std::string("No user profile for unshared network configuration."));
317 VpnConfiguration
* configuration
=
318 CreateConfigurationInternal(extension_id
, configuration_name
, key
);
320 base::DictionaryValue properties
;
321 properties
.SetStringWithoutPathExpansion(shill::kTypeProperty
,
323 properties
.SetStringWithoutPathExpansion(shill::kNameProperty
,
325 properties
.SetStringWithoutPathExpansion(shill::kProviderHostProperty
,
327 properties
.SetStringWithoutPathExpansion(shill::kObjectPathSuffixProperty
,
328 configuration
->key());
329 properties
.SetStringWithoutPathExpansion(shill::kProviderTypeProperty
,
330 shill::kProviderThirdPartyVpn
);
331 properties
.SetStringWithoutPathExpansion(shill::kProfileProperty
,
334 // Note: This will not create an entry in |policy_util|. TODO(pneubeck):
335 // Determine the correct thing to do here, crbug.com/459278.
336 std::string guid
= base::GenerateGUID();
337 properties
.SetStringWithoutPathExpansion(shill::kGuidProperty
, guid
);
339 network_configuration_handler_
->CreateShillConfiguration(
340 properties
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
341 base::Bind(&VpnService::OnCreateConfigurationSuccess
,
342 weak_factory_
.GetWeakPtr(), success
, configuration
),
343 base::Bind(&VpnService::OnCreateConfigurationFailure
,
344 weak_factory_
.GetWeakPtr(), failure
, configuration
));
347 void VpnService::DestroyConfiguration(const std::string
& extension_id
,
348 const std::string
& configuration_id
,
349 const SuccessCallback
& success
,
350 const FailureCallback
& failure
) {
351 // The ID is the configuration name for now. This may change in the future.
352 const std::string key
= GetKey(extension_id
, configuration_id
);
353 if (!ContainsKey(key_to_configuration_map_
, key
)) {
354 failure
.Run(std::string(), std::string("Unauthorized access."));
358 VpnConfiguration
* configuration
= key_to_configuration_map_
[key
];
359 const std::string service_path
= configuration
->service_path();
360 if (service_path
.empty()) {
361 failure
.Run(std::string(), std::string("Pending create."));
364 if (active_configuration_
== configuration
) {
365 configuration
->OnPlatformMessage(api_vpn::PLATFORM_MESSAGE_DISCONNECTED
);
367 DestroyConfigurationInternal(configuration
);
369 network_configuration_handler_
->RemoveConfiguration(
370 service_path
, NetworkConfigurationObserver::SOURCE_EXTENSION_INSTALL
,
371 base::Bind(&VpnService::OnRemoveConfigurationSuccess
,
372 weak_factory_
.GetWeakPtr(), success
),
373 base::Bind(&VpnService::OnRemoveConfigurationFailure
,
374 weak_factory_
.GetWeakPtr(), failure
));
377 void VpnService::SetParameters(const std::string
& extension_id
,
378 const base::DictionaryValue
& parameters
,
379 const StringCallback
& success
,
380 const FailureCallback
& failure
) {
381 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
382 failure
.Run(std::string(), std::string("Unauthorized access."));
386 shill_client_
->SetParameters(active_configuration_
->object_path(), parameters
,
390 void VpnService::SendPacket(const std::string
& extension_id
,
391 const std::vector
<char>& data
,
392 const SuccessCallback
& success
,
393 const FailureCallback
& failure
) {
394 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
395 failure
.Run(std::string(), std::string("Unauthorized access."));
400 failure
.Run(std::string(), std::string("Can't send an empty packet."));
404 shill_client_
->SendPacket(active_configuration_
->object_path(), data
, success
,
408 void VpnService::NotifyConnectionStateChanged(const std::string
& extension_id
,
409 api_vpn::VpnConnectionState state
,
410 const SuccessCallback
& success
,
411 const FailureCallback
& failure
) {
412 if (!DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
)) {
413 failure
.Run(std::string(), std::string("Unauthorized access."));
417 shill_client_
->UpdateConnectionState(active_configuration_
->object_path(),
418 static_cast<uint32_t>(state
), success
,
422 bool VpnService::VerifyConfigExistsForTesting(
423 const std::string
& extension_id
,
424 const std::string
& configuration_name
) {
425 const std::string key
= GetKey(extension_id
, configuration_name
);
426 return ContainsKey(key_to_configuration_map_
, key
);
429 bool VpnService::VerifyConfigIsConnectedForTesting(
430 const std::string
& extension_id
) {
431 return DoesActiveConfigurationExistAndIsAccessAuthorized(extension_id
);
434 void VpnService::DestroyConfigurationsForExtension(
435 const extensions::Extension
* extension
) {
436 std::vector
<VpnConfiguration
*> to_be_destroyed
;
437 for (const auto& iter
: key_to_configuration_map_
) {
438 if (iter
.second
->extension_id() == extension
->id()) {
439 to_be_destroyed
.push_back(iter
.second
);
443 for (auto& iter
: to_be_destroyed
) {
444 DestroyConfiguration(extension
->id(), // Extension ID
445 iter
->configuration_name(), // Configuration name
446 base::Bind(base::DoNothing
),
447 base::Bind(DoNothingFailureCallback
));
451 void VpnService::OnExtensionUninstalled(
452 content::BrowserContext
* browser_context
,
453 const extensions::Extension
* extension
,
454 extensions::UninstallReason reason
) {
455 if (browser_context
!= browser_context_
) {
460 DestroyConfigurationsForExtension(extension
);
463 void VpnService::OnExtensionUnloaded(
464 content::BrowserContext
* browser_context
,
465 const extensions::Extension
* extension
,
466 extensions::UnloadedExtensionInfo::Reason reason
) {
467 if (browser_context
!= browser_context_
) {
472 if (active_configuration_
&&
473 active_configuration_
->extension_id() == extension
->id()) {
474 shill_client_
->UpdateConnectionState(
475 active_configuration_
->object_path(),
476 static_cast<uint32_t>(api_vpn::VPN_CONNECTION_STATE_FAILURE
),
477 base::Bind(base::DoNothing
), base::Bind(DoNothingFailureCallback
));
479 if (reason
== extensions::UnloadedExtensionInfo::REASON_DISABLE
||
480 reason
== extensions::UnloadedExtensionInfo::REASON_BLACKLIST
) {
481 DestroyConfigurationsForExtension(extension
);
485 void VpnService::OnCreateConfigurationSuccess(
486 const VpnService::SuccessCallback
& callback
,
487 VpnConfiguration
* configuration
,
488 const std::string
& service_path
) {
489 configuration
->set_service_path(service_path
);
490 service_path_to_configuration_map_
[service_path
] = configuration
;
491 shill_client_
->AddShillThirdPartyVpnObserver(configuration
->object_path(),
496 void VpnService::OnCreateConfigurationFailure(
497 const VpnService::FailureCallback
& callback
,
498 VpnConfiguration
* configuration
,
499 const std::string
& error_name
,
500 scoped_ptr
<base::DictionaryValue
> error_data
) {
501 DestroyConfigurationInternal(configuration
);
502 callback
.Run(error_name
, std::string());
505 void VpnService::OnRemoveConfigurationSuccess(
506 const VpnService::SuccessCallback
& callback
) {
510 void VpnService::OnRemoveConfigurationFailure(
511 const VpnService::FailureCallback
& callback
,
512 const std::string
& error_name
,
513 scoped_ptr
<base::DictionaryValue
> error_data
) {
514 callback
.Run(error_name
, std::string());
517 void VpnService::SendSignalToExtension(const std::string
& extension_id
,
518 const std::string
& event_name
,
519 scoped_ptr
<base::ListValue
> event_args
) {
520 scoped_ptr
<extensions::Event
> event(
521 new extensions::Event(extensions::events::UNKNOWN
, event_name
,
522 event_args
.Pass(), browser_context_
));
524 event_router_
->DispatchEventToExtension(extension_id
, event
.Pass());
527 void VpnService::SetActiveConfiguration(
528 VpnService::VpnConfiguration
* configuration
) {
529 active_configuration_
= configuration
;
532 VpnService::VpnConfiguration
* VpnService::CreateConfigurationInternal(
533 const std::string
& extension_id
,
534 const std::string
& configuration_name
,
535 const std::string
& key
) {
536 VpnConfiguration
* configuration
= new VpnConfiguration(
537 extension_id
, configuration_name
, key
, weak_factory_
.GetWeakPtr());
538 // The object is owned by key_to_configuration_map_ henceforth.
539 key_to_configuration_map_
[key
] = configuration
;
540 return configuration
;
543 void VpnService::DestroyConfigurationInternal(VpnConfiguration
* configuration
) {
544 key_to_configuration_map_
.erase(configuration
->key());
545 if (active_configuration_
== configuration
) {
546 active_configuration_
= nullptr;
548 if (!configuration
->service_path().empty()) {
549 shill_client_
->RemoveShillThirdPartyVpnObserver(
550 configuration
->object_path());
551 service_path_to_configuration_map_
.erase(configuration
->service_path());
553 delete configuration
;
556 bool VpnService::DoesActiveConfigurationExistAndIsAccessAuthorized(
557 const std::string
& extension_id
) {
558 return active_configuration_
&&
559 active_configuration_
->extension_id() == extension_id
;
562 } // namespace chromeos