1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/vpn/vpn_service.h" 18 19 #include <algorithm> 20 21 #include <base/strings/stringprintf.h> 22 #if defined(__ANDROID__) 23 #include <dbus/service_constants.h> 24 #else 25 #include <chromeos/dbus/service_constants.h> 26 #endif // __ANDROID__ 27 28 #include "shill/key_value_store.h" 29 #include "shill/logging.h" 30 #include "shill/manager.h" 31 #include "shill/profile.h" 32 #include "shill/property_accessor.h" 33 #include "shill/technology.h" 34 #include "shill/vpn/vpn_driver.h" 35 #include "shill/vpn/vpn_provider.h" 36 37 using base::Bind; 38 using base::StringPrintf; 39 using base::Unretained; 40 using std::replace_if; 41 using std::string; 42 43 namespace shill { 44 45 namespace Logging { 46 static auto kModuleLogScope = ScopeLogger::kVPN; 47 static string ObjectID(const VPNService* s) { return s->GetRpcIdentifier(); } 48 } 49 50 const char VPNService::kAutoConnNeverConnected[] = "never connected"; 51 const char VPNService::kAutoConnVPNAlreadyActive[] = "vpn already active"; 52 53 VPNService::VPNService(ControlInterface* control, 54 EventDispatcher* dispatcher, 55 Metrics* metrics, 56 Manager* manager, 57 VPNDriver* driver) 58 : Service(control, dispatcher, metrics, manager, Technology::kVPN), 59 driver_(driver) { 60 SetConnectable(true); 61 set_save_credentials(false); 62 mutable_store()->RegisterString(kVPNDomainProperty, &vpn_domain_); 63 mutable_store()->RegisterDerivedString( 64 kPhysicalTechnologyProperty, 65 StringAccessor( 66 new CustomAccessor<VPNService, string>( 67 this, 68 &VPNService::GetPhysicalTechnologyProperty, 69 nullptr))); 70 } 71 72 VPNService::~VPNService() {} 73 74 void VPNService::Connect(Error* error, const char* reason) { 75 if (IsConnected()) { 76 Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected, 77 StringPrintf("VPN service %s already connected.", 78 unique_name().c_str())); 79 return; 80 } 81 if (IsConnecting()) { 82 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress, 83 StringPrintf("VPN service %s already connecting.", 84 unique_name().c_str())); 85 return; 86 } 87 manager()->vpn_provider()->DisconnectAll(); 88 Service::Connect(error, reason); 89 driver_->Connect(this, error); 90 } 91 92 void VPNService::Disconnect(Error* error, const char* reason) { 93 SLOG(this, 1) << "Disconnect from service " << unique_name(); 94 Service::Disconnect(error, reason); 95 driver_->Disconnect(); 96 } 97 98 string VPNService::GetStorageIdentifier() const { 99 return storage_id_; 100 } 101 102 // static 103 string VPNService::CreateStorageIdentifier(const KeyValueStore& args, 104 Error* error) { 105 string host = args.LookupString(kProviderHostProperty, ""); 106 if (host.empty()) { 107 Error::PopulateAndLog( 108 FROM_HERE, error, Error::kInvalidProperty, "Missing VPN host."); 109 return ""; 110 } 111 string name = args.LookupString(kNameProperty, ""); 112 if (name.empty()) { 113 Error::PopulateAndLog( 114 FROM_HERE, error, Error::kNotSupported, "Missing VPN name."); 115 return ""; 116 } 117 string id = StringPrintf("vpn_%s_%s", host.c_str(), name.c_str()); 118 replace_if(id.begin(), id.end(), &Service::IllegalChar, '_'); 119 return id; 120 } 121 122 string VPNService::GetDeviceRpcId(Error* error) const { 123 error->Populate(Error::kNotSupported); 124 return "/"; 125 } 126 127 bool VPNService::Load(StoreInterface* storage) { 128 return Service::Load(storage) && 129 driver_->Load(storage, GetStorageIdentifier()); 130 } 131 132 bool VPNService::Save(StoreInterface* storage) { 133 return Service::Save(storage) && 134 driver_->Save(storage, GetStorageIdentifier(), save_credentials()); 135 } 136 137 bool VPNService::Unload() { 138 // The base method also disconnects the service. 139 Service::Unload(); 140 141 set_save_credentials(false); 142 driver_->UnloadCredentials(); 143 144 // Ask the VPN provider to remove us from its list. 145 manager()->vpn_provider()->RemoveService(this); 146 147 return true; 148 } 149 150 void VPNService::InitDriverPropertyStore() { 151 driver_->InitPropertyStore(mutable_store()); 152 } 153 154 void VPNService::EnableAndRetainAutoConnect() { 155 // The base EnableAndRetainAutoConnect method also sets auto_connect_ to true 156 // which is not desirable for VPN services. 157 RetainAutoConnect(); 158 } 159 160 void VPNService::SetConnection(const ConnectionRefPtr& connection) { 161 // Construct the connection binder here rather than in the constructor because 162 // there's really no reason to construct a binder if we never connect to this 163 // service. It's safe to use an unretained callback to driver's method because 164 // both the binder and the driver will be destroyed when this service is 165 // destructed. 166 if (!connection_binder_.get()) { 167 connection_binder_.reset( 168 new Connection::Binder(unique_name(), 169 Bind(&VPNDriver::OnConnectionDisconnected, 170 Unretained(driver_.get())))); 171 } 172 // Note that |connection_| is a reference-counted pointer and is always set 173 // through this method. This means that the connection binder will not be 174 // notified when the connection is destructed (because we will unbind it first 175 // here when it's set to NULL, or because the binder will already be destroyed 176 // by ~VPNService) -- it will be notified only if the connection disconnects 177 // (e.g., because an underlying connection is destructed). 178 connection_binder_->Attach(connection); 179 Service::SetConnection(connection); 180 } 181 182 bool VPNService::IsAutoConnectable(const char** reason) const { 183 if (!Service::IsAutoConnectable(reason)) { 184 return false; 185 } 186 // Don't auto-connect VPN services that have never connected. This improves 187 // the chances that the VPN service is connectable and avoids dialog popups. 188 if (!has_ever_connected()) { 189 *reason = kAutoConnNeverConnected; 190 return false; 191 } 192 // Don't auto-connect a VPN service if another VPN service is already active. 193 if (manager()->vpn_provider()->HasActiveService()) { 194 *reason = kAutoConnVPNAlreadyActive; 195 return false; 196 } 197 return true; 198 } 199 200 string VPNService::GetTethering(Error* error) const { 201 ConnectionRefPtr conn = connection(); 202 if (conn) 203 conn = conn->GetCarrierConnection(); 204 205 string tethering; 206 if (conn) { 207 tethering = conn->tethering(); 208 if (!tethering.empty()) { 209 return tethering; 210 } 211 // The underlying service may not have a Tethering property. This is 212 // not strictly an error, so we don't print an error message. Populating 213 // an error here just serves to propagate the lack of a property in 214 // GetProperties(). 215 error->Populate(Error::kNotSupported); 216 } else { 217 error->Populate(Error::kOperationFailed); 218 } 219 return ""; 220 } 221 222 bool VPNService::SetNameProperty(const string& name, Error* error) { 223 if (name == friendly_name()) { 224 return false; 225 } 226 LOG(INFO) << "Renaming service " << unique_name() << ": " 227 << friendly_name() << " -> " << name; 228 229 KeyValueStore* args = driver_->args(); 230 args->SetString(kNameProperty, name); 231 string new_storage_id = CreateStorageIdentifier(*args, error); 232 if (new_storage_id.empty()) { 233 return false; 234 } 235 string old_storage_id = storage_id_; 236 DCHECK_NE(old_storage_id, new_storage_id); 237 238 SetFriendlyName(name); 239 240 // Update the storage identifier before invoking DeleteEntry to prevent it 241 // from unloading this service. 242 storage_id_ = new_storage_id; 243 profile()->DeleteEntry(old_storage_id, nullptr); 244 profile()->UpdateService(this); 245 return true; 246 } 247 248 string VPNService::GetPhysicalTechnologyProperty(Error* error) { 249 ConnectionRefPtr conn = connection(); 250 if (conn) 251 conn = conn->GetCarrierConnection(); 252 253 if (!conn) { 254 error->Populate(Error::kOperationFailed); 255 return ""; 256 } 257 258 return Technology::NameFromIdentifier(conn->technology()); 259 } 260 261 } // namespace shill 262