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 template <typename T, size_t N> 24 std::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/. 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]; 35 } 36 37 } // namespace 38 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) {} 48 49 Validator::~Validator() {} 50 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; 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 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>(); 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 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); 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 &signature == &kSavedIPConfigSignature || 114 &signature == &kStaticIPConfigSignature) { 115 valid = ValidateIPConfig(repaired.get()); 116 } else if (&signature == &kWiFiSignature) { 117 valid = ValidateWiFi(repaired.get()); 118 } else if (&signature == &kVPNSignature) { 119 valid = ValidateVPN(repaired.get()); 120 } else if (&signature == &kIPsecSignature) { 121 valid = ValidateIPsec(repaired.get()); 122 } else if (&signature == &kOpenVPNSignature) { 123 valid = ValidateOpenVPN(repaired.get()); 124 } else if (&signature == &kVerifyX509Signature) { 125 valid = ValidateVerifyX509(repaired.get()); 126 } else if (&signature == &kCertificatePatternSignature) { 127 valid = ValidateCertificatePattern(repaired.get()); 128 } else if (&signature == &kProxySettingsSignature) { 129 valid = ValidateProxySettings(repaired.get()); 130 } else if (&signature == &kProxyLocationSignature) { 131 valid = ValidateProxyLocation(repaired.get()); 132 } else if (&signature == &kEAPSignature) { 133 valid = ValidateEAP(repaired.get()); 134 } else if (&signature == &kCertificateSignature) { 135 valid = ValidateCertificate(repaired.get()); 136 } 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); 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) { 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 bool Validator::ValidateClientCertFields(bool allow_cert_type_none, 297 base::DictionaryValue* result) { 298 using namespace ::onc::client_cert; 299 const char* const kValidCertTypes[] = {kRef, kPattern}; 300 std::vector<const char*> valid_cert_types(toVector(kValidCertTypes)); 301 if (allow_cert_type_none) 302 valid_cert_types.push_back(kClientCertTypeNone); 303 if (FieldExistsAndHasNoValidValue(*result, kClientCertType, valid_cert_types)) 304 return false; 305 306 std::string cert_type; 307 result->GetStringWithoutPathExpansion(kClientCertType, &cert_type); 308 309 if (IsCertPatternInDevicePolicy(cert_type)) 310 return false; 311 312 bool all_required_exist = true; 313 314 if (cert_type == kPattern) 315 all_required_exist &= RequireField(*result, kClientCertPattern); 316 else if (cert_type == kRef) 317 all_required_exist &= RequireField(*result, kClientCertRef); 318 319 return !error_on_missing_field_ || all_required_exist; 320 } 321 322 namespace { 323 324 std::string JoinStringRange(const std::vector<const char*>& strings, 325 const std::string& separator) { 326 std::vector<std::string> string_vector; 327 std::copy(strings.begin(), strings.end(), std::back_inserter(string_vector)); 328 return JoinString(string_vector, separator); 329 } 330 331 } // namespace 332 333 bool Validator::FieldExistsAndHasNoValidValue( 334 const base::DictionaryValue& object, 335 const std::string& field_name, 336 const std::vector<const char*>& valid_values) { 337 std::string actual_value; 338 if (!object.GetStringWithoutPathExpansion(field_name, &actual_value)) 339 return false; 340 341 for (std::vector<const char*>::const_iterator it = valid_values.begin(); 342 it != valid_values.end(); 343 ++it) { 344 if (actual_value == *it) 345 return false; 346 } 347 error_or_warning_found_ = true; 348 std::string valid_values_str = 349 "[" + JoinStringRange(valid_values, ", ") + "]"; 350 path_.push_back(field_name); 351 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value << 352 "', but expected one of the values " << valid_values_str; 353 path_.pop_back(); 354 return true; 355 } 356 357 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object, 358 const std::string& field_name, 359 int lower_bound, 360 int upper_bound) { 361 int actual_value; 362 if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) || 363 (lower_bound <= actual_value && actual_value <= upper_bound)) { 364 return false; 365 } 366 error_or_warning_found_ = true; 367 path_.push_back(field_name); 368 LOG(ERROR) << MessageHeader() << "Found value '" << actual_value 369 << "', but expected a value in the range [" << lower_bound 370 << ", " << upper_bound << "] (boundaries inclusive)"; 371 path_.pop_back(); 372 return true; 373 } 374 375 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object, 376 const std::string& field_name) { 377 const base::Value* value = NULL; 378 if (!object.GetWithoutPathExpansion(field_name, &value)) 379 return false; 380 381 std::string str; 382 const base::ListValue* list = NULL; 383 if (value->GetAsString(&str)) { 384 if (!str.empty()) 385 return false; 386 } else if (value->GetAsList(&list)) { 387 if (!list->empty()) 388 return false; 389 } else { 390 NOTREACHED(); 391 return false; 392 } 393 394 error_or_warning_found_ = true; 395 path_.push_back(field_name); 396 LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a " 397 << "non-empty string."; 398 path_.pop_back(); 399 return true; 400 } 401 402 bool Validator::RequireField(const base::DictionaryValue& dict, 403 const std::string& field_name) { 404 if (dict.HasKey(field_name)) 405 return true; 406 error_or_warning_found_ = true; 407 std::string message = MessageHeader() + "The required field '" + field_name + 408 "' is missing."; 409 if (error_on_missing_field_) 410 LOG(ERROR) << message; 411 else 412 LOG(WARNING) << message; 413 return false; 414 } 415 416 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict, 417 const std::string& key_guid, 418 std::set<std::string> *guids) { 419 std::string guid; 420 if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) { 421 if (guids->count(guid) != 0) { 422 error_or_warning_found_ = true; 423 LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << "."; 424 return false; 425 } 426 guids->insert(guid); 427 } 428 return true; 429 } 430 431 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) { 432 if (cert_type == ::onc::client_cert::kPattern && 433 onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) { 434 error_or_warning_found_ = true; 435 LOG(ERROR) << MessageHeader() << "Client certificate patterns are " 436 << "prohibited in ONC device policies."; 437 return true; 438 } 439 return false; 440 } 441 442 bool Validator::IsGlobalNetworkConfigInUserImport( 443 const base::DictionaryValue& onc_object) { 444 if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT && 445 onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) { 446 error_or_warning_found_ = true; 447 LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited " 448 << "in ONC user imports"; 449 return true; 450 } 451 return false; 452 } 453 454 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) { 455 using namespace ::onc::toplevel_config; 456 457 const char* const kValidTypes[] = {kUnencryptedConfiguration, 458 kEncryptedConfiguration}; 459 const std::vector<const char*> valid_types(toVector(kValidTypes)); 460 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types)) 461 return false; 462 463 if (IsGlobalNetworkConfigInUserImport(*result)) 464 return false; 465 466 return true; 467 } 468 469 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) { 470 using namespace ::onc::network_config; 471 472 const char* const kValidTypes[] = { 473 ::onc::network_type::kEthernet, ::onc::network_type::kVPN, 474 ::onc::network_type::kWiFi, ::onc::network_type::kCellular}; 475 const std::vector<const char*> valid_types(toVector(kValidTypes)); 476 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) || 477 FieldExistsAndIsEmpty(*result, kGUID)) { 478 return false; 479 } 480 481 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_)) 482 return false; 483 484 bool all_required_exist = RequireField(*result, kGUID); 485 486 bool remove = false; 487 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 488 if (!remove) { 489 all_required_exist &= 490 RequireField(*result, kName) && RequireField(*result, kType); 491 492 std::string type; 493 result->GetStringWithoutPathExpansion(kType, &type); 494 495 // Prohibit anything but WiFi and Ethernet for device-level policy (which 496 // corresponds to shared networks). See also http://crosbug.com/28741. 497 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && 498 type != ::onc::network_type::kWiFi && 499 type != ::onc::network_type::kEthernet) { 500 error_or_warning_found_ = true; 501 LOG(ERROR) << MessageHeader() << "Networks of type '" 502 << type << "' are prohibited in ONC device policies."; 503 return false; 504 } 505 506 if (type == ::onc::network_type::kWiFi) { 507 all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi); 508 } else if (type == ::onc::network_type::kEthernet) { 509 all_required_exist &= 510 RequireField(*result, ::onc::network_config::kEthernet); 511 } else if (type == ::onc::network_type::kCellular) { 512 all_required_exist &= 513 RequireField(*result, ::onc::network_config::kCellular); 514 } else if (type == ::onc::network_type::kVPN) { 515 all_required_exist &= RequireField(*result, ::onc::network_config::kVPN); 516 } else if (!type.empty()) { 517 NOTREACHED(); 518 } 519 } 520 521 return !error_on_missing_field_ || all_required_exist; 522 } 523 524 bool Validator::ValidateEthernet(base::DictionaryValue* result) { 525 using namespace ::onc::ethernet; 526 527 const char* const kValidAuthentications[] = {kAuthenticationNone, k8021X}; 528 const std::vector<const char*> valid_authentications( 529 toVector(kValidAuthentications)); 530 if (FieldExistsAndHasNoValidValue( 531 *result, kAuthentication, valid_authentications)) { 532 return false; 533 } 534 535 bool all_required_exist = true; 536 std::string auth; 537 result->GetStringWithoutPathExpansion(kAuthentication, &auth); 538 if (auth == k8021X) 539 all_required_exist &= RequireField(*result, kEAP); 540 541 return !error_on_missing_field_ || all_required_exist; 542 } 543 544 bool Validator::ValidateIPConfig(base::DictionaryValue* result) { 545 using namespace ::onc::ipconfig; 546 547 const char* const kValidTypes[] = {kIPv4, kIPv6}; 548 const std::vector<const char*> valid_types(toVector(kValidTypes)); 549 if (FieldExistsAndHasNoValidValue( 550 *result, ::onc::ipconfig::kType, valid_types)) 551 return false; 552 553 std::string type; 554 result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type); 555 int lower_bound = 1; 556 // In case of missing type, choose higher upper_bound. 557 int upper_bound = (type == kIPv4) ? 32 : 128; 558 if (FieldExistsAndIsNotInRange( 559 *result, kRoutingPrefix, lower_bound, upper_bound)) { 560 return false; 561 } 562 563 bool all_required_exist = RequireField(*result, kIPAddress) && 564 RequireField(*result, kRoutingPrefix) && 565 RequireField(*result, ::onc::ipconfig::kType); 566 567 return !error_on_missing_field_ || all_required_exist; 568 } 569 570 bool Validator::ValidateWiFi(base::DictionaryValue* result) { 571 using namespace ::onc::wifi; 572 573 const char* const kValidSecurities[] = {kSecurityNone, kWEP_PSK, kWEP_8021X, 574 kWPA_PSK, kWPA_EAP}; 575 const std::vector<const char*> valid_securities(toVector(kValidSecurities)); 576 if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities)) 577 return false; 578 579 bool all_required_exist = 580 RequireField(*result, kSecurity) && RequireField(*result, kSSID); 581 582 std::string security; 583 result->GetStringWithoutPathExpansion(kSecurity, &security); 584 if (security == kWEP_8021X || security == kWPA_EAP) 585 all_required_exist &= RequireField(*result, kEAP); 586 else if (security == kWEP_PSK || security == kWPA_PSK) 587 all_required_exist &= RequireField(*result, kPassphrase); 588 589 return !error_on_missing_field_ || all_required_exist; 590 } 591 592 bool Validator::ValidateVPN(base::DictionaryValue* result) { 593 using namespace ::onc::vpn; 594 595 const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN}; 596 const std::vector<const char*> valid_types(toVector(kValidTypes)); 597 if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types)) 598 return false; 599 600 bool all_required_exist = RequireField(*result, ::onc::vpn::kType); 601 std::string type; 602 result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type); 603 if (type == kOpenVPN) { 604 all_required_exist &= RequireField(*result, kOpenVPN); 605 } else if (type == kIPsec) { 606 all_required_exist &= RequireField(*result, kIPsec); 607 } else if (type == kTypeL2TP_IPsec) { 608 all_required_exist &= 609 RequireField(*result, kIPsec) && RequireField(*result, kL2TP); 610 } 611 612 return !error_on_missing_field_ || all_required_exist; 613 } 614 615 bool Validator::ValidateIPsec(base::DictionaryValue* result) { 616 using namespace ::onc::ipsec; 617 618 const char* const kValidAuthentications[] = {kPSK, kCert}; 619 const std::vector<const char*> valid_authentications( 620 toVector(kValidAuthentications)); 621 if (FieldExistsAndHasNoValidValue( 622 *result, kAuthenticationType, valid_authentications) || 623 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 624 return false; 625 } 626 627 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 628 error_or_warning_found_ = true; 629 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 630 << " and " << kServerCARef << " can be set."; 631 return false; 632 } 633 634 if (!ValidateClientCertFields(false, // don't allow ClientCertType None 635 result)) { 636 return false; 637 } 638 639 bool all_required_exist = RequireField(*result, kAuthenticationType) && 640 RequireField(*result, kIKEVersion); 641 std::string auth; 642 result->GetStringWithoutPathExpansion(kAuthenticationType, &auth); 643 bool has_server_ca_cert = 644 result->HasKey(kServerCARefs) || result->HasKey(kServerCARef); 645 if (auth == kCert) { 646 all_required_exist &= 647 RequireField(*result, ::onc::client_cert::kClientCertType); 648 if (!has_server_ca_cert) { 649 all_required_exist = false; 650 error_or_warning_found_ = true; 651 std::string message = MessageHeader() + "The required field '" + 652 kServerCARefs + "' is missing."; 653 if (error_on_missing_field_) 654 LOG(ERROR) << message; 655 else 656 LOG(WARNING) << message; 657 } 658 } else if (has_server_ca_cert) { 659 error_or_warning_found_ = true; 660 LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef 661 << ") can only be set if " << kAuthenticationType 662 << " is set to " << kCert << "."; 663 return false; 664 } 665 666 return !error_on_missing_field_ || all_required_exist; 667 } 668 669 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) { 670 using namespace ::onc::openvpn; 671 672 const char* const kValidAuthRetryValues[] = {::onc::openvpn::kNone, kInteract, 673 kNoInteract}; 674 const std::vector<const char*> valid_auth_retry_values( 675 toVector(kValidAuthRetryValues)); 676 const char* const kValidCertTlsValues[] = {::onc::openvpn::kNone, 677 ::onc::openvpn::kServer}; 678 const std::vector<const char*> valid_cert_tls_values( 679 toVector(kValidCertTlsValues)); 680 681 if (FieldExistsAndHasNoValidValue( 682 *result, kAuthRetry, valid_auth_retry_values) || 683 FieldExistsAndHasNoValidValue( 684 *result, kRemoteCertTLS, valid_cert_tls_values) || 685 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 686 return false; 687 } 688 689 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 690 error_or_warning_found_ = true; 691 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 692 << " and " << kServerCARef << " can be set."; 693 return false; 694 } 695 696 if (!ValidateClientCertFields(true /* allow ClientCertType None */, result)) 697 return false; 698 699 bool all_required_exist = 700 RequireField(*result, ::onc::client_cert::kClientCertType); 701 702 return !error_on_missing_field_ || all_required_exist; 703 } 704 705 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) { 706 using namespace ::onc::verify_x509; 707 708 const char* const kValidTypes[] = {types::kName, types::kNamePrefix, 709 types::kSubject}; 710 const std::vector<const char*> valid_types(toVector(kValidTypes)); 711 712 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types)) 713 return false; 714 715 bool all_required_exist = RequireField(*result, kName); 716 717 return !error_on_missing_field_ || all_required_exist; 718 } 719 720 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) { 721 using namespace ::onc::client_cert; 722 723 bool all_required_exist = true; 724 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) && 725 !result->HasKey(kIssuerCARef)) { 726 error_or_warning_found_ = true; 727 all_required_exist = false; 728 std::string message = MessageHeader() + "None of the fields '" + kSubject + 729 "', '" + kIssuer + "', and '" + kIssuerCARef + 730 "' is present, but at least one is required."; 731 if (error_on_missing_field_) 732 LOG(ERROR) << message; 733 else 734 LOG(WARNING) << message; 735 } 736 737 return !error_on_missing_field_ || all_required_exist; 738 } 739 740 bool Validator::ValidateProxySettings(base::DictionaryValue* result) { 741 using namespace ::onc::proxy; 742 743 const char* const kValidTypes[] = {kDirect, kManual, kPAC, kWPAD}; 744 const std::vector<const char*> valid_types(toVector(kValidTypes)); 745 if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types)) 746 return false; 747 748 bool all_required_exist = RequireField(*result, ::onc::proxy::kType); 749 std::string type; 750 result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type); 751 if (type == kManual) 752 all_required_exist &= RequireField(*result, kManual); 753 else if (type == kPAC) 754 all_required_exist &= RequireField(*result, kPAC); 755 756 return !error_on_missing_field_ || all_required_exist; 757 } 758 759 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) { 760 using namespace ::onc::proxy; 761 762 bool all_required_exist = 763 RequireField(*result, kHost) && RequireField(*result, kPort); 764 765 return !error_on_missing_field_ || all_required_exist; 766 } 767 768 bool Validator::ValidateEAP(base::DictionaryValue* result) { 769 using namespace ::onc::eap; 770 771 const char* const kValidInnerValues[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP}; 772 const std::vector<const char*> valid_inner_values( 773 toVector(kValidInnerValues)); 774 const char* const kValidOuterValues[] = { 775 kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA}; 776 const std::vector<const char*> valid_outer_values( 777 toVector(kValidOuterValues)); 778 779 if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) || 780 FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) || 781 FieldExistsAndIsEmpty(*result, kServerCARefs)) { 782 return false; 783 } 784 785 if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) { 786 error_or_warning_found_ = true; 787 LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs 788 << " and " << kServerCARef << " can be set."; 789 return false; 790 } 791 792 if (!ValidateClientCertFields(false, // don't allow ClientCertType None 793 result)) { 794 return false; 795 } 796 797 bool all_required_exist = RequireField(*result, kOuter); 798 799 return !error_on_missing_field_ || all_required_exist; 800 } 801 802 bool Validator::ValidateCertificate(base::DictionaryValue* result) { 803 using namespace ::onc::certificate; 804 805 const char* const kValidTypes[] = {kClient, kServer, kAuthority}; 806 const std::vector<const char*> valid_types(toVector(kValidTypes)); 807 if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) || 808 FieldExistsAndIsEmpty(*result, kGUID)) { 809 return false; 810 } 811 812 std::string type; 813 result->GetStringWithoutPathExpansion(kType, &type); 814 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY && 815 (type == kServer || type == kAuthority)) { 816 error_or_warning_found_ = true; 817 LOG(ERROR) << MessageHeader() << "Server and authority certificates are " 818 << "prohibited in ONC device policies."; 819 return false; 820 } 821 822 if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_)) 823 return false; 824 825 bool all_required_exist = RequireField(*result, kGUID); 826 827 bool remove = false; 828 result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove); 829 if (!remove) { 830 all_required_exist &= RequireField(*result, kType); 831 832 if (type == kClient) 833 all_required_exist &= RequireField(*result, kPKCS12); 834 else if (type == kServer || type == kAuthority) 835 all_required_exist &= RequireField(*result, kX509); 836 } 837 838 return !error_on_missing_field_ || all_required_exist; 839 } 840 841 std::string Validator::MessageHeader() { 842 std::string path = path_.empty() ? "toplevel" : JoinString(path_, "."); 843 std::string message = "At " + path + ": "; 844 return message; 845 } 846 847 } // namespace onc 848 } // namespace chromeos 849