5f7aa9663d6034d85047b5d212279a3763b263ae
[platform/framework/web/crosswalk.git] / src / chromeos / network / onc / onc_validator.cc
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
18 namespace chromeos {
19 namespace onc {
20
21 namespace {
22
23 template <typename T, size_t N>
24 std::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/.
30 std::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
39 Validator::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
49 Validator::~Validator() {}
50
51 scoped_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
79 scoped_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
98 scoped_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
145 scoped_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
172 scoped_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
190 scoped_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
203 bool 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
222 bool 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
293 bool 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
319 namespace {
320
321 std::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
330 bool 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
354 bool 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
372 bool 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
399 bool 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
413 bool 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
428 bool 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
439 bool 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
451 bool 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
466 bool 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
521 bool 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
541 bool 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
567 bool 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
589 bool 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
612 bool 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
666 bool 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
702 bool 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
717 bool 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
737 bool 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
756 bool 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
765 bool 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
799 bool 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
838 std::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