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 18 namespace chromeos { 19 namespace onc { 20 21 namespace { 22 23 // Copied from policy/configuration_policy_handler.cc. 24 // TODO(pneubeck): move to a common place like base/. 25 std::string ValueTypeToString(base::Value::Type type) { 26 static const char* strings[] = { 27 "null", 28 "boolean", 29 "integer", 30 "double", 31 "string", 32 "binary", 33 "dictionary", 34 "list" 35 }; 36 CHECK(static_cast<size_t>(type) < arraysize(strings)); 37 return strings[type]; 38 } 39 40 } // namespace 41 42 Validator::Validator(bool error_on_unknown_field, 43 bool error_on_wrong_recommended, 44 bool error_on_missing_field, 45 bool managed_onc) 46 : error_on_unknown_field_(error_on_unknown_field), 47 error_on_wrong_recommended_(error_on_wrong_recommended), 48 error_on_missing_field_(error_on_missing_field), 49 managed_onc_(managed_onc), 50 onc_source_(::onc::ONC_SOURCE_NONE) {} 51 52 Validator::~Validator() {} 53 54 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject( 55 const OncValueSignature* object_signature, 56 const base::DictionaryValue& onc_object, 57 Result* result) { 58 CHECK(object_signature != NULL); 59 *result = VALID; 60 error_or_warning_found_ = false; 61 bool error = false; 62 scoped_ptr<base::Value> result_value = 63 MapValue(*object_signature, onc_object, &error); 64 if (error) { 65 *result = INVALID; 66 result_value.reset(); 67 } else if (error_or_warning_found_) { 68 *result = VALID_WITH_WARNINGS; 69 } 70 // The return value should be NULL if, and only if, |result| equals INVALID. 71 DCHECK_EQ(result_value.get() == NULL, *result == INVALID); 72 73 base::DictionaryValue* result_dict = NULL; 74 if (result_value.get() != NULL) { 75 result_value.release()->GetAsDictionary(&result_dict); 76 CHECK(result_dict != NULL); 77 } 78 79 return make_scoped_ptr(result_dict); 80 } 81 82 scoped_ptr<base::Value> Validator::MapValue(const OncValueSignature& signature, 83 const base::Value& onc_value, 84 bool* error) { 85 if (onc_value.GetType() != signature.onc_type) { 86 LOG(ERROR) << MessageHeader() << "Found value '" << onc_value 87 << "' of type '" << ValueTypeToString(onc_value.GetType()) 88 << "', but type '" << ValueTypeToString(signature.onc_type) 89 << "' is required."; 90 error_or_warning_found_ = *error = true; 91 return scoped_ptr<base::Value>(); 92 } 93 94 scoped_ptr<base::Value> repaired = 95 Mapper::MapValue(signature, onc_value, error); 96 if (repaired.get() != NULL) 97 CHECK_EQ(repaired->GetType(), signature.onc_type); 98 return repaired.Pass(); 99 } 100 101 scoped_ptr<base::DictionaryValue> Validator::MapObject( 102 const OncValueSignature& signature, 103 const base::DictionaryValue& onc_object, 104 bool* error) { 105 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue); 106 107 bool valid = ValidateObjectDefault(signature, onc_object, repaired.get()); 108 if (valid) { 109 if (&signature == &kToplevelConfigurationSignature) 110 valid = ValidateToplevelConfiguration(repaired.get()); 111 else if (&signature == &kNetworkConfigurationSignature) 112 valid = ValidateNetworkConfiguration(repaired.get()); 113 else if (&signature == &kEthernetSignature) 114 valid = ValidateEthernet(repaired.get()); 115 else if (&signature == &kIPConfigSignature) 116 valid = ValidateIPConfig(repaired.get()); 117 else if (&signature == &kWiFiSignature) 118 valid = ValidateWiFi(repaired.get()); 119 else if (&signature == &kVPNSignature) 120 valid = ValidateVPN(repaired.get()); 121 else if (&signature == &kIPsecSignature) 122 valid = ValidateIPsec(repaired.get()); 123 else if (&signature == &kOpenVPNSignature) 124 valid = ValidateOpenVPN(repaired.get()); 125 else if (&signature == &kVerifyX509Signature) 126 valid = ValidateVerifyX509(repaired.get()); 127 else if (&signature == &kCertificatePatternSignature) 128 valid = ValidateCertificatePattern(repaired.get()); 129 else if (&signature == &kProxySettingsSignature) 130 valid = ValidateProxySettings(repaired.get()); 131 else if (&signature == &kProxyLocationSignature) 132 valid = ValidateProxyLocation(repaired.get()); 133 else if (&signature == &kEAPSignature) 134 valid = ValidateEAP(repaired.get()); 135 else if (&signature == &kCertificateSignature) 136 valid = ValidateCertificate(repaired.get()); 137 } 138 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>(); 145 } 146 } 147 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, ¤t_field_unknown, error); 158 159 DCHECK_EQ(field_name, path_.back()); 160 path_.pop_back(); 161 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; 170 } 171 172 return result.Pass(); 173 } 174 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); 182 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; 189 } 190 return result.Pass(); 191 } 192 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(); 204 } 205 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); 213 214 if (found_unknown_field && error_on_unknown_field_) { 215 DVLOG(1) << "Unknown field names are errors: Aborting."; 216 return false; 217 } 218 219 if (nested_error_occured) 220 return false; 221 222 return ValidateRecommendedField(signature, result); 223 } 224 225 bool Validator::ValidateRecommendedField( 226 const OncValueSignature& object_signature, 227 base::DictionaryValue* result) { 228 CHECK(result != NULL); 229 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; 236 } 237 base::ListValue* recommended_list = NULL; 238 recommended_value.release()->GetAsList(&recommended_list); 239 CHECK(recommended_list); 240 241 recommended.reset(recommended_list); 242 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; 249 } 250 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; 258 } 259 260 const OncFieldSignature* field_signature = 261 GetFieldSignature(object_signature, field_name); 262 263 bool found_error = false; 264 std::string error_cause; 265 if (field_signature == NULL) { 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"; 272 } 273 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; 286 } 287 } 288 289 repaired_recommended->Append((*it)->DeepCopy()); 290 } 291 292 result->Set(::onc::kRecommended, repaired_recommended.release()); 293 return true; 294 } 295 296 namespace { 297 298 std::string JoinStringRange(const char** range_begin, 299 const char** range_end, 300 const std::string& separator) { 301 std::vector<std::string> string_vector; 302 std::copy(range_begin, range_end, std::back_inserter(string_vector)); 303 return JoinString(string_vector, separator); 304 } 305 306 } // namespace 307 308 bool Validator::FieldExistsAndHasNoValidValue( 309 const base::DictionaryValue& object, 310 const std::string& field_name, 311 const char** valid_values) { 312 std::string actual_value; 313 if (!object.GetStringWithoutPathExpansion(field_name, &actual_value)) 314 return false; 315 316 const char** it = valid_values; 317 for (; *it != NULL; ++it) { 318 if (actual_value == *it) 319 return false; 320 } 321 error_or_warning_found_ = true; 322 std::string valid_values_str = 323 "[" + JoinStringRange(valid_values, it, ", ") + "]"; 324 path_.push_back(field_name); 325 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value << 326 "', but expected one of the values " << valid_values_str; 327 path_.pop_back(); 328 return true; 329 } 330 331 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object, 332 const std::string& field_name, 333 int lower_bound, 334 int upper_bound) { 335 int actual_value; 336 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) || 337 (lower_bound <= actual_value && actual_value <= upper_bound)) { 338 return false; 339 } 340 error_or_warning_found_ = true; 341 path_.push_back(field_name); 342 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value 343 << "', but expected a value in the range [" << lower_bound 344 << ", " << upper_bound << "] (boundaries inclusive)"; 345 path_.pop_back(); 346 return true; 347 } 348 349 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object, 350 const std::string& field_name) { 351 const base::Value* value = NULL; 352 if (!object.GetWithoutPathExpansion(field_name, &value)) 353 return false; 354 355 std::string str; 356 const base::ListValue* list = NULL; 357 if (value->GetAsString(&str)) { 358 if (!str.empty()) 359 return false; 360 } else if (value->GetAsList(&list)) { 361 if (!list->empty()) 362 return false; 363 } else { 364 NOTREACHED(); 365 return false; 366 } 367 368 error_or_warning_found_ = true; 369 path_.push_back(field_name); 370 LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a " 371 << "non-empty string."; 372 path_.pop_back(); 373 return true; 374 } 375 376 bool Validator::RequireField(const base::DictionaryValue& dict, 377 const std::string& field_name) { 378 if (dict.HasKey(field_name)) 379 return true; 380 error_or_warning_found_ = true; 381 std::string message = MessageHeader() + "The required field '" + field_name + 382 "' is missing."; 383 if (error_on_missing_field_) 384 LOG(ERROR) << message; 385 else 386 LOG(WARNING) << message; 387 return false; 388 } 389 390 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) { 391 if (cert_type == ::onc::certificate::kPattern && 392 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) { 393 error_or_warning_found_ = true; 394 LOG(ERROR) << MessageHeader() << "Client certificate patterns are " 395 << "prohibited in ONC device policies."; 396 return true; 397 } 398 return false; 399 } 400 401 bool Validator::IsGlobalNetworkConfigInUserImport( 402 const base::DictionaryValue& onc_object) { 403 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT && 404 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) { 405 error_or_warning_found_ = true; 406 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited " 407 << "in ONC user imports"; 408 return true; 409 } 410 return false; 411 } 412 413 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) { 414 using namespace ::onc::toplevel_config; 415 416 static const char* kValidTypes[] = { kUnencryptedConfiguration, 417 kEncryptedConfiguration, 418 NULL }; 419 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes)) 420 return false; 421 422 bool all_required_exist = true; 423 424 // Not part of the ONC spec yet: 425 // We don't require the type field and default to UnencryptedConfiguration. 426 std::string type = kUnencryptedConfiguration; 427 result->GetStringWithoutPathExpansion(kType, &type); 428 if (type == kUnencryptedConfiguration && 429 !result->HasKey(kNetworkConfigurations) && 430 !result->HasKey(kCertificates)) { 431 error_or_warning_found_ = true; 432 std::string message = MessageHeader() + "Neither the field '" + 433 kNetworkConfigurations + "' nor '" + kCertificates + 434 "is present, but at least one is required."; 435 if (error_on_missing_field_) 436 LOG(ERROR) << message; 437 else 438 LOG(WARNING) << message; 439 all_required_exist = false; 440 } 441 442 if (IsGlobalNetworkConfigInUserImport(*result)) 443 return false; 444 445 return !error_on_missing_field_ || all_required_exist; 446 } 447 448 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) { 449 using namespace ::onc::network_config; 450 451 static const char* kValidTypes[] = { ::onc::network_type::kEthernet, 452 ::onc::network_type::kVPN, 453 ::onc::network_type::kWiFi, 454 ::onc::network_type::kCellular, 455 NULL }; 456 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) || 457 FieldExistsAndIsEmpty(*result, kGUID)) { 458 return false; 459 } 460 461 bool all_required_exist = RequireField(*result, kGUID); 462 463 bool remove = false; 464 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 465 if (!remove) { 466 all_required_exist &= 467 RequireField(*result, kName) && RequireField(*result, kType); 468 469 std::string type; 470 result->GetStringWithoutPathExpansion(kType, &type); 471 472 // Prohibit anything but WiFi and Ethernet for device-level policy (which 473 // corresponds to shared networks). See also http://crosbug.com/28741. 474 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && 475 type != ::onc::network_type::kWiFi && 476 type != ::onc::network_type::kEthernet) { 477 error_or_warning_found_ = true; 478 LOG(ERROR) << MessageHeader() << "Networks of type '" 479 << type << "' are prohibited in ONC device policies."; 480 return false; 481 } 482 483 if (type == ::onc::network_type::kWiFi) { 484 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi); 485 } else if (type == ::onc::network_type::kEthernet) { 486 all_required_exist &= 487 RequireField(*result, ::onc::network_config::kEthernet); 488 } else if (type == ::onc::network_type::kCellular) { 489 all_required_exist &= 490 RequireField(*result, ::onc::network_config::kCellular); 491 } else if (type == ::onc::network_type::kVPN) { 492 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN); 493 } else if (!type.empty()) { 494 NOTREACHED(); 495 } 496 } 497 498 return !error_on_missing_field_ || all_required_exist; 499 } 500 501 bool Validator::ValidateEthernet(base::DictionaryValue* result) { 502 using namespace ::onc::ethernet; 503 504 static const char* kValidAuthentications[] = { kNone, k8021X, NULL }; 505 if (FieldExistsAndHasNoValidValue( 506 *result, kAuthentication, kValidAuthentications)) { 507 return false; 508 } 509 510 bool all_required_exist = true; 511 std::string auth; 512 result->GetStringWithoutPathExpansion(kAuthentication, &auth); 513 if (auth == k8021X) 514 all_required_exist &= RequireField(*result, kEAP); 515 516 return !error_on_missing_field_ || all_required_exist; 517 } 518 519 bool Validator::ValidateIPConfig(base::DictionaryValue* result) { 520 using namespace ::onc::ipconfig; 521 522 static const char* kValidTypes[] = { kIPv4, kIPv6, NULL }; 523 if (FieldExistsAndHasNoValidValue( 524 *result, ::onc::ipconfig::kType, kValidTypes)) 525 return false; 526 527 std::string type; 528 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type); 529 int lower_bound = 1; 530 // In case of missing type, choose higher upper_bound. 531 int upper_bound = (type == kIPv4) ? 32 : 128; 532 if (FieldExistsAndIsNotInRange( 533 *result, kRoutingPrefix, lower_bound, upper_bound)) { 534 return false; 535 } 536 537 bool all_required_exist = RequireField(*result, kIPAddress) && 538 RequireField(*result, kRoutingPrefix) && 539 RequireField(*result, ::onc::ipconfig::kType); 540 541 return !error_on_missing_field_ || all_required_exist; 542 } 543 544 bool Validator::ValidateWiFi(base::DictionaryValue* result) { 545 using namespace ::onc::wifi; 546 547 static const char* kValidSecurities[] = 548 { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL }; 549 if (FieldExistsAndHasNoValidValue(*result, kSecurity, kValidSecurities)) 550 return false; 551 552 bool all_required_exist = 553 RequireField(*result, kSecurity) && RequireField(*result, kSSID); 554 555 std::string security; 556 result->GetStringWithoutPathExpansion(kSecurity, &security); 557 if (security == kWEP_8021X || security == kWPA_EAP) 558 all_required_exist &= RequireField(*result, kEAP); 559 else if (security == kWEP_PSK || security == kWPA_PSK) 560 all_required_exist &= RequireField(*result, kPassphrase); 561 562 return !error_on_missing_field_ || all_required_exist; 563 } 564 565 bool Validator::ValidateVPN(base::DictionaryValue* result) { 566 using namespace ::onc::vpn; 567 568 static const char* kValidTypes[] = 569 { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL }; 570 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, kValidTypes)) 571 return false; 572 573 bool all_required_exist = RequireField(*result, ::onc::vpn::kType); 574 std::string type; 575 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type); 576 if (type == kOpenVPN) { 577 all_required_exist &= RequireField(*result, kOpenVPN); 578 } else if (type == kIPsec) { 579 all_required_exist &= RequireField(*result, kIPsec); 580 } else if (type == kTypeL2TP_IPsec) { 581 all_required_exist &= 582 RequireField(*result, kIPsec) && RequireField(*result, kL2TP); 583 } 584 585 return !error_on_missing_field_ || all_required_exist; 586 } 587 588 bool Validator::ValidateIPsec(base::DictionaryValue* result) { 589 using namespace ::onc::ipsec; 590 using namespace ::onc::certificate; 591 592 static const char* kValidAuthentications[] = { kPSK, kCert, NULL }; 593 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; 594 if (FieldExistsAndHasNoValidValue( 595 *result, kAuthenticationType, kValidAuthentications) || 596 FieldExistsAndHasNoValidValue( 597 *result, ::onc::vpn::kClientCertType, kValidCertTypes) || 598 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 599 return false; 600 } 601 602 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 603 error_or_warning_found_ = true; 604 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 605 << " and " << kServerCARef << " can be set."; 606 return false; 607 } 608 609 bool all_required_exist = RequireField(*result, kAuthenticationType) && 610 RequireField(*result, kIKEVersion); 611 std::string auth; 612 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth); 613 bool has_server_ca_cert = 614 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef); 615 if (auth == kCert) { 616 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertType); 617 if (!has_server_ca_cert) { 618 all_required_exist = false; 619 error_or_warning_found_ = true; 620 std::string message = MessageHeader() + "The required field '" + 621 kServerCARefs + "' is missing."; 622 if (error_on_missing_field_) 623 LOG(ERROR) << message; 624 else 625 LOG(WARNING) << message; 626 } 627 } else if (has_server_ca_cert) { 628 error_or_warning_found_ = true; 629 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef 630 << ") can only be set if " << kAuthenticationType 631 << " is set to " << kCert << "."; 632 return false; 633 } 634 635 std::string cert_type; 636 result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType, 637 &cert_type); 638 639 if (IsCertPatternInDevicePolicy(cert_type)) 640 return false; 641 642 if (cert_type == kPattern) 643 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern); 644 else if (cert_type == kRef) 645 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef); 646 647 return !error_on_missing_field_ || all_required_exist; 648 } 649 650 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) { 651 using namespace ::onc::openvpn; 652 using namespace ::onc::certificate; 653 654 static const char* kValidAuthRetryValues[] = 655 { ::onc::openvpn::kNone, kInteract, kNoInteract, NULL }; 656 static const char* kValidCertTypes[] = 657 { ::onc::certificate::kNone, kRef, kPattern, NULL }; 658 static const char* kValidCertTlsValues[] = 659 { ::onc::openvpn::kNone, ::onc::openvpn::kServer, NULL }; 660 661 if (FieldExistsAndHasNoValidValue( 662 *result, kAuthRetry, kValidAuthRetryValues) || 663 FieldExistsAndHasNoValidValue( 664 *result, ::onc::vpn::kClientCertType, kValidCertTypes) || 665 FieldExistsAndHasNoValidValue( 666 *result, kRemoteCertTLS, kValidCertTlsValues) || 667 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 668 return false; 669 } 670 671 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 672 error_or_warning_found_ = true; 673 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 674 << " and " << kServerCARef << " can be set."; 675 return false; 676 } 677 678 bool all_required_exist = RequireField(*result, ::onc::vpn::kClientCertType); 679 std::string cert_type; 680 result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType, 681 &cert_type); 682 683 if (IsCertPatternInDevicePolicy(cert_type)) 684 return false; 685 686 if (cert_type == kPattern) 687 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern); 688 else if (cert_type == kRef) 689 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef); 690 691 return !error_on_missing_field_ || all_required_exist; 692 } 693 694 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) { 695 using namespace ::onc::verify_x509; 696 697 static const char* kValidTypeValues[] = 698 {types::kName, types::kNamePrefix, types::kSubject, NULL}; 699 700 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypeValues)) 701 return false; 702 703 bool all_required_exist = RequireField(*result, kName); 704 705 return !error_on_missing_field_ || all_required_exist; 706 } 707 708 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) { 709 using namespace ::onc::certificate; 710 711 bool all_required_exist = true; 712 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) && 713 !result->HasKey(kIssuerCARef)) { 714 error_or_warning_found_ = true; 715 all_required_exist = false; 716 std::string message = MessageHeader() + "None of the fields '" + kSubject + 717 "', '" + kIssuer + "', and '" + kIssuerCARef + 718 "' is present, but at least one is required."; 719 if (error_on_missing_field_) 720 LOG(ERROR) << message; 721 else 722 LOG(WARNING) << message; 723 } 724 725 return !error_on_missing_field_ || all_required_exist; 726 } 727 728 bool Validator::ValidateProxySettings(base::DictionaryValue* result) { 729 using namespace ::onc::proxy; 730 731 static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL }; 732 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, kValidTypes)) 733 return false; 734 735 bool all_required_exist = RequireField(*result, ::onc::proxy::kType); 736 std::string type; 737 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type); 738 if (type == kManual) 739 all_required_exist &= RequireField(*result, kManual); 740 else if (type == kPAC) 741 all_required_exist &= RequireField(*result, kPAC); 742 743 return !error_on_missing_field_ || all_required_exist; 744 } 745 746 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) { 747 using namespace ::onc::proxy; 748 749 bool all_required_exist = 750 RequireField(*result, kHost) && RequireField(*result, kPort); 751 752 return !error_on_missing_field_ || all_required_exist; 753 } 754 755 bool Validator::ValidateEAP(base::DictionaryValue* result) { 756 using namespace ::onc::eap; 757 using namespace ::onc::certificate; 758 759 static const char* kValidInnerValues[] = 760 { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL }; 761 static const char* kValidOuterValues[] = 762 { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA, 763 NULL }; 764 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; 765 766 if (FieldExistsAndHasNoValidValue(*result, kInner, kValidInnerValues) || 767 FieldExistsAndHasNoValidValue(*result, kOuter, kValidOuterValues) || 768 FieldExistsAndHasNoValidValue( 769 *result, kClientCertType, kValidCertTypes) || 770 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 771 return false; 772 } 773 774 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 775 error_or_warning_found_ = true; 776 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 777 << " and " << kServerCARef << " can be set."; 778 return false; 779 } 780 781 bool all_required_exist = RequireField(*result, kOuter); 782 std::string cert_type; 783 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); 784 785 if (IsCertPatternInDevicePolicy(cert_type)) 786 return false; 787 788 if (cert_type == kPattern) 789 all_required_exist &= RequireField(*result, kClientCertPattern); 790 else if (cert_type == kRef) 791 all_required_exist &= RequireField(*result, kClientCertRef); 792 793 return !error_on_missing_field_ || all_required_exist; 794 } 795 796 bool Validator::ValidateCertificate(base::DictionaryValue* result) { 797 using namespace ::onc::certificate; 798 799 static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL }; 800 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) || 801 FieldExistsAndIsEmpty(*result, kGUID)) { 802 return false; 803 } 804 805 std::string type; 806 result->GetStringWithoutPathExpansion(kType, &type); 807 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && 808 (type == kServer || type == kAuthority)) { 809 error_or_warning_found_ = true; 810 LOG(ERROR) << MessageHeader() << "Server and authority certificates are " 811 << "prohibited in ONC device policies."; 812 return false; 813 } 814 815 bool all_required_exist = RequireField(*result, kGUID); 816 817 bool remove = false; 818 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 819 if (!remove) { 820 all_required_exist &= RequireField(*result, kType); 821 822 if (type == kClient) 823 all_required_exist &= RequireField(*result, kPKCS12); 824 else if (type == kServer || type == kAuthority) 825 all_required_exist &= RequireField(*result, kX509); 826 } 827 828 return !error_on_missing_field_ || all_required_exist; 829 } 830 831 std::string Validator::MessageHeader() { 832 std::string path = path_.empty() ? "toplevel" : JoinString(path_, "."); 833 std::string message = "At " + path + ": "; 834 return message; 835 } 836 837 } // namespace onc 838 } // namespace chromeos 839