Ignore title parameter for navigator.registerProtocolHandler
[chromium-blink-merge.git] / components / policy / core / common / policy_loader_win.cc
blobfc739ad45d368ffe5451c14d2702992c8d546e1a
1 // Copyright (c) 2014 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.
5 #include "components/policy/core/common/policy_loader_win.h"
7 #include <windows.h>
8 #include <lm.h> // For limits.
9 #include <ntdsapi.h> // For Ds[Un]Bind
10 #include <rpc.h> // For struct GUID
11 #include <shlwapi.h> // For PathIsUNC()
12 #include <userenv.h> // For GPO functions
14 #include <string>
15 #include <vector>
17 // shlwapi.dll is required for PathIsUNC().
18 #pragma comment(lib, "shlwapi.lib")
19 // userenv.dll is required for various GPO functions.
20 #pragma comment(lib, "userenv.lib")
21 // ntdsapi.dll is required for Ds[Un]Bind calls.
22 #pragma comment(lib, "ntdsapi.lib")
24 #include "base/basictypes.h"
25 #include "base/bind.h"
26 #include "base/file_util.h"
27 #include "base/json/json_reader.h"
28 #include "base/json/json_writer.h"
29 #include "base/lazy_instance.h"
30 #include "base/logging.h"
31 #include "base/memory/scoped_ptr.h"
32 #include "base/metrics/histogram.h"
33 #include "base/scoped_native_library.h"
34 #include "base/sequenced_task_runner.h"
35 #include "base/stl_util.h"
36 #include "base/strings/string16.h"
37 #include "base/strings/string_util.h"
38 #include "base/values.h"
39 #include "base/win/win_util.h"
40 #include "base/win/windows_version.h"
41 #include "components/json_schema/json_schema_constants.h"
42 #include "components/policy/core/common/policy_bundle.h"
43 #include "components/policy/core/common/policy_load_status.h"
44 #include "components/policy/core/common/policy_map.h"
45 #include "components/policy/core/common/policy_namespace.h"
46 #include "components/policy/core/common/preg_parser_win.h"
47 #include "components/policy/core/common/registry_dict_win.h"
48 #include "components/policy/core/common/schema.h"
49 #include "policy/policy_constants.h"
51 namespace schema = json_schema_constants;
53 namespace policy {
55 namespace {
57 const char kKeyMandatory[] = "policy";
58 const char kKeyRecommended[] = "recommended";
59 const char kKeySchema[] = "schema";
60 const char kKeyThirdParty[] = "3rdparty";
62 // The Legacy Browser Support was the first user of the policy-for-extensions
63 // API, and relied on behavior that will be phased out. If this extension is
64 // present then its policies will be loaded in a special way.
65 // TODO(joaodasilva): remove this for M35. http://crbug.com/325349
66 const char kLegacyBrowserSupportExtensionId[] =
67 "heildphpnddilhkemkielfhnkaagiabh";
69 // The web store url that is the only trusted source for extensions.
70 const char kExpectedWebStoreUrl[] =
71 ";https://clients2.google.com/service/update2/crx";
72 // String to be prepended to each blocked entry.
73 const char kBlockedExtensionPrefix[] = "[BLOCKED]";
75 // The GUID of the registry settings group policy extension.
76 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID;
78 // The list of possible errors that can occur while collecting information about
79 // the current enterprise environment.
80 enum DomainCheckErrors {
81 DOMAIN_CHECK_ERROR_GET_JOIN_INFO = 0,
82 DOMAIN_CHECK_ERROR_DS_BIND,
83 DOMAIN_CHECK_ERROR_LAST,
86 // If the LBS extension is found and contains a schema in the registry then this
87 // function is used to patch it, and make it compliant. The fix is to
88 // add an "items" attribute to lists that don't declare it.
89 std::string PatchSchema(const std::string& schema) {
90 base::JSONParserOptions options = base::JSON_PARSE_RFC;
91 scoped_ptr<base::Value> json(base::JSONReader::Read(schema, options));
92 base::DictionaryValue* dict = NULL;
93 base::DictionaryValue* properties = NULL;
94 if (!json ||
95 !json->GetAsDictionary(&dict) ||
96 !dict->GetDictionary(schema::kProperties, &properties)) {
97 return schema;
100 for (base::DictionaryValue::Iterator it(*properties);
101 !it.IsAtEnd(); it.Advance()) {
102 base::DictionaryValue* policy_schema = NULL;
103 std::string type;
104 if (properties->GetDictionary(it.key(), &policy_schema) &&
105 policy_schema->GetString(schema::kType, &type) &&
106 type == schema::kArray &&
107 !policy_schema->HasKey(schema::kItems)) {
108 scoped_ptr<base::DictionaryValue> items(new base::DictionaryValue());
109 items->SetString(schema::kType, schema::kString);
110 policy_schema->Set(schema::kItems, items.release());
114 std::string serialized;
115 base::JSONWriter::Write(json.get(), &serialized);
116 return serialized;
119 // Verifies that untrusted policies contain only safe values. Modifies the
120 // |policy| in place.
121 void FilterUntrustedPolicy(PolicyMap* policy) {
122 if (base::win::IsEnrolledToDomain())
123 return;
125 const PolicyMap::Entry* map_entry =
126 policy->Get(policy::key::kExtensionInstallForcelist);
127 if (map_entry && map_entry->value) {
128 int invalid_policies = 0;
129 const base::ListValue* policy_list_value = NULL;
130 if (!map_entry->value->GetAsList(&policy_list_value))
131 return;
133 scoped_ptr<base::ListValue> filtered_values(new base::ListValue);
134 for (base::ListValue::const_iterator list_entry(policy_list_value->begin());
135 list_entry != policy_list_value->end(); ++list_entry) {
136 std::string entry;
137 if (!(*list_entry)->GetAsString(&entry))
138 continue;
139 size_t pos = entry.find(';');
140 if (pos == std::string::npos)
141 continue;
142 // Only allow custom update urls in enterprise environments.
143 if (!LowerCaseEqualsASCII(entry.substr(pos), kExpectedWebStoreUrl)) {
144 entry = kBlockedExtensionPrefix + entry;
145 invalid_policies++;
148 filtered_values->AppendString(entry);
150 policy->Set(policy::key::kExtensionInstallForcelist,
151 map_entry->level, map_entry->scope,
152 filtered_values.release(),
153 map_entry->external_data_fetcher);
154 UMA_HISTOGRAM_COUNTS("EnterpriseCheck.InvalidPoliciesDetected",
155 invalid_policies);
159 // A helper class encapsulating run-time-linked function calls to Wow64 APIs.
160 class Wow64Functions {
161 public:
162 Wow64Functions()
163 : kernel32_lib_(base::FilePath(L"kernel32")),
164 is_wow_64_process_(NULL),
165 wow_64_disable_wow_64_fs_redirection_(NULL),
166 wow_64_revert_wow_64_fs_redirection_(NULL) {
167 if (kernel32_lib_.is_valid()) {
168 is_wow_64_process_ = reinterpret_cast<IsWow64Process>(
169 kernel32_lib_.GetFunctionPointer("IsWow64Process"));
170 wow_64_disable_wow_64_fs_redirection_ =
171 reinterpret_cast<Wow64DisableWow64FSRedirection>(
172 kernel32_lib_.GetFunctionPointer(
173 "Wow64DisableWow64FsRedirection"));
174 wow_64_revert_wow_64_fs_redirection_ =
175 reinterpret_cast<Wow64RevertWow64FSRedirection>(
176 kernel32_lib_.GetFunctionPointer(
177 "Wow64RevertWow64FsRedirection"));
181 bool is_valid() {
182 return is_wow_64_process_ &&
183 wow_64_disable_wow_64_fs_redirection_ &&
184 wow_64_revert_wow_64_fs_redirection_;
187 bool IsWow64() {
188 BOOL result = 0;
189 if (!is_wow_64_process_(GetCurrentProcess(), &result))
190 PLOG(WARNING) << "IsWow64ProcFailed";
191 return !!result;
194 bool DisableFsRedirection(PVOID* previous_state) {
195 return !!wow_64_disable_wow_64_fs_redirection_(previous_state);
198 bool RevertFsRedirection(PVOID previous_state) {
199 return !!wow_64_revert_wow_64_fs_redirection_(previous_state);
202 private:
203 typedef BOOL (WINAPI* IsWow64Process)(HANDLE, PBOOL);
204 typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
205 typedef BOOL (WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
207 base::ScopedNativeLibrary kernel32_lib_;
209 IsWow64Process is_wow_64_process_;
210 Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection_;
211 Wow64RevertWow64FSRedirection wow_64_revert_wow_64_fs_redirection_;
213 DISALLOW_COPY_AND_ASSIGN(Wow64Functions);
216 // Global Wow64Function instance used by ScopedDisableWow64Redirection below.
217 static base::LazyInstance<Wow64Functions> g_wow_64_functions =
218 LAZY_INSTANCE_INITIALIZER;
220 // Scoper that switches off Wow64 File System Redirection during its lifetime.
221 class ScopedDisableWow64Redirection {
222 public:
223 ScopedDisableWow64Redirection()
224 : active_(false),
225 previous_state_(NULL) {
226 Wow64Functions* wow64 = g_wow_64_functions.Pointer();
227 if (wow64->is_valid() && wow64->IsWow64()) {
228 if (wow64->DisableFsRedirection(&previous_state_))
229 active_ = true;
230 else
231 PLOG(WARNING) << "Wow64DisableWow64FSRedirection";
235 ~ScopedDisableWow64Redirection() {
236 if (active_)
237 CHECK(g_wow_64_functions.Get().RevertFsRedirection(previous_state_));
240 bool is_active() { return active_; }
242 private:
243 bool active_;
244 PVOID previous_state_;
246 DISALLOW_COPY_AND_ASSIGN(ScopedDisableWow64Redirection);
249 // AppliedGPOListProvider implementation that calls actual Windows APIs.
250 class WinGPOListProvider : public AppliedGPOListProvider {
251 public:
252 virtual ~WinGPOListProvider() {}
254 // AppliedGPOListProvider:
255 virtual DWORD GetAppliedGPOList(DWORD flags,
256 LPCTSTR machine_name,
257 PSID sid_user,
258 GUID* extension_guid,
259 PGROUP_POLICY_OBJECT* gpo_list) OVERRIDE {
260 return ::GetAppliedGPOList(flags, machine_name, sid_user, extension_guid,
261 gpo_list);
264 virtual BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) OVERRIDE {
265 return ::FreeGPOList(gpo_list);
269 // The default windows GPO list provider used for PolicyLoaderWin.
270 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider =
271 LAZY_INSTANCE_INITIALIZER;
273 // Parses |gpo_dict| according to |schema| and writes the resulting policy
274 // settings to |policy| for the given |scope| and |level|.
275 void ParsePolicy(const RegistryDict* gpo_dict,
276 PolicyLevel level,
277 PolicyScope scope,
278 const Schema& schema,
279 PolicyMap* policy) {
280 if (!gpo_dict)
281 return;
283 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema));
284 const base::DictionaryValue* policy_dict = NULL;
285 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) {
286 LOG(WARNING) << "Root policy object is not a dictionary!";
287 return;
290 policy->LoadFrom(policy_dict, level, scope);
293 // Collects stats about the enterprise environment that can be used to decide
294 // how to parse the existing policy information.
295 void CollectEntepriseUMAs() {
296 // Collect statistics about the windows suite.
297 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.OSType",
298 base::win::OSInfo::GetInstance()->version_type(),
299 base::win::SUITE_LAST);
301 // Get the computer's domain status.
302 LPWSTR domain;
303 NETSETUP_JOIN_STATUS join_status;
304 if(NERR_Success != ::NetGetJoinInformation(NULL, &domain, &join_status)) {
305 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.DomainCheckFailed",
306 DOMAIN_CHECK_ERROR_GET_JOIN_INFO,
307 DOMAIN_CHECK_ERROR_LAST);
308 return;
310 ::NetApiBufferFree(domain);
312 bool in_domain = join_status == NetSetupDomainName;
313 UMA_HISTOGRAM_BOOLEAN("EnterpriseCheck.InDomain", in_domain);
314 if (in_domain) {
315 // This check will tell us how often are domain computers actually
316 // connected to the enterprise network while Chrome is running.
317 HANDLE server_bind;
318 if (ERROR_SUCCESS == ::DsBind(NULL, NULL, &server_bind)) {
319 UMA_HISTOGRAM_COUNTS("EnterpriseCheck.DomainBindSucceeded", 1);
320 ::DsUnBind(&server_bind);
321 } else {
322 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.DomainCheckFailed",
323 DOMAIN_CHECK_ERROR_DS_BIND,
324 DOMAIN_CHECK_ERROR_LAST);
329 } // namespace
331 const base::FilePath::CharType PolicyLoaderWin::kPRegFileName[] =
332 FILE_PATH_LITERAL("Registry.pol");
334 PolicyLoaderWin::PolicyLoaderWin(
335 scoped_refptr<base::SequencedTaskRunner> task_runner,
336 const base::string16& chrome_policy_key,
337 AppliedGPOListProvider* gpo_provider)
338 : AsyncPolicyLoader(task_runner),
339 is_initialized_(false),
340 chrome_policy_key_(chrome_policy_key),
341 gpo_provider_(gpo_provider),
342 user_policy_changed_event_(false, false),
343 machine_policy_changed_event_(false, false),
344 user_policy_watcher_failed_(false),
345 machine_policy_watcher_failed_(false) {
346 if (!::RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
347 DPLOG(WARNING) << "Failed to register user group policy notification";
348 user_policy_watcher_failed_ = true;
350 if (!::RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
351 DPLOG(WARNING) << "Failed to register machine group policy notification.";
352 machine_policy_watcher_failed_ = true;
356 PolicyLoaderWin::~PolicyLoaderWin() {
357 if (!user_policy_watcher_failed_) {
358 ::UnregisterGPNotification(user_policy_changed_event_.handle());
359 user_policy_watcher_.StopWatching();
361 if (!machine_policy_watcher_failed_) {
362 ::UnregisterGPNotification(machine_policy_changed_event_.handle());
363 machine_policy_watcher_.StopWatching();
367 // static
368 scoped_ptr<PolicyLoaderWin> PolicyLoaderWin::Create(
369 scoped_refptr<base::SequencedTaskRunner> task_runner,
370 const base::string16& chrome_policy_key) {
371 return make_scoped_ptr(
372 new PolicyLoaderWin(task_runner,
373 chrome_policy_key,
374 g_win_gpo_list_provider.Pointer()));
377 void PolicyLoaderWin::InitOnBackgroundThread() {
378 is_initialized_ = true;
379 SetupWatches();
380 CollectEntepriseUMAs();
383 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() {
384 // Reset the watches BEFORE reading the individual policies to avoid
385 // missing a change notification.
386 if (is_initialized_)
387 SetupWatches();
389 // Policy scope and corresponding hive.
390 static const struct {
391 PolicyScope scope;
392 HKEY hive;
393 } kScopes[] = {
394 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE },
395 { POLICY_SCOPE_USER, HKEY_CURRENT_USER },
398 bool is_enterprise = base::win::IsEnrolledToDomain();
399 VLOG(1) << "Reading policy from the registry is "
400 << (is_enterprise ? "enabled." : "disabled.");
402 // Load policy data for the different scopes/levels and merge them.
403 scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
404 PolicyMap* chrome_policy =
405 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
406 for (size_t i = 0; i < arraysize(kScopes); ++i) {
407 PolicyScope scope = kScopes[i].scope;
408 PolicyLoadStatusSample status;
409 RegistryDict gpo_dict;
411 // Note: GPO rules mandate a call to EnterCriticalPolicySection() here, and
412 // a matching LeaveCriticalPolicySection() call below after the
413 // ReadPolicyFromGPO() block. Unfortunately, the policy mutex may be
414 // unavailable for extended periods of time, and there are reports of this
415 // happening in the wild: http://crbug.com/265862.
417 // Blocking for minutes is neither acceptable for Chrome startup, nor on
418 // the FILE thread on which this code runs in steady state. Given that
419 // there have never been any reports of issues due to partially-applied /
420 // corrupt group policy, this code intentionally omits the
421 // EnterCriticalPolicySection() call.
423 // If there's ever reason to revisit this decision, one option could be to
424 // make the EnterCriticalPolicySection() call on a dedicated thread and
425 // timeout on it more aggressively. For now, there's no justification for
426 // the additional effort this would introduce.
428 if (is_enterprise || !ReadPolicyFromGPO(scope, &gpo_dict, &status)) {
429 VLOG_IF(1, !is_enterprise) << "Failed to read GPO files for " << scope
430 << " falling back to registry.";
431 gpo_dict.ReadRegistry(kScopes[i].hive, chrome_policy_key_);
434 // Remove special-cased entries from the GPO dictionary.
435 scoped_ptr<RegistryDict> recommended_dict(
436 gpo_dict.RemoveKey(kKeyRecommended));
437 scoped_ptr<RegistryDict> third_party_dict(
438 gpo_dict.RemoveKey(kKeyThirdParty));
440 // Load Chrome policy.
441 LoadChromePolicy(&gpo_dict, POLICY_LEVEL_MANDATORY, scope, chrome_policy);
442 LoadChromePolicy(recommended_dict.get(), POLICY_LEVEL_RECOMMENDED, scope,
443 chrome_policy);
445 // Load 3rd-party policy.
446 if (third_party_dict)
447 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get());
450 return bundle.Pass();
453 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file,
454 RegistryDict* policy,
455 PolicyLoadStatusSample* status) {
456 // The following deals with the minor annoyance that Wow64 FS redirection
457 // might need to be turned off: This is the case if running as a 32-bit
458 // process on a 64-bit system, in which case Wow64 FS redirection redirects
459 // access to the %WINDIR%/System32/GroupPolicy directory to
460 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the
461 // system-native directory.
462 if (base::PathExists(preg_file)) {
463 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy, status);
464 } else {
465 // Try with redirection switched off.
466 ScopedDisableWow64Redirection redirection_disable;
467 if (redirection_disable.is_active() && base::PathExists(preg_file)) {
468 status->Add(POLICY_LOAD_STATUS_WOW64_REDIRECTION_DISABLED);
469 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy,
470 status);
474 // Report the error.
475 LOG(ERROR) << "PReg file doesn't exist: " << preg_file.value();
476 status->Add(POLICY_LOAD_STATUS_MISSING);
477 return false;
480 bool PolicyLoaderWin::LoadGPOPolicy(PolicyScope scope,
481 PGROUP_POLICY_OBJECT policy_object_list,
482 RegistryDict* policy,
483 PolicyLoadStatusSample* status) {
484 RegistryDict parsed_policy;
485 RegistryDict forced_policy;
486 for (GROUP_POLICY_OBJECT* policy_object = policy_object_list;
487 policy_object; policy_object = policy_object->pNext) {
488 if (policy_object->dwOptions & GPO_FLAG_DISABLE)
489 continue;
491 if (PathIsUNC(policy_object->lpFileSysPath)) {
492 // UNC path: Assume this is an AD-managed machine, which updates the
493 // registry via GPO's standard registry CSE periodically. Fall back to
494 // reading from the registry in this case.
495 status->Add(POLICY_LOAD_STATUS_INACCCESSIBLE);
496 return false;
499 base::FilePath preg_file_path(
500 base::FilePath(policy_object->lpFileSysPath).Append(kPRegFileName));
501 if (policy_object->dwOptions & GPO_FLAG_FORCE) {
502 RegistryDict new_forced_policy;
503 if (!ReadPRegFile(preg_file_path, &new_forced_policy, status))
504 return false;
506 // Merge with existing forced policy, giving precedence to the existing
507 // forced policy.
508 new_forced_policy.Merge(forced_policy);
509 forced_policy.Swap(&new_forced_policy);
510 } else {
511 if (!ReadPRegFile(preg_file_path, &parsed_policy, status))
512 return false;
516 // Merge, give precedence to forced policy.
517 parsed_policy.Merge(forced_policy);
518 policy->Swap(&parsed_policy);
520 return true;
523 bool PolicyLoaderWin::ReadPolicyFromGPO(PolicyScope scope,
524 RegistryDict* policy,
525 PolicyLoadStatusSample* status) {
526 PGROUP_POLICY_OBJECT policy_object_list = NULL;
527 DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0;
528 if (gpo_provider_->GetAppliedGPOList(
529 flags, NULL, NULL, &kRegistrySettingsCSEGUID,
530 &policy_object_list) != ERROR_SUCCESS) {
531 PLOG(ERROR) << "GetAppliedGPOList scope " << scope;
532 status->Add(POLICY_LOAD_STATUS_QUERY_FAILED);
533 return false;
536 bool result = true;
537 if (policy_object_list) {
538 result = LoadGPOPolicy(scope, policy_object_list, policy, status);
539 if (!gpo_provider_->FreeGPOList(policy_object_list))
540 LOG(WARNING) << "FreeGPOList";
541 } else {
542 status->Add(POLICY_LOAD_STATUS_NO_POLICY);
545 return result;
548 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict,
549 PolicyLevel level,
550 PolicyScope scope,
551 PolicyMap* chrome_policy_map) {
552 PolicyMap policy;
553 const Schema* chrome_schema =
554 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
555 ParsePolicy(gpo_dict, level, scope, *chrome_schema, &policy);
556 FilterUntrustedPolicy(&policy);
557 chrome_policy_map->MergeFrom(policy);
560 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict,
561 PolicyScope scope,
562 PolicyBundle* bundle) {
563 // Map of known 3rd party policy domain name to their enum values.
564 static const struct {
565 const char* name;
566 PolicyDomain domain;
567 } k3rdPartyDomains[] = {
568 { "extensions", POLICY_DOMAIN_EXTENSIONS },
571 // Policy level and corresponding path.
572 static const struct {
573 PolicyLevel level;
574 const char* path;
575 } kLevels[] = {
576 { POLICY_LEVEL_MANDATORY, kKeyMandatory },
577 { POLICY_LEVEL_RECOMMENDED, kKeyRecommended },
580 for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) {
581 const char* name = k3rdPartyDomains[i].name;
582 const PolicyDomain domain = k3rdPartyDomains[i].domain;
583 const RegistryDict* domain_dict = gpo_dict->GetKey(name);
584 if (!domain_dict)
585 continue;
587 for (RegistryDict::KeyMap::const_iterator component(
588 domain_dict->keys().begin());
589 component != domain_dict->keys().end();
590 ++component) {
591 const PolicyNamespace policy_namespace(domain, component->first);
593 const Schema* schema_from_map = schema_map()->GetSchema(policy_namespace);
594 if (!schema_from_map) {
595 // This extension isn't installed or doesn't support policies.
596 continue;
598 Schema schema = *schema_from_map;
600 if (!schema.valid() &&
601 policy_namespace.domain == POLICY_DOMAIN_EXTENSIONS &&
602 policy_namespace.component_id == kLegacyBrowserSupportExtensionId) {
603 // TODO(joaodasilva): remove this special treatment for LBS by M35.
604 std::string schema_json;
605 const base::Value* value = component->second->GetValue(kKeySchema);
606 if (value && value->GetAsString(&schema_json)) {
607 std::string error;
608 schema = Schema::Parse(PatchSchema(schema_json), &error);
609 if (!schema.valid())
610 LOG(WARNING) << "Invalid schema in the registry for LBS: " << error;
614 // Parse policy.
615 for (size_t j = 0; j < arraysize(kLevels); j++) {
616 const RegistryDict* policy_dict =
617 component->second->GetKey(kLevels[j].path);
618 if (!policy_dict)
619 continue;
621 PolicyMap policy;
622 ParsePolicy(policy_dict, kLevels[j].level, scope, schema, &policy);
623 bundle->Get(policy_namespace).MergeFrom(policy);
629 void PolicyLoaderWin::SetupWatches() {
630 DCHECK(is_initialized_);
631 if (!user_policy_watcher_failed_ &&
632 !user_policy_watcher_.GetWatchedObject() &&
633 !user_policy_watcher_.StartWatching(
634 user_policy_changed_event_.handle(), this)) {
635 DLOG(WARNING) << "Failed to start watch for user policy change event";
636 user_policy_watcher_failed_ = true;
638 if (!machine_policy_watcher_failed_ &&
639 !machine_policy_watcher_.GetWatchedObject() &&
640 !machine_policy_watcher_.StartWatching(
641 machine_policy_changed_event_.handle(), this)) {
642 DLOG(WARNING) << "Failed to start watch for machine policy change event";
643 machine_policy_watcher_failed_ = true;
647 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
648 DCHECK(object == user_policy_changed_event_.handle() ||
649 object == machine_policy_changed_event_.handle())
650 << "unexpected object signaled policy reload, obj = "
651 << std::showbase << std::hex << object;
652 Reload(false);
655 } // namespace policy