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.
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
11 #include "chromeos/network/onc/onc_translator.h"
15 #include "base/json/json_reader.h"
16 #include "base/json/json_writer.h"
17 #include "base/logging.h"
18 #include "base/strings/string_util.h"
19 #include "base/values.h"
20 #include "chromeos/network/onc/onc_signature.h"
21 #include "chromeos/network/onc/onc_translation_tables.h"
22 #include "chromeos/network/shill_property_util.h"
23 #include "components/onc/onc_constants.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
31 bool ConvertListValueToStringVector(const base::ListValue& string_list,
32 std::vector<std::string>* result) {
33 for (size_t i = 0; i < string_list.GetSize(); ++i) {
35 if (!string_list.GetString(i, &str))
37 result->push_back(str);
42 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
44 if (!value.GetAsString(&str))
45 base::JSONWriter::Write(&value, &str);
46 return make_scoped_ptr(new base::StringValue(str));
49 // This class is responsible to translate the local fields of the given
50 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
51 // translation should consider (if possible) only fields of this ONC object and
52 // not nested objects because recursion is handled by the calling function
53 // TranslateONCHierarchy.
54 class LocalTranslator {
56 LocalTranslator(const OncValueSignature& onc_signature,
57 const base::DictionaryValue& onc_object,
58 base::DictionaryValue* shill_dictionary)
59 : onc_signature_(&onc_signature),
60 onc_object_(&onc_object),
61 shill_dictionary_(shill_dictionary) {
62 field_translation_table_ = GetFieldTranslationTable(onc_signature);
65 void TranslateFields();
68 void TranslateEthernet();
69 void TranslateOpenVPN();
70 void TranslateIPsec();
74 void TranslateStaticIPConfig();
75 void TranslateNetworkConfiguration();
77 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
78 // translation (shill_property_name) is defined by |onc_signature_|.
79 void CopyFieldsAccordingToSignature();
81 // Adds |value| to |shill_dictionary| at the field shill_property_name given
82 // by the associated signature. Takes ownership of |value|. Does nothing if
83 // |value| is NULL or the property name cannot be read from the signature.
84 void AddValueAccordingToSignature(const std::string& onc_field_name,
85 scoped_ptr<base::Value> value);
87 // If existent, translates the entry at |onc_field_name| in |onc_object_|
88 // using |table|. It is an error if no matching table entry is found. Writes
89 // the result as entry at |shill_property_name| in |shill_dictionary_|.
90 void TranslateWithTableAndSet(const std::string& onc_field_name,
91 const StringTranslationEntry table[],
92 const std::string& shill_property_name);
94 const OncValueSignature* onc_signature_;
95 const FieldTranslationEntry* field_translation_table_;
96 const base::DictionaryValue* onc_object_;
97 base::DictionaryValue* shill_dictionary_;
99 DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
102 void LocalTranslator::TranslateFields() {
103 if (onc_signature_ == &kNetworkConfigurationSignature)
104 TranslateNetworkConfiguration();
105 else if (onc_signature_ == &kStaticIPConfigSignature)
106 TranslateStaticIPConfig();
107 else if (onc_signature_ == &kEthernetSignature)
109 else if (onc_signature_ == &kVPNSignature)
111 else if (onc_signature_ == &kOpenVPNSignature)
113 else if (onc_signature_ == &kIPsecSignature)
115 else if (onc_signature_ == &kWiFiSignature)
117 else if (onc_signature_ == &kEAPSignature)
120 CopyFieldsAccordingToSignature();
123 void LocalTranslator::TranslateEthernet() {
124 std::string authentication;
125 onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
128 const char* shill_type = shill::kTypeEthernet;
129 if (authentication == ::onc::ethernet::k8021X)
130 shill_type = shill::kTypeEthernetEap;
131 shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
134 CopyFieldsAccordingToSignature();
138 void LocalTranslator::TranslateStaticIPConfig() {
139 const base::ListValue* onc_nameservers = NULL;
140 if (onc_object_->GetListWithoutPathExpansion(::onc::ipconfig::kNameServers,
142 std::vector<std::string> onc_nameservers_vector;
143 ConvertListValueToStringVector(*onc_nameservers, &onc_nameservers_vector);
144 std::string shill_nameservers = JoinString(onc_nameservers_vector, ',');
145 shill_dictionary_->SetStringWithoutPathExpansion(
146 shill::kStaticIPNameServersProperty, shill_nameservers);
149 CopyFieldsAccordingToSignature();
152 void LocalTranslator::TranslateOpenVPN() {
153 // SaveCredentials needs special handling when translating from Shill -> ONC
154 // so handle it explicitly here.
155 bool save_credentials;
156 if (onc_object_->GetBooleanWithoutPathExpansion(
157 ::onc::vpn::kSaveCredentials, &save_credentials)) {
158 shill_dictionary_->SetBooleanWithoutPathExpansion(
159 shill::kSaveCredentialsProperty, save_credentials);
161 // Shill supports only one RemoteCertKU but ONC a list.
162 // Copy only the first entry if existing.
163 const base::ListValue* certKUs = NULL;
165 if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
167 certKUs->GetString(0, &certKU)) {
168 shill_dictionary_->SetStringWithoutPathExpansion(
169 shill::kOpenVPNRemoteCertKUProperty, certKU);
172 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
174 scoped_ptr<base::Value> translated;
175 if (it.key() == ::onc::openvpn::kRemoteCertKU ||
176 it.key() == ::onc::openvpn::kServerCAPEMs) {
177 translated.reset(it.value().DeepCopy());
179 // Shill wants all Provider/VPN fields to be strings.
180 translated = ConvertValueToString(it.value());
182 AddValueAccordingToSignature(it.key(), translated.Pass());
186 void LocalTranslator::TranslateIPsec() {
187 CopyFieldsAccordingToSignature();
189 // SaveCredentials needs special handling when translating from Shill -> ONC
190 // so handle it explicitly here.
191 bool save_credentials;
192 if (onc_object_->GetBooleanWithoutPathExpansion(
193 ::onc::vpn::kSaveCredentials, &save_credentials)) {
194 shill_dictionary_->SetBooleanWithoutPathExpansion(
195 shill::kSaveCredentialsProperty, save_credentials);
199 void LocalTranslator::TranslateVPN() {
201 if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kHost, &host)) {
202 shill_dictionary_->SetStringWithoutPathExpansion(
203 shill::kProviderHostProperty, host);
206 onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
207 TranslateWithTableAndSet(type, kVPNTypeTable, shill::kProviderTypeProperty);
209 CopyFieldsAccordingToSignature();
212 void LocalTranslator::TranslateWiFi() {
213 std::string security;
214 onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSecurity, &security);
215 TranslateWithTableAndSet(security, kWiFiSecurityTable,
216 shill::kSecurityProperty);
219 onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid);
220 shill_property_util::SetSSID(ssid, shill_dictionary_);
222 // We currently only support managed and no adhoc networks.
223 shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
224 shill::kModeManaged);
225 CopyFieldsAccordingToSignature();
228 void LocalTranslator::TranslateEAP() {
230 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
231 TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
233 // Translate the inner protocol only for outer tunneling protocols.
234 if (outer == ::onc::eap::kPEAP || outer == ::onc::eap::kEAP_TTLS) {
235 // In ONC the Inner protocol defaults to "Automatic".
236 std::string inner = ::onc::eap::kAutomatic;
237 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
239 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kInner, &inner);
240 if (inner != ::onc::eap::kAutomatic) {
241 const StringTranslationEntry* table =
242 outer == ::onc::eap::kPEAP ? kEAP_PEAP_InnerTable :
243 kEAP_TTLS_InnerTable;
244 TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty);
248 CopyFieldsAccordingToSignature();
251 void LocalTranslator::TranslateNetworkConfiguration() {
253 onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
256 // Set the type except for Ethernet which is set in TranslateEthernet.
257 if (type != ::onc::network_type::kEthernet)
258 TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty);
260 // Shill doesn't allow setting the name for non-VPN networks.
261 if (type == ::onc::network_type::kVPN) {
263 onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kName,
265 shill_dictionary_->SetStringWithoutPathExpansion(shill::kNameProperty,
269 CopyFieldsAccordingToSignature();
272 void LocalTranslator::CopyFieldsAccordingToSignature() {
273 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
275 AddValueAccordingToSignature(it.key(),
276 make_scoped_ptr(it.value().DeepCopy()));
280 void LocalTranslator::AddValueAccordingToSignature(
281 const std::string& onc_name,
282 scoped_ptr<base::Value> value) {
283 if (!value || !field_translation_table_)
285 std::string shill_property_name;
286 if (!GetShillPropertyName(onc_name,
287 field_translation_table_,
288 &shill_property_name))
291 shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
295 void LocalTranslator::TranslateWithTableAndSet(
296 const std::string& onc_value,
297 const StringTranslationEntry table[],
298 const std::string& shill_property_name) {
299 std::string shill_value;
300 if (TranslateStringToShill(table, onc_value, &shill_value)) {
301 shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
305 // As we previously validate ONC, this case should never occur. If it still
306 // occurs, we should check here. Otherwise the failure will only show up much
308 LOG(ERROR) << "Value '" << onc_value
309 << "' cannot be translated to Shill property "
310 << shill_property_name;
313 // Iterates recursively over |onc_object| and its |signature|. At each object
314 // applies the local translation using LocalTranslator::TranslateFields. The
315 // results are written to |shill_dictionary|.
316 void TranslateONCHierarchy(const OncValueSignature& signature,
317 const base::DictionaryValue& onc_object,
318 base::DictionaryValue* shill_dictionary) {
319 base::DictionaryValue* target_shill_dictionary = shill_dictionary;
320 std::vector<std::string> path_to_shill_dictionary =
321 GetPathToNestedShillDictionary(signature);
322 for (std::vector<std::string>::const_iterator it =
323 path_to_shill_dictionary.begin();
324 it != path_to_shill_dictionary.end();
326 base::DictionaryValue* nested_shill_dict = NULL;
327 target_shill_dictionary->GetDictionaryWithoutPathExpansion(
328 *it, &nested_shill_dict);
329 if (!nested_shill_dict)
330 nested_shill_dict = new base::DictionaryValue;
331 target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict);
332 target_shill_dictionary = nested_shill_dict;
334 // Translates fields of |onc_object| and writes them to
335 // |target_shill_dictionary_| nested in |shill_dictionary|.
336 LocalTranslator translator(signature, onc_object, target_shill_dictionary);
337 translator.TranslateFields();
339 // Recurse into nested objects.
340 for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
342 const base::DictionaryValue* inner_object = NULL;
343 if (!it.value().GetAsDictionary(&inner_object))
346 const OncFieldSignature* field_signature =
347 GetFieldSignature(signature, it.key());
349 TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
356 scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
357 const OncValueSignature* onc_signature,
358 const base::DictionaryValue& onc_object) {
359 CHECK(onc_signature != NULL);
360 scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
361 TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
362 return shill_dictionary.Pass();
366 } // namespace chromeos