cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / components / policy / core / common / policy_loader_win.cc
blob3516754f1460de3ba8267ca7506f6a07c1ed7ca8
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/files/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/metrics/sparse_histogram.h"
34 #include "base/scoped_native_library.h"
35 #include "base/sequenced_task_runner.h"
36 #include "base/stl_util.h"
37 #include "base/strings/string16.h"
38 #include "base/strings/string_util.h"
39 #include "base/values.h"
40 #include "base/win/win_util.h"
41 #include "base/win/windows_version.h"
42 #include "components/json_schema/json_schema_constants.h"
43 #include "components/policy/core/common/policy_bundle.h"
44 #include "components/policy/core/common/policy_load_status.h"
45 #include "components/policy/core/common/policy_map.h"
46 #include "components/policy/core/common/policy_namespace.h"
47 #include "components/policy/core/common/preg_parser_win.h"
48 #include "components/policy/core/common/registry_dict_win.h"
49 #include "components/policy/core/common/schema.h"
50 #include "policy/policy_constants.h"
52 namespace schema = json_schema_constants;
54 namespace policy {
56 namespace {
58 const char kKeyMandatory[] = "policy";
59 const char kKeyRecommended[] = "recommended";
60 const char kKeySchema[] = "schema";
61 const char kKeyThirdParty[] = "3rdparty";
63 // The Legacy Browser Support was the first user of the policy-for-extensions
64 // API, and relied on behavior that will be phased out. If this extension is
65 // present then its policies will be loaded in a special way.
66 // TODO(joaodasilva): remove this for M35. http://crbug.com/325349
67 const char kLegacyBrowserSupportExtensionId[] =
68 "heildphpnddilhkemkielfhnkaagiabh";
70 // The web store url that is the only trusted source for extensions.
71 const char kExpectedWebStoreUrl[] =
72 ";https://clients2.google.com/service/update2/crx";
73 // String to be prepended to each blocked entry.
74 const char kBlockedExtensionPrefix[] = "[BLOCKED]";
76 // List of policies that are considered only if the user is part of a AD domain.
77 // Please document any new additions in policy_templates.json!
78 const char* kInsecurePolicies[] = {
79 key::kMetricsReportingEnabled,
80 key::kDefaultSearchProviderEnabled,
81 key::kHomepageIsNewTabPage,
82 key::kHomepageLocation,
83 key::kRestoreOnStartup,
84 key::kRestoreOnStartupURLs
87 #pragma warning(push)
88 #pragma warning(disable: 4068) // unknown pragmas
89 // TODO(dcheng): Remove pragma once http://llvm.org/PR24007 is fixed.
90 #pragma clang diagnostic ignored "-Wmissing-braces"
91 // The GUID of the registry settings group policy extension.
92 GUID kRegistrySettingsCSEGUID = REGISTRY_EXTENSION_GUID;
93 #pragma warning(pop)
95 // The list of possible errors that can occur while collecting information about
96 // the current enterprise environment.
97 // This enum is used to define the buckets for an enumerated UMA histogram.
98 // Hence,
99 // (a) existing enumerated constants should never be deleted or reordered, and
100 // (b) new constants should only be appended at the end of the enumeration.
101 enum DomainCheckErrors {
102 DOMAIN_CHECK_ERROR_GET_JOIN_INFO = 0,
103 DOMAIN_CHECK_ERROR_DS_BIND = 1,
104 DOMAIN_CHECK_ERROR_SIZE, // Not a DomainCheckError. Must be last.
107 // If the LBS extension is found and contains a schema in the registry then this
108 // function is used to patch it, and make it compliant. The fix is to
109 // add an "items" attribute to lists that don't declare it.
110 std::string PatchSchema(const std::string& schema) {
111 base::JSONParserOptions options = base::JSON_PARSE_RFC;
112 scoped_ptr<base::Value> json = base::JSONReader::Read(schema, options);
113 base::DictionaryValue* dict = NULL;
114 base::DictionaryValue* properties = NULL;
115 if (!json ||
116 !json->GetAsDictionary(&dict) ||
117 !dict->GetDictionary(schema::kProperties, &properties)) {
118 return schema;
121 for (base::DictionaryValue::Iterator it(*properties);
122 !it.IsAtEnd(); it.Advance()) {
123 base::DictionaryValue* policy_schema = NULL;
124 std::string type;
125 if (properties->GetDictionary(it.key(), &policy_schema) &&
126 policy_schema->GetString(schema::kType, &type) &&
127 type == schema::kArray &&
128 !policy_schema->HasKey(schema::kItems)) {
129 scoped_ptr<base::DictionaryValue> items(new base::DictionaryValue());
130 items->SetString(schema::kType, schema::kString);
131 policy_schema->Set(schema::kItems, items.release());
135 std::string serialized;
136 base::JSONWriter::Write(*json, &serialized);
137 return serialized;
140 // Verifies that untrusted policies contain only safe values. Modifies the
141 // |policy| in place.
142 void FilterUntrustedPolicy(PolicyMap* policy) {
143 if (base::win::IsEnrolledToDomain())
144 return;
146 int invalid_policies = 0;
147 const PolicyMap::Entry* map_entry =
148 policy->Get(key::kExtensionInstallForcelist);
149 if (map_entry && map_entry->value) {
150 const base::ListValue* policy_list_value = NULL;
151 if (!map_entry->value->GetAsList(&policy_list_value))
152 return;
154 scoped_ptr<base::ListValue> filtered_values(new base::ListValue);
155 for (base::ListValue::const_iterator list_entry(policy_list_value->begin());
156 list_entry != policy_list_value->end(); ++list_entry) {
157 std::string entry;
158 if (!(*list_entry)->GetAsString(&entry))
159 continue;
160 size_t pos = entry.find(';');
161 if (pos == std::string::npos)
162 continue;
163 // Only allow custom update urls in enterprise environments.
164 if (!base::LowerCaseEqualsASCII(entry.substr(pos),
165 kExpectedWebStoreUrl)) {
166 entry = kBlockedExtensionPrefix + entry;
167 invalid_policies++;
170 filtered_values->AppendString(entry);
172 if (invalid_policies) {
173 policy->Set(key::kExtensionInstallForcelist,
174 map_entry->level, map_entry->scope,
175 filtered_values.release(),
176 map_entry->external_data_fetcher);
178 const PolicyDetails* details = GetChromePolicyDetails(
179 key::kExtensionInstallForcelist);
180 UMA_HISTOGRAM_SPARSE_SLOWLY("EnterpriseCheck.InvalidPolicies",
181 details->id);
185 for (size_t i = 0; i < arraysize(kInsecurePolicies); ++i) {
186 if (policy->Get(kInsecurePolicies[i])) {
187 // TODO(pastarmovj): Surface this issue in the about:policy page.
188 policy->Erase(kInsecurePolicies[i]);
189 invalid_policies++;
190 const PolicyDetails* details =
191 GetChromePolicyDetails(kInsecurePolicies[i]);
192 UMA_HISTOGRAM_SPARSE_SLOWLY("EnterpriseCheck.InvalidPolicies",
193 details->id);
197 UMA_HISTOGRAM_COUNTS("EnterpriseCheck.InvalidPoliciesDetected",
198 invalid_policies);
201 // A helper class encapsulating run-time-linked function calls to Wow64 APIs.
202 class Wow64Functions {
203 public:
204 Wow64Functions()
205 : kernel32_lib_(base::FilePath(L"kernel32")),
206 is_wow_64_process_(NULL),
207 wow_64_disable_wow_64_fs_redirection_(NULL),
208 wow_64_revert_wow_64_fs_redirection_(NULL) {
209 if (kernel32_lib_.is_valid()) {
210 is_wow_64_process_ = reinterpret_cast<IsWow64Process>(
211 kernel32_lib_.GetFunctionPointer("IsWow64Process"));
212 wow_64_disable_wow_64_fs_redirection_ =
213 reinterpret_cast<Wow64DisableWow64FSRedirection>(
214 kernel32_lib_.GetFunctionPointer(
215 "Wow64DisableWow64FsRedirection"));
216 wow_64_revert_wow_64_fs_redirection_ =
217 reinterpret_cast<Wow64RevertWow64FSRedirection>(
218 kernel32_lib_.GetFunctionPointer(
219 "Wow64RevertWow64FsRedirection"));
223 bool is_valid() {
224 return is_wow_64_process_ &&
225 wow_64_disable_wow_64_fs_redirection_ &&
226 wow_64_revert_wow_64_fs_redirection_;
229 bool IsWow64() {
230 BOOL result = 0;
231 if (!is_wow_64_process_(GetCurrentProcess(), &result))
232 PLOG(WARNING) << "IsWow64ProcFailed";
233 return !!result;
236 bool DisableFsRedirection(PVOID* previous_state) {
237 return !!wow_64_disable_wow_64_fs_redirection_(previous_state);
240 bool RevertFsRedirection(PVOID previous_state) {
241 return !!wow_64_revert_wow_64_fs_redirection_(previous_state);
244 private:
245 typedef BOOL (WINAPI* IsWow64Process)(HANDLE, PBOOL);
246 typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
247 typedef BOOL (WINAPI* Wow64RevertWow64FSRedirection)(PVOID);
249 base::ScopedNativeLibrary kernel32_lib_;
251 IsWow64Process is_wow_64_process_;
252 Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection_;
253 Wow64RevertWow64FSRedirection wow_64_revert_wow_64_fs_redirection_;
255 DISALLOW_COPY_AND_ASSIGN(Wow64Functions);
258 // Global Wow64Function instance used by ScopedDisableWow64Redirection below.
259 static base::LazyInstance<Wow64Functions> g_wow_64_functions =
260 LAZY_INSTANCE_INITIALIZER;
262 // Scoper that switches off Wow64 File System Redirection during its lifetime.
263 class ScopedDisableWow64Redirection {
264 public:
265 ScopedDisableWow64Redirection()
266 : active_(false),
267 previous_state_(NULL) {
268 Wow64Functions* wow64 = g_wow_64_functions.Pointer();
269 if (wow64->is_valid() && wow64->IsWow64()) {
270 if (wow64->DisableFsRedirection(&previous_state_))
271 active_ = true;
272 else
273 PLOG(WARNING) << "Wow64DisableWow64FSRedirection";
277 ~ScopedDisableWow64Redirection() {
278 if (active_)
279 CHECK(g_wow_64_functions.Get().RevertFsRedirection(previous_state_));
282 bool is_active() { return active_; }
284 private:
285 bool active_;
286 PVOID previous_state_;
288 DISALLOW_COPY_AND_ASSIGN(ScopedDisableWow64Redirection);
291 // AppliedGPOListProvider implementation that calls actual Windows APIs.
292 class WinGPOListProvider : public AppliedGPOListProvider {
293 public:
294 ~WinGPOListProvider() override {}
296 // AppliedGPOListProvider:
297 DWORD GetAppliedGPOList(DWORD flags,
298 LPCTSTR machine_name,
299 PSID sid_user,
300 GUID* extension_guid,
301 PGROUP_POLICY_OBJECT* gpo_list) override {
302 return ::GetAppliedGPOList(flags, machine_name, sid_user, extension_guid,
303 gpo_list);
306 BOOL FreeGPOList(PGROUP_POLICY_OBJECT gpo_list) override {
307 return ::FreeGPOList(gpo_list);
311 // The default windows GPO list provider used for PolicyLoaderWin.
312 static base::LazyInstance<WinGPOListProvider> g_win_gpo_list_provider =
313 LAZY_INSTANCE_INITIALIZER;
315 // Parses |gpo_dict| according to |schema| and writes the resulting policy
316 // settings to |policy| for the given |scope| and |level|.
317 void ParsePolicy(const RegistryDict* gpo_dict,
318 PolicyLevel level,
319 PolicyScope scope,
320 const Schema& schema,
321 PolicyMap* policy) {
322 if (!gpo_dict)
323 return;
325 scoped_ptr<base::Value> policy_value(gpo_dict->ConvertToJSON(schema));
326 const base::DictionaryValue* policy_dict = NULL;
327 if (!policy_value->GetAsDictionary(&policy_dict) || !policy_dict) {
328 LOG(WARNING) << "Root policy object is not a dictionary!";
329 return;
332 policy->LoadFrom(policy_dict, level, scope);
335 // Collects stats about the enterprise environment that can be used to decide
336 // how to parse the existing policy information.
337 void CollectEnterpriseUMAs() {
338 // Collect statistics about the windows suite.
339 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.OSType",
340 base::win::OSInfo::GetInstance()->version_type(),
341 base::win::SUITE_LAST);
343 // Get the computer's domain status.
344 LPWSTR domain;
345 NETSETUP_JOIN_STATUS join_status;
346 if (NERR_Success != ::NetGetJoinInformation(NULL, &domain, &join_status)) {
347 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.DomainCheckFailed",
348 DOMAIN_CHECK_ERROR_GET_JOIN_INFO,
349 DOMAIN_CHECK_ERROR_SIZE);
350 return;
352 ::NetApiBufferFree(domain);
354 bool in_domain = join_status == NetSetupDomainName;
355 UMA_HISTOGRAM_BOOLEAN("EnterpriseCheck.InDomain", in_domain);
356 if (in_domain) {
357 // This check will tell us how often are domain computers actually
358 // connected to the enterprise network while Chrome is running.
359 HANDLE server_bind;
360 if (ERROR_SUCCESS == ::DsBind(NULL, NULL, &server_bind)) {
361 UMA_HISTOGRAM_COUNTS("EnterpriseCheck.DomainBindSucceeded", 1);
362 ::DsUnBind(&server_bind);
363 } else {
364 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.DomainCheckFailed",
365 DOMAIN_CHECK_ERROR_DS_BIND,
366 DOMAIN_CHECK_ERROR_SIZE);
371 } // namespace
373 const base::FilePath::CharType PolicyLoaderWin::kPRegFileName[] =
374 FILE_PATH_LITERAL("Registry.pol");
376 PolicyLoaderWin::PolicyLoaderWin(
377 scoped_refptr<base::SequencedTaskRunner> task_runner,
378 const base::string16& chrome_policy_key,
379 AppliedGPOListProvider* gpo_provider)
380 : AsyncPolicyLoader(task_runner),
381 is_initialized_(false),
382 chrome_policy_key_(chrome_policy_key),
383 gpo_provider_(gpo_provider),
384 user_policy_changed_event_(false, false),
385 machine_policy_changed_event_(false, false),
386 user_policy_watcher_failed_(false),
387 machine_policy_watcher_failed_(false) {
388 if (!::RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
389 DPLOG(WARNING) << "Failed to register user group policy notification";
390 user_policy_watcher_failed_ = true;
392 if (!::RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
393 DPLOG(WARNING) << "Failed to register machine group policy notification.";
394 machine_policy_watcher_failed_ = true;
398 PolicyLoaderWin::~PolicyLoaderWin() {
399 if (!user_policy_watcher_failed_) {
400 ::UnregisterGPNotification(user_policy_changed_event_.handle());
401 user_policy_watcher_.StopWatching();
403 if (!machine_policy_watcher_failed_) {
404 ::UnregisterGPNotification(machine_policy_changed_event_.handle());
405 machine_policy_watcher_.StopWatching();
409 // static
410 scoped_ptr<PolicyLoaderWin> PolicyLoaderWin::Create(
411 scoped_refptr<base::SequencedTaskRunner> task_runner,
412 const base::string16& chrome_policy_key) {
413 return make_scoped_ptr(
414 new PolicyLoaderWin(task_runner,
415 chrome_policy_key,
416 g_win_gpo_list_provider.Pointer()));
419 void PolicyLoaderWin::InitOnBackgroundThread() {
420 is_initialized_ = true;
421 SetupWatches();
422 CollectEnterpriseUMAs();
425 scoped_ptr<PolicyBundle> PolicyLoaderWin::Load() {
426 // Reset the watches BEFORE reading the individual policies to avoid
427 // missing a change notification.
428 if (is_initialized_)
429 SetupWatches();
431 // Policy scope and corresponding hive.
432 static const struct {
433 PolicyScope scope;
434 HKEY hive;
435 } kScopes[] = {
436 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE },
437 { POLICY_SCOPE_USER, HKEY_CURRENT_USER },
440 bool is_enterprise = base::win::IsEnrolledToDomain();
441 VLOG(1) << "Reading policy from the registry is "
442 << (is_enterprise ? "enabled." : "disabled.");
444 // Load policy data for the different scopes/levels and merge them.
445 scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
446 PolicyMap* chrome_policy =
447 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
448 for (size_t i = 0; i < arraysize(kScopes); ++i) {
449 PolicyScope scope = kScopes[i].scope;
450 PolicyLoadStatusSample status;
451 RegistryDict gpo_dict;
453 // Note: GPO rules mandate a call to EnterCriticalPolicySection() here, and
454 // a matching LeaveCriticalPolicySection() call below after the
455 // ReadPolicyFromGPO() block. Unfortunately, the policy mutex may be
456 // unavailable for extended periods of time, and there are reports of this
457 // happening in the wild: http://crbug.com/265862.
459 // Blocking for minutes is neither acceptable for Chrome startup, nor on
460 // the FILE thread on which this code runs in steady state. Given that
461 // there have never been any reports of issues due to partially-applied /
462 // corrupt group policy, this code intentionally omits the
463 // EnterCriticalPolicySection() call.
465 // If there's ever reason to revisit this decision, one option could be to
466 // make the EnterCriticalPolicySection() call on a dedicated thread and
467 // timeout on it more aggressively. For now, there's no justification for
468 // the additional effort this would introduce.
470 bool is_registry_forced = is_enterprise || gpo_provider_ == nullptr;
471 if (is_registry_forced || !ReadPolicyFromGPO(scope, &gpo_dict, &status)) {
472 VLOG_IF(1, !is_registry_forced) << "Failed to read GPO files for "
473 << scope << " falling back to registry.";
474 gpo_dict.ReadRegistry(kScopes[i].hive, chrome_policy_key_);
477 // Remove special-cased entries from the GPO dictionary.
478 scoped_ptr<RegistryDict> recommended_dict(
479 gpo_dict.RemoveKey(kKeyRecommended));
480 scoped_ptr<RegistryDict> third_party_dict(
481 gpo_dict.RemoveKey(kKeyThirdParty));
483 // Load Chrome policy.
484 LoadChromePolicy(&gpo_dict, POLICY_LEVEL_MANDATORY, scope, chrome_policy);
485 LoadChromePolicy(recommended_dict.get(), POLICY_LEVEL_RECOMMENDED, scope,
486 chrome_policy);
488 // Load 3rd-party policy.
489 if (third_party_dict)
490 Load3rdPartyPolicy(third_party_dict.get(), scope, bundle.get());
493 return bundle.Pass();
496 bool PolicyLoaderWin::ReadPRegFile(const base::FilePath& preg_file,
497 RegistryDict* policy,
498 PolicyLoadStatusSample* status) {
499 // The following deals with the minor annoyance that Wow64 FS redirection
500 // might need to be turned off: This is the case if running as a 32-bit
501 // process on a 64-bit system, in which case Wow64 FS redirection redirects
502 // access to the %WINDIR%/System32/GroupPolicy directory to
503 // %WINDIR%/SysWOW64/GroupPolicy, but the file is actually in the
504 // system-native directory.
505 if (base::PathExists(preg_file)) {
506 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy, status);
507 } else {
508 // Try with redirection switched off.
509 ScopedDisableWow64Redirection redirection_disable;
510 if (redirection_disable.is_active() && base::PathExists(preg_file)) {
511 status->Add(POLICY_LOAD_STATUS_WOW64_REDIRECTION_DISABLED);
512 return preg_parser::ReadFile(preg_file, chrome_policy_key_, policy,
513 status);
517 // Report the error.
518 LOG(ERROR) << "PReg file doesn't exist: " << preg_file.value();
519 status->Add(POLICY_LOAD_STATUS_MISSING);
520 return false;
523 bool PolicyLoaderWin::LoadGPOPolicy(PolicyScope scope,
524 PGROUP_POLICY_OBJECT policy_object_list,
525 RegistryDict* policy,
526 PolicyLoadStatusSample* status) {
527 RegistryDict parsed_policy;
528 RegistryDict forced_policy;
529 for (GROUP_POLICY_OBJECT* policy_object = policy_object_list;
530 policy_object; policy_object = policy_object->pNext) {
531 if (policy_object->dwOptions & GPO_FLAG_DISABLE)
532 continue;
534 if (PathIsUNC(policy_object->lpFileSysPath)) {
535 // UNC path: Assume this is an AD-managed machine, which updates the
536 // registry via GPO's standard registry CSE periodically. Fall back to
537 // reading from the registry in this case.
538 status->Add(POLICY_LOAD_STATUS_INACCCESSIBLE);
539 return false;
542 base::FilePath preg_file_path(
543 base::FilePath(policy_object->lpFileSysPath).Append(kPRegFileName));
544 if (policy_object->dwOptions & GPO_FLAG_FORCE) {
545 RegistryDict new_forced_policy;
546 if (!ReadPRegFile(preg_file_path, &new_forced_policy, status))
547 return false;
549 // Merge with existing forced policy, giving precedence to the existing
550 // forced policy.
551 new_forced_policy.Merge(forced_policy);
552 forced_policy.Swap(&new_forced_policy);
553 } else {
554 if (!ReadPRegFile(preg_file_path, &parsed_policy, status))
555 return false;
559 // Merge, give precedence to forced policy.
560 parsed_policy.Merge(forced_policy);
561 policy->Swap(&parsed_policy);
563 return true;
566 bool PolicyLoaderWin::ReadPolicyFromGPO(PolicyScope scope,
567 RegistryDict* policy,
568 PolicyLoadStatusSample* status) {
569 PGROUP_POLICY_OBJECT policy_object_list = NULL;
570 DWORD flags = scope == POLICY_SCOPE_MACHINE ? GPO_LIST_FLAG_MACHINE : 0;
571 if (gpo_provider_->GetAppliedGPOList(
572 flags, NULL, NULL, &kRegistrySettingsCSEGUID,
573 &policy_object_list) != ERROR_SUCCESS) {
574 PLOG(ERROR) << "GetAppliedGPOList scope " << scope;
575 status->Add(POLICY_LOAD_STATUS_QUERY_FAILED);
576 return false;
579 bool result = true;
580 if (policy_object_list) {
581 result = LoadGPOPolicy(scope, policy_object_list, policy, status);
582 if (!gpo_provider_->FreeGPOList(policy_object_list))
583 LOG(WARNING) << "FreeGPOList";
584 } else {
585 status->Add(POLICY_LOAD_STATUS_NO_POLICY);
588 return result;
591 void PolicyLoaderWin::LoadChromePolicy(const RegistryDict* gpo_dict,
592 PolicyLevel level,
593 PolicyScope scope,
594 PolicyMap* chrome_policy_map) {
595 PolicyMap policy;
596 const Schema* chrome_schema =
597 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
598 ParsePolicy(gpo_dict, level, scope, *chrome_schema, &policy);
599 FilterUntrustedPolicy(&policy);
600 chrome_policy_map->MergeFrom(policy);
603 void PolicyLoaderWin::Load3rdPartyPolicy(const RegistryDict* gpo_dict,
604 PolicyScope scope,
605 PolicyBundle* bundle) {
606 // Map of known 3rd party policy domain name to their enum values.
607 static const struct {
608 const char* name;
609 PolicyDomain domain;
610 } k3rdPartyDomains[] = {
611 { "extensions", POLICY_DOMAIN_EXTENSIONS },
614 // Policy level and corresponding path.
615 static const struct {
616 PolicyLevel level;
617 const char* path;
618 } kLevels[] = {
619 { POLICY_LEVEL_MANDATORY, kKeyMandatory },
620 { POLICY_LEVEL_RECOMMENDED, kKeyRecommended },
623 for (size_t i = 0; i < arraysize(k3rdPartyDomains); i++) {
624 const char* name = k3rdPartyDomains[i].name;
625 const PolicyDomain domain = k3rdPartyDomains[i].domain;
626 const RegistryDict* domain_dict = gpo_dict->GetKey(name);
627 if (!domain_dict)
628 continue;
630 for (RegistryDict::KeyMap::const_iterator component(
631 domain_dict->keys().begin());
632 component != domain_dict->keys().end();
633 ++component) {
634 const PolicyNamespace policy_namespace(domain, component->first);
636 const Schema* schema_from_map = schema_map()->GetSchema(policy_namespace);
637 if (!schema_from_map) {
638 // This extension isn't installed or doesn't support policies.
639 continue;
641 Schema schema = *schema_from_map;
643 if (!schema.valid() &&
644 policy_namespace.domain == POLICY_DOMAIN_EXTENSIONS &&
645 policy_namespace.component_id == kLegacyBrowserSupportExtensionId) {
646 // TODO(joaodasilva): remove this special treatment for LBS by M35.
647 std::string schema_json;
648 const base::Value* value = component->second->GetValue(kKeySchema);
649 if (value && value->GetAsString(&schema_json)) {
650 std::string error;
651 schema = Schema::Parse(PatchSchema(schema_json), &error);
652 if (!schema.valid())
653 LOG(WARNING) << "Invalid schema in the registry for LBS: " << error;
657 // Parse policy.
658 for (size_t j = 0; j < arraysize(kLevels); j++) {
659 const RegistryDict* policy_dict =
660 component->second->GetKey(kLevels[j].path);
661 if (!policy_dict)
662 continue;
664 PolicyMap policy;
665 ParsePolicy(policy_dict, kLevels[j].level, scope, schema, &policy);
666 bundle->Get(policy_namespace).MergeFrom(policy);
672 void PolicyLoaderWin::SetupWatches() {
673 DCHECK(is_initialized_);
674 if (!user_policy_watcher_failed_ &&
675 !user_policy_watcher_.GetWatchedObject() &&
676 !user_policy_watcher_.StartWatching(
677 user_policy_changed_event_.handle(), this)) {
678 DLOG(WARNING) << "Failed to start watch for user policy change event";
679 user_policy_watcher_failed_ = true;
681 if (!machine_policy_watcher_failed_ &&
682 !machine_policy_watcher_.GetWatchedObject() &&
683 !machine_policy_watcher_.StartWatching(
684 machine_policy_changed_event_.handle(), this)) {
685 DLOG(WARNING) << "Failed to start watch for machine policy change event";
686 machine_policy_watcher_failed_ = true;
690 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) {
691 DCHECK(object == user_policy_changed_event_.handle() ||
692 object == machine_policy_changed_event_.handle())
693 << "unexpected object signaled policy reload, obj = "
694 << std::showbase << std::hex << object;
695 Reload(false);
698 } // namespace policy