[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / chromeos / network / onc / onc_validator.cc
blobe3ea49a9daf7404cb2e3f39d054960075f227645
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"
7 #include <algorithm>
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"
16 namespace chromeos {
17 namespace onc {
19 namespace {
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));
35 return strings[type];
38 } // namespace
40 Validator::Validator(bool error_on_unknown_field,
41 bool error_on_wrong_recommended,
42 bool error_on_missing_field,
43 bool managed_onc)
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,
55 Result* result) {
56 CHECK(object_signature);
57 *result = VALID;
58 error_or_warning_found_ = false;
59 bool error = false;
60 scoped_ptr<base::Value> result_value =
61 MapValue(*object_signature, onc_object, &error);
62 if (error) {
63 *result = INVALID;
64 result_value.reset();
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;
72 if (result_value) {
73 result_value.release()->GetAsDictionary(&result_dict);
74 CHECK(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,
82 bool* error) {
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)
87 << "' is required.";
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);
94 if (repaired)
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,
102 bool* error) {
103 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
105 bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
106 if (valid) {
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());
142 if (valid) {
143 return repaired.Pass();
144 } else {
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,
156 bool* error) {
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, &current_field_unknown, error);
162 DCHECK_EQ(field_name, path_.back());
163 path_.pop_back();
165 if (current_field_unknown) {
166 error_or_warning_found_ = *found_unknown_field = true;
167 std::string message = MessageHeader() + "Field name '" + field_name +
168 "' is unknown.";
169 if (error_on_unknown_field_)
170 LOG(ERROR) << message;
171 else
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,
199 bool* error) {
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());
205 path_.pop_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,
215 result);
217 if (found_unknown_field && error_on_unknown_field_) {
218 DVLOG(1) << "Unknown field names are errors: Aborting.";
219 return false;
222 if (nested_error_occured)
223 return false;
225 return ValidateRecommendedField(signature, result);
228 bool Validator::ValidateRecommendedField(
229 const OncValueSignature& object_signature,
230 base::DictionaryValue* result) {
231 CHECK(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)) {
237 return true;
240 base::ListValue* recommended_list = nullptr;
241 recommended_value->GetAsList(&recommended_list);
242 DCHECK(recommended_list); // The types of field values are already verified.
244 if (!managed_onc_) {
245 error_or_warning_found_ = true;
246 LOG(WARNING) << MessageHeader() << "Found the field '"
247 << ::onc::kRecommended
248 << "' in an unmanaged ONC. Removing it.";
249 return true;
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.
257 continue;
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) {
266 found_error = true;
267 error_cause = "unknown";
268 } else if (field_signature->value_signature->onc_type ==
269 base::Value::TYPE_DICTIONARY) {
270 found_error = true;
271 error_cause = "dictionary-typed";
274 if (found_error) {
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.";
279 path_.pop_back();
280 if (error_on_wrong_recommended_) {
281 LOG(ERROR) << message;
282 return false;
283 } else {
284 LOG(WARNING) << message;
285 continue;
289 repaired_recommended->AppendString(field_name);
292 result->Set(::onc::kRecommended, repaired_recommended.release());
293 return true;
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))
304 return false;
306 std::string cert_type;
307 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
309 if (IsCertPatternInDevicePolicy(cert_type))
310 return false;
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;
322 namespace {
324 std::string JoinStringRange(const std::vector<const char*>& strings,
325 const std::string& separator) {
326 std::vector<std::string> string_vector;
327 std::copy(strings.begin(), strings.end(), std::back_inserter(string_vector));
328 return JoinString(string_vector, separator);
331 } // namespace
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))
339 return false;
341 for (std::vector<const char*>::const_iterator it = valid_values.begin();
342 it != valid_values.end();
343 ++it) {
344 if (actual_value == *it)
345 return false;
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;
353 path_.pop_back();
354 return true;
357 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
358 const std::string& field_name,
359 int lower_bound,
360 int upper_bound) {
361 int actual_value;
362 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
363 (lower_bound <= actual_value && actual_value <= upper_bound)) {
364 return false;
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)";
371 path_.pop_back();
372 return true;
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))
379 return false;
381 std::string str;
382 const base::ListValue* list = NULL;
383 if (value->GetAsString(&str)) {
384 if (!str.empty())
385 return false;
386 } else if (value->GetAsList(&list)) {
387 if (!list->empty())
388 return false;
389 } else {
390 NOTREACHED();
391 return false;
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.";
398 path_.pop_back();
399 return true;
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)) {
415 LOG(WARNING) << msg;
416 } else {
417 LOG(ERROR) << msg;
418 return false;
422 // Check HexSSID validity.
423 std::string hex_ssid_string;
424 if (object->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID,
425 &hex_ssid_string)) {
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
430 << "\"";
431 error_or_warning_found_ = true;
432 return false;
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;
439 return false;
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
444 // field.
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);
458 return true;
461 bool Validator::RequireField(const base::DictionaryValue& dict,
462 const std::string& field_name) {
463 if (dict.HasKey(field_name))
464 return true;
465 std::string message = MessageHeader() + "The required field '" + field_name +
466 "' is missing.";
467 if (error_on_missing_field_) {
468 error_or_warning_found_ = true;
469 LOG(ERROR) << message;
470 } else {
471 VLOG(1) << message;
473 return false;
476 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
477 const std::string& key_guid,
478 std::set<std::string> *guids) {
479 std::string guid;
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 << ".";
484 return false;
486 guids->insert(guid);
488 return true;
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.";
497 return true;
499 return false;
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";
509 return true;
511 return false;
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))
521 return false;
523 if (IsGlobalNetworkConfigInUserImport(*result))
524 return false;
526 return true;
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)) {
548 return false;
551 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
552 return false;
554 bool all_required_exist = RequireField(*result, kGUID);
556 bool remove = false;
557 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
558 if (!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);
574 std::string type;
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.";
585 return false;
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)) {
615 return false;
618 bool all_required_exist = true;
619 std::string auth;
620 result->GetStringWithoutPathExpansion(kAuthentication, &auth);
621 if (auth == k8021X)
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))
634 return false;
636 std::string type;
637 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
638 int lower_bound = 1;
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)) {
643 return false;
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,
659 kWPA_PSK, kWPA_EAP};
660 const std::vector<const char*> valid_securities(toVector(kValidSecurities));
661 if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities))
662 return false;
664 if (!ValidateSSIDAndHexSSID(result))
665 return false;
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))
692 return false;
694 bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
695 std::string type;
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)) {
720 return false;
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.";
727 return false;
730 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
731 result)) {
732 return false;
735 bool all_required_exist = RequireField(*result, kAuthenticationType) &&
736 RequireField(*result, kIKEVersion);
737 std::string auth;
738 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
739 bool has_server_ca_cert =
740 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
741 if (auth == kCert) {
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;
751 else
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 << ".";
759 return false;
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,
769 kNoInteract};
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)) {
791 return false;
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.";
798 return false;
801 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
802 return false;
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,
821 types::kSubject};
822 const std::vector<const char*> valid_types(toVector(kValidTypes));
824 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
825 return false;
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;
845 else
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))
858 return false;
860 bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
861 std::string type;
862 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
863 if (type == kManual)
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[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP};
884 const std::vector<const char*> valid_inner_values(
885 toVector(kValidInnerValues));
886 const char* const kValidOuterValues[] = {
887 kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA};
888 const std::vector<const char*> valid_outer_values(
889 toVector(kValidOuterValues));
891 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) ||
892 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) ||
893 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
894 return false;
897 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
898 error_or_warning_found_ = true;
899 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
900 << " and " << kServerCARef << " can be set.";
901 return false;
904 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
905 result)) {
906 return false;
909 bool all_required_exist = RequireField(*result, kOuter);
911 return !error_on_missing_field_ || all_required_exist;
914 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
915 using namespace ::onc::certificate;
917 const char* const kValidTypes[] = {kClient, kServer, kAuthority};
918 const std::vector<const char*> valid_types(toVector(kValidTypes));
919 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
920 FieldExistsAndIsEmpty(*result, kGUID)) {
921 return false;
924 std::string type;
925 result->GetStringWithoutPathExpansion(kType, &type);
926 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
927 (type == kServer || type == kAuthority)) {
928 error_or_warning_found_ = true;
929 LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
930 << "prohibited in ONC device policies.";
931 return false;
934 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_))
935 return false;
937 bool all_required_exist = RequireField(*result, kGUID);
939 bool remove = false;
940 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
941 if (!remove) {
942 all_required_exist &= RequireField(*result, kType);
944 if (type == kClient)
945 all_required_exist &= RequireField(*result, kPKCS12);
946 else if (type == kServer || type == kAuthority)
947 all_required_exist &= RequireField(*result, kX509);
950 return !error_on_missing_field_ || all_required_exist;
953 std::string Validator::MessageHeader() {
954 std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
955 std::string message = "At " + path + ": ";
956 return message;
959 } // namespace onc
960 } // namespace chromeos