onc_translator_onc_to_shill.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 TranslateOpenVPN(); 56 void TranslateVPN(); 57 void TranslateWiFi(); 58 void TranslateEAP(); 59 void TranslateNetworkConfiguration(); 60 61 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a 62 // translation (shill_property_name) is defined by |onc_signature_|. 63 void CopyFieldsAccordingToSignature(); 64 65 // Adds |value| to |shill_dictionary| at the field shill_property_name given 66 // by the associated signature. Takes ownership of |value|. Does nothing if 67 // |value| is NULL or the property name cannot be read from the signature. 68 void AddValueAccordingToSignature(const std::string& onc_field_name, 69 scoped_ptr<base::Value> value); 70 71 // If existent, translates the entry at |onc_field_name| in |onc_object_| 72 // using |table|. It is an error if no matching table entry is found. Writes 73 // the result as entry at |shill_property_name| in |shill_dictionary_|. 74 void TranslateWithTableAndSet(const std::string& onc_field_name, 75 const StringTranslationEntry table[], 76 const std::string& shill_property_name); 77 78 const OncValueSignature* onc_signature_; 79 const FieldTranslationEntry* field_translation_table_; 80 const base::DictionaryValue* onc_object_; 81 base::DictionaryValue* shill_dictionary_; 82 83 DISALLOW_COPY_AND_ASSIGN(LocalTranslator); 84}; 85 86void LocalTranslator::TranslateFields() { 87 if (onc_signature_ == &kNetworkConfigurationSignature) 88 TranslateNetworkConfiguration(); 89 else if (onc_signature_ == &kVPNSignature) 90 TranslateVPN(); 91 else if (onc_signature_ == &kOpenVPNSignature) 92 TranslateOpenVPN(); 93 else if (onc_signature_ == &kWiFiSignature) 94 TranslateWiFi(); 95 else if (onc_signature_ == &kEAPSignature) 96 TranslateEAP(); 97 else 98 CopyFieldsAccordingToSignature(); 99} 100 101void LocalTranslator::TranslateOpenVPN() { 102 // Shill supports only one RemoteCertKU but ONC a list. 103 // Copy only the first entry if existing. 104 const base::ListValue* certKUs = NULL; 105 std::string certKU; 106 if (onc_object_->GetListWithoutPathExpansion(vpn::kRemoteCertKU, &certKUs) && 107 certKUs->GetString(0, &certKU)) { 108 shill_dictionary_->SetStringWithoutPathExpansion( 109 flimflam::kOpenVPNRemoteCertKUProperty, certKU); 110 } 111 112 for (base::DictionaryValue::Iterator it(*onc_object_); it.HasNext(); 113 it.Advance()) { 114 scoped_ptr<base::Value> translated; 115 if (it.key() == vpn::kSaveCredentials || it.key() == vpn::kRemoteCertKU) { 116 translated.reset(it.value().DeepCopy()); 117 } else { 118 // Shill wants all Provider/VPN fields to be strings. 119 translated = ConvertValueToString(it.value()); 120 } 121 AddValueAccordingToSignature(it.key(), translated.Pass()); 122 } 123} 124 125void LocalTranslator::TranslateVPN() { 126 std::string type; 127 onc_object_->GetStringWithoutPathExpansion(vpn::kType, &type); 128 TranslateWithTableAndSet(type, kVPNTypeTable, 129 flimflam::kProviderTypeProperty); 130 131 CopyFieldsAccordingToSignature(); 132} 133 134void LocalTranslator::TranslateWiFi() { 135 std::string security; 136 onc_object_->GetStringWithoutPathExpansion(wifi::kSecurity, &security); 137 TranslateWithTableAndSet(security, kWiFiSecurityTable, 138 flimflam::kSecurityProperty); 139 140 // We currently only support managed and no adhoc networks. 141 shill_dictionary_->SetStringWithoutPathExpansion(flimflam::kModeProperty, 142 flimflam::kModeManaged); 143 CopyFieldsAccordingToSignature(); 144} 145 146void LocalTranslator::TranslateEAP() { 147 std::string outer; 148 onc_object_->GetStringWithoutPathExpansion(eap::kOuter, &outer); 149 TranslateWithTableAndSet(outer, kEAPOuterTable, flimflam::kEapMethodProperty); 150 151 // Translate the inner protocol only for outer tunneling protocols. 152 if (outer == eap::kPEAP || outer == eap::kEAP_TTLS) { 153 // In ONC the Inner protocol defaults to "Automatic". 154 std::string inner = eap::kAutomatic; 155 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in 156 // Shill. 157 onc_object_->GetStringWithoutPathExpansion(eap::kInner, &inner); 158 if (inner != eap::kAutomatic) { 159 const StringTranslationEntry* table = 160 outer == eap::kPEAP ? kEAP_PEAP_InnerTable : kEAP_TTLS_InnerTable; 161 TranslateWithTableAndSet(inner, table, flimflam::kEapPhase2AuthProperty); 162 } 163 } 164 165 CopyFieldsAccordingToSignature(); 166} 167 168void LocalTranslator::TranslateNetworkConfiguration() { 169 std::string type; 170 onc_object_->GetStringWithoutPathExpansion(network_config::kType, &type); 171 TranslateWithTableAndSet(type, kNetworkTypeTable, flimflam::kTypeProperty); 172 173 // Shill doesn't allow setting the name for non-VPN networks. 174 if (type == network_type::kVPN) { 175 std::string name; 176 onc_object_->GetStringWithoutPathExpansion(network_config::kName, &name); 177 shill_dictionary_->SetStringWithoutPathExpansion( 178 flimflam::kNameProperty, name); 179 } 180 181 CopyFieldsAccordingToSignature(); 182} 183 184void LocalTranslator::CopyFieldsAccordingToSignature() { 185 for (base::DictionaryValue::Iterator it(*onc_object_); it.HasNext(); 186 it.Advance()) { 187 AddValueAccordingToSignature(it.key(), 188 make_scoped_ptr(it.value().DeepCopy())); 189 } 190} 191 192void LocalTranslator::AddValueAccordingToSignature( 193 const std::string& onc_name, 194 scoped_ptr<base::Value> value) { 195 if (!value || !field_translation_table_) 196 return; 197 198 std::string shill_property_name; 199 if (!GetShillPropertyName(onc_name, 200 field_translation_table_, 201 &shill_property_name)) 202 return; 203 204 shill_dictionary_->SetWithoutPathExpansion(shill_property_name, 205 value.release()); 206} 207 208void LocalTranslator::TranslateWithTableAndSet( 209 const std::string& onc_value, 210 const StringTranslationEntry table[], 211 const std::string& shill_property_name) { 212 std::string shill_value; 213 if (TranslateStringToShill(table, onc_value, &shill_value)) { 214 shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name, 215 shill_value); 216 return; 217 } 218 // As we previously validate ONC, this case should never occur. If it still 219 // occurs, we should check here. Otherwise the failure will only show up much 220 // later in Shill. 221 LOG(ERROR) << "Value '" << onc_value 222 << "' cannot be translated to Shill property " 223 << shill_property_name; 224} 225 226// Iterates recursively over |onc_object| and its |signature|. At each object 227// applies the local translation using LocalTranslator::TranslateFields. The 228// results are written to |shill_dictionary|. 229void TranslateONCHierarchy(const OncValueSignature& signature, 230 const base::DictionaryValue& onc_object, 231 base::DictionaryValue* shill_dictionary) { 232 // Translates fields of |onc_object| and writes them to |shill_dictionary_|. 233 LocalTranslator translator(signature, onc_object, shill_dictionary); 234 translator.TranslateFields(); 235 236 // Recurse into nested objects. 237 for (base::DictionaryValue::Iterator it(onc_object); it.HasNext(); 238 it.Advance()) { 239 const base::DictionaryValue* inner_object = NULL; 240 if (!it.value().GetAsDictionary(&inner_object)) 241 continue; 242 243 const OncFieldSignature* field_signature = 244 GetFieldSignature(signature, it.key()); 245 246 TranslateONCHierarchy(*field_signature->value_signature, *inner_object, 247 shill_dictionary); 248 } 249} 250 251} // namespace 252 253scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill( 254 const OncValueSignature* onc_signature, 255 const base::DictionaryValue& onc_object) { 256 CHECK(onc_signature != NULL); 257 scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue); 258 TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get()); 259 return shill_dictionary.Pass(); 260} 261 262} // namespace onc 263} // namespace chromeos 264