onc_validator.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/onc/onc_validator.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_writer.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/onc/onc_constants.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/onc/onc_signature.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace onc {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string ValueToString(const base::Value& value) {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::JSONWriter::Write(&value, &json);
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return json;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copied from policy/configuration_policy_handler.cc.
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(pneubeck): move to a common place like base/.
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string ValueTypeToString(base::Value::Type type) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* strings[] = {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "null",
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "boolean",
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "integer",
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "double",
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "string",
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "binary",
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "dictionary",
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "list"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(static_cast<size_t>(type) < arraysize(strings));
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return strings[type];
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Validator::Validator(
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool error_on_unknown_field,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool error_on_wrong_recommended,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool error_on_missing_field,
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool managed_onc)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : error_on_unknown_field_(error_on_unknown_field),
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_on_wrong_recommended_(error_on_wrong_recommended),
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_on_missing_field_(error_on_missing_field),
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      managed_onc_(managed_onc),
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      onc_source_(ONC_SOURCE_NONE) {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Validator::~Validator() {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature* object_signature,
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Result* result) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(object_signature != NULL);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *result = VALID;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = false;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool error = false;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result_value =
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MapValue(*object_signature, onc_object, &error);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = INVALID;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result_value.reset();
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (error_or_warning_found_) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = VALID_WITH_WARNINGS;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The return value should be NULL if, and only if, |result| equals INVALID.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(result_value.get() == NULL, *result == INVALID);
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* result_dict = NULL;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (result_value.get() != NULL) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result_value.release()->GetAsDictionary(&result_dict);
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(result_dict != NULL);
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return make_scoped_ptr(result_dict);
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::Value> Validator::MapValue(
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& signature,
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Value& onc_value,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* error) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (onc_value.GetType() != signature.onc_type) {
96b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Found value '" << onc_value
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "' of type '" << ValueTypeToString(onc_value.GetType())
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "', but type '" << ValueTypeToString(signature.onc_type)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "' is required.";
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *error = true;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::Value>();
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> repaired =
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Mapper::MapValue(signature, onc_value, error);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (repaired.get() != NULL)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(repaired->GetType(), signature.onc_type);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return repaired.Pass();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Validator::MapObject(
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& signature,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* error) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (valid) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (&signature == &kToplevelConfigurationSignature)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateToplevelConfiguration(onc_object, repaired.get());
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kNetworkConfigurationSignature)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateNetworkConfiguration(onc_object, repaired.get());
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kEthernetSignature)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateEthernet(onc_object, repaired.get());
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kIPConfigSignature)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateIPConfig(onc_object, repaired.get());
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kWiFiSignature)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateWiFi(onc_object, repaired.get());
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kVPNSignature)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateVPN(onc_object, repaired.get());
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kIPsecSignature)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateIPsec(onc_object, repaired.get());
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kOpenVPNSignature)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateOpenVPN(onc_object, repaired.get());
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kCertificatePatternSignature)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateCertificatePattern(onc_object, repaired.get());
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kProxySettingsSignature)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateProxySettings(onc_object, repaired.get());
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kProxyLocationSignature)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateProxyLocation(onc_object, repaired.get());
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kEAPSignature)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateEAP(onc_object, repaired.get());
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (&signature == &kCertificateSignature)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      valid = ValidateCertificate(onc_object, repaired.get());
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (valid) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return repaired.Pass();
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(error_or_warning_found_);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *error = true;
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::Value> Validator::MapField(
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& field_name,
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& object_signature,
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Value& onc_value,
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* found_unknown_field,
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* error) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool current_field_unknown = false;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result = Mapper::MapField(
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      field_name, object_signature, onc_value, &current_field_unknown, error);
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(field_name, path_.back());
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_field_unknown) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *found_unknown_field = true;
172b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    std::string message = MessageHeader() + "Field name '" + field_name +
173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "' is unknown.";
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (error_on_unknown_field_)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << message;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << message;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::ListValue> Validator::MapArray(
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& array_signature,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::ListValue& onc_array,
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* nested_error) {
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool nested_error_in_current_array = false;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> result = Mapper::MapArray(
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      array_signature, onc_array, &nested_error_in_current_array);
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Drop individual networks and certificates instead of rejecting all of
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the configuration.
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nested_error_in_current_array &&
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &array_signature != &kNetworkConfigurationListSignature &&
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &array_signature != &kCertificateListSignature) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *nested_error = nested_error_in_current_array;
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::Value> Validator::MapEntry(int index,
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const OncValueSignature& signature,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const base::Value& onc_value,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            bool* error) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string str = base::IntToString(index);
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(str);
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result =
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Mapper::MapEntry(index, signature, onc_value, error);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(str, path_.back());
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateObjectDefault(
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& signature,
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool found_unknown_field = false;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool nested_error_occured = false;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            result);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (found_unknown_field && error_on_unknown_field_) {
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Unknown field names are errors: Aborting.";
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nested_error_occured)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ValidateRecommendedField(signature, result);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateRecommendedField(
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& object_signature,
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(result != NULL);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> recommended;
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Value* recommended_value = NULL;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This remove passes ownership to |recommended_value|.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!result->RemoveWithoutPathExpansion(onc::kRecommended,
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          &recommended_value)) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* recommended_list = NULL;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recommended_value->GetAsList(&recommended_list);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(recommended_list != NULL);
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recommended.reset(recommended_list);
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!managed_onc_) {
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(WARNING) << MessageHeader() << "Found the field '" << onc::kRecommended
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << "' in an unmanaged ONC. Removing it.";
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::ListValue::iterator it = recommended->begin();
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != recommended->end(); ++it) {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string field_name;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!(*it)->GetAsString(&field_name)) {
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncFieldSignature* field_signature =
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetFieldSignature(object_signature, field_name);
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool found_error = false;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string error_cause;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (field_signature == NULL) {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      found_error = true;
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_cause = "unknown";
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (field_signature->value_signature->onc_type ==
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               base::Value::TYPE_DICTIONARY) {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      found_error = true;
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_cause = "dictionary-typed";
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (found_error) {
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_or_warning_found_ = true;
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path_.push_back(onc::kRecommended);
285b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      std::string message = MessageHeader() + "The " + error_cause +
286b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          " field '" + field_name + "' cannot be recommended.";
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path_.pop_back();
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (error_on_wrong_recommended_) {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(ERROR) << message;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << message;
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    repaired_recommended->Append((*it)->DeepCopy());
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->Set(onc::kRecommended, repaired_recommended.release());
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string JoinStringRange(const char** range_begin,
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const char** range_end,
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const std::string& separator) {
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> string_vector;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::copy(range_begin, range_end, std::back_inserter(string_vector));
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return JoinString(string_vector, separator);
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndHasNoValidValue(
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& object,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string &field_name,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const char** valid_values) {
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string actual_value;
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char** it = valid_values;
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; *it != NULL; ++it) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (actual_value == *it)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string valid_values_str =
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "[" + JoinStringRange(valid_values, it, ", ") + "]";
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
333b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found value '" << actual_value <<
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "', but expected one of the values " << valid_values_str;
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           const std::string &field_name,
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           int lower_bound,
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           int upper_bound) {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int actual_value;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (lower_bound <= actual_value && actual_value <= upper_bound)) {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
350b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found value '" << actual_value
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << "', but expected a value in the range [" << lower_bound
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << ", " << upper_bound << "] (boundaries inclusive)";
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& field_name) {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string value;
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!object.GetStringWithoutPathExpansion(field_name, &value) ||
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !value.empty()) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
367b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a "
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << "non-empty string.";
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::RequireField(const base::DictionaryValue& dict,
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const std::string& field_name) {
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (dict.HasKey(field_name))
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
378b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::string message = MessageHeader() + "The required field '" + field_name +
379b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      "' is missing.";
380b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (error_on_missing_field_)
381b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << message;
382b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  else
383b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(WARNING) << message;
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Prohibit certificate patterns for device policy ONC so that an unmanaged user
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// won't have a certificate presented for them involuntarily.
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::CertPatternInDevicePolicy(const std::string& cert_type) {
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_type == certificate::kPattern &&
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      onc_source_ == ONC_SOURCE_DEVICE_POLICY) {
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
393b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "prohibited in ONC device policies.";
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateToplevelConfiguration(
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::toplevel_config;
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] = { kUnencryptedConfiguration,
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       kEncryptedConfiguration,
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NULL };
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes))
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = true;
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Not part of the ONC spec yet:
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We don't require the type field and default to UnencryptedConfiguration.
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type = kUnencryptedConfiguration;
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kType, &type);
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == kUnencryptedConfiguration &&
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !result->HasKey(kNetworkConfigurations) &&
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !result->HasKey(kCertificates)) {
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
421b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    std::string message = MessageHeader() + "Neither the field '" +
422b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        kNetworkConfigurations + "' nor '" + kCertificates +
423b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "is present, but at least one is required.";
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (error_on_missing_field_)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << message;
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << message;
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist = false;
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateNetworkConfiguration(
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::network_config;
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] = { network_type::kEthernet,
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       network_type::kVPN,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       network_type::kWiFi,
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       network_type::kCellular,
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       NULL };
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) ||
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndIsEmpty(*result, kGUID)) {
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kGUID);
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool remove = false;
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetBooleanWithoutPathExpansion(kRemove, &remove);
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!remove) {
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kName);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kType);
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string type;
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result->GetStringWithoutPathExpansion(kType, &type);
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Prohibit anything but WiFi and Ethernet for device-level policy (which
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // corresponds to shared networks). See also http://crosbug.com/28741.
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (onc_source_ == ONC_SOURCE_DEVICE_POLICY &&
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        type != network_type::kWiFi &&
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        type != network_type::kEthernet) {
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_or_warning_found_ = true;
466b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      LOG(ERROR) << MessageHeader() << "Networks of type '"
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << type << "' are prohibited in ONC device policies.";
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (type == network_type::kWiFi)
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, network_config::kWiFi);
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (type == network_type::kEthernet)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, network_config::kEthernet);
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (type == network_type::kCellular)
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, network_config::kCellular);
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (type == network_type::kVPN)
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, network_config::kVPN);
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (!type.empty())
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateEthernet(
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::ethernet;
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidAuthentications[] = { kNone, k8021X, NULL };
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kAuthentication,
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidAuthentications)) {
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = true;
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string auth;
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kAuthentication, &auth);
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (auth == k8021X)
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kEAP);
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateIPConfig(
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::ipconfig;
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] = { kIPv4, kIPv6, NULL };
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, ipconfig::kType, kValidTypes))
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(ipconfig::kType, &type);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int lower_bound = 1;
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // In case of missing type, choose higher upper_bound.
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int upper_bound = (type == kIPv4) ? 32 : 128;
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndIsNotInRange(*result, kRoutingPrefix,
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 lower_bound, upper_bound)) {
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kIPAddress) &
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RequireField(*result, kRoutingPrefix) &
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RequireField(*result, ipconfig::kType);
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateWiFi(
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::wifi;
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidSecurities[] =
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL };
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kSecurity, kValidSecurities))
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kSecurity) &
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RequireField(*result, kSSID);
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string security;
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kSecurity, &security);
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (security == kWEP_8021X || security == kWPA_EAP)
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kEAP);
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (security == kWEP_PSK || security == kWPA_PSK)
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kPassphrase);
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateVPN(
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace vpn;
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] =
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL };
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, vpn::kType, kValidTypes))
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, vpn::kType);
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(vpn::kType, &type);
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == kOpenVPN) {
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kOpenVPN);
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (type == kIPsec) {
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kIPsec);
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (type == kTypeL2TP_IPsec) {
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kIPsec) &
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        RequireField(*result, kL2TP);
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateIPsec(
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  using namespace onc::ipsec;
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::certificate;
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidAuthentications[] = { kPSK, kCert, NULL };
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Using strict bit-wise OR to check all conditions.
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kAuthenticationType,
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidAuthentications) |
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FieldExistsAndHasNoValidValue(*result, vpn::kClientCertType,
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidCertTypes)) {
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kAuthenticationType) &
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RequireField(*result, kIKEVersion);
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string auth;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (auth == kCert) {
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    allRequiredExist &= RequireField(*result, vpn::kClientCertType) &
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        RequireField(*result, kServerCARef);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string cert_type;
605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  result->GetStringWithoutPathExpansion(vpn::kClientCertType, &cert_type);
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CertPatternInDevicePolicy(cert_type))
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_type == kPattern)
611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    allRequiredExist &= RequireField(*result, vpn::kClientCertPattern);
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (cert_type == kRef)
613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    allRequiredExist &= RequireField(*result, vpn::kClientCertRef);
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateOpenVPN(
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::openvpn;
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::certificate;
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidAuthRetryValues[] =
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { openvpn::kNone, kInteract, kNoInteract, NULL };
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidCertTypes[] =
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { certificate::kNone, kRef, kPattern, NULL };
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidCertTlsValues[] =
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { openvpn::kNone, openvpn::kServer, NULL };
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Using strict bit-wise OR to check all conditions.
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kAuthRetry,
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidAuthRetryValues) |
634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      FieldExistsAndHasNoValidValue(*result, vpn::kClientCertType,
635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    kValidCertTypes) |
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndHasNoValidValue(*result, kRemoteCertTLS,
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidCertTlsValues)) {
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool allRequiredExist = RequireField(*result, vpn::kClientCertType);
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string cert_type;
643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  result->GetStringWithoutPathExpansion(vpn::kClientCertType, &cert_type);
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CertPatternInDevicePolicy(cert_type))
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_type == kPattern)
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    allRequiredExist &= RequireField(*result, vpn::kClientCertPattern);
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (cert_type == kRef)
651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    allRequiredExist &= RequireField(*result, vpn::kClientCertRef);
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateCertificatePattern(
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::certificate;
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = true;
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !result->HasKey(kIssuerCARef)) {
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist = false;
666b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    std::string message = MessageHeader() + "None of the fields '" + kSubject +
667b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "', '" + kIssuer + "', and '" + kIssuerCARef +
668b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "' is present, but at least one is required.";
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (error_on_missing_field_)
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << message;
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << message;
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object,
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::DictionaryValue* result) {
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::proxy;
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL };
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, proxy::kType, kValidTypes))
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, proxy::kType);
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(proxy::kType, &type);
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == kManual)
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kManual);
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (type == kPAC)
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kPAC);
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateProxyLocation(const base::DictionaryValue& onc_object,
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::DictionaryValue* result) {
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::proxy;
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kHost) &
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      RequireField(*result, kPort);
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateEAP(const base::DictionaryValue& onc_object,
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::DictionaryValue* result) {
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::eap;
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::certificate;
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidInnerValues[] =
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL };
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidOuterValues[] =
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA,
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NULL };
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Using strict bit-wise OR to check all conditions.
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kInner, kValidInnerValues) |
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndHasNoValidValue(*result, kOuter, kValidOuterValues) |
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndHasNoValidValue(*result, kClientCertType,
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    kValidCertTypes)) {
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kOuter);
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string cert_type;
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CertPatternInDevicePolicy(cert_type))
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_type == kPattern)
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kClientCertPattern);
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (cert_type == kRef)
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kClientCertRef);
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateCertificate(
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  using namespace onc::certificate;
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL };
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) ||
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndIsEmpty(*result, kGUID)) {
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kType, &type);
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (onc_source_ == ONC_SOURCE_DEVICE_POLICY &&
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (type == kServer || type == kAuthority)) {
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
758b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "prohibited in ONC device policies.";
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allRequiredExist = RequireField(*result, kGUID);
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool remove = false;
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetBooleanWithoutPathExpansion(kRemove, &remove);
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!remove) {
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allRequiredExist &= RequireField(*result, kType);
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (type == kClient)
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, kPKCS12);
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (type == kServer || type == kAuthority)
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      allRequiredExist &= RequireField(*result, kX509);
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !error_on_missing_field_ || allRequiredExist;
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
779b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)std::string Validator::MessageHeader() {
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string message = "At " + path + ": ";
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return message;
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace onc
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
787