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 #include "chromeos/network/onc/onc_utils.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <utility>
12 
13 #include "base/base64.h"
14 #include "base/json/json_reader.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/values.h"
22 #include "chromeos/network/managed_network_configuration_handler.h"
23 #include "chromeos/network/network_configuration_handler.h"
24 #include "chromeos/network/network_event_log.h"
25 #include "chromeos/network/network_profile.h"
26 #include "chromeos/network/network_profile_handler.h"
27 #include "chromeos/network/network_state.h"
28 #include "chromeos/network/network_state_handler.h"
29 #include "chromeos/network/network_ui_data.h"
30 #include "chromeos/network/onc/onc_mapper.h"
31 #include "chromeos/network/onc/onc_normalizer.h"
32 #include "chromeos/network/onc/onc_signature.h"
33 #include "chromeos/network/onc/onc_translator.h"
34 #include "chromeos/network/onc/onc_utils.h"
35 #include "chromeos/network/onc/onc_validator.h"
36 #include "chromeos/network/tether_constants.h"
37 #include "components/account_id/account_id.h"
38 #include "components/device_event_log/device_event_log.h"
39 #include "components/onc/onc_constants.h"
40 #include "components/onc/onc_pref_names.h"
41 #include "components/prefs/pref_service.h"
42 #include "components/proxy_config/proxy_config_dictionary.h"
43 #include "components/url_formatter/url_fixer.h"
44 #include "components/user_manager/user.h"
45 #include "components/user_manager/user_manager.h"
46 #include "crypto/encryptor.h"
47 #include "crypto/hmac.h"
48 #include "crypto/symmetric_key.h"
49 #include "net/base/host_port_pair.h"
50 #include "net/base/proxy_server.h"
51 #include "net/cert/pem.h"
52 #include "net/cert/x509_certificate.h"
53 #include "net/cert/x509_util_nss.h"
54 #include "net/proxy_resolution/proxy_bypass_rules.h"
55 #include "net/proxy_resolution/proxy_config.h"
56 #include "third_party/cros_system_api/dbus/service_constants.h"
57 #include "url/gurl.h"
58 #include "url/url_constants.h"
59 
60 namespace chromeos {
61 namespace onc {
62 
63 namespace {
64 
65 // Error messages that can be reported when decrypting encrypted ONC.
66 constexpr char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
67 constexpr char kUnableToDecode[] = "Unable to decode encrypted ONC";
68 
69 // Scheme strings for supported |net::ProxyServer::SCHEME_*| enum values.
70 constexpr char kDirectScheme[] = "direct";
71 constexpr char kQuicScheme[] = "quic";
72 constexpr char kSocksScheme[] = "socks";
73 constexpr char kSocks4Scheme[] = "socks4";
74 constexpr char kSocks5Scheme[] = "socks5";
75 
GetString(const base::Value & dict,const char * key)76 std::string GetString(const base::Value& dict, const char* key) {
77   const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
78   if (!value)
79     return std::string();
80   return value->GetString();
81 }
82 
GetString(const base::Value & dict,const char * key,std::string * result)83 bool GetString(const base::Value& dict, const char* key, std::string* result) {
84   const base::Value* value = dict.FindKeyOfType(key, base::Value::Type::STRING);
85   if (!value)
86     return false;
87   *result = value->GetString();
88   return true;
89 }
90 
GetInt(const base::Value & dict,const char * key,int default_value)91 int GetInt(const base::Value& dict, const char* key, int default_value) {
92   const base::Value* value =
93       dict.FindKeyOfType(key, base::Value::Type::INTEGER);
94   if (!value)
95     return default_value;
96   return value->GetInt();
97 }
98 
GetInt(const base::Value & dict,const char * key,int * result)99 bool GetInt(const base::Value& dict, const char* key, int* result) {
100   const base::Value* value =
101       dict.FindKeyOfType(key, base::Value::Type::INTEGER);
102   if (!value)
103     return false;
104   *result = value->GetInt();
105   return true;
106 }
107 
108 // Runs |variable_expander.ExpandString| on the field |fieldname| in
109 // |onc_object|.
ExpandField(const std::string & fieldname,const VariableExpander & variable_expander,base::DictionaryValue * onc_object)110 void ExpandField(const std::string& fieldname,
111                  const VariableExpander& variable_expander,
112                  base::DictionaryValue* onc_object) {
113   std::string field_value;
114   if (!onc_object->GetStringWithoutPathExpansion(fieldname, &field_value))
115     return;
116 
117   variable_expander.ExpandString(&field_value);
118 
119   onc_object->SetKey(fieldname, base::Value(field_value));
120 }
121 
122 // A |Mapper| for masking sensitive fields (e.g. credentials such as
123 // passphrases) in ONC.
124 class OncMaskValues : public Mapper {
125  public:
Mask(const OncValueSignature & signature,const base::Value & onc_object,const std::string & mask)126   static base::Value Mask(const OncValueSignature& signature,
127                           const base::Value& onc_object,
128                           const std::string& mask) {
129     OncMaskValues masker(mask);
130     bool unused_error;
131     return base::Value::FromUniquePtrValue(
132         masker.MapObject(signature, onc_object, &unused_error));
133   }
134 
135  protected:
OncMaskValues(const std::string & mask)136   explicit OncMaskValues(const std::string& mask) : mask_(mask) {}
137 
MapField(const std::string & field_name,const OncValueSignature & object_signature,const base::Value & onc_value,bool * found_unknown_field,bool * error)138   std::unique_ptr<base::Value> MapField(
139       const std::string& field_name,
140       const OncValueSignature& object_signature,
141       const base::Value& onc_value,
142       bool* found_unknown_field,
143       bool* error) override {
144     if (FieldIsCredential(object_signature, field_name)) {
145       // If it's the password field and the substitution string is used, don't
146       // mask it.
147       if (&object_signature == &kEAPSignature &&
148           field_name == ::onc::eap::kPassword &&
149           onc_value.GetString() ==
150               ::onc::substitutes::kPasswordPlaceholderVerbatim) {
151         return Mapper::MapField(field_name, object_signature, onc_value,
152                                 found_unknown_field, error);
153       }
154       return std::unique_ptr<base::Value>(new base::Value(mask_));
155     } else {
156       return Mapper::MapField(field_name, object_signature, onc_value,
157                               found_unknown_field, error);
158     }
159   }
160 
161   // Mask to insert in place of the sensitive values.
162   std::string mask_;
163 };
164 
165 // Returns a map GUID->PEM of all server and authority certificates defined in
166 // the Certificates section of ONC, which is passed in as |certificates|.
GetServerAndCACertsByGUID(const base::ListValue & certificates)167 CertPEMsByGUIDMap GetServerAndCACertsByGUID(
168     const base::ListValue& certificates) {
169   CertPEMsByGUIDMap certs_by_guid;
170   for (const auto& entry : certificates) {
171     const base::DictionaryValue* cert = nullptr;
172     bool entry_is_dictionary = entry.GetAsDictionary(&cert);
173     DCHECK(entry_is_dictionary);
174 
175     std::string guid;
176     cert->GetStringWithoutPathExpansion(::onc::certificate::kGUID, &guid);
177     std::string cert_type;
178     cert->GetStringWithoutPathExpansion(::onc::certificate::kType, &cert_type);
179     if (cert_type != ::onc::certificate::kServer &&
180         cert_type != ::onc::certificate::kAuthority) {
181       continue;
182     }
183     std::string x509_data;
184     cert->GetStringWithoutPathExpansion(::onc::certificate::kX509, &x509_data);
185 
186     std::string der = DecodePEM(x509_data);
187     std::string pem;
188     if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
189       LOG(ERROR) << "Certificate with GUID " << guid
190                  << " is not in PEM encoding.";
191       continue;
192     }
193     certs_by_guid[guid] = pem;
194   }
195 
196   return certs_by_guid;
197 }
198 
199 // Fills HexSSID fields in all entries in the |network_configs| list.
FillInHexSSIDFieldsInNetworks(base::Value * network_configs)200 void FillInHexSSIDFieldsInNetworks(base::Value* network_configs) {
201   for (auto& network : network_configs->GetList())
202     FillInHexSSIDFieldsInOncObject(kNetworkConfigurationSignature, &network);
203 }
204 
205 // Given a GUID->PEM certificate mapping |certs_by_guid|, looks up the PEM
206 // encoded certificate referenced by |guid_ref|. If a match is found, sets
207 // |*pem_encoded| to the PEM encoded certificate and returns true. Otherwise,
208 // returns false.
GUIDRefToPEMEncoding(const CertPEMsByGUIDMap & certs_by_guid,const std::string & guid_ref,std::string * pem_encoded)209 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
210                           const std::string& guid_ref,
211                           std::string* pem_encoded) {
212   CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
213   if (it == certs_by_guid.end()) {
214     LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
215     return false;
216   }
217   *pem_encoded = it->second;
218   if (pem_encoded->empty()) {
219     LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
220     return false;
221   }
222   return true;
223 }
224 
225 // Given a GUID-> PM certificate mapping |certs_by_guid|, attempts to resolve
226 // the certificate referenced by the |key_guid_ref| field in |onc_object|.
227 // * If |onc_object| has no |key_guid_ref| field, returns true.
228 // * If no matching certificate is found in |certs_by_guid|, returns false.
229 // * If a matching certificate is found, removes the |key_guid_ref| field,
230 //   fills the |key_pem| field in |onc_object| and returns true.
ResolveSingleCertRef(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref,const std::string & key_pem,base::DictionaryValue * onc_object)231 bool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
232                           const std::string& key_guid_ref,
233                           const std::string& key_pem,
234                           base::DictionaryValue* onc_object) {
235   std::string guid_ref;
236   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
237     return true;
238 
239   std::string pem_encoded;
240   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
241     return false;
242 
243   onc_object->RemoveKey(key_guid_ref);
244   onc_object->SetKey(key_pem, base::Value(pem_encoded));
245   return true;
246 }
247 
248 // Given a GUID-> PM certificate mapping |certs_by_guid|, attempts to resolve
249 // the certificates referenced by the list-of-strings field |key_guid_ref_list|
250 // in |onc_object|.
251 // * If |key_guid_ref_list| does not exist in |onc_object|, returns true.
252 // * If any element |key_guid_ref_list| can not be found in |certs_by_guid|,
253 //   aborts processing and returns false. |onc_object| is unchanged in this
254 //   case.
255 // * Otherwise, sets |key_pem_list| to be a list-of-strings field in
256 //   |onc_object|, containing all PEM encoded resolved certificates in order and
257 //   returns true.
ResolveCertRefList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref_list,const std::string & key_pem_list,base::DictionaryValue * onc_object)258 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
259                         const std::string& key_guid_ref_list,
260                         const std::string& key_pem_list,
261                         base::DictionaryValue* onc_object) {
262   const base::ListValue* guid_ref_list = nullptr;
263   if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
264                                                &guid_ref_list)) {
265     return true;
266   }
267 
268   std::unique_ptr<base::ListValue> pem_list(new base::ListValue);
269   for (const auto& entry : *guid_ref_list) {
270     std::string guid_ref;
271     bool entry_is_string = entry.GetAsString(&guid_ref);
272     DCHECK(entry_is_string);
273 
274     std::string pem_encoded;
275     if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
276       return false;
277 
278     pem_list->AppendString(pem_encoded);
279   }
280 
281   onc_object->RemoveKey(key_guid_ref_list);
282   onc_object->SetWithoutPathExpansion(key_pem_list, std::move(pem_list));
283   return true;
284 }
285 
286 // Same as |ResolveSingleCertRef|, but the output |key_pem_list| will be set to
287 // a list with exactly one value when resolution succeeds.
ResolveSingleCertRefToList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_ref,const std::string & key_pem_list,base::DictionaryValue * onc_object)288 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
289                                 const std::string& key_guid_ref,
290                                 const std::string& key_pem_list,
291                                 base::DictionaryValue* onc_object) {
292   std::string guid_ref;
293   if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
294     return true;
295 
296   std::string pem_encoded;
297   if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
298     return false;
299 
300   std::unique_ptr<base::ListValue> pem_list(new base::ListValue);
301   pem_list->AppendString(pem_encoded);
302   onc_object->RemoveKey(key_guid_ref);
303   onc_object->SetWithoutPathExpansion(key_pem_list, std::move(pem_list));
304   return true;
305 }
306 
307 // Resolves the reference list at |key_guid_refs| if present and otherwise the
308 // single reference at |key_guid_ref|. Returns whether the respective resolving
309 // was successful.
ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap & certs_by_guid,const std::string & key_guid_refs,const std::string & key_guid_ref,const std::string & key_pem_list,base::DictionaryValue * onc_object)310 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
311                                 const std::string& key_guid_refs,
312                                 const std::string& key_guid_ref,
313                                 const std::string& key_pem_list,
314                                 base::DictionaryValue* onc_object) {
315   if (onc_object->HasKey(key_guid_refs)) {
316     if (onc_object->HasKey(key_guid_ref)) {
317       LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
318                  << ". Ignoring and removing the latter.";
319       onc_object->RemoveKey(key_guid_ref);
320     }
321     return ResolveCertRefList(certs_by_guid, key_guid_refs, key_pem_list,
322                               onc_object);
323   }
324 
325   // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
326   return ResolveSingleCertRefToList(certs_by_guid, key_guid_ref, key_pem_list,
327                                     onc_object);
328 }
329 
330 // Resolve known server and authority certiifcate reference fields in
331 // |onc_object|.
ResolveServerCertRefsInObject(const CertPEMsByGUIDMap & certs_by_guid,const OncValueSignature & signature,base::DictionaryValue * onc_object)332 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
333                                    const OncValueSignature& signature,
334                                    base::DictionaryValue* onc_object) {
335   if (&signature == &kCertificatePatternSignature) {
336     if (!ResolveCertRefList(certs_by_guid, ::onc::client_cert::kIssuerCARef,
337                             ::onc::client_cert::kIssuerCAPEMs, onc_object)) {
338       return false;
339     }
340   } else if (&signature == &kEAPSignature) {
341     if (!ResolveCertRefsOrRefToList(certs_by_guid, ::onc::eap::kServerCARefs,
342                                     ::onc::eap::kServerCARef,
343                                     ::onc::eap::kServerCAPEMs, onc_object)) {
344       return false;
345     }
346   } else if (&signature == &kIPsecSignature) {
347     if (!ResolveCertRefsOrRefToList(certs_by_guid, ::onc::ipsec::kServerCARefs,
348                                     ::onc::ipsec::kServerCARef,
349                                     ::onc::ipsec::kServerCAPEMs, onc_object)) {
350       return false;
351     }
352   } else if (&signature == &kIPsecSignature ||
353              &signature == &kOpenVPNSignature) {
354     if (!ResolveSingleCertRef(certs_by_guid, ::onc::openvpn::kServerCertRef,
355                               ::onc::openvpn::kServerCertPEM, onc_object) ||
356         !ResolveCertRefsOrRefToList(
357             certs_by_guid, ::onc::openvpn::kServerCARefs,
358             ::onc::openvpn::kServerCARef, ::onc::openvpn::kServerCAPEMs,
359             onc_object)) {
360       return false;
361     }
362   }
363 
364   // Recurse into nested objects.
365   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
366        it.Advance()) {
367     base::DictionaryValue* inner_object = nullptr;
368     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
369       continue;
370 
371     const OncFieldSignature* field_signature =
372         GetFieldSignature(signature, it.key());
373     if (!field_signature)
374       continue;
375 
376     if (!ResolveServerCertRefsInObject(
377             certs_by_guid, *field_signature->value_signature, inner_object)) {
378       return false;
379     }
380   }
381   return true;
382 }
383 
ConvertOncProxyLocationToHostPort(net::ProxyServer::Scheme default_proxy_scheme,const base::Value & onc_proxy_location)384 net::ProxyServer ConvertOncProxyLocationToHostPort(
385     net::ProxyServer::Scheme default_proxy_scheme,
386     const base::Value& onc_proxy_location) {
387   std::string host = GetString(onc_proxy_location, ::onc::proxy::kHost);
388   // Parse |host| according to the format [<scheme>"://"]<server>[":"<port>].
389   net::ProxyServer proxy_server =
390       net::ProxyServer::FromURI(host, default_proxy_scheme);
391   int port = GetInt(onc_proxy_location, ::onc::proxy::kPort, 0);
392 
393   // Replace the port parsed from |host| by the provided |port|.
394   return net::ProxyServer(
395       proxy_server.scheme(),
396       net::HostPortPair(proxy_server.host_port_pair().host(),
397                         static_cast<uint16_t>(port)));
398 }
399 
AppendProxyServerForScheme(const base::Value & onc_manual,const std::string & onc_scheme,std::string * spec)400 void AppendProxyServerForScheme(const base::Value& onc_manual,
401                                 const std::string& onc_scheme,
402                                 std::string* spec) {
403   const base::Value* onc_proxy_location = onc_manual.FindKey(onc_scheme);
404   if (!onc_proxy_location)
405     return;
406 
407   net::ProxyServer::Scheme default_proxy_scheme = net::ProxyServer::SCHEME_HTTP;
408   std::string url_scheme;
409   if (onc_scheme == ::onc::proxy::kFtp) {
410     url_scheme = url::kFtpScheme;
411   } else if (onc_scheme == ::onc::proxy::kHttp) {
412     url_scheme = url::kHttpScheme;
413   } else if (onc_scheme == ::onc::proxy::kHttps) {
414     url_scheme = url::kHttpsScheme;
415   } else if (onc_scheme == ::onc::proxy::kSocks) {
416     default_proxy_scheme = net::ProxyServer::SCHEME_SOCKS4;
417     url_scheme = kSocksScheme;
418   } else {
419     NOTREACHED();
420   }
421 
422   net::ProxyServer proxy_server = ConvertOncProxyLocationToHostPort(
423       default_proxy_scheme, *onc_proxy_location);
424 
425   ProxyConfigDictionary::EncodeAndAppendProxyServer(url_scheme, proxy_server,
426                                                     spec);
427 }
428 
ConvertOncExcludeDomainsToBypassRules(const base::Value & onc_exclude_domains)429 net::ProxyBypassRules ConvertOncExcludeDomainsToBypassRules(
430     const base::Value& onc_exclude_domains) {
431   net::ProxyBypassRules rules;
432   for (const base::Value& value : onc_exclude_domains.GetList()) {
433     if (!value.is_string()) {
434       LOG(ERROR) << "Badly formatted ONC exclude domains";
435       continue;
436     }
437     rules.AddRuleFromString(value.GetString());
438   }
439   return rules;
440 }
441 
SchemeToString(net::ProxyServer::Scheme scheme)442 std::string SchemeToString(net::ProxyServer::Scheme scheme) {
443   switch (scheme) {
444     case net::ProxyServer::SCHEME_DIRECT:
445       return kDirectScheme;
446     case net::ProxyServer::SCHEME_HTTP:
447       return url::kHttpScheme;
448     case net::ProxyServer::SCHEME_SOCKS4:
449       return kSocks4Scheme;
450     case net::ProxyServer::SCHEME_SOCKS5:
451       return kSocks5Scheme;
452     case net::ProxyServer::SCHEME_HTTPS:
453       return url::kHttpsScheme;
454     case net::ProxyServer::SCHEME_QUIC:
455       return kQuicScheme;
456     case net::ProxyServer::SCHEME_INVALID:
457       break;
458   }
459   NOTREACHED();
460   return "";
461 }
462 
SetProxyForScheme(const net::ProxyConfig::ProxyRules & proxy_rules,const std::string & scheme,const std::string & onc_scheme,base::DictionaryValue * dict)463 void SetProxyForScheme(const net::ProxyConfig::ProxyRules& proxy_rules,
464                        const std::string& scheme,
465                        const std::string& onc_scheme,
466                        base::DictionaryValue* dict) {
467   const net::ProxyList* proxy_list = nullptr;
468   if (proxy_rules.type == net::ProxyConfig::ProxyRules::Type::PROXY_LIST) {
469     proxy_list = &proxy_rules.single_proxies;
470   } else if (proxy_rules.type ==
471              net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME) {
472     proxy_list = proxy_rules.MapUrlSchemeToProxyList(scheme);
473   }
474   if (!proxy_list || proxy_list->IsEmpty())
475     return;
476   const net::ProxyServer& server = proxy_list->Get();
477   std::unique_ptr<base::DictionaryValue> url_dict(new base::DictionaryValue);
478   std::string host = server.host_port_pair().host();
479 
480   // For all proxy types except SOCKS, the default scheme of the proxy host is
481   // HTTP.
482   net::ProxyServer::Scheme default_scheme =
483       (onc_scheme == ::onc::proxy::kSocks) ? net::ProxyServer::SCHEME_SOCKS4
484                                            : net::ProxyServer::SCHEME_HTTP;
485   // Only prefix the host with a non-default scheme.
486   if (server.scheme() != default_scheme)
487     host = SchemeToString(server.scheme()) + "://" + host;
488   url_dict->SetKey(::onc::proxy::kHost, base::Value(host));
489   url_dict->SetKey(::onc::proxy::kPort,
490                    base::Value(server.host_port_pair().port()));
491   dict->SetWithoutPathExpansion(onc_scheme, std::move(url_dict));
492 }
493 
494 // Returns the NetworkConfiugration with |guid| from |network_configs|, or
495 // nullptr if no such NetworkConfiguration is found.
GetNetworkConfigByGUID(const base::ListValue & network_configs,const std::string & guid)496 const base::DictionaryValue* GetNetworkConfigByGUID(
497     const base::ListValue& network_configs,
498     const std::string& guid) {
499   for (base::ListValue::const_iterator it = network_configs.begin();
500        it != network_configs.end(); ++it) {
501     const base::DictionaryValue* network = NULL;
502     it->GetAsDictionary(&network);
503     DCHECK(network);
504 
505     std::string current_guid;
506     network->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
507                                            &current_guid);
508     if (current_guid == guid)
509       return network;
510   }
511   return NULL;
512 }
513 
514 // Returns the first Ethernet NetworkConfiguration from |network_configs| with
515 // "Authentication: None", or nullptr if no such NetworkConfiguration is found.
GetNetworkConfigForEthernetWithoutEAP(const base::ListValue & network_configs)516 const base::DictionaryValue* GetNetworkConfigForEthernetWithoutEAP(
517     const base::ListValue& network_configs) {
518   VLOG(2) << "Search for ethernet policy without EAP.";
519   for (base::ListValue::const_iterator it = network_configs.begin();
520        it != network_configs.end(); ++it) {
521     const base::DictionaryValue* network = NULL;
522     it->GetAsDictionary(&network);
523     DCHECK(network);
524 
525     std::string type;
526     network->GetStringWithoutPathExpansion(::onc::network_config::kType, &type);
527     if (type != ::onc::network_type::kEthernet)
528       continue;
529 
530     const base::DictionaryValue* ethernet = NULL;
531     network->GetDictionaryWithoutPathExpansion(::onc::network_config::kEthernet,
532                                                &ethernet);
533 
534     std::string auth;
535     ethernet->GetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
536                                             &auth);
537     if (auth == ::onc::ethernet::kAuthenticationNone)
538       return network;
539   }
540   return NULL;
541 }
542 
543 // Returns the NetworkConfiguration object for |network| from
544 // |network_configs| or nullptr if no matching NetworkConfiguration is found. If
545 // |network| is a non-Ethernet network, performs a lookup by GUID. If |network|
546 // is an Ethernet network, tries lookup of the GUID of the shared EthernetEAP
547 // service, or otherwise returns the first Ethernet NetworkConfiguration with
548 // "Authentication: None".
GetNetworkConfigForNetworkFromOnc(const base::ListValue & network_configs,const NetworkState & network)549 const base::DictionaryValue* GetNetworkConfigForNetworkFromOnc(
550     const base::ListValue& network_configs,
551     const NetworkState& network) {
552   // In all cases except Ethernet, we use the GUID of |network|.
553   if (!network.Matches(NetworkTypePattern::Ethernet()))
554     return GetNetworkConfigByGUID(network_configs, network.guid());
555 
556   // Ethernet is always shared and thus cannot store a GUID per user. Thus we
557   // search for any Ethernet policy intead of a matching GUID.
558   // EthernetEAP service contains only the EAP parameters and stores the GUID of
559   // the respective ONC policy. The EthernetEAP service itself is however never
560   // in state "connected". An EthernetEAP policy must be applied, if an Ethernet
561   // service is connected using the EAP parameters.
562   const NetworkState* ethernet_eap = nullptr;
563   if (NetworkHandler::IsInitialized()) {
564     ethernet_eap =
565         NetworkHandler::Get()->network_state_handler()->GetEAPForEthernet(
566             network.path(), /*connected_only=*/true);
567   }
568 
569   // The GUID associated with the EthernetEAP service refers to the ONC policy
570   // with "Authentication: 8021X".
571   if (ethernet_eap)
572     return GetNetworkConfigByGUID(network_configs, ethernet_eap->guid());
573 
574   // Otherwise, EAP is not used and instead the Ethernet policy with
575   // "Authentication: None" applies.
576   return GetNetworkConfigForEthernetWithoutEAP(network_configs);
577 }
578 
579 // Expects |pref_name| in |pref_service| to be a pref holding an ONC blob.
580 // Returns the NetworkConfiguration ONC object for |network| from this ONC, or
581 // nullptr if no configuration is found. See |GetNetworkConfigForNetworkFromOnc|
582 // for the NetworkConfiguration lookup rules.
GetPolicyForNetworkFromPref(const PrefService * pref_service,const char * pref_name,const NetworkState & network)583 const base::DictionaryValue* GetPolicyForNetworkFromPref(
584     const PrefService* pref_service,
585     const char* pref_name,
586     const NetworkState& network) {
587   if (!pref_service) {
588     VLOG(2) << "No pref service";
589     return NULL;
590   }
591 
592   const PrefService::Preference* preference =
593       pref_service->FindPreference(pref_name);
594   if (!preference) {
595     VLOG(2) << "No preference " << pref_name;
596     // The preference may not exist in tests.
597     return NULL;
598   }
599 
600   // User prefs are not stored in this Preference yet but only the policy.
601   //
602   // The policy server incorrectly configures the OpenNetworkConfiguration user
603   // policy as Recommended. To work around that, we handle the Recommended and
604   // the Mandatory value in the same way.
605   // TODO(pneubeck): Remove this workaround, once the server is fixed. See
606   // http://crbug.com/280553 .
607   if (preference->IsDefaultValue()) {
608     VLOG(2) << "Preference has no recommended or mandatory value.";
609     // No policy set.
610     return NULL;
611   }
612   VLOG(2) << "Preference with policy found.";
613   const base::Value* onc_policy_value = preference->GetValue();
614   DCHECK(onc_policy_value);
615 
616   const base::ListValue* onc_policy = NULL;
617   onc_policy_value->GetAsList(&onc_policy);
618   DCHECK(onc_policy);
619 
620   return GetNetworkConfigForNetworkFromOnc(*onc_policy, network);
621 }
622 
623 // Returns the global network configuration dictionary from the ONC policy of
624 // the active user if |for_active_user| is true, or from device policy if it is
625 // false.
GetGlobalConfigFromPolicy(bool for_active_user)626 const base::DictionaryValue* GetGlobalConfigFromPolicy(bool for_active_user) {
627   std::string username_hash;
628   if (for_active_user) {
629     const user_manager::User* user =
630         user_manager::UserManager::Get()->GetActiveUser();
631     if (!user) {
632       LOG(ERROR) << "No user logged in yet.";
633       return NULL;
634     }
635     username_hash = user->username_hash();
636   }
637   return NetworkHandler::Get()
638       ->managed_network_configuration_handler()
639       ->GetGlobalConfigFromPolicy(username_hash);
640 }
641 
642 }  // namespace
643 
644 const char kEmptyUnencryptedConfiguration[] =
645     "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
646     "\"Certificates\":[]}";
647 
ReadDictionaryFromJson(const std::string & json)648 base::Value ReadDictionaryFromJson(const std::string& json) {
649   if (json.empty()) {
650     // Policy may contain empty values, just log a debug message.
651     NET_LOG(DEBUG) << "Empty json string";
652     return base::Value();
653   }
654   base::JSONReader::ValueWithError parsed_json =
655       base::JSONReader::ReadAndReturnValueWithError(
656           json, base::JSON_ALLOW_TRAILING_COMMAS);
657   if (!parsed_json.value || !parsed_json.value->is_dict()) {
658     NET_LOG(ERROR) << "Invalid JSON Dictionary: " << parsed_json.error_message;
659     return base::Value();
660   }
661   return std::move(*parsed_json.value);
662 }
663 
Decrypt(const std::string & passphrase,const base::Value & root)664 base::Value Decrypt(const std::string& passphrase, const base::Value& root) {
665   const int kKeySizeInBits = 256;
666   const int kMaxIterationCount = 500000;
667   std::string onc_type;
668   std::string initial_vector;
669   std::string salt;
670   std::string cipher;
671   std::string stretch_method;
672   std::string hmac_method;
673   std::string hmac;
674   int iterations;
675   std::string ciphertext;
676 
677   if (!GetString(root, ::onc::encrypted::kCiphertext, &ciphertext) ||
678       !GetString(root, ::onc::encrypted::kCipher, &cipher) ||
679       !GetString(root, ::onc::encrypted::kHMAC, &hmac) ||
680       !GetString(root, ::onc::encrypted::kHMACMethod, &hmac_method) ||
681       !GetString(root, ::onc::encrypted::kIV, &initial_vector) ||
682       !GetInt(root, ::onc::encrypted::kIterations, &iterations) ||
683       !GetString(root, ::onc::encrypted::kSalt, &salt) ||
684       !GetString(root, ::onc::encrypted::kStretch, &stretch_method) ||
685       !GetString(root, ::onc::toplevel_config::kType, &onc_type) ||
686       onc_type != ::onc::toplevel_config::kEncryptedConfiguration) {
687     NET_LOG(ERROR) << "Encrypted ONC malformed.";
688     return base::Value();
689   }
690 
691   if (hmac_method != ::onc::encrypted::kSHA1 ||
692       cipher != ::onc::encrypted::kAES256 ||
693       stretch_method != ::onc::encrypted::kPBKDF2) {
694     NET_LOG(ERROR) << "Encrypted ONC unsupported encryption scheme.";
695     return base::Value();
696   }
697 
698   // Make sure iterations != 0, since that's not valid.
699   if (iterations == 0) {
700     NET_LOG(ERROR) << kUnableToDecrypt;
701     return base::Value();
702   }
703 
704   // Simply a sanity check to make sure we can't lock up the machine
705   // for too long with a huge number (or a negative number).
706   if (iterations < 0 || iterations > kMaxIterationCount) {
707     NET_LOG(ERROR) << "Too many iterations in encrypted ONC";
708     return base::Value();
709   }
710 
711   if (!base::Base64Decode(salt, &salt)) {
712     NET_LOG(ERROR) << kUnableToDecode;
713     return base::Value();
714   }
715 
716   std::unique_ptr<crypto::SymmetricKey> key(
717       crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
718           crypto::SymmetricKey::AES, passphrase, salt, iterations,
719           kKeySizeInBits));
720 
721   if (!base::Base64Decode(initial_vector, &initial_vector)) {
722     NET_LOG(ERROR) << kUnableToDecode;
723     return base::Value();
724   }
725   if (!base::Base64Decode(ciphertext, &ciphertext)) {
726     NET_LOG(ERROR) << kUnableToDecode;
727     return base::Value();
728   }
729   if (!base::Base64Decode(hmac, &hmac)) {
730     NET_LOG(ERROR) << kUnableToDecode;
731     return base::Value();
732   }
733 
734   crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
735   if (!hmac_verifier.Init(key.get()) ||
736       !hmac_verifier.Verify(ciphertext, hmac)) {
737     NET_LOG(ERROR) << kUnableToDecrypt;
738     return base::Value();
739   }
740 
741   crypto::Encryptor decryptor;
742   if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
743     NET_LOG(ERROR) << kUnableToDecrypt;
744     return base::Value();
745   }
746 
747   std::string plaintext;
748   if (!decryptor.Decrypt(ciphertext, &plaintext)) {
749     NET_LOG(ERROR) << kUnableToDecrypt;
750     return base::Value();
751   }
752 
753   base::Value new_root = ReadDictionaryFromJson(plaintext);
754   if (new_root.is_none())
755     NET_LOG(ERROR) << "Property dictionary malformed.";
756 
757   return new_root;
758 }
759 
GetSourceAsString(::onc::ONCSource source)760 std::string GetSourceAsString(::onc::ONCSource source) {
761   switch (source) {
762     case ::onc::ONC_SOURCE_UNKNOWN:
763       return "unknown";
764     case ::onc::ONC_SOURCE_NONE:
765       return "none";
766     case ::onc::ONC_SOURCE_DEVICE_POLICY:
767       return "device policy";
768     case ::onc::ONC_SOURCE_USER_POLICY:
769       return "user policy";
770     case ::onc::ONC_SOURCE_USER_IMPORT:
771       return "user import";
772   }
773   NOTREACHED();
774   return "unknown";
775 }
776 
ExpandStringsInOncObject(const OncValueSignature & signature,const VariableExpander & variable_expander,base::DictionaryValue * onc_object)777 void ExpandStringsInOncObject(const OncValueSignature& signature,
778                               const VariableExpander& variable_expander,
779                               base::DictionaryValue* onc_object) {
780   if (&signature == &kEAPSignature) {
781     ExpandField(::onc::eap::kAnonymousIdentity, variable_expander, onc_object);
782     ExpandField(::onc::eap::kIdentity, variable_expander, onc_object);
783   } else if (&signature == &kL2TPSignature ||
784              &signature == &kOpenVPNSignature) {
785     ExpandField(::onc::vpn::kUsername, variable_expander, onc_object);
786   }
787 
788   // Recurse into nested objects.
789   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
790        it.Advance()) {
791     base::DictionaryValue* inner_object = nullptr;
792     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
793       continue;
794 
795     const OncFieldSignature* field_signature =
796         GetFieldSignature(signature, it.key());
797     if (!field_signature)
798       continue;
799 
800     ExpandStringsInOncObject(*field_signature->value_signature,
801                              variable_expander, inner_object);
802   }
803 }
804 
ExpandStringsInNetworks(const VariableExpander & variable_expander,base::ListValue * network_configs)805 void ExpandStringsInNetworks(const VariableExpander& variable_expander,
806                              base::ListValue* network_configs) {
807   for (auto& entry : *network_configs) {
808     base::DictionaryValue* network = nullptr;
809     entry.GetAsDictionary(&network);
810     DCHECK(network);
811     ExpandStringsInOncObject(kNetworkConfigurationSignature, variable_expander,
812                              network);
813   }
814 }
815 
FillInHexSSIDFieldsInOncObject(const OncValueSignature & signature,base::Value * onc_object)816 void FillInHexSSIDFieldsInOncObject(const OncValueSignature& signature,
817                                     base::Value* onc_object) {
818   DCHECK(onc_object->is_dict());
819   if (&signature == &kWiFiSignature)
820     FillInHexSSIDField(onc_object);
821 
822   // Recurse into nested objects.
823   for (auto it : onc_object->DictItems()) {
824     if (!it.second.is_dict())
825       continue;
826 
827     const OncFieldSignature* field_signature =
828         GetFieldSignature(signature, it.first);
829     if (!field_signature)
830       continue;
831 
832     FillInHexSSIDFieldsInOncObject(*field_signature->value_signature,
833                                    &it.second);
834   }
835 }
836 
FillInHexSSIDField(base::Value * wifi_fields)837 void FillInHexSSIDField(base::Value* wifi_fields) {
838   if (wifi_fields->FindKey(::onc::wifi::kHexSSID))
839     return;
840   base::Value* ssid =
841       wifi_fields->FindKeyOfType(::onc::wifi::kSSID, base::Value::Type::STRING);
842   if (!ssid)
843     return;
844   std::string ssid_string = ssid->GetString();
845   if (ssid_string.empty()) {
846     NET_LOG(ERROR) << "Found empty SSID field.";
847     return;
848   }
849   wifi_fields->SetKey(
850       ::onc::wifi::kHexSSID,
851       base::Value(base::HexEncode(ssid_string.c_str(), ssid_string.size())));
852 }
853 
MaskCredentialsInOncObject(const OncValueSignature & signature,const base::Value & onc_object,const std::string & mask)854 base::Value MaskCredentialsInOncObject(const OncValueSignature& signature,
855                                        const base::Value& onc_object,
856                                        const std::string& mask) {
857   return OncMaskValues::Mask(signature, onc_object, mask);
858 }
859 
DecodePEM(const std::string & pem_encoded)860 std::string DecodePEM(const std::string& pem_encoded) {
861   // The PEM block header used for DER certificates
862   const char kCertificateHeader[] = "CERTIFICATE";
863 
864   // This is an older PEM marker for DER certificates.
865   const char kX509CertificateHeader[] = "X509 CERTIFICATE";
866 
867   std::vector<std::string> pem_headers;
868   pem_headers.push_back(kCertificateHeader);
869   pem_headers.push_back(kX509CertificateHeader);
870 
871   net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
872   std::string decoded;
873   if (pem_tokenizer.GetNext()) {
874     decoded = pem_tokenizer.data();
875   } else {
876     // If we failed to read the data as a PEM file, then try plain base64 decode
877     // in case the PEM marker strings are missing. For this to work, there has
878     // to be no white space, and it has to only contain the base64-encoded data.
879     if (!base::Base64Decode(pem_encoded, &decoded)) {
880       LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
881       return std::string();
882     }
883   }
884   return decoded;
885 }
886 
ParseAndValidateOncForImport(const std::string & onc_blob,::onc::ONCSource onc_source,const std::string & passphrase,base::ListValue * network_configs,base::DictionaryValue * global_network_config,base::ListValue * certificates)887 bool ParseAndValidateOncForImport(const std::string& onc_blob,
888                                   ::onc::ONCSource onc_source,
889                                   const std::string& passphrase,
890                                   base::ListValue* network_configs,
891                                   base::DictionaryValue* global_network_config,
892                                   base::ListValue* certificates) {
893   if (network_configs)
894     network_configs->Clear();
895   if (global_network_config)
896     global_network_config->Clear();
897   if (certificates)
898     certificates->Clear();
899   if (onc_blob.empty())
900     return true;
901 
902   base::Value toplevel_onc = ReadDictionaryFromJson(onc_blob);
903   if (toplevel_onc.is_none()) {
904     NET_LOG(ERROR) << "Not a valid ONC JSON dictionary: "
905                    << GetSourceAsString(onc_source);
906     return false;
907   }
908 
909   // Check and see if this is an encrypted ONC file. If so, decrypt it.
910   std::string onc_type;
911   if (GetString(toplevel_onc, ::onc::toplevel_config::kType, &onc_type) &&
912       onc_type == ::onc::toplevel_config::kEncryptedConfiguration) {
913     toplevel_onc = Decrypt(passphrase, toplevel_onc);
914     if (toplevel_onc.is_none()) {
915       NET_LOG(ERROR) << "Unable to decrypt ONC from "
916                      << GetSourceAsString(onc_source);
917       return false;
918     }
919   }
920 
921   bool from_policy = (onc_source == ::onc::ONC_SOURCE_USER_POLICY ||
922                       onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY);
923 
924   // Validate the ONC dictionary. We are liberal and ignore unknown field
925   // names and ignore invalid field names in kRecommended arrays.
926   Validator validator(false,  // Ignore unknown fields.
927                       false,  // Ignore invalid recommended field names.
928                       true,   // Fail on missing fields.
929                       from_policy,
930                       true);  // Log warnings.
931   validator.SetOncSource(onc_source);
932 
933   Validator::Result validation_result;
934   std::unique_ptr<base::DictionaryValue> validated_toplevel_onc =
935       validator.ValidateAndRepairObject(&kToplevelConfigurationSignature,
936                                         toplevel_onc, &validation_result);
937 
938   if (from_policy) {
939     UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
940                           validation_result == Validator::VALID);
941   }
942 
943   bool success = true;
944   if (validation_result == Validator::VALID_WITH_WARNINGS) {
945     NET_LOG(DEBUG) << "ONC validation produced warnings: "
946                    << GetSourceAsString(onc_source);
947     success = false;
948   } else if (validation_result == Validator::INVALID ||
949              !validated_toplevel_onc) {
950     NET_LOG(ERROR) << "ONC is invalid and couldn't be repaired: "
951                    << GetSourceAsString(onc_source);
952     return false;
953   }
954 
955   if (certificates) {
956     base::Value* validated_certs = validated_toplevel_onc->FindKeyOfType(
957         ::onc::toplevel_config::kCertificates, base::Value::Type::LIST);
958     if (validated_certs)
959       *certificates = base::ListValue(validated_certs->TakeList());
960   }
961 
962   // Note that this processing is performed even if |network_configs| is
963   // nullptr, because ResolveServerCertRefsInNetworks could affect the return
964   // value of the function (which is supposed to aggregate validation issues in
965   // all segments of the ONC blob).
966   base::Value* validated_networks = validated_toplevel_onc->FindKeyOfType(
967       ::onc::toplevel_config::kNetworkConfigurations, base::Value::Type::LIST);
968   base::ListValue* validated_networks_list;
969   if (validated_networks &&
970       validated_networks->GetAsList(&validated_networks_list)) {
971     FillInHexSSIDFieldsInNetworks(validated_networks_list);
972 
973     CertPEMsByGUIDMap server_and_ca_certs =
974         GetServerAndCACertsByGUID(*certificates);
975 
976     if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
977                                          validated_networks_list)) {
978       NET_LOG(ERROR) << "Some certificate references in the ONC policy could "
979                         "not be resolved: "
980                      << GetSourceAsString(onc_source);
981       success = false;
982     }
983 
984     if (network_configs)
985       network_configs->Swap(validated_networks_list);
986   }
987 
988   if (global_network_config) {
989     base::Value* validated_global_config =
990         validated_toplevel_onc->FindKeyOfType(
991             ::onc::toplevel_config::kGlobalNetworkConfiguration,
992             base::Value::Type::DICTIONARY);
993     if (validated_global_config) {
994       base::DictionaryValue* validated_global_config_dict = nullptr;
995       if (validated_global_config->GetAsDictionary(
996               &validated_global_config_dict)) {
997         global_network_config->Swap(validated_global_config_dict);
998       }
999     }
1000   }
1001 
1002   return success;
1003 }
1004 
DecodePEMCertificate(const std::string & pem_encoded)1005 net::ScopedCERTCertificate DecodePEMCertificate(
1006     const std::string& pem_encoded) {
1007   std::string decoded = DecodePEM(pem_encoded);
1008   net::ScopedCERTCertificate cert =
1009       net::x509_util::CreateCERTCertificateFromBytes(
1010           reinterpret_cast<const uint8_t*>(decoded.data()), decoded.size());
1011   LOG_IF(ERROR, !cert.get())
1012       << "Couldn't create certificate from X509 data: " << decoded;
1013   return cert;
1014 }
1015 
ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap & certs_by_guid,base::ListValue * network_configs)1016 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
1017                                      base::ListValue* network_configs) {
1018   bool success = true;
1019   for (base::ListValue::iterator it = network_configs->begin();
1020        it != network_configs->end();) {
1021     base::DictionaryValue* network = nullptr;
1022     it->GetAsDictionary(&network);
1023     if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
1024       std::string guid;
1025       network->GetStringWithoutPathExpansion(::onc::network_config::kGUID,
1026                                              &guid);
1027       // This might happen even with correct validation, if the referenced
1028       // certificate couldn't be imported.
1029       LOG(ERROR) << "Couldn't resolve some certificate reference of network "
1030                  << guid;
1031       it = network_configs->Erase(it, nullptr);
1032       success = false;
1033       continue;
1034     }
1035     ++it;
1036   }
1037   return success;
1038 }
1039 
ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap & certs_by_guid,base::DictionaryValue * network_config)1040 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
1041                                     base::DictionaryValue* network_config) {
1042   return ResolveServerCertRefsInObject(
1043       certs_by_guid, kNetworkConfigurationSignature, network_config);
1044 }
1045 
NetworkTypePatternFromOncType(const std::string & type)1046 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
1047   if (type == ::onc::network_type::kAllTypes)
1048     return NetworkTypePattern::Default();
1049   if (type == ::onc::network_type::kCellular)
1050     return NetworkTypePattern::Cellular();
1051   if (type == ::onc::network_type::kEthernet)
1052     return NetworkTypePattern::Ethernet();
1053   if (type == ::onc::network_type::kTether)
1054     return NetworkTypePattern::Tether();
1055   if (type == ::onc::network_type::kVPN)
1056     return NetworkTypePattern::VPN();
1057   if (type == ::onc::network_type::kWiFi)
1058     return NetworkTypePattern::WiFi();
1059   if (type == ::onc::network_type::kWireless)
1060     return NetworkTypePattern::Wireless();
1061   NET_LOG(ERROR) << "Unrecognized ONC type: " << type;
1062   return NetworkTypePattern::Default();
1063 }
1064 
ConvertOncProxySettingsToProxyConfig(const base::Value & onc_proxy_settings)1065 base::Value ConvertOncProxySettingsToProxyConfig(
1066     const base::Value& onc_proxy_settings) {
1067   std::string type = GetString(onc_proxy_settings, ::onc::proxy::kType);
1068 
1069   if (type == ::onc::proxy::kDirect) {
1070     return ProxyConfigDictionary::CreateDirect();
1071   }
1072   if (type == ::onc::proxy::kWPAD) {
1073     return ProxyConfigDictionary::CreateAutoDetect();
1074   }
1075   if (type == ::onc::proxy::kPAC) {
1076     std::string pac_url = GetString(onc_proxy_settings, ::onc::proxy::kPAC);
1077     GURL url(url_formatter::FixupURL(pac_url, std::string()));
1078     return ProxyConfigDictionary::CreatePacScript(
1079         url.is_valid() ? url.spec() : std::string(), false);
1080   }
1081   if (type == ::onc::proxy::kManual) {
1082     const base::Value* manual_dict =
1083         onc_proxy_settings.FindKey(::onc::proxy::kManual);
1084     if (!manual_dict) {
1085       NET_LOG(ERROR) << "Manual proxy missing dictionary";
1086       return base::Value();
1087     }
1088     std::string manual_spec;
1089     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kFtp, &manual_spec);
1090     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttp, &manual_spec);
1091     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kSocks,
1092                                &manual_spec);
1093     AppendProxyServerForScheme(*manual_dict, ::onc::proxy::kHttps,
1094                                &manual_spec);
1095 
1096     net::ProxyBypassRules bypass_rules;
1097     const base::Value* exclude_domains = onc_proxy_settings.FindKeyOfType(
1098         ::onc::proxy::kExcludeDomains, base::Value::Type::LIST);
1099     if (exclude_domains)
1100       bypass_rules = ConvertOncExcludeDomainsToBypassRules(*exclude_domains);
1101     return ProxyConfigDictionary::CreateFixedServers(manual_spec,
1102                                                      bypass_rules.ToString());
1103   }
1104   NOTREACHED();
1105   return base::Value();
1106 }
1107 
ConvertProxyConfigToOncProxySettings(const base::Value & proxy_config_value)1108 base::Value ConvertProxyConfigToOncProxySettings(
1109     const base::Value& proxy_config_value) {
1110   DCHECK(proxy_config_value.is_dict());
1111 
1112   // Create a ProxyConfigDictionary from the dictionary.
1113   ProxyConfigDictionary proxy_config(proxy_config_value.Clone());
1114 
1115   // Create the result DictionaryValue and populate it.
1116   base::Value proxy_settings(base::Value::Type::DICTIONARY);
1117   ProxyPrefs::ProxyMode mode;
1118   if (!proxy_config.GetMode(&mode))
1119     return base::Value();
1120   switch (mode) {
1121     case ProxyPrefs::MODE_DIRECT: {
1122       proxy_settings.SetKey(::onc::proxy::kType,
1123                             base::Value(::onc::proxy::kDirect));
1124       break;
1125     }
1126     case ProxyPrefs::MODE_AUTO_DETECT: {
1127       proxy_settings.SetKey(::onc::proxy::kType,
1128                             base::Value(::onc::proxy::kWPAD));
1129       break;
1130     }
1131     case ProxyPrefs::MODE_PAC_SCRIPT: {
1132       proxy_settings.SetKey(::onc::proxy::kType,
1133                             base::Value(::onc::proxy::kPAC));
1134       std::string pac_url;
1135       proxy_config.GetPacUrl(&pac_url);
1136       proxy_settings.SetKey(::onc::proxy::kPAC, base::Value(pac_url));
1137       break;
1138     }
1139     case ProxyPrefs::MODE_FIXED_SERVERS: {
1140       proxy_settings.SetKey(::onc::proxy::kType,
1141                             base::Value(::onc::proxy::kManual));
1142       base::DictionaryValue manual;
1143       std::string proxy_rules_string;
1144       if (proxy_config.GetProxyServer(&proxy_rules_string)) {
1145         net::ProxyConfig::ProxyRules proxy_rules;
1146         proxy_rules.ParseFromString(proxy_rules_string);
1147         SetProxyForScheme(proxy_rules, url::kFtpScheme, ::onc::proxy::kFtp,
1148                           &manual);
1149         SetProxyForScheme(proxy_rules, url::kHttpScheme, ::onc::proxy::kHttp,
1150                           &manual);
1151         SetProxyForScheme(proxy_rules, url::kHttpsScheme, ::onc::proxy::kHttps,
1152                           &manual);
1153         SetProxyForScheme(proxy_rules, kSocksScheme, ::onc::proxy::kSocks,
1154                           &manual);
1155       }
1156       proxy_settings.SetKey(::onc::proxy::kManual, std::move(manual));
1157 
1158       // Convert the 'bypass_list' string into dictionary entries.
1159       std::string bypass_rules_string;
1160       if (proxy_config.GetBypassList(&bypass_rules_string)) {
1161         net::ProxyBypassRules bypass_rules;
1162         bypass_rules.ParseFromString(bypass_rules_string);
1163         base::ListValue exclude_domains;
1164         for (const auto& rule : bypass_rules.rules())
1165           exclude_domains.AppendString(rule->ToString());
1166         if (!exclude_domains.empty()) {
1167           proxy_settings.SetKey(::onc::proxy::kExcludeDomains,
1168                                 std::move(exclude_domains));
1169         }
1170       }
1171       break;
1172     }
1173     default: {
1174       LOG(ERROR) << "Unexpected proxy mode in Shill config: " << mode;
1175       return base::Value();
1176     }
1177   }
1178   return proxy_settings;
1179 }
1180 
ExpandStringPlaceholdersInNetworksForUser(const user_manager::User * user,base::ListValue * network_configs)1181 void ExpandStringPlaceholdersInNetworksForUser(
1182     const user_manager::User* user,
1183     base::ListValue* network_configs) {
1184   if (!user) {
1185     // In tests no user may be logged in. It's not harmful if we just don't
1186     // expand the strings.
1187     return;
1188   }
1189 
1190   // Note: It is OK for the placeholders to be replaced with empty strings if
1191   // that is what the getters on |user| provide.
1192   std::map<std::string, std::string> substitutions;
1193   substitutions[::onc::substitutes::kLoginID] = user->GetAccountName(false);
1194   substitutions[::onc::substitutes::kLoginEmail] =
1195       user->GetAccountId().GetUserEmail();
1196   VariableExpander variable_expander(std::move(substitutions));
1197   chromeos::onc::ExpandStringsInNetworks(variable_expander, network_configs);
1198 }
1199 
ImportNetworksForUser(const user_manager::User * user,const base::ListValue & network_configs,std::string * error)1200 int ImportNetworksForUser(const user_manager::User* user,
1201                           const base::ListValue& network_configs,
1202                           std::string* error) {
1203   error->clear();
1204 
1205   std::unique_ptr<base::ListValue> expanded_networks(
1206       network_configs.DeepCopy());
1207   ExpandStringPlaceholdersInNetworksForUser(user, expanded_networks.get());
1208 
1209   const NetworkProfile* profile =
1210       NetworkHandler::Get()->network_profile_handler()->GetProfileForUserhash(
1211           user->username_hash());
1212   if (!profile) {
1213     *error = "User profile doesn't exist for: " + user->display_email();
1214     return 0;
1215   }
1216 
1217   bool ethernet_not_found = false;
1218   int networks_created = 0;
1219   for (base::ListValue::const_iterator it = expanded_networks->begin();
1220        it != expanded_networks->end(); ++it) {
1221     const base::DictionaryValue* network = NULL;
1222     it->GetAsDictionary(&network);
1223     DCHECK(network);
1224 
1225     // Remove irrelevant fields.
1226     onc::Normalizer normalizer(true /* remove recommended fields */);
1227     std::unique_ptr<base::DictionaryValue> normalized_network =
1228         normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
1229                                    *network);
1230 
1231     // TODO(pneubeck): Use ONC and ManagedNetworkConfigurationHandler instead.
1232     // crbug.com/457936
1233     std::unique_ptr<base::DictionaryValue> shill_dict =
1234         onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
1235                                        *normalized_network);
1236 
1237     std::unique_ptr<NetworkUIData> ui_data(
1238         NetworkUIData::CreateFromONC(::onc::ONC_SOURCE_USER_IMPORT));
1239     shill_dict->SetKey(shill::kUIDataProperty,
1240                        base::Value(ui_data->GetAsJson()));
1241     shill_dict->SetKey(shill::kProfileProperty, base::Value(profile->path));
1242 
1243     std::string type;
1244     shill_dict->GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
1245     NetworkConfigurationHandler* config_handler =
1246         NetworkHandler::Get()->network_configuration_handler();
1247     if (NetworkTypePattern::Ethernet().MatchesType(type)) {
1248       // Ethernet has to be configured using an existing Ethernet service.
1249       const NetworkState* ethernet =
1250           NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
1251               NetworkTypePattern::Ethernet());
1252       if (ethernet) {
1253         config_handler->SetShillProperties(ethernet->path(), *shill_dict,
1254                                            base::OnceClosure(),
1255                                            network_handler::ErrorCallback());
1256       } else {
1257         ethernet_not_found = true;
1258       }
1259 
1260     } else {
1261       config_handler->CreateShillConfiguration(
1262           *shill_dict, network_handler::ServiceResultCallback(),
1263           network_handler::ErrorCallback());
1264       ++networks_created;
1265     }
1266   }
1267 
1268   if (ethernet_not_found)
1269     *error = "No Ethernet available to configure.";
1270   return networks_created;
1271 }
1272 
FindPolicyForActiveUser(const std::string & guid,::onc::ONCSource * onc_source)1273 const base::DictionaryValue* FindPolicyForActiveUser(
1274     const std::string& guid,
1275     ::onc::ONCSource* onc_source) {
1276   const user_manager::User* user =
1277       user_manager::UserManager::Get()->GetActiveUser();
1278   std::string username_hash = user ? user->username_hash() : std::string();
1279   return NetworkHandler::Get()
1280       ->managed_network_configuration_handler()
1281       ->FindPolicyByGUID(username_hash, guid, onc_source);
1282 }
1283 
PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user)1284 bool PolicyAllowsOnlyPolicyNetworksToAutoconnect(bool for_active_user) {
1285   const base::DictionaryValue* global_config =
1286       GetGlobalConfigFromPolicy(for_active_user);
1287   if (!global_config)
1288     return false;  // By default, all networks are allowed to autoconnect.
1289 
1290   bool only_policy_autoconnect = false;
1291   global_config->GetBooleanWithoutPathExpansion(
1292       ::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
1293       &only_policy_autoconnect);
1294   return only_policy_autoconnect;
1295 }
1296 
GetPolicyForNetwork(const PrefService * profile_prefs,const PrefService * local_state_prefs,const NetworkState & network,::onc::ONCSource * onc_source)1297 const base::DictionaryValue* GetPolicyForNetwork(
1298     const PrefService* profile_prefs,
1299     const PrefService* local_state_prefs,
1300     const NetworkState& network,
1301     ::onc::ONCSource* onc_source) {
1302   VLOG(2) << "GetPolicyForNetwork: " << network.path();
1303   *onc_source = ::onc::ONC_SOURCE_NONE;
1304 
1305   const base::DictionaryValue* network_policy = GetPolicyForNetworkFromPref(
1306       profile_prefs, ::onc::prefs::kOpenNetworkConfiguration, network);
1307   if (network_policy) {
1308     VLOG(1) << "Network " << network.path() << " is managed by user policy.";
1309     *onc_source = ::onc::ONC_SOURCE_USER_POLICY;
1310     return network_policy;
1311   }
1312   network_policy = GetPolicyForNetworkFromPref(
1313       local_state_prefs, ::onc::prefs::kDeviceOpenNetworkConfiguration,
1314       network);
1315   if (network_policy) {
1316     VLOG(1) << "Network " << network.path() << " is managed by device policy.";
1317     *onc_source = ::onc::ONC_SOURCE_DEVICE_POLICY;
1318     return network_policy;
1319   }
1320   VLOG(2) << "Network " << network.path() << " is unmanaged.";
1321   return NULL;
1322 }
1323 
HasPolicyForNetwork(const PrefService * profile_prefs,const PrefService * local_state_prefs,const NetworkState & network)1324 bool HasPolicyForNetwork(const PrefService* profile_prefs,
1325                          const PrefService* local_state_prefs,
1326                          const NetworkState& network) {
1327   ::onc::ONCSource ignored_onc_source;
1328   const base::DictionaryValue* policy = onc::GetPolicyForNetwork(
1329       profile_prefs, local_state_prefs, network, &ignored_onc_source);
1330   return policy != NULL;
1331 }
1332 
HasUserPasswordSubsitutionVariable(const OncValueSignature & signature,base::DictionaryValue * onc_object)1333 bool HasUserPasswordSubsitutionVariable(const OncValueSignature& signature,
1334                                         base::DictionaryValue* onc_object) {
1335   if (&signature == &kEAPSignature) {
1336     std::string password_field;
1337     if (!onc_object->GetStringWithoutPathExpansion(::onc::eap::kPassword,
1338                                                    &password_field)) {
1339       return false;
1340     }
1341 
1342     if (password_field == ::onc::substitutes::kPasswordPlaceholderVerbatim) {
1343       return true;
1344     }
1345   }
1346 
1347   // Recurse into nested objects.
1348   for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
1349        it.Advance()) {
1350     base::DictionaryValue* inner_object = nullptr;
1351     if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
1352       continue;
1353 
1354     const OncFieldSignature* field_signature =
1355         GetFieldSignature(signature, it.key());
1356     if (!field_signature)
1357       continue;
1358 
1359     bool result = HasUserPasswordSubsitutionVariable(
1360         *field_signature->value_signature, inner_object);
1361     if (result) {
1362       return true;
1363     }
1364   }
1365 
1366   return false;
1367 }
1368 
HasUserPasswordSubsitutionVariable(base::ListValue * network_configs)1369 bool HasUserPasswordSubsitutionVariable(base::ListValue* network_configs) {
1370   for (auto& entry : *network_configs) {
1371     base::DictionaryValue* network = nullptr;
1372     entry.GetAsDictionary(&network);
1373     DCHECK(network);
1374 
1375     bool result = HasUserPasswordSubsitutionVariable(
1376         kNetworkConfigurationSignature, network);
1377     if (result) {
1378       return true;
1379     }
1380   }
1381   return false;
1382 }
1383 
1384 }  // namespace onc
1385 }  // namespace chromeos
1386