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