| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 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 | 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 <ntdsapi.h> // For Ds[Un]Bind | 8 #include <ntdsapi.h> // For Ds[Un]Bind |
| 9 #include <rpc.h> // For struct GUID | 9 #include <rpc.h> // For struct GUID |
| 10 #include <shlwapi.h> // For PathIsUNC() | 10 #include <shlwapi.h> // For PathIsUNC() |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 // Hence, | 85 // Hence, |
| 86 // (a) existing enumerated constants should never be deleted or reordered, and | 86 // (a) existing enumerated constants should never be deleted or reordered, and |
| 87 // (b) new constants should only be appended at the end of the enumeration. | 87 // (b) new constants should only be appended at the end of the enumeration. |
| 88 enum DomainCheckErrors { | 88 enum DomainCheckErrors { |
| 89 // The check error below is no longer possible. | 89 // The check error below is no longer possible. |
| 90 DEPRECATED_DOMAIN_CHECK_ERROR_GET_JOIN_INFO = 0, | 90 DEPRECATED_DOMAIN_CHECK_ERROR_GET_JOIN_INFO = 0, |
| 91 DOMAIN_CHECK_ERROR_DS_BIND = 1, | 91 DOMAIN_CHECK_ERROR_DS_BIND = 1, |
| 92 DOMAIN_CHECK_ERROR_SIZE, // Not a DomainCheckError. Must be last. | 92 DOMAIN_CHECK_ERROR_SIZE, // Not a DomainCheckError. Must be last. |
| 93 }; | 93 }; |
| 94 | 94 |
| 95 bool ShouldHonorPolicies() { |
| 96 return base::win::IsEnterpriseUser(); |
| 97 } |
| 98 |
| 95 // Verifies that untrusted policies contain only safe values. Modifies the | 99 // Verifies that untrusted policies contain only safe values. Modifies the |
| 96 // |policy| in place. | 100 // |policy| in place. |
| 97 void FilterUntrustedPolicy(PolicyMap* policy) { | 101 void FilterUntrustedPolicy(PolicyMap* policy) { |
| 98 if (base::win::IsEnrolledToDomain()) | 102 if (ShouldHonorPolicies()) |
| 99 return; | 103 return; |
| 100 | 104 |
| 101 int invalid_policies = 0; | 105 int invalid_policies = 0; |
| 102 const PolicyMap::Entry* map_entry = | 106 const PolicyMap::Entry* map_entry = |
| 103 policy->Get(key::kExtensionInstallForcelist); | 107 policy->Get(key::kExtensionInstallForcelist); |
| 104 if (map_entry && map_entry->value) { | 108 if (map_entry && map_entry->value) { |
| 105 const base::ListValue* policy_list_value = NULL; | 109 const base::ListValue* policy_list_value = NULL; |
| 106 if (!map_entry->value->GetAsList(&policy_list_value)) | 110 if (!map_entry->value->GetAsList(&policy_list_value)) |
| 107 return; | 111 return; |
| 108 | 112 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 } | 290 } |
| 287 | 291 |
| 288 // Collects stats about the enterprise environment that can be used to decide | 292 // Collects stats about the enterprise environment that can be used to decide |
| 289 // how to parse the existing policy information. | 293 // how to parse the existing policy information. |
| 290 void CollectEnterpriseUMAs() { | 294 void CollectEnterpriseUMAs() { |
| 291 // Collect statistics about the windows suite. | 295 // Collect statistics about the windows suite. |
| 292 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.OSType", | 296 UMA_HISTOGRAM_ENUMERATION("EnterpriseCheck.OSType", |
| 293 base::win::OSInfo::GetInstance()->version_type(), | 297 base::win::OSInfo::GetInstance()->version_type(), |
| 294 base::win::SUITE_LAST); | 298 base::win::SUITE_LAST); |
| 295 | 299 |
| 296 bool in_domain = base::win::IsEnrolledToDomain(); | 300 UMA_HISTOGRAM_BOOLEAN("EnterpriseCheck.InDomain", ShouldHonorPolicies()); |
| 297 UMA_HISTOGRAM_BOOLEAN("EnterpriseCheck.InDomain", in_domain); | |
| 298 } | 301 } |
| 299 | 302 |
| 300 } // namespace | 303 } // namespace |
| 301 | 304 |
| 302 const base::FilePath::CharType PolicyLoaderWin::kPRegFileName[] = | 305 const base::FilePath::CharType PolicyLoaderWin::kPRegFileName[] = |
| 303 FILE_PATH_LITERAL("Registry.pol"); | 306 FILE_PATH_LITERAL("Registry.pol"); |
| 304 | 307 |
| 305 PolicyLoaderWin::PolicyLoaderWin( | 308 PolicyLoaderWin::PolicyLoaderWin( |
| 306 scoped_refptr<base::SequencedTaskRunner> task_runner, | 309 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 307 const base::string16& chrome_policy_key, | 310 const base::string16& chrome_policy_key, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 | 364 |
| 362 // Policy scope and corresponding hive. | 365 // Policy scope and corresponding hive. |
| 363 static const struct { | 366 static const struct { |
| 364 PolicyScope scope; | 367 PolicyScope scope; |
| 365 HKEY hive; | 368 HKEY hive; |
| 366 } kScopes[] = { | 369 } kScopes[] = { |
| 367 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, | 370 { POLICY_SCOPE_MACHINE, HKEY_LOCAL_MACHINE }, |
| 368 { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, | 371 { POLICY_SCOPE_USER, HKEY_CURRENT_USER }, |
| 369 }; | 372 }; |
| 370 | 373 |
| 371 bool is_enterprise = base::win::IsEnrolledToDomain(); | 374 bool honor_policies = ShouldHonorPolicies(); |
| 372 VLOG(1) << "Reading policy from the registry is " | 375 VLOG(1) << "Reading policy from the registry is " |
| 373 << (is_enterprise ? "enabled." : "disabled."); | 376 << (honor_policies ? "enabled." : "disabled."); |
| 374 | 377 |
| 375 // Load policy data for the different scopes/levels and merge them. | 378 // Load policy data for the different scopes/levels and merge them. |
| 376 std::unique_ptr<PolicyBundle> bundle(new PolicyBundle()); | 379 std::unique_ptr<PolicyBundle> bundle(new PolicyBundle()); |
| 377 PolicyMap* chrome_policy = | 380 PolicyMap* chrome_policy = |
| 378 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); | 381 &bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); |
| 379 for (size_t i = 0; i < arraysize(kScopes); ++i) { | 382 for (size_t i = 0; i < arraysize(kScopes); ++i) { |
| 380 PolicyScope scope = kScopes[i].scope; | 383 PolicyScope scope = kScopes[i].scope; |
| 381 PolicyLoadStatusSample status; | 384 PolicyLoadStatusSample status; |
| 382 RegistryDict gpo_dict; | 385 RegistryDict gpo_dict; |
| 383 | 386 |
| 384 // Note: GPO rules mandate a call to EnterCriticalPolicySection() here, and | 387 // Note: GPO rules mandate a call to EnterCriticalPolicySection() here, and |
| 385 // a matching LeaveCriticalPolicySection() call below after the | 388 // a matching LeaveCriticalPolicySection() call below after the |
| 386 // ReadPolicyFromGPO() block. Unfortunately, the policy mutex may be | 389 // ReadPolicyFromGPO() block. Unfortunately, the policy mutex may be |
| 387 // unavailable for extended periods of time, and there are reports of this | 390 // unavailable for extended periods of time, and there are reports of this |
| 388 // happening in the wild: http://crbug.com/265862. | 391 // happening in the wild: http://crbug.com/265862. |
| 389 // | 392 // |
| 390 // Blocking for minutes is neither acceptable for Chrome startup, nor on | 393 // Blocking for minutes is neither acceptable for Chrome startup, nor on |
| 391 // the FILE thread on which this code runs in steady state. Given that | 394 // the FILE thread on which this code runs in steady state. Given that |
| 392 // there have never been any reports of issues due to partially-applied / | 395 // there have never been any reports of issues due to partially-applied / |
| 393 // corrupt group policy, this code intentionally omits the | 396 // corrupt group policy, this code intentionally omits the |
| 394 // EnterCriticalPolicySection() call. | 397 // EnterCriticalPolicySection() call. |
| 395 // | 398 // |
| 396 // If there's ever reason to revisit this decision, one option could be to | 399 // If there's ever reason to revisit this decision, one option could be to |
| 397 // make the EnterCriticalPolicySection() call on a dedicated thread and | 400 // make the EnterCriticalPolicySection() call on a dedicated thread and |
| 398 // timeout on it more aggressively. For now, there's no justification for | 401 // timeout on it more aggressively. For now, there's no justification for |
| 399 // the additional effort this would introduce. | 402 // the additional effort this would introduce. |
| 400 | 403 |
| 401 bool is_registry_forced = is_enterprise || gpo_provider_ == nullptr; | 404 bool is_registry_forced = honor_policies || gpo_provider_ == nullptr; |
| 402 if (is_registry_forced || !ReadPolicyFromGPO(scope, &gpo_dict, &status)) { | 405 if (is_registry_forced || !ReadPolicyFromGPO(scope, &gpo_dict, &status)) { |
| 403 VLOG_IF(1, !is_registry_forced) << "Failed to read GPO files for " | 406 VLOG_IF(1, !is_registry_forced) << "Failed to read GPO files for " |
| 404 << scope << " falling back to registry."; | 407 << scope << " falling back to registry."; |
| 405 gpo_dict.ReadRegistry(kScopes[i].hive, chrome_policy_key_); | 408 gpo_dict.ReadRegistry(kScopes[i].hive, chrome_policy_key_); |
| 406 } | 409 } |
| 407 | 410 |
| 408 // Remove special-cased entries from the GPO dictionary. | 411 // Remove special-cased entries from the GPO dictionary. |
| 409 std::unique_ptr<RegistryDict> recommended_dict( | 412 std::unique_ptr<RegistryDict> recommended_dict( |
| 410 gpo_dict.RemoveKey(kKeyRecommended)); | 413 gpo_dict.RemoveKey(kKeyRecommended)); |
| 411 std::unique_ptr<RegistryDict> third_party_dict( | 414 std::unique_ptr<RegistryDict> third_party_dict( |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 | 615 |
| 613 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { | 616 void PolicyLoaderWin::OnObjectSignaled(HANDLE object) { |
| 614 DCHECK(object == user_policy_changed_event_.handle() || | 617 DCHECK(object == user_policy_changed_event_.handle() || |
| 615 object == machine_policy_changed_event_.handle()) | 618 object == machine_policy_changed_event_.handle()) |
| 616 << "unexpected object signaled policy reload, obj = " | 619 << "unexpected object signaled policy reload, obj = " |
| 617 << std::showbase << std::hex << object; | 620 << std::showbase << std::hex << object; |
| 618 Reload(false); | 621 Reload(false); |
| 619 } | 622 } |
| 620 | 623 |
| 621 } // namespace policy | 624 } // namespace policy |
| OLD | NEW |