Home | History | Annotate | Download | only in network
      1 // Copyright 2013 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/managed_network_configuration_handler_impl.h"
      6 
      7 #include <set>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/guid.h"
     12 #include "base/location.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/values.h"
     18 #include "chromeos/dbus/shill_manager_client.h"
     19 #include "chromeos/dbus/shill_profile_client.h"
     20 #include "chromeos/dbus/shill_service_client.h"
     21 #include "chromeos/network/network_configuration_handler.h"
     22 #include "chromeos/network/network_event_log.h"
     23 #include "chromeos/network/network_policy_observer.h"
     24 #include "chromeos/network/network_profile.h"
     25 #include "chromeos/network/network_profile_handler.h"
     26 #include "chromeos/network/network_state.h"
     27 #include "chromeos/network/network_state_handler.h"
     28 #include "chromeos/network/network_ui_data.h"
     29 #include "chromeos/network/onc/onc_merger.h"
     30 #include "chromeos/network/onc/onc_signature.h"
     31 #include "chromeos/network/onc/onc_translator.h"
     32 #include "chromeos/network/onc/onc_validator.h"
     33 #include "chromeos/network/policy_util.h"
     34 #include "chromeos/network/shill_property_util.h"
     35 #include "components/onc/onc_constants.h"
     36 #include "third_party/cros_system_api/dbus/service_constants.h"
     37 
     38 namespace chromeos {
     39 
     40 namespace {
     41 
     42 typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
     43 
     44 // These are error strings used for error callbacks. None of these error
     45 // messages are user-facing: they should only appear in logs.
     46 const char kInvalidUserSettings[] = "InvalidUserSettings";
     47 const char kNetworkAlreadyConfigured[] = "NetworkAlreadyConfigured";
     48 const char kPoliciesNotInitialized[] = "PoliciesNotInitialized";
     49 const char kProfileNotInitialized[] = "ProflieNotInitialized";
     50 const char kSetOnUnconfiguredNetwork[] = "SetCalledOnUnconfiguredNetwork";
     51 const char kUnknownProfilePath[] = "UnknownProfilePath";
     52 const char kUnknownServicePath[] = "UnknownServicePath";
     53 
     54 std::string ToDebugString(::onc::ONCSource source,
     55                           const std::string& userhash) {
     56   return source == ::onc::ONC_SOURCE_USER_POLICY ?
     57       ("user policy of " + userhash) : "device policy";
     58 }
     59 
     60 void InvokeErrorCallback(const std::string& service_path,
     61                          const network_handler::ErrorCallback& error_callback,
     62                          const std::string& error_name) {
     63   std::string error_msg = "ManagedConfig Error: " + error_name;
     64   NET_LOG_ERROR(error_msg, service_path);
     65   network_handler::RunErrorCallback(
     66       error_callback, service_path, error_name, error_msg);
     67 }
     68 
     69 void LogErrorWithDict(const tracked_objects::Location& from_where,
     70                       const std::string& error_name,
     71                       scoped_ptr<base::DictionaryValue> error_data) {
     72   LOG(ERROR) << from_where.ToString() << ": " << error_name;
     73 }
     74 
     75 const base::DictionaryValue* GetByGUID(const GuidToPolicyMap& policies,
     76                                        const std::string& guid) {
     77   GuidToPolicyMap::const_iterator it = policies.find(guid);
     78   if (it == policies.end())
     79     return NULL;
     80   return it->second;
     81 }
     82 
     83 void TranslatePropertiesToOncAndRunCallback(
     84     const network_handler::DictionaryResultCallback& callback,
     85     const std::string& service_path,
     86     const base::DictionaryValue& shill_properties) {
     87   scoped_ptr<base::DictionaryValue> onc_network(
     88       onc::TranslateShillServiceToONCPart(
     89           shill_properties,
     90           &onc::kNetworkWithStateSignature));
     91   callback.Run(service_path, *onc_network);
     92 }
     93 
     94 }  // namespace
     95 
     96 struct ManagedNetworkConfigurationHandlerImpl::Policies {
     97   ~Policies();
     98 
     99   GuidToPolicyMap per_network_config;
    100   base::DictionaryValue global_network_config;
    101 };
    102 
    103 ManagedNetworkConfigurationHandlerImpl::Policies::~Policies() {
    104   STLDeleteValues(&per_network_config);
    105 }
    106 
    107 void ManagedNetworkConfigurationHandlerImpl::AddObserver(
    108     NetworkPolicyObserver* observer) {
    109   observers_.AddObserver(observer);
    110 }
    111 
    112 void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
    113     NetworkPolicyObserver* observer) {
    114   observers_.RemoveObserver(observer);
    115 }
    116 
    117 void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
    118     const std::string& userhash,
    119     const std::string& service_path,
    120     const network_handler::DictionaryResultCallback& callback,
    121     const network_handler::ErrorCallback& error_callback) {
    122   if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
    123     InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
    124     return;
    125   }
    126   network_configuration_handler_->GetProperties(
    127       service_path,
    128       base::Bind(
    129           &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
    130           weak_ptr_factory_.GetWeakPtr(),
    131           callback,
    132           error_callback),
    133       error_callback);
    134 }
    135 
    136 void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
    137     const network_handler::DictionaryResultCallback& callback,
    138     const network_handler::ErrorCallback& error_callback,
    139     const std::string& service_path,
    140     const base::DictionaryValue& shill_properties) {
    141   std::string profile_path;
    142   shill_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
    143                                                  &profile_path);
    144   const NetworkProfile* profile =
    145       network_profile_handler_->GetProfileForPath(profile_path);
    146   if (!profile) {
    147     LOG(ERROR) << "No or no known profile received for service "
    148             << service_path << ".";
    149   }
    150 
    151   scoped_ptr<NetworkUIData> ui_data =
    152       shill_property_util::GetUIDataFromProperties(shill_properties);
    153 
    154   const base::DictionaryValue* user_settings = NULL;
    155   const base::DictionaryValue* shared_settings = NULL;
    156 
    157   if (ui_data && profile) {
    158     if (profile->type() == NetworkProfile::TYPE_SHARED)
    159       shared_settings = ui_data->user_settings();
    160     else if (profile->type() == NetworkProfile::TYPE_USER)
    161       user_settings = ui_data->user_settings();
    162     else
    163       NOTREACHED();
    164   } else if (profile) {
    165     LOG(WARNING) << "Service " << service_path << " of profile "
    166                  << profile_path << " contains no or no valid UIData.";
    167     // TODO(pneubeck): add a conversion of user configured entries of old
    168     // ChromeOS versions. We will have to use a heuristic to determine which
    169     // properties _might_ be user configured.
    170   }
    171 
    172   scoped_ptr<base::DictionaryValue> active_settings(
    173       onc::TranslateShillServiceToONCPart(
    174           shill_properties,
    175           &onc::kNetworkWithStateSignature));
    176 
    177   std::string guid;
    178   active_settings->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
    179                                                  &guid);
    180 
    181   const base::DictionaryValue* user_policy = NULL;
    182   const base::DictionaryValue* device_policy = NULL;
    183   if (!guid.empty() && profile) {
    184     const Policies* policies = GetPoliciesForProfile(*profile);
    185     if (!policies) {
    186       InvokeErrorCallback(
    187           service_path, error_callback, kPoliciesNotInitialized);
    188       return;
    189     }
    190     const base::DictionaryValue* policy =
    191         GetByGUID(policies->per_network_config, guid);
    192     if (profile->type() == NetworkProfile::TYPE_SHARED)
    193       device_policy = policy;
    194     else if (profile->type() == NetworkProfile::TYPE_USER)
    195       user_policy = policy;
    196     else
    197       NOTREACHED();
    198   }
    199 
    200   // This call also removes credentials from policies.
    201   scoped_ptr<base::DictionaryValue> augmented_properties =
    202       onc::MergeSettingsAndPoliciesToAugmented(
    203           onc::kNetworkConfigurationSignature,
    204           user_policy,
    205           device_policy,
    206           user_settings,
    207           shared_settings,
    208           active_settings.get());
    209   callback.Run(service_path, *augmented_properties);
    210 }
    211 
    212 void ManagedNetworkConfigurationHandlerImpl::GetProperties(
    213     const std::string& service_path,
    214     const network_handler::DictionaryResultCallback& callback,
    215     const network_handler::ErrorCallback& error_callback) const {
    216   network_configuration_handler_->GetProperties(
    217       service_path,
    218       base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
    219       error_callback);
    220 }
    221 
    222 void ManagedNetworkConfigurationHandlerImpl::SetProperties(
    223     const std::string& service_path,
    224     const base::DictionaryValue& user_settings,
    225     const base::Closure& callback,
    226     const network_handler::ErrorCallback& error_callback) const {
    227   const NetworkState* state =
    228       network_state_handler_->GetNetworkState(service_path);
    229 
    230   if (!state) {
    231     InvokeErrorCallback(service_path, error_callback, kUnknownServicePath);
    232     return;
    233   }
    234 
    235   std::string guid = state->guid();
    236   if (guid.empty()) {
    237     // TODO(pneubeck): create an initial configuration in this case. As for
    238     // CreateConfiguration, user settings from older ChromeOS versions have to
    239     // determined here.
    240     InvokeErrorCallback(
    241         service_path, error_callback, kSetOnUnconfiguredNetwork);
    242     return;
    243   }
    244 
    245   const std::string& profile_path = state->profile_path();
    246   const NetworkProfile *profile =
    247       network_profile_handler_->GetProfileForPath(profile_path);
    248   if (!profile) {
    249     InvokeErrorCallback(service_path, error_callback, kUnknownProfilePath);
    250     return;
    251   }
    252 
    253   VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
    254           << profile->ToDebugString();
    255 
    256   const Policies* policies = GetPoliciesForProfile(*profile);
    257   if (!policies) {
    258     InvokeErrorCallback(service_path, error_callback, kPoliciesNotInitialized);
    259     return;
    260   }
    261 
    262   // Validate the ONC dictionary. We are liberal and ignore unknown field
    263   // names. User settings are only partial ONC, thus we ignore missing fields.
    264   onc::Validator validator(false,  // Ignore unknown fields.
    265                            false,  // Ignore invalid recommended field names.
    266                            false,  // Ignore missing fields.
    267                            false);  // This ONC does not come from policy.
    268 
    269   onc::Validator::Result validation_result;
    270   scoped_ptr<base::DictionaryValue> validated_user_settings =
    271       validator.ValidateAndRepairObject(
    272           &onc::kNetworkConfigurationSignature,
    273           user_settings,
    274           &validation_result);
    275 
    276   if (validation_result == onc::Validator::INVALID) {
    277     InvokeErrorCallback(service_path, error_callback, kInvalidUserSettings);
    278     return;
    279   }
    280   if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
    281     LOG(WARNING) << "Validation of ONC user settings produced warnings.";
    282 
    283   const base::DictionaryValue* policy =
    284       GetByGUID(policies->per_network_config, guid);
    285   VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
    286 
    287   scoped_ptr<base::DictionaryValue> shill_dictionary(
    288       policy_util::CreateShillConfiguration(
    289           *profile, guid, policy, validated_user_settings.get()));
    290 
    291   network_configuration_handler_->SetProperties(
    292       service_path, *shill_dictionary, callback, error_callback);
    293 }
    294 
    295 void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
    296     const std::string& userhash,
    297     const base::DictionaryValue& properties,
    298     const network_handler::StringResultCallback& callback,
    299     const network_handler::ErrorCallback& error_callback) const {
    300   const Policies* policies = GetPoliciesForUser(userhash);
    301   if (!policies) {
    302     InvokeErrorCallback("", error_callback, kPoliciesNotInitialized);
    303     return;
    304   }
    305 
    306   if (policy_util::FindMatchingPolicy(policies->per_network_config,
    307                                       properties)) {
    308     InvokeErrorCallback("", error_callback, kNetworkAlreadyConfigured);
    309     return;
    310   }
    311 
    312   const NetworkProfile* profile =
    313       network_profile_handler_->GetProfileForUserhash(userhash);
    314   if (!profile) {
    315     InvokeErrorCallback("", error_callback, kProfileNotInitialized);
    316     return;
    317   }
    318 
    319   // TODO(pneubeck): In case of WiFi, check that no other configuration for the
    320   // same {SSID, mode, security} exists. We don't support such multiple
    321   // configurations, yet.
    322 
    323   // Generate a new GUID for this configuration. Ignore the maybe provided GUID
    324   // in |properties| as it is not our own and from an untrusted source.
    325   std::string guid = base::GenerateGUID();
    326   scoped_ptr<base::DictionaryValue> shill_dictionary(
    327       policy_util::CreateShillConfiguration(
    328           *profile, guid, NULL /*no policy*/, &properties));
    329 
    330   network_configuration_handler_->CreateConfiguration(
    331       *shill_dictionary, callback, error_callback);
    332 }
    333 
    334 void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
    335     const std::string& service_path,
    336     const base::Closure& callback,
    337     const network_handler::ErrorCallback& error_callback) const {
    338   network_configuration_handler_->RemoveConfiguration(
    339       service_path, callback, error_callback);
    340 }
    341 
    342 void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
    343     ::onc::ONCSource onc_source,
    344     const std::string& userhash,
    345     const base::ListValue& network_configs_onc,
    346     const base::DictionaryValue& global_network_config) {
    347   VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
    348           << ".";
    349 
    350   // |userhash| must be empty for device policies.
    351   DCHECK(onc_source != ::onc::ONC_SOURCE_DEVICE_POLICY ||
    352          userhash.empty());
    353   Policies* policies = NULL;
    354   if (ContainsKey(policies_by_user_, userhash)) {
    355     policies = policies_by_user_[userhash].get();
    356   } else {
    357     policies = new Policies;
    358     policies_by_user_[userhash] = make_linked_ptr(policies);
    359   }
    360 
    361   policies->global_network_config.MergeDictionary(&global_network_config);
    362 
    363   GuidToPolicyMap old_per_network_config;
    364   policies->per_network_config.swap(old_per_network_config);
    365 
    366   // This stores all GUIDs of policies that have changed or are new.
    367   std::set<std::string> modified_policies;
    368 
    369   for (base::ListValue::const_iterator it = network_configs_onc.begin();
    370        it != network_configs_onc.end(); ++it) {
    371     const base::DictionaryValue* network = NULL;
    372     (*it)->GetAsDictionary(&network);
    373     DCHECK(network);
    374 
    375     std::string guid;
    376     network->GetStringWithoutPathExpansion(::onc::network_config::kGUID, &guid);
    377     DCHECK(!guid.empty());
    378 
    379     if (policies->per_network_config.count(guid) > 0) {
    380       LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
    381                  << " contains several entries for the same GUID "
    382                  << guid << ".";
    383       delete policies->per_network_config[guid];
    384     }
    385     const base::DictionaryValue* new_entry = network->DeepCopy();
    386     policies->per_network_config[guid] = new_entry;
    387 
    388     const base::DictionaryValue* old_entry = old_per_network_config[guid];
    389     if (!old_entry || !old_entry->Equals(new_entry))
    390       modified_policies.insert(guid);
    391   }
    392 
    393   STLDeleteValues(&old_per_network_config);
    394 
    395   const NetworkProfile* profile =
    396       network_profile_handler_->GetProfileForUserhash(userhash);
    397   if (!profile) {
    398     VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
    399             << "policy application.";
    400     return;
    401   }
    402 
    403   scoped_refptr<PolicyApplicator> applicator =
    404       new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
    405                            *profile,
    406                            policies->per_network_config,
    407                            policies->global_network_config,
    408                            &modified_policies);
    409   applicator->Run();
    410 }
    411 
    412 void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
    413     const NetworkProfile& profile) {
    414   VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
    415 
    416   const Policies* policies = GetPoliciesForProfile(profile);
    417   if (!policies) {
    418     VLOG(1) << "The relevant policy is not initialized, "
    419             << "postponing policy application.";
    420     return;
    421   }
    422 
    423   std::set<std::string> policy_guids;
    424   for (GuidToPolicyMap::const_iterator it =
    425            policies->per_network_config.begin();
    426        it != policies->per_network_config.end(); ++it) {
    427     policy_guids.insert(it->first);
    428   }
    429 
    430   scoped_refptr<PolicyApplicator> applicator =
    431       new PolicyApplicator(weak_ptr_factory_.GetWeakPtr(),
    432                            profile,
    433                            policies->per_network_config,
    434                            policies->global_network_config,
    435                            &policy_guids);
    436   applicator->Run();
    437 }
    438 
    439 void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
    440     const NetworkProfile& profile) {
    441   // Nothing to do in this case.
    442 }
    443 
    444 void ManagedNetworkConfigurationHandlerImpl::CreateConfigurationFromPolicy(
    445     const base::DictionaryValue& shill_properties) {
    446   network_configuration_handler_->CreateConfiguration(
    447       shill_properties,
    448       base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
    449                  weak_ptr_factory_.GetWeakPtr()),
    450       base::Bind(&LogErrorWithDict, FROM_HERE));
    451 }
    452 
    453 void ManagedNetworkConfigurationHandlerImpl::
    454     UpdateExistingConfigurationWithPropertiesFromPolicy(
    455         const base::DictionaryValue& existing_properties,
    456         const base::DictionaryValue& new_properties) {
    457   base::DictionaryValue shill_properties;
    458 
    459   std::string profile;
    460   existing_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
    461                                                     &profile);
    462   if (profile.empty()) {
    463     LOG(ERROR) << "Missing profile property.";
    464     return;
    465   }
    466   shill_properties.SetStringWithoutPathExpansion(shill::kProfileProperty,
    467                                                  profile);
    468 
    469   if (!shill_property_util::CopyIdentifyingProperties(existing_properties,
    470                                                       &shill_properties)) {
    471     LOG(ERROR) << "Missing identifying properties.";
    472   }
    473 
    474   shill_properties.MergeDictionary(&new_properties);
    475 
    476   network_configuration_handler_->CreateConfiguration(
    477       shill_properties,
    478       base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
    479                  weak_ptr_factory_.GetWeakPtr()),
    480       base::Bind(&LogErrorWithDict, FROM_HERE));
    481 }
    482 
    483 const base::DictionaryValue*
    484 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
    485     const std::string userhash,
    486     const std::string& guid,
    487     ::onc::ONCSource* onc_source) const {
    488   *onc_source = ::onc::ONC_SOURCE_NONE;
    489 
    490   if (!userhash.empty()) {
    491     const Policies* user_policies = GetPoliciesForUser(userhash);
    492     if (user_policies) {
    493       const base::DictionaryValue* policy =
    494           GetByGUID(user_policies->per_network_config, guid);
    495       if (policy) {
    496         *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
    497         return policy;
    498       }
    499     }
    500   }
    501 
    502   const Policies* device_policies = GetPoliciesForUser(std::string());
    503   if (device_policies) {
    504     const base::DictionaryValue* policy =
    505         GetByGUID(device_policies->per_network_config, guid);
    506     if (policy) {
    507       *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
    508       return policy;
    509     }
    510   }
    511 
    512   return NULL;
    513 }
    514 
    515 const base::DictionaryValue*
    516 ManagedNetworkConfigurationHandlerImpl::GetGlobalConfigFromPolicy(
    517     const std::string userhash) const {
    518   const Policies* policies = GetPoliciesForUser(userhash);
    519   if (!policies)
    520     return NULL;
    521 
    522   return &policies->global_network_config;
    523 }
    524 const base::DictionaryValue*
    525 ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
    526     const std::string& guid,
    527     const std::string& profile_path) const {
    528   const NetworkProfile* profile =
    529       network_profile_handler_->GetProfileForPath(profile_path);
    530   if (!profile) {
    531     LOG(ERROR) << "Profile path unknown: " << profile_path;
    532     return NULL;
    533   }
    534 
    535   const Policies* policies = GetPoliciesForProfile(*profile);
    536   if (!policies)
    537     return NULL;
    538 
    539   return GetByGUID(policies->per_network_config, guid);
    540 }
    541 
    542 const ManagedNetworkConfigurationHandlerImpl::Policies*
    543 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
    544     const std::string& userhash) const {
    545   UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
    546   if (it == policies_by_user_.end())
    547     return NULL;
    548   return it->second.get();
    549 }
    550 
    551 const ManagedNetworkConfigurationHandlerImpl::Policies*
    552 ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
    553     const NetworkProfile& profile) const {
    554   DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
    555          profile.userhash.empty());
    556   return GetPoliciesForUser(profile.userhash);
    557 }
    558 
    559 ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
    560     : network_state_handler_(NULL),
    561       network_profile_handler_(NULL),
    562       network_configuration_handler_(NULL),
    563       weak_ptr_factory_(this) {}
    564 
    565 ManagedNetworkConfigurationHandlerImpl::
    566     ~ManagedNetworkConfigurationHandlerImpl() {
    567   network_profile_handler_->RemoveObserver(this);
    568 }
    569 
    570 void ManagedNetworkConfigurationHandlerImpl::Init(
    571     NetworkStateHandler* network_state_handler,
    572     NetworkProfileHandler* network_profile_handler,
    573     NetworkConfigurationHandler* network_configuration_handler) {
    574   network_state_handler_ = network_state_handler;
    575   network_profile_handler_ = network_profile_handler;
    576   network_configuration_handler_ = network_configuration_handler;
    577   network_profile_handler_->AddObserver(this);
    578 }
    579 
    580 void ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied(
    581     const std::string& service_path) {
    582   if (service_path.empty())
    583     return;
    584   FOR_EACH_OBSERVER(
    585       NetworkPolicyObserver, observers_, PolicyApplied(service_path));
    586 }
    587 
    588 }  // namespace chromeos
    589