onc_translator_onc_to_shill.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 = shill::kTypeEthernet; 110 if (authentication == ethernet::k8021X) 111 shill_type = shill::kTypeEthernetEap; 112 shill_dictionary_->SetStringWithoutPathExpansion(shill::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 shill::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, shill::kProviderTypeProperty); 149 150 CopyFieldsAccordingToSignature(); 151} 152 153void LocalTranslator::TranslateWiFi() { 154 std::string security; 155 onc_object_->GetStringWithoutPathExpansion(wifi::kSecurity, &security); 156 TranslateWithTableAndSet(security, kWiFiSecurityTable, 157 shill::kSecurityProperty); 158 159 // We currently only support managed and no adhoc networks. 160 shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty, 161 shill::kModeManaged); 162 CopyFieldsAccordingToSignature(); 163} 164 165void LocalTranslator::TranslateEAP() { 166 std::string outer; 167 onc_object_->GetStringWithoutPathExpansion(eap::kOuter, &outer); 168 TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty); 169 170 // Translate the inner protocol only for outer tunneling protocols. 171 if (outer == eap::kPEAP || outer == eap::kEAP_TTLS) { 172 // In ONC the Inner protocol defaults to "Automatic". 173 std::string inner = eap::kAutomatic; 174 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in 175 // Shill. 176 onc_object_->GetStringWithoutPathExpansion(eap::kInner, &inner); 177 if (inner != eap::kAutomatic) { 178 const StringTranslationEntry* table = 179 outer == eap::kPEAP ? kEAP_PEAP_InnerTable : kEAP_TTLS_InnerTable; 180 TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty); 181 } 182 } 183 184 CopyFieldsAccordingToSignature(); 185} 186 187void LocalTranslator::TranslateNetworkConfiguration() { 188 std::string type; 189 onc_object_->GetStringWithoutPathExpansion(network_config::kType, &type); 190 191 // Set the type except for Ethernet which is set in TranslateEthernet. 192 if (type != network_type::kEthernet) 193 TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty); 194 195 // Shill doesn't allow setting the name for non-VPN networks. 196 if (type == network_type::kVPN) { 197 std::string name; 198 onc_object_->GetStringWithoutPathExpansion(network_config::kName, &name); 199 shill_dictionary_->SetStringWithoutPathExpansion(shill::kNameProperty, 200 name); 201 } 202 203 CopyFieldsAccordingToSignature(); 204} 205 206void LocalTranslator::CopyFieldsAccordingToSignature() { 207 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd(); 208 it.Advance()) { 209 AddValueAccordingToSignature(it.key(), 210 make_scoped_ptr(it.value().DeepCopy())); 211 } 212} 213 214void LocalTranslator::AddValueAccordingToSignature( 215 const std::string& onc_name, 216 scoped_ptr<base::Value> value) { 217 if (!value || !field_translation_table_) 218 return; 219 std::string shill_property_name; 220 if (!GetShillPropertyName(onc_name, 221 field_translation_table_, 222 &shill_property_name)) 223 return; 224 225 shill_dictionary_->SetWithoutPathExpansion(shill_property_name, 226 value.release()); 227} 228 229void LocalTranslator::TranslateWithTableAndSet( 230 const std::string& onc_value, 231 const StringTranslationEntry table[], 232 const std::string& shill_property_name) { 233 std::string shill_value; 234 if (TranslateStringToShill(table, onc_value, &shill_value)) { 235 shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name, 236 shill_value); 237 return; 238 } 239 // As we previously validate ONC, this case should never occur. If it still 240 // occurs, we should check here. Otherwise the failure will only show up much 241 // later in Shill. 242 LOG(ERROR) << "Value '" << onc_value 243 << "' cannot be translated to Shill property " 244 << shill_property_name; 245} 246 247// Iterates recursively over |onc_object| and its |signature|. At each object 248// applies the local translation using LocalTranslator::TranslateFields. The 249// results are written to |shill_dictionary|. 250void TranslateONCHierarchy(const OncValueSignature& signature, 251 const base::DictionaryValue& onc_object, 252 base::DictionaryValue* shill_dictionary) { 253 base::DictionaryValue* target_shill_dictionary = shill_dictionary; 254 std::vector<std::string> path_to_shill_dictionary = 255 GetPathToNestedShillDictionary(signature); 256 for (std::vector<std::string>::const_iterator it = 257 path_to_shill_dictionary.begin(); 258 it != path_to_shill_dictionary.end(); 259 ++it) { 260 base::DictionaryValue* nested_shill_dict = NULL; 261 target_shill_dictionary->GetDictionaryWithoutPathExpansion( 262 *it, &nested_shill_dict); 263 if (!nested_shill_dict) 264 nested_shill_dict = new base::DictionaryValue; 265 target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict); 266 target_shill_dictionary = nested_shill_dict; 267 } 268 // Translates fields of |onc_object| and writes them to 269 // |target_shill_dictionary_| nested in |shill_dictionary|. 270 LocalTranslator translator(signature, onc_object, target_shill_dictionary); 271 translator.TranslateFields(); 272 273 // Recurse into nested objects. 274 for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd(); 275 it.Advance()) { 276 const base::DictionaryValue* inner_object = NULL; 277 if (!it.value().GetAsDictionary(&inner_object)) 278 continue; 279 280 const OncFieldSignature* field_signature = 281 GetFieldSignature(signature, it.key()); 282 283 TranslateONCHierarchy(*field_signature->value_signature, *inner_object, 284 shill_dictionary); 285 } 286} 287 288} // namespace 289 290scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill( 291 const OncValueSignature* onc_signature, 292 const base::DictionaryValue& onc_object) { 293 CHECK(onc_signature != NULL); 294 scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue); 295 TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get()); 296 return shill_dictionary.Pass(); 297} 298 299} // namespace onc 300} // namespace chromeos 301