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"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "chromeos/network/onc/onc_signature.h"
21 // According to the IEEE 802.11 standard the SSID is a series of 0 to 32 octets.
22 const int kMaximumSSIDLengthInBytes
= 32;
24 template <typename T
, size_t N
>
25 std::vector
<T
> toVector(T
const (&array
)[N
]) {
26 return std::vector
<T
>(array
, array
+ N
);
29 // Copied from policy/configuration_policy_handler.cc.
30 // TODO(pneubeck): move to a common place like base/.
31 std::string
ValueTypeToString(base::Value::Type type
) {
32 const char* const strings
[] = {"null", "boolean", "integer", "double",
33 "string", "binary", "dictionary", "list"};
34 CHECK(static_cast<size_t>(type
) < arraysize(strings
));
40 Validator::Validator(bool error_on_unknown_field
,
41 bool error_on_wrong_recommended
,
42 bool error_on_missing_field
,
44 : error_on_unknown_field_(error_on_unknown_field
),
45 error_on_wrong_recommended_(error_on_wrong_recommended
),
46 error_on_missing_field_(error_on_missing_field
),
47 managed_onc_(managed_onc
),
48 onc_source_(::onc::ONC_SOURCE_NONE
) {}
50 Validator::~Validator() {}
52 scoped_ptr
<base::DictionaryValue
> Validator::ValidateAndRepairObject(
53 const OncValueSignature
* object_signature
,
54 const base::DictionaryValue
& onc_object
,
56 CHECK(object_signature
);
58 error_or_warning_found_
= false;
60 scoped_ptr
<base::Value
> result_value
=
61 MapValue(*object_signature
, onc_object
, &error
);
65 } else if (error_or_warning_found_
) {
66 *result
= VALID_WITH_WARNINGS
;
68 // The return value should be NULL if, and only if, |result| equals INVALID.
69 DCHECK_EQ(result_value
.get() == NULL
, *result
== INVALID
);
71 base::DictionaryValue
* result_dict
= NULL
;
73 result_value
.release()->GetAsDictionary(&result_dict
);
77 return make_scoped_ptr(result_dict
);
80 scoped_ptr
<base::Value
> Validator::MapValue(const OncValueSignature
& signature
,
81 const base::Value
& onc_value
,
83 if (onc_value
.GetType() != signature
.onc_type
) {
84 LOG(ERROR
) << MessageHeader() << "Found value '" << onc_value
85 << "' of type '" << ValueTypeToString(onc_value
.GetType())
86 << "', but type '" << ValueTypeToString(signature
.onc_type
)
88 error_or_warning_found_
= *error
= true;
89 return scoped_ptr
<base::Value
>();
92 scoped_ptr
<base::Value
> repaired
=
93 Mapper::MapValue(signature
, onc_value
, error
);
95 CHECK_EQ(repaired
->GetType(), signature
.onc_type
);
96 return repaired
.Pass();
99 scoped_ptr
<base::DictionaryValue
> Validator::MapObject(
100 const OncValueSignature
& signature
,
101 const base::DictionaryValue
& onc_object
,
103 scoped_ptr
<base::DictionaryValue
> repaired(new base::DictionaryValue
);
105 bool valid
= ValidateObjectDefault(signature
, onc_object
, repaired
.get());
107 if (&signature
== &kToplevelConfigurationSignature
) {
108 valid
= ValidateToplevelConfiguration(repaired
.get());
109 } else if (&signature
== &kNetworkConfigurationSignature
) {
110 valid
= ValidateNetworkConfiguration(repaired
.get());
111 } else if (&signature
== &kEthernetSignature
) {
112 valid
= ValidateEthernet(repaired
.get());
113 } else if (&signature
== &kIPConfigSignature
||
114 &signature
== &kSavedIPConfigSignature
||
115 &signature
== &kStaticIPConfigSignature
) {
116 valid
= ValidateIPConfig(repaired
.get());
117 } else if (&signature
== &kWiFiSignature
) {
118 valid
= ValidateWiFi(repaired
.get());
119 } else if (&signature
== &kVPNSignature
) {
120 valid
= ValidateVPN(repaired
.get());
121 } else if (&signature
== &kIPsecSignature
) {
122 valid
= ValidateIPsec(repaired
.get());
123 } else if (&signature
== &kOpenVPNSignature
) {
124 valid
= ValidateOpenVPN(repaired
.get());
125 } else if (&signature
== &kVerifyX509Signature
) {
126 valid
= ValidateVerifyX509(repaired
.get());
127 } else if (&signature
== &kCertificatePatternSignature
) {
128 valid
= ValidateCertificatePattern(repaired
.get());
129 } else if (&signature
== &kProxySettingsSignature
) {
130 valid
= ValidateProxySettings(repaired
.get());
131 } else if (&signature
== &kProxyLocationSignature
) {
132 valid
= ValidateProxyLocation(repaired
.get());
133 } else if (&signature
== &kEAPSignature
) {
134 valid
= ValidateEAP(repaired
.get());
135 } else if (&signature
== &kCertificateSignature
) {
136 valid
= ValidateCertificate(repaired
.get());
141 return repaired
.Pass();
143 DCHECK(error_or_warning_found_
);
144 error_or_warning_found_
= *error
= true;
145 return scoped_ptr
<base::DictionaryValue
>();
149 scoped_ptr
<base::Value
> Validator::MapField(
150 const std::string
& field_name
,
151 const OncValueSignature
& object_signature
,
152 const base::Value
& onc_value
,
153 bool* found_unknown_field
,
155 path_
.push_back(field_name
);
156 bool current_field_unknown
= false;
157 scoped_ptr
<base::Value
> result
= Mapper::MapField(
158 field_name
, object_signature
, onc_value
, ¤t_field_unknown
, error
);
160 DCHECK_EQ(field_name
, path_
.back());
163 if (current_field_unknown
) {
164 error_or_warning_found_
= *found_unknown_field
= true;
165 std::string message
= MessageHeader() + "Field name '" + field_name
+
167 if (error_on_unknown_field_
)
168 LOG(ERROR
) << message
;
170 LOG(WARNING
) << message
;
173 return result
.Pass();
176 scoped_ptr
<base::ListValue
> Validator::MapArray(
177 const OncValueSignature
& array_signature
,
178 const base::ListValue
& onc_array
,
179 bool* nested_error
) {
180 bool nested_error_in_current_array
= false;
181 scoped_ptr
<base::ListValue
> result
= Mapper::MapArray(
182 array_signature
, onc_array
, &nested_error_in_current_array
);
184 // Drop individual networks and certificates instead of rejecting all of
185 // the configuration.
186 if (nested_error_in_current_array
&&
187 &array_signature
!= &kNetworkConfigurationListSignature
&&
188 &array_signature
!= &kCertificateListSignature
) {
189 *nested_error
= nested_error_in_current_array
;
191 return result
.Pass();
194 scoped_ptr
<base::Value
> Validator::MapEntry(int index
,
195 const OncValueSignature
& signature
,
196 const base::Value
& onc_value
,
198 std::string str
= base::IntToString(index
);
199 path_
.push_back(str
);
200 scoped_ptr
<base::Value
> result
=
201 Mapper::MapEntry(index
, signature
, onc_value
, error
);
202 DCHECK_EQ(str
, path_
.back());
204 return result
.Pass();
207 bool Validator::ValidateObjectDefault(const OncValueSignature
& signature
,
208 const base::DictionaryValue
& onc_object
,
209 base::DictionaryValue
* result
) {
210 bool found_unknown_field
= false;
211 bool nested_error_occured
= false;
212 MapFields(signature
, onc_object
, &found_unknown_field
, &nested_error_occured
,
215 if (found_unknown_field
&& error_on_unknown_field_
) {
216 DVLOG(1) << "Unknown field names are errors: Aborting.";
220 if (nested_error_occured
)
223 return ValidateRecommendedField(signature
, result
);
226 bool Validator::ValidateRecommendedField(
227 const OncValueSignature
& object_signature
,
228 base::DictionaryValue
* result
) {
231 scoped_ptr
<base::Value
> recommended_value
;
232 // This remove passes ownership to |recommended_value|.
233 if (!result
->RemoveWithoutPathExpansion(::onc::kRecommended
,
234 &recommended_value
)) {
238 base::ListValue
* recommended_list
= nullptr;
239 recommended_value
->GetAsList(&recommended_list
);
240 DCHECK(recommended_list
); // The types of field values are already verified.
243 error_or_warning_found_
= true;
244 LOG(WARNING
) << MessageHeader() << "Found the field '"
245 << ::onc::kRecommended
246 << "' in an unmanaged ONC. Removing it.";
250 scoped_ptr
<base::ListValue
> repaired_recommended(new base::ListValue
);
251 for (const base::Value
* entry
: *recommended_list
) {
252 std::string field_name
;
253 if (!entry
->GetAsString(&field_name
)) {
254 NOTREACHED(); // The types of field values are already verified.
258 const OncFieldSignature
* field_signature
=
259 GetFieldSignature(object_signature
, field_name
);
261 bool found_error
= false;
262 std::string error_cause
;
263 if (!field_signature
) {
265 error_cause
= "unknown";
266 } else if (field_signature
->value_signature
->onc_type
==
267 base::Value::TYPE_DICTIONARY
) {
269 error_cause
= "dictionary-typed";
273 error_or_warning_found_
= true;
274 path_
.push_back(::onc::kRecommended
);
275 std::string message
= MessageHeader() + "The " + error_cause
+
276 " field '" + field_name
+ "' cannot be recommended.";
278 if (error_on_wrong_recommended_
) {
279 LOG(ERROR
) << message
;
282 LOG(WARNING
) << message
;
287 repaired_recommended
->AppendString(field_name
);
290 result
->Set(::onc::kRecommended
, repaired_recommended
.release());
294 bool Validator::ValidateClientCertFields(bool allow_cert_type_none
,
295 base::DictionaryValue
* result
) {
296 using namespace ::onc::client_cert
;
297 const char* const kValidCertTypes
[] = {kRef
, kPattern
};
298 std::vector
<const char*> valid_cert_types(toVector(kValidCertTypes
));
299 if (allow_cert_type_none
)
300 valid_cert_types
.push_back(kClientCertTypeNone
);
301 if (FieldExistsAndHasNoValidValue(*result
, kClientCertType
, valid_cert_types
))
304 std::string cert_type
;
305 result
->GetStringWithoutPathExpansion(kClientCertType
, &cert_type
);
307 if (IsCertPatternInDevicePolicy(cert_type
))
310 bool all_required_exist
= true;
312 if (cert_type
== kPattern
)
313 all_required_exist
&= RequireField(*result
, kClientCertPattern
);
314 else if (cert_type
== kRef
)
315 all_required_exist
&= RequireField(*result
, kClientCertRef
);
317 return !error_on_missing_field_
|| all_required_exist
;
322 std::string
JoinStringRange(const std::vector
<const char*>& strings
,
323 const std::string
& separator
) {
324 std::vector
<std::string
> string_vector
;
325 std::copy(strings
.begin(), strings
.end(), std::back_inserter(string_vector
));
326 return JoinString(string_vector
, separator
);
331 bool Validator::FieldExistsAndHasNoValidValue(
332 const base::DictionaryValue
& object
,
333 const std::string
& field_name
,
334 const std::vector
<const char*>& valid_values
) {
335 std::string actual_value
;
336 if (!object
.GetStringWithoutPathExpansion(field_name
, &actual_value
))
339 for (std::vector
<const char*>::const_iterator it
= valid_values
.begin();
340 it
!= valid_values
.end();
342 if (actual_value
== *it
)
345 error_or_warning_found_
= true;
346 std::string valid_values_str
=
347 "[" + JoinStringRange(valid_values
, ", ") + "]";
348 path_
.push_back(field_name
);
349 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
<<
350 "', but expected one of the values " << valid_values_str
;
355 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue
& object
,
356 const std::string
& field_name
,
360 if (!object
.GetIntegerWithoutPathExpansion(field_name
, &actual_value
) ||
361 (lower_bound
<= actual_value
&& actual_value
<= upper_bound
)) {
364 error_or_warning_found_
= true;
365 path_
.push_back(field_name
);
366 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
367 << "', but expected a value in the range [" << lower_bound
368 << ", " << upper_bound
<< "] (boundaries inclusive)";
373 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue
& object
,
374 const std::string
& field_name
) {
375 const base::Value
* value
= NULL
;
376 if (!object
.GetWithoutPathExpansion(field_name
, &value
))
380 const base::ListValue
* list
= NULL
;
381 if (value
->GetAsString(&str
)) {
384 } else if (value
->GetAsList(&list
)) {
392 error_or_warning_found_
= true;
393 path_
.push_back(field_name
);
394 LOG(ERROR
) << MessageHeader() << "Found an empty string, but expected a "
395 << "non-empty string.";
400 bool Validator::ValidateSSIDAndHexSSID(base::DictionaryValue
* object
) {
401 // Check SSID validity.
402 std::string ssid_string
;
403 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kSSID
, &ssid_string
) &&
404 (ssid_string
.size() <= 0 ||
405 ssid_string
.size() > kMaximumSSIDLengthInBytes
)) {
406 error_or_warning_found_
= true;
407 const std::string msg
=
408 MessageHeader() + ::onc::wifi::kSSID
+ " has an invalid length.";
409 // If the HexSSID field is present, ignore errors in SSID because these
410 // might be caused by the usage of a non-UTF-8 encoding when the SSID
411 // field was automatically added (see FillInHexSSIDField).
412 if (object
->HasKey(::onc::wifi::kHexSSID
)) {
420 // Check HexSSID validity.
421 std::string hex_ssid_string
;
422 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID
,
424 std::vector
<uint8
> decoded_ssid
;
425 if (!base::HexStringToBytes(hex_ssid_string
, &decoded_ssid
)) {
426 LOG(ERROR
) << MessageHeader() << "Field " << ::onc::wifi::kHexSSID
427 << " is not a valid hex representation: \"" << hex_ssid_string
429 error_or_warning_found_
= true;
432 if (decoded_ssid
.size() <= 0 ||
433 decoded_ssid
.size() > kMaximumSSIDLengthInBytes
) {
434 LOG(ERROR
) << MessageHeader() << ::onc::wifi::kHexSSID
435 << " has an invalid length.";
436 error_or_warning_found_
= true;
440 // If both SSID and HexSSID are set, check whether they are consistent, i.e.
441 // HexSSID contains the UTF-8 encoding of SSID. If not, remove the SSID
443 if (ssid_string
.length() > 0) {
444 std::string
decoded_ssid_string(
445 reinterpret_cast<const char*>(&decoded_ssid
[0]), decoded_ssid
.size());
446 if (ssid_string
!= decoded_ssid_string
) {
447 LOG(WARNING
) << MessageHeader() << "Fields " << ::onc::wifi::kSSID
448 << " and " << ::onc::wifi::kHexSSID
449 << " contain inconsistent values. Removing "
450 << ::onc::wifi::kSSID
<< ".";
451 error_or_warning_found_
= true;
452 object
->RemoveWithoutPathExpansion(::onc::wifi::kSSID
, nullptr);
459 bool Validator::RequireField(const base::DictionaryValue
& dict
,
460 const std::string
& field_name
) {
461 if (dict
.HasKey(field_name
))
463 std::string message
= MessageHeader() + "The required field '" + field_name
+
465 if (error_on_missing_field_
) {
466 error_or_warning_found_
= true;
467 LOG(ERROR
) << message
;
474 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue
& dict
,
475 const std::string
& key_guid
,
476 std::set
<std::string
> *guids
) {
478 if (dict
.GetStringWithoutPathExpansion(key_guid
, &guid
)) {
479 if (guids
->count(guid
) != 0) {
480 error_or_warning_found_
= true;
481 LOG(ERROR
) << MessageHeader() << "Found a duplicate GUID " << guid
<< ".";
489 bool Validator::IsCertPatternInDevicePolicy(const std::string
& cert_type
) {
490 if (cert_type
== ::onc::client_cert::kPattern
&&
491 onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
) {
492 error_or_warning_found_
= true;
493 LOG(ERROR
) << MessageHeader() << "Client certificate patterns are "
494 << "prohibited in ONC device policies.";
500 bool Validator::IsGlobalNetworkConfigInUserImport(
501 const base::DictionaryValue
& onc_object
) {
502 if (onc_source_
== ::onc::ONC_SOURCE_USER_IMPORT
&&
503 onc_object
.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration
)) {
504 error_or_warning_found_
= true;
505 LOG(ERROR
) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
506 << "in ONC user imports";
512 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue
* result
) {
513 using namespace ::onc::toplevel_config
;
515 const char* const kValidTypes
[] = {kUnencryptedConfiguration
,
516 kEncryptedConfiguration
};
517 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
518 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
521 if (IsGlobalNetworkConfigInUserImport(*result
))
527 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue
* result
) {
528 using namespace ::onc::network_config
;
530 const char* const kValidTypes
[] = {::onc::network_type::kEthernet
,
531 ::onc::network_type::kVPN
,
532 ::onc::network_type::kWiFi
,
533 ::onc::network_type::kCellular
,
534 ::onc::network_type::kWimax
};
535 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
536 const char* const kValidIPConfigTypes
[] = {kIPConfigTypeDHCP
,
537 kIPConfigTypeStatic
};
538 const std::vector
<const char*> valid_ipconfig_types(
539 toVector(kValidIPConfigTypes
));
540 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
541 FieldExistsAndHasNoValidValue(*result
, kIPAddressConfigType
,
542 valid_ipconfig_types
) ||
543 FieldExistsAndHasNoValidValue(*result
, kNameServersConfigType
,
544 valid_ipconfig_types
) ||
545 FieldExistsAndIsEmpty(*result
, kGUID
)) {
549 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &network_guids_
))
552 bool all_required_exist
= RequireField(*result
, kGUID
);
555 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
557 all_required_exist
&=
558 RequireField(*result
, kName
) && RequireField(*result
, kType
);
560 std::string ip_address_config_type
, name_servers_config_type
;
561 result
->GetStringWithoutPathExpansion(kIPAddressConfigType
,
562 &ip_address_config_type
);
563 result
->GetStringWithoutPathExpansion(kNameServersConfigType
,
564 &name_servers_config_type
);
565 if (ip_address_config_type
== kIPConfigTypeStatic
||
566 name_servers_config_type
== kIPConfigTypeStatic
) {
567 // TODO(pneubeck): Add ValidateStaticIPConfig and confirm that the
568 // correct properties are provided based on the config type.
569 all_required_exist
&= RequireField(*result
, kStaticIPConfig
);
573 result
->GetStringWithoutPathExpansion(kType
, &type
);
575 // Prohibit anything but WiFi and Ethernet for device-level policy (which
576 // corresponds to shared networks). See also http://crosbug.com/28741.
577 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&& !type
.empty() &&
578 type
!= ::onc::network_type::kWiFi
&&
579 type
!= ::onc::network_type::kEthernet
) {
580 error_or_warning_found_
= true;
581 LOG(ERROR
) << MessageHeader() << "Networks of type '"
582 << type
<< "' are prohibited in ONC device policies.";
586 if (type
== ::onc::network_type::kWiFi
) {
587 all_required_exist
&= RequireField(*result
, ::onc::network_config::kWiFi
);
588 } else if (type
== ::onc::network_type::kEthernet
) {
589 all_required_exist
&=
590 RequireField(*result
, ::onc::network_config::kEthernet
);
591 } else if (type
== ::onc::network_type::kCellular
) {
592 all_required_exist
&=
593 RequireField(*result
, ::onc::network_config::kCellular
);
594 } else if (type
== ::onc::network_type::kWimax
) {
595 all_required_exist
&=
596 RequireField(*result
, ::onc::network_config::kWimax
);
597 } else if (type
== ::onc::network_type::kVPN
) {
598 all_required_exist
&= RequireField(*result
, ::onc::network_config::kVPN
);
602 return !error_on_missing_field_
|| all_required_exist
;
605 bool Validator::ValidateEthernet(base::DictionaryValue
* result
) {
606 using namespace ::onc::ethernet
;
608 const char* const kValidAuthentications
[] = {kAuthenticationNone
, k8021X
};
609 const std::vector
<const char*> valid_authentications(
610 toVector(kValidAuthentications
));
611 if (FieldExistsAndHasNoValidValue(
612 *result
, kAuthentication
, valid_authentications
)) {
616 bool all_required_exist
= true;
618 result
->GetStringWithoutPathExpansion(kAuthentication
, &auth
);
620 all_required_exist
&= RequireField(*result
, kEAP
);
622 return !error_on_missing_field_
|| all_required_exist
;
625 bool Validator::ValidateIPConfig(base::DictionaryValue
* result
) {
626 using namespace ::onc::ipconfig
;
628 const char* const kValidTypes
[] = {kIPv4
, kIPv6
};
629 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
630 if (FieldExistsAndHasNoValidValue(
631 *result
, ::onc::ipconfig::kType
, valid_types
))
635 result
->GetStringWithoutPathExpansion(::onc::ipconfig::kType
, &type
);
637 // In case of missing type, choose higher upper_bound.
638 int upper_bound
= (type
== kIPv4
) ? 32 : 128;
639 if (FieldExistsAndIsNotInRange(
640 *result
, kRoutingPrefix
, lower_bound
, upper_bound
)) {
644 bool all_required_exist
= RequireField(*result
, kIPAddress
) &&
645 RequireField(*result
, ::onc::ipconfig::kType
);
646 if (result
->HasKey(kIPAddress
))
647 all_required_exist
&= RequireField(*result
, kRoutingPrefix
);
650 return !error_on_missing_field_
|| all_required_exist
;
653 bool Validator::ValidateWiFi(base::DictionaryValue
* result
) {
654 using namespace ::onc::wifi
;
656 const char* const kValidSecurities
[] = {kSecurityNone
, kWEP_PSK
, kWEP_8021X
,
658 const std::vector
<const char*> valid_securities(toVector(kValidSecurities
));
659 if (FieldExistsAndHasNoValidValue(*result
, kSecurity
, valid_securities
))
662 if (!ValidateSSIDAndHexSSID(result
))
665 bool all_required_exist
= RequireField(*result
, kSecurity
);
667 // One of {kSSID, kHexSSID} must be present.
668 if (!result
->HasKey(kSSID
))
669 all_required_exist
&= RequireField(*result
, kHexSSID
);
670 if (!result
->HasKey(kHexSSID
))
671 all_required_exist
&= RequireField(*result
, kSSID
);
673 std::string security
;
674 result
->GetStringWithoutPathExpansion(kSecurity
, &security
);
675 if (security
== kWEP_8021X
|| security
== kWPA_EAP
)
676 all_required_exist
&= RequireField(*result
, kEAP
);
677 else if (security
== kWEP_PSK
|| security
== kWPA_PSK
)
678 all_required_exist
&= RequireField(*result
, kPassphrase
);
680 return !error_on_missing_field_
|| all_required_exist
;
683 bool Validator::ValidateVPN(base::DictionaryValue
* result
) {
684 using namespace ::onc::vpn
;
686 const char* const kValidTypes
[] = {kIPsec
, kTypeL2TP_IPsec
, kOpenVPN
};
687 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
688 if (FieldExistsAndHasNoValidValue(*result
, ::onc::vpn::kType
, valid_types
))
691 bool all_required_exist
= RequireField(*result
, ::onc::vpn::kType
);
693 result
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
694 if (type
== kOpenVPN
) {
695 all_required_exist
&= RequireField(*result
, kOpenVPN
);
696 } else if (type
== kIPsec
) {
697 all_required_exist
&= RequireField(*result
, kIPsec
);
698 } else if (type
== kTypeL2TP_IPsec
) {
699 all_required_exist
&=
700 RequireField(*result
, kIPsec
) && RequireField(*result
, kL2TP
);
703 return !error_on_missing_field_
|| all_required_exist
;
706 bool Validator::ValidateIPsec(base::DictionaryValue
* result
) {
707 using namespace ::onc::ipsec
;
709 const char* const kValidAuthentications
[] = {kPSK
, kCert
};
710 const std::vector
<const char*> valid_authentications(
711 toVector(kValidAuthentications
));
712 if (FieldExistsAndHasNoValidValue(
713 *result
, kAuthenticationType
, valid_authentications
) ||
714 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
718 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
719 error_or_warning_found_
= true;
720 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
721 << " and " << kServerCARef
<< " can be set.";
725 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
730 bool all_required_exist
= RequireField(*result
, kAuthenticationType
) &&
731 RequireField(*result
, kIKEVersion
);
733 result
->GetStringWithoutPathExpansion(kAuthenticationType
, &auth
);
734 bool has_server_ca_cert
=
735 result
->HasKey(kServerCARefs
) || result
->HasKey(kServerCARef
);
737 all_required_exist
&=
738 RequireField(*result
, ::onc::client_cert::kClientCertType
);
739 if (!has_server_ca_cert
) {
740 all_required_exist
= false;
741 error_or_warning_found_
= true;
742 std::string message
= MessageHeader() + "The required field '" +
743 kServerCARefs
+ "' is missing.";
744 if (error_on_missing_field_
)
745 LOG(ERROR
) << message
;
747 LOG(WARNING
) << message
;
749 } else if (has_server_ca_cert
) {
750 error_or_warning_found_
= true;
751 LOG(ERROR
) << MessageHeader() << kServerCARefs
<< " (or " << kServerCARef
752 << ") can only be set if " << kAuthenticationType
753 << " is set to " << kCert
<< ".";
757 return !error_on_missing_field_
|| all_required_exist
;
760 bool Validator::ValidateOpenVPN(base::DictionaryValue
* result
) {
761 using namespace ::onc::openvpn
;
763 const char* const kValidAuthRetryValues
[] = {::onc::openvpn::kNone
, kInteract
,
765 const std::vector
<const char*> valid_auth_retry_values(
766 toVector(kValidAuthRetryValues
));
767 const char* const kValidCertTlsValues
[] = {::onc::openvpn::kNone
,
768 ::onc::openvpn::kServer
};
769 const std::vector
<const char*> valid_cert_tls_values(
770 toVector(kValidCertTlsValues
));
771 const char* const kValidUserAuthTypes
[] = {
772 ::onc::openvpn_user_auth_type::kNone
,
773 ::onc::openvpn_user_auth_type::kOTP
,
774 ::onc::openvpn_user_auth_type::kPassword
,
775 ::onc::openvpn_user_auth_type::kPasswordAndOTP
};
776 const std::vector
<const char*> valid_user_auth_types(
777 toVector(kValidUserAuthTypes
));
779 if (FieldExistsAndHasNoValidValue(
780 *result
, kAuthRetry
, valid_auth_retry_values
) ||
781 FieldExistsAndHasNoValidValue(
782 *result
, kRemoteCertTLS
, valid_cert_tls_values
) ||
783 FieldExistsAndHasNoValidValue(
784 *result
, kUserAuthenticationType
, valid_user_auth_types
) ||
785 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
789 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
790 error_or_warning_found_
= true;
791 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
792 << " and " << kServerCARef
<< " can be set.";
796 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result
))
799 bool all_required_exist
=
800 RequireField(*result
, ::onc::client_cert::kClientCertType
);
802 return !error_on_missing_field_
|| all_required_exist
;
805 bool Validator::ValidateVerifyX509(base::DictionaryValue
* result
) {
806 using namespace ::onc::verify_x509
;
808 const char* const kValidTypes
[] = {types::kName
, types::kNamePrefix
,
810 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
812 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
815 bool all_required_exist
= RequireField(*result
, kName
);
817 return !error_on_missing_field_
|| all_required_exist
;
820 bool Validator::ValidateCertificatePattern(base::DictionaryValue
* result
) {
821 using namespace ::onc::client_cert
;
823 bool all_required_exist
= true;
824 if (!result
->HasKey(kSubject
) && !result
->HasKey(kIssuer
) &&
825 !result
->HasKey(kIssuerCARef
)) {
826 error_or_warning_found_
= true;
827 all_required_exist
= false;
828 std::string message
= MessageHeader() + "None of the fields '" + kSubject
+
829 "', '" + kIssuer
+ "', and '" + kIssuerCARef
+
830 "' is present, but at least one is required.";
831 if (error_on_missing_field_
)
832 LOG(ERROR
) << message
;
834 LOG(WARNING
) << message
;
837 return !error_on_missing_field_
|| all_required_exist
;
840 bool Validator::ValidateProxySettings(base::DictionaryValue
* result
) {
841 using namespace ::onc::proxy
;
843 const char* const kValidTypes
[] = {kDirect
, kManual
, kPAC
, kWPAD
};
844 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
845 if (FieldExistsAndHasNoValidValue(*result
, ::onc::proxy::kType
, valid_types
))
848 bool all_required_exist
= RequireField(*result
, ::onc::proxy::kType
);
850 result
->GetStringWithoutPathExpansion(::onc::proxy::kType
, &type
);
852 all_required_exist
&= RequireField(*result
, kManual
);
853 else if (type
== kPAC
)
854 all_required_exist
&= RequireField(*result
, kPAC
);
856 return !error_on_missing_field_
|| all_required_exist
;
859 bool Validator::ValidateProxyLocation(base::DictionaryValue
* result
) {
860 using namespace ::onc::proxy
;
862 bool all_required_exist
=
863 RequireField(*result
, kHost
) && RequireField(*result
, kPort
);
865 return !error_on_missing_field_
|| all_required_exist
;
868 bool Validator::ValidateEAP(base::DictionaryValue
* result
) {
869 using namespace ::onc::eap
;
871 const char* const kValidInnerValues
[] = {kAutomatic
, kMD5
, kMSCHAPv2
, kPAP
};
872 const std::vector
<const char*> valid_inner_values(
873 toVector(kValidInnerValues
));
874 const char* const kValidOuterValues
[] = {
875 kPEAP
, kEAP_TLS
, kEAP_TTLS
, kLEAP
, kEAP_SIM
, kEAP_FAST
, kEAP_AKA
};
876 const std::vector
<const char*> valid_outer_values(
877 toVector(kValidOuterValues
));
879 if (FieldExistsAndHasNoValidValue(*result
, kInner
, valid_inner_values
) ||
880 FieldExistsAndHasNoValidValue(*result
, kOuter
, valid_outer_values
) ||
881 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
885 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
886 error_or_warning_found_
= true;
887 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
888 << " and " << kServerCARef
<< " can be set.";
892 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
897 bool all_required_exist
= RequireField(*result
, kOuter
);
899 return !error_on_missing_field_
|| all_required_exist
;
902 bool Validator::ValidateCertificate(base::DictionaryValue
* result
) {
903 using namespace ::onc::certificate
;
905 const char* const kValidTypes
[] = {kClient
, kServer
, kAuthority
};
906 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
907 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
908 FieldExistsAndIsEmpty(*result
, kGUID
)) {
913 result
->GetStringWithoutPathExpansion(kType
, &type
);
914 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
915 (type
== kServer
|| type
== kAuthority
)) {
916 error_or_warning_found_
= true;
917 LOG(ERROR
) << MessageHeader() << "Server and authority certificates are "
918 << "prohibited in ONC device policies.";
922 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &certificate_guids_
))
925 bool all_required_exist
= RequireField(*result
, kGUID
);
928 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
930 all_required_exist
&= RequireField(*result
, kType
);
933 all_required_exist
&= RequireField(*result
, kPKCS12
);
934 else if (type
== kServer
|| type
== kAuthority
)
935 all_required_exist
&= RequireField(*result
, kX509
);
938 return !error_on_missing_field_
|| all_required_exist
;
941 std::string
Validator::MessageHeader() {
942 std::string path
= path_
.empty() ? "toplevel" : JoinString(path_
, ".");
943 std::string message
= "At " + path
+ ": ";
948 } // namespace chromeos