Home | History | Annotate | Download | only in onc
      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 // The implementation of TranslateONCObjectToShill is structured in two parts:
      6 // - The recursion through the existing ONC hierarchy
      7 //     see TranslateONCHierarchy
      8 // - The local translation of an object depending on the associated signature
      9 //     see LocalTranslator::TranslateFields
     10 
     11 #include "chromeos/network/onc/onc_translator.h"
     12 
     13 #include <string>
     14 
     15 #include "base/json/json_reader.h"
     16 #include "base/json/json_writer.h"
     17 #include "base/logging.h"
     18 #include "base/values.h"
     19 #include "chromeos/network/onc/onc_signature.h"
     20 #include "chromeos/network/onc/onc_translation_tables.h"
     21 #include "chromeos/network/shill_property_util.h"
     22 #include "components/onc/onc_constants.h"
     23 #include "third_party/cros_system_api/dbus/service_constants.h"
     24 
     25 namespace chromeos {
     26 namespace onc {
     27 
     28 namespace {
     29 
     30 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
     31   std::string str;
     32   if (!value.GetAsString(&str))
     33     base::JSONWriter::Write(&value, &str);
     34   return make_scoped_ptr(base::Value::CreateStringValue(str));
     35 }
     36 
     37 // This class is responsible to translate the local fields of the given
     38 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
     39 // translation should consider (if possible) only fields of this ONC object and
     40 // not nested objects because recursion is handled by the calling function
     41 // TranslateONCHierarchy.
     42 class LocalTranslator {
     43  public:
     44   LocalTranslator(const OncValueSignature& onc_signature,
     45                   const base::DictionaryValue& onc_object,
     46                   base::DictionaryValue* shill_dictionary)
     47       : onc_signature_(&onc_signature),
     48         onc_object_(&onc_object),
     49         shill_dictionary_(shill_dictionary) {
     50     field_translation_table_ = GetFieldTranslationTable(onc_signature);
     51   }
     52 
     53   void TranslateFields();
     54 
     55  private:
     56   void TranslateEthernet();
     57   void TranslateOpenVPN();
     58   void TranslateVPN();
     59   void TranslateWiFi();
     60   void TranslateEAP();
     61   void TranslateNetworkConfiguration();
     62 
     63   // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
     64   // translation (shill_property_name) is defined by |onc_signature_|.
     65   void CopyFieldsAccordingToSignature();
     66 
     67   // Adds |value| to |shill_dictionary| at the field shill_property_name given
     68   // by the associated signature. Takes ownership of |value|. Does nothing if
     69   // |value| is NULL or the property name cannot be read from the signature.
     70   void AddValueAccordingToSignature(const std::string& onc_field_name,
     71                                     scoped_ptr<base::Value> value);
     72 
     73   // If existent, translates the entry at |onc_field_name| in |onc_object_|
     74   // using |table|. It is an error if no matching table entry is found. Writes
     75   // the result as entry at |shill_property_name| in |shill_dictionary_|.
     76   void TranslateWithTableAndSet(const std::string& onc_field_name,
     77                                 const StringTranslationEntry table[],
     78                                 const std::string& shill_property_name);
     79 
     80   const OncValueSignature* onc_signature_;
     81   const FieldTranslationEntry* field_translation_table_;
     82   const base::DictionaryValue* onc_object_;
     83   base::DictionaryValue* shill_dictionary_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
     86 };
     87 
     88 void LocalTranslator::TranslateFields() {
     89   if (onc_signature_ == &kNetworkConfigurationSignature)
     90     TranslateNetworkConfiguration();
     91   else if (onc_signature_ == &kEthernetSignature)
     92     TranslateEthernet();
     93   else if (onc_signature_ == &kVPNSignature)
     94     TranslateVPN();
     95   else if (onc_signature_ == &kOpenVPNSignature)
     96     TranslateOpenVPN();
     97   else if (onc_signature_ == &kWiFiSignature)
     98     TranslateWiFi();
     99   else if (onc_signature_ == &kEAPSignature)
    100     TranslateEAP();
    101   else
    102     CopyFieldsAccordingToSignature();
    103 }
    104 
    105 void LocalTranslator::TranslateEthernet() {
    106   std::string authentication;
    107   onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
    108                                              &authentication);
    109 
    110   const char* shill_type = shill::kTypeEthernet;
    111   if (authentication == ::onc::ethernet::k8021X)
    112     shill_type = shill::kTypeEthernetEap;
    113   shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
    114                                                    shill_type);
    115 
    116   CopyFieldsAccordingToSignature();
    117 }
    118 
    119 void LocalTranslator::TranslateOpenVPN() {
    120   // Shill supports only one RemoteCertKU but ONC a list.
    121   // Copy only the first entry if existing.
    122   const base::ListValue* certKUs = NULL;
    123   std::string certKU;
    124   if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
    125                                                &certKUs) &&
    126       certKUs->GetString(0, &certKU)) {
    127     shill_dictionary_->SetStringWithoutPathExpansion(
    128         shill::kOpenVPNRemoteCertKUProperty, certKU);
    129   }
    130 
    131   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
    132        it.Advance()) {
    133     scoped_ptr<base::Value> translated;
    134     if (it.key() == ::onc::vpn::kSaveCredentials ||
    135         it.key() == ::onc::openvpn::kRemoteCertKU ||
    136         it.key() == ::onc::openvpn::kServerCAPEMs) {
    137       translated.reset(it.value().DeepCopy());
    138     } else {
    139       // Shill wants all Provider/VPN fields to be strings.
    140       translated = ConvertValueToString(it.value());
    141     }
    142     AddValueAccordingToSignature(it.key(), translated.Pass());
    143   }
    144 }
    145 
    146 void LocalTranslator::TranslateVPN() {
    147   std::string type;
    148   onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
    149   TranslateWithTableAndSet(type, kVPNTypeTable, shill::kProviderTypeProperty);
    150 
    151   CopyFieldsAccordingToSignature();
    152 }
    153 
    154 void LocalTranslator::TranslateWiFi() {
    155   std::string security;
    156   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSecurity, &security);
    157   TranslateWithTableAndSet(security, kWiFiSecurityTable,
    158                            shill::kSecurityProperty);
    159 
    160   std::string ssid;
    161   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid);
    162   shill_property_util::SetSSID(ssid, shill_dictionary_);
    163 
    164   // We currently only support managed and no adhoc networks.
    165   shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
    166                                                    shill::kModeManaged);
    167   CopyFieldsAccordingToSignature();
    168 }
    169 
    170 void LocalTranslator::TranslateEAP() {
    171   std::string outer;
    172   onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
    173   TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
    174 
    175   // Translate the inner protocol only for outer tunneling protocols.
    176   if (outer == ::onc::eap::kPEAP || outer == ::onc::eap::kEAP_TTLS) {
    177     // In ONC the Inner protocol defaults to "Automatic".
    178     std::string inner = ::onc::eap::kAutomatic;
    179     // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
    180     // Shill.
    181     onc_object_->GetStringWithoutPathExpansion(::onc::eap::kInner, &inner);
    182     if (inner != ::onc::eap::kAutomatic) {
    183       const StringTranslationEntry* table =
    184           outer == ::onc::eap::kPEAP ? kEAP_PEAP_InnerTable :
    185                                        kEAP_TTLS_InnerTable;
    186       TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty);
    187     }
    188   }
    189 
    190   CopyFieldsAccordingToSignature();
    191 }
    192 
    193 void LocalTranslator::TranslateNetworkConfiguration() {
    194   std::string type;
    195   onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
    196                                              &type);
    197 
    198   // Set the type except for Ethernet which is set in TranslateEthernet.
    199   if (type != ::onc::network_type::kEthernet)
    200     TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty);
    201 
    202   // Shill doesn't allow setting the name for non-VPN networks.
    203   if (type == ::onc::network_type::kVPN) {
    204     std::string name;
    205     onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kName,
    206                                                &name);
    207     shill_dictionary_->SetStringWithoutPathExpansion(shill::kNameProperty,
    208                                                      name);
    209   }
    210 
    211   CopyFieldsAccordingToSignature();
    212 }
    213 
    214 void LocalTranslator::CopyFieldsAccordingToSignature() {
    215   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
    216        it.Advance()) {
    217     AddValueAccordingToSignature(it.key(),
    218                                  make_scoped_ptr(it.value().DeepCopy()));
    219   }
    220 }
    221 
    222 void LocalTranslator::AddValueAccordingToSignature(
    223     const std::string& onc_name,
    224     scoped_ptr<base::Value> value) {
    225   if (!value || !field_translation_table_)
    226     return;
    227   std::string shill_property_name;
    228   if (!GetShillPropertyName(onc_name,
    229                             field_translation_table_,
    230                             &shill_property_name))
    231     return;
    232 
    233   shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
    234                                              value.release());
    235 }
    236 
    237 void LocalTranslator::TranslateWithTableAndSet(
    238     const std::string& onc_value,
    239     const StringTranslationEntry table[],
    240     const std::string& shill_property_name) {
    241   std::string shill_value;
    242   if (TranslateStringToShill(table, onc_value, &shill_value)) {
    243     shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
    244                                                      shill_value);
    245     return;
    246   }
    247   // As we previously validate ONC, this case should never occur. If it still
    248   // occurs, we should check here. Otherwise the failure will only show up much
    249   // later in Shill.
    250   LOG(ERROR) << "Value '" << onc_value
    251              << "' cannot be translated to Shill property "
    252              << shill_property_name;
    253 }
    254 
    255 // Iterates recursively over |onc_object| and its |signature|. At each object
    256 // applies the local translation using LocalTranslator::TranslateFields. The
    257 // results are written to |shill_dictionary|.
    258 void TranslateONCHierarchy(const OncValueSignature& signature,
    259                            const base::DictionaryValue& onc_object,
    260                            base::DictionaryValue* shill_dictionary) {
    261   base::DictionaryValue* target_shill_dictionary = shill_dictionary;
    262   std::vector<std::string> path_to_shill_dictionary =
    263       GetPathToNestedShillDictionary(signature);
    264   for (std::vector<std::string>::const_iterator it =
    265            path_to_shill_dictionary.begin();
    266        it != path_to_shill_dictionary.end();
    267        ++it) {
    268     base::DictionaryValue* nested_shill_dict = NULL;
    269     target_shill_dictionary->GetDictionaryWithoutPathExpansion(
    270         *it, &nested_shill_dict);
    271     if (!nested_shill_dict)
    272       nested_shill_dict = new base::DictionaryValue;
    273     target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict);
    274     target_shill_dictionary = nested_shill_dict;
    275   }
    276   // Translates fields of |onc_object| and writes them to
    277   // |target_shill_dictionary_| nested in |shill_dictionary|.
    278   LocalTranslator translator(signature, onc_object, target_shill_dictionary);
    279   translator.TranslateFields();
    280 
    281   // Recurse into nested objects.
    282   for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
    283        it.Advance()) {
    284     const base::DictionaryValue* inner_object = NULL;
    285     if (!it.value().GetAsDictionary(&inner_object))
    286       continue;
    287 
    288     const OncFieldSignature* field_signature =
    289         GetFieldSignature(signature, it.key());
    290 
    291     TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
    292                           shill_dictionary);
    293   }
    294 }
    295 
    296 }  // namespace
    297 
    298 scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
    299     const OncValueSignature* onc_signature,
    300     const base::DictionaryValue& onc_object) {
    301   CHECK(onc_signature != NULL);
    302   scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
    303   TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
    304   return shill_dictionary.Pass();
    305 }
    306 
    307 }  // namespace onc
    308 }  // namespace chromeos
    309