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_constants.h"
20 #include "chromeos/network/onc/onc_signature.h"
21 #include "chromeos/network/onc/onc_translation_tables.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
29 scoped_ptr
<base::StringValue
> ConvertValueToString(const base::Value
& value
) {
31 if (!value
.GetAsString(&str
))
32 base::JSONWriter::Write(&value
, &str
);
33 return make_scoped_ptr(base::Value::CreateStringValue(str
));
36 // This class is responsible to translate the local fields of the given
37 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
38 // translation should consider (if possible) only fields of this ONC object and
39 // not nested objects because recursion is handled by the calling function
40 // TranslateONCHierarchy.
41 class LocalTranslator
{
43 LocalTranslator(const OncValueSignature
& onc_signature
,
44 const base::DictionaryValue
& onc_object
,
45 base::DictionaryValue
* shill_dictionary
)
46 : onc_signature_(&onc_signature
),
47 onc_object_(&onc_object
),
48 shill_dictionary_(shill_dictionary
) {
49 field_translation_table_
= GetFieldTranslationTable(onc_signature
);
52 void TranslateFields();
55 void TranslateOpenVPN();
59 void TranslateNetworkConfiguration();
61 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
62 // translation (shill_property_name) is defined by |onc_signature_|.
63 void CopyFieldsAccordingToSignature();
65 // Adds |value| to |shill_dictionary| at the field shill_property_name given
66 // by the associated signature. Takes ownership of |value|. Does nothing if
67 // |value| is NULL or the property name cannot be read from the signature.
68 void AddValueAccordingToSignature(const std::string
& onc_field_name
,
69 scoped_ptr
<base::Value
> value
);
71 // If existent, translates the entry at |onc_field_name| in |onc_object_|
72 // using |table|. It is an error if no matching table entry is found. Writes
73 // the result as entry at |shill_property_name| in |shill_dictionary_|.
74 void TranslateWithTableAndSet(const std::string
& onc_field_name
,
75 const StringTranslationEntry table
[],
76 const std::string
& shill_property_name
);
78 const OncValueSignature
* onc_signature_
;
79 const FieldTranslationEntry
* field_translation_table_
;
80 const base::DictionaryValue
* onc_object_
;
81 base::DictionaryValue
* shill_dictionary_
;
83 DISALLOW_COPY_AND_ASSIGN(LocalTranslator
);
86 void LocalTranslator::TranslateFields() {
87 if (onc_signature_
== &kNetworkConfigurationSignature
)
88 TranslateNetworkConfiguration();
89 else if (onc_signature_
== &kVPNSignature
)
91 else if (onc_signature_
== &kOpenVPNSignature
)
93 else if (onc_signature_
== &kWiFiSignature
)
95 else if (onc_signature_
== &kEAPSignature
)
98 CopyFieldsAccordingToSignature();
101 void LocalTranslator::TranslateOpenVPN() {
102 // Shill supports only one RemoteCertKU but ONC a list.
103 // Copy only the first entry if existing.
104 const base::ListValue
* certKUs
= NULL
;
106 if (onc_object_
->GetListWithoutPathExpansion(openvpn::kRemoteCertKU
,
108 certKUs
->GetString(0, &certKU
)) {
109 shill_dictionary_
->SetStringWithoutPathExpansion(
110 flimflam::kOpenVPNRemoteCertKUProperty
, certKU
);
113 for (base::DictionaryValue::Iterator
it(*onc_object_
); !it
.IsAtEnd();
115 scoped_ptr
<base::Value
> translated
;
116 if (it
.key() == vpn::kSaveCredentials
||
117 it
.key() == openvpn::kRemoteCertKU
||
118 it
.key() == openvpn::kServerCAPEMs
) {
119 translated
.reset(it
.value().DeepCopy());
121 // Shill wants all Provider/VPN fields to be strings.
122 translated
= ConvertValueToString(it
.value());
124 AddValueAccordingToSignature(it
.key(), translated
.Pass());
128 void LocalTranslator::TranslateVPN() {
130 onc_object_
->GetStringWithoutPathExpansion(vpn::kType
, &type
);
131 TranslateWithTableAndSet(type
, kVPNTypeTable
,
132 flimflam::kProviderTypeProperty
);
134 CopyFieldsAccordingToSignature();
137 void LocalTranslator::TranslateWiFi() {
138 std::string security
;
139 onc_object_
->GetStringWithoutPathExpansion(wifi::kSecurity
, &security
);
140 TranslateWithTableAndSet(security
, kWiFiSecurityTable
,
141 flimflam::kSecurityProperty
);
143 // We currently only support managed and no adhoc networks.
144 shill_dictionary_
->SetStringWithoutPathExpansion(flimflam::kModeProperty
,
145 flimflam::kModeManaged
);
146 CopyFieldsAccordingToSignature();
149 void LocalTranslator::TranslateEAP() {
151 onc_object_
->GetStringWithoutPathExpansion(eap::kOuter
, &outer
);
152 TranslateWithTableAndSet(outer
, kEAPOuterTable
, flimflam::kEapMethodProperty
);
154 // Translate the inner protocol only for outer tunneling protocols.
155 if (outer
== eap::kPEAP
|| outer
== eap::kEAP_TTLS
) {
156 // In ONC the Inner protocol defaults to "Automatic".
157 std::string inner
= eap::kAutomatic
;
158 // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
160 onc_object_
->GetStringWithoutPathExpansion(eap::kInner
, &inner
);
161 if (inner
!= eap::kAutomatic
) {
162 const StringTranslationEntry
* table
=
163 outer
== eap::kPEAP
? kEAP_PEAP_InnerTable
: kEAP_TTLS_InnerTable
;
164 TranslateWithTableAndSet(inner
, table
, flimflam::kEapPhase2AuthProperty
);
168 CopyFieldsAccordingToSignature();
171 void LocalTranslator::TranslateNetworkConfiguration() {
173 onc_object_
->GetStringWithoutPathExpansion(network_config::kType
, &type
);
174 TranslateWithTableAndSet(type
, kNetworkTypeTable
, flimflam::kTypeProperty
);
176 // Shill doesn't allow setting the name for non-VPN networks.
177 if (type
== network_type::kVPN
) {
179 onc_object_
->GetStringWithoutPathExpansion(network_config::kName
, &name
);
180 shill_dictionary_
->SetStringWithoutPathExpansion(
181 flimflam::kNameProperty
, name
);
184 CopyFieldsAccordingToSignature();
187 void LocalTranslator::CopyFieldsAccordingToSignature() {
188 for (base::DictionaryValue::Iterator
it(*onc_object_
); !it
.IsAtEnd();
190 AddValueAccordingToSignature(it
.key(),
191 make_scoped_ptr(it
.value().DeepCopy()));
195 void LocalTranslator::AddValueAccordingToSignature(
196 const std::string
& onc_name
,
197 scoped_ptr
<base::Value
> value
) {
198 if (!value
|| !field_translation_table_
)
201 std::string shill_property_name
;
202 if (!GetShillPropertyName(onc_name
,
203 field_translation_table_
,
204 &shill_property_name
))
207 shill_dictionary_
->SetWithoutPathExpansion(shill_property_name
,
211 void LocalTranslator::TranslateWithTableAndSet(
212 const std::string
& onc_value
,
213 const StringTranslationEntry table
[],
214 const std::string
& shill_property_name
) {
215 std::string shill_value
;
216 if (TranslateStringToShill(table
, onc_value
, &shill_value
)) {
217 shill_dictionary_
->SetStringWithoutPathExpansion(shill_property_name
,
221 // As we previously validate ONC, this case should never occur. If it still
222 // occurs, we should check here. Otherwise the failure will only show up much
224 LOG(ERROR
) << "Value '" << onc_value
225 << "' cannot be translated to Shill property "
226 << shill_property_name
;
229 // Iterates recursively over |onc_object| and its |signature|. At each object
230 // applies the local translation using LocalTranslator::TranslateFields. The
231 // results are written to |shill_dictionary|.
232 void TranslateONCHierarchy(const OncValueSignature
& signature
,
233 const base::DictionaryValue
& onc_object
,
234 base::DictionaryValue
* shill_dictionary
) {
235 // Translates fields of |onc_object| and writes them to |shill_dictionary_|.
236 LocalTranslator
translator(signature
, onc_object
, shill_dictionary
);
237 translator
.TranslateFields();
239 // Recurse into nested objects.
240 for (base::DictionaryValue::Iterator
it(onc_object
); !it
.IsAtEnd();
242 const base::DictionaryValue
* inner_object
= NULL
;
243 if (!it
.value().GetAsDictionary(&inner_object
))
246 const OncFieldSignature
* field_signature
=
247 GetFieldSignature(signature
, it
.key());
249 TranslateONCHierarchy(*field_signature
->value_signature
, *inner_object
,
256 scoped_ptr
<base::DictionaryValue
> TranslateONCObjectToShill(
257 const OncValueSignature
* onc_signature
,
258 const base::DictionaryValue
& onc_object
) {
259 CHECK(onc_signature
!= NULL
);
260 scoped_ptr
<base::DictionaryValue
> shill_dictionary(new base::DictionaryValue
);
261 TranslateONCHierarchy(*onc_signature
, onc_object
, shill_dictionary
.get());
262 return shill_dictionary
.Pass();
266 } // namespace chromeos