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