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