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/values.h"
19 #include "chromeos/network/onc/onc_signature.h"
20 #include "chromeos/network/onc/onc_translation_tables.h"
21 #include "chromeos/network/shill_property_util.h"
22 #include "components/onc/onc_constants.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
30 scoped_ptr
<base::StringValue
> ConvertValueToString(const base::Value
& value
) {
32 if (!value
.GetAsString(&str
))
33 base::JSONWriter::Write(&value
, &str
);
34 return make_scoped_ptr(base::Value::CreateStringValue(str
));
37 // This class is responsible to translate the local fields of the given
38 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
39 // translation should consider (if possible) only fields of this ONC object and
40 // not nested objects because recursion is handled by the calling function
41 // TranslateONCHierarchy.
42 class LocalTranslator
{
44 LocalTranslator(const OncValueSignature
& onc_signature
,
45 const base::DictionaryValue
& onc_object
,
46 base::DictionaryValue
* shill_dictionary
)
47 : onc_signature_(&onc_signature
),
48 onc_object_(&onc_object
),
49 shill_dictionary_(shill_dictionary
) {
50 field_translation_table_
= GetFieldTranslationTable(onc_signature
);
53 void TranslateFields();
56 void TranslateEthernet();
57 void TranslateOpenVPN();
61 void TranslateNetworkConfiguration();
63 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
64 // translation (shill_property_name) is defined by |onc_signature_|.
65 void CopyFieldsAccordingToSignature();
67 // Adds |value| to |shill_dictionary| at the field shill_property_name given
68 // by the associated signature. Takes ownership of |value|. Does nothing if
69 // |value| is NULL or the property name cannot be read from the signature.
70 void AddValueAccordingToSignature(const std::string
& onc_field_name
,
71 scoped_ptr
<base::Value
> value
);
73 // If existent, translates the entry at |onc_field_name| in |onc_object_|
74 // using |table|. It is an error if no matching table entry is found. Writes
75 // the result as entry at |shill_property_name| in |shill_dictionary_|.
76 void TranslateWithTableAndSet(const std::string
& onc_field_name
,
77 const StringTranslationEntry table
[],
78 const std::string
& shill_property_name
);
80 const OncValueSignature
* onc_signature_
;
81 const FieldTranslationEntry
* field_translation_table_
;
82 const base::DictionaryValue
* onc_object_
;
83 base::DictionaryValue
* shill_dictionary_
;
85 DISALLOW_COPY_AND_ASSIGN(LocalTranslator
);
88 void LocalTranslator::TranslateFields() {
89 if (onc_signature_
== &kNetworkConfigurationSignature
)
90 TranslateNetworkConfiguration();
91 else if (onc_signature_
== &kEthernetSignature
)
93 else if (onc_signature_
== &kVPNSignature
)
95 else if (onc_signature_
== &kOpenVPNSignature
)
97 else if (onc_signature_
== &kWiFiSignature
)
99 else if (onc_signature_
== &kEAPSignature
)
102 CopyFieldsAccordingToSignature();
105 void LocalTranslator::TranslateEthernet() {
106 std::string authentication
;
107 onc_object_
->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication
,
110 const char* shill_type
= shill::kTypeEthernet
;
111 if (authentication
== ::onc::ethernet::k8021X
)
112 shill_type
= shill::kTypeEthernetEap
;
113 shill_dictionary_
->SetStringWithoutPathExpansion(shill::kTypeProperty
,
116 CopyFieldsAccordingToSignature();
119 void LocalTranslator::TranslateOpenVPN() {
120 // Shill supports only one RemoteCertKU but ONC a list.
121 // Copy only the first entry if existing.
122 const base::ListValue
* certKUs
= NULL
;
124 if (onc_object_
->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU
,
126 certKUs
->GetString(0, &certKU
)) {
127 shill_dictionary_
->SetStringWithoutPathExpansion(
128 shill::kOpenVPNRemoteCertKUProperty
, certKU
);
131 for (base::DictionaryValue::Iterator
it(*onc_object_
); !it
.IsAtEnd();
133 scoped_ptr
<base::Value
> translated
;
134 if (it
.key() == ::onc::vpn::kSaveCredentials
||
135 it
.key() == ::onc::openvpn::kRemoteCertKU
||
136 it
.key() == ::onc::openvpn::kServerCAPEMs
) {
137 translated
.reset(it
.value().DeepCopy());
139 // Shill wants all Provider/VPN fields to be strings.
140 translated
= ConvertValueToString(it
.value());
142 AddValueAccordingToSignature(it
.key(), translated
.Pass());
146 void LocalTranslator::TranslateVPN() {
148 onc_object_
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
149 TranslateWithTableAndSet(type
, kVPNTypeTable
, shill::kProviderTypeProperty
);
151 CopyFieldsAccordingToSignature();
154 void LocalTranslator::TranslateWiFi() {
155 std::string security
;
156 onc_object_
->GetStringWithoutPathExpansion(::onc::wifi::kSecurity
, &security
);
157 TranslateWithTableAndSet(security
, kWiFiSecurityTable
,
158 shill::kSecurityProperty
);
161 onc_object_
->GetStringWithoutPathExpansion(::onc::wifi::kSSID
, &ssid
);
162 shill_property_util::SetSSID(ssid
, shill_dictionary_
);
164 // We currently only support managed and no adhoc networks.
165 shill_dictionary_
->SetStringWithoutPathExpansion(shill::kModeProperty
,
166 shill::kModeManaged
);
167 CopyFieldsAccordingToSignature();
170 void LocalTranslator::TranslateEAP() {
172 onc_object_
->GetStringWithoutPathExpansion(::onc::eap::kOuter
, &outer
);
173 TranslateWithTableAndSet(outer
, kEAPOuterTable
, shill::kEapMethodProperty
);
175 // Translate the inner protocol only for outer tunneling protocols.
176 if (outer
== ::onc::eap::kPEAP
|| outer
== ::onc::eap::kEAP_TTLS
) {
177 // In ONC the Inner protocol defaults to "Automatic".
178 std::string inner
= ::onc::eap::kAutomatic
;
179 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
181 onc_object_
->GetStringWithoutPathExpansion(::onc::eap::kInner
, &inner
);
182 if (inner
!= ::onc::eap::kAutomatic
) {
183 const StringTranslationEntry
* table
=
184 outer
== ::onc::eap::kPEAP
? kEAP_PEAP_InnerTable
:
185 kEAP_TTLS_InnerTable
;
186 TranslateWithTableAndSet(inner
, table
, shill::kEapPhase2AuthProperty
);
190 CopyFieldsAccordingToSignature();
193 void LocalTranslator::TranslateNetworkConfiguration() {
195 onc_object_
->GetStringWithoutPathExpansion(::onc::network_config::kType
,
198 // Set the type except for Ethernet which is set in TranslateEthernet.
199 if (type
!= ::onc::network_type::kEthernet
)
200 TranslateWithTableAndSet(type
, kNetworkTypeTable
, shill::kTypeProperty
);
202 // Shill doesn't allow setting the name for non-VPN networks.
203 if (type
== ::onc::network_type::kVPN
) {
205 onc_object_
->GetStringWithoutPathExpansion(::onc::network_config::kName
,
207 shill_dictionary_
->SetStringWithoutPathExpansion(shill::kNameProperty
,
211 CopyFieldsAccordingToSignature();
214 void LocalTranslator::CopyFieldsAccordingToSignature() {
215 for (base::DictionaryValue::Iterator
it(*onc_object_
); !it
.IsAtEnd();
217 AddValueAccordingToSignature(it
.key(),
218 make_scoped_ptr(it
.value().DeepCopy()));
222 void LocalTranslator::AddValueAccordingToSignature(
223 const std::string
& onc_name
,
224 scoped_ptr
<base::Value
> value
) {
225 if (!value
|| !field_translation_table_
)
227 std::string shill_property_name
;
228 if (!GetShillPropertyName(onc_name
,
229 field_translation_table_
,
230 &shill_property_name
))
233 shill_dictionary_
->SetWithoutPathExpansion(shill_property_name
,
237 void LocalTranslator::TranslateWithTableAndSet(
238 const std::string
& onc_value
,
239 const StringTranslationEntry table
[],
240 const std::string
& shill_property_name
) {
241 std::string shill_value
;
242 if (TranslateStringToShill(table
, onc_value
, &shill_value
)) {
243 shill_dictionary_
->SetStringWithoutPathExpansion(shill_property_name
,
247 // As we previously validate ONC, this case should never occur. If it still
248 // occurs, we should check here. Otherwise the failure will only show up much
250 LOG(ERROR
) << "Value '" << onc_value
251 << "' cannot be translated to Shill property "
252 << shill_property_name
;
255 // Iterates recursively over |onc_object| and its |signature|. At each object
256 // applies the local translation using LocalTranslator::TranslateFields. The
257 // results are written to |shill_dictionary|.
258 void TranslateONCHierarchy(const OncValueSignature
& signature
,
259 const base::DictionaryValue
& onc_object
,
260 base::DictionaryValue
* shill_dictionary
) {
261 base::DictionaryValue
* target_shill_dictionary
= shill_dictionary
;
262 std::vector
<std::string
> path_to_shill_dictionary
=
263 GetPathToNestedShillDictionary(signature
);
264 for (std::vector
<std::string
>::const_iterator it
=
265 path_to_shill_dictionary
.begin();
266 it
!= path_to_shill_dictionary
.end();
268 base::DictionaryValue
* nested_shill_dict
= NULL
;
269 target_shill_dictionary
->GetDictionaryWithoutPathExpansion(
270 *it
, &nested_shill_dict
);
271 if (!nested_shill_dict
)
272 nested_shill_dict
= new base::DictionaryValue
;
273 target_shill_dictionary
->SetWithoutPathExpansion(*it
, nested_shill_dict
);
274 target_shill_dictionary
= nested_shill_dict
;
276 // Translates fields of |onc_object| and writes them to
277 // |target_shill_dictionary_| nested in |shill_dictionary|.
278 LocalTranslator
translator(signature
, onc_object
, target_shill_dictionary
);
279 translator
.TranslateFields();
281 // Recurse into nested objects.
282 for (base::DictionaryValue::Iterator
it(onc_object
); !it
.IsAtEnd();
284 const base::DictionaryValue
* inner_object
= NULL
;
285 if (!it
.value().GetAsDictionary(&inner_object
))
288 const OncFieldSignature
* field_signature
=
289 GetFieldSignature(signature
, it
.key());
291 TranslateONCHierarchy(*field_signature
->value_signature
, *inner_object
,
298 scoped_ptr
<base::DictionaryValue
> TranslateONCObjectToShill(
299 const OncValueSignature
* onc_signature
,
300 const base::DictionaryValue
& onc_object
) {
301 CHECK(onc_signature
!= NULL
);
302 scoped_ptr
<base::DictionaryValue
> shill_dictionary(new base::DictionaryValue
);
303 TranslateONCHierarchy(*onc_signature
, onc_object
, shill_dictionary
.get());
304 return shill_dictionary
.Pass();
308 } // namespace chromeos