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
== &kThirdPartyVPNSignature
) {
126 valid
= ValidateThirdPartyVPN(repaired
.get());
127 } else if (&signature
== &kVerifyX509Signature
) {
128 valid
= ValidateVerifyX509(repaired
.get());
129 } else if (&signature
== &kCertificatePatternSignature
) {
130 valid
= ValidateCertificatePattern(repaired
.get());
131 } else if (&signature
== &kGlobalNetworkConfigurationSignature
) {
132 valid
= ValidateGlobalNetworkConfiguration(repaired
.get());
133 } else if (&signature
== &kProxySettingsSignature
) {
134 valid
= ValidateProxySettings(repaired
.get());
135 } else if (&signature
== &kProxyLocationSignature
) {
136 valid
= ValidateProxyLocation(repaired
.get());
137 } else if (&signature
== &kEAPSignature
) {
138 valid
= ValidateEAP(repaired
.get());
139 } else if (&signature
== &kCertificateSignature
) {
140 valid
= ValidateCertificate(repaired
.get());
145 return repaired
.Pass();
147 DCHECK(error_or_warning_found_
);
148 error_or_warning_found_
= *error
= true;
149 return scoped_ptr
<base::DictionaryValue
>();
153 scoped_ptr
<base::Value
> Validator::MapField(
154 const std::string
& field_name
,
155 const OncValueSignature
& object_signature
,
156 const base::Value
& onc_value
,
157 bool* found_unknown_field
,
159 path_
.push_back(field_name
);
160 bool current_field_unknown
= false;
161 scoped_ptr
<base::Value
> result
= Mapper::MapField(
162 field_name
, object_signature
, onc_value
, ¤t_field_unknown
, error
);
164 DCHECK_EQ(field_name
, path_
.back());
167 if (current_field_unknown
) {
168 error_or_warning_found_
= *found_unknown_field
= true;
169 std::string message
= MessageHeader() + "Field name '" + field_name
+
171 if (error_on_unknown_field_
)
172 LOG(ERROR
) << message
;
174 LOG(WARNING
) << message
;
177 return result
.Pass();
180 scoped_ptr
<base::ListValue
> Validator::MapArray(
181 const OncValueSignature
& array_signature
,
182 const base::ListValue
& onc_array
,
183 bool* nested_error
) {
184 bool nested_error_in_current_array
= false;
185 scoped_ptr
<base::ListValue
> result
= Mapper::MapArray(
186 array_signature
, onc_array
, &nested_error_in_current_array
);
188 // Drop individual networks and certificates instead of rejecting all of
189 // the configuration.
190 if (nested_error_in_current_array
&&
191 &array_signature
!= &kNetworkConfigurationListSignature
&&
192 &array_signature
!= &kCertificateListSignature
) {
193 *nested_error
= nested_error_in_current_array
;
195 return result
.Pass();
198 scoped_ptr
<base::Value
> Validator::MapEntry(int index
,
199 const OncValueSignature
& signature
,
200 const base::Value
& onc_value
,
202 std::string str
= base::IntToString(index
);
203 path_
.push_back(str
);
204 scoped_ptr
<base::Value
> result
=
205 Mapper::MapEntry(index
, signature
, onc_value
, error
);
206 DCHECK_EQ(str
, path_
.back());
208 return result
.Pass();
211 bool Validator::ValidateObjectDefault(const OncValueSignature
& signature
,
212 const base::DictionaryValue
& onc_object
,
213 base::DictionaryValue
* result
) {
214 bool found_unknown_field
= false;
215 bool nested_error_occured
= false;
216 MapFields(signature
, onc_object
, &found_unknown_field
, &nested_error_occured
,
219 if (found_unknown_field
&& error_on_unknown_field_
) {
220 DVLOG(1) << "Unknown field names are errors: Aborting.";
224 if (nested_error_occured
)
227 return ValidateRecommendedField(signature
, result
);
230 bool Validator::ValidateRecommendedField(
231 const OncValueSignature
& object_signature
,
232 base::DictionaryValue
* result
) {
235 scoped_ptr
<base::Value
> recommended_value
;
236 // This remove passes ownership to |recommended_value|.
237 if (!result
->RemoveWithoutPathExpansion(::onc::kRecommended
,
238 &recommended_value
)) {
242 base::ListValue
* recommended_list
= nullptr;
243 recommended_value
->GetAsList(&recommended_list
);
244 DCHECK(recommended_list
); // The types of field values are already verified.
247 error_or_warning_found_
= true;
248 LOG(WARNING
) << MessageHeader() << "Found the field '"
249 << ::onc::kRecommended
250 << "' in an unmanaged ONC. Removing it.";
254 scoped_ptr
<base::ListValue
> repaired_recommended(new base::ListValue
);
255 for (const base::Value
* entry
: *recommended_list
) {
256 std::string field_name
;
257 if (!entry
->GetAsString(&field_name
)) {
258 NOTREACHED(); // The types of field values are already verified.
262 const OncFieldSignature
* field_signature
=
263 GetFieldSignature(object_signature
, field_name
);
265 bool found_error
= false;
266 std::string error_cause
;
267 if (!field_signature
) {
269 error_cause
= "unknown";
270 } else if (field_signature
->value_signature
->onc_type
==
271 base::Value::TYPE_DICTIONARY
) {
273 error_cause
= "dictionary-typed";
277 error_or_warning_found_
= true;
278 path_
.push_back(::onc::kRecommended
);
279 std::string message
= MessageHeader() + "The " + error_cause
+
280 " field '" + field_name
+ "' cannot be recommended.";
282 if (error_on_wrong_recommended_
) {
283 LOG(ERROR
) << message
;
286 LOG(WARNING
) << message
;
291 repaired_recommended
->AppendString(field_name
);
294 result
->Set(::onc::kRecommended
, repaired_recommended
.release());
298 bool Validator::ValidateClientCertFields(bool allow_cert_type_none
,
299 base::DictionaryValue
* result
) {
300 using namespace ::onc::client_cert
;
301 const char* const kValidCertTypes
[] = {kRef
, kPattern
};
302 std::vector
<const char*> valid_cert_types(toVector(kValidCertTypes
));
303 if (allow_cert_type_none
)
304 valid_cert_types
.push_back(kClientCertTypeNone
);
305 if (FieldExistsAndHasNoValidValue(*result
, kClientCertType
, valid_cert_types
))
308 std::string cert_type
;
309 result
->GetStringWithoutPathExpansion(kClientCertType
, &cert_type
);
311 if (IsCertPatternInDevicePolicy(cert_type
))
314 bool all_required_exist
= true;
316 if (cert_type
== kPattern
)
317 all_required_exist
&= RequireField(*result
, kClientCertPattern
);
318 else if (cert_type
== kRef
)
319 all_required_exist
&= RequireField(*result
, kClientCertRef
);
321 return !error_on_missing_field_
|| all_required_exist
;
326 std::string
JoinStringRange(const std::vector
<const char*>& strings
,
327 const std::string
& separator
) {
328 std::vector
<std::string
> string_vector
;
329 std::copy(strings
.begin(), strings
.end(), std::back_inserter(string_vector
));
330 return base::JoinString(string_vector
, separator
);
335 bool Validator::IsValidValue(const std::string
& field_value
,
336 const std::vector
<const char*>& valid_values
) {
337 for (const char* it
: valid_values
) {
338 if (field_value
== it
)
341 error_or_warning_found_
= true;
342 const std::string valid_values_str
=
343 "[" + JoinStringRange(valid_values
, ", ") + "]";
344 LOG(ERROR
) << MessageHeader() << "Found value '" << field_value
345 << "', but expected one of the values " << valid_values_str
;
349 bool Validator::FieldExistsAndHasNoValidValue(
350 const base::DictionaryValue
& object
,
351 const std::string
& field_name
,
352 const std::vector
<const char*>& valid_values
) {
353 std::string actual_value
;
354 if (!object
.GetStringWithoutPathExpansion(field_name
, &actual_value
))
357 path_
.push_back(field_name
);
358 const bool valid
= IsValidValue(actual_value
, valid_values
);
363 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue
& object
,
364 const std::string
& field_name
,
368 if (!object
.GetIntegerWithoutPathExpansion(field_name
, &actual_value
) ||
369 (lower_bound
<= actual_value
&& actual_value
<= upper_bound
)) {
372 error_or_warning_found_
= true;
373 path_
.push_back(field_name
);
374 LOG(ERROR
) << MessageHeader() << "Found value '" << actual_value
375 << "', but expected a value in the range [" << lower_bound
376 << ", " << upper_bound
<< "] (boundaries inclusive)";
381 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue
& object
,
382 const std::string
& field_name
) {
383 const base::Value
* value
= NULL
;
384 if (!object
.GetWithoutPathExpansion(field_name
, &value
))
388 const base::ListValue
* list
= NULL
;
389 if (value
->GetAsString(&str
)) {
392 } else if (value
->GetAsList(&list
)) {
400 error_or_warning_found_
= true;
401 path_
.push_back(field_name
);
402 LOG(ERROR
) << MessageHeader() << "Found an empty string, but expected a "
403 << "non-empty string.";
408 bool Validator::ListFieldContainsValidValues(
409 const base::DictionaryValue
& object
,
410 const std::string
& field_name
,
411 const std::vector
<const char*>& valid_values
) {
412 const base::ListValue
* list
= NULL
;
413 if (object
.GetListWithoutPathExpansion(field_name
, &list
)) {
414 path_
.push_back(field_name
);
415 for (const base::Value
* entry
: *list
) {
417 if (!entry
->GetAsString(&value
)) {
418 NOTREACHED(); // The types of field values are already verified.
421 if (!IsValidValue(value
, valid_values
)) {
431 bool Validator::ValidateSSIDAndHexSSID(base::DictionaryValue
* object
) {
432 // Check SSID validity.
433 std::string ssid_string
;
434 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kSSID
, &ssid_string
) &&
435 (ssid_string
.size() <= 0 ||
436 ssid_string
.size() > kMaximumSSIDLengthInBytes
)) {
437 error_or_warning_found_
= true;
438 const std::string msg
=
439 MessageHeader() + ::onc::wifi::kSSID
+ " has an invalid length.";
440 // If the HexSSID field is present, ignore errors in SSID because these
441 // might be caused by the usage of a non-UTF-8 encoding when the SSID
442 // field was automatically added (see FillInHexSSIDField).
443 if (object
->HasKey(::onc::wifi::kHexSSID
)) {
451 // Check HexSSID validity.
452 std::string hex_ssid_string
;
453 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID
,
455 std::vector
<uint8
> decoded_ssid
;
456 if (!base::HexStringToBytes(hex_ssid_string
, &decoded_ssid
)) {
457 LOG(ERROR
) << MessageHeader() << "Field " << ::onc::wifi::kHexSSID
458 << " is not a valid hex representation: \"" << hex_ssid_string
460 error_or_warning_found_
= true;
463 if (decoded_ssid
.size() <= 0 ||
464 decoded_ssid
.size() > kMaximumSSIDLengthInBytes
) {
465 LOG(ERROR
) << MessageHeader() << ::onc::wifi::kHexSSID
466 << " has an invalid length.";
467 error_or_warning_found_
= true;
471 // If both SSID and HexSSID are set, check whether they are consistent, i.e.
472 // HexSSID contains the UTF-8 encoding of SSID. If not, remove the SSID
474 if (ssid_string
.length() > 0) {
475 std::string
decoded_ssid_string(
476 reinterpret_cast<const char*>(&decoded_ssid
[0]), decoded_ssid
.size());
477 if (ssid_string
!= decoded_ssid_string
) {
478 LOG(WARNING
) << MessageHeader() << "Fields " << ::onc::wifi::kSSID
479 << " and " << ::onc::wifi::kHexSSID
480 << " contain inconsistent values. Removing "
481 << ::onc::wifi::kSSID
<< ".";
482 error_or_warning_found_
= true;
483 object
->RemoveWithoutPathExpansion(::onc::wifi::kSSID
, nullptr);
490 bool Validator::RequireField(const base::DictionaryValue
& dict
,
491 const std::string
& field_name
) {
492 if (dict
.HasKey(field_name
))
494 std::string message
= MessageHeader() + "The required field '" + field_name
+
496 if (error_on_missing_field_
) {
497 error_or_warning_found_
= true;
498 LOG(ERROR
) << message
;
505 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue
& dict
,
506 const std::string
& key_guid
,
507 std::set
<std::string
> *guids
) {
509 if (dict
.GetStringWithoutPathExpansion(key_guid
, &guid
)) {
510 if (guids
->count(guid
) != 0) {
511 error_or_warning_found_
= true;
512 LOG(ERROR
) << MessageHeader() << "Found a duplicate GUID " << guid
<< ".";
520 bool Validator::IsCertPatternInDevicePolicy(const std::string
& cert_type
) {
521 if (cert_type
== ::onc::client_cert::kPattern
&&
522 onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
) {
523 error_or_warning_found_
= true;
524 LOG(ERROR
) << MessageHeader() << "Client certificate patterns are "
525 << "prohibited in ONC device policies.";
531 bool Validator::IsGlobalNetworkConfigInUserImport(
532 const base::DictionaryValue
& onc_object
) {
533 if (onc_source_
== ::onc::ONC_SOURCE_USER_IMPORT
&&
534 onc_object
.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration
)) {
535 error_or_warning_found_
= true;
536 LOG(ERROR
) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
537 << "in ONC user imports";
543 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue
* result
) {
544 using namespace ::onc::toplevel_config
;
546 const char* const kValidTypes
[] = {kUnencryptedConfiguration
,
547 kEncryptedConfiguration
};
548 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
549 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
552 if (IsGlobalNetworkConfigInUserImport(*result
))
558 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue
* result
) {
559 using namespace ::onc::network_config
;
561 const char* const kValidTypes
[] = {::onc::network_type::kEthernet
,
562 ::onc::network_type::kVPN
,
563 ::onc::network_type::kWiFi
,
564 ::onc::network_type::kCellular
,
565 ::onc::network_type::kWimax
};
566 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
567 const char* const kValidIPConfigTypes
[] = {kIPConfigTypeDHCP
,
568 kIPConfigTypeStatic
};
569 const std::vector
<const char*> valid_ipconfig_types(
570 toVector(kValidIPConfigTypes
));
571 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
572 FieldExistsAndHasNoValidValue(*result
, kIPAddressConfigType
,
573 valid_ipconfig_types
) ||
574 FieldExistsAndHasNoValidValue(*result
, kNameServersConfigType
,
575 valid_ipconfig_types
) ||
576 FieldExistsAndIsEmpty(*result
, kGUID
)) {
580 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &network_guids_
))
583 bool all_required_exist
= RequireField(*result
, kGUID
);
586 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
588 all_required_exist
&=
589 RequireField(*result
, kName
) && RequireField(*result
, kType
);
591 std::string ip_address_config_type
, name_servers_config_type
;
592 result
->GetStringWithoutPathExpansion(kIPAddressConfigType
,
593 &ip_address_config_type
);
594 result
->GetStringWithoutPathExpansion(kNameServersConfigType
,
595 &name_servers_config_type
);
596 if (ip_address_config_type
== kIPConfigTypeStatic
||
597 name_servers_config_type
== kIPConfigTypeStatic
) {
598 // TODO(pneubeck): Add ValidateStaticIPConfig and confirm that the
599 // correct properties are provided based on the config type.
600 all_required_exist
&= RequireField(*result
, kStaticIPConfig
);
604 result
->GetStringWithoutPathExpansion(kType
, &type
);
606 // Prohibit anything but WiFi and Ethernet for device-level policy (which
607 // corresponds to shared networks). See also http://crosbug.com/28741.
608 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&& !type
.empty() &&
609 type
!= ::onc::network_type::kWiFi
&&
610 type
!= ::onc::network_type::kEthernet
) {
611 error_or_warning_found_
= true;
612 LOG(ERROR
) << MessageHeader() << "Networks of type '"
613 << type
<< "' are prohibited in ONC device policies.";
617 if (type
== ::onc::network_type::kWiFi
) {
618 all_required_exist
&= RequireField(*result
, ::onc::network_config::kWiFi
);
619 } else if (type
== ::onc::network_type::kEthernet
) {
620 all_required_exist
&=
621 RequireField(*result
, ::onc::network_config::kEthernet
);
622 } else if (type
== ::onc::network_type::kCellular
) {
623 all_required_exist
&=
624 RequireField(*result
, ::onc::network_config::kCellular
);
625 } else if (type
== ::onc::network_type::kWimax
) {
626 all_required_exist
&=
627 RequireField(*result
, ::onc::network_config::kWimax
);
628 } else if (type
== ::onc::network_type::kVPN
) {
629 all_required_exist
&= RequireField(*result
, ::onc::network_config::kVPN
);
633 return !error_on_missing_field_
|| all_required_exist
;
636 bool Validator::ValidateEthernet(base::DictionaryValue
* result
) {
637 using namespace ::onc::ethernet
;
639 const char* const kValidAuthentications
[] = {kAuthenticationNone
, k8021X
};
640 const std::vector
<const char*> valid_authentications(
641 toVector(kValidAuthentications
));
642 if (FieldExistsAndHasNoValidValue(
643 *result
, kAuthentication
, valid_authentications
)) {
647 bool all_required_exist
= true;
649 result
->GetStringWithoutPathExpansion(kAuthentication
, &auth
);
651 all_required_exist
&= RequireField(*result
, kEAP
);
653 return !error_on_missing_field_
|| all_required_exist
;
656 bool Validator::ValidateIPConfig(base::DictionaryValue
* result
) {
657 using namespace ::onc::ipconfig
;
659 const char* const kValidTypes
[] = {kIPv4
, kIPv6
};
660 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
661 if (FieldExistsAndHasNoValidValue(
662 *result
, ::onc::ipconfig::kType
, valid_types
))
666 result
->GetStringWithoutPathExpansion(::onc::ipconfig::kType
, &type
);
668 // In case of missing type, choose higher upper_bound.
669 int upper_bound
= (type
== kIPv4
) ? 32 : 128;
670 if (FieldExistsAndIsNotInRange(
671 *result
, kRoutingPrefix
, lower_bound
, upper_bound
)) {
675 bool all_required_exist
= RequireField(*result
, kIPAddress
) &&
676 RequireField(*result
, ::onc::ipconfig::kType
);
677 if (result
->HasKey(kIPAddress
))
678 all_required_exist
&= RequireField(*result
, kRoutingPrefix
);
681 return !error_on_missing_field_
|| all_required_exist
;
684 bool Validator::ValidateWiFi(base::DictionaryValue
* result
) {
685 using namespace ::onc::wifi
;
687 const char* const kValidSecurities
[] = {kSecurityNone
, kWEP_PSK
, kWEP_8021X
,
689 const std::vector
<const char*> valid_securities(toVector(kValidSecurities
));
690 if (FieldExistsAndHasNoValidValue(*result
, kSecurity
, valid_securities
))
693 if (!ValidateSSIDAndHexSSID(result
))
696 bool all_required_exist
= RequireField(*result
, kSecurity
);
698 // One of {kSSID, kHexSSID} must be present.
699 if (!result
->HasKey(kSSID
))
700 all_required_exist
&= RequireField(*result
, kHexSSID
);
701 if (!result
->HasKey(kHexSSID
))
702 all_required_exist
&= RequireField(*result
, kSSID
);
704 std::string security
;
705 result
->GetStringWithoutPathExpansion(kSecurity
, &security
);
706 if (security
== kWEP_8021X
|| security
== kWPA_EAP
)
707 all_required_exist
&= RequireField(*result
, kEAP
);
708 else if (security
== kWEP_PSK
|| security
== kWPA_PSK
)
709 all_required_exist
&= RequireField(*result
, kPassphrase
);
711 return !error_on_missing_field_
|| all_required_exist
;
714 bool Validator::ValidateVPN(base::DictionaryValue
* result
) {
715 using namespace ::onc::vpn
;
717 const char* const kValidTypes
[] = {
718 kIPsec
, kTypeL2TP_IPsec
, kOpenVPN
, kThirdPartyVpn
};
719 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
720 if (FieldExistsAndHasNoValidValue(*result
, ::onc::vpn::kType
, valid_types
))
723 bool all_required_exist
= RequireField(*result
, ::onc::vpn::kType
);
725 result
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
726 if (type
== kOpenVPN
) {
727 all_required_exist
&= RequireField(*result
, kOpenVPN
);
728 } else if (type
== kIPsec
) {
729 all_required_exist
&= RequireField(*result
, kIPsec
);
730 } else if (type
== kTypeL2TP_IPsec
) {
731 all_required_exist
&=
732 RequireField(*result
, kIPsec
) && RequireField(*result
, kL2TP
);
733 } else if (type
== kThirdPartyVpn
) {
734 all_required_exist
&= RequireField(*result
, kThirdPartyVpn
);
737 return !error_on_missing_field_
|| all_required_exist
;
740 bool Validator::ValidateIPsec(base::DictionaryValue
* result
) {
741 using namespace ::onc::ipsec
;
743 const char* const kValidAuthentications
[] = {kPSK
, kCert
};
744 const std::vector
<const char*> valid_authentications(
745 toVector(kValidAuthentications
));
746 if (FieldExistsAndHasNoValidValue(
747 *result
, kAuthenticationType
, valid_authentications
) ||
748 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
752 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
753 error_or_warning_found_
= true;
754 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
755 << " and " << kServerCARef
<< " can be set.";
759 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
764 bool all_required_exist
= RequireField(*result
, kAuthenticationType
) &&
765 RequireField(*result
, kIKEVersion
);
767 result
->GetStringWithoutPathExpansion(kAuthenticationType
, &auth
);
768 bool has_server_ca_cert
=
769 result
->HasKey(kServerCARefs
) || result
->HasKey(kServerCARef
);
771 all_required_exist
&=
772 RequireField(*result
, ::onc::client_cert::kClientCertType
);
773 if (!has_server_ca_cert
) {
774 all_required_exist
= false;
775 error_or_warning_found_
= true;
776 std::string message
= MessageHeader() + "The required field '" +
777 kServerCARefs
+ "' is missing.";
778 if (error_on_missing_field_
)
779 LOG(ERROR
) << message
;
781 LOG(WARNING
) << message
;
783 } else if (has_server_ca_cert
) {
784 error_or_warning_found_
= true;
785 LOG(ERROR
) << MessageHeader() << kServerCARefs
<< " (or " << kServerCARef
786 << ") can only be set if " << kAuthenticationType
787 << " is set to " << kCert
<< ".";
791 return !error_on_missing_field_
|| all_required_exist
;
794 bool Validator::ValidateOpenVPN(base::DictionaryValue
* result
) {
795 using namespace ::onc::openvpn
;
797 const char* const kValidAuthRetryValues
[] = {::onc::openvpn::kNone
, kInteract
,
799 const std::vector
<const char*> valid_auth_retry_values(
800 toVector(kValidAuthRetryValues
));
801 const char* const kValidCertTlsValues
[] = {::onc::openvpn::kNone
,
802 ::onc::openvpn::kServer
};
803 const std::vector
<const char*> valid_cert_tls_values(
804 toVector(kValidCertTlsValues
));
805 const char* const kValidUserAuthTypes
[] = {
806 ::onc::openvpn_user_auth_type::kNone
,
807 ::onc::openvpn_user_auth_type::kOTP
,
808 ::onc::openvpn_user_auth_type::kPassword
,
809 ::onc::openvpn_user_auth_type::kPasswordAndOTP
};
810 const std::vector
<const char*> valid_user_auth_types(
811 toVector(kValidUserAuthTypes
));
813 if (FieldExistsAndHasNoValidValue(
814 *result
, kAuthRetry
, valid_auth_retry_values
) ||
815 FieldExistsAndHasNoValidValue(
816 *result
, kRemoteCertTLS
, valid_cert_tls_values
) ||
817 FieldExistsAndHasNoValidValue(
818 *result
, kUserAuthenticationType
, valid_user_auth_types
) ||
819 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
823 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
824 error_or_warning_found_
= true;
825 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
826 << " and " << kServerCARef
<< " can be set.";
830 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result
))
833 bool all_required_exist
=
834 RequireField(*result
, ::onc::client_cert::kClientCertType
);
836 return !error_on_missing_field_
|| all_required_exist
;
839 bool Validator::ValidateThirdPartyVPN(base::DictionaryValue
* result
) {
840 const bool all_required_exist
=
841 RequireField(*result
, ::onc::third_party_vpn::kExtensionID
);
843 return !error_on_missing_field_
|| all_required_exist
;
846 bool Validator::ValidateVerifyX509(base::DictionaryValue
* result
) {
847 using namespace ::onc::verify_x509
;
849 const char* const kValidTypes
[] = {types::kName
, types::kNamePrefix
,
851 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
853 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
856 bool all_required_exist
= RequireField(*result
, kName
);
858 return !error_on_missing_field_
|| all_required_exist
;
861 bool Validator::ValidateCertificatePattern(base::DictionaryValue
* result
) {
862 using namespace ::onc::client_cert
;
864 bool all_required_exist
= true;
865 if (!result
->HasKey(kSubject
) && !result
->HasKey(kIssuer
) &&
866 !result
->HasKey(kIssuerCARef
)) {
867 error_or_warning_found_
= true;
868 all_required_exist
= false;
869 std::string message
= MessageHeader() + "None of the fields '" + kSubject
+
870 "', '" + kIssuer
+ "', and '" + kIssuerCARef
+
871 "' is present, but at least one is required.";
872 if (error_on_missing_field_
)
873 LOG(ERROR
) << message
;
875 LOG(WARNING
) << message
;
878 return !error_on_missing_field_
|| all_required_exist
;
881 bool Validator::ValidateGlobalNetworkConfiguration(
882 base::DictionaryValue
* result
) {
883 using namespace ::onc::global_network_config
;
884 using namespace ::onc::network_config
;
886 // Validate kDisableNetworkTypes field.
887 const base::ListValue
* disabled_network_types
= NULL
;
888 if (result
->GetListWithoutPathExpansion(kDisableNetworkTypes
,
889 &disabled_network_types
)) {
890 // The kDisableNetworkTypes field is only allowed in user policy.
891 if (!disabled_network_types
->empty() &&
892 onc_source_
!= ::onc::ONC_SOURCE_USER_POLICY
) {
893 error_or_warning_found_
= true;
894 LOG(ERROR
) << "Disabled network types only allowed in user policy.";
899 // Ensure the list contains only legitimate network type identifiers.
900 const char* const kValidNetworkTypeValues
[] = {kCellular
, kEthernet
, kWiFi
,
902 const std::vector
<const char*> valid_network_type_values(
903 toVector(kValidNetworkTypeValues
));
904 if (!ListFieldContainsValidValues(*result
, kDisableNetworkTypes
,
905 valid_network_type_values
)) {
911 bool Validator::ValidateProxySettings(base::DictionaryValue
* result
) {
912 using namespace ::onc::proxy
;
914 const char* const kValidTypes
[] = {kDirect
, kManual
, kPAC
, kWPAD
};
915 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
916 if (FieldExistsAndHasNoValidValue(*result
, ::onc::proxy::kType
, valid_types
))
919 bool all_required_exist
= RequireField(*result
, ::onc::proxy::kType
);
921 result
->GetStringWithoutPathExpansion(::onc::proxy::kType
, &type
);
923 all_required_exist
&= RequireField(*result
, kManual
);
924 else if (type
== kPAC
)
925 all_required_exist
&= RequireField(*result
, kPAC
);
927 return !error_on_missing_field_
|| all_required_exist
;
930 bool Validator::ValidateProxyLocation(base::DictionaryValue
* result
) {
931 using namespace ::onc::proxy
;
933 bool all_required_exist
=
934 RequireField(*result
, kHost
) && RequireField(*result
, kPort
);
936 return !error_on_missing_field_
|| all_required_exist
;
939 bool Validator::ValidateEAP(base::DictionaryValue
* result
) {
940 using namespace ::onc::eap
;
942 const char* const kValidInnerValues
[] = {
943 kAutomatic
, kGTC
, kMD5
, kMSCHAPv2
, kPAP
};
944 const std::vector
<const char*> valid_inner_values(
945 toVector(kValidInnerValues
));
946 const char* const kValidOuterValues
[] = {
947 kPEAP
, kEAP_TLS
, kEAP_TTLS
, kLEAP
, kEAP_SIM
, kEAP_FAST
, kEAP_AKA
};
948 const std::vector
<const char*> valid_outer_values(
949 toVector(kValidOuterValues
));
951 if (FieldExistsAndHasNoValidValue(*result
, kInner
, valid_inner_values
) ||
952 FieldExistsAndHasNoValidValue(*result
, kOuter
, valid_outer_values
) ||
953 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
957 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
958 error_or_warning_found_
= true;
959 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
960 << " and " << kServerCARef
<< " can be set.";
964 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
969 bool all_required_exist
= RequireField(*result
, kOuter
);
971 return !error_on_missing_field_
|| all_required_exist
;
974 bool Validator::ValidateCertificate(base::DictionaryValue
* result
) {
975 using namespace ::onc::certificate
;
977 const char* const kValidTypes
[] = {kClient
, kServer
, kAuthority
};
978 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
979 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
980 FieldExistsAndIsEmpty(*result
, kGUID
)) {
985 result
->GetStringWithoutPathExpansion(kType
, &type
);
986 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
987 (type
== kServer
|| type
== kAuthority
)) {
988 error_or_warning_found_
= true;
989 LOG(ERROR
) << MessageHeader() << "Server and authority certificates are "
990 << "prohibited in ONC device policies.";
994 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &certificate_guids_
))
997 bool all_required_exist
= RequireField(*result
, kGUID
);
1000 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
1002 all_required_exist
&= RequireField(*result
, kType
);
1004 if (type
== kClient
)
1005 all_required_exist
&= RequireField(*result
, kPKCS12
);
1006 else if (type
== kServer
|| type
== kAuthority
)
1007 all_required_exist
&= RequireField(*result
, kX509
);
1010 return !error_on_missing_field_
|| all_required_exist
;
1013 std::string
Validator::MessageHeader() {
1014 std::string path
= path_
.empty() ? "toplevel" : base::JoinString(path_
, ".");
1015 std::string message
= "At " + path
+ ": ";
1020 } // namespace chromeos