- add sources.
[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/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"
24
25 namespace chromeos {
26 namespace onc {
27
28 namespace {
29
30 scoped_ptr<base::StringValue> ConvertValueToString(const base::Value& value) {
31   std::string str;
32   if (!value.GetAsString(&str))
33     base::JSONWriter::Write(&value, &str);
34   return make_scoped_ptr(base::Value::CreateStringValue(str));
35 }
36
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 {
43  public:
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);
51   }
52
53   void TranslateFields();
54
55  private:
56   void TranslateEthernet();
57   void TranslateOpenVPN();
58   void TranslateVPN();
59   void TranslateWiFi();
60   void TranslateEAP();
61   void TranslateNetworkConfiguration();
62
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();
66
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);
72
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);
79
80   const OncValueSignature* onc_signature_;
81   const FieldTranslationEntry* field_translation_table_;
82   const base::DictionaryValue* onc_object_;
83   base::DictionaryValue* shill_dictionary_;
84
85   DISALLOW_COPY_AND_ASSIGN(LocalTranslator);
86 };
87
88 void LocalTranslator::TranslateFields() {
89   if (onc_signature_ == &kNetworkConfigurationSignature)
90     TranslateNetworkConfiguration();
91   else if (onc_signature_ == &kEthernetSignature)
92     TranslateEthernet();
93   else if (onc_signature_ == &kVPNSignature)
94     TranslateVPN();
95   else if (onc_signature_ == &kOpenVPNSignature)
96     TranslateOpenVPN();
97   else if (onc_signature_ == &kWiFiSignature)
98     TranslateWiFi();
99   else if (onc_signature_ == &kEAPSignature)
100     TranslateEAP();
101   else
102     CopyFieldsAccordingToSignature();
103 }
104
105 void LocalTranslator::TranslateEthernet() {
106   std::string authentication;
107   onc_object_->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
108                                              &authentication);
109
110   const char* shill_type = shill::kTypeEthernet;
111   if (authentication == ::onc::ethernet::k8021X)
112     shill_type = shill::kTypeEthernetEap;
113   shill_dictionary_->SetStringWithoutPathExpansion(shill::kTypeProperty,
114                                                    shill_type);
115
116   CopyFieldsAccordingToSignature();
117 }
118
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;
123   std::string certKU;
124   if (onc_object_->GetListWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
125                                                &certKUs) &&
126       certKUs->GetString(0, &certKU)) {
127     shill_dictionary_->SetStringWithoutPathExpansion(
128         shill::kOpenVPNRemoteCertKUProperty, certKU);
129   }
130
131   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
132        it.Advance()) {
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());
138     } else {
139       // Shill wants all Provider/VPN fields to be strings.
140       translated = ConvertValueToString(it.value());
141     }
142     AddValueAccordingToSignature(it.key(), translated.Pass());
143   }
144 }
145
146 void LocalTranslator::TranslateVPN() {
147   std::string type;
148   onc_object_->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
149   TranslateWithTableAndSet(type, kVPNTypeTable, shill::kProviderTypeProperty);
150
151   CopyFieldsAccordingToSignature();
152 }
153
154 void LocalTranslator::TranslateWiFi() {
155   std::string security;
156   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSecurity, &security);
157   TranslateWithTableAndSet(security, kWiFiSecurityTable,
158                            shill::kSecurityProperty);
159
160   std::string ssid;
161   onc_object_->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid);
162   shill_property_util::SetSSID(ssid, shill_dictionary_);
163
164   // We currently only support managed and no adhoc networks.
165   shill_dictionary_->SetStringWithoutPathExpansion(shill::kModeProperty,
166                                                    shill::kModeManaged);
167   CopyFieldsAccordingToSignature();
168 }
169
170 void LocalTranslator::TranslateEAP() {
171   std::string outer;
172   onc_object_->GetStringWithoutPathExpansion(::onc::eap::kOuter, &outer);
173   TranslateWithTableAndSet(outer, kEAPOuterTable, shill::kEapMethodProperty);
174
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
180     // Shill.
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);
187     }
188   }
189
190   CopyFieldsAccordingToSignature();
191 }
192
193 void LocalTranslator::TranslateNetworkConfiguration() {
194   std::string type;
195   onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kType,
196                                              &type);
197
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);
201
202   // Shill doesn't allow setting the name for non-VPN networks.
203   if (type == ::onc::network_type::kVPN) {
204     std::string name;
205     onc_object_->GetStringWithoutPathExpansion(::onc::network_config::kName,
206                                                &name);
207     shill_dictionary_->SetStringWithoutPathExpansion(shill::kNameProperty,
208                                                      name);
209   }
210
211   CopyFieldsAccordingToSignature();
212 }
213
214 void LocalTranslator::CopyFieldsAccordingToSignature() {
215   for (base::DictionaryValue::Iterator it(*onc_object_); !it.IsAtEnd();
216        it.Advance()) {
217     AddValueAccordingToSignature(it.key(),
218                                  make_scoped_ptr(it.value().DeepCopy()));
219   }
220 }
221
222 void LocalTranslator::AddValueAccordingToSignature(
223     const std::string& onc_name,
224     scoped_ptr<base::Value> value) {
225   if (!value || !field_translation_table_)
226     return;
227   std::string shill_property_name;
228   if (!GetShillPropertyName(onc_name,
229                             field_translation_table_,
230                             &shill_property_name))
231     return;
232
233   shill_dictionary_->SetWithoutPathExpansion(shill_property_name,
234                                              value.release());
235 }
236
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,
244                                                      shill_value);
245     return;
246   }
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
249   // later in Shill.
250   LOG(ERROR) << "Value '" << onc_value
251              << "' cannot be translated to Shill property "
252              << shill_property_name;
253 }
254
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();
267        ++it) {
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;
275   }
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();
280
281   // Recurse into nested objects.
282   for (base::DictionaryValue::Iterator it(onc_object); !it.IsAtEnd();
283        it.Advance()) {
284     const base::DictionaryValue* inner_object = NULL;
285     if (!it.value().GetAsDictionary(&inner_object))
286       continue;
287
288     const OncFieldSignature* field_signature =
289         GetFieldSignature(signature, it.key());
290
291     TranslateONCHierarchy(*field_signature->value_signature, *inner_object,
292                           shill_dictionary);
293   }
294 }
295
296 }  // namespace
297
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();
305 }
306
307 }  // namespace onc
308 }  // namespace chromeos