onc_translator_shill_to_onc.cc revision 3551c9c881056c480085172ff9840cab31610854
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#include "chromeos/network/onc/onc_translator.h" 6 7#include <string> 8 9#include "base/basictypes.h" 10#include "base/json/json_reader.h" 11#include "base/json/json_writer.h" 12#include "base/logging.h" 13#include "base/values.h" 14#include "chromeos/network/network_state.h" 15#include "chromeos/network/onc/onc_constants.h" 16#include "chromeos/network/onc/onc_signature.h" 17#include "chromeos/network/onc/onc_translation_tables.h" 18#include "third_party/cros_system_api/dbus/service_constants.h" 19 20namespace chromeos { 21namespace onc { 22 23namespace { 24 25// Converts |str| to a base::Value of the given |type|. If the conversion fails, 26// returns NULL. 27scoped_ptr<base::Value> ConvertStringToValue(const std::string& str, 28 base::Value::Type type) { 29 base::Value* value; 30 if (type == base::Value::TYPE_STRING) { 31 value = base::Value::CreateStringValue(str); 32 } else { 33 value = base::JSONReader::Read(str); 34 } 35 36 if (value == NULL || value->GetType() != type) { 37 delete value; 38 value = NULL; 39 } 40 return make_scoped_ptr(value); 41} 42 43// This class implements the translation of properties from the given 44// |shill_dictionary| to a new ONC object of signature |onc_signature|. Using 45// recursive calls to CreateTranslatedONCObject of new instances, nested objects 46// are translated. 47class ShillToONCTranslator { 48 public: 49 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary, 50 const OncValueSignature& onc_signature) 51 : shill_dictionary_(&shill_dictionary), 52 onc_signature_(&onc_signature) { 53 field_translation_table_ = GetFieldTranslationTable(onc_signature); 54 } 55 56 // Translates the associated Shill dictionary and creates an ONC object of the 57 // given signature. 58 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject(); 59 60 private: 61 void TranslateOpenVPN(); 62 void TranslateVPN(); 63 void TranslateWiFiWithState(); 64 void TranslateCellularWithState(); 65 void TranslateNetworkWithState(); 66 67 // Creates an ONC object from |dictionary| according to the signature 68 // associated to |onc_field_name| and adds it to |onc_object_| at 69 // |onc_field_name|. 70 void TranslateAndAddNestedObject(const std::string& onc_field_name, 71 const base::DictionaryValue& dictionary); 72 73 // Creates an ONC object from |shill_dictionary_| according to the signature 74 // associated to |onc_field_name| and adds it to |onc_object_| at 75 // |onc_field_name|. 76 void TranslateAndAddNestedObject(const std::string& onc_field_name); 77 78 // Applies function CopyProperty to each field of |value_signature| and its 79 // base signatures. 80 void CopyPropertiesAccordingToSignature( 81 const OncValueSignature* value_signature); 82 83 // Applies function CopyProperty to each field of |onc_signature_| and its 84 // base signatures. 85 void CopyPropertiesAccordingToSignature(); 86 87 // If |shill_property_name| is defined in |field_signature|, copies this 88 // entry from |shill_dictionary_| to |onc_object_| if it exists. 89 void CopyProperty(const OncFieldSignature* field_signature); 90 91 // If existent, translates the entry at |shill_property_name| in 92 // |shill_dictionary_| using |table|. It is an error if no matching table 93 // entry is found. Writes the result as entry at |onc_field_name| in 94 // |onc_object_|. 95 void TranslateWithTableAndSet(const std::string& shill_property_name, 96 const StringTranslationEntry table[], 97 const std::string& onc_field_name); 98 99 const base::DictionaryValue* shill_dictionary_; 100 const OncValueSignature* onc_signature_; 101 const FieldTranslationEntry* field_translation_table_; 102 scoped_ptr<base::DictionaryValue> onc_object_; 103 104 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator); 105}; 106 107scoped_ptr<base::DictionaryValue> 108ShillToONCTranslator::CreateTranslatedONCObject() { 109 onc_object_.reset(new base::DictionaryValue); 110 if (onc_signature_ == &kNetworkWithStateSignature) { 111 TranslateNetworkWithState(); 112 } else if (onc_signature_ == &kVPNSignature) { 113 TranslateVPN(); 114 } else if (onc_signature_ == &kOpenVPNSignature) { 115 TranslateOpenVPN(); 116 } else if (onc_signature_ == &kWiFiWithStateSignature) { 117 TranslateWiFiWithState(); 118 } else if (onc_signature_ == &kCellularWithStateSignature) { 119 TranslateCellularWithState(); 120 } else { 121 CopyPropertiesAccordingToSignature(); 122 } 123 return onc_object_.Pass(); 124} 125 126void ShillToONCTranslator::TranslateOpenVPN() { 127 // Shill supports only one RemoteCertKU but ONC requires a list. If existing, 128 // wraps the value into a list. 129 std::string certKU; 130 if (shill_dictionary_->GetStringWithoutPathExpansion( 131 flimflam::kOpenVPNRemoteCertKUProperty, &certKU)) { 132 scoped_ptr<base::ListValue> certKUs(new base::ListValue); 133 certKUs->AppendString(certKU); 134 onc_object_->SetWithoutPathExpansion(openvpn::kRemoteCertKU, 135 certKUs.release()); 136 } 137 138 for (const OncFieldSignature* field_signature = onc_signature_->fields; 139 field_signature->onc_field_name != NULL; ++field_signature) { 140 const std::string& onc_field_name = field_signature->onc_field_name; 141 if (onc_field_name == vpn::kSaveCredentials || 142 onc_field_name == openvpn::kRemoteCertKU || 143 onc_field_name == openvpn::kServerCAPEMs) { 144 CopyProperty(field_signature); 145 continue; 146 } 147 148 std::string shill_property_name; 149 const base::Value* shill_value = NULL; 150 if (!field_translation_table_ || 151 !GetShillPropertyName(field_signature->onc_field_name, 152 field_translation_table_, 153 &shill_property_name) || 154 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name, 155 &shill_value)) { 156 continue; 157 } 158 159 scoped_ptr<base::Value> translated; 160 std::string shill_str; 161 if (shill_value->GetAsString(&shill_str)) { 162 // Shill wants all Provider/VPN fields to be strings. Translates these 163 // strings back to the correct ONC type. 164 translated = ConvertStringToValue( 165 shill_str, 166 field_signature->value_signature->onc_type); 167 168 if (translated.get() == NULL) { 169 LOG(ERROR) << "Shill property '" << shill_property_name 170 << "' with value " << *shill_value 171 << " couldn't be converted to base::Value::Type " 172 << field_signature->value_signature->onc_type; 173 } else { 174 onc_object_->SetWithoutPathExpansion(onc_field_name, 175 translated.release()); 176 } 177 } else { 178 LOG(ERROR) << "Shill property '" << shill_property_name 179 << "' has value " << *shill_value 180 << ", but expected a string"; 181 } 182 } 183} 184 185void ShillToONCTranslator::TranslateVPN() { 186 TranslateWithTableAndSet(flimflam::kProviderTypeProperty, kVPNTypeTable, 187 vpn::kType); 188 CopyPropertiesAccordingToSignature(); 189 190 std::string vpn_type; 191 if (onc_object_->GetStringWithoutPathExpansion(vpn::kType, 192 &vpn_type)) { 193 if (vpn_type == vpn::kTypeL2TP_IPsec) { 194 TranslateAndAddNestedObject(vpn::kIPsec); 195 TranslateAndAddNestedObject(vpn::kL2TP); 196 } else { 197 TranslateAndAddNestedObject(vpn_type); 198 } 199 } 200} 201 202void ShillToONCTranslator::TranslateWiFiWithState() { 203 TranslateWithTableAndSet(flimflam::kSecurityProperty, kWiFiSecurityTable, 204 wifi::kSecurity); 205 CopyPropertiesAccordingToSignature(); 206} 207 208void ShillToONCTranslator::TranslateCellularWithState() { 209 CopyPropertiesAccordingToSignature(); 210 const base::DictionaryValue* serving_operator = NULL; 211 if (shill_dictionary_->GetDictionaryWithoutPathExpansion( 212 flimflam::kServingOperatorProperty, &serving_operator)) { 213 TranslateAndAddNestedObject(cellular::kServingOperator, *serving_operator); 214 } 215} 216 217void ShillToONCTranslator::TranslateNetworkWithState() { 218 TranslateWithTableAndSet(flimflam::kTypeProperty, kNetworkTypeTable, 219 network_config::kType); 220 CopyPropertiesAccordingToSignature(); 221 222 std::string network_type; 223 if (onc_object_->GetStringWithoutPathExpansion(network_config::kType, 224 &network_type)) { 225 TranslateAndAddNestedObject(network_type); 226 } 227 228 // Since Name is a read only field in Shill unless it's a VPN, it is copied 229 // here, but not when going the other direction (if it's not a VPN). 230 std::string name; 231 shill_dictionary_->GetStringWithoutPathExpansion(flimflam::kNameProperty, 232 &name); 233 onc_object_->SetStringWithoutPathExpansion(network_config::kName, name); 234 235 std::string state; 236 if (shill_dictionary_->GetStringWithoutPathExpansion(flimflam::kStateProperty, 237 &state)) { 238 std::string onc_state = connection_state::kNotConnected; 239 if (NetworkState::StateIsConnected(state)) { 240 onc_state = connection_state::kConnected; 241 } else if (NetworkState::StateIsConnecting(state)) { 242 onc_state = connection_state::kConnecting; 243 } 244 onc_object_->SetStringWithoutPathExpansion(network_config::kConnectionState, 245 onc_state); 246 } 247} 248 249void ShillToONCTranslator::TranslateAndAddNestedObject( 250 const std::string& onc_field_name) { 251 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_); 252} 253 254void ShillToONCTranslator::TranslateAndAddNestedObject( 255 const std::string& onc_field_name, 256 const base::DictionaryValue& dictionary) { 257 const OncFieldSignature* field_signature = 258 GetFieldSignature(*onc_signature_, onc_field_name); 259 ShillToONCTranslator nested_translator(dictionary, 260 *field_signature->value_signature); 261 scoped_ptr<base::DictionaryValue> nested_object = 262 nested_translator.CreateTranslatedONCObject(); 263 if (nested_object->empty()) 264 return; 265 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release()); 266} 267 268void ShillToONCTranslator::CopyPropertiesAccordingToSignature() { 269 CopyPropertiesAccordingToSignature(onc_signature_); 270} 271 272void ShillToONCTranslator::CopyPropertiesAccordingToSignature( 273 const OncValueSignature* value_signature) { 274 if (value_signature->base_signature) 275 CopyPropertiesAccordingToSignature(value_signature->base_signature); 276 for (const OncFieldSignature* field_signature = value_signature->fields; 277 field_signature->onc_field_name != NULL; ++field_signature) { 278 CopyProperty(field_signature); 279 } 280} 281 282void ShillToONCTranslator::CopyProperty( 283 const OncFieldSignature* field_signature) { 284 std::string shill_property_name; 285 const base::Value* shill_value = NULL; 286 if (!field_translation_table_ || 287 !GetShillPropertyName(field_signature->onc_field_name, 288 field_translation_table_, 289 &shill_property_name) || 290 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name, 291 &shill_value)) { 292 return; 293 } 294 295 if (shill_value->GetType() != field_signature->value_signature->onc_type) { 296 LOG(ERROR) << "Shill property '" << shill_property_name 297 << "' with value " << *shill_value 298 << " has base::Value::Type " << shill_value->GetType() 299 << " but ONC field '" << field_signature->onc_field_name 300 << "' requires type " 301 << field_signature->value_signature->onc_type << "."; 302 return; 303 } 304 305 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name, 306 shill_value->DeepCopy()); 307} 308 309void ShillToONCTranslator::TranslateWithTableAndSet( 310 const std::string& shill_property_name, 311 const StringTranslationEntry table[], 312 const std::string& onc_field_name) { 313 std::string shill_value; 314 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name, 315 &shill_value)) { 316 return; 317 } 318 std::string onc_value; 319 if (TranslateStringToONC(table, shill_value, &onc_value)) { 320 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value); 321 return; 322 } 323 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value " 324 << shill_value << " couldn't be translated to ONC"; 325} 326 327} // namespace 328 329scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart( 330 const base::DictionaryValue& shill_dictionary, 331 const OncValueSignature* onc_signature) { 332 CHECK(onc_signature != NULL); 333 334 ShillToONCTranslator translator(shill_dictionary, *onc_signature); 335 return translator.CreateTranslatedONCObject(); 336} 337 338} // namespace onc 339} // namespace chromeos 340