ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chromeos / network / onc / onc_validator.cc
blobc3cd2bb3965afd6a156bec0cb303630a03c8cdd8
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 == &kVerifyX509Signature) {
126 valid = ValidateVerifyX509(repaired.get());
127 } else if (&signature == &kCertificatePatternSignature) {
128 valid = ValidateCertificatePattern(repaired.get());
129 } else if (&signature == &kProxySettingsSignature) {
130 valid = ValidateProxySettings(repaired.get());
131 } else if (&signature == &kProxyLocationSignature) {
132 valid = ValidateProxyLocation(repaired.get());
133 } else if (&signature == &kEAPSignature) {
134 valid = ValidateEAP(repaired.get());
135 } else if (&signature == &kCertificateSignature) {
136 valid = ValidateCertificate(repaired.get());
140 if (valid) {
141 return repaired.Pass();
142 } else {
143 DCHECK(error_or_warning_found_);
144 error_or_warning_found_ = *error = true;
145 return scoped_ptr<base::DictionaryValue>();
149 scoped_ptr<base::Value> Validator::MapField(
150 const std::string& field_name,
151 const OncValueSignature& object_signature,
152 const base::Value& onc_value,
153 bool* found_unknown_field,
154 bool* error) {
155 path_.push_back(field_name);
156 bool current_field_unknown = false;
157 scoped_ptr<base::Value> result = Mapper::MapField(
158 field_name, object_signature, onc_value, &current_field_unknown, error);
160 DCHECK_EQ(field_name, path_.back());
161 path_.pop_back();
163 if (current_field_unknown) {
164 error_or_warning_found_ = *found_unknown_field = true;
165 std::string message = MessageHeader() + "Field name '" + field_name +
166 "' is unknown.";
167 if (error_on_unknown_field_)
168 LOG(ERROR) << message;
169 else
170 LOG(WARNING) << message;
173 return result.Pass();
176 scoped_ptr<base::ListValue> Validator::MapArray(
177 const OncValueSignature& array_signature,
178 const base::ListValue& onc_array,
179 bool* nested_error) {
180 bool nested_error_in_current_array = false;
181 scoped_ptr<base::ListValue> result = Mapper::MapArray(
182 array_signature, onc_array, &nested_error_in_current_array);
184 // Drop individual networks and certificates instead of rejecting all of
185 // the configuration.
186 if (nested_error_in_current_array &&
187 &array_signature != &kNetworkConfigurationListSignature &&
188 &array_signature != &kCertificateListSignature) {
189 *nested_error = nested_error_in_current_array;
191 return result.Pass();
194 scoped_ptr<base::Value> Validator::MapEntry(int index,
195 const OncValueSignature& signature,
196 const base::Value& onc_value,
197 bool* error) {
198 std::string str = base::IntToString(index);
199 path_.push_back(str);
200 scoped_ptr<base::Value> result =
201 Mapper::MapEntry(index, signature, onc_value, error);
202 DCHECK_EQ(str, path_.back());
203 path_.pop_back();
204 return result.Pass();
207 bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
208 const base::DictionaryValue& onc_object,
209 base::DictionaryValue* result) {
210 bool found_unknown_field = false;
211 bool nested_error_occured = false;
212 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
213 result);
215 if (found_unknown_field && error_on_unknown_field_) {
216 DVLOG(1) << "Unknown field names are errors: Aborting.";
217 return false;
220 if (nested_error_occured)
221 return false;
223 return ValidateRecommendedField(signature, result);
226 bool Validator::ValidateRecommendedField(
227 const OncValueSignature& object_signature,
228 base::DictionaryValue* result) {
229 CHECK(result);
231 scoped_ptr<base::Value> recommended_value;
232 // This remove passes ownership to |recommended_value|.
233 if (!result->RemoveWithoutPathExpansion(::onc::kRecommended,
234 &recommended_value)) {
235 return true;
238 base::ListValue* recommended_list = nullptr;
239 recommended_value->GetAsList(&recommended_list);
240 DCHECK(recommended_list); // The types of field values are already verified.
242 if (!managed_onc_) {
243 error_or_warning_found_ = true;
244 LOG(WARNING) << MessageHeader() << "Found the field '"
245 << ::onc::kRecommended
246 << "' in an unmanaged ONC. Removing it.";
247 return true;
250 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
251 for (const base::Value* entry : *recommended_list) {
252 std::string field_name;
253 if (!entry->GetAsString(&field_name)) {
254 NOTREACHED(); // The types of field values are already verified.
255 continue;
258 const OncFieldSignature* field_signature =
259 GetFieldSignature(object_signature, field_name);
261 bool found_error = false;
262 std::string error_cause;
263 if (!field_signature) {
264 found_error = true;
265 error_cause = "unknown";
266 } else if (field_signature->value_signature->onc_type ==
267 base::Value::TYPE_DICTIONARY) {
268 found_error = true;
269 error_cause = "dictionary-typed";
272 if (found_error) {
273 error_or_warning_found_ = true;
274 path_.push_back(::onc::kRecommended);
275 std::string message = MessageHeader() + "The " + error_cause +
276 " field '" + field_name + "' cannot be recommended.";
277 path_.pop_back();
278 if (error_on_wrong_recommended_) {
279 LOG(ERROR) << message;
280 return false;
281 } else {
282 LOG(WARNING) << message;
283 continue;
287 repaired_recommended->AppendString(field_name);
290 result->Set(::onc::kRecommended, repaired_recommended.release());
291 return true;
294 bool Validator::ValidateClientCertFields(bool allow_cert_type_none,
295 base::DictionaryValue* result) {
296 using namespace ::onc::client_cert;
297 const char* const kValidCertTypes[] = {kRef, kPattern};
298 std::vector<const char*> valid_cert_types(toVector(kValidCertTypes));
299 if (allow_cert_type_none)
300 valid_cert_types.push_back(kClientCertTypeNone);
301 if (FieldExistsAndHasNoValidValue(*result, kClientCertType, valid_cert_types))
302 return false;
304 std::string cert_type;
305 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
307 if (IsCertPatternInDevicePolicy(cert_type))
308 return false;
310 bool all_required_exist = true;
312 if (cert_type == kPattern)
313 all_required_exist &= RequireField(*result, kClientCertPattern);
314 else if (cert_type == kRef)
315 all_required_exist &= RequireField(*result, kClientCertRef);
317 return !error_on_missing_field_ || all_required_exist;
320 namespace {
322 std::string JoinStringRange(const std::vector<const char*>& strings,
323 const std::string& separator) {
324 std::vector<std::string> string_vector;
325 std::copy(strings.begin(), strings.end(), std::back_inserter(string_vector));
326 return JoinString(string_vector, separator);
329 } // namespace
331 bool Validator::FieldExistsAndHasNoValidValue(
332 const base::DictionaryValue& object,
333 const std::string& field_name,
334 const std::vector<const char*>& valid_values) {
335 std::string actual_value;
336 if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
337 return false;
339 for (std::vector<const char*>::const_iterator it = valid_values.begin();
340 it != valid_values.end();
341 ++it) {
342 if (actual_value == *it)
343 return false;
345 error_or_warning_found_ = true;
346 std::string valid_values_str =
347 "[" + JoinStringRange(valid_values, ", ") + "]";
348 path_.push_back(field_name);
349 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value <<
350 "', but expected one of the values " << valid_values_str;
351 path_.pop_back();
352 return true;
355 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
356 const std::string& field_name,
357 int lower_bound,
358 int upper_bound) {
359 int actual_value;
360 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
361 (lower_bound <= actual_value && actual_value <= upper_bound)) {
362 return false;
364 error_or_warning_found_ = true;
365 path_.push_back(field_name);
366 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value
367 << "', but expected a value in the range [" << lower_bound
368 << ", " << upper_bound << "] (boundaries inclusive)";
369 path_.pop_back();
370 return true;
373 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
374 const std::string& field_name) {
375 const base::Value* value = NULL;
376 if (!object.GetWithoutPathExpansion(field_name, &value))
377 return false;
379 std::string str;
380 const base::ListValue* list = NULL;
381 if (value->GetAsString(&str)) {
382 if (!str.empty())
383 return false;
384 } else if (value->GetAsList(&list)) {
385 if (!list->empty())
386 return false;
387 } else {
388 NOTREACHED();
389 return false;
392 error_or_warning_found_ = true;
393 path_.push_back(field_name);
394 LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a "
395 << "non-empty string.";
396 path_.pop_back();
397 return true;
400 bool Validator::ValidateSSIDAndHexSSID(base::DictionaryValue* object) {
401 // Check SSID validity.
402 std::string ssid_string;
403 if (object->GetStringWithoutPathExpansion(::onc::wifi::kSSID, &ssid_string) &&
404 (ssid_string.size() <= 0 ||
405 ssid_string.size() > kMaximumSSIDLengthInBytes)) {
406 error_or_warning_found_ = true;
407 const std::string msg =
408 MessageHeader() + ::onc::wifi::kSSID + " has an invalid length.";
409 // If the HexSSID field is present, ignore errors in SSID because these
410 // might be caused by the usage of a non-UTF-8 encoding when the SSID
411 // field was automatically added (see FillInHexSSIDField).
412 if (object->HasKey(::onc::wifi::kHexSSID)) {
413 LOG(WARNING) << msg;
414 } else {
415 LOG(ERROR) << msg;
416 return false;
420 // Check HexSSID validity.
421 std::string hex_ssid_string;
422 if (object->GetStringWithoutPathExpansion(::onc::wifi::kHexSSID,
423 &hex_ssid_string)) {
424 std::vector<uint8> decoded_ssid;
425 if (!base::HexStringToBytes(hex_ssid_string, &decoded_ssid)) {
426 LOG(ERROR) << MessageHeader() << "Field " << ::onc::wifi::kHexSSID
427 << " is not a valid hex representation: \"" << hex_ssid_string
428 << "\"";
429 error_or_warning_found_ = true;
430 return false;
432 if (decoded_ssid.size() <= 0 ||
433 decoded_ssid.size() > kMaximumSSIDLengthInBytes) {
434 LOG(ERROR) << MessageHeader() << ::onc::wifi::kHexSSID
435 << " has an invalid length.";
436 error_or_warning_found_ = true;
437 return false;
440 // If both SSID and HexSSID are set, check whether they are consistent, i.e.
441 // HexSSID contains the UTF-8 encoding of SSID. If not, remove the SSID
442 // field.
443 if (ssid_string.length() > 0) {
444 std::string decoded_ssid_string(
445 reinterpret_cast<const char*>(&decoded_ssid[0]), decoded_ssid.size());
446 if (ssid_string != decoded_ssid_string) {
447 LOG(WARNING) << MessageHeader() << "Fields " << ::onc::wifi::kSSID
448 << " and " << ::onc::wifi::kHexSSID
449 << " contain inconsistent values. Removing "
450 << ::onc::wifi::kSSID << ".";
451 error_or_warning_found_ = true;
452 object->RemoveWithoutPathExpansion(::onc::wifi::kSSID, nullptr);
456 return true;
459 bool Validator::RequireField(const base::DictionaryValue& dict,
460 const std::string& field_name) {
461 if (dict.HasKey(field_name))
462 return true;
463 std::string message = MessageHeader() + "The required field '" + field_name +
464 "' is missing.";
465 if (error_on_missing_field_) {
466 error_or_warning_found_ = true;
467 LOG(ERROR) << message;
468 } else {
469 VLOG(1) << message;
471 return false;
474 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
475 const std::string& key_guid,
476 std::set<std::string> *guids) {
477 std::string guid;
478 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
479 if (guids->count(guid) != 0) {
480 error_or_warning_found_ = true;
481 LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << ".";
482 return false;
484 guids->insert(guid);
486 return true;
489 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) {
490 if (cert_type == ::onc::client_cert::kPattern &&
491 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) {
492 error_or_warning_found_ = true;
493 LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
494 << "prohibited in ONC device policies.";
495 return true;
497 return false;
500 bool Validator::IsGlobalNetworkConfigInUserImport(
501 const base::DictionaryValue& onc_object) {
502 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
503 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
504 error_or_warning_found_ = true;
505 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
506 << "in ONC user imports";
507 return true;
509 return false;
512 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
513 using namespace ::onc::toplevel_config;
515 const char* const kValidTypes[] = {kUnencryptedConfiguration,
516 kEncryptedConfiguration};
517 const std::vector<const char*> valid_types(toVector(kValidTypes));
518 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
519 return false;
521 if (IsGlobalNetworkConfigInUserImport(*result))
522 return false;
524 return true;
527 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
528 using namespace ::onc::network_config;
530 const char* const kValidTypes[] = {::onc::network_type::kEthernet,
531 ::onc::network_type::kVPN,
532 ::onc::network_type::kWiFi,
533 ::onc::network_type::kCellular,
534 ::onc::network_type::kWimax};
535 const std::vector<const char*> valid_types(toVector(kValidTypes));
536 const char* const kValidIPConfigTypes[] = {kIPConfigTypeDHCP,
537 kIPConfigTypeStatic};
538 const std::vector<const char*> valid_ipconfig_types(
539 toVector(kValidIPConfigTypes));
540 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
541 FieldExistsAndHasNoValidValue(*result, kIPAddressConfigType,
542 valid_ipconfig_types) ||
543 FieldExistsAndHasNoValidValue(*result, kNameServersConfigType,
544 valid_ipconfig_types) ||
545 FieldExistsAndIsEmpty(*result, kGUID)) {
546 return false;
549 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
550 return false;
552 bool all_required_exist = RequireField(*result, kGUID);
554 bool remove = false;
555 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
556 if (!remove) {
557 all_required_exist &=
558 RequireField(*result, kName) && RequireField(*result, kType);
560 std::string ip_address_config_type, name_servers_config_type;
561 result->GetStringWithoutPathExpansion(kIPAddressConfigType,
562 &ip_address_config_type);
563 result->GetStringWithoutPathExpansion(kNameServersConfigType,
564 &name_servers_config_type);
565 if (ip_address_config_type == kIPConfigTypeStatic ||
566 name_servers_config_type == kIPConfigTypeStatic) {
567 // TODO(pneubeck): Add ValidateStaticIPConfig and confirm that the
568 // correct properties are provided based on the config type.
569 all_required_exist &= RequireField(*result, kStaticIPConfig);
572 std::string type;
573 result->GetStringWithoutPathExpansion(kType, &type);
575 // Prohibit anything but WiFi and Ethernet for device-level policy (which
576 // corresponds to shared networks). See also http://crosbug.com/28741.
577 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && !type.empty() &&
578 type != ::onc::network_type::kWiFi &&
579 type != ::onc::network_type::kEthernet) {
580 error_or_warning_found_ = true;
581 LOG(ERROR) << MessageHeader() << "Networks of type '"
582 << type << "' are prohibited in ONC device policies.";
583 return false;
586 if (type == ::onc::network_type::kWiFi) {
587 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
588 } else if (type == ::onc::network_type::kEthernet) {
589 all_required_exist &=
590 RequireField(*result, ::onc::network_config::kEthernet);
591 } else if (type == ::onc::network_type::kCellular) {
592 all_required_exist &=
593 RequireField(*result, ::onc::network_config::kCellular);
594 } else if (type == ::onc::network_type::kWimax) {
595 all_required_exist &=
596 RequireField(*result, ::onc::network_config::kWimax);
597 } else if (type == ::onc::network_type::kVPN) {
598 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
602 return !error_on_missing_field_ || all_required_exist;
605 bool Validator::ValidateEthernet(base::DictionaryValue* result) {
606 using namespace ::onc::ethernet;
608 const char* const kValidAuthentications[] = {kAuthenticationNone, k8021X};
609 const std::vector<const char*> valid_authentications(
610 toVector(kValidAuthentications));
611 if (FieldExistsAndHasNoValidValue(
612 *result, kAuthentication, valid_authentications)) {
613 return false;
616 bool all_required_exist = true;
617 std::string auth;
618 result->GetStringWithoutPathExpansion(kAuthentication, &auth);
619 if (auth == k8021X)
620 all_required_exist &= RequireField(*result, kEAP);
622 return !error_on_missing_field_ || all_required_exist;
625 bool Validator::ValidateIPConfig(base::DictionaryValue* result) {
626 using namespace ::onc::ipconfig;
628 const char* const kValidTypes[] = {kIPv4, kIPv6};
629 const std::vector<const char*> valid_types(toVector(kValidTypes));
630 if (FieldExistsAndHasNoValidValue(
631 *result, ::onc::ipconfig::kType, valid_types))
632 return false;
634 std::string type;
635 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
636 int lower_bound = 1;
637 // In case of missing type, choose higher upper_bound.
638 int upper_bound = (type == kIPv4) ? 32 : 128;
639 if (FieldExistsAndIsNotInRange(
640 *result, kRoutingPrefix, lower_bound, upper_bound)) {
641 return false;
644 bool all_required_exist = RequireField(*result, kIPAddress) &&
645 RequireField(*result, ::onc::ipconfig::kType);
646 if (result->HasKey(kIPAddress))
647 all_required_exist &= RequireField(*result, kRoutingPrefix);
650 return !error_on_missing_field_ || all_required_exist;
653 bool Validator::ValidateWiFi(base::DictionaryValue* result) {
654 using namespace ::onc::wifi;
656 const char* const kValidSecurities[] = {kSecurityNone, kWEP_PSK, kWEP_8021X,
657 kWPA_PSK, kWPA_EAP};
658 const std::vector<const char*> valid_securities(toVector(kValidSecurities));
659 if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities))
660 return false;
662 if (!ValidateSSIDAndHexSSID(result))
663 return false;
665 bool all_required_exist = RequireField(*result, kSecurity);
667 // One of {kSSID, kHexSSID} must be present.
668 if (!result->HasKey(kSSID))
669 all_required_exist &= RequireField(*result, kHexSSID);
670 if (!result->HasKey(kHexSSID))
671 all_required_exist &= RequireField(*result, kSSID);
673 std::string security;
674 result->GetStringWithoutPathExpansion(kSecurity, &security);
675 if (security == kWEP_8021X || security == kWPA_EAP)
676 all_required_exist &= RequireField(*result, kEAP);
677 else if (security == kWEP_PSK || security == kWPA_PSK)
678 all_required_exist &= RequireField(*result, kPassphrase);
680 return !error_on_missing_field_ || all_required_exist;
683 bool Validator::ValidateVPN(base::DictionaryValue* result) {
684 using namespace ::onc::vpn;
686 const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN};
687 const std::vector<const char*> valid_types(toVector(kValidTypes));
688 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
689 return false;
691 bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
692 std::string type;
693 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
694 if (type == kOpenVPN) {
695 all_required_exist &= RequireField(*result, kOpenVPN);
696 } else if (type == kIPsec) {
697 all_required_exist &= RequireField(*result, kIPsec);
698 } else if (type == kTypeL2TP_IPsec) {
699 all_required_exist &=
700 RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
703 return !error_on_missing_field_ || all_required_exist;
706 bool Validator::ValidateIPsec(base::DictionaryValue* result) {
707 using namespace ::onc::ipsec;
709 const char* const kValidAuthentications[] = {kPSK, kCert};
710 const std::vector<const char*> valid_authentications(
711 toVector(kValidAuthentications));
712 if (FieldExistsAndHasNoValidValue(
713 *result, kAuthenticationType, valid_authentications) ||
714 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
715 return false;
718 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
719 error_or_warning_found_ = true;
720 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
721 << " and " << kServerCARef << " can be set.";
722 return false;
725 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
726 result)) {
727 return false;
730 bool all_required_exist = RequireField(*result, kAuthenticationType) &&
731 RequireField(*result, kIKEVersion);
732 std::string auth;
733 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
734 bool has_server_ca_cert =
735 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
736 if (auth == kCert) {
737 all_required_exist &=
738 RequireField(*result, ::onc::client_cert::kClientCertType);
739 if (!has_server_ca_cert) {
740 all_required_exist = false;
741 error_or_warning_found_ = true;
742 std::string message = MessageHeader() + "The required field '" +
743 kServerCARefs + "' is missing.";
744 if (error_on_missing_field_)
745 LOG(ERROR) << message;
746 else
747 LOG(WARNING) << message;
749 } else if (has_server_ca_cert) {
750 error_or_warning_found_ = true;
751 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef
752 << ") can only be set if " << kAuthenticationType
753 << " is set to " << kCert << ".";
754 return false;
757 return !error_on_missing_field_ || all_required_exist;
760 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
761 using namespace ::onc::openvpn;
763 const char* const kValidAuthRetryValues[] = {::onc::openvpn::kNone, kInteract,
764 kNoInteract};
765 const std::vector<const char*> valid_auth_retry_values(
766 toVector(kValidAuthRetryValues));
767 const char* const kValidCertTlsValues[] = {::onc::openvpn::kNone,
768 ::onc::openvpn::kServer};
769 const std::vector<const char*> valid_cert_tls_values(
770 toVector(kValidCertTlsValues));
771 const char* const kValidUserAuthTypes[] = {
772 ::onc::openvpn_user_auth_type::kNone,
773 ::onc::openvpn_user_auth_type::kOTP,
774 ::onc::openvpn_user_auth_type::kPassword,
775 ::onc::openvpn_user_auth_type::kPasswordAndOTP};
776 const std::vector<const char*> valid_user_auth_types(
777 toVector(kValidUserAuthTypes));
779 if (FieldExistsAndHasNoValidValue(
780 *result, kAuthRetry, valid_auth_retry_values) ||
781 FieldExistsAndHasNoValidValue(
782 *result, kRemoteCertTLS, valid_cert_tls_values) ||
783 FieldExistsAndHasNoValidValue(
784 *result, kUserAuthenticationType, valid_user_auth_types) ||
785 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
786 return false;
789 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
790 error_or_warning_found_ = true;
791 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
792 << " and " << kServerCARef << " can be set.";
793 return false;
796 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
797 return false;
799 bool all_required_exist =
800 RequireField(*result, ::onc::client_cert::kClientCertType);
802 return !error_on_missing_field_ || all_required_exist;
805 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
806 using namespace ::onc::verify_x509;
808 const char* const kValidTypes[] = {types::kName, types::kNamePrefix,
809 types::kSubject};
810 const std::vector<const char*> valid_types(toVector(kValidTypes));
812 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
813 return false;
815 bool all_required_exist = RequireField(*result, kName);
817 return !error_on_missing_field_ || all_required_exist;
820 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
821 using namespace ::onc::client_cert;
823 bool all_required_exist = true;
824 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
825 !result->HasKey(kIssuerCARef)) {
826 error_or_warning_found_ = true;
827 all_required_exist = false;
828 std::string message = MessageHeader() + "None of the fields '" + kSubject +
829 "', '" + kIssuer + "', and '" + kIssuerCARef +
830 "' is present, but at least one is required.";
831 if (error_on_missing_field_)
832 LOG(ERROR) << message;
833 else
834 LOG(WARNING) << message;
837 return !error_on_missing_field_ || all_required_exist;
840 bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
841 using namespace ::onc::proxy;
843 const char* const kValidTypes[] = {kDirect, kManual, kPAC, kWPAD};
844 const std::vector<const char*> valid_types(toVector(kValidTypes));
845 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types))
846 return false;
848 bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
849 std::string type;
850 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
851 if (type == kManual)
852 all_required_exist &= RequireField(*result, kManual);
853 else if (type == kPAC)
854 all_required_exist &= RequireField(*result, kPAC);
856 return !error_on_missing_field_ || all_required_exist;
859 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
860 using namespace ::onc::proxy;
862 bool all_required_exist =
863 RequireField(*result, kHost) && RequireField(*result, kPort);
865 return !error_on_missing_field_ || all_required_exist;
868 bool Validator::ValidateEAP(base::DictionaryValue* result) {
869 using namespace ::onc::eap;
871 const char* const kValidInnerValues[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP};
872 const std::vector<const char*> valid_inner_values(
873 toVector(kValidInnerValues));
874 const char* const kValidOuterValues[] = {
875 kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA};
876 const std::vector<const char*> valid_outer_values(
877 toVector(kValidOuterValues));
879 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) ||
880 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) ||
881 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
882 return false;
885 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
886 error_or_warning_found_ = true;
887 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
888 << " and " << kServerCARef << " can be set.";
889 return false;
892 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
893 result)) {
894 return false;
897 bool all_required_exist = RequireField(*result, kOuter);
899 return !error_on_missing_field_ || all_required_exist;
902 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
903 using namespace ::onc::certificate;
905 const char* const kValidTypes[] = {kClient, kServer, kAuthority};
906 const std::vector<const char*> valid_types(toVector(kValidTypes));
907 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
908 FieldExistsAndIsEmpty(*result, kGUID)) {
909 return false;
912 std::string type;
913 result->GetStringWithoutPathExpansion(kType, &type);
914 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
915 (type == kServer || type == kAuthority)) {
916 error_or_warning_found_ = true;
917 LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
918 << "prohibited in ONC device policies.";
919 return false;
922 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_))
923 return false;
925 bool all_required_exist = RequireField(*result, kGUID);
927 bool remove = false;
928 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
929 if (!remove) {
930 all_required_exist &= RequireField(*result, kType);
932 if (type == kClient)
933 all_required_exist &= RequireField(*result, kPKCS12);
934 else if (type == kServer || type == kAuthority)
935 all_required_exist &= RequireField(*result, kX509);
938 return !error_on_missing_field_ || all_required_exist;
941 std::string Validator::MessageHeader() {
942 std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
943 std::string message = "At " + path + ": ";
944 return message;
947 } // namespace onc
948 } // namespace chromeos