onc_translator_shill_to_onc.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file.
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/onc/onc_translator.h"
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <string>
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/basictypes.h"
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_reader.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_writer.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/logging.h"
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_util.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/values.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/network_profile_handler.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/network_state.h"
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/network_util.h"
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/onc/onc_signature.h"
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/onc/onc_translation_tables.h"
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chromeos/network/shill_property_util.h"
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "components/onc/onc_constants.h"
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace chromeos {
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace onc {
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace {
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Converts |str| to a base::Value of the given |type|. If the conversion fails,
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// returns NULL.
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                             base::Value::Type type) {
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::Value* value;
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (type == base::Value::TYPE_STRING) {
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    value = new base::StringValue(str);
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    value = base::JSONReader::Read(str);
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (value == NULL || value->GetType() != type) {
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    delete value;
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    value = NULL;
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return make_scoped_ptr(value);
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This class implements the translation of properties from the given
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// recursive calls to CreateTranslatedONCObject of new instances, nested objects
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// are translated.
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class ShillToONCTranslator {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                       ::onc::ONCSource onc_source,
558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                       const OncValueSignature& onc_signature)
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : shill_dictionary_(&shill_dictionary),
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        onc_source_(onc_source),
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        onc_signature_(&onc_signature) {
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    field_translation_table_ = GetFieldTranslationTable(onc_signature);
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       ::onc::ONCSource onc_source,
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       const OncValueSignature& onc_signature,
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       const FieldTranslationEntry* field_translation_table)
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      : shill_dictionary_(&shill_dictionary),
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        onc_source_(onc_source),
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        onc_signature_(&onc_signature),
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        field_translation_table_(field_translation_table) {
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Translates the associated Shill dictionary and creates an ONC object of the
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // given signature.
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void TranslateEthernet();
788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void TranslateOpenVPN();
798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void TranslateIPsec();
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateVPN();
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void TranslateWiFiWithState();
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateWiMAXWithState();
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateCellularWithState();
848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  void TranslateCellularDevice();
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateNetworkWithState();
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void TranslateIPConfig();
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateSavedOrStaticIPConfig(const std::string& nameserver_property);
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateSavedIPConfig();
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateStaticIPConfig();
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Creates an ONC object from |dictionary| according to the signature
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // associated to |onc_field_name| and adds it to |onc_object_| at
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |onc_field_name|.
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateAndAddNestedObject(const std::string& onc_field_name,
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   const base::DictionaryValue& dictionary);
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Creates an ONC object from |shill_dictionary_| according to the signature
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // associated to |onc_field_name| and adds it to |onc_object_| at
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |onc_field_name|.
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateAndAddNestedObject(const std::string& onc_field_name);
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // to |value| if the dictionary exists.
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void SetNestedOncValue(const std::string& onc_dictionary_name,
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         const std::string& onc_field_name,
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         const base::Value& value);
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Translates a list of nested objects and adds the list to |onc_object_| at
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |onc_field_name|. If there are errors while parsing individual objects or
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // if the resulting list contains no entries, the result will not be added to
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |onc_object_|.
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateAndAddListOfObjects(const std::string& onc_field_name,
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    const base::ListValue& list);
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Applies function CopyProperty to each field of |value_signature| and its
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // base signatures.
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void CopyPropertiesAccordingToSignature(
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      const OncValueSignature* value_signature);
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Applies function CopyProperty to each field of |onc_signature_| and its
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // base signatures.
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void CopyPropertiesAccordingToSignature();
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If |shill_property_name| is defined in |field_signature|, copies this
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // entry from |shill_dictionary_| to |onc_object_| if it exists.
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void CopyProperty(const OncFieldSignature* field_signature);
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If existent, translates the entry at |shill_property_name| in
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |shill_dictionary_| using |table|. It is an error if no matching table
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // entry is found. Writes the result as entry at |onc_field_name| in
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |onc_object_|.
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void TranslateWithTableAndSet(const std::string& shill_property_name,
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                const StringTranslationEntry table[],
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                const std::string& onc_field_name);
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Returns the name of the Shill service provided in |shill_dictionary_|
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // for debugging.
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string GetName();
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const base::DictionaryValue* shill_dictionary_;
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ::onc::ONCSource onc_source_;
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const OncValueSignature* onc_signature_;
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const FieldTranslationEntry* field_translation_table_;
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> onc_object_;
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)scoped_ptr<base::DictionaryValue>
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ShillToONCTranslator::CreateTranslatedONCObject() {
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  onc_object_.reset(new base::DictionaryValue);
15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (onc_signature_ == &kNetworkWithStateSignature) {
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    TranslateNetworkWithState();
15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else if (onc_signature_ == &kEthernetSignature) {
155    TranslateEthernet();
156  } else if (onc_signature_ == &kVPNSignature) {
157    TranslateVPN();
158  } else if (onc_signature_ == &kOpenVPNSignature) {
159    TranslateOpenVPN();
160  } else if (onc_signature_ == &kIPsecSignature) {
161    TranslateIPsec();
162  } else if (onc_signature_ == &kWiFiWithStateSignature) {
163    TranslateWiFiWithState();
164  } else if (onc_signature_ == &kWiMAXWithStateSignature) {
165    TranslateWiMAXWithState();
166  } else if (onc_signature_ == &kCellularWithStateSignature) {
167    if (field_translation_table_ == kCellularDeviceTable)
168      TranslateCellularDevice();
169    else
170      TranslateCellularWithState();
171  } else if (onc_signature_ == &kIPConfigSignature) {
172    TranslateIPConfig();
173  } else if (onc_signature_ == &kSavedIPConfigSignature) {
174    TranslateSavedIPConfig();
175  } else if (onc_signature_ == &kStaticIPConfigSignature) {
176    TranslateStaticIPConfig();
177  } else {
178    CopyPropertiesAccordingToSignature();
179  }
180  return onc_object_.Pass();
181}
182
183void ShillToONCTranslator::TranslateEthernet() {
184  std::string shill_network_type;
185  shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
186                                                   &shill_network_type);
187  const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
188  if (shill_network_type == shill::kTypeEthernetEap)
189    onc_auth = ::onc::ethernet::k8021X;
190  onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
191                                             onc_auth);
192}
193
194void ShillToONCTranslator::TranslateOpenVPN() {
195  if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
196    TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
197
198  // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
199  // wraps the value into a list.
200  std::string certKU;
201  if (shill_dictionary_->GetStringWithoutPathExpansion(
202          shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
203    scoped_ptr<base::ListValue> certKUs(new base::ListValue);
204    certKUs->AppendString(certKU);
205    onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
206                                         certKUs.release());
207  }
208
209  for (const OncFieldSignature* field_signature = onc_signature_->fields;
210       field_signature->onc_field_name != NULL; ++field_signature) {
211    const std::string& onc_field_name = field_signature->onc_field_name;
212    if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
213        onc_field_name == ::onc::openvpn::kServerCAPEMs) {
214      CopyProperty(field_signature);
215      continue;
216    }
217
218    std::string shill_property_name;
219    const base::Value* shill_value = NULL;
220    if (!field_translation_table_ ||
221        !GetShillPropertyName(field_signature->onc_field_name,
222                              field_translation_table_,
223                              &shill_property_name) ||
224        !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
225                                                    &shill_value)) {
226      continue;
227    }
228
229    scoped_ptr<base::Value> translated;
230    std::string shill_str;
231    if (shill_value->GetAsString(&shill_str)) {
232      // Shill wants all Provider/VPN fields to be strings. Translates these
233      // strings back to the correct ONC type.
234      translated = ConvertStringToValue(
235          shill_str,
236          field_signature->value_signature->onc_type);
237
238      if (translated.get() == NULL) {
239        LOG(ERROR) << "Shill property '" << shill_property_name
240                   << "' with value " << *shill_value
241                   << " couldn't be converted to base::Value::Type "
242                   << field_signature->value_signature->onc_type
243                   << ": " << GetName();
244      } else {
245        onc_object_->SetWithoutPathExpansion(onc_field_name,
246                                             translated.release());
247      }
248    } else {
249      LOG(ERROR) << "Shill property '" << shill_property_name
250                 << "' has value " << *shill_value
251                 << ", but expected a string: " << GetName();
252    }
253  }
254}
255
256void ShillToONCTranslator::TranslateIPsec() {
257  CopyPropertiesAccordingToSignature();
258  if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
259    TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
260  std::string client_cert_id;
261  shill_dictionary_->GetStringWithoutPathExpansion(
262      shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
263  std::string authentication_type =
264      client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
265  onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
266                                             authentication_type);
267}
268
269void ShillToONCTranslator::TranslateVPN() {
270  CopyPropertiesAccordingToSignature();
271
272  // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
273  // just translating network state in network_util::TranslateNetworkStateToONC.
274  const base::DictionaryValue* provider = NULL;
275  if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
276          shill::kProviderProperty, &provider)) {
277    return;
278  }
279  std::string shill_provider_type, onc_provider_type;
280  provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
281                                          &shill_provider_type);
282  if (!TranslateStringToONC(
283          kVPNTypeTable, shill_provider_type, &onc_provider_type)) {
284    return;
285  }
286  onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
287                                             onc_provider_type);
288  std::string provider_host;
289  if (provider->GetStringWithoutPathExpansion(shill::kHostProperty,
290                                              &provider_host)) {
291    onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
292                                               provider_host);
293  }
294
295  // Translate the nested dictionary.
296  std::string provider_type_dictionary;
297  if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
298    TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
299    TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
300    provider_type_dictionary = ::onc::vpn::kIPsec;
301  } else {
302    TranslateAndAddNestedObject(onc_provider_type, *provider);
303    provider_type_dictionary = onc_provider_type;
304  }
305
306  bool save_credentials;
307  if (shill_dictionary_->GetBooleanWithoutPathExpansion(
308          shill::kSaveCredentialsProperty, &save_credentials)) {
309    SetNestedOncValue(provider_type_dictionary,
310                      ::onc::vpn::kSaveCredentials,
311                      base::FundamentalValue(save_credentials));
312  }
313}
314
315void ShillToONCTranslator::TranslateWiFiWithState() {
316  TranslateWithTableAndSet(
317      shill::kSecurityProperty, kWiFiSecurityTable, ::onc::wifi::kSecurity);
318  std::string ssid = shill_property_util::GetSSIDFromProperties(
319      *shill_dictionary_, NULL /* ignore unknown encoding */);
320  if (!ssid.empty())
321    onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
322  CopyPropertiesAccordingToSignature();
323  TranslateAndAddNestedObject(::onc::wifi::kEAP);
324}
325
326void ShillToONCTranslator::TranslateWiMAXWithState() {
327  CopyPropertiesAccordingToSignature();
328  TranslateAndAddNestedObject(::onc::wimax::kEAP);
329}
330
331void ShillToONCTranslator::TranslateCellularWithState() {
332  CopyPropertiesAccordingToSignature();
333  TranslateWithTableAndSet(shill::kActivationStateProperty,
334                           kActivationStateTable,
335                           ::onc::cellular::kActivationState);
336  TranslateWithTableAndSet(shill::kRoamingStateProperty,
337                           kRoamingStateTable,
338                           ::onc::cellular::kRoamingState);
339  const base::DictionaryValue* dictionary = NULL;
340  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
341        shill::kServingOperatorProperty, &dictionary)) {
342    TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
343  }
344  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
345        shill::kCellularApnProperty, &dictionary)) {
346    TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
347  }
348  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
349        shill::kCellularLastGoodApnProperty, &dictionary)) {
350    TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
351  }
352  // Merge the Device dictionary with this one (Cellular) using the
353  // CellularDevice signature.
354  const base::DictionaryValue* device_dictionary = NULL;
355  if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
356          shill::kDeviceProperty, &device_dictionary)) {
357    return;
358  }
359  ShillToONCTranslator nested_translator(*device_dictionary,
360                                         onc_source_,
361                                         kCellularWithStateSignature,
362                                         kCellularDeviceTable);
363  scoped_ptr<base::DictionaryValue> nested_object =
364      nested_translator.CreateTranslatedONCObject();
365  onc_object_->MergeDictionary(nested_object.get());
366}
367
368void ShillToONCTranslator::TranslateCellularDevice() {
369  CopyPropertiesAccordingToSignature();
370  const base::DictionaryValue* shill_sim_lock_status = NULL;
371  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
372          shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
373    TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
374                                *shill_sim_lock_status);
375  }
376  const base::ListValue* shill_apns = NULL;
377  if (shill_dictionary_->GetListWithoutPathExpansion(
378          shill::kCellularApnListProperty, &shill_apns)) {
379    TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
380  }
381  const base::ListValue* shill_found_networks = NULL;
382  if (shill_dictionary_->GetListWithoutPathExpansion(
383          shill::kFoundNetworksProperty, &shill_found_networks)) {
384    TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
385                                 *shill_found_networks);
386  }
387}
388
389void ShillToONCTranslator::TranslateNetworkWithState() {
390  CopyPropertiesAccordingToSignature();
391
392  std::string shill_network_type;
393  shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
394                                                   &shill_network_type);
395  std::string onc_network_type = ::onc::network_type::kEthernet;
396  if (shill_network_type != shill::kTypeEthernet &&
397      shill_network_type != shill::kTypeEthernetEap) {
398    TranslateStringToONC(
399        kNetworkTypeTable, shill_network_type, &onc_network_type);
400  }
401  // Translate nested Cellular, WiFi, etc. properties.
402  if (!onc_network_type.empty()) {
403    onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
404                                               onc_network_type);
405    TranslateAndAddNestedObject(onc_network_type);
406  }
407
408  // Since Name is a read only field in Shill unless it's a VPN, it is copied
409  // here, but not when going the other direction (if it's not a VPN).
410  std::string name;
411  shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
412  onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
413                                             name);
414
415  // Limit ONC state to "NotConnected", "Connected", or "Connecting".
416  std::string state;
417  if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
418                                                       &state)) {
419    std::string onc_state = ::onc::connection_state::kNotConnected;
420    if (NetworkState::StateIsConnected(state)) {
421      onc_state = ::onc::connection_state::kConnected;
422    } else if (NetworkState::StateIsConnecting(state)) {
423      onc_state = ::onc::connection_state::kConnecting;
424    }
425    onc_object_->SetStringWithoutPathExpansion(
426        ::onc::network_config::kConnectionState, onc_state);
427    // Only set 'RestrictedConnectivity' if true.
428    if (state == shill::kStatePortal) {
429      onc_object_->SetBooleanWithoutPathExpansion(
430          ::onc::network_config::kRestrictedConnectivity, true);
431    }
432  }
433
434  std::string profile_path;
435  if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
436      shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
437                                                       &profile_path)) {
438    std::string source;
439    if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
440      source = ::onc::network_config::kSourceDevicePolicy;
441    else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
442      source = ::onc::network_config::kSourceUserPolicy;
443    else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
444      source = ::onc::network_config::kSourceDevice;
445    else if (!profile_path.empty())
446      source = ::onc::network_config::kSourceUser;
447    else
448      source = ::onc::network_config::kSourceNone;
449    onc_object_->SetStringWithoutPathExpansion(
450        ::onc::network_config::kSource, source);
451  }
452
453  // Use a human-readable aa:bb format for any hardware MAC address. Note:
454  // this property is provided by the caller but is not part of the Shill
455  // Service properties (it is copied from the Device properties).
456  std::string address;
457  if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
458                                                       &address)) {
459    onc_object_->SetStringWithoutPathExpansion(
460        ::onc::network_config::kMacAddress,
461        network_util::FormattedMacAddress(address));
462  }
463
464  // Shill's Service has an IPConfig property (note the singular), not an
465  // IPConfigs property. However, we require the caller of the translation to
466  // patch the Shill dictionary before passing it to the translator.
467  const base::ListValue* shill_ipconfigs = NULL;
468  if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
469                                                     &shill_ipconfigs)) {
470    TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
471                                 *shill_ipconfigs);
472  }
473
474  TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig);
475  TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig);
476}
477
478void ShillToONCTranslator::TranslateIPConfig() {
479  CopyPropertiesAccordingToSignature();
480  std::string shill_ip_method;
481  shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
482                                                   &shill_ip_method);
483  std::string type;
484  if (shill_ip_method == shill::kTypeIPv4 ||
485      shill_ip_method == shill::kTypeDHCP) {
486    type = ::onc::ipconfig::kIPv4;
487  } else if (shill_ip_method == shill::kTypeIPv6 ||
488             shill_ip_method == shill::kTypeDHCP6) {
489    type = ::onc::ipconfig::kIPv6;
490  } else {
491    return;  // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
492  }
493
494  onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
495}
496
497void ShillToONCTranslator::TranslateSavedOrStaticIPConfig(
498    const std::string& nameserver_property) {
499  CopyPropertiesAccordingToSignature();
500  // Saved/Static IP config nameservers are stored as a comma separated list.
501  std::string shill_nameservers;
502  shill_dictionary_->GetStringWithoutPathExpansion(
503      nameserver_property, &shill_nameservers);
504  std::vector<std::string> onc_nameserver_vector;
505  if (Tokenize(shill_nameservers, ",", &onc_nameserver_vector) > 0) {
506    scoped_ptr<base::ListValue> onc_nameservers(new base::ListValue);
507    for (std::vector<std::string>::iterator iter =
508             onc_nameserver_vector.begin();
509         iter != onc_nameserver_vector.end(); ++iter) {
510      onc_nameservers->AppendString(*iter);
511    }
512    onc_object_->SetWithoutPathExpansion(::onc::ipconfig::kNameServers,
513                                         onc_nameservers.release());
514  }
515  // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
516  // in ONC, but not if the object would be empty except the type.
517  if (!onc_object_->empty()) {
518    onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
519                                               ::onc::ipconfig::kIPv4);
520  }
521}
522
523void ShillToONCTranslator::TranslateSavedIPConfig() {
524  TranslateSavedOrStaticIPConfig(shill::kSavedIPNameServersProperty);
525}
526
527void ShillToONCTranslator::TranslateStaticIPConfig() {
528  TranslateSavedOrStaticIPConfig(shill::kStaticIPNameServersProperty);
529}
530
531void ShillToONCTranslator::TranslateAndAddNestedObject(
532    const std::string& onc_field_name) {
533  TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
534}
535
536void ShillToONCTranslator::TranslateAndAddNestedObject(
537    const std::string& onc_field_name,
538    const base::DictionaryValue& dictionary) {
539  const OncFieldSignature* field_signature =
540      GetFieldSignature(*onc_signature_, onc_field_name);
541  if (!field_signature) {
542    NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
543    return;
544  }
545  ShillToONCTranslator nested_translator(
546      dictionary, onc_source_, *field_signature->value_signature);
547  scoped_ptr<base::DictionaryValue> nested_object =
548      nested_translator.CreateTranslatedONCObject();
549  if (nested_object->empty())
550    return;
551  onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
552}
553
554void ShillToONCTranslator::SetNestedOncValue(
555    const std::string& onc_dictionary_name,
556    const std::string& onc_field_name,
557    const base::Value& value) {
558  base::DictionaryValue* nested;
559  if (!onc_object_->GetDictionaryWithoutPathExpansion(
560          onc_dictionary_name, &nested)) {
561    nested = new base::DictionaryValue;
562    onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
563  }
564  nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
565}
566
567void ShillToONCTranslator::TranslateAndAddListOfObjects(
568    const std::string& onc_field_name,
569    const base::ListValue& list) {
570  const OncFieldSignature* field_signature =
571      GetFieldSignature(*onc_signature_, onc_field_name);
572  if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
573    LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
574               << field_signature->value_signature->onc_type
575               << "', expected: base::Value::TYPE_LIST: " << GetName();
576    return;
577  }
578  DCHECK(field_signature->value_signature->onc_array_entry_signature);
579  scoped_ptr<base::ListValue> result(new base::ListValue());
580  for (base::ListValue::const_iterator it = list.begin();
581       it != list.end(); ++it) {
582    const base::DictionaryValue* shill_value = NULL;
583    if (!(*it)->GetAsDictionary(&shill_value))
584      continue;
585    ShillToONCTranslator nested_translator(
586        *shill_value,
587        onc_source_,
588        *field_signature->value_signature->onc_array_entry_signature);
589    scoped_ptr<base::DictionaryValue> nested_object =
590        nested_translator.CreateTranslatedONCObject();
591    // If the nested object couldn't be parsed, simply omit it.
592    if (nested_object->empty())
593      continue;
594    result->Append(nested_object.release());
595  }
596  // If there are no entries in the list, there is no need to expose this field.
597  if (result->empty())
598    return;
599  onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
600}
601
602void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
603  CopyPropertiesAccordingToSignature(onc_signature_);
604}
605
606void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
607    const OncValueSignature* value_signature) {
608  if (value_signature->base_signature)
609    CopyPropertiesAccordingToSignature(value_signature->base_signature);
610  if (!value_signature->fields)
611    return;
612  for (const OncFieldSignature* field_signature = value_signature->fields;
613       field_signature->onc_field_name != NULL; ++field_signature) {
614    CopyProperty(field_signature);
615  }
616}
617
618void ShillToONCTranslator::CopyProperty(
619    const OncFieldSignature* field_signature) {
620  std::string shill_property_name;
621  const base::Value* shill_value = NULL;
622  if (!field_translation_table_ ||
623      !GetShillPropertyName(field_signature->onc_field_name,
624                            field_translation_table_,
625                            &shill_property_name) ||
626      !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
627                                                  &shill_value)) {
628    return;
629  }
630
631  if (shill_value->GetType() != field_signature->value_signature->onc_type) {
632    LOG(ERROR) << "Shill property '" << shill_property_name
633               << "' with value " << *shill_value
634               << " has base::Value::Type " << shill_value->GetType()
635               << " but ONC field '" << field_signature->onc_field_name
636               << "' requires type "
637               << field_signature->value_signature->onc_type
638               << ": " << GetName();
639    return;
640  }
641
642 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
643                                      shill_value->DeepCopy());
644}
645
646void ShillToONCTranslator::TranslateWithTableAndSet(
647    const std::string& shill_property_name,
648    const StringTranslationEntry table[],
649    const std::string& onc_field_name) {
650  std::string shill_value;
651  if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
652                                                        &shill_value)) {
653    return;
654  }
655  std::string onc_value;
656  if (TranslateStringToONC(table, shill_value, &onc_value)) {
657    onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
658    return;
659  }
660  LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
661             << shill_value << " couldn't be translated to ONC: " << GetName();
662}
663
664std::string ShillToONCTranslator::GetName() {
665  DCHECK(shill_dictionary_);
666  std::string name;
667  shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
668  return name;
669}
670
671}  // namespace
672
673scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
674    const base::DictionaryValue& shill_dictionary,
675    ::onc::ONCSource onc_source,
676    const OncValueSignature* onc_signature) {
677  CHECK(onc_signature != NULL);
678
679  ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature);
680  return translator.CreateTranslatedONCObject();
681}
682
683}  // namespace onc
684}  // namespace chromeos
685