Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / onc / onc_translator_onc_to_shill.cc
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.
4
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
10
11 #include "chromeos/network/onc/onc_translator.h"
12
13 #include <string>
14
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"
25
26 namespace chromeos {
27 namespace onc {
28
29 namespace {
30
31 bool ConvertListValueToStringVector(const base::ListValue& string_list,
32                                     std::vector<std::string>* result) {
33   for (size_t i = 0; i < string_list.GetSize(); ++i) {
34     std::string str;
35     if (!string_list.GetString(i, &str))
36       return false;
37     result->push_back(str);
38   }
39   return true;
40 }
41
42 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
43   std::string str;
44   if (!value.GetAsString(&str))
45     base::JSONWriter::Write(&value, &str);
46   return make_scoped_ptr(new base::StringValue(str));
47 }
48
49 // This class is responsible to translate the local fields of the given
50 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
51 // translation should consider (if possible) only fields of this ONC object and
52 // not nested objects because recursion is handled by the calling function
53 // TranslateONCHierarchy.
54 class LocalTranslator {
55  public:
56   LocalTranslator(const OncValueSignature& onc_signature,
57                   const base::DictionaryValue& onc_object,
58                   base::DictionaryValue* shill_dictionary)
59       : onc_signature_(&onc_signature),
60         onc_object_(&onc_object),
61         shill_dictionary_(shill_dictionary) {
62     field_translation_table_ = GetFieldTranslationTable(onc_signature);
63   }
64
65   void TranslateFields();
66
67  private:
68   void TranslateEthernet();
69   void TranslateOpenVPN();
70   void TranslateIPsec();
71   void TranslateVPN();
72   void TranslateWiFi();
73   void TranslateEAP();
74   void TranslateStaticIPConfig();
75   void TranslateNetworkConfiguration();
76
77   // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
78   // translation (shill_property_name) is defined by |onc_signature_|.
79   void CopyFieldsAccordingToSignature();
80
81   // Adds |value| to |shill_dictionary| at the field shill_property_name given
82   // by the associated signature. Takes ownership of |value|. Does nothing if
83   // |value| is NULL or the property name cannot be read from the signature.
84   void AddValueAccordingToSignature(const std::string& onc_field_name,
85                                     scoped_ptr<base::Value> value);
86
87   // If existent, translates the entry at |onc_field_name| in |onc_object_|
88   // using |table|. It is an error if no matching table entry is found. Writes
89   // the result as entry at |shill_property_name| in |shill_dictionary_|.
90   void TranslateWithTableAndSet(const std::string& onc_field_name,
91                                 const StringTranslationEntry table[],
92                                 const std::string& shill_property_name);
93
94   const OncValueSignature* onc_signature_;
95   const FieldTranslationEntry* field_translation_table_;
96   const base::DictionaryValue* onc_object_;
97   base::DictionaryValue* shill_dictionary_;
98
99   DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
100 };
101
102 void LocalTranslator::TranslateFields() {
103   if (onc_signature_ == &kNetworkConfigurationSignature)
104     TranslateNetworkConfiguration();
105   else if (onc_signature_ == &kStaticIPConfigSignature)
106     TranslateStaticIPConfig();
107   else if (onc_signature_ == &kEthernetSignature)
108     TranslateEthernet();
109   else if (onc_signature_ == &kVPNSignature)
110     TranslateVPN();
111   else if (onc_signature_ == &kOpenVPNSignature)
112     TranslateOpenVPN();
113   else if (onc_signature_ == &kIPsecSignature)
114     TranslateIPsec();
115   else if (onc_signature_ == &kWiFiSignature)
116     TranslateWiFi();
117   else if (onc_signature_ == &kEAPSignature)
118     TranslateEAP();
119   else
120     CopyFieldsAccordingToSignature();
121 }
122
123 void LocalTranslator::TranslateEthernet() {
124   std::string authentication;
125   onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
126                                              &authentication);
127
128   const char* shill_type = shill::kTypeEthernet;
129   if (authentication == ::onc::ethernet::k8021X)
130     shill_type = shill::kTypeEthernetEap;
131   shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
132                                                    shill_type);
133
134   CopyFieldsAccordingToSignature();
135 }
136
137
138 void LocalTranslator::TranslateStaticIPConfig() {
139   const base::ListValue* onc_nameservers = NULL;
140   if (onc_object_->GetListWithoutPathExpansion(::onc::ipconfig::kNameServers,
141                                                &onc_nameservers)) {
142     std::vector<std::string> onc_nameservers_vector;
143     ConvertListValueToStringVector(*onc_nameservers, &onc_nameservers_vector);
144     std::string shill_nameservers = JoinString(onc_nameservers_vector, ',');
145     shill_dictionary_->SetStringWithoutPathExpansion(
146         shill::kStaticIPNameServersProperty, shill_nameservers);
147   }
148
149   CopyFieldsAccordingToSignature();
150 }
151
152 void LocalTranslator::TranslateOpenVPN() {
153   // SaveCredentials needs special handling when translating from Shill -> ONC
154   // so handle it explicitly here.
155   bool save_credentials;
156   if (onc_object_->GetBooleanWithoutPathExpansion(
157           ::onc::vpn::kSaveCredentials, &save_credentials)) {
158     shill_dictionary_->SetBooleanWithoutPathExpansion(
159         shill::kSaveCredentialsProperty, save_credentials);
160   }
161   // Shill supports only one RemoteCertKU but ONC a list.
162   // Copy only the first entry if existing.
163   const base::ListValue* certKUs = NULL;
164   std::string certKU;
165   if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
166                                                &certKUs) &&
167       certKUs->GetString(0, &certKU)) {
168     shill_dictionary_->SetStringWithoutPathExpansion(
169         shill::kOpenVPNRemoteCertKUProperty, certKU);
170   }
171
172   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
173        it.Advance()) {
174     scoped_ptr<base::Value> translated;
175     if (it.key() == ::onc::openvpn::kRemoteCertKU ||
176         it.key() == ::onc::openvpn::kServerCAPEMs) {
177       translated.reset(it.value().DeepCopy());
178     } else {
179       // Shill wants all Provider/VPN fields to be strings.
180       translated = ConvertValueToString(it.value());
181     }
182     AddValueAccordingToSignature(it.key(), translated.Pass());
183   }
184 }
185
186 void LocalTranslator::TranslateIPsec() {
187   CopyFieldsAccordingToSignature();
188
189   // SaveCredentials needs special handling when translating from Shill -> ONC
190   // so handle it explicitly here.
191   bool save_credentials;
192   if (onc_object_->GetBooleanWithoutPathExpansion(
193           ::onc::vpn::kSaveCredentials, &save_credentials)) {
194     shill_dictionary_->SetBooleanWithoutPathExpansion(
195         shill::kSaveCredentialsProperty, save_credentials);
196   }
197 }
198
199 void LocalTranslator::TranslateVPN() {
200   std::string host;
201   if (onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kHost, &host)) {
202     shill_dictionary_->SetStringWithoutPathExpansion(
203         shill::kProviderHostProperty, host);
204   }
205   std::string type;
206   onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
207   TranslateWithTableAndSet(type, kVPNTypeTable, shill::kProviderTypeProperty);
208
209   CopyFieldsAccordingToSignature();
210 }
211
212 void LocalTranslator::TranslateWiFi() {
213   std::string security;
214   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSecurity, &security);
215   TranslateWithTableAndSet(security, kWiFiSecurityTable,
216                            shill::kSecurityProperty);
217
218   std::string ssid;
219   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid);
220   shill_property_util::SetSSID(ssid, shill_dictionary_);
221
222   // We currently only support managed and no adhoc networks.
223   shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
224                                                    shill::kModeManaged);
225   CopyFieldsAccordingToSignature();
226 }
227
228 void LocalTranslator::TranslateEAP() {
229   std::string outer;
230   onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
231   TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
232
233   // Translate the inner protocol only for outer tunneling protocols.
234   if (outer == ::onc::eap::kPEAP || outer == ::onc::eap::kEAP_TTLS) {
235     // In ONC the Inner protocol defaults to "Automatic".
236     std::string inner = ::onc::eap::kAutomatic;
237     // ONC's Inner == "Automatic" translates to omitting the Phase2 property in
238     // Shill.
239     onc_object_->GetStringWithoutPathExpansion(::onc::eap::kInner, &inner);
240     if (inner != ::onc::eap::kAutomatic) {
241       const StringTranslationEntry* table =
242           outer == ::onc::eap::kPEAP ? kEAP_PEAP_InnerTable :
243                                        kEAP_TTLS_InnerTable;
244       TranslateWithTableAndSet(inner, table, shill::kEapPhase2AuthProperty);
245     }
246   }
247
248   CopyFieldsAccordingToSignature();
249 }
250
251 void LocalTranslator::TranslateNetworkConfiguration() {
252   std::string type;
253   onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
254                                              &type);
255
256   // Set the type except for Ethernet which is set in TranslateEthernet.
257   if (type != ::onc::network_type::kEthernet)
258     TranslateWithTableAndSet(type, kNetworkTypeTable, shill::kTypeProperty);
259
260   // Shill doesn't allow setting the name for non-VPN networks.
261   if (type == ::onc::network_type::kVPN) {
262     std::string name;
263     onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kName,
264                                                &name);
265     shill_dictionary_->SetStringWithoutPathExpansion(shill::kNameProperty,
266                                                      name);
267   }
268
269   CopyFieldsAccordingToSignature();
270 }
271
272 void LocalTranslator::CopyFieldsAccordingToSignature() {
273   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
274        it.Advance()) {
275     AddValueAccordingToSignature(it.key(),
276                                  make_scoped_ptr(it.value().DeepCopy()));
277   }
278 }
279
280 void LocalTranslator::AddValueAccordingToSignature(
281     const std::string& onc_name,
282     scoped_ptr<base::Value> value) {
283   if (!value || !field_translation_table_)
284     return;
285   std::string shill_property_name;
286   if (!GetShillPropertyName(onc_name,
287                             field_translation_table_,
288                             &shill_property_name))
289     return;
290
291   shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
292                                              value.release());
293 }
294
295 void LocalTranslator::TranslateWithTableAndSet(
296     const std::string& onc_value,
297     const StringTranslationEntry table[],
298     const std::string& shill_property_name) {
299   std::string shill_value;
300   if (TranslateStringToShill(table, onc_value, &shill_value)) {
301     shill_dictionary_->SetStringWithoutPathExpansion(shill_property_name,
302                                                      shill_value);
303     return;
304   }
305   // As we previously validate ONC, this case should never occur. If it still
306   // occurs, we should check here. Otherwise the failure will only show up much
307   // later in Shill.
308   LOG(ERROR) << "Value '" << onc_value
309              << "' cannot be translated to Shill property "
310              << shill_property_name;
311 }
312
313 // Iterates recursively over |onc_object| and its |signature|. At each object
314 // applies the local translation using LocalTranslator::TranslateFields. The
315 // results are written to |shill_dictionary|.
316 void TranslateONCHierarchy(const OncValueSignature& signature,
317                            const base::DictionaryValue& onc_object,
318                            base::DictionaryValue* shill_dictionary) {
319   base::DictionaryValue* target_shill_dictionary = shill_dictionary;
320   std::vector<std::string> path_to_shill_dictionary =
321       GetPathToNestedShillDictionary(signature);
322   for (std::vector<std::string>::const_iterator it =
323            path_to_shill_dictionary.begin();
324        it != path_to_shill_dictionary.end();
325        ++it) {
326     base::DictionaryValue* nested_shill_dict = NULL;
327     target_shill_dictionary->GetDictionaryWithoutPathExpansion(
328         *it, &nested_shill_dict);
329     if (!nested_shill_dict)
330       nested_shill_dict = new base::DictionaryValue;
331     target_shill_dictionary->SetWithoutPathExpansion(*it, nested_shill_dict);
332     target_shill_dictionary = nested_shill_dict;
333   }
334   // Translates fields of |onc_object| and writes them to
335   // |target_shill_dictionary_| nested in |shill_dictionary|.
336   LocalTranslator translator(signature, onc_object, target_shill_dictionary);
337   translator.TranslateFields();
338
339   // Recurse into nested objects.
340   for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
341        it.Advance()) {
342     const base::DictionaryValue* inner_object = NULL;
343     if (!it.value().GetAsDictionary(&inner_object))
344       continue;
345
346     const OncFieldSignature* field_signature =
347         GetFieldSignature(signature, it.key());
348
349     TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
350                           shill_dictionary);
351   }
352 }
353
354 }  // namespace
355
356 scoped_ptr<base::DictionaryValue> TranslateONCObjectToShill(
357     const OncValueSignature* onc_signature,
358     const base::DictionaryValue& onc_object) {
359   CHECK(onc_signature != NULL);
360   scoped_ptr<base::DictionaryValue> shill_dictionary(new base::DictionaryValue);
361   TranslateONCHierarchy(*onc_signature, onc_object, shill_dictionary.get());
362   return shill_dictionary.Pass();
363 }
364
365 }  // namespace onc
366 }  // namespace chromeos