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_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, &current_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