Some additional network settings cleanup
[chromium-blink-merge.git] / chromeos / network / onc / onc_utils.cc
blob9eb4e500f5f1b68a3043c12844c07b43c1f5121c
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_utils.h"
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chromeos/network/network_event_log.h"
14 #include "chromeos/network/onc/onc_mapper.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_utils.h"
17 #include "chromeos/network/onc/onc_validator.h"
18 #include "crypto/encryptor.h"
19 #include "crypto/hmac.h"
20 #include "crypto/symmetric_key.h"
21 #include "net/cert/pem_tokenizer.h"
22 #include "net/cert/x509_certificate.h"
24 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
25 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
27 using namespace ::onc;
29 namespace chromeos {
30 namespace onc {
32 namespace {
34 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
35 const char kUnableToDecode[] = "Unable to decode encrypted ONC";
37 } // namespace
39 const char kEmptyUnencryptedConfiguration[] =
40 "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
41 "\"Certificates\":[]}";
43 scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson(
44 const std::string& json) {
45 std::string error;
46 base::Value* root = base::JSONReader::ReadAndReturnError(
47 json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
49 base::DictionaryValue* dict_ptr = NULL;
50 if (!root || !root->GetAsDictionary(&dict_ptr)) {
51 ONC_LOG_ERROR("Invalid JSON Dictionary: " + error);
52 delete root;
55 return make_scoped_ptr(dict_ptr);
58 scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase,
59 const base::DictionaryValue& root) {
60 const int kKeySizeInBits = 256;
61 const int kMaxIterationCount = 500000;
62 std::string onc_type;
63 std::string initial_vector;
64 std::string salt;
65 std::string cipher;
66 std::string stretch_method;
67 std::string hmac_method;
68 std::string hmac;
69 int iterations;
70 std::string ciphertext;
72 if (!root.GetString(encrypted::kCiphertext, &ciphertext) ||
73 !root.GetString(encrypted::kCipher, &cipher) ||
74 !root.GetString(encrypted::kHMAC, &hmac) ||
75 !root.GetString(encrypted::kHMACMethod, &hmac_method) ||
76 !root.GetString(encrypted::kIV, &initial_vector) ||
77 !root.GetInteger(encrypted::kIterations, &iterations) ||
78 !root.GetString(encrypted::kSalt, &salt) ||
79 !root.GetString(encrypted::kStretch, &stretch_method) ||
80 !root.GetString(toplevel_config::kType, &onc_type) ||
81 onc_type != toplevel_config::kEncryptedConfiguration) {
83 ONC_LOG_ERROR("Encrypted ONC malformed.");
84 return scoped_ptr<base::DictionaryValue>();
87 if (hmac_method != encrypted::kSHA1 ||
88 cipher != encrypted::kAES256 ||
89 stretch_method != encrypted::kPBKDF2) {
90 ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme.");
91 return scoped_ptr<base::DictionaryValue>();
94 // Make sure iterations != 0, since that's not valid.
95 if (iterations == 0) {
96 ONC_LOG_ERROR(kUnableToDecrypt);
97 return scoped_ptr<base::DictionaryValue>();
100 // Simply a sanity check to make sure we can't lock up the machine
101 // for too long with a huge number (or a negative number).
102 if (iterations < 0 || iterations > kMaxIterationCount) {
103 ONC_LOG_ERROR("Too many iterations in encrypted ONC");
104 return scoped_ptr<base::DictionaryValue>();
107 if (!base::Base64Decode(salt, &salt)) {
108 ONC_LOG_ERROR(kUnableToDecode);
109 return scoped_ptr<base::DictionaryValue>();
112 scoped_ptr<crypto::SymmetricKey> key(
113 crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
114 passphrase,
115 salt,
116 iterations,
117 kKeySizeInBits));
119 if (!base::Base64Decode(initial_vector, &initial_vector)) {
120 ONC_LOG_ERROR(kUnableToDecode);
121 return scoped_ptr<base::DictionaryValue>();
123 if (!base::Base64Decode(ciphertext, &ciphertext)) {
124 ONC_LOG_ERROR(kUnableToDecode);
125 return scoped_ptr<base::DictionaryValue>();
127 if (!base::Base64Decode(hmac, &hmac)) {
128 ONC_LOG_ERROR(kUnableToDecode);
129 return scoped_ptr<base::DictionaryValue>();
132 crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
133 if (!hmac_verifier.Init(key.get()) ||
134 !hmac_verifier.Verify(ciphertext, hmac)) {
135 ONC_LOG_ERROR(kUnableToDecrypt);
136 return scoped_ptr<base::DictionaryValue>();
139 crypto::Encryptor decryptor;
140 if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector)) {
141 ONC_LOG_ERROR(kUnableToDecrypt);
142 return scoped_ptr<base::DictionaryValue>();
145 std::string plaintext;
146 if (!decryptor.Decrypt(ciphertext, &plaintext)) {
147 ONC_LOG_ERROR(kUnableToDecrypt);
148 return scoped_ptr<base::DictionaryValue>();
151 scoped_ptr<base::DictionaryValue> new_root =
152 ReadDictionaryFromJson(plaintext);
153 if (new_root.get() == NULL) {
154 ONC_LOG_ERROR("Property dictionary malformed.");
155 return scoped_ptr<base::DictionaryValue>();
158 return new_root.Pass();
161 std::string GetSourceAsString(ONCSource source) {
162 switch (source) {
163 case ONC_SOURCE_UNKNOWN:
164 return "unknown";
165 case ONC_SOURCE_NONE:
166 return "none";
167 case ONC_SOURCE_DEVICE_POLICY:
168 return "device policy";
169 case ONC_SOURCE_USER_POLICY:
170 return "user policy";
171 case ONC_SOURCE_USER_IMPORT:
172 return "user import";
174 NOTREACHED() << "unknown ONC source " << source;
175 return "unknown";
178 void ExpandField(const std::string& fieldname,
179 const StringSubstitution& substitution,
180 base::DictionaryValue* onc_object) {
181 std::string user_string;
182 if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string))
183 return;
185 std::string login_id;
186 if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
187 ReplaceSubstringsAfterOffset(&user_string, 0,
188 substitutes::kLoginIDField,
189 login_id);
192 std::string email;
193 if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
194 ReplaceSubstringsAfterOffset(&user_string, 0,
195 substitutes::kEmailField,
196 email);
199 onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
202 void ExpandStringsInOncObject(
203 const OncValueSignature& signature,
204 const StringSubstitution& substitution,
205 base::DictionaryValue* onc_object) {
206 if (&signature == &kEAPSignature) {
207 ExpandField(eap::kAnonymousIdentity, substitution, onc_object);
208 ExpandField(eap::kIdentity, substitution, onc_object);
209 } else if (&signature == &kL2TPSignature ||
210 &signature == &kOpenVPNSignature) {
211 ExpandField(vpn::kUsername, substitution, onc_object);
214 // Recurse into nested objects.
215 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
216 it.Advance()) {
217 base::DictionaryValue* inner_object = NULL;
218 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
219 continue;
221 const OncFieldSignature* field_signature =
222 GetFieldSignature(signature, it.key());
223 if (!field_signature)
224 continue;
226 ExpandStringsInOncObject(*field_signature->value_signature,
227 substitution, inner_object);
231 void ExpandStringsInNetworks(const StringSubstitution& substitution,
232 base::ListValue* network_configs) {
233 for (base::ListValue::iterator it = network_configs->begin();
234 it != network_configs->end(); ++it) {
235 base::DictionaryValue* network = NULL;
236 (*it)->GetAsDictionary(&network);
237 DCHECK(network);
238 ExpandStringsInOncObject(
239 kNetworkConfigurationSignature, substitution, network);
243 namespace {
245 class OncMaskValues : public Mapper {
246 public:
247 static scoped_ptr<base::DictionaryValue> Mask(
248 const OncValueSignature& signature,
249 const base::DictionaryValue& onc_object,
250 const std::string& mask) {
251 OncMaskValues masker(mask);
252 bool unused_error;
253 return masker.MapObject(signature, onc_object, &unused_error);
256 protected:
257 explicit OncMaskValues(const std::string& mask)
258 : mask_(mask) {
261 virtual scoped_ptr<base::Value> MapField(
262 const std::string& field_name,
263 const OncValueSignature& object_signature,
264 const base::Value& onc_value,
265 bool* found_unknown_field,
266 bool* error) OVERRIDE {
267 if (FieldIsCredential(object_signature, field_name)) {
268 return scoped_ptr<base::Value>(new base::StringValue(mask_));
269 } else {
270 return Mapper::MapField(field_name, object_signature, onc_value,
271 found_unknown_field, error);
275 // Mask to insert in place of the sensitive values.
276 std::string mask_;
279 } // namespace
281 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
282 const OncValueSignature& signature,
283 const base::DictionaryValue& onc_object,
284 const std::string& mask) {
285 return OncMaskValues::Mask(signature, onc_object, mask);
288 namespace {
290 std::string DecodePEM(const std::string& pem_encoded) {
291 // The PEM block header used for DER certificates
292 const char kCertificateHeader[] = "CERTIFICATE";
294 // This is an older PEM marker for DER certificates.
295 const char kX509CertificateHeader[] = "X509 CERTIFICATE";
297 std::vector<std::string> pem_headers;
298 pem_headers.push_back(kCertificateHeader);
299 pem_headers.push_back(kX509CertificateHeader);
301 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
302 std::string decoded;
303 if (pem_tokenizer.GetNext()) {
304 decoded = pem_tokenizer.data();
305 } else {
306 // If we failed to read the data as a PEM file, then try plain base64 decode
307 // in case the PEM marker strings are missing. For this to work, there has
308 // to be no white space, and it has to only contain the base64-encoded data.
309 if (!base::Base64Decode(pem_encoded, &decoded)) {
310 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
311 return std::string();
314 return decoded;
317 CertPEMsByGUIDMap GetServerAndCACertsByGUID(
318 const base::ListValue& certificates) {
319 CertPEMsByGUIDMap certs_by_guid;
320 for (base::ListValue::const_iterator it = certificates.begin();
321 it != certificates.end(); ++it) {
322 base::DictionaryValue* cert = NULL;
323 (*it)->GetAsDictionary(&cert);
325 std::string guid;
326 cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid);
327 std::string cert_type;
328 cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type);
329 if (cert_type != certificate::kServer &&
330 cert_type != certificate::kAuthority) {
331 continue;
333 std::string x509_data;
334 cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data);
336 std::string der = DecodePEM(x509_data);
337 std::string pem;
338 if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
339 LOG(ERROR) << "Certificate with GUID " << guid
340 << " is not in PEM encoding.";
341 continue;
343 certs_by_guid[guid] = pem;
346 return certs_by_guid;
349 } // namespace
351 bool ParseAndValidateOncForImport(const std::string& onc_blob,
352 ONCSource onc_source,
353 const std::string& passphrase,
354 base::ListValue* network_configs,
355 base::DictionaryValue* global_network_config,
356 base::ListValue* certificates) {
357 network_configs->Clear();
358 global_network_config->Clear();
359 certificates->Clear();
360 if (onc_blob.empty())
361 return true;
363 scoped_ptr<base::DictionaryValue> toplevel_onc =
364 ReadDictionaryFromJson(onc_blob);
365 if (toplevel_onc.get() == NULL) {
366 LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
367 << " is not a valid JSON dictionary.";
368 return false;
371 // Check and see if this is an encrypted ONC file. If so, decrypt it.
372 std::string onc_type;
373 toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
374 &onc_type);
375 if (onc_type == toplevel_config::kEncryptedConfiguration) {
376 toplevel_onc = Decrypt(passphrase, *toplevel_onc);
377 if (toplevel_onc.get() == NULL) {
378 LOG(ERROR) << "Couldn't decrypt the ONC from "
379 << GetSourceAsString(onc_source);
380 return false;
384 bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
385 onc_source == ONC_SOURCE_DEVICE_POLICY);
387 // Validate the ONC dictionary. We are liberal and ignore unknown field
388 // names and ignore invalid field names in kRecommended arrays.
389 Validator validator(false, // Ignore unknown fields.
390 false, // Ignore invalid recommended field names.
391 true, // Fail on missing fields.
392 from_policy);
393 validator.SetOncSource(onc_source);
395 Validator::Result validation_result;
396 toplevel_onc = validator.ValidateAndRepairObject(
397 &kToplevelConfigurationSignature,
398 *toplevel_onc,
399 &validation_result);
401 if (from_policy) {
402 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
403 validation_result == Validator::VALID);
406 bool success = true;
407 if (validation_result == Validator::VALID_WITH_WARNINGS) {
408 LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
409 << " produced warnings.";
410 success = false;
411 } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) {
412 LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
413 << " is invalid and couldn't be repaired.";
414 return false;
417 base::ListValue* validated_certs = NULL;
418 if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
419 &validated_certs)) {
420 certificates->Swap(validated_certs);
423 base::ListValue* validated_networks = NULL;
424 if (toplevel_onc->GetListWithoutPathExpansion(
425 toplevel_config::kNetworkConfigurations, &validated_networks)) {
426 CertPEMsByGUIDMap server_and_ca_certs =
427 GetServerAndCACertsByGUID(*certificates);
429 if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
430 validated_networks)) {
431 LOG(ERROR) << "Some certificate references in the ONC policy for source "
432 << GetSourceAsString(onc_source) << " could not be resolved.";
433 success = false;
436 network_configs->Swap(validated_networks);
439 base::DictionaryValue* validated_global_config = NULL;
440 if (toplevel_onc->GetDictionaryWithoutPathExpansion(
441 toplevel_config::kGlobalNetworkConfiguration,
442 &validated_global_config)) {
443 global_network_config->Swap(validated_global_config);
446 return success;
449 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
450 const std::string& pem_encoded) {
451 std::string decoded = DecodePEM(pem_encoded);
452 scoped_refptr<net::X509Certificate> cert =
453 net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
454 LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: "
455 << decoded;
456 return cert;
459 namespace {
461 bool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
462 const std::string& guid_ref,
463 std::string* pem_encoded) {
464 CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
465 if (it == certs_by_guid.end()) {
466 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
467 return false;
469 *pem_encoded = it->second;
470 if (pem_encoded->empty()) {
471 LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
472 return false;
474 return true;
477 bool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
478 const std::string& key_guid_ref,
479 const std::string& key_pem,
480 base::DictionaryValue* onc_object) {
481 std::string guid_ref;
482 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
483 return true;
485 std::string pem_encoded;
486 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
487 return false;
489 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
490 onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
491 return true;
494 bool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
495 const std::string& key_guid_ref_list,
496 const std::string& key_pem_list,
497 base::DictionaryValue* onc_object) {
498 const base::ListValue* guid_ref_list = NULL;
499 if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
500 &guid_ref_list)) {
501 return true;
504 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
505 for (base::ListValue::const_iterator it = guid_ref_list->begin();
506 it != guid_ref_list->end(); ++it) {
507 std::string guid_ref;
508 (*it)->GetAsString(&guid_ref);
510 std::string pem_encoded;
511 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
512 return false;
514 pem_list->AppendString(pem_encoded);
517 onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL);
518 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
519 return true;
522 bool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
523 const std::string& key_guid_ref,
524 const std::string& key_pem_list,
525 base::DictionaryValue* onc_object) {
526 std::string guid_ref;
527 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
528 return true;
530 std::string pem_encoded;
531 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
532 return false;
534 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
535 pem_list->AppendString(pem_encoded);
536 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
537 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
538 return true;
541 // Resolves the reference list at |key_guid_refs| if present and otherwise the
542 // single reference at |key_guid_ref|. Returns whether the respective resolving
543 // was successful.
544 bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
545 const std::string& key_guid_refs,
546 const std::string& key_guid_ref,
547 const std::string& key_pem_list,
548 base::DictionaryValue* onc_object) {
549 if (onc_object->HasKey(key_guid_refs)) {
550 if (onc_object->HasKey(key_guid_ref)) {
551 LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
552 << ". Ignoring and removing the latter.";
553 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
555 return ResolveCertRefList(
556 certs_by_guid, key_guid_refs, key_pem_list, onc_object);
559 // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
560 return ResolveSingleCertRefToList(
561 certs_by_guid, key_guid_ref, key_pem_list, onc_object);
564 bool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
565 const OncValueSignature& signature,
566 base::DictionaryValue* onc_object) {
567 if (&signature == &kCertificatePatternSignature) {
568 if (!ResolveCertRefList(certs_by_guid,
569 client_cert::kIssuerCARef,
570 client_cert::kIssuerCAPEMs,
571 onc_object)) {
572 return false;
574 } else if (&signature == &kEAPSignature) {
575 if (!ResolveCertRefsOrRefToList(certs_by_guid,
576 eap::kServerCARefs,
577 eap::kServerCARef,
578 eap::kServerCAPEMs,
579 onc_object)) {
580 return false;
582 } else if (&signature == &kIPsecSignature) {
583 if (!ResolveCertRefsOrRefToList(certs_by_guid,
584 ipsec::kServerCARefs,
585 ipsec::kServerCARef,
586 ipsec::kServerCAPEMs,
587 onc_object)) {
588 return false;
590 } else if (&signature == &kIPsecSignature ||
591 &signature == &kOpenVPNSignature) {
592 if (!ResolveSingleCertRef(certs_by_guid,
593 openvpn::kServerCertRef,
594 openvpn::kServerCertPEM,
595 onc_object) ||
596 !ResolveCertRefsOrRefToList(certs_by_guid,
597 openvpn::kServerCARefs,
598 openvpn::kServerCARef,
599 openvpn::kServerCAPEMs,
600 onc_object)) {
601 return false;
605 // Recurse into nested objects.
606 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
607 it.Advance()) {
608 base::DictionaryValue* inner_object = NULL;
609 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
610 continue;
612 const OncFieldSignature* field_signature =
613 GetFieldSignature(signature, it.key());
614 if (!field_signature)
615 continue;
617 if (!ResolveServerCertRefsInObject(certs_by_guid,
618 *field_signature->value_signature,
619 inner_object)) {
620 return false;
623 return true;
626 } // namespace
628 bool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
629 base::ListValue* network_configs) {
630 bool success = true;
631 for (base::ListValue::iterator it = network_configs->begin();
632 it != network_configs->end(); ) {
633 base::DictionaryValue* network = NULL;
634 (*it)->GetAsDictionary(&network);
635 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
636 std::string guid;
637 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
638 // This might happen even with correct validation, if the referenced
639 // certificate couldn't be imported.
640 LOG(ERROR) << "Couldn't resolve some certificate reference of network "
641 << guid;
642 it = network_configs->Erase(it, NULL);
643 success = false;
644 continue;
646 ++it;
648 return success;
651 bool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
652 base::DictionaryValue* network_config) {
653 return ResolveServerCertRefsInObject(certs_by_guid,
654 kNetworkConfigurationSignature,
655 network_config);
658 NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
659 if (type == ::onc::network_type::kAllTypes)
660 return NetworkTypePattern::Default();
661 if (type == ::onc::network_type::kCellular)
662 return NetworkTypePattern::Cellular();
663 if (type == ::onc::network_type::kEthernet)
664 return NetworkTypePattern::Ethernet();
665 if (type == ::onc::network_type::kVPN)
666 return NetworkTypePattern::VPN();
667 if (type == ::onc::network_type::kWiFi)
668 return NetworkTypePattern::WiFi();
669 if (type == ::onc::network_type::kWimax)
670 return NetworkTypePattern::Wimax();
671 if (type == ::onc::network_type::kWireless)
672 return NetworkTypePattern::Wireless();
673 NOTREACHED();
674 return NetworkTypePattern::Default();
677 bool IsRecommendedValue(const base::DictionaryValue* onc,
678 const std::string& property_key) {
679 std::string property_basename, recommended_property_key;
680 size_t pos = property_key.find_last_of('.');
681 if (pos != std::string::npos) {
682 // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
683 property_basename = property_key.substr(pos + 1);
684 recommended_property_key =
685 property_key.substr(0, pos + 1) + ::onc::kRecommended;
686 } else {
687 // 'Name' -> 'Name', 'Recommended'
688 property_basename = property_key;
689 recommended_property_key = ::onc::kRecommended;
692 const base::ListValue* recommended_keys = NULL;
693 return (onc->GetList(recommended_property_key, &recommended_keys) &&
694 recommended_keys->Find(base::StringValue(property_basename)) !=
695 recommended_keys->end());
698 } // namespace onc
699 } // namespace chromeos