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 valid
= ValidateIPConfig(repaired
.get());
114 else if (&signature
== &kWiFiSignature
)
115 valid
= ValidateWiFi(repaired
.get());
116 else if (&signature
== &kVPNSignature
)
117 valid
= ValidateVPN(repaired
.get());
118 else if (&signature
== &kIPsecSignature
)
119 valid
= ValidateIPsec(repaired
.get());
120 else if (&signature
== &kOpenVPNSignature
)
121 valid
= ValidateOpenVPN(repaired
.get());
122 else if (&signature
== &kVerifyX509Signature
)
123 valid
= ValidateVerifyX509(repaired
.get());
124 else if (&signature
== &kCertificatePatternSignature
)
125 valid
= ValidateCertificatePattern(repaired
.get());
126 else if (&signature
== &kProxySettingsSignature
)
127 valid
= ValidateProxySettings(repaired
.get());
128 else if (&signature
== &kProxyLocationSignature
)
129 valid
= ValidateProxyLocation(repaired
.get());
130 else if (&signature
== &kEAPSignature
)
131 valid
= ValidateEAP(repaired
.get());
132 else if (&signature
== &kCertificateSignature
)
133 valid
= ValidateCertificate(repaired
.get());
137 return repaired
.Pass();
139 DCHECK(error_or_warning_found_
);
140 error_or_warning_found_
= *error
= true;
141 return scoped_ptr
<base::DictionaryValue
>();
145 scoped_ptr
<base::Value
> Validator::MapField(
146 const std::string
& field_name
,
147 const OncValueSignature
& object_signature
,
148 const base::Value
& onc_value
,
149 bool* found_unknown_field
,
151 path_
.push_back(field_name
);
152 bool current_field_unknown
= false;
153 scoped_ptr
<base::Value
> result
= Mapper::MapField(
154 field_name
, object_signature
, onc_value
, ¤t_field_unknown
, error
);
156 DCHECK_EQ(field_name
, path_
.back());
159 if (current_field_unknown
) {
160 error_or_warning_found_
= *found_unknown_field
= true;
161 std::string message
= MessageHeader() + "Field name '" + field_name
+
163 if (error_on_unknown_field_
)
164 LOG(ERROR
) << message
;
166 LOG(WARNING
) << message
;
169 return result
.Pass();
172 scoped_ptr
<base::ListValue
> Validator::MapArray(
173 const OncValueSignature
& array_signature
,
174 const base::ListValue
& onc_array
,
175 bool* nested_error
) {
176 bool nested_error_in_current_array
= false;
177 scoped_ptr
<base::ListValue
> result
= Mapper::MapArray(
178 array_signature
, onc_array
, &nested_error_in_current_array
);
180 // Drop individual networks and certificates instead of rejecting all of
181 // the configuration.
182 if (nested_error_in_current_array
&&
183 &array_signature
!= &kNetworkConfigurationListSignature
&&
184 &array_signature
!= &kCertificateListSignature
) {
185 *nested_error
= nested_error_in_current_array
;
187 return result
.Pass();
190 scoped_ptr
<base::Value
> Validator::MapEntry(int index
,
191 const OncValueSignature
& signature
,
192 const base::Value
& onc_value
,
194 std::string str
= base::IntToString(index
);
195 path_
.push_back(str
);
196 scoped_ptr
<base::Value
> result
=
197 Mapper::MapEntry(index
, signature
, onc_value
, error
);
198 DCHECK_EQ(str
, path_
.back());
200 return result
.Pass();
203 bool Validator::ValidateObjectDefault(const OncValueSignature
& signature
,
204 const base::DictionaryValue
& onc_object
,
205 base::DictionaryValue
* result
) {
206 bool found_unknown_field
= false;
207 bool nested_error_occured
= false;
208 MapFields(signature
, onc_object
, &found_unknown_field
, &nested_error_occured
,
211 if (found_unknown_field
&& error_on_unknown_field_
) {
212 DVLOG(1) << "Unknown field names are errors: Aborting.";
216 if (nested_error_occured
)
219 return ValidateRecommendedField(signature
, result
);
222 bool Validator::ValidateRecommendedField(
223 const OncValueSignature
& object_signature
,
224 base::DictionaryValue
* result
) {
227 scoped_ptr
<base::ListValue
> recommended
;
228 scoped_ptr
<base::Value
> recommended_value
;
229 // This remove passes ownership to |recommended_value|.
230 if (!result
->RemoveWithoutPathExpansion(::onc::kRecommended
,
231 &recommended_value
)) {
234 base::ListValue
* recommended_list
= NULL
;
235 recommended_value
.release()->GetAsList(&recommended_list
);
236 CHECK(recommended_list
);
238 recommended
.reset(recommended_list
);
241 error_or_warning_found_
= true;
242 LOG(WARNING
) << MessageHeader() << "Found the field '"
243 << ::onc::kRecommended
244 << "' in an unmanaged ONC. Removing it.";
248 scoped_ptr
<base::ListValue
> repaired_recommended(new base::ListValue
);
249 for (base::ListValue::iterator it
= recommended
->begin();
250 it
!= recommended
->end(); ++it
) {
251 std::string field_name
;
252 if (!(*it
)->GetAsString(&field_name
)) {
257 const OncFieldSignature
* field_signature
=
258 GetFieldSignature(object_signature
, field_name
);
260 bool found_error
= false;
261 std::string error_cause
;
262 if (!field_signature
) {
264 error_cause
= "unknown";
265 } else if (field_signature
->value_signature
->onc_type
==
266 base::Value::TYPE_DICTIONARY
) {
268 error_cause
= "dictionary-typed";
272 error_or_warning_found_
= true;
273 path_
.push_back(::onc::kRecommended
);
274 std::string message
= MessageHeader() + "The " + error_cause
+
275 " field '" + field_name
+ "' cannot be recommended.";
277 if (error_on_wrong_recommended_
) {
278 LOG(ERROR
) << message
;
281 LOG(WARNING
) << message
;
286 repaired_recommended
->Append((*it
)->DeepCopy());
289 result
->Set(::onc::kRecommended
, repaired_recommended
.release());
293 bool Validator::ValidateClientCertFields(bool allow_cert_type_none
,
294 base::DictionaryValue
* result
) {
295 using namespace ::onc::client_cert
;
296 const char* const kValidCertTypes
[] = {kRef
, kPattern
};
297 std::vector
<const char*> valid_cert_types(toVector(kValidCertTypes
));
298 if (allow_cert_type_none
)
299 valid_cert_types
.push_back(kClientCertTypeNone
);
300 if (FieldExistsAndHasNoValidValue(*result
, kClientCertType
, valid_cert_types
))
303 std::string cert_type
;
304 result
->GetStringWithoutPathExpansion(kClientCertType
, &cert_type
);
306 if (IsCertPatternInDevicePolicy(cert_type
))
309 bool all_required_exist
= true;
311 if (cert_type
== kPattern
)
312 all_required_exist
&= RequireField(*result
, kClientCertPattern
);
313 else if (cert_type
== kRef
)
314 all_required_exist
&= RequireField(*result
, kClientCertRef
);
316 return !error_on_missing_field_
|| all_required_exist
;
321 std::string
JoinStringRange(const std::vector
<const char*>& strings
,
322 const std::string
& separator
) {
323 std::vector
<std::string
> string_vector
;
324 std::copy(strings
.begin(), strings
.end(), std::back_inserter(string_vector
));
325 return JoinString(string_vector
, separator
);
330 bool Validator::FieldExistsAndHasNoValidValue(
331 const base::DictionaryValue
& object
,
332 const std::string
& field_name
,
333 const std::vector
<const char*>& valid_values
) {
334 std::string actual_value
;
335 if (!object
.GetStringWithoutPathExpansion(field_name
, &actual_value
))
338 for (std::vector
<const char*>::const_iterator it
= valid_values
.begin();
339 it
!= valid_values
.end();
341 if (actual_value
== *it
)
344 error_or_warning_found_
= true;
345 std::string valid_values_str
=
346 "[" + JoinStringRange(valid_values
, ", ") + "]";
347 path_
.push_back(field_name
);
348 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
<<
349 "', but expected one of the values " << valid_values_str
;
354 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue
& object
,
355 const std::string
& field_name
,
359 if (!object
.GetIntegerWithoutPathExpansion(field_name
, &actual_value
) ||
360 (lower_bound
<= actual_value
&& actual_value
<= upper_bound
)) {
363 error_or_warning_found_
= true;
364 path_
.push_back(field_name
);
365 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
366 << "', but expected a value in the range [" << lower_bound
367 << ", " << upper_bound
<< "] (boundaries inclusive)";
372 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue
& object
,
373 const std::string
& field_name
) {
374 const base::Value
* value
= NULL
;
375 if (!object
.GetWithoutPathExpansion(field_name
, &value
))
379 const base::ListValue
* list
= NULL
;
380 if (value
->GetAsString(&str
)) {
383 } else if (value
->GetAsList(&list
)) {
391 error_or_warning_found_
= true;
392 path_
.push_back(field_name
);
393 LOG(ERROR
) << MessageHeader() << "Found an empty string, but expected a "
394 << "non-empty string.";
399 bool Validator::RequireField(const base::DictionaryValue
& dict
,
400 const std::string
& field_name
) {
401 if (dict
.HasKey(field_name
))
403 error_or_warning_found_
= true;
404 std::string message
= MessageHeader() + "The required field '" + field_name
+
406 if (error_on_missing_field_
)
407 LOG(ERROR
) << message
;
409 LOG(WARNING
) << message
;
413 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue
& dict
,
414 const std::string
& key_guid
,
415 std::set
<std::string
> *guids
) {
417 if (dict
.GetStringWithoutPathExpansion(key_guid
, &guid
)) {
418 if (guids
->count(guid
) != 0) {
419 error_or_warning_found_
= true;
420 LOG(ERROR
) << MessageHeader() << "Found a duplicate GUID " << guid
<< ".";
428 bool Validator::IsCertPatternInDevicePolicy(const std::string
& cert_type
) {
429 if (cert_type
== ::onc::client_cert::kPattern
&&
430 onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
) {
431 error_or_warning_found_
= true;
432 LOG(ERROR
) << MessageHeader() << "Client certificate patterns are "
433 << "prohibited in ONC device policies.";
439 bool Validator::IsGlobalNetworkConfigInUserImport(
440 const base::DictionaryValue
& onc_object
) {
441 if (onc_source_
== ::onc::ONC_SOURCE_USER_IMPORT
&&
442 onc_object
.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration
)) {
443 error_or_warning_found_
= true;
444 LOG(ERROR
) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
445 << "in ONC user imports";
451 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue
* result
) {
452 using namespace ::onc::toplevel_config
;
454 const char* const kValidTypes
[] = {kUnencryptedConfiguration
,
455 kEncryptedConfiguration
};
456 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
457 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
460 if (IsGlobalNetworkConfigInUserImport(*result
))
466 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue
* result
) {
467 using namespace ::onc::network_config
;
469 const char* const kValidTypes
[] = {
470 ::onc::network_type::kEthernet
, ::onc::network_type::kVPN
,
471 ::onc::network_type::kWiFi
, ::onc::network_type::kCellular
};
472 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
473 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
474 FieldExistsAndIsEmpty(*result
, kGUID
)) {
478 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &network_guids_
))
481 bool all_required_exist
= RequireField(*result
, kGUID
);
484 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
486 all_required_exist
&=
487 RequireField(*result
, kName
) && RequireField(*result
, kType
);
490 result
->GetStringWithoutPathExpansion(kType
, &type
);
492 // Prohibit anything but WiFi and Ethernet for device-level policy (which
493 // corresponds to shared networks). See also http://crosbug.com/28741.
494 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
495 type
!= ::onc::network_type::kWiFi
&&
496 type
!= ::onc::network_type::kEthernet
) {
497 error_or_warning_found_
= true;
498 LOG(ERROR
) << MessageHeader() << "Networks of type '"
499 << type
<< "' are prohibited in ONC device policies.";
503 if (type
== ::onc::network_type::kWiFi
) {
504 all_required_exist
&= RequireField(*result
, ::onc::network_config::kWiFi
);
505 } else if (type
== ::onc::network_type::kEthernet
) {
506 all_required_exist
&=
507 RequireField(*result
, ::onc::network_config::kEthernet
);
508 } else if (type
== ::onc::network_type::kCellular
) {
509 all_required_exist
&=
510 RequireField(*result
, ::onc::network_config::kCellular
);
511 } else if (type
== ::onc::network_type::kVPN
) {
512 all_required_exist
&= RequireField(*result
, ::onc::network_config::kVPN
);
513 } else if (!type
.empty()) {
518 return !error_on_missing_field_
|| all_required_exist
;
521 bool Validator::ValidateEthernet(base::DictionaryValue
* result
) {
522 using namespace ::onc::ethernet
;
524 const char* const kValidAuthentications
[] = {kAuthenticationNone
, k8021X
};
525 const std::vector
<const char*> valid_authentications(
526 toVector(kValidAuthentications
));
527 if (FieldExistsAndHasNoValidValue(
528 *result
, kAuthentication
, valid_authentications
)) {
532 bool all_required_exist
= true;
534 result
->GetStringWithoutPathExpansion(kAuthentication
, &auth
);
536 all_required_exist
&= RequireField(*result
, kEAP
);
538 return !error_on_missing_field_
|| all_required_exist
;
541 bool Validator::ValidateIPConfig(base::DictionaryValue
* result
) {
542 using namespace ::onc::ipconfig
;
544 const char* const kValidTypes
[] = {kIPv4
, kIPv6
};
545 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
546 if (FieldExistsAndHasNoValidValue(
547 *result
, ::onc::ipconfig::kType
, valid_types
))
551 result
->GetStringWithoutPathExpansion(::onc::ipconfig::kType
, &type
);
553 // In case of missing type, choose higher upper_bound.
554 int upper_bound
= (type
== kIPv4
) ? 32 : 128;
555 if (FieldExistsAndIsNotInRange(
556 *result
, kRoutingPrefix
, lower_bound
, upper_bound
)) {
560 bool all_required_exist
= RequireField(*result
, kIPAddress
) &&
561 RequireField(*result
, kRoutingPrefix
) &&
562 RequireField(*result
, ::onc::ipconfig::kType
);
564 return !error_on_missing_field_
|| all_required_exist
;
567 bool Validator::ValidateWiFi(base::DictionaryValue
* result
) {
568 using namespace ::onc::wifi
;
570 const char* const kValidSecurities
[] = {kSecurityNone
, kWEP_PSK
, kWEP_8021X
,
572 const std::vector
<const char*> valid_securities(toVector(kValidSecurities
));
573 if (FieldExistsAndHasNoValidValue(*result
, kSecurity
, valid_securities
))
576 bool all_required_exist
=
577 RequireField(*result
, kSecurity
) && RequireField(*result
, kSSID
);
579 std::string security
;
580 result
->GetStringWithoutPathExpansion(kSecurity
, &security
);
581 if (security
== kWEP_8021X
|| security
== kWPA_EAP
)
582 all_required_exist
&= RequireField(*result
, kEAP
);
583 else if (security
== kWEP_PSK
|| security
== kWPA_PSK
)
584 all_required_exist
&= RequireField(*result
, kPassphrase
);
586 return !error_on_missing_field_
|| all_required_exist
;
589 bool Validator::ValidateVPN(base::DictionaryValue
* result
) {
590 using namespace ::onc::vpn
;
592 const char* const kValidTypes
[] = {kIPsec
, kTypeL2TP_IPsec
, kOpenVPN
};
593 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
594 if (FieldExistsAndHasNoValidValue(*result
, ::onc::vpn::kType
, valid_types
))
597 bool all_required_exist
= RequireField(*result
, ::onc::vpn::kType
);
599 result
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
600 if (type
== kOpenVPN
) {
601 all_required_exist
&= RequireField(*result
, kOpenVPN
);
602 } else if (type
== kIPsec
) {
603 all_required_exist
&= RequireField(*result
, kIPsec
);
604 } else if (type
== kTypeL2TP_IPsec
) {
605 all_required_exist
&=
606 RequireField(*result
, kIPsec
) && RequireField(*result
, kL2TP
);
609 return !error_on_missing_field_
|| all_required_exist
;
612 bool Validator::ValidateIPsec(base::DictionaryValue
* result
) {
613 using namespace ::onc::ipsec
;
615 const char* const kValidAuthentications
[] = {kPSK
, kCert
};
616 const std::vector
<const char*> valid_authentications(
617 toVector(kValidAuthentications
));
618 if (FieldExistsAndHasNoValidValue(
619 *result
, kAuthenticationType
, valid_authentications
) ||
620 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
624 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
625 error_or_warning_found_
= true;
626 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
627 << " and " << kServerCARef
<< " can be set.";
631 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
636 bool all_required_exist
= RequireField(*result
, kAuthenticationType
) &&
637 RequireField(*result
, kIKEVersion
);
639 result
->GetStringWithoutPathExpansion(kAuthenticationType
, &auth
);
640 bool has_server_ca_cert
=
641 result
->HasKey(kServerCARefs
) || result
->HasKey(kServerCARef
);
643 all_required_exist
&=
644 RequireField(*result
, ::onc::client_cert::kClientCertType
);
645 if (!has_server_ca_cert
) {
646 all_required_exist
= false;
647 error_or_warning_found_
= true;
648 std::string message
= MessageHeader() + "The required field '" +
649 kServerCARefs
+ "' is missing.";
650 if (error_on_missing_field_
)
651 LOG(ERROR
) << message
;
653 LOG(WARNING
) << message
;
655 } else if (has_server_ca_cert
) {
656 error_or_warning_found_
= true;
657 LOG(ERROR
) << MessageHeader() << kServerCARefs
<< " (or " << kServerCARef
658 << ") can only be set if " << kAuthenticationType
659 << " is set to " << kCert
<< ".";
663 return !error_on_missing_field_
|| all_required_exist
;
666 bool Validator::ValidateOpenVPN(base::DictionaryValue
* result
) {
667 using namespace ::onc::openvpn
;
669 const char* const kValidAuthRetryValues
[] = {::onc::openvpn::kNone
, kInteract
,
671 const std::vector
<const char*> valid_auth_retry_values(
672 toVector(kValidAuthRetryValues
));
673 const char* const kValidCertTlsValues
[] = {::onc::openvpn::kNone
,
674 ::onc::openvpn::kServer
};
675 const std::vector
<const char*> valid_cert_tls_values(
676 toVector(kValidCertTlsValues
));
678 if (FieldExistsAndHasNoValidValue(
679 *result
, kAuthRetry
, valid_auth_retry_values
) ||
680 FieldExistsAndHasNoValidValue(
681 *result
, kRemoteCertTLS
, valid_cert_tls_values
) ||
682 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
686 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
687 error_or_warning_found_
= true;
688 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
689 << " and " << kServerCARef
<< " can be set.";
693 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result
))
696 bool all_required_exist
=
697 RequireField(*result
, ::onc::client_cert::kClientCertType
);
699 return !error_on_missing_field_
|| all_required_exist
;
702 bool Validator::ValidateVerifyX509(base::DictionaryValue
* result
) {
703 using namespace ::onc::verify_x509
;
705 const char* const kValidTypes
[] = {types::kName
, types::kNamePrefix
,
707 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
709 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
712 bool all_required_exist
= RequireField(*result
, kName
);
714 return !error_on_missing_field_
|| all_required_exist
;
717 bool Validator::ValidateCertificatePattern(base::DictionaryValue
* result
) {
718 using namespace ::onc::client_cert
;
720 bool all_required_exist
= true;
721 if (!result
->HasKey(kSubject
) && !result
->HasKey(kIssuer
) &&
722 !result
->HasKey(kIssuerCARef
)) {
723 error_or_warning_found_
= true;
724 all_required_exist
= false;
725 std::string message
= MessageHeader() + "None of the fields '" + kSubject
+
726 "', '" + kIssuer
+ "', and '" + kIssuerCARef
+
727 "' is present, but at least one is required.";
728 if (error_on_missing_field_
)
729 LOG(ERROR
) << message
;
731 LOG(WARNING
) << message
;
734 return !error_on_missing_field_
|| all_required_exist
;
737 bool Validator::ValidateProxySettings(base::DictionaryValue
* result
) {
738 using namespace ::onc::proxy
;
740 const char* const kValidTypes
[] = {kDirect
, kManual
, kPAC
, kWPAD
};
741 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
742 if (FieldExistsAndHasNoValidValue(*result
, ::onc::proxy::kType
, valid_types
))
745 bool all_required_exist
= RequireField(*result
, ::onc::proxy::kType
);
747 result
->GetStringWithoutPathExpansion(::onc::proxy::kType
, &type
);
749 all_required_exist
&= RequireField(*result
, kManual
);
750 else if (type
== kPAC
)
751 all_required_exist
&= RequireField(*result
, kPAC
);
753 return !error_on_missing_field_
|| all_required_exist
;
756 bool Validator::ValidateProxyLocation(base::DictionaryValue
* result
) {
757 using namespace ::onc::proxy
;
759 bool all_required_exist
=
760 RequireField(*result
, kHost
) && RequireField(*result
, kPort
);
762 return !error_on_missing_field_
|| all_required_exist
;
765 bool Validator::ValidateEAP(base::DictionaryValue
* result
) {
766 using namespace ::onc::eap
;
768 const char* const kValidInnerValues
[] = {kAutomatic
, kMD5
, kMSCHAPv2
, kPAP
};
769 const std::vector
<const char*> valid_inner_values(
770 toVector(kValidInnerValues
));
771 const char* const kValidOuterValues
[] = {
772 kPEAP
, kEAP_TLS
, kEAP_TTLS
, kLEAP
, kEAP_SIM
, kEAP_FAST
, kEAP_AKA
};
773 const std::vector
<const char*> valid_outer_values(
774 toVector(kValidOuterValues
));
776 if (FieldExistsAndHasNoValidValue(*result
, kInner
, valid_inner_values
) ||
777 FieldExistsAndHasNoValidValue(*result
, kOuter
, valid_outer_values
) ||
778 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
782 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
783 error_or_warning_found_
= true;
784 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
785 << " and " << kServerCARef
<< " can be set.";
789 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
794 bool all_required_exist
= RequireField(*result
, kOuter
);
796 return !error_on_missing_field_
|| all_required_exist
;
799 bool Validator::ValidateCertificate(base::DictionaryValue
* result
) {
800 using namespace ::onc::certificate
;
802 const char* const kValidTypes
[] = {kClient
, kServer
, kAuthority
};
803 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
804 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
805 FieldExistsAndIsEmpty(*result
, kGUID
)) {
810 result
->GetStringWithoutPathExpansion(kType
, &type
);
811 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
812 (type
== kServer
|| type
== kAuthority
)) {
813 error_or_warning_found_
= true;
814 LOG(ERROR
) << MessageHeader() << "Server and authority certificates are "
815 << "prohibited in ONC device policies.";
819 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &certificate_guids_
))
822 bool all_required_exist
= RequireField(*result
, kGUID
);
825 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
827 all_required_exist
&= RequireField(*result
, kType
);
830 all_required_exist
&= RequireField(*result
, kPKCS12
);
831 else if (type
== kServer
|| type
== kAuthority
)
832 all_required_exist
&= RequireField(*result
, kX509
);
835 return !error_on_missing_field_
|| all_required_exist
;
838 std::string
Validator::MessageHeader() {
839 std::string path
= path_
.empty() ? "toplevel" : JoinString(path_
, ".");
840 std::string message
= "At " + path
+ ": ";
845 } // namespace chromeos