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
== &kProxySettingsSignature
) {
132 valid
= ValidateProxySettings(repaired
.get());
133 } else if (&signature
== &kProxyLocationSignature
) {
134 valid
= ValidateProxyLocation(repaired
.get());
135 } else if (&signature
== &kEAPSignature
) {
136 valid
= ValidateEAP(repaired
.get());
137 } else if (&signature
== &kCertificateSignature
) {
138 valid
= ValidateCertificate(repaired
.get());
143 return repaired
.Pass();
145 DCHECK(error_or_warning_found_
);
146 error_or_warning_found_
= *error
= true;
147 return scoped_ptr
<base::DictionaryValue
>();
151 scoped_ptr
<base::Value
> Validator::MapField(
152 const std::string
& field_name
,
153 const OncValueSignature
& object_signature
,
154 const base::Value
& onc_value
,
155 bool* found_unknown_field
,
157 path_
.push_back(field_name
);
158 bool current_field_unknown
= false;
159 scoped_ptr
<base::Value
> result
= Mapper::MapField(
160 field_name
, object_signature
, onc_value
, ¤t_field_unknown
, error
);
162 DCHECK_EQ(field_name
, path_
.back());
165 if (current_field_unknown
) {
166 error_or_warning_found_
= *found_unknown_field
= true;
167 std::string message
= MessageHeader() + "Field name '" + field_name
+
169 if (error_on_unknown_field_
)
170 LOG(ERROR
) << message
;
172 LOG(WARNING
) << message
;
175 return result
.Pass();
178 scoped_ptr
<base::ListValue
> Validator::MapArray(
179 const OncValueSignature
& array_signature
,
180 const base::ListValue
& onc_array
,
181 bool* nested_error
) {
182 bool nested_error_in_current_array
= false;
183 scoped_ptr
<base::ListValue
> result
= Mapper::MapArray(
184 array_signature
, onc_array
, &nested_error_in_current_array
);
186 // Drop individual networks and certificates instead of rejecting all of
187 // the configuration.
188 if (nested_error_in_current_array
&&
189 &array_signature
!= &kNetworkConfigurationListSignature
&&
190 &array_signature
!= &kCertificateListSignature
) {
191 *nested_error
= nested_error_in_current_array
;
193 return result
.Pass();
196 scoped_ptr
<base::Value
> Validator::MapEntry(int index
,
197 const OncValueSignature
& signature
,
198 const base::Value
& onc_value
,
200 std::string str
= base::IntToString(index
);
201 path_
.push_back(str
);
202 scoped_ptr
<base::Value
> result
=
203 Mapper::MapEntry(index
, signature
, onc_value
, error
);
204 DCHECK_EQ(str
, path_
.back());
206 return result
.Pass();
209 bool Validator::ValidateObjectDefault(const OncValueSignature
& signature
,
210 const base::DictionaryValue
& onc_object
,
211 base::DictionaryValue
* result
) {
212 bool found_unknown_field
= false;
213 bool nested_error_occured
= false;
214 MapFields(signature
, onc_object
, &found_unknown_field
, &nested_error_occured
,
217 if (found_unknown_field
&& error_on_unknown_field_
) {
218 DVLOG(1) << "Unknown field names are errors: Aborting.";
222 if (nested_error_occured
)
225 return ValidateRecommendedField(signature
, result
);
228 bool Validator::ValidateRecommendedField(
229 const OncValueSignature
& object_signature
,
230 base::DictionaryValue
* result
) {
233 scoped_ptr
<base::Value
> recommended_value
;
234 // This remove passes ownership to |recommended_value|.
235 if (!result
->RemoveWithoutPathExpansion(::onc::kRecommended
,
236 &recommended_value
)) {
240 base::ListValue
* recommended_list
= nullptr;
241 recommended_value
->GetAsList(&recommended_list
);
242 DCHECK(recommended_list
); // The types of field values are already verified.
245 error_or_warning_found_
= true;
246 LOG(WARNING
) << MessageHeader() << "Found the field '"
247 << ::onc::kRecommended
248 << "' in an unmanaged ONC. Removing it.";
252 scoped_ptr
<base::ListValue
> repaired_recommended(new base::ListValue
);
253 for (const base::Value
* entry
: *recommended_list
) {
254 std::string field_name
;
255 if (!entry
->GetAsString(&field_name
)) {
256 NOTREACHED(); // The types of field values are already verified.
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
->AppendString(field_name
);
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 base::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::ValidateSSIDAndHexSSID(base::DictionaryValue
* object
) {
403 // Check SSID validity.
404 std::string ssid_string
;
405 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kSSID
, &ssid_string
) &&
406 (ssid_string
.size() <= 0 ||
407 ssid_string
.size() > kMaximumSSIDLengthInBytes
)) {
408 error_or_warning_found_
= true;
409 const std::string msg
=
410 MessageHeader() + ::onc::wifi::kSSID
+ " has an invalid length.";
411 // If the HexSSID field is present, ignore errors in SSID because these
412 // might be caused by the usage of a non-UTF-8 encoding when the SSID
413 // field was automatically added (see FillInHexSSIDField).
414 if (object
->HasKey(::onc::wifi::kHexSSID
)) {
422 // Check HexSSID validity.
423 std::string hex_ssid_string
;
424 if (object
->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID
,
426 std::vector
<uint8
> decoded_ssid
;
427 if (!base::HexStringToBytes(hex_ssid_string
, &decoded_ssid
)) {
428 LOG(ERROR
) << MessageHeader() << "Field " << ::onc::wifi::kHexSSID
429 << " is not a valid hex representation: \"" << hex_ssid_string
431 error_or_warning_found_
= true;
434 if (decoded_ssid
.size() <= 0 ||
435 decoded_ssid
.size() > kMaximumSSIDLengthInBytes
) {
436 LOG(ERROR
) << MessageHeader() << ::onc::wifi::kHexSSID
437 << " has an invalid length.";
438 error_or_warning_found_
= true;
442 // If both SSID and HexSSID are set, check whether they are consistent, i.e.
443 // HexSSID contains the UTF-8 encoding of SSID. If not, remove the SSID
445 if (ssid_string
.length() > 0) {
446 std::string
decoded_ssid_string(
447 reinterpret_cast<const char*>(&decoded_ssid
[0]), decoded_ssid
.size());
448 if (ssid_string
!= decoded_ssid_string
) {
449 LOG(WARNING
) << MessageHeader() << "Fields " << ::onc::wifi::kSSID
450 << " and " << ::onc::wifi::kHexSSID
451 << " contain inconsistent values. Removing "
452 << ::onc::wifi::kSSID
<< ".";
453 error_or_warning_found_
= true;
454 object
->RemoveWithoutPathExpansion(::onc::wifi::kSSID
, nullptr);
461 bool Validator::RequireField(const base::DictionaryValue
& dict
,
462 const std::string
& field_name
) {
463 if (dict
.HasKey(field_name
))
465 std::string message
= MessageHeader() + "The required field '" + field_name
+
467 if (error_on_missing_field_
) {
468 error_or_warning_found_
= true;
469 LOG(ERROR
) << message
;
476 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue
& dict
,
477 const std::string
& key_guid
,
478 std::set
<std::string
> *guids
) {
480 if (dict
.GetStringWithoutPathExpansion(key_guid
, &guid
)) {
481 if (guids
->count(guid
) != 0) {
482 error_or_warning_found_
= true;
483 LOG(ERROR
) << MessageHeader() << "Found a duplicate GUID " << guid
<< ".";
491 bool Validator::IsCertPatternInDevicePolicy(const std::string
& cert_type
) {
492 if (cert_type
== ::onc::client_cert::kPattern
&&
493 onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
) {
494 error_or_warning_found_
= true;
495 LOG(ERROR
) << MessageHeader() << "Client certificate patterns are "
496 << "prohibited in ONC device policies.";
502 bool Validator::IsGlobalNetworkConfigInUserImport(
503 const base::DictionaryValue
& onc_object
) {
504 if (onc_source_
== ::onc::ONC_SOURCE_USER_IMPORT
&&
505 onc_object
.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration
)) {
506 error_or_warning_found_
= true;
507 LOG(ERROR
) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
508 << "in ONC user imports";
514 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue
* result
) {
515 using namespace ::onc::toplevel_config
;
517 const char* const kValidTypes
[] = {kUnencryptedConfiguration
,
518 kEncryptedConfiguration
};
519 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
520 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
523 if (IsGlobalNetworkConfigInUserImport(*result
))
529 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue
* result
) {
530 using namespace ::onc::network_config
;
532 const char* const kValidTypes
[] = {::onc::network_type::kEthernet
,
533 ::onc::network_type::kVPN
,
534 ::onc::network_type::kWiFi
,
535 ::onc::network_type::kCellular
,
536 ::onc::network_type::kWimax
};
537 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
538 const char* const kValidIPConfigTypes
[] = {kIPConfigTypeDHCP
,
539 kIPConfigTypeStatic
};
540 const std::vector
<const char*> valid_ipconfig_types(
541 toVector(kValidIPConfigTypes
));
542 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
543 FieldExistsAndHasNoValidValue(*result
, kIPAddressConfigType
,
544 valid_ipconfig_types
) ||
545 FieldExistsAndHasNoValidValue(*result
, kNameServersConfigType
,
546 valid_ipconfig_types
) ||
547 FieldExistsAndIsEmpty(*result
, kGUID
)) {
551 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &network_guids_
))
554 bool all_required_exist
= RequireField(*result
, kGUID
);
557 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
559 all_required_exist
&=
560 RequireField(*result
, kName
) && RequireField(*result
, kType
);
562 std::string ip_address_config_type
, name_servers_config_type
;
563 result
->GetStringWithoutPathExpansion(kIPAddressConfigType
,
564 &ip_address_config_type
);
565 result
->GetStringWithoutPathExpansion(kNameServersConfigType
,
566 &name_servers_config_type
);
567 if (ip_address_config_type
== kIPConfigTypeStatic
||
568 name_servers_config_type
== kIPConfigTypeStatic
) {
569 // TODO(pneubeck): Add ValidateStaticIPConfig and confirm that the
570 // correct properties are provided based on the config type.
571 all_required_exist
&= RequireField(*result
, kStaticIPConfig
);
575 result
->GetStringWithoutPathExpansion(kType
, &type
);
577 // Prohibit anything but WiFi and Ethernet for device-level policy (which
578 // corresponds to shared networks). See also http://crosbug.com/28741.
579 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&& !type
.empty() &&
580 type
!= ::onc::network_type::kWiFi
&&
581 type
!= ::onc::network_type::kEthernet
) {
582 error_or_warning_found_
= true;
583 LOG(ERROR
) << MessageHeader() << "Networks of type '"
584 << type
<< "' are prohibited in ONC device policies.";
588 if (type
== ::onc::network_type::kWiFi
) {
589 all_required_exist
&= RequireField(*result
, ::onc::network_config::kWiFi
);
590 } else if (type
== ::onc::network_type::kEthernet
) {
591 all_required_exist
&=
592 RequireField(*result
, ::onc::network_config::kEthernet
);
593 } else if (type
== ::onc::network_type::kCellular
) {
594 all_required_exist
&=
595 RequireField(*result
, ::onc::network_config::kCellular
);
596 } else if (type
== ::onc::network_type::kWimax
) {
597 all_required_exist
&=
598 RequireField(*result
, ::onc::network_config::kWimax
);
599 } else if (type
== ::onc::network_type::kVPN
) {
600 all_required_exist
&= RequireField(*result
, ::onc::network_config::kVPN
);
604 return !error_on_missing_field_
|| all_required_exist
;
607 bool Validator::ValidateEthernet(base::DictionaryValue
* result
) {
608 using namespace ::onc::ethernet
;
610 const char* const kValidAuthentications
[] = {kAuthenticationNone
, k8021X
};
611 const std::vector
<const char*> valid_authentications(
612 toVector(kValidAuthentications
));
613 if (FieldExistsAndHasNoValidValue(
614 *result
, kAuthentication
, valid_authentications
)) {
618 bool all_required_exist
= true;
620 result
->GetStringWithoutPathExpansion(kAuthentication
, &auth
);
622 all_required_exist
&= RequireField(*result
, kEAP
);
624 return !error_on_missing_field_
|| all_required_exist
;
627 bool Validator::ValidateIPConfig(base::DictionaryValue
* result
) {
628 using namespace ::onc::ipconfig
;
630 const char* const kValidTypes
[] = {kIPv4
, kIPv6
};
631 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
632 if (FieldExistsAndHasNoValidValue(
633 *result
, ::onc::ipconfig::kType
, valid_types
))
637 result
->GetStringWithoutPathExpansion(::onc::ipconfig::kType
, &type
);
639 // In case of missing type, choose higher upper_bound.
640 int upper_bound
= (type
== kIPv4
) ? 32 : 128;
641 if (FieldExistsAndIsNotInRange(
642 *result
, kRoutingPrefix
, lower_bound
, upper_bound
)) {
646 bool all_required_exist
= RequireField(*result
, kIPAddress
) &&
647 RequireField(*result
, ::onc::ipconfig::kType
);
648 if (result
->HasKey(kIPAddress
))
649 all_required_exist
&= RequireField(*result
, kRoutingPrefix
);
652 return !error_on_missing_field_
|| all_required_exist
;
655 bool Validator::ValidateWiFi(base::DictionaryValue
* result
) {
656 using namespace ::onc::wifi
;
658 const char* const kValidSecurities
[] = {kSecurityNone
, kWEP_PSK
, kWEP_8021X
,
660 const std::vector
<const char*> valid_securities(toVector(kValidSecurities
));
661 if (FieldExistsAndHasNoValidValue(*result
, kSecurity
, valid_securities
))
664 if (!ValidateSSIDAndHexSSID(result
))
667 bool all_required_exist
= RequireField(*result
, kSecurity
);
669 // One of {kSSID, kHexSSID} must be present.
670 if (!result
->HasKey(kSSID
))
671 all_required_exist
&= RequireField(*result
, kHexSSID
);
672 if (!result
->HasKey(kHexSSID
))
673 all_required_exist
&= RequireField(*result
, kSSID
);
675 std::string security
;
676 result
->GetStringWithoutPathExpansion(kSecurity
, &security
);
677 if (security
== kWEP_8021X
|| security
== kWPA_EAP
)
678 all_required_exist
&= RequireField(*result
, kEAP
);
679 else if (security
== kWEP_PSK
|| security
== kWPA_PSK
)
680 all_required_exist
&= RequireField(*result
, kPassphrase
);
682 return !error_on_missing_field_
|| all_required_exist
;
685 bool Validator::ValidateVPN(base::DictionaryValue
* result
) {
686 using namespace ::onc::vpn
;
688 const char* const kValidTypes
[] = {
689 kIPsec
, kTypeL2TP_IPsec
, kOpenVPN
, kThirdPartyVpn
};
690 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
691 if (FieldExistsAndHasNoValidValue(*result
, ::onc::vpn::kType
, valid_types
))
694 bool all_required_exist
= RequireField(*result
, ::onc::vpn::kType
);
696 result
->GetStringWithoutPathExpansion(::onc::vpn::kType
, &type
);
697 if (type
== kOpenVPN
) {
698 all_required_exist
&= RequireField(*result
, kOpenVPN
);
699 } else if (type
== kIPsec
) {
700 all_required_exist
&= RequireField(*result
, kIPsec
);
701 } else if (type
== kTypeL2TP_IPsec
) {
702 all_required_exist
&=
703 RequireField(*result
, kIPsec
) && RequireField(*result
, kL2TP
);
704 } else if (type
== kThirdPartyVpn
) {
705 all_required_exist
&= RequireField(*result
, kThirdPartyVpn
);
708 return !error_on_missing_field_
|| all_required_exist
;
711 bool Validator::ValidateIPsec(base::DictionaryValue
* result
) {
712 using namespace ::onc::ipsec
;
714 const char* const kValidAuthentications
[] = {kPSK
, kCert
};
715 const std::vector
<const char*> valid_authentications(
716 toVector(kValidAuthentications
));
717 if (FieldExistsAndHasNoValidValue(
718 *result
, kAuthenticationType
, valid_authentications
) ||
719 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
723 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
724 error_or_warning_found_
= true;
725 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
726 << " and " << kServerCARef
<< " can be set.";
730 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
735 bool all_required_exist
= RequireField(*result
, kAuthenticationType
) &&
736 RequireField(*result
, kIKEVersion
);
738 result
->GetStringWithoutPathExpansion(kAuthenticationType
, &auth
);
739 bool has_server_ca_cert
=
740 result
->HasKey(kServerCARefs
) || result
->HasKey(kServerCARef
);
742 all_required_exist
&=
743 RequireField(*result
, ::onc::client_cert::kClientCertType
);
744 if (!has_server_ca_cert
) {
745 all_required_exist
= false;
746 error_or_warning_found_
= true;
747 std::string message
= MessageHeader() + "The required field '" +
748 kServerCARefs
+ "' is missing.";
749 if (error_on_missing_field_
)
750 LOG(ERROR
) << message
;
752 LOG(WARNING
) << message
;
754 } else if (has_server_ca_cert
) {
755 error_or_warning_found_
= true;
756 LOG(ERROR
) << MessageHeader() << kServerCARefs
<< " (or " << kServerCARef
757 << ") can only be set if " << kAuthenticationType
758 << " is set to " << kCert
<< ".";
762 return !error_on_missing_field_
|| all_required_exist
;
765 bool Validator::ValidateOpenVPN(base::DictionaryValue
* result
) {
766 using namespace ::onc::openvpn
;
768 const char* const kValidAuthRetryValues
[] = {::onc::openvpn::kNone
, kInteract
,
770 const std::vector
<const char*> valid_auth_retry_values(
771 toVector(kValidAuthRetryValues
));
772 const char* const kValidCertTlsValues
[] = {::onc::openvpn::kNone
,
773 ::onc::openvpn::kServer
};
774 const std::vector
<const char*> valid_cert_tls_values(
775 toVector(kValidCertTlsValues
));
776 const char* const kValidUserAuthTypes
[] = {
777 ::onc::openvpn_user_auth_type::kNone
,
778 ::onc::openvpn_user_auth_type::kOTP
,
779 ::onc::openvpn_user_auth_type::kPassword
,
780 ::onc::openvpn_user_auth_type::kPasswordAndOTP
};
781 const std::vector
<const char*> valid_user_auth_types(
782 toVector(kValidUserAuthTypes
));
784 if (FieldExistsAndHasNoValidValue(
785 *result
, kAuthRetry
, valid_auth_retry_values
) ||
786 FieldExistsAndHasNoValidValue(
787 *result
, kRemoteCertTLS
, valid_cert_tls_values
) ||
788 FieldExistsAndHasNoValidValue(
789 *result
, kUserAuthenticationType
, valid_user_auth_types
) ||
790 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
794 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
795 error_or_warning_found_
= true;
796 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
797 << " and " << kServerCARef
<< " can be set.";
801 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result
))
804 bool all_required_exist
=
805 RequireField(*result
, ::onc::client_cert::kClientCertType
);
807 return !error_on_missing_field_
|| all_required_exist
;
810 bool Validator::ValidateThirdPartyVPN(base::DictionaryValue
* result
) {
811 const bool all_required_exist
=
812 RequireField(*result
, ::onc::third_party_vpn::kExtensionID
);
814 return !error_on_missing_field_
|| all_required_exist
;
817 bool Validator::ValidateVerifyX509(base::DictionaryValue
* result
) {
818 using namespace ::onc::verify_x509
;
820 const char* const kValidTypes
[] = {types::kName
, types::kNamePrefix
,
822 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
824 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
))
827 bool all_required_exist
= RequireField(*result
, kName
);
829 return !error_on_missing_field_
|| all_required_exist
;
832 bool Validator::ValidateCertificatePattern(base::DictionaryValue
* result
) {
833 using namespace ::onc::client_cert
;
835 bool all_required_exist
= true;
836 if (!result
->HasKey(kSubject
) && !result
->HasKey(kIssuer
) &&
837 !result
->HasKey(kIssuerCARef
)) {
838 error_or_warning_found_
= true;
839 all_required_exist
= false;
840 std::string message
= MessageHeader() + "None of the fields '" + kSubject
+
841 "', '" + kIssuer
+ "', and '" + kIssuerCARef
+
842 "' is present, but at least one is required.";
843 if (error_on_missing_field_
)
844 LOG(ERROR
) << message
;
846 LOG(WARNING
) << message
;
849 return !error_on_missing_field_
|| all_required_exist
;
852 bool Validator::ValidateProxySettings(base::DictionaryValue
* result
) {
853 using namespace ::onc::proxy
;
855 const char* const kValidTypes
[] = {kDirect
, kManual
, kPAC
, kWPAD
};
856 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
857 if (FieldExistsAndHasNoValidValue(*result
, ::onc::proxy::kType
, valid_types
))
860 bool all_required_exist
= RequireField(*result
, ::onc::proxy::kType
);
862 result
->GetStringWithoutPathExpansion(::onc::proxy::kType
, &type
);
864 all_required_exist
&= RequireField(*result
, kManual
);
865 else if (type
== kPAC
)
866 all_required_exist
&= RequireField(*result
, kPAC
);
868 return !error_on_missing_field_
|| all_required_exist
;
871 bool Validator::ValidateProxyLocation(base::DictionaryValue
* result
) {
872 using namespace ::onc::proxy
;
874 bool all_required_exist
=
875 RequireField(*result
, kHost
) && RequireField(*result
, kPort
);
877 return !error_on_missing_field_
|| all_required_exist
;
880 bool Validator::ValidateEAP(base::DictionaryValue
* result
) {
881 using namespace ::onc::eap
;
883 const char* const kValidInnerValues
[] = {
884 kAutomatic
, kGTC
, kMD5
, kMSCHAPv2
, kPAP
};
885 const std::vector
<const char*> valid_inner_values(
886 toVector(kValidInnerValues
));
887 const char* const kValidOuterValues
[] = {
888 kPEAP
, kEAP_TLS
, kEAP_TTLS
, kLEAP
, kEAP_SIM
, kEAP_FAST
, kEAP_AKA
};
889 const std::vector
<const char*> valid_outer_values(
890 toVector(kValidOuterValues
));
892 if (FieldExistsAndHasNoValidValue(*result
, kInner
, valid_inner_values
) ||
893 FieldExistsAndHasNoValidValue(*result
, kOuter
, valid_outer_values
) ||
894 FieldExistsAndIsEmpty(*result
, kServerCARefs
)) {
898 if (result
->HasKey(kServerCARefs
) && result
->HasKey(kServerCARef
)) {
899 error_or_warning_found_
= true;
900 LOG(ERROR
) << MessageHeader() << "At most one of " << kServerCARefs
901 << " and " << kServerCARef
<< " can be set.";
905 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
910 bool all_required_exist
= RequireField(*result
, kOuter
);
912 return !error_on_missing_field_
|| all_required_exist
;
915 bool Validator::ValidateCertificate(base::DictionaryValue
* result
) {
916 using namespace ::onc::certificate
;
918 const char* const kValidTypes
[] = {kClient
, kServer
, kAuthority
};
919 const std::vector
<const char*> valid_types(toVector(kValidTypes
));
920 if (FieldExistsAndHasNoValidValue(*result
, kType
, valid_types
) ||
921 FieldExistsAndIsEmpty(*result
, kGUID
)) {
926 result
->GetStringWithoutPathExpansion(kType
, &type
);
927 if (onc_source_
== ::onc::ONC_SOURCE_DEVICE_POLICY
&&
928 (type
== kServer
|| type
== kAuthority
)) {
929 error_or_warning_found_
= true;
930 LOG(ERROR
) << MessageHeader() << "Server and authority certificates are "
931 << "prohibited in ONC device policies.";
935 if (!CheckGuidIsUniqueAndAddToSet(*result
, kGUID
, &certificate_guids_
))
938 bool all_required_exist
= RequireField(*result
, kGUID
);
941 result
->GetBooleanWithoutPathExpansion(::onc::kRemove
, &remove
);
943 all_required_exist
&= RequireField(*result
, kType
);
946 all_required_exist
&= RequireField(*result
, kPKCS12
);
947 else if (type
== kServer
|| type
== kAuthority
)
948 all_required_exist
&= RequireField(*result
, kX509
);
951 return !error_on_missing_field_
|| all_required_exist
;
954 std::string
Validator::MessageHeader() {
955 std::string path
= path_
.empty() ? "toplevel" : base::JoinString(path_
, ".");
956 std::string message
= "At " + path
+ ": ";
961 } // namespace chromeos