Home | History | Annotate | Download | only in network
      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.
      4 
      5 #include "chromeos/network/network_configuration_handler.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     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"
     28 
     29 namespace chromeos {
     30 
     31 namespace {
     32 
     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);
     38   return in_str;
     39 }
     40 
     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);
     48 }
     49 
     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());
     58   std::string name =
     59       shill_property_util::GetNameFromProperties(service_path, properties);
     60   if (!name.empty()) {
     61     properties_copy->SetStringWithoutPathExpansion(shill::kNameProperty, name);
     62   }
     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,
     67                                       service_path,
     68                                       network_handler::kDBusFailedError,
     69                                       network_handler::kDBusFailedErrorMessage);
     70   } else if (!callback.is_null()) {
     71     callback.Run(service_path, *properties_copy.get());
     72   }
     73 }
     74 
     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);
     85 }
     86 
     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;
     97 }
     98 
     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);
    108   }
    109 }
    110 
    111 }  // namespace
    112 
    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> {
    119  public:
    120   ProfileEntryDeleter(NetworkConfigurationHandler* handler,
    121                       const std::string& service_path,
    122                       const base::Closure& callback,
    123                       const network_handler::ErrorCallback& error_callback)
    124       : owner_(handler),
    125         service_path_(service_path),
    126         callback_(callback),
    127         error_callback_(error_callback) {
    128   }
    129 
    130   void Run() {
    131     DBusThreadManager::Get()->GetShillServiceClient()->
    132         GetLoadableProfileEntries(
    133             dbus::ObjectPath(service_path_),
    134             base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback,
    135                        AsWeakPtr()));
    136   }
    137 
    138  private:
    139   void GetProfileEntriesToDeleteCallback(
    140       DBusMethodCallStatus call_status,
    141       const base::DictionaryValue& profile_entries) {
    142     if (call_status != DBUS_METHOD_CALL_SUCCESS) {
    143       InvokeErrorCallback(
    144           service_path_, error_callback_, "GetLoadableProfileEntriesFailed");
    145       owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
    146       return;
    147     }
    148 
    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()));
    157         continue;
    158       }
    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()));
    162         continue;
    163       }
    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),
    169           entry_path,
    170           base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback,
    171                      AsWeakPtr(), profile_path, entry_path),
    172           base::Bind(&ProfileEntryDeleter::ShillErrorCallback,
    173                      AsWeakPtr(), profile_path, entry_path));
    174     }
    175   }
    176 
    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())
    183       return;
    184     // Run the callback if this is the last pending deletion.
    185     if (!callback_.is_null())
    186       callback_.Run();
    187     // Request NetworkStateHandler manager update to update ServiceCompleteList.
    188     owner_->network_state_handler_->UpdateManagerProperties();
    189     owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
    190   }
    191 
    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.
    203   }
    204 
    205   NetworkConfigurationHandler* owner_;  // Unowned
    206   std::string service_path_;
    207   base::Closure callback_;
    208   network_handler::ErrorCallback error_callback_;
    209 
    210   // Map of pending profile entry deletions, indexed by profile path.
    211   std::map<std::string, std::string> profile_delete_entries_;
    212 
    213   DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter);
    214 };
    215 
    216 // NetworkConfigurationHandler
    217 
    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));
    226 }
    227 
    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())
    235       callback.Run();
    236     return;
    237   }
    238   NET_LOG_USER("SetProperties", service_path);
    239   LogConfigProperties("SetProperty", service_path, properties);
    240 
    241   DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
    242       dbus::ObjectPath(service_path),
    243       properties,
    244       base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback,
    245                  AsWeakPtr(), service_path, callback),
    246       base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback,
    247                  AsWeakPtr(), service_path, error_callback));
    248 }
    249 
    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) {
    255   if (names.empty()) {
    256     if (!callback.is_null())
    257       callback.Run();
    258     return;
    259   }
    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);
    264   }
    265   DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
    266       dbus::ObjectPath(service_path),
    267       names,
    268       base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback,
    269                  AsWeakPtr(), service_path, names, callback, error_callback),
    270       base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback,
    271                  AsWeakPtr(), service_path, error_callback));
    272 }
    273 
    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();
    280   std::string type;
    281   properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
    282   if (NetworkTypePattern::Ethernet().MatchesType(type)) {
    283     InvokeErrorCallback(
    284         "" /* no service path */,
    285         error_callback,
    286         "ConfigureServiceForProfile is not implemented for Ethernet");
    287     return;
    288   }
    289 
    290   NET_LOG_USER("CreateConfiguration", type);
    291   LogConfigProperties("Configure", type, properties);
    292 
    293   std::string profile;
    294   properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
    295                                            &profile);
    296   DCHECK(!profile.empty());
    297   manager->ConfigureServiceForProfile(
    298       dbus::ObjectPath(profile),
    299       properties,
    300       base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
    301                  AsWeakPtr(),
    302                  callback),
    303       base::Bind(&network_handler::ShillErrorCallbackFunction,
    304                  "Config.CreateConfiguration Failed",
    305                  "",
    306                  error_callback));
    307 }
    308 
    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)) {
    316     InvokeErrorCallback(
    317         service_path, error_callback, "RemoveConfigurationInProgress");
    318     return;
    319   }
    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;
    324   deleter->Run();
    325 }
    326 
    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,
    337       profile_path_value,
    338       callback,
    339       base::Bind(&SetNetworkProfileErrorCallback,
    340                  service_path, profile_path, error_callback));
    341 }
    342 
    343 // NetworkConfigurationHandler Private methods
    344 
    345 NetworkConfigurationHandler::NetworkConfigurationHandler()
    346     : network_state_handler_(NULL) {
    347 }
    348 
    349 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
    350   STLDeleteContainerPairSecondPointers(
    351       profile_entry_deleters_.begin(), profile_entry_deleters_.end());
    352 }
    353 
    354 void NetworkConfigurationHandler::Init(
    355     NetworkStateHandler* network_state_handler) {
    356   network_state_handler_ = network_state_handler;
    357 }
    358 
    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());
    369 }
    370 
    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());
    376   delete iter->second;
    377   profile_entry_deleters_.erase(iter);
    378 }
    379 
    380 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
    381     const std::string& service_path,
    382     const base::Closure& callback) {
    383   if (!callback.is_null())
    384     callback.Run();
    385   network_state_handler_->RequestUpdateForNetwork(service_path);
    386 }
    387 
    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);
    399 }
    400 
    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.";
    410 
    411   bool some_failed = false;
    412   for (size_t i = 0; i < result.GetSize(); ++i) {
    413     bool success = false;
    414     result.GetBoolean(i, &success);
    415     if (!success) {
    416       NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path);
    417       some_failed = true;
    418     }
    419   }
    420 
    421   if (some_failed) {
    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());
    432     }
    433   } else if (!callback.is_null()) {
    434     callback.Run();
    435   }
    436   network_state_handler_->RequestUpdateForNetwork(service_path);
    437 }
    438 
    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);
    450 }
    451 
    452 // static
    453 NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
    454     NetworkStateHandler* network_state_handler) {
    455   NetworkConfigurationHandler* handler = new NetworkConfigurationHandler();
    456   handler->Init(network_state_handler);
    457   return handler;
    458 }
    459 
    460 }  // namespace chromeos
    461