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 #include "chromeos/network/onc/onc_translator.h"
9 #include "base/basictypes.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/values.h"
14 #include "chromeos/network/onc/onc_constants.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_translation_tables.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
24 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
26 scoped_ptr
<base::Value
> ConvertStringToValue(const std::string
& str
,
27 base::Value::Type type
) {
29 if (type
== base::Value::TYPE_STRING
)
30 value
= base::Value::CreateStringValue(str
);
32 value
= base::JSONReader::Read(str
);
34 if (value
== NULL
|| value
->GetType() != type
) {
38 return make_scoped_ptr(value
);
41 // This class implements the translation of properties from the given
42 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
43 // recursive calls to TranslateShillServiceToONCPart, nested objects are
45 class ShillToONCTranslator
{
47 ShillToONCTranslator(const base::DictionaryValue
& shill_dictionary
,
48 const OncValueSignature
& onc_signature
)
49 : shill_dictionary_(&shill_dictionary
),
50 onc_signature_(&onc_signature
) {
53 // Translates the associated Shill dictionary and creates an ONC object of the
55 scoped_ptr
<base::DictionaryValue
> CreateTranslatedONCObject();
58 void TranslateOpenVPN();
60 void TranslateNetworkConfiguration();
62 // Creates an ONC object from |shill_dictionary| according to the signature
63 // associated to |onc_field_name| and adds it to |onc_object_| at
65 void TranslateAndAddNestedObject(const std::string
& onc_field_name
);
67 // Copies all entries from |shill_dictionary_| to |onc_object_| for which a
68 // translation (shill_property_name) is defined by |onc_signature_|.
69 void CopyPropertiesAccordingToSignature();
71 // If existent, translates the entry at |shill_property_name| in
72 // |shill_dictionary_| using |table|. It is an error if no matching table
73 // entry is found. Writes the result as entry at |onc_field_name| in
75 void TranslateWithTableAndSet(const std::string
& shill_property_name
,
76 const StringTranslationEntry table
[],
77 const std::string
& onc_field_name
);
79 const base::DictionaryValue
* shill_dictionary_
;
80 const OncValueSignature
* onc_signature_
;
81 scoped_ptr
<base::DictionaryValue
> onc_object_
;
83 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator
);
86 scoped_ptr
<base::DictionaryValue
>
87 ShillToONCTranslator::CreateTranslatedONCObject() {
88 onc_object_
.reset(new base::DictionaryValue
);
89 if (onc_signature_
== &kNetworkConfigurationSignature
)
90 TranslateNetworkConfiguration();
91 else if (onc_signature_
== &kVPNSignature
)
93 else if (onc_signature_
== &kOpenVPNSignature
)
96 CopyPropertiesAccordingToSignature();
97 return onc_object_
.Pass();
100 void ShillToONCTranslator::TranslateOpenVPN() {
101 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
102 // wraps the value into a list.
104 if (shill_dictionary_
->GetStringWithoutPathExpansion(
105 flimflam::kOpenVPNRemoteCertKUProperty
, &certKU
)) {
106 scoped_ptr
<base::ListValue
> certKUs(new base::ListValue
);
107 certKUs
->AppendString(certKU
);
108 onc_object_
->SetWithoutPathExpansion(vpn::kRemoteCertKU
, certKUs
.release());
111 for (const OncFieldSignature
* field_signature
= onc_signature_
->fields
;
112 field_signature
->onc_field_name
!= NULL
; ++field_signature
) {
113 const base::Value
* shill_value
;
114 if (field_signature
->shill_property_name
== NULL
||
115 !shill_dictionary_
->GetWithoutPathExpansion(
116 field_signature
->shill_property_name
, &shill_value
)) {
120 scoped_ptr
<base::Value
> translated
;
121 std::string shill_str
;
122 const std::string
& onc_field_name
= field_signature
->onc_field_name
;
123 if (onc_field_name
== vpn::kSaveCredentials
||
124 onc_field_name
== vpn::kRemoteCertKU
) {
125 translated
.reset(shill_value
->DeepCopy());
126 } else if (shill_value
->GetAsString(&shill_str
)) {
127 // Shill wants all Provider/VPN fields to be strings. Translates these
128 // strings back to the correct ONC type.
129 translated
= ConvertStringToValue(
131 field_signature
->value_signature
->onc_type
);
133 if (translated
.get() == NULL
) {
134 LOG(ERROR
) << "Shill property '" << field_signature
->shill_property_name
135 << "' with value '" << shill_value
136 << "' couldn't be converted to base::Value::Type "
137 << field_signature
->value_signature
->onc_type
;
140 LOG(ERROR
) << "Shill property '" << field_signature
->shill_property_name
141 << "' has value '" << shill_value
142 << "', but expected a string";
144 onc_object_
->SetWithoutPathExpansion(onc_field_name
, translated
.release());
148 void ShillToONCTranslator::TranslateVPN() {
149 TranslateWithTableAndSet(flimflam::kProviderTypeProperty
, kVPNTypeTable
,
151 CopyPropertiesAccordingToSignature();
153 std::string vpn_type
;
154 if (onc_object_
->GetStringWithoutPathExpansion(kType
, &vpn_type
)) {
155 if (vpn_type
== vpn::kTypeL2TP_IPsec
) {
156 TranslateAndAddNestedObject(vpn::kIPsec
);
157 TranslateAndAddNestedObject(vpn::kL2TP
);
159 TranslateAndAddNestedObject(vpn_type
);
164 void ShillToONCTranslator::TranslateAndAddNestedObject(
165 const std::string
& onc_field_name
) {
166 const OncFieldSignature
* field_signature
=
167 GetFieldSignature(*onc_signature_
, onc_field_name
);
168 ShillToONCTranslator
nested_translator(*shill_dictionary_
,
169 *field_signature
->value_signature
);
170 scoped_ptr
<base::DictionaryValue
> nested_object
=
171 nested_translator
.CreateTranslatedONCObject();
172 onc_object_
->SetWithoutPathExpansion(onc_field_name
, nested_object
.release());
175 void ShillToONCTranslator::TranslateNetworkConfiguration() {
176 TranslateWithTableAndSet(flimflam::kTypeProperty
, kNetworkTypeTable
, kType
);
177 CopyPropertiesAccordingToSignature();
179 std::string network_type
;
180 if (onc_object_
->GetStringWithoutPathExpansion(kType
, &network_type
))
181 TranslateAndAddNestedObject(network_type
);
184 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
185 for (const OncFieldSignature
* field_signature
= onc_signature_
->fields
;
186 field_signature
->onc_field_name
!= NULL
; ++field_signature
) {
187 const base::Value
* shill_value
;
188 if (field_signature
->shill_property_name
== NULL
||
189 !shill_dictionary_
->GetWithoutPathExpansion(
190 field_signature
->shill_property_name
, &shill_value
)) {
193 onc_object_
->SetWithoutPathExpansion(
194 field_signature
->onc_field_name
, shill_value
->DeepCopy());
198 void ShillToONCTranslator::TranslateWithTableAndSet(
199 const std::string
& shill_property_name
,
200 const StringTranslationEntry table
[],
201 const std::string
& onc_field_name
) {
202 std::string shill_value
;
203 if (!shill_dictionary_
->GetStringWithoutPathExpansion(shill_property_name
,
208 for (int i
= 0; table
[i
].onc_value
!= NULL
; ++i
) {
209 if (shill_value
!= table
[i
].shill_value
)
211 onc_object_
->SetStringWithoutPathExpansion(onc_field_name
,
215 LOG(ERROR
) << "Shill property '" << shill_property_name
<< "' with value '"
216 << shill_value
<< "' couldn't be translated to ONC";
221 scoped_ptr
<base::DictionaryValue
> TranslateShillServiceToONCPart(
222 const base::DictionaryValue
& shill_dictionary
,
223 const OncValueSignature
* onc_signature
) {
224 CHECK(onc_signature
!= NULL
);
226 ShillToONCTranslator
translator(shill_dictionary
, *onc_signature
);
227 return translator
.CreateTranslatedONCObject();
231 } // namespace chromeos