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