onc_translator_onc_to_shill.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 25namespace chromeos { 26namespace onc { 27 28namespace { 29 30scoped_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. 42class 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 88void 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 105void 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 119void 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 146void 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 154void 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 170void 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 193void 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 214void 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 222void 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 237void 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|. 258void 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 298scoped_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