Home | History | Annotate | Download | only in onc
      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, &current_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