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