Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: components/policy/core/common/policy_loader_win.cc

Issue 102493002: Use schemas bundled in extensions to convert policies loaded on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "components/policy/core/common/policy_loader_win.h" 5 #include "components/policy/core/common/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" 22 #include "base/json/json_reader.h"
23 #include "base/json/json_writer.h"
23 #include "base/lazy_instance.h" 24 #include "base/lazy_instance.h"
24 #include "base/logging.h" 25 #include "base/logging.h"
25 #include "base/scoped_native_library.h" 26 #include "base/scoped_native_library.h"
26 #include "base/sequenced_task_runner.h" 27 #include "base/sequenced_task_runner.h"
27 #include "base/stl_util.h" 28 #include "base/stl_util.h"
28 #include "base/strings/string16.h" 29 #include "base/strings/string16.h"
29 #include "base/strings/string_util.h" 30 #include "base/strings/string_util.h"
31 #include "base/values.h"
30 #include "components/json_schema/json_schema_constants.h" 32 #include "components/json_schema/json_schema_constants.h"
31 #include "components/policy/core/common/policy_bundle.h" 33 #include "components/policy/core/common/policy_bundle.h"
32 #include "components/policy/core/common/policy_load_status.h" 34 #include "components/policy/core/common/policy_load_status.h"
33 #include "components/policy/core/common/policy_map.h" 35 #include "components/policy/core/common/policy_map.h"
34 #include "components/policy/core/common/policy_namespace.h" 36 #include "components/policy/core/common/policy_namespace.h"
35 #include "components/policy/core/common/preg_parser_win.h" 37 #include "components/policy/core/common/preg_parser_win.h"
36 #include "components/policy/core/common/registry_dict_win.h" 38 #include "components/policy/core/common/registry_dict_win.h"
37 #include "components/policy/core/common/schema.h" 39 #include "components/policy/core/common/schema.h"
38 40
39 namespace schema = json_schema_constants; 41 namespace schema = json_schema_constants;
40 42
41 namespace policy { 43 namespace policy {
42 44
43 namespace { 45 namespace {
44 46
45 const char kKeyMandatory[] = "policy"; 47 const char kKeyMandatory[] = "policy";
46 const char kKeyRecommended[] = "recommended"; 48 const char kKeyRecommended[] = "recommended";
47 const char kKeySchema[] = "schema"; 49 const char kKeySchema[] = "schema";
48 const char kKeyThirdParty[] = "3rdparty"; 50 const char kKeyThirdParty[] = "3rdparty";
49 51
52 // The Legacy Browser Support was the first user of the policy-for-extensions
53 // API, and relied on behavior that will be phased out. If this extension is
54 // present then its policies will be loaded in a special way.
55 // TODO(joaodasilva): remove this for M35. http://crbug.com/325349
56 const char kLegacyBrowserSupportExtensionId[] =
57 "heildphpnddilhkemkielfhnkaagiabh";
58
50 // The GUID of the registry settings group policy extension. 59 // The GUID of the registry settings group policy extension.
51 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID; 60 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID;
52 61
62 // If the LBS extension is found and contains a schema in the registry then this
63 // function is used to patch it, and make it compliant. The fix is to
64 // add an "items" attribute to lists that don't declare it.
65 std::string PatchSchema(const std::string& schema) {
66 base::JSONParserOptions options = base::JSON_PARSE_RFC;
67 scoped_ptr<base::Value> json(base::JSONReader::Read(schema, options));
68 base::DictionaryValue* dict = NULL;
69 base::DictionaryValue* properties = NULL;
70 if (!json ||
71 !json->GetAsDictionary(&dict) ||
72 !dict->GetDictionary(schema::kProperties, &properties)) {
73 return schema;
74 }
75
76 for (base::DictionaryValue::Iterator it(*properties);
77 !it.IsAtEnd(); it.Advance()) {
78 base::DictionaryValue* policy_schema = NULL;
79 std::string type;
80 if (properties->GetDictionary(it.key(), &policy_schema) &&
81 policy_schema->GetString(schema::kType, &type) &&
82 type == schema::kArray &&
83 !policy_schema->HasKey(schema::kItems)) {
84 scoped_ptr<base::DictionaryValue> items(new base::DictionaryValue());
85 items->SetString(schema::kType, schema::kString);
86 policy_schema->Set(schema::kItems, items.release());
87 }
88 }
89
90 std::string serialized;
91 base::JSONWriter::Write(json.get(), &serialized);
92 return serialized;
93 }
94
53 // A helper class encapsulating run-time-linked function calls to Wow64 APIs. 95 // A helper class encapsulating run-time-linked function calls to Wow64 APIs.
54 class Wow64Functions { 96 class Wow64Functions {
55 public: 97 public:
56 Wow64Functions() 98 Wow64Functions()
57 : kernel32_lib_(base::FilePath(L"kernel32")), 99 : kernel32_lib_(base::FilePath(L"kernel32")),
58 is_wow_64_process_(NULL), 100 is_wow_64_process_(NULL),
59 wow_64_disable_wow_64_fs_redirection_(NULL), 101 wow_64_disable_wow_64_fs_redirection_(NULL),
60 wow_64_revert_wow_64_fs_redirection_(NULL) { 102 wow_64_revert_wow_64_fs_redirection_(NULL) {
61 if (kernel32_lib_.is_valid()) { 103 if (kernel32_lib_.is_valid()) {
62 is_wow_64_process_ = reinterpret_cast<IsWow64Process>( 104 is_wow_64_process_ = reinterpret_cast<IsWow64Process>(
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 199
158 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE { 200 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
159 return ::FreeGPOList(gpo_list); 201 return ::FreeGPOList(gpo_list);
160 } 202 }
161 }; 203 };
162 204
163 // The default windows GPO list provider used for PolicyLoaderWin. 205 // The default windows GPO list provider used for PolicyLoaderWin.
164 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider = 206 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider =
165 LAZY_INSTANCE_INITIALIZER; 207 LAZY_INSTANCE_INITIALIZER;
166 208
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 209 // Parses |gpo_dict| according to |schema| and writes the resulting policy
188 // settings to |policy| for the given |scope| and |level|. 210 // settings to |policy| for the given |scope| and |level|.
189 void ParsePolicy(const RegistryDict* gpo_dict, 211 void ParsePolicy(const RegistryDict* gpo_dict,
190 PolicyLevel level, 212 PolicyLevel level,
191 PolicyScope scope, 213 PolicyScope scope,
192 const base::DictionaryValue* schema, 214 const Schema& schema,
193 PolicyMap* policy) { 215 PolicyMap* policy) {
194 if (!gpo_dict) 216 if (!gpo_dict)
195 return; 217 return;
196 218
197 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema)); 219 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema));
198 const base::DictionaryValue* policy_dict = NULL; 220 const base::DictionaryValue* policy_dict = NULL;
199 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) { 221 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) {
200 LOG(WARNING) << "Root policy object is not a dictionary!"; 222 LOG(WARNING) << "Root policy object is not a dictionary!";
201 return; 223 return;
202 } 224 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 is_initialized_ = true; 278 is_initialized_ = true;
257 SetupWatches(); 279 SetupWatches();
258 } 280 }
259 281
260 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() { 282 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() {
261 // Reset the watches BEFORE reading the individual policies to avoid 283 // Reset the watches BEFORE reading the individual policies to avoid
262 // missing a change notification. 284 // missing a change notification.
263 if (is_initialized_) 285 if (is_initialized_)
264 SetupWatches(); 286 SetupWatches();
265 287
266 if (chrome_policy_schema_.empty())
267 BuildChromePolicySchema();
268
269 // Policy scope and corresponding hive. 288 // Policy scope and corresponding hive.
270 static const struct { 289 static const struct {
271 PolicyScope scope; 290 PolicyScope scope;
272 HKEY hive; 291 HKEY hive;
273 } kScopes[] = { 292 } kScopes[] = {
274 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, 293 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE },
275 { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, 294 { POLICY_SCOPE_USER, HKEY_CURRENT_USER },
276 }; 295 };
277 296
278 // Load policy data for the different scopes/levels and merge them. 297 // Load policy data for the different scopes/levels and merge them.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 chrome_policy); 338 chrome_policy);
320 339
321 // Load 3rd-party policy. 340 // Load 3rd-party policy.
322 if (third_party_dict) 341 if (third_party_dict)
323 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get()); 342 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get());
324 } 343 }
325 344
326 return bundle.Pass(); 345 return bundle.Pass();
327 } 346 }
328 347
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, 348 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file,
360 RegistryDict* policy, 349 RegistryDict* policy,
361 PolicyLoadStatusSample* status) { 350 PolicyLoadStatusSample* status) {
362 // The following deals with the minor annoyance that Wow64 FS redirection 351 // 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 352 // 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 353 // process on a 64-bit system, in which case Wow64 FS redirection redirects
365 // access to the %WINDIR%/System32/GroupPolicy directory to 354 // access to the %WINDIR%/System32/GroupPolicy directory to
366 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the 355 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the
367 // system-native directory. 356 // system-native directory.
368 if (base::PathExists(preg_file)) { 357 if (base::PathExists(preg_file)) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 } 438 }
450 439
451 return result; 440 return result;
452 } 441 }
453 442
454 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict, 443 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict,
455 PolicyLevel level, 444 PolicyLevel level,
456 PolicyScope scope, 445 PolicyScope scope,
457 PolicyMap* chrome_policy_map) { 446 PolicyMap* chrome_policy_map) {
458 PolicyMap policy; 447 PolicyMap policy;
459 ParsePolicy(gpo_dict, level, scope, &chrome_policy_schema_, &policy); 448 const Schema* chrome_schema =
449 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
450 ParsePolicy(gpo_dict, level, scope, *chrome_schema, &policy);
460 chrome_policy_map->MergeFrom(policy); 451 chrome_policy_map->MergeFrom(policy);
461 } 452 }
462 453
463 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict, 454 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict,
464 PolicyScope scope, 455 PolicyScope scope,
465 PolicyBundle* bundle) { 456 PolicyBundle* bundle) {
466 // Map of known 3rd party policy domain name to their enum values. 457 // Map of known 3rd party policy domain name to their enum values.
467 static const struct { 458 static const struct {
468 const char* name; 459 const char* name;
469 PolicyDomain domain; 460 PolicyDomain domain;
(...skipping 14 matching lines...) Expand all
484 const char* name = k3rdPartyDomains[i].name; 475 const char* name = k3rdPartyDomains[i].name;
485 const PolicyDomain domain = k3rdPartyDomains[i].domain; 476 const PolicyDomain domain = k3rdPartyDomains[i].domain;
486 const RegistryDict* domain_dict = gpo_dict->GetKey(name); 477 const RegistryDict* domain_dict = gpo_dict->GetKey(name);
487 if (!domain_dict) 478 if (!domain_dict)
488 continue; 479 continue;
489 480
490 for (RegistryDict::KeyMap::const_iterator component( 481 for (RegistryDict::KeyMap::const_iterator component(
491 domain_dict->keys().begin()); 482 domain_dict->keys().begin());
492 component != domain_dict->keys().end(); 483 component != domain_dict->keys().end();
493 ++component) { 484 ++component) {
494 // Load the schema. 485 const PolicyNamespace policy_namespace(domain, component->first);
495 const base::DictionaryValue* schema_dict = NULL; 486
496 scoped_ptr<base::Value> schema; 487 const Schema* schema_from_map = schema_map()->GetSchema(policy_namespace);
497 std::string schema_json; 488 if (!schema_from_map) {
498 const base::Value* schema_value = component->second->GetValue(kKeySchema); 489 // This extension isn't installed or doesn't support policies.
499 if (schema_value && schema_value->GetAsString(&schema_json)) { 490 continue;
500 schema.reset(base::JSONReader::Read(schema_json)); 491 }
501 if (!schema || !schema->GetAsDictionary(&schema_dict)) { 492 Schema schema = *schema_from_map;
502 LOG(WARNING) << "Failed to parse 3rd-part policy schema for " 493
503 << domain << "/" << component->first; 494 if (!schema.valid() &&
495 policy_namespace.domain == POLICY_DOMAIN_EXTENSIONS &&
496 policy_namespace.component_id == kLegacyBrowserSupportExtensionId) {
497 // TODO(joaodasilva): remove this special treatment for LBS by M35.
498 std::string schema_json;
499 const base::Value* value = component->second->GetValue(kKeySchema);
500 if (value && value->GetAsString(&schema_json)) {
501 std::string error;
502 schema = Schema::Parse(PatchSchema(schema_json), &error);
503 if (!schema.valid())
504 LOG(WARNING) << "Invalid schema in the registry for LBS: " << error;
504 } 505 }
505 } 506 }
506 507
507 // Parse policy. 508 // Parse policy.
508 for (size_t j = 0; j < arraysize(kLevels); j++) { 509 for (size_t j = 0; j < arraysize(kLevels); j++) {
509 const RegistryDict* policy_dict = 510 const RegistryDict* policy_dict =
510 component->second->GetKey(kLevels[j].path); 511 component->second->GetKey(kLevels[j].path);
511 if (!policy_dict) 512 if (!policy_dict)
512 continue; 513 continue;
513 514
514 PolicyMap policy; 515 PolicyMap policy;
515 ParsePolicy(policy_dict, kLevels[j].level, scope, schema_dict, &policy); 516 ParsePolicy(policy_dict, kLevels[j].level, scope, schema, &policy);
516 PolicyNamespace policy_namespace(domain, component->first);
517 bundle->Get(policy_namespace).MergeFrom(policy); 517 bundle->Get(policy_namespace).MergeFrom(policy);
518 } 518 }
519 } 519 }
520 } 520 }
521 } 521 }
522 522
523 void PolicyLoaderWin::SetupWatches() { 523 void PolicyLoaderWin::SetupWatches() {
524 DCHECK(is_initialized_); 524 DCHECK(is_initialized_);
525 if (!user_policy_watcher_failed_ && 525 if (!user_policy_watcher_failed_ &&
526 !user_policy_watcher_.GetWatchedObject() && 526 !user_policy_watcher_.GetWatchedObject() &&
(...skipping 13 matching lines...) Expand all
540 540
541 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { 541 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
542 DCHECK(object == user_policy_changed_event_.handle() || 542 DCHECK(object == user_policy_changed_event_.handle() ||
543 object == machine_policy_changed_event_.handle()) 543 object == machine_policy_changed_event_.handle())
544 << "unexpected object signaled policy reload, obj = " 544 << "unexpected object signaled policy reload, obj = "
545 << std::showbase << std::hex << object; 545 << std::showbase << std::hex << object;
546 Reload(false); 546 Reload(false);
547 } 547 }
548 548
549 } // namespace policy 549 } // namespace policy
OLDNEW
« no previous file with comments | « components/policy/core/common/policy_loader_win.h ('k') | components/policy/core/common/policy_loader_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698