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