Some additional network settings cleanup
[chromium-blink-merge.git] / chromeos / network / onc / onc_validator.cc
blobd02f8e04c78bb4756301eee883e6a22f71439be3
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>
8 #include <string>
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chromeos/network/onc/onc_signature.h"
16 #include "components/onc/onc_constants.h"
18 namespace chromeos {
19 namespace onc {
21 namespace {
23 template <typename T, size_t N>
24 std::vector<T> toVector(T const (&array)[N]) {
25 return std::vector<T>(array, array + N);
28 // Copied from policy/configuration_policy_handler.cc.
29 // TODO(pneubeck): move to a common place like base/.
30 std::string ValueTypeToString(base::Value::Type type) {
31 const char* const strings[] = {"null", "boolean", "integer", "double",
32 "string", "binary", "dictionary", "list"};
33 CHECK(static_cast<size_t>(type) < arraysize(strings));
34 return strings[type];
37 } // namespace
39 Validator::Validator(bool error_on_unknown_field,
40 bool error_on_wrong_recommended,
41 bool error_on_missing_field,
42 bool managed_onc)
43 : error_on_unknown_field_(error_on_unknown_field),
44 error_on_wrong_recommended_(error_on_wrong_recommended),
45 error_on_missing_field_(error_on_missing_field),
46 managed_onc_(managed_onc),
47 onc_source_(::onc::ONC_SOURCE_NONE) {}
49 Validator::~Validator() {}
51 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
52 const OncValueSignature* object_signature,
53 const base::DictionaryValue& onc_object,
54 Result* result) {
55 CHECK(object_signature);
56 *result = VALID;
57 error_or_warning_found_ = false;
58 bool error = false;
59 scoped_ptr<base::Value> result_value =
60 MapValue(*object_signature, onc_object, &error);
61 if (error) {
62 *result = INVALID;
63 result_value.reset();
64 } else if (error_or_warning_found_) {
65 *result = VALID_WITH_WARNINGS;
67 // The return value should be NULL if, and only if, |result| equals INVALID.
68 DCHECK_EQ(result_value.get() == NULL, *result == INVALID);
70 base::DictionaryValue* result_dict = NULL;
71 if (result_value) {
72 result_value.release()->GetAsDictionary(&result_dict);
73 CHECK(result_dict);
76 return make_scoped_ptr(result_dict);
79 scoped_ptr<base::Value> Validator::MapValue(const OncValueSignature& signature,
80 const base::Value& onc_value,
81 bool* error) {
82 if (onc_value.GetType() != signature.onc_type) {
83 LOG(ERROR) << MessageHeader() << "Found value '" << onc_value
84 << "' of type '" << ValueTypeToString(onc_value.GetType())
85 << "', but type '" << ValueTypeToString(signature.onc_type)
86 << "' is required.";
87 error_or_warning_found_ = *error = true;
88 return scoped_ptr<base::Value>();
91 scoped_ptr<base::Value> repaired =
92 Mapper::MapValue(signature, onc_value, error);
93 if (repaired)
94 CHECK_EQ(repaired->GetType(), signature.onc_type);
95 return repaired.Pass();
98 scoped_ptr<base::DictionaryValue> Validator::MapObject(
99 const OncValueSignature& signature,
100 const base::DictionaryValue& onc_object,
101 bool* error) {
102 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
104 bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
105 if (valid) {
106 if (&signature == &kToplevelConfigurationSignature) {
107 valid = ValidateToplevelConfiguration(repaired.get());
108 } else if (&signature == &kNetworkConfigurationSignature) {
109 valid = ValidateNetworkConfiguration(repaired.get());
110 } else if (&signature == &kEthernetSignature) {
111 valid = ValidateEthernet(repaired.get());
112 } else if (&signature == &kIPConfigSignature ||
113 &signature == &kSavedIPConfigSignature ||
114 &signature == &kStaticIPConfigSignature) {
115 valid = ValidateIPConfig(repaired.get());
116 } else if (&signature == &kWiFiSignature) {
117 valid = ValidateWiFi(repaired.get());
118 } else if (&signature == &kVPNSignature) {
119 valid = ValidateVPN(repaired.get());
120 } else if (&signature == &kIPsecSignature) {
121 valid = ValidateIPsec(repaired.get());
122 } else if (&signature == &kOpenVPNSignature) {
123 valid = ValidateOpenVPN(repaired.get());
124 } else if (&signature == &kVerifyX509Signature) {
125 valid = ValidateVerifyX509(repaired.get());
126 } else if (&signature == &kCertificatePatternSignature) {
127 valid = ValidateCertificatePattern(repaired.get());
128 } else if (&signature == &kProxySettingsSignature) {
129 valid = ValidateProxySettings(repaired.get());
130 } else if (&signature == &kProxyLocationSignature) {
131 valid = ValidateProxyLocation(repaired.get());
132 } else if (&signature == &kEAPSignature) {
133 valid = ValidateEAP(repaired.get());
134 } else if (&signature == &kCertificateSignature) {
135 valid = ValidateCertificate(repaired.get());
139 if (valid) {
140 return repaired.Pass();
141 } else {
142 DCHECK(error_or_warning_found_);
143 error_or_warning_found_ = *error = true;
144 return scoped_ptr<base::DictionaryValue>();
148 scoped_ptr<base::Value> Validator::MapField(
149 const std::string& field_name,
150 const OncValueSignature& object_signature,
151 const base::Value& onc_value,
152 bool* found_unknown_field,
153 bool* error) {
154 path_.push_back(field_name);
155 bool current_field_unknown = false;
156 scoped_ptr<base::Value> result = Mapper::MapField(
157 field_name, object_signature, onc_value, &current_field_unknown, error);
159 DCHECK_EQ(field_name, path_.back());
160 path_.pop_back();
162 if (current_field_unknown) {
163 error_or_warning_found_ = *found_unknown_field = true;
164 std::string message = MessageHeader() + "Field name '" + field_name +
165 "' is unknown.";
166 if (error_on_unknown_field_)
167 LOG(ERROR) << message;
168 else
169 LOG(WARNING) << message;
172 return result.Pass();
175 scoped_ptr<base::ListValue> Validator::MapArray(
176 const OncValueSignature& array_signature,
177 const base::ListValue& onc_array,
178 bool* nested_error) {
179 bool nested_error_in_current_array = false;
180 scoped_ptr<base::ListValue> result = Mapper::MapArray(
181 array_signature, onc_array, &nested_error_in_current_array);
183 // Drop individual networks and certificates instead of rejecting all of
184 // the configuration.
185 if (nested_error_in_current_array &&
186 &array_signature != &kNetworkConfigurationListSignature &&
187 &array_signature != &kCertificateListSignature) {
188 *nested_error = nested_error_in_current_array;
190 return result.Pass();
193 scoped_ptr<base::Value> Validator::MapEntry(int index,
194 const OncValueSignature& signature,
195 const base::Value& onc_value,
196 bool* error) {
197 std::string str = base::IntToString(index);
198 path_.push_back(str);
199 scoped_ptr<base::Value> result =
200 Mapper::MapEntry(index, signature, onc_value, error);
201 DCHECK_EQ(str, path_.back());
202 path_.pop_back();
203 return result.Pass();
206 bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
207 const base::DictionaryValue& onc_object,
208 base::DictionaryValue* result) {
209 bool found_unknown_field = false;
210 bool nested_error_occured = false;
211 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
212 result);
214 if (found_unknown_field && error_on_unknown_field_) {
215 DVLOG(1) << "Unknown field names are errors: Aborting.";
216 return false;
219 if (nested_error_occured)
220 return false;
222 return ValidateRecommendedField(signature, result);
225 bool Validator::ValidateRecommendedField(
226 const OncValueSignature& object_signature,
227 base::DictionaryValue* result) {
228 CHECK(result);
230 scoped_ptr<base::ListValue> recommended;
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;
237 base::ListValue* recommended_list = NULL;
238 recommended_value.release()->GetAsList(&recommended_list);
239 CHECK(recommended_list);
241 recommended.reset(recommended_list);
243 if (!managed_onc_) {
244 error_or_warning_found_ = true;
245 LOG(WARNING) << MessageHeader() << "Found the field '"
246 << ::onc::kRecommended
247 << "' in an unmanaged ONC. Removing it.";
248 return true;
251 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
252 for (base::ListValue::iterator it = recommended->begin();
253 it != recommended->end(); ++it) {
254 std::string field_name;
255 if (!(*it)->GetAsString(&field_name)) {
256 NOTREACHED();
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->Append((*it)->DeepCopy());
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::RequireField(const base::DictionaryValue& dict,
403 const std::string& field_name) {
404 if (dict.HasKey(field_name))
405 return true;
406 error_or_warning_found_ = true;
407 std::string message = MessageHeader() + "The required field '" + field_name +
408 "' is missing.";
409 if (error_on_missing_field_)
410 LOG(ERROR) << message;
411 else
412 LOG(WARNING) << message;
413 return false;
416 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
417 const std::string& key_guid,
418 std::set<std::string> *guids) {
419 std::string guid;
420 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
421 if (guids->count(guid) != 0) {
422 error_or_warning_found_ = true;
423 LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << ".";
424 return false;
426 guids->insert(guid);
428 return true;
431 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) {
432 if (cert_type == ::onc::client_cert::kPattern &&
433 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) {
434 error_or_warning_found_ = true;
435 LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
436 << "prohibited in ONC device policies.";
437 return true;
439 return false;
442 bool Validator::IsGlobalNetworkConfigInUserImport(
443 const base::DictionaryValue& onc_object) {
444 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
445 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
446 error_or_warning_found_ = true;
447 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
448 << "in ONC user imports";
449 return true;
451 return false;
454 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
455 using namespace ::onc::toplevel_config;
457 const char* const kValidTypes[] = {kUnencryptedConfiguration,
458 kEncryptedConfiguration};
459 const std::vector<const char*> valid_types(toVector(kValidTypes));
460 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
461 return false;
463 if (IsGlobalNetworkConfigInUserImport(*result))
464 return false;
466 return true;
469 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
470 using namespace ::onc::network_config;
472 const char* const kValidTypes[] = {
473 ::onc::network_type::kEthernet, ::onc::network_type::kVPN,
474 ::onc::network_type::kWiFi, ::onc::network_type::kCellular};
475 const std::vector<const char*> valid_types(toVector(kValidTypes));
476 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
477 FieldExistsAndIsEmpty(*result, kGUID)) {
478 return false;
481 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
482 return false;
484 bool all_required_exist = RequireField(*result, kGUID);
486 bool remove = false;
487 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
488 if (!remove) {
489 all_required_exist &=
490 RequireField(*result, kName) && RequireField(*result, kType);
492 std::string type;
493 result->GetStringWithoutPathExpansion(kType, &type);
495 // Prohibit anything but WiFi and Ethernet for device-level policy (which
496 // corresponds to shared networks). See also http://crosbug.com/28741.
497 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
498 type != ::onc::network_type::kWiFi &&
499 type != ::onc::network_type::kEthernet) {
500 error_or_warning_found_ = true;
501 LOG(ERROR) << MessageHeader() << "Networks of type '"
502 << type << "' are prohibited in ONC device policies.";
503 return false;
506 if (type == ::onc::network_type::kWiFi) {
507 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
508 } else if (type == ::onc::network_type::kEthernet) {
509 all_required_exist &=
510 RequireField(*result, ::onc::network_config::kEthernet);
511 } else if (type == ::onc::network_type::kCellular) {
512 all_required_exist &=
513 RequireField(*result, ::onc::network_config::kCellular);
514 } else if (type == ::onc::network_type::kVPN) {
515 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
516 } else if (!type.empty()) {
517 NOTREACHED();
521 return !error_on_missing_field_ || all_required_exist;
524 bool Validator::ValidateEthernet(base::DictionaryValue* result) {
525 using namespace ::onc::ethernet;
527 const char* const kValidAuthentications[] = {kAuthenticationNone, k8021X};
528 const std::vector<const char*> valid_authentications(
529 toVector(kValidAuthentications));
530 if (FieldExistsAndHasNoValidValue(
531 *result, kAuthentication, valid_authentications)) {
532 return false;
535 bool all_required_exist = true;
536 std::string auth;
537 result->GetStringWithoutPathExpansion(kAuthentication, &auth);
538 if (auth == k8021X)
539 all_required_exist &= RequireField(*result, kEAP);
541 return !error_on_missing_field_ || all_required_exist;
544 bool Validator::ValidateIPConfig(base::DictionaryValue* result) {
545 using namespace ::onc::ipconfig;
547 const char* const kValidTypes[] = {kIPv4, kIPv6};
548 const std::vector<const char*> valid_types(toVector(kValidTypes));
549 if (FieldExistsAndHasNoValidValue(
550 *result, ::onc::ipconfig::kType, valid_types))
551 return false;
553 std::string type;
554 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
555 int lower_bound = 1;
556 // In case of missing type, choose higher upper_bound.
557 int upper_bound = (type == kIPv4) ? 32 : 128;
558 if (FieldExistsAndIsNotInRange(
559 *result, kRoutingPrefix, lower_bound, upper_bound)) {
560 return false;
563 bool all_required_exist = RequireField(*result, kIPAddress) &&
564 RequireField(*result, kRoutingPrefix) &&
565 RequireField(*result, ::onc::ipconfig::kType);
567 return !error_on_missing_field_ || all_required_exist;
570 bool Validator::ValidateWiFi(base::DictionaryValue* result) {
571 using namespace ::onc::wifi;
573 const char* const kValidSecurities[] = {kSecurityNone, kWEP_PSK, kWEP_8021X,
574 kWPA_PSK, kWPA_EAP};
575 const std::vector<const char*> valid_securities(toVector(kValidSecurities));
576 if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities))
577 return false;
579 bool all_required_exist =
580 RequireField(*result, kSecurity) && RequireField(*result, kSSID);
582 std::string security;
583 result->GetStringWithoutPathExpansion(kSecurity, &security);
584 if (security == kWEP_8021X || security == kWPA_EAP)
585 all_required_exist &= RequireField(*result, kEAP);
586 else if (security == kWEP_PSK || security == kWPA_PSK)
587 all_required_exist &= RequireField(*result, kPassphrase);
589 return !error_on_missing_field_ || all_required_exist;
592 bool Validator::ValidateVPN(base::DictionaryValue* result) {
593 using namespace ::onc::vpn;
595 const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN};
596 const std::vector<const char*> valid_types(toVector(kValidTypes));
597 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
598 return false;
600 bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
601 std::string type;
602 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
603 if (type == kOpenVPN) {
604 all_required_exist &= RequireField(*result, kOpenVPN);
605 } else if (type == kIPsec) {
606 all_required_exist &= RequireField(*result, kIPsec);
607 } else if (type == kTypeL2TP_IPsec) {
608 all_required_exist &=
609 RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
612 return !error_on_missing_field_ || all_required_exist;
615 bool Validator::ValidateIPsec(base::DictionaryValue* result) {
616 using namespace ::onc::ipsec;
618 const char* const kValidAuthentications[] = {kPSK, kCert};
619 const std::vector<const char*> valid_authentications(
620 toVector(kValidAuthentications));
621 if (FieldExistsAndHasNoValidValue(
622 *result, kAuthenticationType, valid_authentications) ||
623 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
624 return false;
627 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
628 error_or_warning_found_ = true;
629 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
630 << " and " << kServerCARef << " can be set.";
631 return false;
634 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
635 result)) {
636 return false;
639 bool all_required_exist = RequireField(*result, kAuthenticationType) &&
640 RequireField(*result, kIKEVersion);
641 std::string auth;
642 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
643 bool has_server_ca_cert =
644 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
645 if (auth == kCert) {
646 all_required_exist &=
647 RequireField(*result, ::onc::client_cert::kClientCertType);
648 if (!has_server_ca_cert) {
649 all_required_exist = false;
650 error_or_warning_found_ = true;
651 std::string message = MessageHeader() + "The required field '" +
652 kServerCARefs + "' is missing.";
653 if (error_on_missing_field_)
654 LOG(ERROR) << message;
655 else
656 LOG(WARNING) << message;
658 } else if (has_server_ca_cert) {
659 error_or_warning_found_ = true;
660 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef
661 << ") can only be set if " << kAuthenticationType
662 << " is set to " << kCert << ".";
663 return false;
666 return !error_on_missing_field_ || all_required_exist;
669 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
670 using namespace ::onc::openvpn;
672 const char* const kValidAuthRetryValues[] = {::onc::openvpn::kNone, kInteract,
673 kNoInteract};
674 const std::vector<const char*> valid_auth_retry_values(
675 toVector(kValidAuthRetryValues));
676 const char* const kValidCertTlsValues[] = {::onc::openvpn::kNone,
677 ::onc::openvpn::kServer};
678 const std::vector<const char*> valid_cert_tls_values(
679 toVector(kValidCertTlsValues));
681 if (FieldExistsAndHasNoValidValue(
682 *result, kAuthRetry, valid_auth_retry_values) ||
683 FieldExistsAndHasNoValidValue(
684 *result, kRemoteCertTLS, valid_cert_tls_values) ||
685 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
686 return false;
689 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
690 error_or_warning_found_ = true;
691 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
692 << " and " << kServerCARef << " can be set.";
693 return false;
696 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
697 return false;
699 bool all_required_exist =
700 RequireField(*result, ::onc::client_cert::kClientCertType);
702 return !error_on_missing_field_ || all_required_exist;
705 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
706 using namespace ::onc::verify_x509;
708 const char* const kValidTypes[] = {types::kName, types::kNamePrefix,
709 types::kSubject};
710 const std::vector<const char*> valid_types(toVector(kValidTypes));
712 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
713 return false;
715 bool all_required_exist = RequireField(*result, kName);
717 return !error_on_missing_field_ || all_required_exist;
720 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
721 using namespace ::onc::client_cert;
723 bool all_required_exist = true;
724 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
725 !result->HasKey(kIssuerCARef)) {
726 error_or_warning_found_ = true;
727 all_required_exist = false;
728 std::string message = MessageHeader() + "None of the fields '" + kSubject +
729 "', '" + kIssuer + "', and '" + kIssuerCARef +
730 "' is present, but at least one is required.";
731 if (error_on_missing_field_)
732 LOG(ERROR) << message;
733 else
734 LOG(WARNING) << message;
737 return !error_on_missing_field_ || all_required_exist;
740 bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
741 using namespace ::onc::proxy;
743 const char* const kValidTypes[] = {kDirect, kManual, kPAC, kWPAD};
744 const std::vector<const char*> valid_types(toVector(kValidTypes));
745 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types))
746 return false;
748 bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
749 std::string type;
750 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
751 if (type == kManual)
752 all_required_exist &= RequireField(*result, kManual);
753 else if (type == kPAC)
754 all_required_exist &= RequireField(*result, kPAC);
756 return !error_on_missing_field_ || all_required_exist;
759 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
760 using namespace ::onc::proxy;
762 bool all_required_exist =
763 RequireField(*result, kHost) && RequireField(*result, kPort);
765 return !error_on_missing_field_ || all_required_exist;
768 bool Validator::ValidateEAP(base::DictionaryValue* result) {
769 using namespace ::onc::eap;
771 const char* const kValidInnerValues[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP};
772 const std::vector<const char*> valid_inner_values(
773 toVector(kValidInnerValues));
774 const char* const kValidOuterValues[] = {
775 kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA};
776 const std::vector<const char*> valid_outer_values(
777 toVector(kValidOuterValues));
779 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) ||
780 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) ||
781 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
782 return false;
785 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
786 error_or_warning_found_ = true;
787 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
788 << " and " << kServerCARef << " can be set.";
789 return false;
792 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
793 result)) {
794 return false;
797 bool all_required_exist = RequireField(*result, kOuter);
799 return !error_on_missing_field_ || all_required_exist;
802 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
803 using namespace ::onc::certificate;
805 const char* const kValidTypes[] = {kClient, kServer, kAuthority};
806 const std::vector<const char*> valid_types(toVector(kValidTypes));
807 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
808 FieldExistsAndIsEmpty(*result, kGUID)) {
809 return false;
812 std::string type;
813 result->GetStringWithoutPathExpansion(kType, &type);
814 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
815 (type == kServer || type == kAuthority)) {
816 error_or_warning_found_ = true;
817 LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
818 << "prohibited in ONC device policies.";
819 return false;
822 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_))
823 return false;
825 bool all_required_exist = RequireField(*result, kGUID);
827 bool remove = false;
828 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
829 if (!remove) {
830 all_required_exist &= RequireField(*result, kType);
832 if (type == kClient)
833 all_required_exist &= RequireField(*result, kPKCS12);
834 else if (type == kServer || type == kAuthority)
835 all_required_exist &= RequireField(*result, kX509);
838 return !error_on_missing_field_ || all_required_exist;
841 std::string Validator::MessageHeader() {
842 std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
843 std::string message = "At " + path + ": ";
844 return message;
847 } // namespace onc
848 } // namespace chromeos