Fix race condition in gyp/ninja builds.
[chromium-blink-merge.git] / chromeos / network / onc / onc_validator.cc
blob5f7aa9663d6034d85047b5d212279a3763b263ae
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 valid = ValidateIPConfig(repaired.get());
114 else if (&signature == &kWiFiSignature)
115 valid = ValidateWiFi(repaired.get());
116 else if (&signature == &kVPNSignature)
117 valid = ValidateVPN(repaired.get());
118 else if (&signature == &kIPsecSignature)
119 valid = ValidateIPsec(repaired.get());
120 else if (&signature == &kOpenVPNSignature)
121 valid = ValidateOpenVPN(repaired.get());
122 else if (&signature == &kVerifyX509Signature)
123 valid = ValidateVerifyX509(repaired.get());
124 else if (&signature == &kCertificatePatternSignature)
125 valid = ValidateCertificatePattern(repaired.get());
126 else if (&signature == &kProxySettingsSignature)
127 valid = ValidateProxySettings(repaired.get());
128 else if (&signature == &kProxyLocationSignature)
129 valid = ValidateProxyLocation(repaired.get());
130 else if (&signature == &kEAPSignature)
131 valid = ValidateEAP(repaired.get());
132 else if (&signature == &kCertificateSignature)
133 valid = ValidateCertificate(repaired.get());
136 if (valid) {
137 return repaired.Pass();
138 } else {
139 DCHECK(error_or_warning_found_);
140 error_or_warning_found_ = *error = true;
141 return scoped_ptr<base::DictionaryValue>();
145 scoped_ptr<base::Value> Validator::MapField(
146 const std::string& field_name,
147 const OncValueSignature& object_signature,
148 const base::Value& onc_value,
149 bool* found_unknown_field,
150 bool* error) {
151 path_.push_back(field_name);
152 bool current_field_unknown = false;
153 scoped_ptr<base::Value> result = Mapper::MapField(
154 field_name, object_signature, onc_value, &current_field_unknown, error);
156 DCHECK_EQ(field_name, path_.back());
157 path_.pop_back();
159 if (current_field_unknown) {
160 error_or_warning_found_ = *found_unknown_field = true;
161 std::string message = MessageHeader() + "Field name '" + field_name +
162 "' is unknown.";
163 if (error_on_unknown_field_)
164 LOG(ERROR) << message;
165 else
166 LOG(WARNING) << message;
169 return result.Pass();
172 scoped_ptr<base::ListValue> Validator::MapArray(
173 const OncValueSignature& array_signature,
174 const base::ListValue& onc_array,
175 bool* nested_error) {
176 bool nested_error_in_current_array = false;
177 scoped_ptr<base::ListValue> result = Mapper::MapArray(
178 array_signature, onc_array, &nested_error_in_current_array);
180 // Drop individual networks and certificates instead of rejecting all of
181 // the configuration.
182 if (nested_error_in_current_array &&
183 &array_signature != &kNetworkConfigurationListSignature &&
184 &array_signature != &kCertificateListSignature) {
185 *nested_error = nested_error_in_current_array;
187 return result.Pass();
190 scoped_ptr<base::Value> Validator::MapEntry(int index,
191 const OncValueSignature& signature,
192 const base::Value& onc_value,
193 bool* error) {
194 std::string str = base::IntToString(index);
195 path_.push_back(str);
196 scoped_ptr<base::Value> result =
197 Mapper::MapEntry(index, signature, onc_value, error);
198 DCHECK_EQ(str, path_.back());
199 path_.pop_back();
200 return result.Pass();
203 bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
204 const base::DictionaryValue& onc_object,
205 base::DictionaryValue* result) {
206 bool found_unknown_field = false;
207 bool nested_error_occured = false;
208 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
209 result);
211 if (found_unknown_field && error_on_unknown_field_) {
212 DVLOG(1) << "Unknown field names are errors: Aborting.";
213 return false;
216 if (nested_error_occured)
217 return false;
219 return ValidateRecommendedField(signature, result);
222 bool Validator::ValidateRecommendedField(
223 const OncValueSignature& object_signature,
224 base::DictionaryValue* result) {
225 CHECK(result);
227 scoped_ptr<base::ListValue> recommended;
228 scoped_ptr<base::Value> recommended_value;
229 // This remove passes ownership to |recommended_value|.
230 if (!result->RemoveWithoutPathExpansion(::onc::kRecommended,
231 &recommended_value)) {
232 return true;
234 base::ListValue* recommended_list = NULL;
235 recommended_value.release()->GetAsList(&recommended_list);
236 CHECK(recommended_list);
238 recommended.reset(recommended_list);
240 if (!managed_onc_) {
241 error_or_warning_found_ = true;
242 LOG(WARNING) << MessageHeader() << "Found the field '"
243 << ::onc::kRecommended
244 << "' in an unmanaged ONC. Removing it.";
245 return true;
248 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
249 for (base::ListValue::iterator it = recommended->begin();
250 it != recommended->end(); ++it) {
251 std::string field_name;
252 if (!(*it)->GetAsString(&field_name)) {
253 NOTREACHED();
254 continue;
257 const OncFieldSignature* field_signature =
258 GetFieldSignature(object_signature, field_name);
260 bool found_error = false;
261 std::string error_cause;
262 if (!field_signature) {
263 found_error = true;
264 error_cause = "unknown";
265 } else if (field_signature->value_signature->onc_type ==
266 base::Value::TYPE_DICTIONARY) {
267 found_error = true;
268 error_cause = "dictionary-typed";
271 if (found_error) {
272 error_or_warning_found_ = true;
273 path_.push_back(::onc::kRecommended);
274 std::string message = MessageHeader() + "The " + error_cause +
275 " field '" + field_name + "' cannot be recommended.";
276 path_.pop_back();
277 if (error_on_wrong_recommended_) {
278 LOG(ERROR) << message;
279 return false;
280 } else {
281 LOG(WARNING) << message;
282 continue;
286 repaired_recommended->Append((*it)->DeepCopy());
289 result->Set(::onc::kRecommended, repaired_recommended.release());
290 return true;
293 bool Validator::ValidateClientCertFields(bool allow_cert_type_none,
294 base::DictionaryValue* result) {
295 using namespace ::onc::client_cert;
296 const char* const kValidCertTypes[] = {kRef, kPattern};
297 std::vector<const char*> valid_cert_types(toVector(kValidCertTypes));
298 if (allow_cert_type_none)
299 valid_cert_types.push_back(kClientCertTypeNone);
300 if (FieldExistsAndHasNoValidValue(*result, kClientCertType, valid_cert_types))
301 return false;
303 std::string cert_type;
304 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
306 if (IsCertPatternInDevicePolicy(cert_type))
307 return false;
309 bool all_required_exist = true;
311 if (cert_type == kPattern)
312 all_required_exist &= RequireField(*result, kClientCertPattern);
313 else if (cert_type == kRef)
314 all_required_exist &= RequireField(*result, kClientCertRef);
316 return !error_on_missing_field_ || all_required_exist;
319 namespace {
321 std::string JoinStringRange(const std::vector<const char*>& strings,
322 const std::string& separator) {
323 std::vector<std::string> string_vector;
324 std::copy(strings.begin(), strings.end(), std::back_inserter(string_vector));
325 return JoinString(string_vector, separator);
328 } // namespace
330 bool Validator::FieldExistsAndHasNoValidValue(
331 const base::DictionaryValue& object,
332 const std::string& field_name,
333 const std::vector<const char*>& valid_values) {
334 std::string actual_value;
335 if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
336 return false;
338 for (std::vector<const char*>::const_iterator it = valid_values.begin();
339 it != valid_values.end();
340 ++it) {
341 if (actual_value == *it)
342 return false;
344 error_or_warning_found_ = true;
345 std::string valid_values_str =
346 "[" + JoinStringRange(valid_values, ", ") + "]";
347 path_.push_back(field_name);
348 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value <<
349 "', but expected one of the values " << valid_values_str;
350 path_.pop_back();
351 return true;
354 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
355 const std::string& field_name,
356 int lower_bound,
357 int upper_bound) {
358 int actual_value;
359 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
360 (lower_bound <= actual_value && actual_value <= upper_bound)) {
361 return false;
363 error_or_warning_found_ = true;
364 path_.push_back(field_name);
365 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value
366 << "', but expected a value in the range [" << lower_bound
367 << ", " << upper_bound << "] (boundaries inclusive)";
368 path_.pop_back();
369 return true;
372 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
373 const std::string& field_name) {
374 const base::Value* value = NULL;
375 if (!object.GetWithoutPathExpansion(field_name, &value))
376 return false;
378 std::string str;
379 const base::ListValue* list = NULL;
380 if (value->GetAsString(&str)) {
381 if (!str.empty())
382 return false;
383 } else if (value->GetAsList(&list)) {
384 if (!list->empty())
385 return false;
386 } else {
387 NOTREACHED();
388 return false;
391 error_or_warning_found_ = true;
392 path_.push_back(field_name);
393 LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a "
394 << "non-empty string.";
395 path_.pop_back();
396 return true;
399 bool Validator::RequireField(const base::DictionaryValue& dict,
400 const std::string& field_name) {
401 if (dict.HasKey(field_name))
402 return true;
403 error_or_warning_found_ = true;
404 std::string message = MessageHeader() + "The required field '" + field_name +
405 "' is missing.";
406 if (error_on_missing_field_)
407 LOG(ERROR) << message;
408 else
409 LOG(WARNING) << message;
410 return false;
413 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
414 const std::string& key_guid,
415 std::set<std::string> *guids) {
416 std::string guid;
417 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
418 if (guids->count(guid) != 0) {
419 error_or_warning_found_ = true;
420 LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << ".";
421 return false;
423 guids->insert(guid);
425 return true;
428 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) {
429 if (cert_type == ::onc::client_cert::kPattern &&
430 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) {
431 error_or_warning_found_ = true;
432 LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
433 << "prohibited in ONC device policies.";
434 return true;
436 return false;
439 bool Validator::IsGlobalNetworkConfigInUserImport(
440 const base::DictionaryValue& onc_object) {
441 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
442 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
443 error_or_warning_found_ = true;
444 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
445 << "in ONC user imports";
446 return true;
448 return false;
451 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
452 using namespace ::onc::toplevel_config;
454 const char* const kValidTypes[] = {kUnencryptedConfiguration,
455 kEncryptedConfiguration};
456 const std::vector<const char*> valid_types(toVector(kValidTypes));
457 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
458 return false;
460 if (IsGlobalNetworkConfigInUserImport(*result))
461 return false;
463 return true;
466 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
467 using namespace ::onc::network_config;
469 const char* const kValidTypes[] = {
470 ::onc::network_type::kEthernet, ::onc::network_type::kVPN,
471 ::onc::network_type::kWiFi, ::onc::network_type::kCellular};
472 const std::vector<const char*> valid_types(toVector(kValidTypes));
473 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
474 FieldExistsAndIsEmpty(*result, kGUID)) {
475 return false;
478 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
479 return false;
481 bool all_required_exist = RequireField(*result, kGUID);
483 bool remove = false;
484 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
485 if (!remove) {
486 all_required_exist &=
487 RequireField(*result, kName) && RequireField(*result, kType);
489 std::string type;
490 result->GetStringWithoutPathExpansion(kType, &type);
492 // Prohibit anything but WiFi and Ethernet for device-level policy (which
493 // corresponds to shared networks). See also http://crosbug.com/28741.
494 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
495 type != ::onc::network_type::kWiFi &&
496 type != ::onc::network_type::kEthernet) {
497 error_or_warning_found_ = true;
498 LOG(ERROR) << MessageHeader() << "Networks of type '"
499 << type << "' are prohibited in ONC device policies.";
500 return false;
503 if (type == ::onc::network_type::kWiFi) {
504 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
505 } else if (type == ::onc::network_type::kEthernet) {
506 all_required_exist &=
507 RequireField(*result, ::onc::network_config::kEthernet);
508 } else if (type == ::onc::network_type::kCellular) {
509 all_required_exist &=
510 RequireField(*result, ::onc::network_config::kCellular);
511 } else if (type == ::onc::network_type::kVPN) {
512 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
513 } else if (!type.empty()) {
514 NOTREACHED();
518 return !error_on_missing_field_ || all_required_exist;
521 bool Validator::ValidateEthernet(base::DictionaryValue* result) {
522 using namespace ::onc::ethernet;
524 const char* const kValidAuthentications[] = {kAuthenticationNone, k8021X};
525 const std::vector<const char*> valid_authentications(
526 toVector(kValidAuthentications));
527 if (FieldExistsAndHasNoValidValue(
528 *result, kAuthentication, valid_authentications)) {
529 return false;
532 bool all_required_exist = true;
533 std::string auth;
534 result->GetStringWithoutPathExpansion(kAuthentication, &auth);
535 if (auth == k8021X)
536 all_required_exist &= RequireField(*result, kEAP);
538 return !error_on_missing_field_ || all_required_exist;
541 bool Validator::ValidateIPConfig(base::DictionaryValue* result) {
542 using namespace ::onc::ipconfig;
544 const char* const kValidTypes[] = {kIPv4, kIPv6};
545 const std::vector<const char*> valid_types(toVector(kValidTypes));
546 if (FieldExistsAndHasNoValidValue(
547 *result, ::onc::ipconfig::kType, valid_types))
548 return false;
550 std::string type;
551 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
552 int lower_bound = 1;
553 // In case of missing type, choose higher upper_bound.
554 int upper_bound = (type == kIPv4) ? 32 : 128;
555 if (FieldExistsAndIsNotInRange(
556 *result, kRoutingPrefix, lower_bound, upper_bound)) {
557 return false;
560 bool all_required_exist = RequireField(*result, kIPAddress) &&
561 RequireField(*result, kRoutingPrefix) &&
562 RequireField(*result, ::onc::ipconfig::kType);
564 return !error_on_missing_field_ || all_required_exist;
567 bool Validator::ValidateWiFi(base::DictionaryValue* result) {
568 using namespace ::onc::wifi;
570 const char* const kValidSecurities[] = {kSecurityNone, kWEP_PSK, kWEP_8021X,
571 kWPA_PSK, kWPA_EAP};
572 const std::vector<const char*> valid_securities(toVector(kValidSecurities));
573 if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities))
574 return false;
576 bool all_required_exist =
577 RequireField(*result, kSecurity) && RequireField(*result, kSSID);
579 std::string security;
580 result->GetStringWithoutPathExpansion(kSecurity, &security);
581 if (security == kWEP_8021X || security == kWPA_EAP)
582 all_required_exist &= RequireField(*result, kEAP);
583 else if (security == kWEP_PSK || security == kWPA_PSK)
584 all_required_exist &= RequireField(*result, kPassphrase);
586 return !error_on_missing_field_ || all_required_exist;
589 bool Validator::ValidateVPN(base::DictionaryValue* result) {
590 using namespace ::onc::vpn;
592 const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN};
593 const std::vector<const char*> valid_types(toVector(kValidTypes));
594 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
595 return false;
597 bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
598 std::string type;
599 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
600 if (type == kOpenVPN) {
601 all_required_exist &= RequireField(*result, kOpenVPN);
602 } else if (type == kIPsec) {
603 all_required_exist &= RequireField(*result, kIPsec);
604 } else if (type == kTypeL2TP_IPsec) {
605 all_required_exist &=
606 RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
609 return !error_on_missing_field_ || all_required_exist;
612 bool Validator::ValidateIPsec(base::DictionaryValue* result) {
613 using namespace ::onc::ipsec;
615 const char* const kValidAuthentications[] = {kPSK, kCert};
616 const std::vector<const char*> valid_authentications(
617 toVector(kValidAuthentications));
618 if (FieldExistsAndHasNoValidValue(
619 *result, kAuthenticationType, valid_authentications) ||
620 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
621 return false;
624 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
625 error_or_warning_found_ = true;
626 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
627 << " and " << kServerCARef << " can be set.";
628 return false;
631 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
632 result)) {
633 return false;
636 bool all_required_exist = RequireField(*result, kAuthenticationType) &&
637 RequireField(*result, kIKEVersion);
638 std::string auth;
639 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
640 bool has_server_ca_cert =
641 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
642 if (auth == kCert) {
643 all_required_exist &=
644 RequireField(*result, ::onc::client_cert::kClientCertType);
645 if (!has_server_ca_cert) {
646 all_required_exist = false;
647 error_or_warning_found_ = true;
648 std::string message = MessageHeader() + "The required field '" +
649 kServerCARefs + "' is missing.";
650 if (error_on_missing_field_)
651 LOG(ERROR) << message;
652 else
653 LOG(WARNING) << message;
655 } else if (has_server_ca_cert) {
656 error_or_warning_found_ = true;
657 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef
658 << ") can only be set if " << kAuthenticationType
659 << " is set to " << kCert << ".";
660 return false;
663 return !error_on_missing_field_ || all_required_exist;
666 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
667 using namespace ::onc::openvpn;
669 const char* const kValidAuthRetryValues[] = {::onc::openvpn::kNone, kInteract,
670 kNoInteract};
671 const std::vector<const char*> valid_auth_retry_values(
672 toVector(kValidAuthRetryValues));
673 const char* const kValidCertTlsValues[] = {::onc::openvpn::kNone,
674 ::onc::openvpn::kServer};
675 const std::vector<const char*> valid_cert_tls_values(
676 toVector(kValidCertTlsValues));
678 if (FieldExistsAndHasNoValidValue(
679 *result, kAuthRetry, valid_auth_retry_values) ||
680 FieldExistsAndHasNoValidValue(
681 *result, kRemoteCertTLS, valid_cert_tls_values) ||
682 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
683 return false;
686 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
687 error_or_warning_found_ = true;
688 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
689 << " and " << kServerCARef << " can be set.";
690 return false;
693 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
694 return false;
696 bool all_required_exist =
697 RequireField(*result, ::onc::client_cert::kClientCertType);
699 return !error_on_missing_field_ || all_required_exist;
702 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
703 using namespace ::onc::verify_x509;
705 const char* const kValidTypes[] = {types::kName, types::kNamePrefix,
706 types::kSubject};
707 const std::vector<const char*> valid_types(toVector(kValidTypes));
709 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
710 return false;
712 bool all_required_exist = RequireField(*result, kName);
714 return !error_on_missing_field_ || all_required_exist;
717 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
718 using namespace ::onc::client_cert;
720 bool all_required_exist = true;
721 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
722 !result->HasKey(kIssuerCARef)) {
723 error_or_warning_found_ = true;
724 all_required_exist = false;
725 std::string message = MessageHeader() + "None of the fields '" + kSubject +
726 "', '" + kIssuer + "', and '" + kIssuerCARef +
727 "' is present, but at least one is required.";
728 if (error_on_missing_field_)
729 LOG(ERROR) << message;
730 else
731 LOG(WARNING) << message;
734 return !error_on_missing_field_ || all_required_exist;
737 bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
738 using namespace ::onc::proxy;
740 const char* const kValidTypes[] = {kDirect, kManual, kPAC, kWPAD};
741 const std::vector<const char*> valid_types(toVector(kValidTypes));
742 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types))
743 return false;
745 bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
746 std::string type;
747 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
748 if (type == kManual)
749 all_required_exist &= RequireField(*result, kManual);
750 else if (type == kPAC)
751 all_required_exist &= RequireField(*result, kPAC);
753 return !error_on_missing_field_ || all_required_exist;
756 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
757 using namespace ::onc::proxy;
759 bool all_required_exist =
760 RequireField(*result, kHost) && RequireField(*result, kPort);
762 return !error_on_missing_field_ || all_required_exist;
765 bool Validator::ValidateEAP(base::DictionaryValue* result) {
766 using namespace ::onc::eap;
768 const char* const kValidInnerValues[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP};
769 const std::vector<const char*> valid_inner_values(
770 toVector(kValidInnerValues));
771 const char* const kValidOuterValues[] = {
772 kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA};
773 const std::vector<const char*> valid_outer_values(
774 toVector(kValidOuterValues));
776 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) ||
777 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) ||
778 FieldExistsAndIsEmpty(*result, kServerCARefs)) {
779 return false;
782 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
783 error_or_warning_found_ = true;
784 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
785 << " and " << kServerCARef << " can be set.";
786 return false;
789 if (!ValidateClientCertFields(false, // don't allow ClientCertType None
790 result)) {
791 return false;
794 bool all_required_exist = RequireField(*result, kOuter);
796 return !error_on_missing_field_ || all_required_exist;
799 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
800 using namespace ::onc::certificate;
802 const char* const kValidTypes[] = {kClient, kServer, kAuthority};
803 const std::vector<const char*> valid_types(toVector(kValidTypes));
804 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
805 FieldExistsAndIsEmpty(*result, kGUID)) {
806 return false;
809 std::string type;
810 result->GetStringWithoutPathExpansion(kType, &type);
811 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
812 (type == kServer || type == kAuthority)) {
813 error_or_warning_found_ = true;
814 LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
815 << "prohibited in ONC device policies.";
816 return false;
819 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_))
820 return false;
822 bool all_required_exist = RequireField(*result, kGUID);
824 bool remove = false;
825 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
826 if (!remove) {
827 all_required_exist &= RequireField(*result, kType);
829 if (type == kClient)
830 all_required_exist &= RequireField(*result, kPKCS12);
831 else if (type == kServer || type == kAuthority)
832 all_required_exist &= RequireField(*result, kX509);
835 return !error_on_missing_field_ || all_required_exist;
838 std::string Validator::MessageHeader() {
839 std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
840 std::string message = "At " + path + ": ";
841 return message;
844 } // namespace onc
845 } // namespace chromeos