ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_onc_to_shill.cc
blobfdd8fbdd8a10aad2b9a3e6c0ee425bfd9e2406ca
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/shill_property_util.h"
23 #include "components/onc/onc_constants.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
26 namespace chromeos {
27 namespace onc {
29 namespace {
31 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
32 std::string str;
33 if (!value.GetAsString(&str))
34 base::JSONWriter::Write(&value, &str);
35 return make_scoped_ptr(new base::StringValue(str));
38 // This class is responsible to translate the local fields of the given
39 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
40 // translation should consider (if possible) only fields of this ONC object and
41 // not nested objects because recursion is handled by the calling function
42 // TranslateONCHierarchy.
43 class LocalTranslator {
44 public:
45 LocalTranslator(const OncValueSignature& onc_signature,
46 const base::DictionaryValue& onc_object,
47 base::DictionaryValue* shill_dictionary)
48 : onc_signature_(&onc_signature),
49 onc_object_(&onc_object),
50 shill_dictionary_(shill_dictionary) {
51 field_translation_table_ = GetFieldTranslationTable(onc_signature);
54 void TranslateFields();
56 private:
57 void TranslateEthernet();
58 void TranslateOpenVPN();
59 void TranslateIPsec();
60 void TranslateVPN();
61 void TranslateWiFi();
62 void TranslateEAP();
63 void TranslateNetworkConfiguration();
65 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
66 // translation (shill_property_name) is defined by the translation table for
67 // |onc_signature_|.
68 void CopyFieldsAccordingToSignature();
70 // If existent, copies the value of field |onc_field_name| from |onc_object_|
71 // to the property |shill_property_name| in |shill_dictionary_|.
72 void CopyFieldFromONCToShill(const std::string& onc_field_name,
73 const std::string& shill_property_name);
75 // Adds |value| to |shill_dictionary| at the field shill_property_name given
76 // by the associated signature. Takes ownership of |value|. Does nothing if
77 // |value| is NULL or the property name cannot be read from the signature.
78 void AddValueAccordingToSignature(const std::string& onc_field_name,
79 scoped_ptr<base::Value> value);
81 // Translates the value |onc_value| using |table|. It is an error if no
82 // matching table entry is found. Writes the result as entry at
83 // |shill_property_name| in |shill_dictionary_|.
84 void TranslateWithTableAndSet(const std::string& onc_value,
85 const StringTranslationEntry table[],
86 const std::string& shill_property_name);
88 const OncValueSignature* onc_signature_;
89 const FieldTranslationEntry* field_translation_table_;
90 const base::DictionaryValue* onc_object_;
91 base::DictionaryValue* shill_dictionary_;
93 DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
96 void LocalTranslator::TranslateFields() {
97 if (onc_signature_ == &kNetworkConfigurationSignature)
98 TranslateNetworkConfiguration();
99 else if (onc_signature_ == &kEthernetSignature)
100 TranslateEthernet();
101 else if (onc_signature_ == &kVPNSignature)
102 TranslateVPN();
103 else if (onc_signature_ == &kOpenVPNSignature)
104 TranslateOpenVPN();
105 else if (onc_signature_ == &kIPsecSignature)
106 TranslateIPsec();
107 else if (onc_signature_ == &kWiFiSignature)
108 TranslateWiFi();
109 else if (onc_signature_ == &kEAPSignature)
110 TranslateEAP();
111 else
112 CopyFieldsAccordingToSignature();
115 void LocalTranslator::TranslateEthernet() {
116 std::string authentication;
117 onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
118 &authentication);
120 const char* shill_type = shill::kTypeEthernet;
121 if (authentication == ::onc::ethernet::k8021X)
122 shill_type = shill::kTypeEthernetEap;
123 shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
124 shill_type);
126 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 CopyFieldFromONCToShill(::onc::vpn::kHost, shill::kProviderHostProperty);
192 std::string type;
193 if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType, &type))
194 TranslateWithTableAndSet(type, kVPNTypeTable, shill::kProviderTypeProperty);
196 CopyFieldsAccordingToSignature();
199 void LocalTranslator::TranslateWiFi() {
200 std::string security;
201 if (onc_object_->GetStringWithoutPathExpansion(
202 ::onc::wifi::kSecurity, &security)) {
203 TranslateWithTableAndSet(security, kWiFiSecurityTable,
204 shill::kSecurityClassProperty);
207 // We currently only support managed and no adhoc networks.
208 shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
209 shill::kModeManaged);
211 bool allow_gateway_arp_polling;
212 if (onc_object_->GetBooleanWithoutPathExpansion(
213 ::onc::wifi::kAllowGatewayARPPolling, &allow_gateway_arp_polling)) {
214 shill_dictionary_->SetBooleanWithoutPathExpansion(
215 shill::kLinkMonitorDisableProperty, !allow_gateway_arp_polling);
218 CopyFieldsAccordingToSignature();
221 void LocalTranslator::TranslateEAP() {
222 std::string outer;
223 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
224 TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
226 // Translate the inner protocol only for outer tunneling protocols.
227 if (outer == ::onc::eap::kPEAP || outer == ::onc::eap::kEAP_TTLS) {
228 // In ONC the Inner protocol defaults to "Automatic".
229 std::string inner = ::onc::eap::kAutomatic;
230 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
231 // Shill.
232 onc_object_->GetStringWithoutPathExpansion(::onc::eap::kInner, &inner);
233 if (inner != ::onc::eap::kAutomatic) {
234 const StringTranslationEntry* table =
235 outer == ::onc::eap::kPEAP ? kEAP_PEAP_InnerTable :
236 kEAP_TTLS_InnerTable;
237 TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty);
241 CopyFieldsAccordingToSignature();
244 void LocalTranslator::TranslateNetworkConfiguration() {
245 std::string type;
246 onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
247 &type);
249 // Set the type except for Ethernet which is set in TranslateEthernet.
250 if (type != ::onc::network_type::kEthernet)
251 TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty);
253 // Shill doesn't allow setting the name for non-VPN networks.
254 if (type == ::onc::network_type::kVPN)
255 CopyFieldFromONCToShill(::onc::network_config::kName, shill::kNameProperty);
257 std::string ip_address_config_type, name_servers_config_type;
258 onc_object_->GetStringWithoutPathExpansion(
259 ::onc::network_config::kIPAddressConfigType, &ip_address_config_type);
260 onc_object_->GetStringWithoutPathExpansion(
261 ::onc::network_config::kNameServersConfigType, &name_servers_config_type);
262 if ((ip_address_config_type == ::onc::network_config::kIPConfigTypeDHCP) ||
263 (name_servers_config_type == ::onc::network_config::kIPConfigTypeDHCP)) {
264 // If either type is set to DHCP, provide an empty dictionary to ensure
265 // that any unset properties are cleared. Note: if either type is specified,
266 // the other type defaults to DHCP if not specified.
267 shill_dictionary_->SetWithoutPathExpansion(shill::kStaticIPConfigProperty,
268 new base::DictionaryValue);
270 CopyFieldsAccordingToSignature();
273 void LocalTranslator::CopyFieldsAccordingToSignature() {
274 for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
275 it.Advance()) {
276 AddValueAccordingToSignature(it.key(),
277 make_scoped_ptr(it.value().DeepCopy()));
281 void LocalTranslator::CopyFieldFromONCToShill(
282 const std::string& onc_field_name,
283 const std::string& shill_property_name) {
284 const base::Value* value = NULL;
285 if (!onc_object_->GetWithoutPathExpansion(onc_field_name, &value))
286 return;
288 const OncFieldSignature* field_signature =
289 GetFieldSignature(*onc_signature_, onc_field_name);
290 if (field_signature) {
291 base::Value::Type expected_type =
292 field_signature->value_signature->onc_type;
293 if (value->GetType() != expected_type) {
294 LOG(ERROR) << "Found field " << onc_field_name << " of type "
295 << value->GetType() << " but expected type " << expected_type;
296 return;
298 } else {
299 LOG(ERROR)
300 << "Attempt to translate a field that is not part of the ONC format.";
301 return;
303 shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
304 value->DeepCopy());
307 void LocalTranslator::AddValueAccordingToSignature(
308 const std::string& onc_name,
309 scoped_ptr<base::Value> value) {
310 if (!value || !field_translation_table_)
311 return;
312 std::string shill_property_name;
313 if (!GetShillPropertyName(
314 onc_name, field_translation_table_, &shill_property_name)) {
315 return;
318 shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
319 value.release());
322 void LocalTranslator::TranslateWithTableAndSet(
323 const std::string& onc_value,
324 const StringTranslationEntry table[],
325 const std::string& shill_property_name) {
326 std::string shill_value;
327 if (TranslateStringToShill(table, onc_value, &shill_value)) {
328 shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
329 shill_value);
330 return;
332 // As we previously validate ONC, this case should never occur. If it still
333 // occurs, we should check here. Otherwise the failure will only show up much
334 // later in Shill.
335 LOG(ERROR) << "Value '" << onc_value
336 << "' cannot be translated to Shill property: "
337 << shill_property_name;
340 // Iterates recursively over |onc_object| and its |signature|. At each object
341 // applies the local translation using LocalTranslator::TranslateFields. The
342 // results are written to |shill_dictionary|.
343 void TranslateONCHierarchy(const OncValueSignature& signature,
344 const base::DictionaryValue& onc_object,
345 base::DictionaryValue* shill_dictionary) {
346 base::DictionaryValue* target_shill_dictionary = shill_dictionary;
347 std::vector<std::string> path_to_shill_dictionary =
348 GetPathToNestedShillDictionary(signature);
349 for (std::vector<std::string>::const_iterator it =
350 path_to_shill_dictionary.begin();
351 it != path_to_shill_dictionary.end();
352 ++it) {
353 base::DictionaryValue* nested_shill_dict = NULL;
354 target_shill_dictionary->GetDictionaryWithoutPathExpansion(
355 *it, &nested_shill_dict);
356 if (!nested_shill_dict) {
357 nested_shill_dict = new base::DictionaryValue;
358 target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict);
360 target_shill_dictionary = nested_shill_dict;
362 // Translates fields of |onc_object| and writes them to
363 // |target_shill_dictionary_| nested in |shill_dictionary|.
364 LocalTranslator translator(signature, onc_object, target_shill_dictionary);
365 translator.TranslateFields();
367 // Recurse into nested objects.
368 for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
369 it.Advance()) {
370 const base::DictionaryValue* inner_object = NULL;
371 if (!it.value().GetAsDictionary(&inner_object))
372 continue;
374 const OncFieldSignature* field_signature =
375 GetFieldSignature(signature, it.key());
377 TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
378 shill_dictionary);
382 } // namespace
384 scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
385 const OncValueSignature* onc_signature,
386 const base::DictionaryValue& onc_object) {
387 CHECK(onc_signature != NULL);
388 scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
389 TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
390 return shill_dictionary.Pass();
393 } // namespace onc
394 } // namespace chromeos