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