OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/policy/policy_loader_win.h" | 5 #include "chrome/browser/policy/policy_loader_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <rpc.h> // For struct GUID | 8 #include <rpc.h> // For struct GUID |
9 #include <shlwapi.h> // For PathIsUNC() | 9 #include <shlwapi.h> // For PathIsUNC() |
10 #include <userenv.h> // For GPO functions | 10 #include <userenv.h> // For GPO functions |
11 | 11 |
12 #include <string> | 12 #include <string> |
13 #include <vector> | 13 #include <vector> |
14 | 14 |
15 // shlwapi.dll is required for PathIsUNC(). | 15 // shlwapi.dll is required for PathIsUNC(). |
16 #pragma comment(lib, "shlwapi.lib") | 16 #pragma comment(lib, "shlwapi.lib") |
17 // userenv.dll is required for various GPO functions. | 17 // userenv.dll is required for various GPO functions. |
18 #pragma comment(lib, "userenv.lib") | 18 #pragma comment(lib, "userenv.lib") |
19 | 19 |
20 #include "base/basictypes.h" | 20 #include "base/basictypes.h" |
21 #include "base/file_util.h" | 21 #include "base/file_util.h" |
22 #include "base/json/json_reader.h" | |
23 #include "base/lazy_instance.h" | 22 #include "base/lazy_instance.h" |
24 #include "base/logging.h" | 23 #include "base/logging.h" |
25 #include "base/scoped_native_library.h" | 24 #include "base/scoped_native_library.h" |
26 #include "base/sequenced_task_runner.h" | 25 #include "base/sequenced_task_runner.h" |
27 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
28 #include "base/strings/string16.h" | 27 #include "base/strings/string16.h" |
29 #include "base/strings/string_util.h" | 28 #include "base/strings/string_util.h" |
| 29 #include "base/values.h" |
30 #include "chrome/browser/policy/policy_load_status.h" | 30 #include "chrome/browser/policy/policy_load_status.h" |
31 #include "chrome/browser/policy/preg_parser_win.h" | 31 #include "chrome/browser/policy/preg_parser_win.h" |
32 #include "components/json_schema/json_schema_constants.h" | |
33 #include "components/policy/core/common/policy_bundle.h" | 32 #include "components/policy/core/common/policy_bundle.h" |
34 #include "components/policy/core/common/policy_map.h" | 33 #include "components/policy/core/common/policy_map.h" |
35 #include "components/policy/core/common/policy_namespace.h" | 34 #include "components/policy/core/common/policy_namespace.h" |
36 #include "components/policy/core/common/registry_dict_win.h" | 35 #include "components/policy/core/common/registry_dict_win.h" |
37 #include "components/policy/core/common/schema.h" | 36 #include "components/policy/core/common/schema.h" |
38 | 37 |
39 namespace schema = json_schema_constants; | |
40 | |
41 namespace policy { | 38 namespace policy { |
42 | 39 |
43 namespace { | 40 namespace { |
44 | 41 |
45 const char kKeyMandatory[] = "policy"; | 42 const char kKeyMandatory[] = "policy"; |
46 const char kKeyRecommended[] = "recommended"; | 43 const char kKeyRecommended[] = "recommended"; |
47 const char kKeySchema[] = "schema"; | 44 const char kKeySchema[] = "schema"; |
48 const char kKeyThirdParty[] = "3rdparty"; | 45 const char kKeyThirdParty[] = "3rdparty"; |
49 | 46 |
50 // The GUID of the registry settings group policy extension. | 47 // The GUID of the registry settings group policy extension. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 | 154 |
158 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE { | 155 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE { |
159 return ::FreeGPOList(gpo_list); | 156 return ::FreeGPOList(gpo_list); |
160 } | 157 } |
161 }; | 158 }; |
162 | 159 |
163 // The default windows GPO list provider used for PolicyLoaderWin. | 160 // The default windows GPO list provider used for PolicyLoaderWin. |
164 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider = | 161 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider = |
165 LAZY_INSTANCE_INITIALIZER; | 162 LAZY_INSTANCE_INITIALIZER; |
166 | 163 |
167 std::string GetSchemaTypeForValueType(base::Value::Type value_type) { | |
168 switch (value_type) { | |
169 case base::Value::TYPE_DICTIONARY: | |
170 return json_schema_constants::kObject; | |
171 case base::Value::TYPE_INTEGER: | |
172 return json_schema_constants::kInteger; | |
173 case base::Value::TYPE_LIST: | |
174 return json_schema_constants::kArray; | |
175 case base::Value::TYPE_BOOLEAN: | |
176 return json_schema_constants::kBoolean; | |
177 case base::Value::TYPE_STRING: | |
178 return json_schema_constants::kString; | |
179 default: | |
180 break; | |
181 } | |
182 | |
183 NOTREACHED() << "Unsupported policy value type " << value_type; | |
184 return json_schema_constants::kNull; | |
185 } | |
186 | |
187 // Parses |gpo_dict| according to |schema| and writes the resulting policy | 164 // Parses |gpo_dict| according to |schema| and writes the resulting policy |
188 // settings to |policy| for the given |scope| and |level|. | 165 // settings to |policy| for the given |scope| and |level|. |
189 void ParsePolicy(const RegistryDict* gpo_dict, | 166 void ParsePolicy(const RegistryDict* gpo_dict, |
190 PolicyLevel level, | 167 PolicyLevel level, |
191 PolicyScope scope, | 168 PolicyScope scope, |
192 const base::DictionaryValue* schema, | 169 const Schema& schema, |
193 PolicyMap* policy) { | 170 PolicyMap* policy) { |
194 if (!gpo_dict) | 171 if (!gpo_dict) |
195 return; | 172 return; |
196 | 173 |
197 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema)); | 174 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema)); |
198 const base::DictionaryValue* policy_dict = NULL; | 175 const base::DictionaryValue* policy_dict = NULL; |
199 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) { | 176 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) { |
200 LOG(WARNING) << "Root policy object is not a dictionary!"; | 177 LOG(WARNING) << "Root policy object is not a dictionary!"; |
201 return; | 178 return; |
202 } | 179 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 is_initialized_ = true; | 233 is_initialized_ = true; |
257 SetupWatches(); | 234 SetupWatches(); |
258 } | 235 } |
259 | 236 |
260 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { | 237 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { |
261 // Reset the watches BEFORE reading the individual policies to avoid | 238 // Reset the watches BEFORE reading the individual policies to avoid |
262 // missing a change notification. | 239 // missing a change notification. |
263 if (is_initialized_) | 240 if (is_initialized_) |
264 SetupWatches(); | 241 SetupWatches(); |
265 | 242 |
266 if (chrome_policy_schema_.empty()) | |
267 BuildChromePolicySchema(); | |
268 | |
269 // Policy scope and corresponding hive. | 243 // Policy scope and corresponding hive. |
270 static const struct { | 244 static const struct { |
271 PolicyScope scope; | 245 PolicyScope scope; |
272 HKEY hive; | 246 HKEY hive; |
273 } kScopes[] = { | 247 } kScopes[] = { |
274 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, | 248 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, |
275 { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, | 249 { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, |
276 }; | 250 }; |
277 | 251 |
278 // Load policy data for the different scopes/levels and merge them. | 252 // Load policy data for the different scopes/levels and merge them. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 chrome_policy); | 293 chrome_policy); |
320 | 294 |
321 // Load 3rd-party policy. | 295 // Load 3rd-party policy. |
322 if (third_party_dict) | 296 if (third_party_dict) |
323 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get()); | 297 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get()); |
324 } | 298 } |
325 | 299 |
326 return bundle.Pass(); | 300 return bundle.Pass(); |
327 } | 301 } |
328 | 302 |
329 void PolicyLoaderWin::BuildChromePolicySchema() { | |
330 // TODO(joaodasilva): use the Schema directly instead of building this | |
331 // DictionaryValue. | |
332 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue()); | |
333 const Schema* chrome_schema = | |
334 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, "")); | |
335 for (Schema::Iterator it = chrome_schema->GetPropertiesIterator(); | |
336 !it.IsAtEnd(); it.Advance()) { | |
337 const std::string schema_type = | |
338 GetSchemaTypeForValueType(it.schema().type()); | |
339 scoped_ptr<base::DictionaryValue> entry_schema(new base::DictionaryValue()); | |
340 entry_schema->SetStringWithoutPathExpansion(json_schema_constants::kType, | |
341 schema_type); | |
342 | |
343 if (it.schema().type() == base::Value::TYPE_LIST) { | |
344 scoped_ptr<base::DictionaryValue> items_schema( | |
345 new base::DictionaryValue()); | |
346 items_schema->SetStringWithoutPathExpansion( | |
347 json_schema_constants::kType, json_schema_constants::kString); | |
348 entry_schema->SetWithoutPathExpansion(json_schema_constants::kItems, | |
349 items_schema.release()); | |
350 } | |
351 properties->SetWithoutPathExpansion(it.key(), entry_schema.release()); | |
352 } | |
353 chrome_policy_schema_.SetStringWithoutPathExpansion( | |
354 json_schema_constants::kType, json_schema_constants::kObject); | |
355 chrome_policy_schema_.SetWithoutPathExpansion( | |
356 json_schema_constants::kProperties, properties.release()); | |
357 } | |
358 | |
359 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file, | 303 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file, |
360 RegistryDict* policy, | 304 RegistryDict* policy, |
361 PolicyLoadStatusSample* status) { | 305 PolicyLoadStatusSample* status) { |
362 // The following deals with the minor annoyance that Wow64 FS redirection | 306 // The following deals with the minor annoyance that Wow64 FS redirection |
363 // might need to be turned off: This is the case if running as a 32-bit | 307 // might need to be turned off: This is the case if running as a 32-bit |
364 // process on a 64-bit system, in which case Wow64 FS redirection redirects | 308 // process on a 64-bit system, in which case Wow64 FS redirection redirects |
365 // access to the %WINDIR%/System32/GroupPolicy directory to | 309 // access to the %WINDIR%/System32/GroupPolicy directory to |
366 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the | 310 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the |
367 // system-native directory. | 311 // system-native directory. |
368 if (base::PathExists(preg_file)) { | 312 if (base::PathExists(preg_file)) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 } | 393 } |
450 | 394 |
451 return result; | 395 return result; |
452 } | 396 } |
453 | 397 |
454 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict, | 398 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict, |
455 PolicyLevel level, | 399 PolicyLevel level, |
456 PolicyScope scope, | 400 PolicyScope scope, |
457 PolicyMap* chrome_policy_map) { | 401 PolicyMap* chrome_policy_map) { |
458 PolicyMap policy; | 402 PolicyMap policy; |
459 ParsePolicy(gpo_dict, level, scope, &chrome_policy_schema_, &policy); | 403 const Schema* chrome_schema = |
| 404 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, "")); |
| 405 ParsePolicy(gpo_dict, level, scope, *chrome_schema, &policy); |
460 chrome_policy_map->MergeFrom(policy); | 406 chrome_policy_map->MergeFrom(policy); |
461 } | 407 } |
462 | 408 |
463 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict, | 409 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict, |
464 PolicyScope scope, | 410 PolicyScope scope, |
465 PolicyBundle* bundle) { | 411 PolicyBundle* bundle) { |
466 // Map of known 3rd party policy domain name to their enum values. | 412 // Map of known 3rd party policy domain name to their enum values. |
467 static const struct { | 413 static const struct { |
468 const char* name; | 414 const char* name; |
469 PolicyDomain domain; | 415 PolicyDomain domain; |
(...skipping 14 matching lines...) Expand all Loading... |
484 const char* name = k3rdPartyDomains[i].name; | 430 const char* name = k3rdPartyDomains[i].name; |
485 const PolicyDomain domain = k3rdPartyDomains[i].domain; | 431 const PolicyDomain domain = k3rdPartyDomains[i].domain; |
486 const RegistryDict* domain_dict = gpo_dict->GetKey(name); | 432 const RegistryDict* domain_dict = gpo_dict->GetKey(name); |
487 if (!domain_dict) | 433 if (!domain_dict) |
488 continue; | 434 continue; |
489 | 435 |
490 for (RegistryDict::KeyMap::const_iterator component( | 436 for (RegistryDict::KeyMap::const_iterator component( |
491 domain_dict->keys().begin()); | 437 domain_dict->keys().begin()); |
492 component != domain_dict->keys().end(); | 438 component != domain_dict->keys().end(); |
493 ++component) { | 439 ++component) { |
494 // Load the schema. | 440 const PolicyNamespace policy_namespace(domain, component->first); |
495 const base::DictionaryValue* schema_dict = NULL; | 441 |
496 scoped_ptr<base::Value> schema; | 442 Schema schema; |
497 std::string schema_json; | 443 const Schema* schema_from_map = schema_map()->GetSchema(policy_namespace); |
498 const base::Value* schema_value = component->second->GetValue(kKeySchema); | 444 if (schema_from_map) |
499 if (schema_value && schema_value->GetAsString(&schema_json)) { | 445 schema = *schema_from_map; |
500 schema.reset(base::JSONReader::Read(schema_json)); | 446 if (!schema.valid()) { |
501 if (!schema || !schema->GetAsDictionary(&schema_dict)) { | 447 // TODO(joaodasilva): the schema should come from the schema_map(), but |
502 LOG(WARNING) << "Failed to parse 3rd-part policy schema for " | 448 // the Legacy Browser Support extension was launched when this loader |
503 << domain << "/" << component->first; | 449 // used a schema embedded in the registry. Remove this for M35. |
| 450 // http://crbug.com/325349 |
| 451 std::string schema_json; |
| 452 const base::Value* value = component->second->GetValue(kKeySchema); |
| 453 if (value && value->GetAsString(&schema_json)) { |
| 454 std::string error; |
| 455 schema = Schema::ParseWithBackwardsCompatibility( |
| 456 schema_json, &error, true); |
| 457 if (!schema.valid()) { |
| 458 LOG(WARNING) << "Invalid schema in the registry for " |
| 459 << name << "/" << component->first << ": " << error; |
| 460 } |
504 } | 461 } |
505 } | 462 } |
506 | 463 |
507 // Parse policy. | 464 // Parse policy. |
508 for (size_t j = 0; j < arraysize(kLevels); j++) { | 465 for (size_t j = 0; j < arraysize(kLevels); j++) { |
509 const RegistryDict* policy_dict = | 466 const RegistryDict* policy_dict = |
510 component->second->GetKey(kLevels[j].path); | 467 component->second->GetKey(kLevels[j].path); |
511 if (!policy_dict) | 468 if (!policy_dict) |
512 continue; | 469 continue; |
513 | 470 |
514 PolicyMap policy; | 471 PolicyMap policy; |
515 ParsePolicy(policy_dict, kLevels[j].level, scope, schema_dict, &policy); | 472 ParsePolicy(policy_dict, kLevels[j].level, scope, schema, &policy); |
516 PolicyNamespace policy_namespace(domain, component->first); | |
517 bundle->Get(policy_namespace).MergeFrom(policy); | 473 bundle->Get(policy_namespace).MergeFrom(policy); |
518 } | 474 } |
519 } | 475 } |
520 } | 476 } |
521 } | 477 } |
522 | 478 |
523 void PolicyLoaderWin::SetupWatches() { | 479 void PolicyLoaderWin::SetupWatches() { |
524 DCHECK(is_initialized_); | 480 DCHECK(is_initialized_); |
525 if (!user_policy_watcher_failed_ && | 481 if (!user_policy_watcher_failed_ && |
526 !user_policy_watcher_.GetWatchedObject() && | 482 !user_policy_watcher_.GetWatchedObject() && |
(...skipping 13 matching lines...) Expand all Loading... |
540 | 496 |
541 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { | 497 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { |
542 DCHECK(object == user_policy_changed_event_.handle() || | 498 DCHECK(object == user_policy_changed_event_.handle() || |
543 object == machine_policy_changed_event_.handle()) | 499 object == machine_policy_changed_event_.handle()) |
544 << "unexpected object signaled policy reload, obj = " | 500 << "unexpected object signaled policy reload, obj = " |
545 << std::showbase << std::hex << object; | 501 << std::showbase << std::hex << object; |
546 Reload(false); | 502 Reload(false); |
547 } | 503 } |
548 | 504 |
549 } // namespace policy | 505 } // namespace policy |
OLD | NEW |