Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_onc_to_shill.cc
blobf399d8b48f755fdc182de0b14a2199cbf1de537d
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"
13 #include <string>
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/onc/onc_utils.h"
23 #include "chromeos/network/shill_property_util.h"
24 #include "components/onc/onc_constants.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
27 namespace chromeos {
28 namespace onc {
30 namespace {
32 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
33 std::string str;
34 if (!value.GetAsString(&str))
35 base::JSONWriter::Write(value, &str);
36 return make_scoped_ptr(new base::StringValue(str));
39 // This class is responsible to translate the local fields of the given
40 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
41 // translation should consider (if possible) only fields of this ONC object and
42 // not nested objects because recursion is handled by the calling function
43 // TranslateONCHierarchy.
44 class LocalTranslator {
45 public:
46 LocalTranslator(const OncValueSignature& onc_signature,
47 const base::DictionaryValue& onc_object,
48 base::DictionaryValue* shill_dictionary)
49 : onc_signature_(&onc_signature),
50 onc_object_(&onc_object),
51 shill_dictionary_(shill_dictionary) {
52 field_translation_table_ = GetFieldTranslationTable(onc_signature);
55 void TranslateFields();
57 private:
58 void TranslateEthernet();
59 void TranslateOpenVPN();
60 void TranslateIPsec();
61 void TranslateVPN();
62 void TranslateWiFi();
63 void TranslateEAP();
64 void TranslateNetworkConfiguration();
66 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
67 // translation (shill_property_name) is defined by the translation table for
68 // |onc_signature_|.
69 void CopyFieldsAccordingToSignature();
71 // If existent, copies the value of field |onc_field_name| from |onc_object_|
72 // to the property |shill_property_name| in |shill_dictionary_|.
73 void CopyFieldFromONCToShill(const std::string& onc_field_name,
74 const std::string& shill_property_name);
76 // Adds |value| to |shill_dictionary| at the field shill_property_name given
77 // by the associated signature. Takes ownership of |value|. Does nothing if
78 // |value| is NULL or the property name cannot be read from the signature.
79 void AddValueAccordingToSignature(const std::string& onc_field_name,
80 scoped_ptr<base::Value> value);
82 // Translates the value |onc_value| using |table|. It is an error if no
83 // matching table entry is found. Writes the result as entry at
84 // |shill_property_name| in |shill_dictionary_|.
85 void TranslateWithTableAndSet(const std::string& onc_value,
86 const StringTranslationEntry table[],
87 const std::string& shill_property_name);
89 const OncValueSignature* onc_signature_;
90 const FieldTranslationEntry* field_translation_table_;
91 const base::DictionaryValue* onc_object_;
92 base::DictionaryValue* shill_dictionary_;
94 DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
97 void LocalTranslator::TranslateFields() {
98 if (onc_signature_ == &kNetworkConfigurationSignature)
99 TranslateNetworkConfiguration();
100 else if (onc_signature_ == &kEthernetSignature)
101 TranslateEthernet();
102 else if (onc_signature_ == &kVPNSignature)
103 TranslateVPN();
104 else if (onc_signature_ == &kOpenVPNSignature)
105 TranslateOpenVPN();
106 else if (onc_signature_ == &kIPsecSignature)
107 TranslateIPsec();
108 else if (onc_signature_ == &kWiFiSignature)
109 TranslateWiFi();
110 else if (onc_signature_ == &kEAPSignature)
111 TranslateEAP();
112 else
113 CopyFieldsAccordingToSignature();
116 void LocalTranslator::TranslateEthernet() {
117 std::string authentication;
118 onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
119 &authentication);
121 const char* shill_type = shill::kTypeEthernet;
122 if (authentication == ::onc::ethernet::k8021X)
123 shill_type = shill::kTypeEthernetEap;
124 shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
125 shill_type);
127 CopyFieldsAccordingToSignature();
130 void LocalTranslator::TranslateOpenVPN() {
131 // SaveCredentials needs special handling when translating from Shill -> ONC
132 // so handle it explicitly here.
133 CopyFieldFromONCToShill(::onc::vpn::kSaveCredentials,
134 shill::kSaveCredentialsProperty);
136 std::string user_auth_type;
137 onc_object_->GetStringWithoutPathExpansion(
138 ::onc::openvpn::kUserAuthenticationType, &user_auth_type);
139 // The default behavior (if user_auth_type is empty) is to use both password
140 // and OTP in a static challenge and only the password otherwise. As long as
141 // Shill doe not know about the exact user authentication type, this is
142 // identical to kPasswordAndOTP.
143 if (user_auth_type.empty())
144 user_auth_type = ::onc::openvpn_user_auth_type::kPasswordAndOTP;
146 if (user_auth_type == ::onc::openvpn_user_auth_type::kPassword ||
147 user_auth_type == ::onc::openvpn_user_auth_type::kPasswordAndOTP) {
148 CopyFieldFromONCToShill(::onc::openvpn::kPassword,
149 shill::kOpenVPNPasswordProperty);
151 if (user_auth_type == ::onc::openvpn_user_auth_type::kPasswordAndOTP)
152 CopyFieldFromONCToShill(::onc::openvpn::kOTP, shill::kOpenVPNOTPProperty);
153 if (user_auth_type == ::onc::openvpn_user_auth_type::kOTP)
154 CopyFieldFromONCToShill(::onc::openvpn::kOTP, shill::kOpenVPNTokenProperty);
156 // Shill supports only one RemoteCertKU but ONC a list.
157 // Copy only the first entry if existing.
158 const base::ListValue* cert_kus = NULL;
159 std::string cert_ku;
160 if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
161 &cert_kus) &&
162 cert_kus->GetString(0, &cert_ku)) {
163 shill_dictionary_->SetStringWithoutPathExpansion(
164 shill::kOpenVPNRemoteCertKUProperty, cert_ku);
167 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
168 it.Advance()) {
169 scoped_ptr<base::Value> translated;
170 if (it.key() == ::onc::openvpn::kRemoteCertKU ||
171 it.key() == ::onc::openvpn::kServerCAPEMs) {
172 translated.reset(it.value().DeepCopy());
173 } else {
174 // Shill wants all Provider/VPN fields to be strings.
175 translated = ConvertValueToString(it.value());
177 AddValueAccordingToSignature(it.key(), translated.Pass());
181 void LocalTranslator::TranslateIPsec() {
182 CopyFieldsAccordingToSignature();
184 // SaveCredentials needs special handling when translating from Shill -> ONC
185 // so handle it explicitly here.
186 CopyFieldFromONCToShill(::onc::vpn::kSaveCredentials,
187 shill::kSaveCredentialsProperty);
190 void LocalTranslator::TranslateVPN() {
191 std::string onc_type;
192 if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType,
193 &onc_type)) {
194 TranslateWithTableAndSet(onc_type, kVPNTypeTable,
195 shill::kProviderTypeProperty);
197 if (onc_type == ::onc::vpn::kThirdPartyVpn) {
198 // For third-party VPNs, |shill::kProviderHostProperty| is used to store the
199 // provider's extension ID.
200 const base::DictionaryValue* onc_third_party_vpn = nullptr;
201 onc_object_->GetDictionaryWithoutPathExpansion(::onc::vpn::kThirdPartyVpn,
202 &onc_third_party_vpn);
203 std::string onc_extension_id;
204 if (onc_third_party_vpn &&
205 onc_third_party_vpn->GetStringWithoutPathExpansion(
206 ::onc::third_party_vpn::kExtensionID, &onc_extension_id)) {
207 shill_dictionary_->SetStringWithoutPathExpansion(
208 shill::kProviderHostProperty, onc_extension_id);
210 } else {
211 CopyFieldFromONCToShill(::onc::vpn::kHost, shill::kProviderHostProperty);
214 CopyFieldsAccordingToSignature();
217 void LocalTranslator::TranslateWiFi() {
218 std::string security;
219 if (onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSecurity,
220 &security)) {
221 TranslateWithTableAndSet(security, kWiFiSecurityTable,
222 shill::kSecurityClassProperty);
225 // We currently only support managed and no adhoc networks.
226 shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
227 shill::kModeManaged);
229 bool allow_gateway_arp_polling;
230 if (onc_object_->GetBooleanWithoutPathExpansion(
231 ::onc::wifi::kAllowGatewayARPPolling, &allow_gateway_arp_polling)) {
232 shill_dictionary_->SetBooleanWithoutPathExpansion(
233 shill::kLinkMonitorDisableProperty, !allow_gateway_arp_polling);
236 CopyFieldsAccordingToSignature();
239 void LocalTranslator::TranslateEAP() {
240 std::string outer;
241 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
242 TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
244 // Translate the inner protocol only for outer tunneling protocols.
245 if (outer == ::onc::eap::kPEAP || outer == ::onc::eap::kEAP_TTLS) {
246 // In ONC the Inner protocol defaults to "Automatic".
247 std::string inner = ::onc::eap::kAutomatic;
248 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
249 // Shill.
250 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kInner, &inner);
251 if (inner != ::onc::eap::kAutomatic) {
252 const StringTranslationEntry* table = outer == ::onc::eap::kPEAP
253 ? kEAP_PEAP_InnerTable
254 : kEAP_TTLS_InnerTable;
255 TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty);
259 CopyFieldsAccordingToSignature();
262 void LocalTranslator::TranslateNetworkConfiguration() {
263 std::string type;
264 onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
265 &type);
267 // Set the type except for Ethernet which is set in TranslateEthernet.
268 if (type != ::onc::network_type::kEthernet)
269 TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty);
271 // Shill doesn't allow setting the name for non-VPN networks.
272 if (type == ::onc::network_type::kVPN)
273 CopyFieldFromONCToShill(::onc::network_config::kName, shill::kNameProperty);
275 std::string ip_address_config_type, name_servers_config_type;
276 onc_object_->GetStringWithoutPathExpansion(
277 ::onc::network_config::kIPAddressConfigType, &ip_address_config_type);
278 onc_object_->GetStringWithoutPathExpansion(
279 ::onc::network_config::kNameServersConfigType, &name_servers_config_type);
280 if ((ip_address_config_type == ::onc::network_config::kIPConfigTypeDHCP) ||
281 (name_servers_config_type == ::onc::network_config::kIPConfigTypeDHCP)) {
282 // If either type is set to DHCP, provide an empty dictionary to ensure
283 // that any unset properties are cleared. Note: if either type is specified,
284 // the other type defaults to DHCP if not specified.
285 shill_dictionary_->SetWithoutPathExpansion(shill::kStaticIPConfigProperty,
286 new base::DictionaryValue);
289 const base::DictionaryValue* proxy_settings = nullptr;
290 if (onc_object_->GetDictionaryWithoutPathExpansion(
291 ::onc::network_config::kProxySettings, &proxy_settings)) {
292 scoped_ptr<base::DictionaryValue> proxy_config =
293 ConvertOncProxySettingsToProxyConfig(*proxy_settings);
294 std::string proxy_config_str;
295 base::JSONWriter::Write(*proxy_config.get(), &proxy_config_str);
296 shill_dictionary_->SetStringWithoutPathExpansion(
297 shill::kProxyConfigProperty, proxy_config_str);
300 CopyFieldsAccordingToSignature();
303 void LocalTranslator::CopyFieldsAccordingToSignature() {
304 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
305 it.Advance()) {
306 AddValueAccordingToSignature(it.key(),
307 make_scoped_ptr(it.value().DeepCopy()));
311 void LocalTranslator::CopyFieldFromONCToShill(
312 const std::string& onc_field_name,
313 const std::string& shill_property_name) {
314 const base::Value* value = NULL;
315 if (!onc_object_->GetWithoutPathExpansion(onc_field_name, &value))
316 return;
318 const OncFieldSignature* field_signature =
319 GetFieldSignature(*onc_signature_, onc_field_name);
320 if (field_signature) {
321 base::Value::Type expected_type =
322 field_signature->value_signature->onc_type;
323 if (value->GetType() != expected_type) {
324 LOG(ERROR) << "Found field " << onc_field_name << " of type "
325 << value->GetType() << " but expected type " << expected_type;
326 return;
328 } else {
329 LOG(ERROR)
330 << "Attempt to translate a field that is not part of the ONC format.";
331 return;
333 shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
334 value->DeepCopy());
337 void LocalTranslator::AddValueAccordingToSignature(
338 const std::string& onc_name,
339 scoped_ptr<base::Value> value) {
340 if (!value || !field_translation_table_)
341 return;
342 std::string shill_property_name;
343 if (!GetShillPropertyName(onc_name, field_translation_table_,
344 &shill_property_name)) {
345 return;
348 shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
349 value.release());
352 void LocalTranslator::TranslateWithTableAndSet(
353 const std::string& onc_value,
354 const StringTranslationEntry table[],
355 const std::string& shill_property_name) {
356 std::string shill_value;
357 if (TranslateStringToShill(table, onc_value, &shill_value)) {
358 shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
359 shill_value);
360 return;
362 // As we previously validate ONC, this case should never occur. If it still
363 // occurs, we should check here. Otherwise the failure will only show up much
364 // later in Shill.
365 LOG(ERROR) << "Value '" << onc_value
366 << "' cannot be translated to Shill property: "
367 << shill_property_name;
370 // Iterates recursively over |onc_object| and its |signature|. At each object
371 // applies the local translation using LocalTranslator::TranslateFields. The
372 // results are written to |shill_dictionary|.
373 void TranslateONCHierarchy(const OncValueSignature& signature,
374 const base::DictionaryValue& onc_object,
375 base::DictionaryValue* shill_dictionary) {
376 base::DictionaryValue* target_shill_dictionary = shill_dictionary;
377 std::vector<std::string> path_to_shill_dictionary =
378 GetPathToNestedShillDictionary(signature);
379 for (std::vector<std::string>::const_iterator it =
380 path_to_shill_dictionary.begin();
381 it != path_to_shill_dictionary.end(); ++it) {
382 base::DictionaryValue* nested_shill_dict = NULL;
383 target_shill_dictionary->GetDictionaryWithoutPathExpansion(
384 *it, &nested_shill_dict);
385 if (!nested_shill_dict) {
386 nested_shill_dict = new base::DictionaryValue;
387 target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict);
389 target_shill_dictionary = nested_shill_dict;
391 // Translates fields of |onc_object| and writes them to
392 // |target_shill_dictionary_| nested in |shill_dictionary|.
393 LocalTranslator translator(signature, onc_object, target_shill_dictionary);
394 translator.TranslateFields();
396 // Recurse into nested objects.
397 for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
398 it.Advance()) {
399 const base::DictionaryValue* inner_object = NULL;
400 if (!it.value().GetAsDictionary(&inner_object))
401 continue;
403 const OncFieldSignature* field_signature =
404 GetFieldSignature(signature, it.key());
406 TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
407 shill_dictionary);
411 } // namespace
413 scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
414 const OncValueSignature* onc_signature,
415 const base::DictionaryValue& onc_object) {
416 CHECK(onc_signature != NULL);
417 scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
418 TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
419 return shill_dictionary.Pass();
422 } // namespace onc
423 } // namespace chromeos