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