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::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict, 391 const std::string& key_guid, 392 std::set<std::string> *guids) { 393 std::string guid; 394 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) { 395 if (guids->count(guid) != 0) { 396 error_or_warning_found_ = true; 397 LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << "."; 398 return false; 399 } 400 guids->insert(guid); 401 } 402 return true; 403 } 404 405 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) { 406 if (cert_type == ::onc::certificate::kPattern && 407 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) { 408 error_or_warning_found_ = true; 409 LOG(ERROR) << MessageHeader() << "Client certificate patterns are " 410 << "prohibited in ONC device policies."; 411 return true; 412 } 413 return false; 414 } 415 416 bool Validator::IsGlobalNetworkConfigInUserImport( 417 const base::DictionaryValue& onc_object) { 418 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT && 419 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) { 420 error_or_warning_found_ = true; 421 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited " 422 << "in ONC user imports"; 423 return true; 424 } 425 return false; 426 } 427 428 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) { 429 using namespace ::onc::toplevel_config; 430 431 static const char* kValidTypes[] = { kUnencryptedConfiguration, 432 kEncryptedConfiguration, 433 NULL }; 434 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes)) 435 return false; 436 437 // Not part of the ONC spec: 438 // - We don't require the type field (we assume that it's an 439 // UnencryptedConfiguration then). 440 // - We don't require specific toplevel objects to be present (e.g. at least 441 // one of NetworkConfiguration or Certificates). 442 443 if (IsGlobalNetworkConfigInUserImport(*result)) 444 return false; 445 446 return true; 447 } 448 449 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) { 450 using namespace ::onc::network_config; 451 452 static const char* kValidTypes[] = { ::onc::network_type::kEthernet, 453 ::onc::network_type::kVPN, 454 ::onc::network_type::kWiFi, 455 ::onc::network_type::kCellular, 456 NULL }; 457 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) || 458 FieldExistsAndIsEmpty(*result, kGUID)) { 459 return false; 460 } 461 462 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_)) 463 return false; 464 465 bool all_required_exist = RequireField(*result, kGUID); 466 467 bool remove = false; 468 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 469 if (!remove) { 470 all_required_exist &= 471 RequireField(*result, kName) && RequireField(*result, kType); 472 473 std::string type; 474 result->GetStringWithoutPathExpansion(kType, &type); 475 476 // Prohibit anything but WiFi and Ethernet for device-level policy (which 477 // corresponds to shared networks). See also http://crosbug.com/28741. 478 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && 479 type != ::onc::network_type::kWiFi && 480 type != ::onc::network_type::kEthernet) { 481 error_or_warning_found_ = true; 482 LOG(ERROR) << MessageHeader() << "Networks of type '" 483 << type << "' are prohibited in ONC device policies."; 484 return false; 485 } 486 487 if (type == ::onc::network_type::kWiFi) { 488 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi); 489 } else if (type == ::onc::network_type::kEthernet) { 490 all_required_exist &= 491 RequireField(*result, ::onc::network_config::kEthernet); 492 } else if (type == ::onc::network_type::kCellular) { 493 all_required_exist &= 494 RequireField(*result, ::onc::network_config::kCellular); 495 } else if (type == ::onc::network_type::kVPN) { 496 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN); 497 } else if (!type.empty()) { 498 NOTREACHED(); 499 } 500 } 501 502 return !error_on_missing_field_ || all_required_exist; 503 } 504 505 bool Validator::ValidateEthernet(base::DictionaryValue* result) { 506 using namespace ::onc::ethernet; 507 508 static const char* kValidAuthentications[] = { kNone, k8021X, NULL }; 509 if (FieldExistsAndHasNoValidValue( 510 *result, kAuthentication, kValidAuthentications)) { 511 return false; 512 } 513 514 bool all_required_exist = true; 515 std::string auth; 516 result->GetStringWithoutPathExpansion(kAuthentication, &auth); 517 if (auth == k8021X) 518 all_required_exist &= RequireField(*result, kEAP); 519 520 return !error_on_missing_field_ || all_required_exist; 521 } 522 523 bool Validator::ValidateIPConfig(base::DictionaryValue* result) { 524 using namespace ::onc::ipconfig; 525 526 static const char* kValidTypes[] = { kIPv4, kIPv6, NULL }; 527 if (FieldExistsAndHasNoValidValue( 528 *result, ::onc::ipconfig::kType, kValidTypes)) 529 return false; 530 531 std::string type; 532 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type); 533 int lower_bound = 1; 534 // In case of missing type, choose higher upper_bound. 535 int upper_bound = (type == kIPv4) ? 32 : 128; 536 if (FieldExistsAndIsNotInRange( 537 *result, kRoutingPrefix, lower_bound, upper_bound)) { 538 return false; 539 } 540 541 bool all_required_exist = RequireField(*result, kIPAddress) && 542 RequireField(*result, kRoutingPrefix) && 543 RequireField(*result, ::onc::ipconfig::kType); 544 545 return !error_on_missing_field_ || all_required_exist; 546 } 547 548 bool Validator::ValidateWiFi(base::DictionaryValue* result) { 549 using namespace ::onc::wifi; 550 551 static const char* kValidSecurities[] = 552 { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL }; 553 if (FieldExistsAndHasNoValidValue(*result, kSecurity, kValidSecurities)) 554 return false; 555 556 bool all_required_exist = 557 RequireField(*result, kSecurity) && RequireField(*result, kSSID); 558 559 std::string security; 560 result->GetStringWithoutPathExpansion(kSecurity, &security); 561 if (security == kWEP_8021X || security == kWPA_EAP) 562 all_required_exist &= RequireField(*result, kEAP); 563 else if (security == kWEP_PSK || security == kWPA_PSK) 564 all_required_exist &= RequireField(*result, kPassphrase); 565 566 return !error_on_missing_field_ || all_required_exist; 567 } 568 569 bool Validator::ValidateVPN(base::DictionaryValue* result) { 570 using namespace ::onc::vpn; 571 572 static const char* kValidTypes[] = 573 { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL }; 574 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, kValidTypes)) 575 return false; 576 577 bool all_required_exist = RequireField(*result, ::onc::vpn::kType); 578 std::string type; 579 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type); 580 if (type == kOpenVPN) { 581 all_required_exist &= RequireField(*result, kOpenVPN); 582 } else if (type == kIPsec) { 583 all_required_exist &= RequireField(*result, kIPsec); 584 } else if (type == kTypeL2TP_IPsec) { 585 all_required_exist &= 586 RequireField(*result, kIPsec) && RequireField(*result, kL2TP); 587 } 588 589 return !error_on_missing_field_ || all_required_exist; 590 } 591 592 bool Validator::ValidateIPsec(base::DictionaryValue* result) { 593 using namespace ::onc::ipsec; 594 using namespace ::onc::certificate; 595 596 static const char* kValidAuthentications[] = { kPSK, kCert, NULL }; 597 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; 598 if (FieldExistsAndHasNoValidValue( 599 *result, kAuthenticationType, kValidAuthentications) || 600 FieldExistsAndHasNoValidValue( 601 *result, ::onc::vpn::kClientCertType, kValidCertTypes) || 602 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 603 return false; 604 } 605 606 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 607 error_or_warning_found_ = true; 608 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 609 << " and " << kServerCARef << " can be set."; 610 return false; 611 } 612 613 bool all_required_exist = RequireField(*result, kAuthenticationType) && 614 RequireField(*result, kIKEVersion); 615 std::string auth; 616 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth); 617 bool has_server_ca_cert = 618 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef); 619 if (auth == kCert) { 620 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertType); 621 if (!has_server_ca_cert) { 622 all_required_exist = false; 623 error_or_warning_found_ = true; 624 std::string message = MessageHeader() + "The required field '" + 625 kServerCARefs + "' is missing."; 626 if (error_on_missing_field_) 627 LOG(ERROR) << message; 628 else 629 LOG(WARNING) << message; 630 } 631 } else if (has_server_ca_cert) { 632 error_or_warning_found_ = true; 633 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef 634 << ") can only be set if " << kAuthenticationType 635 << " is set to " << kCert << "."; 636 return false; 637 } 638 639 std::string cert_type; 640 result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType, 641 &cert_type); 642 643 if (IsCertPatternInDevicePolicy(cert_type)) 644 return false; 645 646 if (cert_type == kPattern) 647 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern); 648 else if (cert_type == kRef) 649 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef); 650 651 return !error_on_missing_field_ || all_required_exist; 652 } 653 654 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) { 655 using namespace ::onc::openvpn; 656 using namespace ::onc::certificate; 657 658 static const char* kValidAuthRetryValues[] = 659 { ::onc::openvpn::kNone, kInteract, kNoInteract, NULL }; 660 static const char* kValidCertTypes[] = 661 { ::onc::certificate::kNone, kRef, kPattern, NULL }; 662 static const char* kValidCertTlsValues[] = 663 { ::onc::openvpn::kNone, ::onc::openvpn::kServer, NULL }; 664 665 if (FieldExistsAndHasNoValidValue( 666 *result, kAuthRetry, kValidAuthRetryValues) || 667 FieldExistsAndHasNoValidValue( 668 *result, ::onc::vpn::kClientCertType, kValidCertTypes) || 669 FieldExistsAndHasNoValidValue( 670 *result, kRemoteCertTLS, kValidCertTlsValues) || 671 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 672 return false; 673 } 674 675 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 676 error_or_warning_found_ = true; 677 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 678 << " and " << kServerCARef << " can be set."; 679 return false; 680 } 681 682 bool all_required_exist = RequireField(*result, ::onc::vpn::kClientCertType); 683 std::string cert_type; 684 result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType, 685 &cert_type); 686 687 if (IsCertPatternInDevicePolicy(cert_type)) 688 return false; 689 690 if (cert_type == kPattern) 691 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern); 692 else if (cert_type == kRef) 693 all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef); 694 695 return !error_on_missing_field_ || all_required_exist; 696 } 697 698 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) { 699 using namespace ::onc::verify_x509; 700 701 static const char* kValidTypeValues[] = 702 {types::kName, types::kNamePrefix, types::kSubject, NULL}; 703 704 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypeValues)) 705 return false; 706 707 bool all_required_exist = RequireField(*result, kName); 708 709 return !error_on_missing_field_ || all_required_exist; 710 } 711 712 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) { 713 using namespace ::onc::certificate; 714 715 bool all_required_exist = true; 716 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) && 717 !result->HasKey(kIssuerCARef)) { 718 error_or_warning_found_ = true; 719 all_required_exist = false; 720 std::string message = MessageHeader() + "None of the fields '" + kSubject + 721 "', '" + kIssuer + "', and '" + kIssuerCARef + 722 "' is present, but at least one is required."; 723 if (error_on_missing_field_) 724 LOG(ERROR) << message; 725 else 726 LOG(WARNING) << message; 727 } 728 729 return !error_on_missing_field_ || all_required_exist; 730 } 731 732 bool Validator::ValidateProxySettings(base::DictionaryValue* result) { 733 using namespace ::onc::proxy; 734 735 static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL }; 736 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, kValidTypes)) 737 return false; 738 739 bool all_required_exist = RequireField(*result, ::onc::proxy::kType); 740 std::string type; 741 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type); 742 if (type == kManual) 743 all_required_exist &= RequireField(*result, kManual); 744 else if (type == kPAC) 745 all_required_exist &= RequireField(*result, kPAC); 746 747 return !error_on_missing_field_ || all_required_exist; 748 } 749 750 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) { 751 using namespace ::onc::proxy; 752 753 bool all_required_exist = 754 RequireField(*result, kHost) && RequireField(*result, kPort); 755 756 return !error_on_missing_field_ || all_required_exist; 757 } 758 759 bool Validator::ValidateEAP(base::DictionaryValue* result) { 760 using namespace ::onc::eap; 761 using namespace ::onc::certificate; 762 763 static const char* kValidInnerValues[] = 764 { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL }; 765 static const char* kValidOuterValues[] = 766 { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA, 767 NULL }; 768 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; 769 770 if (FieldExistsAndHasNoValidValue(*result, kInner, kValidInnerValues) || 771 FieldExistsAndHasNoValidValue(*result, kOuter, kValidOuterValues) || 772 FieldExistsAndHasNoValidValue( 773 *result, kClientCertType, kValidCertTypes) || 774 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 775 return false; 776 } 777 778 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 779 error_or_warning_found_ = true; 780 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 781 << " and " << kServerCARef << " can be set."; 782 return false; 783 } 784 785 bool all_required_exist = RequireField(*result, kOuter); 786 std::string cert_type; 787 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); 788 789 if (IsCertPatternInDevicePolicy(cert_type)) 790 return false; 791 792 if (cert_type == kPattern) 793 all_required_exist &= RequireField(*result, kClientCertPattern); 794 else if (cert_type == kRef) 795 all_required_exist &= RequireField(*result, kClientCertRef); 796 797 return !error_on_missing_field_ || all_required_exist; 798 } 799 800 bool Validator::ValidateCertificate(base::DictionaryValue* result) { 801 using namespace ::onc::certificate; 802 803 static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL }; 804 if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) || 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 838 std::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