onc_validator.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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. 4 5#include "chromeos/network/onc/onc_validator.h" 6 7#include <algorithm> 8#include <string> 9 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" 17 18namespace chromeos { 19namespace onc { 20 21namespace { 22 23template <typename T, size_t N> 24std::vector<T> toVector(T const (&array)[N]) { 25 return std::vector<T>(array, array + N); 26} 27 28// Copied from policy/configuration_policy_handler.cc. 29// TODO(pneubeck): move to a common place like base/. 30std::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]; 35} 36 37} // namespace 38 39Validator::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) {} 48 49Validator::~Validator() {} 50 51scoped_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; 66 } 67 // The return value should be NULL if, and only if, |result| equals INVALID. 68 DCHECK_EQ(result_value.get() == NULL, *result == INVALID); 69 70 base::DictionaryValue* result_dict = NULL; 71 if (result_value) { 72 result_value.release()->GetAsDictionary(&result_dict); 73 CHECK(result_dict); 74 } 75 76 return make_scoped_ptr(result_dict); 77} 78 79scoped_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>(); 89 } 90 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(); 96} 97 98scoped_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); 103 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()); 134 } 135 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>(); 142 } 143} 144 145scoped_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, ¤t_field_unknown, error); 155 156 DCHECK_EQ(field_name, path_.back()); 157 path_.pop_back(); 158 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; 167 } 168 169 return result.Pass(); 170} 171 172scoped_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); 179 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; 186 } 187 return result.Pass(); 188} 189 190scoped_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(); 201} 202 203bool 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); 210 211 if (found_unknown_field && error_on_unknown_field_) { 212 DVLOG(1) << "Unknown field names are errors: Aborting."; 213 return false; 214 } 215 216 if (nested_error_occured) 217 return false; 218 219 return ValidateRecommendedField(signature, result); 220} 221 222bool Validator::ValidateRecommendedField( 223 const OncValueSignature& object_signature, 224 base::DictionaryValue* result) { 225 CHECK(result); 226 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; 233 } 234 base::ListValue* recommended_list = NULL; 235 recommended_value.release()->GetAsList(&recommended_list); 236 CHECK(recommended_list); 237 238 recommended.reset(recommended_list); 239 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; 246 } 247 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; 255 } 256 257 const OncFieldSignature* field_signature = 258 GetFieldSignature(object_signature, field_name); 259 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"; 269 } 270 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; 283 } 284 } 285 286 repaired_recommended->Append((*it)->DeepCopy()); 287 } 288 289 result->Set(::onc::kRecommended, repaired_recommended.release()); 290 return true; 291} 292 293bool 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; 302 303 std::string cert_type; 304 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); 305 306 if (IsCertPatternInDevicePolicy(cert_type)) 307 return false; 308 309 bool all_required_exist = true; 310 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); 315 316 return !error_on_missing_field_ || all_required_exist; 317} 318 319namespace { 320 321std::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); 326} 327 328} // namespace 329 330bool 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; 337 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; 343 } 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; 352} 353 354bool 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; 362 } 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; 370} 371 372bool 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; 377 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; 389 } 390 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; 397} 398 399bool 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; 411} 412 413bool 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; 422 } 423 guids->insert(guid); 424 } 425 return true; 426} 427 428bool 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; 435 } 436 return false; 437} 438 439bool 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; 447 } 448 return false; 449} 450 451bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) { 452 using namespace ::onc::toplevel_config; 453 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; 459 460 if (IsGlobalNetworkConfigInUserImport(*result)) 461 return false; 462 463 return true; 464} 465 466bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) { 467 using namespace ::onc::network_config; 468 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; 476 } 477 478 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_)) 479 return false; 480 481 bool all_required_exist = RequireField(*result, kGUID); 482 483 bool remove = false; 484 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 485 if (!remove) { 486 all_required_exist &= 487 RequireField(*result, kName) && RequireField(*result, kType); 488 489 std::string type; 490 result->GetStringWithoutPathExpansion(kType, &type); 491 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; 501 } 502 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(); 515 } 516 } 517 518 return !error_on_missing_field_ || all_required_exist; 519} 520 521bool Validator::ValidateEthernet(base::DictionaryValue* result) { 522 using namespace ::onc::ethernet; 523 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; 530 } 531 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); 537 538 return !error_on_missing_field_ || all_required_exist; 539} 540 541bool Validator::ValidateIPConfig(base::DictionaryValue* result) { 542 using namespace ::onc::ipconfig; 543 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; 549 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; 558 } 559 560 bool all_required_exist = RequireField(*result, kIPAddress) && 561 RequireField(*result, kRoutingPrefix) && 562 RequireField(*result, ::onc::ipconfig::kType); 563 564 return !error_on_missing_field_ || all_required_exist; 565} 566 567bool Validator::ValidateWiFi(base::DictionaryValue* result) { 568 using namespace ::onc::wifi; 569 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; 575 576 bool all_required_exist = 577 RequireField(*result, kSecurity) && RequireField(*result, kSSID); 578 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); 585 586 return !error_on_missing_field_ || all_required_exist; 587} 588 589bool Validator::ValidateVPN(base::DictionaryValue* result) { 590 using namespace ::onc::vpn; 591 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; 596 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); 607 } 608 609 return !error_on_missing_field_ || all_required_exist; 610} 611 612bool Validator::ValidateIPsec(base::DictionaryValue* result) { 613 using namespace ::onc::ipsec; 614 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; 622 } 623 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; 629 } 630 631 if (!ValidateClientCertFields(false, // don't allow ClientCertType None 632 result)) { 633 return false; 634 } 635 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; 654 } 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; 661 } 662 663 return !error_on_missing_field_ || all_required_exist; 664} 665 666bool Validator::ValidateOpenVPN(base::DictionaryValue* result) { 667 using namespace ::onc::openvpn; 668 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)); 677 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; 684 } 685 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; 691 } 692 693 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result)) 694 return false; 695 696 bool all_required_exist = 697 RequireField(*result, ::onc::client_cert::kClientCertType); 698 699 return !error_on_missing_field_ || all_required_exist; 700} 701 702bool Validator::ValidateVerifyX509(base::DictionaryValue* result) { 703 using namespace ::onc::verify_x509; 704 705 const char* const kValidTypes[] = {types::kName, types::kNamePrefix, 706 types::kSubject}; 707 const std::vector<const char*> valid_types(toVector(kValidTypes)); 708 709 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types)) 710 return false; 711 712 bool all_required_exist = RequireField(*result, kName); 713 714 return !error_on_missing_field_ || all_required_exist; 715} 716 717bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) { 718 using namespace ::onc::client_cert; 719 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; 732 } 733 734 return !error_on_missing_field_ || all_required_exist; 735} 736 737bool Validator::ValidateProxySettings(base::DictionaryValue* result) { 738 using namespace ::onc::proxy; 739 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; 744 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); 752 753 return !error_on_missing_field_ || all_required_exist; 754} 755 756bool Validator::ValidateProxyLocation(base::DictionaryValue* result) { 757 using namespace ::onc::proxy; 758 759 bool all_required_exist = 760 RequireField(*result, kHost) && RequireField(*result, kPort); 761 762 return !error_on_missing_field_ || all_required_exist; 763} 764 765bool Validator::ValidateEAP(base::DictionaryValue* result) { 766 using namespace ::onc::eap; 767 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)); 775 776 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) || 777 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) || 778 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 779 return false; 780 } 781 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; 787 } 788 789 if (!ValidateClientCertFields(false, // don't allow ClientCertType None 790 result)) { 791 return false; 792 } 793 794 bool all_required_exist = RequireField(*result, kOuter); 795 796 return !error_on_missing_field_ || all_required_exist; 797} 798 799bool Validator::ValidateCertificate(base::DictionaryValue* result) { 800 using namespace ::onc::certificate; 801 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; 807 } 808 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; 817 } 818 819 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_)) 820 return false; 821 822 bool all_required_exist = RequireField(*result, kGUID); 823 824 bool remove = false; 825 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 826 if (!remove) { 827 all_required_exist &= RequireField(*result, kType); 828 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); 833 } 834 835 return !error_on_missing_field_ || all_required_exist; 836} 837 838std::string Validator::MessageHeader() { 839 std::string path = path_.empty() ? "toplevel" : JoinString(path_, "."); 840 std::string message = "At " + path + ": "; 841 return message; 842} 843 844} // namespace onc 845} // namespace chromeos 846