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_validator.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "components/onc/onc_constants.h"
23 template <typename T
, size_t N
>
24 std::vector
<T
> toVector(T
const (&array
)[N
]) {
25 return std::vector
<T
>(array
, array
+ N
);
28 // Copied from policy/configuration_policy_handler.cc.
29 // TODO(pneubeck): move to a common place like base/.
30 std::string
ValueTypeToString(base::Value::Type type
) {
31 const char* const strings
[] = {"null", "boolean", "integer", "double",
32 "string", "binary", "dictionary", "list"};
33 CHECK(static_cast<size_t>(type
) < arraysize(strings
));
39 Validator::Validator(bool error_on_unknown_field
,
40 bool error_on_wrong_recommended
,
41 bool error_on_missing_field
,
43 : error_on_unknown_field_(error_on_unknown_field
),
44 error_on_wrong_recommended_(error_on_wrong_recommended
),
45 error_on_missing_field_(error_on_missing_field
),
46 managed_onc_(managed_onc
),
47 onc_source_(::onc::ONC_SOURCE_NONE
) {}
49 Validator::~Validator() {}
51 scoped_ptr
<base::DictionaryValue
> Validator::ValidateAndRepairObject(
52 const OncValueSignature
* object_signature
,
53 const base::DictionaryValue
& onc_object
,
55 CHECK(object_signature
);
57 error_or_warning_found_
= false;
59 scoped_ptr
<base::Value
> result_value
=
60 MapValue(*object_signature
, onc_object
, &error
);
64 } else if (error_or_warning_found_
) {
65 *result
= VALID_WITH_WARNINGS
;
67 // The return value should be NULL if, and only if, |result| equals INVALID.
68 DCHECK_EQ(result_value
.get() == NULL
, *result
== INVALID
);
70 base::DictionaryValue
* result_dict
= NULL
;
72 result_value
.release()->GetAsDictionary(&result_dict
);
76 return make_scoped_ptr(result_dict
);
79 scoped_ptr
<base::Value
> Validator::MapValue(const OncValueSignature
& signature
,
80 const base::Value
& onc_value
,
82 if (onc_value
.GetType() != signature
.onc_type
) {
83 LOG(ERROR
) << MessageHeader() << "Found value '" << onc_value
84 << "' of type '" << ValueTypeToString(onc_value
.GetType())
85 << "', but type '" << ValueTypeToString(signature
.onc_type
)
87 error_or_warning_found_
= *error
= true;
88 return scoped_ptr
<base::Value
>();
91 scoped_ptr
<base::Value
> repaired
=
92 Mapper::MapValue(signature
, onc_value
, error
);
94 CHECK_EQ(repaired
->GetType(), signature
.onc_type
);
95 return repaired
.Pass();
98 scoped_ptr
<base::DictionaryValue
> Validator::MapObject(
99 const OncValueSignature
& signature
,
100 const base::DictionaryValue
& onc_object
,
102 scoped_ptr
<base::DictionaryValue
> repaired(new base::DictionaryValue
);
104 bool valid
= ValidateObjectDefault(signature
, onc_object
, repaired
.get());
106 if (&signature
== &kToplevelConfigurationSignature
) {
107 valid
= ValidateToplevelConfiguration(repaired
.get());
108 } else if (&signature
== &kNetworkConfigurationSignature
) {
109 valid
= ValidateNetworkConfiguration(repaired
.get());
110 } else if (&signature
== &kEthernetSignature
) {
111 valid
= ValidateEthernet(repaired
.get());
112 } else if (&signature
== &kIPConfigSignature
||
113 &signature
== &kSavedIPConfigSignature
||
114 &signature
== &kStaticIPConfigSignature
) {
115 valid
= ValidateIPConfig(repaired
.get());
116 } else if (&signature
== &kWiFiSignature
) {
117 valid
= ValidateWiFi(repaired
.get());
118 } else if (&signature
== &kVPNSignature
) {
119 valid
= ValidateVPN(repaired
.get());
120 } else if (&signature
== &kIPsecSignature
) {
121 valid
= ValidateIPsec(repaired
.get());
122 } else if (&signature
== &kOpenVPNSignature
) {
123 valid
= ValidateOpenVPN(repaired
.get());
124 } else if (&signature
== &kVerifyX509Signature
) {
125 valid
= ValidateVerifyX509(repaired
.get());
126 } else if (&signature
== &kCertificatePatternSignature
) {
127 valid
= ValidateCertificatePattern(repaired
.get());
128 } else if (&signature
== &kProxySettingsSignature
) {
129 valid
= ValidateProxySettings(repaired
.get());
130 } else if (&signature
== &kProxyLocationSignature
) {
131 valid
= ValidateProxyLocation(repaired
.get());
132 } else if (&signature
== &kEAPSignature
) {
133 valid
= ValidateEAP(repaired
.get());
134 } else if (&signature
== &kCertificateSignature
) {
135 valid
= ValidateCertificate(repaired
.get());
140 return repaired
.Pass();
142 DCHECK(error_or_warning_found_
);
143 error_or_warning_found_
= *error
= true;
144 return scoped_ptr
<base::DictionaryValue
>();
148 scoped_ptr
<base::Value
> Validator::MapField(
149 const std::string
& field_name
,
150 const OncValueSignature
& object_signature
,
151 const base::Value
& onc_value
,
152 bool* found_unknown_field
,
154 path_
.push_back(field_name
);
155 bool current_field_unknown
= false;
156 scoped_ptr
<base::Value
> result
= Mapper::MapField(
157 field_name
, object_signature
, onc_value
, ¤t_field_unknown
, error
);
159 DCHECK_EQ(field_name
, path_
.back());
162 if (current_field_unknown
) {
163 error_or_warning_found_
= *found_unknown_field
= true;
164 std::string message
= MessageHeader() + "Field name '" + field_name
+
166 if (error_on_unknown_field_
)
167 LOG(ERROR
) << message
;
169 LOG(WARNING
) << message
;
172 return result
.Pass();
175 scoped_ptr
<base::ListValue
> Validator::MapArray(
176 const OncValueSignature
& array_signature
,
177 const base::ListValue
& onc_array
,
178 bool* nested_error
) {
179 bool nested_error_in_current_array
= false;
180 scoped_ptr
<base::ListValue
> result
= Mapper::MapArray(
181 array_signature
, onc_array
, &nested_error_in_current_array
);
183 // Drop individual networks and certificates instead of rejecting all of
184 // the configuration.
185 if (nested_error_in_current_array
&&
186 &array_signature
!= &kNetworkConfigurationListSignature
&&
187 &array_signature
!= &kCertificateListSignature
) {
188 *nested_error
= nested_error_in_current_array
;
190 return result
.Pass();
193 scoped_ptr
<base::Value
> Validator::MapEntry(int index
,
194 const OncValueSignature
& signature
,
195 const base::Value
& onc_value
,
197 std::string str
= base::IntToString(index
);
198 path_
.push_back(str
);
199 scoped_ptr
<base::Value
> result
=
200 Mapper::MapEntry(index
, signature
, onc_value
, error
);
201 DCHECK_EQ(str
, path_
.back());
203 return result
.Pass();
206 bool Validator::ValidateObjectDefault(const OncValueSignature
& signature
,
207 const base::DictionaryValue
& onc_object
,
208 base::DictionaryValue
* result
) {
209 bool found_unknown_field
= false;
210 bool nested_error_occured
= false;
211 MapFields(signature
, onc_object
, &found_unknown_field
, &nested_error_occured
,
214 if (found_unknown_field
&& error_on_unknown_field_
) {
215 DVLOG(1) << "Unknown field names are errors: Aborting.";
219 if (nested_error_occured
)
222 return ValidateRecommendedField(signature
, result
);
225 bool Validator::ValidateRecommendedField(
226 const OncValueSignature
& object_signature
,
227 base::DictionaryValue
* result
) {
230 scoped_ptr
<base::ListValue
> recommended
;
231 scoped_ptr
<base::Value
> recommended_value
;
232 // This remove passes ownership to |recommended_value|.
233 if (!result
->RemoveWithoutPathExpansion(::onc::kRecommended
,
234 &recommended_value
)) {
237 base::ListValue
* recommended_list
= NULL
;
238 recommended_value
.release()->GetAsList(&recommended_list
);
239 CHECK(recommended_list
);
241 recommended
.reset(recommended_list
);
244 error_or_warning_found_
= true;
245 LOG(WARNING
) << MessageHeader() << "Found the field '"
246 << ::onc::kRecommended
247 << "' in an unmanaged ONC. Removing it.";
251 scoped_ptr
<base::ListValue
> repaired_recommended(new base::ListValue
);
252 for (base::ListValue::iterator it
= recommended
->begin();
253 it
!= recommended
->end(); ++it
) {
254 std::string field_name
;
255 if (!(*it
)->GetAsString(&field_name
)) {
260 const OncFieldSignature
* field_signature
=
261 GetFieldSignature(object_signature
, field_name
);
263 bool found_error
= false;
264 std::string error_cause
;
265 if (!field_signature
) {
267 error_cause
= "unknown";
268 } else if (field_signature
->value_signature
->onc_type
==
269 base::Value::TYPE_DICTIONARY
) {
271 error_cause
= "dictionary-typed";
275 error_or_warning_found_
= true;
276 path_
.push_back(::onc::kRecommended
);
277 std::string message
= MessageHeader() + "The " + error_cause
+
278 " field '" + field_name
+ "' cannot be recommended.";
280 if (error_on_wrong_recommended_
) {
281 LOG(ERROR
) << message
;
284 LOG(WARNING
) << message
;
289 repaired_recommended
->Append((*it
)->DeepCopy());
292 result
->Set(::onc::kRecommended
, repaired_recommended
.release());
296 bool Validator::ValidateClientCertFields(bool allow_cert_type_none
,
297 base::DictionaryValue
* result
) {
298 using namespace ::onc::client_cert
;
299 const char* const kValidCertTypes
[] = {kRef
, kPattern
};
300 std::vector
<const char*> valid_cert_types(toVector(kValidCertTypes
));
301 if (allow_cert_type_none
)
302 valid_cert_types
.push_back(kClientCertTypeNone
);
303 if (FieldExistsAndHasNoValidValue(*result
, kClientCertType
, valid_cert_types
))
306 std::string cert_type
;
307 result
->GetStringWithoutPathExpansion(kClientCertType
, &cert_type
);
309 if (IsCertPatternInDevicePolicy(cert_type
))
312 bool all_required_exist
= true;
314 if (cert_type
== kPattern
)
315 all_required_exist
&= RequireField(*result
, kClientCertPattern
);
316 else if (cert_type
== kRef
)
317 all_required_exist
&= RequireField(*result
, kClientCertRef
);
319 return !error_on_missing_field_
|| all_required_exist
;
324 std::string
JoinStringRange(const std::vector
<const char*>& strings
,
325 const std::string
& separator
) {
326 std::vector
<std::string
> string_vector
;
327 std::copy(strings
.begin(), strings
.end(), std::back_inserter(string_vector
));
328 return JoinString(string_vector
, separator
);
333 bool Validator::FieldExistsAndHasNoValidValue(
334 const base::DictionaryValue
& object
,
335 const std::string
& field_name
,
336 const std::vector
<const char*>& valid_values
) {
337 std::string actual_value
;
338 if (!object
.GetStringWithoutPathExpansion(field_name
, &actual_value
))
341 for (std::vector
<const char*>::const_iterator it
= valid_values
.begin();
342 it
!= valid_values
.end();
344 if (actual_value
== *it
)
347 error_or_warning_found_
= true;
348 std::string valid_values_str
=
349 "[" + JoinStringRange(valid_values
, ", ") + "]";
350 path_
.push_back(field_name
);
351 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
<<
352 "', but expected one of the values " << valid_values_str
;
357 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue
& object
,
358 const std::string
& field_name
,
362 if (!object
.GetIntegerWithoutPathExpansion(field_name
, &actual_value
) ||
363 (lower_bound
<= actual_value
&& actual_value
<= upper_bound
)) {
366 error_or_warning_found_
= true;
367 path_
.push_back(field_name
);
368 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
369 << "', but expected a value in the range [" << lower_bound
370 << ", " << upper_bound
<< "] (boundaries inclusive)";
375 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue
& object
,
376 const std::string
& field_name
) {
377 const base::Value
* value
= NULL
;
378 if (!object
.GetWithoutPathExpansion(field_name
, &value
))
382 const base::ListValue
* list
= NULL
;
383 if (value
->GetAsString(&str
)) {
386 } else if (value
->GetAsList(&list
)) {
394 error_or_warning_found_
= true;
395 path_
.push_back(field_name
);
396 LOG(ERROR
) << MessageHeader() << "Found an empty string, but expected a "
397 << "non-empty string.";
402 bool Validator::RequireField(const base::DictionaryValue
& dict
,
403 const std::string
& field_name
) {
404 if (dict
.HasKey(field_name
))
406 error_or_warning_found_
= true;
407 std::string message
= MessageHeader() + "The required field '" + field_name
+
409 if (error_on_missing_field_
)
410 LOG(ERROR
) << message
;
412 LOG(WARNING
) << message
;
416 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue
& dict
,
417 const std::string
& key_guid
,
418 std::set
<std::string
> *guids
) {
420 if (dict
.GetStringWithoutPathExpansion(key_guid
, &guid
)) {
421 if (guids
->count(guid
) != 0) {
422 error_or_warning_found_
= true;
423 LOG(ERROR
) << MessageHeader() << "Found a duplicate GUID " << guid
<< ".";
431 bool Validator::IsCertPatternInDevicePolicy(const std::string
& cert_type
) {
432 if (cert_type
== ::onc::client_cert::kPattern
&&
433 onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
) {
434 error_or_warning_found_
= true;
435 LOG(ERROR
) << MessageHeader() << "Client certificate patterns are "
436 << "prohibited in ONC device policies.";
442 bool Validator::IsGlobalNetworkConfigInUserImport(
443 const base::DictionaryValue
& onc_object
) {
444 if (onc_source_
== ::onc::ONC_SOURCE_USER_IMPORT
&&
445 onc_object
.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration
)) {
446 error_or_warning_found_
= true;
447 LOG(ERROR
) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
448 << "in ONC user imports";
454 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue
* result
) {
455 using namespace ::onc::toplevel_config
;
457 const char* const kValidTypes
[] = {kUnencryptedConfiguration
,
458 kEncryptedConfiguration
};
459 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
460 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
463 if (IsGlobalNetworkConfigInUserImport(*result
))
469 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue
* result
) {
470 using namespace ::onc::network_config
;
472 const char* const kValidTypes
[] = {
473 ::onc::network_type::kEthernet
, ::onc::network_type::kVPN
,
474 ::onc::network_type::kWiFi
, ::onc::network_type::kCellular
};
475 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
476 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
477 FieldExistsAndIsEmpty(*result
, kGUID
)) {
481 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &network_guids_
))
484 bool all_required_exist
= RequireField(*result
, kGUID
);
487 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
489 all_required_exist
&=
490 RequireField(*result
, kName
) && RequireField(*result
, kType
);
493 result
->GetStringWithoutPathExpansion(kType
, &type
);
495 // Prohibit anything but WiFi and Ethernet for device-level policy (which
496 // corresponds to shared networks). See also http://crosbug.com/28741.
497 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
498 type
!= ::onc::network_type::kWiFi
&&
499 type
!= ::onc::network_type::kEthernet
) {
500 error_or_warning_found_
= true;
501 LOG(ERROR
) << MessageHeader() << "Networks of type '"
502 << type
<< "' are prohibited in ONC device policies.";
506 if (type
== ::onc::network_type::kWiFi
) {
507 all_required_exist
&= RequireField(*result
, ::onc::network_config::kWiFi
);
508 } else if (type
== ::onc::network_type::kEthernet
) {
509 all_required_exist
&=
510 RequireField(*result
, ::onc::network_config::kEthernet
);
511 } else if (type
== ::onc::network_type::kCellular
) {
512 all_required_exist
&=
513 RequireField(*result
, ::onc::network_config::kCellular
);
514 } else if (type
== ::onc::network_type::kVPN
) {
515 all_required_exist
&= RequireField(*result
, ::onc::network_config::kVPN
);
516 } else if (!type
.empty()) {
521 return !error_on_missing_field_
|| all_required_exist
;
524 bool Validator::ValidateEthernet(base::DictionaryValue
* result
) {
525 using namespace ::onc::ethernet
;
527 const char* const kValidAuthentications
[] = {kAuthenticationNone
, k8021X
};
528 const std::vector
<const char*> valid_authentications(
529 toVector(kValidAuthentications
));
530 if (FieldExistsAndHasNoValidValue(
531 *result
, kAuthentication
, valid_authentications
)) {
535 bool all_required_exist
= true;
537 result
->GetStringWithoutPathExpansion(kAuthentication
, &auth
);
539 all_required_exist
&= RequireField(*result
, kEAP
);
541 return !error_on_missing_field_
|| all_required_exist
;
544 bool Validator::ValidateIPConfig(base::DictionaryValue
* result
) {
545 using namespace ::onc::ipconfig
;
547 const char* const kValidTypes
[] = {kIPv4
, kIPv6
};
548 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
549 if (FieldExistsAndHasNoValidValue(
550 *result
, ::onc::ipconfig::kType
, valid_types
))
554 result
->GetStringWithoutPathExpansion(::onc::ipconfig::kType
, &type
);
556 // In case of missing type, choose higher upper_bound.
557 int upper_bound
= (type
== kIPv4
) ? 32 : 128;
558 if (FieldExistsAndIsNotInRange(
559 *result
, kRoutingPrefix
, lower_bound
, upper_bound
)) {
563 bool all_required_exist
= RequireField(*result
, kIPAddress
) &&
564 RequireField(*result
, kRoutingPrefix
) &&
565 RequireField(*result
, ::onc::ipconfig::kType
);
567 return !error_on_missing_field_
|| all_required_exist
;
570 bool Validator::ValidateWiFi(base::DictionaryValue
* result
) {
571 using namespace ::onc::wifi
;
573 const char* const kValidSecurities
[] = {kSecurityNone
, kWEP_PSK
, kWEP_8021X
,
575 const std::vector
<const char*> valid_securities(toVector(kValidSecurities
));
576 if (FieldExistsAndHasNoValidValue(*result
, kSecurity
, valid_securities
))
579 bool all_required_exist
=
580 RequireField(*result
, kSecurity
) && RequireField(*result
, kSSID
);
582 std::string security
;
583 result
->GetStringWithoutPathExpansion(kSecurity
, &security
);
584 if (security
== kWEP_8021X
|| security
== kWPA_EAP
)
585 all_required_exist
&= RequireField(*result
, kEAP
);
586 else if (security
== kWEP_PSK
|| security
== kWPA_PSK
)
587 all_required_exist
&= RequireField(*result
, kPassphrase
);
589 return !error_on_missing_field_
|| all_required_exist
;
592 bool Validator::ValidateVPN(base::DictionaryValue
* result
) {
593 using namespace ::onc::vpn
;
595 const char* const kValidTypes
[] = {kIPsec
, kTypeL2TP_IPsec
, kOpenVPN
};
596 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
597 if (FieldExistsAndHasNoValidValue(*result
, ::onc::vpn::kType
, valid_types
))
600 bool all_required_exist
= RequireField(*result
, ::onc::vpn::kType
);
602 result
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
603 if (type
== kOpenVPN
) {
604 all_required_exist
&= RequireField(*result
, kOpenVPN
);
605 } else if (type
== kIPsec
) {
606 all_required_exist
&= RequireField(*result
, kIPsec
);
607 } else if (type
== kTypeL2TP_IPsec
) {
608 all_required_exist
&=
609 RequireField(*result
, kIPsec
) && RequireField(*result
, kL2TP
);
612 return !error_on_missing_field_
|| all_required_exist
;
615 bool Validator::ValidateIPsec(base::DictionaryValue
* result
) {
616 using namespace ::onc::ipsec
;
618 const char* const kValidAuthentications
[] = {kPSK
, kCert
};
619 const std::vector
<const char*> valid_authentications(
620 toVector(kValidAuthentications
));
621 if (FieldExistsAndHasNoValidValue(
622 *result
, kAuthenticationType
, valid_authentications
) ||
623 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
627 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
628 error_or_warning_found_
= true;
629 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
630 << " and " << kServerCARef
<< " can be set.";
634 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
639 bool all_required_exist
= RequireField(*result
, kAuthenticationType
) &&
640 RequireField(*result
, kIKEVersion
);
642 result
->GetStringWithoutPathExpansion(kAuthenticationType
, &auth
);
643 bool has_server_ca_cert
=
644 result
->HasKey(kServerCARefs
) || result
->HasKey(kServerCARef
);
646 all_required_exist
&=
647 RequireField(*result
, ::onc::client_cert::kClientCertType
);
648 if (!has_server_ca_cert
) {
649 all_required_exist
= false;
650 error_or_warning_found_
= true;
651 std::string message
= MessageHeader() + "The required field '" +
652 kServerCARefs
+ "' is missing.";
653 if (error_on_missing_field_
)
654 LOG(ERROR
) << message
;
656 LOG(WARNING
) << message
;
658 } else if (has_server_ca_cert
) {
659 error_or_warning_found_
= true;
660 LOG(ERROR
) << MessageHeader() << kServerCARefs
<< " (or " << kServerCARef
661 << ") can only be set if " << kAuthenticationType
662 << " is set to " << kCert
<< ".";
666 return !error_on_missing_field_
|| all_required_exist
;
669 bool Validator::ValidateOpenVPN(base::DictionaryValue
* result
) {
670 using namespace ::onc::openvpn
;
672 const char* const kValidAuthRetryValues
[] = {::onc::openvpn::kNone
, kInteract
,
674 const std::vector
<const char*> valid_auth_retry_values(
675 toVector(kValidAuthRetryValues
));
676 const char* const kValidCertTlsValues
[] = {::onc::openvpn::kNone
,
677 ::onc::openvpn::kServer
};
678 const std::vector
<const char*> valid_cert_tls_values(
679 toVector(kValidCertTlsValues
));
681 if (FieldExistsAndHasNoValidValue(
682 *result
, kAuthRetry
, valid_auth_retry_values
) ||
683 FieldExistsAndHasNoValidValue(
684 *result
, kRemoteCertTLS
, valid_cert_tls_values
) ||
685 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
689 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
690 error_or_warning_found_
= true;
691 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
692 << " and " << kServerCARef
<< " can be set.";
696 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result
))
699 bool all_required_exist
=
700 RequireField(*result
, ::onc::client_cert::kClientCertType
);
702 return !error_on_missing_field_
|| all_required_exist
;
705 bool Validator::ValidateVerifyX509(base::DictionaryValue
* result
) {
706 using namespace ::onc::verify_x509
;
708 const char* const kValidTypes
[] = {types::kName
, types::kNamePrefix
,
710 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
712 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
715 bool all_required_exist
= RequireField(*result
, kName
);
717 return !error_on_missing_field_
|| all_required_exist
;
720 bool Validator::ValidateCertificatePattern(base::DictionaryValue
* result
) {
721 using namespace ::onc::client_cert
;
723 bool all_required_exist
= true;
724 if (!result
->HasKey(kSubject
) && !result
->HasKey(kIssuer
) &&
725 !result
->HasKey(kIssuerCARef
)) {
726 error_or_warning_found_
= true;
727 all_required_exist
= false;
728 std::string message
= MessageHeader() + "None of the fields '" + kSubject
+
729 "', '" + kIssuer
+ "', and '" + kIssuerCARef
+
730 "' is present, but at least one is required.";
731 if (error_on_missing_field_
)
732 LOG(ERROR
) << message
;
734 LOG(WARNING
) << message
;
737 return !error_on_missing_field_
|| all_required_exist
;
740 bool Validator::ValidateProxySettings(base::DictionaryValue
* result
) {
741 using namespace ::onc::proxy
;
743 const char* const kValidTypes
[] = {kDirect
, kManual
, kPAC
, kWPAD
};
744 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
745 if (FieldExistsAndHasNoValidValue(*result
, ::onc::proxy::kType
, valid_types
))
748 bool all_required_exist
= RequireField(*result
, ::onc::proxy::kType
);
750 result
->GetStringWithoutPathExpansion(::onc::proxy::kType
, &type
);
752 all_required_exist
&= RequireField(*result
, kManual
);
753 else if (type
== kPAC
)
754 all_required_exist
&= RequireField(*result
, kPAC
);
756 return !error_on_missing_field_
|| all_required_exist
;
759 bool Validator::ValidateProxyLocation(base::DictionaryValue
* result
) {
760 using namespace ::onc::proxy
;
762 bool all_required_exist
=
763 RequireField(*result
, kHost
) && RequireField(*result
, kPort
);
765 return !error_on_missing_field_
|| all_required_exist
;
768 bool Validator::ValidateEAP(base::DictionaryValue
* result
) {
769 using namespace ::onc::eap
;
771 const char* const kValidInnerValues
[] = {kAutomatic
, kMD5
, kMSCHAPv2
, kPAP
};
772 const std::vector
<const char*> valid_inner_values(
773 toVector(kValidInnerValues
));
774 const char* const kValidOuterValues
[] = {
775 kPEAP
, kEAP_TLS
, kEAP_TTLS
, kLEAP
, kEAP_SIM
, kEAP_FAST
, kEAP_AKA
};
776 const std::vector
<const char*> valid_outer_values(
777 toVector(kValidOuterValues
));
779 if (FieldExistsAndHasNoValidValue(*result
, kInner
, valid_inner_values
) ||
780 FieldExistsAndHasNoValidValue(*result
, kOuter
, valid_outer_values
) ||
781 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
785 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
786 error_or_warning_found_
= true;
787 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
788 << " and " << kServerCARef
<< " can be set.";
792 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
797 bool all_required_exist
= RequireField(*result
, kOuter
);
799 return !error_on_missing_field_
|| all_required_exist
;
802 bool Validator::ValidateCertificate(base::DictionaryValue
* result
) {
803 using namespace ::onc::certificate
;
805 const char* const kValidTypes
[] = {kClient
, kServer
, kAuthority
};
806 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
807 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
808 FieldExistsAndIsEmpty(*result
, kGUID
)) {
813 result
->GetStringWithoutPathExpansion(kType
, &type
);
814 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
815 (type
== kServer
|| type
== kAuthority
)) {
816 error_or_warning_found_
= true;
817 LOG(ERROR
) << MessageHeader() << "Server and authority certificates are "
818 << "prohibited in ONC device policies.";
822 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &certificate_guids_
))
825 bool all_required_exist
= RequireField(*result
, kGUID
);
828 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
830 all_required_exist
&= RequireField(*result
, kType
);
833 all_required_exist
&= RequireField(*result
, kPKCS12
);
834 else if (type
== kServer
|| type
== kAuthority
)
835 all_required_exist
&= RequireField(*result
, kX509
);
838 return !error_on_missing_field_
|| all_required_exist
;
841 std::string
Validator::MessageHeader() {
842 std::string path
= path_
.empty() ? "toplevel" : JoinString(path_
, ".");
843 std::string message
= "At " + path
+ ": ";
848 } // namespace chromeos