• 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 // Copied from policy/configuration_policy_handler.cc.
24 // TODO(pneubeck): move to a common place like base/.
ValueTypeToString(base::Value::Type type)25 std::string ValueTypeToString(base::Value::Type type) {
26   static const char* strings[] = {
27     "null",
28     "boolean",
29     "integer",
30     "double",
31     "string",
32     "binary",
33     "dictionary",
34     "list"
35   };
36   CHECK(static_cast<size_t>(type) < arraysize(strings));
37   return strings[type];
38 }
39 
40 }  // namespace
41 
Validator(bool error_on_unknown_field,bool error_on_wrong_recommended,bool error_on_missing_field,bool managed_onc)42 Validator::Validator(bool error_on_unknown_field,
43                      bool error_on_wrong_recommended,
44                      bool error_on_missing_field,
45                      bool managed_onc)
46     : error_on_unknown_field_(error_on_unknown_field),
47       error_on_wrong_recommended_(error_on_wrong_recommended),
48       error_on_missing_field_(error_on_missing_field),
49       managed_onc_(managed_onc),
50       onc_source_(::onc::ONC_SOURCE_NONE) {}
51 
~Validator()52 Validator::~Validator() {}
53 
ValidateAndRepairObject(const OncValueSignature * object_signature,const base::DictionaryValue & onc_object,Result * result)54 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject(
55     const OncValueSignature* object_signature,
56     const base::DictionaryValue& onc_object,
57     Result* result) {
58   CHECK(object_signature != NULL);
59   *result = VALID;
60   error_or_warning_found_ = false;
61   bool error = false;
62   scoped_ptr<base::Value> result_value =
63       MapValue(*object_signature, onc_object, &error);
64   if (error) {
65     *result = INVALID;
66     result_value.reset();
67   } else if (error_or_warning_found_) {
68     *result = VALID_WITH_WARNINGS;
69   }
70   // The return value should be NULL if, and only if, |result| equals INVALID.
71   DCHECK_EQ(result_value.get() == NULL, *result == INVALID);
72 
73   base::DictionaryValue* result_dict = NULL;
74   if (result_value.get() != NULL) {
75     result_value.release()->GetAsDictionary(&result_dict);
76     CHECK(result_dict != NULL);
77   }
78 
79   return make_scoped_ptr(result_dict);
80 }
81 
MapValue(const OncValueSignature & signature,const base::Value & onc_value,bool * error)82 scoped_ptr<base::Value> Validator::MapValue(const OncValueSignature& signature,
83                                             const base::Value& onc_value,
84                                             bool* error) {
85   if (onc_value.GetType() != signature.onc_type) {
86     LOG(ERROR) << MessageHeader() << "Found value '" << onc_value
87                << "' of type '" << ValueTypeToString(onc_value.GetType())
88                << "', but type '" << ValueTypeToString(signature.onc_type)
89                << "' is required.";
90     error_or_warning_found_ = *error = true;
91     return scoped_ptr<base::Value>();
92   }
93 
94   scoped_ptr<base::Value> repaired =
95       Mapper::MapValue(signature, onc_value, error);
96   if (repaired.get() != NULL)
97     CHECK_EQ(repaired->GetType(), signature.onc_type);
98   return repaired.Pass();
99 }
100 
MapObject(const OncValueSignature & signature,const base::DictionaryValue & onc_object,bool * error)101 scoped_ptr<base::DictionaryValue> Validator::MapObject(
102     const OncValueSignature& signature,
103     const base::DictionaryValue& onc_object,
104     bool* error) {
105   scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue);
106 
107   bool valid = ValidateObjectDefault(signature, onc_object, repaired.get());
108   if (valid) {
109     if (&signature == &kToplevelConfigurationSignature)
110       valid = ValidateToplevelConfiguration(repaired.get());
111     else if (&signature == &kNetworkConfigurationSignature)
112       valid = ValidateNetworkConfiguration(repaired.get());
113     else if (&signature == &kEthernetSignature)
114       valid = ValidateEthernet(repaired.get());
115     else if (&signature == &kIPConfigSignature)
116       valid = ValidateIPConfig(repaired.get());
117     else if (&signature == &kWiFiSignature)
118       valid = ValidateWiFi(repaired.get());
119     else if (&signature == &kVPNSignature)
120       valid = ValidateVPN(repaired.get());
121     else if (&signature == &kIPsecSignature)
122       valid = ValidateIPsec(repaired.get());
123     else if (&signature == &kOpenVPNSignature)
124       valid = ValidateOpenVPN(repaired.get());
125     else if (&signature == &kVerifyX509Signature)
126       valid = ValidateVerifyX509(repaired.get());
127     else if (&signature == &kCertificatePatternSignature)
128       valid = ValidateCertificatePattern(repaired.get());
129     else if (&signature == &kProxySettingsSignature)
130       valid = ValidateProxySettings(repaired.get());
131     else if (&signature == &kProxyLocationSignature)
132       valid = ValidateProxyLocation(repaired.get());
133     else if (&signature == &kEAPSignature)
134       valid = ValidateEAP(repaired.get());
135     else if (&signature == &kCertificateSignature)
136       valid = ValidateCertificate(repaired.get());
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 != NULL);
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 == NULL) {
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 
296 namespace {
297 
JoinStringRange(const char ** range_begin,const char ** range_end,const std::string & separator)298 std::string JoinStringRange(const char** range_begin,
299                             const char** range_end,
300                             const std::string& separator) {
301   std::vector<std::string> string_vector;
302   std::copy(range_begin, range_end, std::back_inserter(string_vector));
303   return JoinString(string_vector, separator);
304 }
305 
306 }  // namespace
307 
FieldExistsAndHasNoValidValue(const base::DictionaryValue & object,const std::string & field_name,const char ** valid_values)308 bool Validator::FieldExistsAndHasNoValidValue(
309     const base::DictionaryValue& object,
310     const std::string& field_name,
311     const char** valid_values) {
312   std::string actual_value;
313   if (!object.GetStringWithoutPathExpansion(field_name, &actual_value))
314     return false;
315 
316   const char** it = valid_values;
317   for (; *it != NULL; ++it) {
318     if (actual_value == *it)
319       return false;
320   }
321   error_or_warning_found_ = true;
322   std::string valid_values_str =
323       "[" + JoinStringRange(valid_values, it, ", ") + "]";
324   path_.push_back(field_name);
325   LOG(ERROR) << MessageHeader() << "Found value '" << actual_value <<
326       "', but expected one of the values " << valid_values_str;
327   path_.pop_back();
328   return true;
329 }
330 
FieldExistsAndIsNotInRange(const base::DictionaryValue & object,const std::string & field_name,int lower_bound,int upper_bound)331 bool Validator::FieldExistsAndIsNotInRange(const base::DictionaryValue& object,
332                                            const std::string& field_name,
333                                            int lower_bound,
334                                            int upper_bound) {
335   int actual_value;
336   if (!object.GetIntegerWithoutPathExpansion(field_name, &actual_value) ||
337       (lower_bound <= actual_value && actual_value <= upper_bound)) {
338     return false;
339   }
340   error_or_warning_found_ = true;
341   path_.push_back(field_name);
342   LOG(ERROR) << MessageHeader() << "Found value '" << actual_value
343              << "', but expected a value in the range [" << lower_bound
344              << ", " << upper_bound << "] (boundaries inclusive)";
345   path_.pop_back();
346   return true;
347 }
348 
FieldExistsAndIsEmpty(const base::DictionaryValue & object,const std::string & field_name)349 bool Validator::FieldExistsAndIsEmpty(const base::DictionaryValue& object,
350                                       const std::string& field_name) {
351   const base::Value* value = NULL;
352   if (!object.GetWithoutPathExpansion(field_name, &value))
353     return false;
354 
355   std::string str;
356   const base::ListValue* list = NULL;
357   if (value->GetAsString(&str)) {
358     if (!str.empty())
359       return false;
360   } else if (value->GetAsList(&list)) {
361     if (!list->empty())
362       return false;
363   } else {
364     NOTREACHED();
365     return false;
366   }
367 
368   error_or_warning_found_ = true;
369   path_.push_back(field_name);
370   LOG(ERROR) << MessageHeader() << "Found an empty string, but expected a "
371              << "non-empty string.";
372   path_.pop_back();
373   return true;
374 }
375 
RequireField(const base::DictionaryValue & dict,const std::string & field_name)376 bool Validator::RequireField(const base::DictionaryValue& dict,
377                              const std::string& field_name) {
378   if (dict.HasKey(field_name))
379     return true;
380   error_or_warning_found_ = true;
381   std::string message = MessageHeader() + "The required field '" + field_name +
382       "' is missing.";
383   if (error_on_missing_field_)
384     LOG(ERROR) << message;
385   else
386     LOG(WARNING) << message;
387   return false;
388 }
389 
CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue & dict,const std::string & key_guid,std::set<std::string> * guids)390 bool Validator::CheckGuidIsUniqueAndAddToSet(const base::DictionaryValue& dict,
391                                              const std::string& key_guid,
392                                              std::set<std::string> *guids) {
393   std::string guid;
394   if (dict.GetStringWithoutPathExpansion(key_guid, &guid)) {
395     if (guids->count(guid) != 0) {
396       error_or_warning_found_ = true;
397       LOG(ERROR) << MessageHeader() << "Found a duplicate GUID " << guid << ".";
398       return false;
399     }
400     guids->insert(guid);
401   }
402   return true;
403 }
404 
IsCertPatternInDevicePolicy(const std::string & cert_type)405 bool Validator::IsCertPatternInDevicePolicy(const std::string& cert_type) {
406   if (cert_type == ::onc::certificate::kPattern &&
407       onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY) {
408     error_or_warning_found_ = true;
409     LOG(ERROR) << MessageHeader() << "Client certificate patterns are "
410                << "prohibited in ONC device policies.";
411     return true;
412   }
413   return false;
414 }
415 
IsGlobalNetworkConfigInUserImport(const base::DictionaryValue & onc_object)416 bool Validator::IsGlobalNetworkConfigInUserImport(
417     const base::DictionaryValue& onc_object) {
418   if (onc_source_ == ::onc::ONC_SOURCE_USER_IMPORT &&
419       onc_object.HasKey(::onc::toplevel_config::kGlobalNetworkConfiguration)) {
420     error_or_warning_found_ = true;
421     LOG(ERROR) << MessageHeader() << "GlobalNetworkConfiguration is prohibited "
422                << "in ONC user imports";
423     return true;
424   }
425   return false;
426 }
427 
ValidateToplevelConfiguration(base::DictionaryValue * result)428 bool Validator::ValidateToplevelConfiguration(base::DictionaryValue* result) {
429   using namespace ::onc::toplevel_config;
430 
431   static const char* kValidTypes[] = { kUnencryptedConfiguration,
432                                        kEncryptedConfiguration,
433                                        NULL };
434   if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes))
435     return false;
436 
437   // Not part of the ONC spec:
438   // - We don't require the type field (we assume that it's an
439   //   UnencryptedConfiguration then).
440   // - We don't require specific toplevel objects to be present (e.g. at least
441   //   one of NetworkConfiguration or Certificates).
442 
443   if (IsGlobalNetworkConfigInUserImport(*result))
444     return false;
445 
446   return true;
447 }
448 
ValidateNetworkConfiguration(base::DictionaryValue * result)449 bool Validator::ValidateNetworkConfiguration(base::DictionaryValue* result) {
450   using namespace ::onc::network_config;
451 
452   static const char* kValidTypes[] = { ::onc::network_type::kEthernet,
453                                        ::onc::network_type::kVPN,
454                                        ::onc::network_type::kWiFi,
455                                        ::onc::network_type::kCellular,
456                                        NULL };
457   if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) ||
458       FieldExistsAndIsEmpty(*result, kGUID)) {
459     return false;
460   }
461 
462   if (!CheckGuidIsUniqueAndAddToSet(*result, kGUID, &network_guids_))
463     return false;
464 
465   bool all_required_exist = RequireField(*result, kGUID);
466 
467   bool remove = false;
468   result->GetBooleanWithoutPathExpansion(::onc::kRemove, &remove);
469   if (!remove) {
470     all_required_exist &=
471         RequireField(*result, kName) && RequireField(*result, kType);
472 
473     std::string type;
474     result->GetStringWithoutPathExpansion(kType, &type);
475 
476     // Prohibit anything but WiFi and Ethernet for device-level policy (which
477     // corresponds to shared networks). See also http://crosbug.com/28741.
478     if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY &&
479         type != ::onc::network_type::kWiFi &&
480         type != ::onc::network_type::kEthernet) {
481       error_or_warning_found_ = true;
482       LOG(ERROR) << MessageHeader() << "Networks of type '"
483                  << type << "' are prohibited in ONC device policies.";
484       return false;
485     }
486 
487     if (type == ::onc::network_type::kWiFi) {
488       all_required_exist &= RequireField(*result, ::onc::network_config::kWiFi);
489     } else if (type == ::onc::network_type::kEthernet) {
490       all_required_exist &=
491           RequireField(*result, ::onc::network_config::kEthernet);
492     } else if (type == ::onc::network_type::kCellular) {
493       all_required_exist &=
494           RequireField(*result, ::onc::network_config::kCellular);
495     } else if (type == ::onc::network_type::kVPN) {
496       all_required_exist &= RequireField(*result, ::onc::network_config::kVPN);
497     } else if (!type.empty()) {
498       NOTREACHED();
499     }
500   }
501 
502   return !error_on_missing_field_ || all_required_exist;
503 }
504 
ValidateEthernet(base::DictionaryValue * result)505 bool Validator::ValidateEthernet(base::DictionaryValue* result) {
506   using namespace ::onc::ethernet;
507 
508   static const char* kValidAuthentications[] = { kNone, k8021X, NULL };
509   if (FieldExistsAndHasNoValidValue(
510           *result, kAuthentication, kValidAuthentications)) {
511     return false;
512   }
513 
514   bool all_required_exist = true;
515   std::string auth;
516   result->GetStringWithoutPathExpansion(kAuthentication, &auth);
517   if (auth == k8021X)
518     all_required_exist &= RequireField(*result, kEAP);
519 
520   return !error_on_missing_field_ || all_required_exist;
521 }
522 
ValidateIPConfig(base::DictionaryValue * result)523 bool Validator::ValidateIPConfig(base::DictionaryValue* result) {
524   using namespace ::onc::ipconfig;
525 
526   static const char* kValidTypes[] = { kIPv4, kIPv6, NULL };
527   if (FieldExistsAndHasNoValidValue(
528           *result, ::onc::ipconfig::kType, kValidTypes))
529     return false;
530 
531   std::string type;
532   result->GetStringWithoutPathExpansion(::onc::ipconfig::kType, &type);
533   int lower_bound = 1;
534   // In case of missing type, choose higher upper_bound.
535   int upper_bound = (type == kIPv4) ? 32 : 128;
536   if (FieldExistsAndIsNotInRange(
537           *result, kRoutingPrefix, lower_bound, upper_bound)) {
538     return false;
539   }
540 
541   bool all_required_exist = RequireField(*result, kIPAddress) &&
542                             RequireField(*result, kRoutingPrefix) &&
543                             RequireField(*result, ::onc::ipconfig::kType);
544 
545   return !error_on_missing_field_ || all_required_exist;
546 }
547 
ValidateWiFi(base::DictionaryValue * result)548 bool Validator::ValidateWiFi(base::DictionaryValue* result) {
549   using namespace ::onc::wifi;
550 
551   static const char* kValidSecurities[] =
552       { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL };
553   if (FieldExistsAndHasNoValidValue(*result, kSecurity, kValidSecurities))
554     return false;
555 
556   bool all_required_exist =
557       RequireField(*result, kSecurity) && RequireField(*result, kSSID);
558 
559   std::string security;
560   result->GetStringWithoutPathExpansion(kSecurity, &security);
561   if (security == kWEP_8021X || security == kWPA_EAP)
562     all_required_exist &= RequireField(*result, kEAP);
563   else if (security == kWEP_PSK || security == kWPA_PSK)
564     all_required_exist &= RequireField(*result, kPassphrase);
565 
566   return !error_on_missing_field_ || all_required_exist;
567 }
568 
ValidateVPN(base::DictionaryValue * result)569 bool Validator::ValidateVPN(base::DictionaryValue* result) {
570   using namespace ::onc::vpn;
571 
572   static const char* kValidTypes[] =
573       { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL };
574   if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, kValidTypes))
575     return false;
576 
577   bool all_required_exist = RequireField(*result, ::onc::vpn::kType);
578   std::string type;
579   result->GetStringWithoutPathExpansion(::onc::vpn::kType, &type);
580   if (type == kOpenVPN) {
581     all_required_exist &= RequireField(*result, kOpenVPN);
582   } else if (type == kIPsec) {
583     all_required_exist &= RequireField(*result, kIPsec);
584   } else if (type == kTypeL2TP_IPsec) {
585     all_required_exist &=
586         RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
587   }
588 
589   return !error_on_missing_field_ || all_required_exist;
590 }
591 
ValidateIPsec(base::DictionaryValue * result)592 bool Validator::ValidateIPsec(base::DictionaryValue* result) {
593   using namespace ::onc::ipsec;
594   using namespace ::onc::certificate;
595 
596   static const char* kValidAuthentications[] = { kPSK, kCert, NULL };
597   static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
598   if (FieldExistsAndHasNoValidValue(
599           *result, kAuthenticationType, kValidAuthentications) ||
600       FieldExistsAndHasNoValidValue(
601           *result, ::onc::vpn::kClientCertType, kValidCertTypes) ||
602       FieldExistsAndIsEmpty(*result, kServerCARefs)) {
603     return false;
604   }
605 
606   if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
607     error_or_warning_found_ = true;
608     LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
609                << " and " << kServerCARef << " can be set.";
610     return false;
611   }
612 
613   bool all_required_exist = RequireField(*result, kAuthenticationType) &&
614                             RequireField(*result, kIKEVersion);
615   std::string auth;
616   result->GetStringWithoutPathExpansion(kAuthenticationType, &auth);
617   bool has_server_ca_cert =
618       result->HasKey(kServerCARefs) || result->HasKey(kServerCARef);
619   if (auth == kCert) {
620     all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertType);
621     if (!has_server_ca_cert) {
622       all_required_exist = false;
623       error_or_warning_found_ = true;
624       std::string message = MessageHeader() + "The required field '" +
625                             kServerCARefs + "' is missing.";
626       if (error_on_missing_field_)
627         LOG(ERROR) << message;
628       else
629         LOG(WARNING) << message;
630     }
631   } else if (has_server_ca_cert) {
632     error_or_warning_found_ = true;
633     LOG(ERROR) << MessageHeader() << kServerCARefs << " (or " << kServerCARef
634                << ") can only be set if " << kAuthenticationType
635                << " is set to " << kCert << ".";
636     return false;
637   }
638 
639   std::string cert_type;
640   result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType,
641                                         &cert_type);
642 
643   if (IsCertPatternInDevicePolicy(cert_type))
644     return false;
645 
646   if (cert_type == kPattern)
647     all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern);
648   else if (cert_type == kRef)
649     all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef);
650 
651   return !error_on_missing_field_ || all_required_exist;
652 }
653 
ValidateOpenVPN(base::DictionaryValue * result)654 bool Validator::ValidateOpenVPN(base::DictionaryValue* result) {
655   using namespace ::onc::openvpn;
656   using namespace ::onc::certificate;
657 
658   static const char* kValidAuthRetryValues[] =
659       { ::onc::openvpn::kNone, kInteract, kNoInteract, NULL };
660   static const char* kValidCertTypes[] =
661       { ::onc::certificate::kNone, kRef, kPattern, NULL };
662   static const char* kValidCertTlsValues[] =
663       { ::onc::openvpn::kNone, ::onc::openvpn::kServer, NULL };
664 
665   if (FieldExistsAndHasNoValidValue(
666           *result, kAuthRetry, kValidAuthRetryValues) ||
667       FieldExistsAndHasNoValidValue(
668           *result, ::onc::vpn::kClientCertType, kValidCertTypes) ||
669       FieldExistsAndHasNoValidValue(
670           *result, kRemoteCertTLS, kValidCertTlsValues) ||
671       FieldExistsAndIsEmpty(*result, kServerCARefs)) {
672     return false;
673   }
674 
675   if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
676     error_or_warning_found_ = true;
677     LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
678                << " and " << kServerCARef << " can be set.";
679     return false;
680   }
681 
682   bool all_required_exist = RequireField(*result, ::onc::vpn::kClientCertType);
683   std::string cert_type;
684   result->GetStringWithoutPathExpansion(::onc::vpn::kClientCertType,
685                                         &cert_type);
686 
687   if (IsCertPatternInDevicePolicy(cert_type))
688     return false;
689 
690   if (cert_type == kPattern)
691     all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertPattern);
692   else if (cert_type == kRef)
693     all_required_exist &= RequireField(*result, ::onc::vpn::kClientCertRef);
694 
695   return !error_on_missing_field_ || all_required_exist;
696 }
697 
ValidateVerifyX509(base::DictionaryValue * result)698 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
699   using namespace ::onc::verify_x509;
700 
701   static const char* kValidTypeValues[] =
702     {types::kName, types::kNamePrefix, types::kSubject, NULL};
703 
704   if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypeValues))
705     return false;
706 
707   bool all_required_exist = RequireField(*result, kName);
708 
709   return !error_on_missing_field_ || all_required_exist;
710 }
711 
ValidateCertificatePattern(base::DictionaryValue * result)712 bool Validator::ValidateCertificatePattern(base::DictionaryValue* result) {
713   using namespace ::onc::certificate;
714 
715   bool all_required_exist = true;
716   if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) &&
717       !result->HasKey(kIssuerCARef)) {
718     error_or_warning_found_ = true;
719     all_required_exist = false;
720     std::string message = MessageHeader() + "None of the fields '" + kSubject +
721         "', '" + kIssuer + "', and '" + kIssuerCARef +
722         "' is present, but at least one is required.";
723     if (error_on_missing_field_)
724       LOG(ERROR) << message;
725     else
726       LOG(WARNING) << message;
727   }
728 
729   return !error_on_missing_field_ || all_required_exist;
730 }
731 
ValidateProxySettings(base::DictionaryValue * result)732 bool Validator::ValidateProxySettings(base::DictionaryValue* result) {
733   using namespace ::onc::proxy;
734 
735   static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL };
736   if (FieldExistsAndHasNoValidValue(*result, ::onc::proxy::kType, kValidTypes))
737     return false;
738 
739   bool all_required_exist = RequireField(*result, ::onc::proxy::kType);
740   std::string type;
741   result->GetStringWithoutPathExpansion(::onc::proxy::kType, &type);
742   if (type == kManual)
743     all_required_exist &= RequireField(*result, kManual);
744   else if (type == kPAC)
745     all_required_exist &= RequireField(*result, kPAC);
746 
747   return !error_on_missing_field_ || all_required_exist;
748 }
749 
ValidateProxyLocation(base::DictionaryValue * result)750 bool Validator::ValidateProxyLocation(base::DictionaryValue* result) {
751   using namespace ::onc::proxy;
752 
753   bool all_required_exist =
754       RequireField(*result, kHost) && RequireField(*result, kPort);
755 
756   return !error_on_missing_field_ || all_required_exist;
757 }
758 
ValidateEAP(base::DictionaryValue * result)759 bool Validator::ValidateEAP(base::DictionaryValue* result) {
760   using namespace ::onc::eap;
761   using namespace ::onc::certificate;
762 
763   static const char* kValidInnerValues[] =
764       { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL };
765   static const char* kValidOuterValues[] =
766       { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA,
767         NULL };
768   static const char* kValidCertTypes[] = { kRef, kPattern, NULL };
769 
770   if (FieldExistsAndHasNoValidValue(*result, kInner, kValidInnerValues) ||
771       FieldExistsAndHasNoValidValue(*result, kOuter, kValidOuterValues) ||
772       FieldExistsAndHasNoValidValue(
773           *result, kClientCertType, kValidCertTypes) ||
774       FieldExistsAndIsEmpty(*result, kServerCARefs)) {
775     return false;
776   }
777 
778   if (result->HasKey(kServerCARefs) && result->HasKey(kServerCARef)) {
779     error_or_warning_found_ = true;
780     LOG(ERROR) << MessageHeader() << "At most one of " << kServerCARefs
781                << " and " << kServerCARef << " can be set.";
782     return false;
783   }
784 
785   bool all_required_exist = RequireField(*result, kOuter);
786   std::string cert_type;
787   result->GetStringWithoutPathExpansion(kClientCertType, &cert_type);
788 
789   if (IsCertPatternInDevicePolicy(cert_type))
790     return false;
791 
792   if (cert_type == kPattern)
793     all_required_exist &= RequireField(*result, kClientCertPattern);
794   else if (cert_type == kRef)
795     all_required_exist &= RequireField(*result, kClientCertRef);
796 
797   return !error_on_missing_field_ || all_required_exist;
798 }
799 
ValidateCertificate(base::DictionaryValue * result)800 bool Validator::ValidateCertificate(base::DictionaryValue* result) {
801   using namespace ::onc::certificate;
802 
803   static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL };
804   if (FieldExistsAndHasNoValidValue(*result, kType, kValidTypes) ||
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 
MessageHeader()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
846