onc_validator.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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_signature.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "components/onc/onc_constants.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace onc {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtemplate <typename T, size_t N>
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::vector<T> toVector(T const (&array)[N]) {
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return std::vector<T>(array, array + N);
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copied from policy/configuration_policy_handler.cc.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO(pneubeck): move to a common place like base/.
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string ValueTypeToString(base::Value::Type type) {
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const strings[] = {"null",   "boolean", "integer",    "double",
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                 "string", "binary",  "dictionary", "list"};
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(static_cast<size_t>(type) < arraysize(strings));
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return strings[type];
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Validator::Validator(bool error_on_unknown_field,
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     bool error_on_wrong_recommended,
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     bool error_on_missing_field,
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     bool managed_onc)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : error_on_unknown_field_(error_on_unknown_field),
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_on_wrong_recommended_(error_on_wrong_recommended),
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_on_missing_field_(error_on_missing_field),
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      managed_onc_(managed_onc),
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      onc_source_(::onc::ONC_SOURCE_NONE) {}
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Validator::~Validator() {}
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature* object_signature,
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Result* result) {
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(object_signature);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *result = VALID;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = false;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool error = false;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result_value =
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MapValue(*object_signature, onc_object, &error);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = INVALID;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result_value.reset();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (error_or_warning_found_) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = VALID_WITH_WARNINGS;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The return value should be NULL if, and only if, |result| equals INVALID.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(result_value.get() == NULL, *result == INVALID);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* result_dict = NULL;
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result_value) {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result_value.release()->GetAsDictionary(&result_dict);
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CHECK(result_dict);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return make_scoped_ptr(result_dict);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::Value> Validator::MapValue(const OncValueSignature& signature,
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            const base::Value& onc_value,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                            bool* error) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (onc_value.GetType() != signature.onc_type) {
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Found value '" << onc_value
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "' of type '" << ValueTypeToString(onc_value.GetType())
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "', but type '" << ValueTypeToString(signature.onc_type)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "' is required.";
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *error = true;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::Value>();
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> repaired =
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Mapper::MapValue(signature, onc_value, error);
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (repaired)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_EQ(repaired->GetType(), signature.onc_type);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return repaired.Pass();
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Validator::MapObject(
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& signature,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& onc_object,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* error) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (valid) {
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (&signature == &kToplevelConfigurationSignature) {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateToplevelConfiguration(repaired.get());
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kNetworkConfigurationSignature) {
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateNetworkConfiguration(repaired.get());
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kEthernetSignature) {
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateEthernet(repaired.get());
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kIPConfigSignature ||
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               &signature == &kSavedIPConfigSignature ||
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               &signature == &kStaticIPConfigSignature) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateIPConfig(repaired.get());
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kWiFiSignature) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateWiFi(repaired.get());
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kVPNSignature) {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateVPN(repaired.get());
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kIPsecSignature) {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateIPsec(repaired.get());
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kOpenVPNSignature) {
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateOpenVPN(repaired.get());
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kVerifyX509Signature) {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateVerifyX509(repaired.get());
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kCertificatePatternSignature) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateCertificatePattern(repaired.get());
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kProxySettingsSignature) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateProxySettings(repaired.get());
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kProxyLocationSignature) {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateProxyLocation(repaired.get());
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kEAPSignature) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateEAP(repaired.get());
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (&signature == &kCertificateSignature) {
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      valid = ValidateCertificate(repaired.get());
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (valid) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return repaired.Pass();
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(error_or_warning_found_);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *error = true;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::Value> Validator::MapField(
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& field_name,
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& object_signature,
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Value& onc_value,
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* found_unknown_field,
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* error) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool current_field_unknown = false;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result = Mapper::MapField(
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      field_name, object_signature, onc_value, &current_field_unknown, error);
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(field_name, path_.back());
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (current_field_unknown) {
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = *found_unknown_field = true;
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    std::string message = MessageHeader() + "Field name '" + field_name +
165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "' is unknown.";
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (error_on_unknown_field_)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << message;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << message;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::ListValue> Validator::MapArray(
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& array_signature,
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::ListValue& onc_array,
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* nested_error) {
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool nested_error_in_current_array = false;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> result = Mapper::MapArray(
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      array_signature, onc_array, &nested_error_in_current_array);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Drop individual networks and certificates instead of rejecting all of
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the configuration.
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nested_error_in_current_array &&
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &array_signature != &kNetworkConfigurationListSignature &&
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &array_signature != &kCertificateListSignature) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *nested_error = nested_error_in_current_array;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::Value> Validator::MapEntry(int index,
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const OncValueSignature& signature,
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            const base::Value& onc_value,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            bool* error) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string str = base::IntToString(index);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(str);
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::Value> result =
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Mapper::MapEntry(index, signature, onc_value, error);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(str, path_.back());
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result.Pass();
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateObjectDefault(const OncValueSignature& signature,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      const base::DictionaryValue& onc_object,
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      base::DictionaryValue* result) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool found_unknown_field = false;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool nested_error_occured = false;
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            result);
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (found_unknown_field && error_on_unknown_field_) {
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Unknown field names are errors: Aborting.";
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nested_error_occured)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ValidateRecommendedField(signature, result);
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::ValidateRecommendedField(
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& object_signature,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* result) {
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(result);
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> recommended;
2313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  scoped_ptr<base::Value> recommended_value;
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This remove passes ownership to |recommended_value|.
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!result->RemoveWithoutPathExpansion(::onc::kRecommended,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          &recommended_value)) {
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* recommended_list = NULL;
2383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  recommended_value.release()->GetAsList(&recommended_list);
2393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  CHECK(recommended_list);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recommended.reset(recommended_list);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!managed_onc_) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    LOG(WARNING) << MessageHeader() << "Found the field '"
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 << ::onc::kRecommended
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << "' in an unmanaged ONC. Removing it.";
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::ListValue::iterator it = recommended->begin();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != recommended->end(); ++it) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string field_name;
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!(*it)->GetAsString(&field_name)) {
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncFieldSignature* field_signature =
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetFieldSignature(object_signature, field_name);
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool found_error = false;
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string error_cause;
265116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!field_signature) {
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      found_error = true;
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_cause = "unknown";
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (field_signature->value_signature->onc_type ==
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               base::Value::TYPE_DICTIONARY) {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      found_error = true;
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_cause = "dictionary-typed";
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (found_error) {
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_or_warning_found_ = true;
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      path_.push_back(::onc::kRecommended);
277b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      std::string message = MessageHeader() + "The " + error_cause +
278b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          " field '" + field_name + "' cannot be recommended.";
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      path_.pop_back();
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (error_on_wrong_recommended_) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(ERROR) << message;
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        LOG(WARNING) << message;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    repaired_recommended->Append((*it)->DeepCopy());
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->Set(::onc::kRecommended, repaired_recommended.release());
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool Validator::ValidateClientCertFields(bool allow_cert_type_none,
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                         base::DictionaryValue* result) {
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  using namespace ::onc::client_cert;
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidCertTypes[] = {kRef, kPattern};
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<const char*> valid_cert_types(toVector(kValidCertTypes));
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (allow_cert_type_none)
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    valid_cert_types.push_back(kClientCertTypeNone);
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kClientCertType, valid_cert_types))
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string cert_type;
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
308116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (IsCertPatternInDevicePolicy(cert_type))
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool all_required_exist = true;
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cert_type == kPattern)
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    all_required_exist &= RequireField(*result, kClientCertPattern);
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  else if (cert_type == kRef)
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    all_required_exist &= RequireField(*result, kClientCertRef);
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return !error_on_missing_field_ || all_required_exist;
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::string JoinStringRange(const std::vector<const char*>& strings,
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const std::string& separator) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> string_vector;
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::copy(strings.begin(), strings.end(), std::back_inserter(string_vector));
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return JoinString(string_vector, separator);
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndHasNoValidValue(
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue& object,
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& field_name,
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::vector<const char*>& valid_values) {
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string actual_value;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::vector<const char*>::const_iterator it = valid_values.begin();
342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       it != valid_values.end();
343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++it) {
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (actual_value == *it)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string valid_values_str =
349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      "[" + JoinStringRange(valid_values, ", ") + "]";
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
351b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found value '" << actual_value <<
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "', but expected one of the values " << valid_values_str;
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const std::string& field_name,
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           int lower_bound,
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           int upper_bound) {
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int actual_value;
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (lower_bound <= actual_value && actual_value <= upper_bound)) {
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
368b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found value '" << actual_value
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << "', but expected a value in the range [" << lower_bound
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << ", " << upper_bound << "] (boundaries inclusive)";
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& field_name) {
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::Value* value = NULL;
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!object.GetWithoutPathExpansion(field_name, &value))
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string str;
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::ListValue* list = NULL;
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (value->GetAsString(&str)) {
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!str.empty())
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (value->GetAsList(&list)) {
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!list->empty())
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NOTREACHED();
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.push_back(field_name);
396b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a "
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             << "non-empty string.";
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  path_.pop_back();
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Validator::RequireField(const base::DictionaryValue& dict,
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const std::string& field_name) {
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (dict.HasKey(field_name))
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  error_or_warning_found_ = true;
407b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  std::string message = MessageHeader() + "The required field '" + field_name +
408b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      "' is missing.";
409b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (error_on_missing_field_)
410b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << message;
411b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  else
412b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(WARNING) << message;
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             const std::string& key_guid,
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             std::set<std::string> *guids) {
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string guid;
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (guids->count(guid) != 0) {
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      error_or_warning_found_ = true;
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << ".";
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    guids->insert(guid);
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) {
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (cert_type == ::onc::client_cert::kPattern &&
4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
435b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "prohibited in ONC device policies.";
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool Validator::IsGlobalNetworkConfigInUserImport(
4438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const base::DictionaryValue& onc_object) {
4448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
4458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
4468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    error_or_warning_found_ = true;
4478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
4488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)               << "in ONC user imports";
4498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return true;
4508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
4518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  return false;
4528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
4538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::toplevel_config;
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
457116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {kUnencryptedConfiguration,
458116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     kEncryptedConfiguration};
459116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
460116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (IsGlobalNetworkConfigInUserImport(*result))
4648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return false;
4658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
466116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::network_config;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {
473116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ::onc::network_type::kEthernet, ::onc::network_type::kVPN,
474116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ::onc::network_type::kWiFi, ::onc::network_type::kCellular};
475116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
476116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndIsEmpty(*result, kGUID)) {
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, kGUID);
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool remove = false;
4874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!remove) {
489f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &=
490f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        RequireField(*result, kName) && RequireField(*result, kType);
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string type;
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result->GetStringWithoutPathExpansion(kType, &type);
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Prohibit anything but WiFi and Ethernet for device-level policy (which
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // corresponds to shared networks). See also http://crosbug.com/28741.
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        type != ::onc::network_type::kWiFi &&
4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        type != ::onc::network_type::kEthernet) {
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      error_or_warning_found_ = true;
501b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      LOG(ERROR) << MessageHeader() << "Networks of type '"
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 << type << "' are prohibited in ONC device policies.";
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (type == ::onc::network_type::kWiFi) {
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
508f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (type == ::onc::network_type::kEthernet) {
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &=
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          RequireField(*result, ::onc::network_config::kEthernet);
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (type == ::onc::network_type::kCellular) {
512f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &=
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          RequireField(*result, ::onc::network_config::kCellular);
514f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (type == ::onc::network_type::kVPN) {
515f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
516f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    } else if (!type.empty()) {
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
521f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateEthernet(base::DictionaryValue* result) {
5254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::ethernet;
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
527116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidAuthentications[] = {kAuthenticationNone, k8021X};
528116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_authentications(
529116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidAuthentications));
530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(
531116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          *result, kAuthentication, valid_authentications)) {
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = true;
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string auth;
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kAuthentication, &auth);
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (auth == k8021X)
539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kEAP);
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
541f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateIPConfig(base::DictionaryValue* result) {
5454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::ipconfig;
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
547116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {kIPv4, kIPv6};
548116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(
550116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          *result, ::onc::ipconfig::kType, valid_types))
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int lower_bound = 1;
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // In case of missing type, choose higher upper_bound.
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int upper_bound = (type == kIPv4) ? 32 : 128;
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FieldExistsAndIsNotInRange(
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          *result, kRoutingPrefix, lower_bound, upper_bound)) {
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, kIPAddress) &&
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            RequireField(*result, kRoutingPrefix) &&
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            RequireField(*result, ::onc::ipconfig::kType);
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateWiFi(base::DictionaryValue* result) {
5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::wifi;
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
573116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidSecurities[] = {kSecurityNone, kWEP_PSK, kWEP_8021X,
574116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                          kWPA_PSK, kWPA_EAP};
575116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_securities(toVector(kValidSecurities));
576116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kSecurity, valid_securities))
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist =
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RequireField(*result, kSecurity) && RequireField(*result, kSSID);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string security;
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kSecurity, &security);
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (security == kWEP_8021X || security == kWPA_EAP)
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kEAP);
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (security == kWEP_PSK || security == kWPA_PSK)
587f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kPassphrase);
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
589f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateVPN(base::DictionaryValue* result) {
5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::vpn;
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
595116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN};
596116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
597116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
6024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == kOpenVPN) {
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kOpenVPN);
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (type == kIPsec) {
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kIPsec);
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (type == kTypeL2TP_IPsec) {
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &=
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateIPsec(base::DictionaryValue* result) {
6164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::ipsec;
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
618116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidAuthentications[] = {kPSK, kCert};
619116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_authentications(
620116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidAuthentications));
621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(
622116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          *result, kAuthenticationType, valid_authentications) ||
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FieldExistsAndIsEmpty(*result, kServerCARefs)) {
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_or_warning_found_ = true;
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << " and " << kServerCARef << " can be set.";
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
634116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ValidateClientCertFields(false,  // don't allow ClientCertType None
635116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                result)) {
636116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
637116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
638116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, kAuthenticationType) &&
640f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            RequireField(*result, kIKEVersion);
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string auth;
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_server_ca_cert =
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (auth == kCert) {
646116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    all_required_exist &=
647116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        RequireField(*result, ::onc::client_cert::kClientCertType);
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!has_server_ca_cert) {
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      all_required_exist = false;
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      error_or_warning_found_ = true;
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string message = MessageHeader() + "The required field '" +
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            kServerCARefs + "' is missing.";
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (error_on_missing_field_)
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LOG(ERROR) << message;
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      else
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LOG(WARNING) << message;
6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (has_server_ca_cert) {
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_or_warning_found_ = true;
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << ") can only be set if " << kAuthenticationType
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << " is set to " << kCert << ".";
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::openvpn;
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidAuthRetryValues[] = {::onc::openvpn::kNone, kInteract,
673116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                               kNoInteract};
674116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_auth_retry_values(
675116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidAuthRetryValues));
676116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidCertTlsValues[] = {::onc::openvpn::kNone,
677116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                             ::onc::openvpn::kServer};
678116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_cert_tls_values(
679116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidCertTlsValues));
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FieldExistsAndHasNoValidValue(
682116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          *result, kAuthRetry, valid_auth_retry_values) ||
683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FieldExistsAndHasNoValidValue(
684116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          *result, kRemoteCertTLS, valid_cert_tls_values) ||
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FieldExistsAndIsEmpty(*result, kServerCARefs)) {
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_or_warning_found_ = true;
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << " and " << kServerCARef << " can be set.";
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
696116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ValidateClientCertFields(true /* allow ClientCertType None */, result))
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
699116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool all_required_exist =
700116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      RequireField(*result, ::onc::client_cert::kClientCertType);
701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
703f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
706f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  using namespace ::onc::verify_x509;
707f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
708116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {types::kName, types::kNamePrefix,
709116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     types::kSubject};
710116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
711f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
712116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kType, valid_types))
713f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, kName);
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
717f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
721116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  using namespace ::onc::client_cert;
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = true;
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !result->HasKey(kIssuerCARef)) {
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
727f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist = false;
728b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    std::string message = MessageHeader() + "None of the fields '" + kSubject +
729b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "', '" + kIssuer + "', and '" + kIssuerCARef +
730b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        "' is present, but at least one is required.";
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (error_on_missing_field_)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << message;
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << message;
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
7414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::proxy;
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
743116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {kDirect, kManual, kPAC, kWPAD};
744116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
745116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, valid_types))
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
748f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
7504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == kManual)
752f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kManual);
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else if (type == kPAC)
754f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kPAC);
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
756f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
7604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::proxy;
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist =
763f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      RequireField(*result, kHost) && RequireField(*result, kPort);
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
765f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateEAP(base::DictionaryValue* result) {
7694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::eap;
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
771116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidInnerValues[] = {kAutomatic, kMD5, kMSCHAPv2, kPAP};
772116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_inner_values(
773116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidInnerValues));
774116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidOuterValues[] = {
775116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA};
776116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_outer_values(
777116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      toVector(kValidOuterValues));
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
779116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kInner, valid_inner_values) ||
780116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      FieldExistsAndHasNoValidValue(*result, kOuter, valid_outer_values) ||
7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      FieldExistsAndIsEmpty(*result, kServerCARefs)) {
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    error_or_warning_found_ = true;
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << " and " << kServerCARef << " can be set.";
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!ValidateClientCertFields(false,  // don't allow ClientCertType None
793116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                result)) {
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
795116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
797116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool all_required_exist = RequireField(*result, kOuter);
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
799f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool Validator::ValidateCertificate(base::DictionaryValue* result) {
8034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  using namespace ::onc::certificate;
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
805116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const char* const kValidTypes[] = {kClient, kServer, kAuthority};
806116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const std::vector<const char*> valid_types(toVector(kValidTypes));
807116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (FieldExistsAndHasNoValidValue(*result, kType, valid_types) ||
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FieldExistsAndIsEmpty(*result, kGUID)) {
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string type;
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->GetStringWithoutPathExpansion(kType, &type);
8144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (type == kServer || type == kAuthority)) {
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    error_or_warning_found_ = true;
817b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    LOG(ERROR) << MessageHeader() << "Server and authority certificates are "
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "prohibited in ONC device policies.";
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &certificate_guids_))
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool all_required_exist = RequireField(*result, kGUID);
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool remove = false;
8284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!remove) {
830f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    all_required_exist &= RequireField(*result, kType);
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (type == kClient)
833f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &= RequireField(*result, kPKCS12);
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else if (type == kServer || type == kAuthority)
835f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      all_required_exist &= RequireField(*result, kX509);
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
838f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !error_on_missing_field_ || all_required_exist;
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
841b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)std::string Validator::MessageHeader() {
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string path = path_.empty() ? "toplevel" : JoinString(path_, ".");
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string message = "At " + path + ": ";
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return message;
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace onc
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
849