OLD | NEW |
| (Empty) |
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 "chrome/browser/chromeos/network_settings/onc_validator.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/string_util.h" | |
12 #include "base/values.h" | |
13 #include "chrome/browser/chromeos/cros/onc_constants.h" | |
14 #include "chrome/browser/chromeos/network_settings/onc_signature.h" | |
15 | |
16 namespace chromeos { | |
17 namespace onc { | |
18 | |
19 Validator::Validator( | |
20 bool error_on_unknown_field, | |
21 bool error_on_wrong_recommended, | |
22 bool error_on_missing_field, | |
23 bool managed_onc) | |
24 : error_on_unknown_field_(error_on_unknown_field), | |
25 error_on_wrong_recommended_(error_on_wrong_recommended), | |
26 error_on_missing_field_(error_on_missing_field), | |
27 managed_onc_(managed_onc) { | |
28 } | |
29 | |
30 Validator::~Validator() { | |
31 } | |
32 | |
33 scoped_ptr<base::DictionaryValue> Validator::ValidateAndRepairObject( | |
34 const OncValueSignature* object_signature, | |
35 const base::DictionaryValue& onc_object) { | |
36 CHECK(object_signature != NULL); | |
37 scoped_ptr<base::Value> result_value = | |
38 MapValue(*object_signature, onc_object); | |
39 base::DictionaryValue* result_dict = NULL; | |
40 if (result_value.get() != NULL) { | |
41 result_value.release()->GetAsDictionary(&result_dict); | |
42 CHECK(result_dict != NULL); | |
43 } | |
44 | |
45 return make_scoped_ptr(result_dict); | |
46 } | |
47 | |
48 scoped_ptr<base::Value> Validator::MapValue( | |
49 const OncValueSignature& signature, | |
50 const base::Value& onc_value) { | |
51 if (onc_value.GetType() != signature.onc_type) { | |
52 DVLOG(1) << "Wrong type. Expected " << signature.onc_type | |
53 << ", but found " << onc_value.GetType(); | |
54 return scoped_ptr<base::Value>(); | |
55 } | |
56 | |
57 scoped_ptr<base::Value> repaired = Mapper::MapValue(signature, onc_value); | |
58 if (repaired.get() != NULL) | |
59 CHECK_EQ(repaired->GetType(), signature.onc_type); | |
60 return repaired.Pass(); | |
61 } | |
62 | |
63 scoped_ptr<base::DictionaryValue> Validator::MapObject( | |
64 const OncValueSignature& signature, | |
65 const base::DictionaryValue& onc_object) { | |
66 scoped_ptr<base::DictionaryValue> repaired(new base::DictionaryValue); | |
67 | |
68 bool valid; | |
69 if (&signature == &kNetworkConfigurationSignature) | |
70 valid = ValidateNetworkConfiguration(onc_object, repaired.get()); | |
71 else if (&signature == &kEthernetSignature) | |
72 valid = ValidateEthernet(onc_object, repaired.get()); | |
73 else if (&signature == &kIPConfigSignature) | |
74 valid = ValidateIPConfig(onc_object, repaired.get()); | |
75 else if (&signature == &kWiFiSignature) | |
76 valid = ValidateWiFi(onc_object, repaired.get()); | |
77 else if (&signature == &kVPNSignature) | |
78 valid = ValidateVPN(onc_object, repaired.get()); | |
79 else if (&signature == &kIPsecSignature) | |
80 valid = ValidateIPsec(onc_object, repaired.get()); | |
81 else if (&signature == &kOpenVPNSignature) | |
82 valid = ValidateOpenVPN(onc_object, repaired.get()); | |
83 else if (&signature == &kCertificatePatternSignature) | |
84 valid = ValidateCertificatePattern(onc_object, repaired.get()); | |
85 else if (&signature == &kProxySettingsSignature) | |
86 valid = ValidateProxySettings(onc_object, repaired.get()); | |
87 else if (&signature == &kProxyLocationSignature) | |
88 valid = ValidateProxyLocation(onc_object, repaired.get()); | |
89 else if (&signature == &kEAPSignature) | |
90 valid = ValidateEAP(onc_object, repaired.get()); | |
91 else if (&signature == &kCertificateSignature) | |
92 valid = ValidateCertificate(onc_object, repaired.get()); | |
93 else | |
94 valid = ValidateObjectDefault(signature, onc_object, repaired.get()); | |
95 | |
96 if (valid) | |
97 return repaired.Pass(); | |
98 else | |
99 return scoped_ptr<base::DictionaryValue>(); | |
100 } | |
101 | |
102 bool Validator::ValidateObjectDefault( | |
103 const OncValueSignature& signature, | |
104 const base::DictionaryValue& onc_object, | |
105 base::DictionaryValue* result) { | |
106 bool found_unknown_field = false; | |
107 bool nested_error_occured = false; | |
108 MapFields(signature, onc_object, &found_unknown_field, &nested_error_occured, | |
109 result); | |
110 if (nested_error_occured) | |
111 return false; | |
112 | |
113 if (found_unknown_field) { | |
114 if (error_on_unknown_field_) { | |
115 DVLOG(1) << "Unknown field name. Aborting."; | |
116 return false; | |
117 } | |
118 DVLOG(1) << "Unknown field name. Ignoring."; | |
119 } | |
120 | |
121 return ValidateRecommendedField(signature, result); | |
122 } | |
123 | |
124 bool Validator::ValidateRecommendedField( | |
125 const OncValueSignature& object_signature, | |
126 base::DictionaryValue* result) { | |
127 CHECK(result != NULL); | |
128 | |
129 scoped_ptr<base::ListValue> recommended; | |
130 base::Value* recommended_value; | |
131 // This remove passes ownership to |recommended_value|. | |
132 if (!result->RemoveWithoutPathExpansion(onc::kRecommended, | |
133 &recommended_value)) { | |
134 return true; | |
135 } | |
136 base::ListValue* recommended_list; | |
137 recommended_value->GetAsList(&recommended_list); | |
138 CHECK(recommended_list != NULL); | |
139 | |
140 recommended.reset(recommended_list); | |
141 | |
142 if (!managed_onc_) { | |
143 DVLOG(1) << "Found a " << onc::kRecommended | |
144 << " field in unmanaged ONC. Removing it."; | |
145 return true; | |
146 } | |
147 | |
148 scoped_ptr<base::ListValue> repaired_recommended(new base::ListValue); | |
149 for (base::ListValue::iterator it = recommended->begin(); | |
150 it != recommended->end(); ++it) { | |
151 std::string field_name; | |
152 if (!(*it)->GetAsString(&field_name)) { | |
153 NOTREACHED(); | |
154 continue; | |
155 } | |
156 | |
157 const OncFieldSignature* field_signature = | |
158 GetFieldSignature(object_signature, field_name); | |
159 | |
160 bool found_error = false; | |
161 std::string error_cause; | |
162 if (field_signature == NULL) { | |
163 found_error = true; | |
164 error_cause = "unknown"; | |
165 } else if (field_signature->value_signature->onc_type == | |
166 base::Value::TYPE_DICTIONARY) { | |
167 found_error = true; | |
168 error_cause = "dictionary-typed"; | |
169 } | |
170 | |
171 if (found_error) { | |
172 DVLOG(1) << "Found " << error_cause << " field name '" << field_name | |
173 << "' in kRecommended array. " | |
174 << (error_on_wrong_recommended_ ? "Aborting." : "Ignoring."); | |
175 if (error_on_wrong_recommended_) | |
176 return false; | |
177 else | |
178 continue; | |
179 } | |
180 | |
181 repaired_recommended->Append((*it)->DeepCopy()); | |
182 } | |
183 | |
184 result->Set(onc::kRecommended, repaired_recommended.release()); | |
185 return true; | |
186 } | |
187 | |
188 namespace { | |
189 | |
190 std::string JoinStringRange(const char** range_begin, | |
191 const char** range_end, | |
192 const std::string& separator) { | |
193 std::vector<std::string> string_vector; | |
194 std::copy(range_begin, range_end, std::back_inserter(string_vector)); | |
195 return JoinString(string_vector, separator); | |
196 } | |
197 | |
198 bool RequireAnyOf(const std::string &actual, const char** valid_values) { | |
199 const char** it = valid_values; | |
200 for (; *it != NULL; ++it) { | |
201 if (actual == *it) | |
202 return true; | |
203 } | |
204 DVLOG(1) << "Found " << actual << ", but expected one of " | |
205 << JoinStringRange(valid_values, it, ", "); | |
206 return false; | |
207 } | |
208 | |
209 bool IsInRange(int actual, int lower_bound, int upper_bound) { | |
210 if (lower_bound <= actual && actual <= upper_bound) | |
211 return true; | |
212 DVLOG(1) << "Found " << actual << ", which is out of range [" << lower_bound | |
213 << ", " << upper_bound << "]"; | |
214 return false; | |
215 } | |
216 | |
217 bool RequireField(const base::DictionaryValue& dict, std::string key) { | |
218 if (dict.HasKey(key)) | |
219 return true; | |
220 DVLOG(1) << "Required field " << key << " missing."; | |
221 return false; | |
222 } | |
223 | |
224 } // namespace | |
225 | |
226 bool Validator::ValidateNetworkConfiguration( | |
227 const base::DictionaryValue& onc_object, | |
228 base::DictionaryValue* result) { | |
229 if (!ValidateObjectDefault(kNetworkConfigurationSignature, | |
230 onc_object, result)) { | |
231 return false; | |
232 } | |
233 | |
234 std::string type; | |
235 static const char* kValidTypes[] = { kEthernet, kVPN, kWiFi, NULL }; | |
236 if (result->GetStringWithoutPathExpansion(kType, &type) && | |
237 !RequireAnyOf(type, kValidTypes)) { | |
238 return false; | |
239 } | |
240 | |
241 bool allRequiredExist = RequireField(*result, kGUID); | |
242 | |
243 bool remove = false; | |
244 result->GetBooleanWithoutPathExpansion(kRemove, &remove); | |
245 if (!remove) { | |
246 allRequiredExist &= RequireField(*result, kName); | |
247 allRequiredExist &= RequireField(*result, kType); | |
248 allRequiredExist &= type.empty() || RequireField(*result, type); | |
249 } | |
250 | |
251 return !error_on_missing_field_ || allRequiredExist; | |
252 } | |
253 | |
254 bool Validator::ValidateEthernet( | |
255 const base::DictionaryValue& onc_object, | |
256 base::DictionaryValue* result) { | |
257 using namespace onc::ethernet; | |
258 if (!ValidateObjectDefault(kEthernetSignature, onc_object, result)) | |
259 return false; | |
260 | |
261 std::string auth; | |
262 static const char* kValidAuthentications[] = { kNone, k8021X, NULL }; | |
263 if (result->GetStringWithoutPathExpansion(kAuthentication, &auth) && | |
264 !RequireAnyOf(auth, kValidAuthentications)) { | |
265 return false; | |
266 } | |
267 | |
268 bool allRequiredExist = true; | |
269 if (auth == k8021X) | |
270 allRequiredExist &= RequireField(*result, kEAP); | |
271 | |
272 return !error_on_missing_field_ || allRequiredExist; | |
273 } | |
274 | |
275 bool Validator::ValidateIPConfig( | |
276 const base::DictionaryValue& onc_object, | |
277 base::DictionaryValue* result) { | |
278 using namespace onc::ipconfig; | |
279 if (!ValidateObjectDefault(kIPConfigSignature, onc_object, result)) | |
280 return false; | |
281 | |
282 std::string type; | |
283 static const char* kValidTypes[] = { kIPv4, kIPv6, NULL }; | |
284 if (result->GetStringWithoutPathExpansion(ipconfig::kType, &type) && | |
285 !RequireAnyOf(type, kValidTypes)) { | |
286 return false; | |
287 } | |
288 | |
289 int routing_prefix; | |
290 int lower_bound = 1; | |
291 // In case of missing type, choose higher upper_bound. | |
292 int upper_bound = (type == kIPv4) ? 32 : 128; | |
293 if (result->GetIntegerWithoutPathExpansion(kRoutingPrefix, &routing_prefix) && | |
294 !IsInRange(routing_prefix, lower_bound, upper_bound)) { | |
295 return false; | |
296 } | |
297 | |
298 bool allRequiredExist = RequireField(*result, kIPAddress) & | |
299 RequireField(*result, kRoutingPrefix) & | |
300 RequireField(*result, ipconfig::kType); | |
301 | |
302 return !error_on_missing_field_ || allRequiredExist; | |
303 } | |
304 | |
305 bool Validator::ValidateWiFi( | |
306 const base::DictionaryValue& onc_object, | |
307 base::DictionaryValue* result) { | |
308 using namespace onc::wifi; | |
309 if (!ValidateObjectDefault(kWiFiSignature, onc_object, result)) | |
310 return false; | |
311 | |
312 std::string security; | |
313 static const char* kValidSecurities[] = | |
314 { kNone, kWEP_PSK, kWEP_8021X, kWPA_PSK, kWPA_EAP, NULL }; | |
315 if (result->GetStringWithoutPathExpansion(kSecurity, &security) && | |
316 !RequireAnyOf(security, kValidSecurities)) { | |
317 return false; | |
318 } | |
319 | |
320 bool allRequiredExist = RequireField(*result, kSecurity) & | |
321 RequireField(*result, kSSID); | |
322 if (security == kWEP_8021X || security == kWPA_EAP) | |
323 allRequiredExist &= RequireField(*result, kEAP); | |
324 else if (security == kWEP_PSK || security == kWPA_PSK) | |
325 allRequiredExist &= RequireField(*result, kPassphrase); | |
326 | |
327 return !error_on_missing_field_ || allRequiredExist; | |
328 } | |
329 | |
330 bool Validator::ValidateVPN( | |
331 const base::DictionaryValue& onc_object, | |
332 base::DictionaryValue* result) { | |
333 using namespace vpn; | |
334 if (!ValidateObjectDefault(kVPNSignature, onc_object, result)) | |
335 return false; | |
336 | |
337 std::string type; | |
338 static const char* kValidTypes[] = | |
339 { kIPsec, kTypeL2TP_IPsec, kOpenVPN, NULL }; | |
340 if (result->GetStringWithoutPathExpansion(vpn::kType, &type) && | |
341 !RequireAnyOf(type, kValidTypes)) { | |
342 return false; | |
343 } | |
344 | |
345 bool allRequiredExist = RequireField(*result, vpn::kType); | |
346 | |
347 if (type == kOpenVPN) { | |
348 allRequiredExist &= RequireField(*result, kOpenVPN); | |
349 } else if (type == kIPsec) { | |
350 allRequiredExist &= RequireField(*result, kIPsec); | |
351 } else if (type == kTypeL2TP_IPsec) { | |
352 allRequiredExist &= RequireField(*result, kIPsec) & | |
353 RequireField(*result, kL2TP); | |
354 } | |
355 | |
356 return !error_on_missing_field_ || allRequiredExist; | |
357 } | |
358 | |
359 bool Validator::ValidateIPsec( | |
360 const base::DictionaryValue& onc_object, | |
361 base::DictionaryValue* result) { | |
362 using namespace onc::vpn; | |
363 using namespace onc::certificate; | |
364 if (!ValidateObjectDefault(kIPsecSignature, onc_object, result)) | |
365 return false; | |
366 | |
367 std::string auth; | |
368 static const char* kValidAuthentications[] = { kPSK, kCert, NULL }; | |
369 if (result->GetStringWithoutPathExpansion(kAuthenticationType, &auth) && | |
370 !RequireAnyOf(auth, kValidAuthentications)) { | |
371 return false; | |
372 } | |
373 | |
374 std::string cert_type; | |
375 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; | |
376 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | |
377 !RequireAnyOf(cert_type, kValidCertTypes)) { | |
378 return false; | |
379 } | |
380 | |
381 bool allRequiredExist = RequireField(*result, kAuthenticationType) & | |
382 RequireField(*result, kIKEVersion); | |
383 if (auth == kCert) { | |
384 allRequiredExist &= RequireField(*result, kClientCertType) & | |
385 RequireField(*result, kServerCARef); | |
386 } | |
387 if (cert_type == kPattern) | |
388 allRequiredExist &= RequireField(*result, kClientCertPattern); | |
389 else if (cert_type == kRef) | |
390 allRequiredExist &= RequireField(*result, kClientCertRef); | |
391 | |
392 return !error_on_missing_field_ || allRequiredExist; | |
393 } | |
394 | |
395 bool Validator::ValidateOpenVPN( | |
396 const base::DictionaryValue& onc_object, | |
397 base::DictionaryValue* result) { | |
398 using namespace onc::vpn; | |
399 using namespace onc::openvpn; | |
400 using namespace onc::certificate; | |
401 if (!ValidateObjectDefault(kOpenVPNSignature, onc_object, result)) | |
402 return false; | |
403 | |
404 std::string auth_retry; | |
405 static const char* kValidAuthRetryValues[] = | |
406 { openvpn::kNone, kInteract, kNoInteract, NULL }; | |
407 if (result->GetStringWithoutPathExpansion(kAuthRetry, &auth_retry) && | |
408 !RequireAnyOf(auth_retry, kValidAuthRetryValues)) { | |
409 return false; | |
410 } | |
411 | |
412 std::string cert_type; | |
413 static const char* kValidCertTypes[] = | |
414 { certificate::kNone, kRef, kPattern, NULL }; | |
415 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | |
416 !RequireAnyOf(cert_type, kValidCertTypes)) { | |
417 return false; | |
418 } | |
419 | |
420 std::string cert_tls; | |
421 static const char* kValidCertTlsValues[] = | |
422 { openvpn::kNone, openvpn::kServer, NULL }; | |
423 if (result->GetStringWithoutPathExpansion(kRemoteCertTLS, &cert_tls) && | |
424 !RequireAnyOf(cert_tls, kValidCertTlsValues)) { | |
425 return false; | |
426 } | |
427 | |
428 bool allRequiredExist = RequireField(*result, kClientCertType); | |
429 if (cert_type == kPattern) | |
430 allRequiredExist &= RequireField(*result, kClientCertPattern); | |
431 else if (cert_type == kRef) | |
432 allRequiredExist &= RequireField(*result, kClientCertRef); | |
433 | |
434 return !error_on_missing_field_ || allRequiredExist; | |
435 } | |
436 | |
437 bool Validator::ValidateCertificatePattern( | |
438 const base::DictionaryValue& onc_object, | |
439 base::DictionaryValue* result) { | |
440 using namespace onc::certificate; | |
441 if (!ValidateObjectDefault(kCertificatePatternSignature, onc_object, result)) | |
442 return false; | |
443 | |
444 bool allRequiredExist = true; | |
445 if (!result->HasKey(kSubject) && !result->HasKey(kIssuer) && | |
446 !result->HasKey(kIssuerCARef)) { | |
447 allRequiredExist = false; | |
448 DVLOG(1) << "None of the fields " << kSubject << ", " << kIssuer << ", and " | |
449 << kIssuerCARef << " exists, but at least one is required."; | |
450 } | |
451 | |
452 return !error_on_missing_field_ || allRequiredExist; | |
453 } | |
454 | |
455 bool Validator::ValidateProxySettings(const base::DictionaryValue& onc_object, | |
456 base::DictionaryValue* result) { | |
457 using namespace onc::proxy; | |
458 if (!ValidateObjectDefault(kProxySettingsSignature, onc_object, result)) | |
459 return false; | |
460 | |
461 std::string type; | |
462 static const char* kValidTypes[] = { kDirect, kManual, kPAC, kWPAD, NULL }; | |
463 if (result->GetStringWithoutPathExpansion(proxy::kType, &type) && | |
464 !RequireAnyOf(type, kValidTypes)) { | |
465 return false; | |
466 } | |
467 | |
468 bool allRequiredExist = RequireField(*result, proxy::kType); | |
469 | |
470 if (type == kManual) | |
471 allRequiredExist &= RequireField(*result, kManual); | |
472 else if (type == kPAC) | |
473 allRequiredExist &= RequireField(*result, kPAC); | |
474 | |
475 return !error_on_missing_field_ || allRequiredExist; | |
476 } | |
477 | |
478 bool Validator::ValidateProxyLocation(const base::DictionaryValue& onc_object, | |
479 base::DictionaryValue* result) { | |
480 using namespace onc::proxy; | |
481 if (!ValidateObjectDefault(kProxyLocationSignature, onc_object, result)) | |
482 return false; | |
483 | |
484 bool allRequiredExist = RequireField(*result, kHost) & | |
485 RequireField(*result, kPort); | |
486 | |
487 return !error_on_missing_field_ || allRequiredExist; | |
488 } | |
489 | |
490 bool Validator::ValidateEAP(const base::DictionaryValue& onc_object, | |
491 base::DictionaryValue* result) { | |
492 using namespace onc::eap; | |
493 using namespace onc::certificate; | |
494 if (!ValidateObjectDefault(kEAPSignature, onc_object, result)) | |
495 return false; | |
496 | |
497 std::string inner; | |
498 static const char* kValidInnerValues[] = | |
499 { kAutomatic, kMD5, kMSCHAPv2, kPAP, NULL }; | |
500 if (result->GetStringWithoutPathExpansion(kInner, &inner) && | |
501 !RequireAnyOf(inner, kValidInnerValues)) { | |
502 return false; | |
503 } | |
504 | |
505 std::string outer; | |
506 static const char* kValidOuterValues[] = | |
507 { kPEAP, kEAP_TLS, kEAP_TTLS, kLEAP, kEAP_SIM, kEAP_FAST, kEAP_AKA, | |
508 NULL }; | |
509 if (result->GetStringWithoutPathExpansion(kOuter, &outer) && | |
510 !RequireAnyOf(outer, kValidOuterValues)) { | |
511 return false; | |
512 } | |
513 | |
514 std::string cert_type; | |
515 static const char* kValidCertTypes[] = { kRef, kPattern, NULL }; | |
516 if (result->GetStringWithoutPathExpansion(kClientCertType, &cert_type) && | |
517 !RequireAnyOf(cert_type, kValidCertTypes )) { | |
518 return false; | |
519 } | |
520 | |
521 bool allRequiredExist = RequireField(*result, kOuter); | |
522 | |
523 if (cert_type == kPattern) | |
524 allRequiredExist &= RequireField(*result, kClientCertPattern); | |
525 else if (cert_type == kRef) | |
526 allRequiredExist &= RequireField(*result, kClientCertRef); | |
527 | |
528 return !error_on_missing_field_ || allRequiredExist; | |
529 } | |
530 | |
531 bool Validator::ValidateCertificate( | |
532 const base::DictionaryValue& onc_object, | |
533 base::DictionaryValue* result) { | |
534 using namespace onc::certificate; | |
535 if (!ValidateObjectDefault(kCertificateSignature, onc_object, result)) | |
536 return false; | |
537 | |
538 std::string type; | |
539 static const char* kValidTypes[] = { kClient, kServer, kAuthority, NULL }; | |
540 if (result->GetStringWithoutPathExpansion(certificate::kType, &type) && | |
541 !RequireAnyOf(type, kValidTypes)) { | |
542 return false; | |
543 } | |
544 | |
545 bool allRequiredExist = RequireField(*result, kGUID); | |
546 | |
547 bool remove = false; | |
548 result->GetBooleanWithoutPathExpansion(kRemove, &remove); | |
549 if (!remove) { | |
550 allRequiredExist &= RequireField(*result, certificate::kType); | |
551 | |
552 if (type == kClient) | |
553 allRequiredExist &= RequireField(*result, kPKCS12); | |
554 else if (type == kServer || type == kAuthority) | |
555 allRequiredExist &= RequireField(*result, kX509); | |
556 } | |
557 | |
558 return !error_on_missing_field_ || allRequiredExist; | |
559 } | |
560 | |
561 } // namespace onc | |
562 } // namespace chromeos | |
OLD | NEW |