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.h"
     25 #include "chromeos/network/network_state_handler.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& error,
     42                          const std::string& path,
     43                          const network_handler::ErrorCallback& error_callback) {
     44   NET_LOG_ERROR(error, path);
     45   if (error_callback.is_null())
     46     return;
     47   scoped_ptr<base::DictionaryValue> error_data(
     48       network_handler::CreateErrorData(path, error, ""));
     49   error_callback.Run(error, error_data.Pass());
     50 }
     51 
     52 void GetPropertiesCallback(
     53     const network_handler::DictionaryResultCallback& callback,
     54     const network_handler::ErrorCallback& error_callback,
     55     const std::string& service_path,
     56     DBusMethodCallStatus call_status,
     57     const base::DictionaryValue& properties) {
     58   // Get the correct name from WifiHex if necessary.
     59   scoped_ptr<base::DictionaryValue> properties_copy(properties.DeepCopy());
     60   std::string name = NetworkState::GetNameFromProperties(
     61       service_path, properties);
     62   if (!name.empty()) {
     63     properties_copy->SetStringWithoutPathExpansion(
     64         flimflam::kNameProperty, name);
     65   }
     66   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
     67     // Because network services are added and removed frequently, we will see
     68     // failures regularly, so don't log these.
     69     if (!error_callback.is_null()) {
     70       scoped_ptr<base::DictionaryValue> error_data(
     71           network_handler::CreateErrorData(
     72               service_path,
     73               network_handler::kDBusFailedError,
     74               network_handler::kDBusFailedErrorMessage));
     75       error_callback.Run(network_handler::kDBusFailedError, error_data.Pass());
     76     }
     77   } else if (!callback.is_null()) {
     78     callback.Run(service_path, *properties_copy.get());
     79   }
     80 }
     81 
     82 void SetNetworkProfileErrorCallback(
     83     const std::string& service_path,
     84     const std::string& profile_path,
     85     const network_handler::ErrorCallback& error_callback,
     86     const std::string& dbus_error_name,
     87     const std::string& dbus_error_message) {
     88   network_handler::ShillErrorCallbackFunction(
     89       "Config.SetNetworkProfile Failed: " + profile_path,
     90       service_path, error_callback,
     91       dbus_error_name, dbus_error_message);
     92 }
     93 
     94 bool IsPassphrase(const std::string& key) {
     95   return key == flimflam::kEapPrivateKeyPasswordProperty ||
     96       key == flimflam::kEapPasswordProperty ||
     97       key == flimflam::kL2tpIpsecPasswordProperty ||
     98       key == flimflam::kOpenVPNPasswordProperty ||
     99       key == flimflam::kPassphraseProperty ||
    100       key == flimflam::kOpenVPNOTPProperty ||
    101       key == flimflam::kEapPrivateKeyProperty ||
    102       key == flimflam::kEapPrivateKeyPasswordProperty ||
    103       key == flimflam::kEapPinProperty ||
    104       key == flimflam::kApnPasswordProperty;
    105 }
    106 
    107 void LogConfigProperties(const std::string& desc,
    108                          const std::string& path,
    109                          const base::DictionaryValue& properties) {
    110   for (base::DictionaryValue::Iterator iter(properties);
    111        !iter.IsAtEnd(); iter.Advance()) {
    112     std::string v = "******";
    113     if (!IsPassphrase(iter.key()))
    114       base::JSONWriter::Write(&iter.value(), &v);
    115     NET_LOG_DEBUG(desc,  path + "." + iter.key() + "=" + v);
    116   }
    117 }
    118 
    119 }  // namespace
    120 
    121 // Helper class to request from Shill the profile entries associated with a
    122 // Service and delete the service from each profile. Triggers either
    123 // |callback| on success or |error_callback| on failure, and calls
    124 // |handler|->ProfileEntryDeleterCompleted() on completion to delete itself.
    125 class NetworkConfigurationHandler::ProfileEntryDeleter
    126     : public base::SupportsWeakPtr<ProfileEntryDeleter> {
    127  public:
    128   ProfileEntryDeleter(NetworkConfigurationHandler* handler,
    129                       const std::string& service_path,
    130                       const base::Closure& callback,
    131                       const network_handler::ErrorCallback& error_callback)
    132       : owner_(handler),
    133         service_path_(service_path),
    134         callback_(callback),
    135         error_callback_(error_callback) {
    136   }
    137 
    138   void Run() {
    139     DBusThreadManager::Get()->GetShillServiceClient()->
    140         GetLoadableProfileEntries(
    141             dbus::ObjectPath(service_path_),
    142             base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback,
    143                        AsWeakPtr()));
    144   }
    145 
    146  private:
    147   void GetProfileEntriesToDeleteCallback(
    148       DBusMethodCallStatus call_status,
    149       const base::DictionaryValue& profile_entries) {
    150     if (call_status != DBUS_METHOD_CALL_SUCCESS) {
    151       InvokeErrorCallback(
    152           "GetLoadableProfileEntries Failed", service_path_, error_callback_);
    153       owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
    154       return;
    155     }
    156 
    157     for (base::DictionaryValue::Iterator iter(profile_entries);
    158          !iter.IsAtEnd(); iter.Advance()) {
    159       std::string profile_path = StripQuotations(iter.key());
    160       std::string entry_path;
    161       iter.value().GetAsString(&entry_path);
    162       if (profile_path.empty() || entry_path.empty()) {
    163         NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf(
    164             "%s: %s", profile_path.c_str(), entry_path.c_str()));
    165         continue;
    166       }
    167       if (profile_delete_entries_.count(profile_path) != 0) {
    168         NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf(
    169             "%s: %s", profile_path.c_str(), entry_path.c_str()));
    170         continue;
    171       }
    172       NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf(
    173           "%s: %s", profile_path.c_str(), entry_path.c_str()));
    174       profile_delete_entries_[profile_path] = entry_path;
    175       DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
    176           dbus::ObjectPath(profile_path),
    177           entry_path,
    178           base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback,
    179                      AsWeakPtr(), profile_path, entry_path),
    180           base::Bind(&ProfileEntryDeleter::ShillErrorCallback,
    181                      AsWeakPtr(), profile_path, entry_path));
    182     }
    183   }
    184 
    185   void ProfileEntryDeletedCallback(const std::string& profile_path,
    186                                    const std::string& entry) {
    187     NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf(
    188         "%s: %s", profile_path.c_str(), entry.c_str()));
    189     profile_delete_entries_.erase(profile_path);
    190     if (!profile_delete_entries_.empty())
    191       return;
    192     // Run the callback if this is the last pending deletion.
    193     if (!callback_.is_null())
    194       callback_.Run();
    195     // Request NetworkStateHandler manager update to update ServiceCompleteList.
    196     owner_->network_state_handler_->UpdateManagerProperties();
    197     owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
    198   }
    199 
    200   void ShillErrorCallback(const std::string& profile_path,
    201                           const std::string& entry,
    202                           const std::string& dbus_error_name,
    203                           const std::string& dbus_error_message) {
    204     // Any Shill Error triggers a failure / error.
    205     network_handler::ShillErrorCallbackFunction(
    206         "GetLoadableProfileEntries Failed", profile_path, error_callback_,
    207         dbus_error_name, dbus_error_message);
    208     // Delete this even if there are pending deletions; any callbacks will
    209     // safely become no-ops (by invalidating the WeakPtrs).
    210     owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
    211   }
    212 
    213   NetworkConfigurationHandler* owner_;  // Unowned
    214   std::string service_path_;
    215   base::Closure callback_;
    216   network_handler::ErrorCallback error_callback_;
    217 
    218   // Map of pending profile entry deletions, indexed by profile path.
    219   std::map<std::string, std::string> profile_delete_entries_;
    220 
    221   DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter);
    222 };
    223 
    224 // NetworkConfigurationHandler
    225 
    226 void NetworkConfigurationHandler::GetProperties(
    227     const std::string& service_path,
    228     const network_handler::DictionaryResultCallback& callback,
    229     const network_handler::ErrorCallback& error_callback) const {
    230   DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
    231       dbus::ObjectPath(service_path),
    232       base::Bind(&GetPropertiesCallback,
    233                  callback, error_callback, service_path));
    234 }
    235 
    236 void NetworkConfigurationHandler::SetProperties(
    237     const std::string& service_path,
    238     const base::DictionaryValue& properties,
    239     const base::Closure& callback,
    240     const network_handler::ErrorCallback& error_callback) {
    241   if (properties.empty()) {
    242     if (!callback.is_null())
    243       callback.Run();
    244     return;
    245   }
    246   NET_LOG_USER("SetProperties", service_path);
    247   LogConfigProperties("SetProperty", service_path, properties);
    248 
    249   DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
    250       dbus::ObjectPath(service_path),
    251       properties,
    252       base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback,
    253                  AsWeakPtr(), service_path, callback),
    254       base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback,
    255                  AsWeakPtr(), service_path, error_callback));
    256 }
    257 
    258 void NetworkConfigurationHandler::ClearProperties(
    259     const std::string& service_path,
    260     const std::vector<std::string>& names,
    261     const base::Closure& callback,
    262     const network_handler::ErrorCallback& error_callback) {
    263   if (names.empty()) {
    264     if (!callback.is_null())
    265       callback.Run();
    266     return;
    267   }
    268   NET_LOG_USER("ClearProperties", service_path);
    269   for (std::vector<std::string>::const_iterator iter = names.begin();
    270        iter != names.end(); ++iter) {
    271     NET_LOG_DEBUG("ClearProperty", service_path + "." + *iter);
    272   }
    273   DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
    274       dbus::ObjectPath(service_path),
    275       names,
    276       base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback,
    277                  AsWeakPtr(), service_path, names, callback, error_callback),
    278       base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback,
    279                  AsWeakPtr(), service_path, error_callback));
    280 }
    281 
    282 void NetworkConfigurationHandler::CreateConfiguration(
    283     const base::DictionaryValue& properties,
    284     const network_handler::StringResultCallback& callback,
    285     const network_handler::ErrorCallback& error_callback) {
    286   ShillManagerClient* manager =
    287       DBusThreadManager::Get()->GetShillManagerClient();
    288   std::string type;
    289   properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, &type);
    290 
    291   NET_LOG_USER("CreateConfiguration", type);
    292   LogConfigProperties("Configure", type, properties);
    293 
    294   std::string profile;
    295   properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
    296                                            &profile);
    297   DCHECK(!profile.empty());
    298   manager->ConfigureServiceForProfile(
    299       dbus::ObjectPath(profile),
    300       properties,
    301       base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
    302                  AsWeakPtr(),
    303                  callback),
    304       base::Bind(&network_handler::ShillErrorCallbackFunction,
    305                  "Config.CreateConfiguration Failed",
    306                  "",
    307                  error_callback));
    308 }
    309 
    310 void NetworkConfigurationHandler::RemoveConfiguration(
    311     const std::string& service_path,
    312     const base::Closure& callback,
    313     const network_handler::ErrorCallback& error_callback) {
    314   // Service.Remove is not reliable. Instead, request the profile entries
    315   // for the service and remove each entry.
    316   if (profile_entry_deleters_.count(service_path)) {
    317     InvokeErrorCallback(
    318         "RemoveConfiguration In-Progress", service_path, error_callback);
    319     return;
    320   }
    321   NET_LOG_USER("Remove Configuration", service_path);
    322   ProfileEntryDeleter* deleter =
    323       new ProfileEntryDeleter(this, service_path, callback, error_callback);
    324   profile_entry_deleters_[service_path] = deleter;
    325   deleter->Run();
    326 }
    327 
    328 void NetworkConfigurationHandler::SetNetworkProfile(
    329     const std::string& service_path,
    330     const std::string& profile_path,
    331     const base::Closure& callback,
    332     const network_handler::ErrorCallback& error_callback) {
    333   NET_LOG_USER("SetNetworkProfile", service_path + ": " + profile_path);
    334   base::StringValue profile_path_value(profile_path);
    335   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
    336       dbus::ObjectPath(service_path),
    337       flimflam::kProfileProperty,
    338       profile_path_value,
    339       callback,
    340       base::Bind(&SetNetworkProfileErrorCallback,
    341                  service_path, profile_path, error_callback));
    342 }
    343 
    344 // NetworkConfigurationHandler Private methods
    345 
    346 NetworkConfigurationHandler::NetworkConfigurationHandler()
    347     : network_state_handler_(NULL) {
    348 }
    349 
    350 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
    351   STLDeleteContainerPairSecondPointers(
    352       profile_entry_deleters_.begin(), profile_entry_deleters_.end());
    353 }
    354 
    355 void NetworkConfigurationHandler::Init(
    356     NetworkStateHandler* network_state_handler) {
    357   network_state_handler_ = network_state_handler;
    358 }
    359 
    360 void NetworkConfigurationHandler::RunCreateNetworkCallback(
    361     const network_handler::StringResultCallback& callback,
    362     const dbus::ObjectPath& service_path) {
    363   if (!callback.is_null())
    364     callback.Run(service_path.value());
    365   // This may also get called when CreateConfiguration is used to update an
    366   // existing configuration, so request a service update just in case.
    367   // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
    368   // this on an update.
    369   network_state_handler_->RequestUpdateForNetwork(service_path.value());
    370 }
    371 
    372 void NetworkConfigurationHandler::ProfileEntryDeleterCompleted(
    373     const std::string& service_path) {
    374   std::map<std::string, ProfileEntryDeleter*>::iterator iter =
    375       profile_entry_deleters_.find(service_path);
    376   DCHECK(iter != profile_entry_deleters_.end());
    377   delete iter->second;
    378   profile_entry_deleters_.erase(iter);
    379 }
    380 
    381 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
    382     const std::string& service_path,
    383     const base::Closure& callback) {
    384   if (!callback.is_null())
    385     callback.Run();
    386   network_state_handler_->RequestUpdateForNetwork(service_path);
    387 }
    388 
    389 void NetworkConfigurationHandler::SetPropertiesErrorCallback(
    390     const std::string& service_path,
    391     const network_handler::ErrorCallback& error_callback,
    392     const std::string& dbus_error_name,
    393     const std::string& dbus_error_message) {
    394   network_handler::ShillErrorCallbackFunction(
    395       "Config.SetProperties Failed",
    396       service_path, error_callback,
    397       dbus_error_name, dbus_error_message);
    398   // Some properties may have changed so request an update regardless.
    399   network_state_handler_->RequestUpdateForNetwork(service_path);
    400 }
    401 
    402 void NetworkConfigurationHandler::ClearPropertiesSuccessCallback(
    403     const std::string& service_path,
    404     const std::vector<std::string>& names,
    405     const base::Closure& callback,
    406     const network_handler::ErrorCallback& error_callback,
    407     const base::ListValue& result) {
    408   const std::string kClearPropertiesFailedError("Error.ClearPropertiesFailed");
    409   DCHECK(names.size() == result.GetSize())
    410       << "Incorrect result size from ClearProperties.";
    411 
    412   bool some_failed = false;
    413   for (size_t i = 0; i < result.GetSize(); ++i) {
    414     bool success = false;
    415     result.GetBoolean(i, &success);
    416     if (!success) {
    417       NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path);
    418       some_failed = true;
    419     }
    420   }
    421 
    422   if (some_failed) {
    423     if (!error_callback.is_null()) {
    424       scoped_ptr<base::DictionaryValue> error_data(
    425           network_handler::CreateErrorData(
    426               service_path, kClearPropertiesFailedError,
    427               base::StringPrintf("Errors: %" PRIuS, result.GetSize())));
    428       error_data->Set("errors", result.DeepCopy());
    429       scoped_ptr<base::ListValue> name_list(new base::ListValue);
    430       name_list->AppendStrings(names);
    431       error_data->Set("names", name_list.release());
    432       error_callback.Run(kClearPropertiesFailedError, error_data.Pass());
    433     }
    434   } else if (!callback.is_null()) {
    435     callback.Run();
    436   }
    437   network_state_handler_->RequestUpdateForNetwork(service_path);
    438 }
    439 
    440 void NetworkConfigurationHandler::ClearPropertiesErrorCallback(
    441     const std::string& service_path,
    442     const network_handler::ErrorCallback& error_callback,
    443     const std::string& dbus_error_name,
    444     const std::string& dbus_error_message) {
    445   network_handler::ShillErrorCallbackFunction(
    446       "Config.ClearProperties Failed",
    447       service_path, error_callback,
    448       dbus_error_name, dbus_error_message);
    449   // Some properties may have changed so request an update regardless.
    450   network_state_handler_->RequestUpdateForNetwork(service_path);
    451 }
    452 
    453 // static
    454 NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
    455     NetworkStateHandler* network_state_handler) {
    456   NetworkConfigurationHandler* handler = new NetworkConfigurationHandler();
    457   handler->Init(network_state_handler);
    458   return handler;
    459 }
    460 
    461 }  // namespace chromeos
    462