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