| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/google/google_update_policy_fetcher_win.h" |
| |
| #include <ATLComTime.h> |
| #include <wrl/client.h> |
| |
| #include <tuple> |
| #include <utility> |
| |
| #include "base/check_op.h" |
| #include "base/functional/bind.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util_win.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/com_init_util.h" |
| #include "base/win/scoped_bstr.h" |
| #include "chrome/browser/component_updater/updater_state.h" |
| #include "chrome/browser/google/google_update_policy_fetcher_win_util.h" |
| #include "chrome/install_static/install_util.h" |
| #include "chrome/updater/app/server/win/updater_legacy_idl.h" |
| #include "components/policy/core/common/policy_map.h" |
| #include "components/policy/core/common/policy_types.h" |
| #include "components/policy/core/common/schema.h" |
| #include "components/strings/grit/components_strings.h" |
| |
| namespace { |
| |
| // TODO(crbug.com/40271852): Add unit tests for these GoogleUpdate policies. |
| constexpr char kAutoUpdateCheckPeriodMinutes[] = "AutoUpdateCheckPeriodMinutes"; |
| constexpr char kDownloadPreference[] = "DownloadPreference"; |
| constexpr char kForceInstallApps[] = "ForceInstallApps"; |
| constexpr char kInstallPolicy[] = "InstallPolicy"; |
| constexpr char kProxyMode[] = "ProxyMode"; |
| constexpr char kProxyPacUrl[] = "ProxyPacUrl"; |
| constexpr char kProxyServer[] = "ProxyServer"; |
| constexpr char kRollbackToTargetVersion[] = "RollbackToTargetVersion"; |
| constexpr char kTargetVersionPrefix[] = "TargetVersionPrefix"; |
| constexpr char kTargetChannel[] = "TargetChannel"; |
| constexpr char kUpdatePolicy[] = "UpdatePolicy"; |
| constexpr char kUpdatesSuppressedDurationMin[] = "UpdatesSuppressedDurationMin"; |
| constexpr char kUpdatesSuppressedStartHour[] = "UpdatesSuppressedStartHour"; |
| constexpr char kUpdatesSuppressedStartMinute[] = "UpdatesSuppressedStartMinute"; |
| constexpr char kCloudPolicyOverridesPlatformPolicy[] = |
| "CloudPolicyOverridesPlatformPolicy"; |
| |
| // Adds the policy |policy_name| extracted from |policy| into |policies|. |
| // |value_override_function| is an optional function that modifies and overrides |
| // the value of the policy that needs to be store in |policies|. This function |
| // may be used to convert the extracted value, that is always a string into |
| // other types or formats. |
| void AddPolicy(const char* policy_name, |
| IPolicyStatusValue* policy, |
| policy::PolicyMap& policies, |
| const PolicyValueOverrideFunction& value_override_function = |
| PolicyValueOverrideFunction()) { |
| auto policy_entry = |
| ConvertPolicyStatusValueToPolicyEntry(policy, value_override_function); |
| if (policy_entry) { |
| policies.Set(policy_name, std::move(*policy_entry)); |
| } |
| } |
| |
| base::Time DateToTime(DATE date) { |
| ::COleDateTime date_time(date); |
| base::Time time; |
| if (date_time.m_status == ::COleDateTime::valid) { |
| std::ignore = base::Time::FromLocalExploded( |
| {date_time.GetYear(), date_time.GetMonth(), date_time.GetDayOfWeek(), |
| date_time.GetDay(), date_time.GetHour(), date_time.GetMinute(), |
| date_time.GetSecond(), 0}, |
| &time); |
| } |
| return time; |
| } |
| |
| // Returns the policies from GoogleUpdate. Requires GoogleUpdate |
| // version 1.3.36.91 (released 07-02-2021) or newer. |
| std::unique_ptr<policy::PolicyMap> GetGoogleUpdatePolicies( |
| IPolicyStatus3* policy_status) { |
| DCHECK(policy_status); |
| |
| policy_status->refreshPolicies(); |
| auto policies = std::make_unique<policy::PolicyMap>(); |
| base::win::ScopedBstr app_id(install_static::GetAppGuid()); |
| |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_lastCheckPeriodMinutes(&policy))) { |
| AddPolicy(kAutoUpdateCheckPeriodMinutes, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_downloadPreferenceGroupPolicy(&policy))) { |
| AddPolicy(kDownloadPreference, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatus4> policy_status4; |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->QueryInterface( |
| install_static::IsSystemInstall() ? __uuidof(IPolicyStatus4System) |
| : __uuidof(IPolicyStatus4User), |
| IID_PPV_ARGS_Helper(&policy_status4))) && |
| SUCCEEDED( |
| policy_status4->get_cloudPolicyOverridesPlatformPolicy(&policy))) { |
| AddPolicy(kCloudPolicyOverridesPlatformPolicy, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_forceInstallApps( |
| install_static::IsSystemInstall(), &policy))) { |
| AddPolicy(kForceInstallApps, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_effectivePolicyForAppInstalls(app_id.Get(), |
| &policy))) { |
| AddPolicy(kInstallPolicy, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_effectivePolicyForAppUpdates(app_id.Get(), |
| &policy))) { |
| AddPolicy(kUpdatePolicy, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| VARIANT_BOOL are_updates_suppressed = VARIANT_FALSE; |
| if (SUCCEEDED(policy_status->get_updatesSuppressedTimes( |
| &policy, &are_updates_suppressed))) { |
| // A function that extracts the |index|-th value from a comma-separated |
| // |initial_value|. |
| const auto extract_value = [](int index, BSTR initial_value) { |
| auto split = base::SplitString( |
| initial_value, L",", base::WhitespaceHandling::TRIM_WHITESPACE, |
| base::SplitResult::SPLIT_WANT_NONEMPTY); |
| return base::Value( |
| base::WideToUTF8(split.size() == 3 ? split[index] : L"")); |
| }; |
| AddPolicy(kUpdatesSuppressedStartHour, policy.Get(), *policies, |
| base::BindRepeating(extract_value, 0)); |
| AddPolicy(kUpdatesSuppressedStartMinute, policy.Get(), *policies, |
| base::BindRepeating(extract_value, 1)); |
| AddPolicy(kUpdatesSuppressedDurationMin, policy.Get(), *policies, |
| base::BindRepeating(extract_value, 2)); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_isRollbackToTargetVersionAllowed( |
| app_id.Get(), &policy))) { |
| AddPolicy(kRollbackToTargetVersion, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED( |
| policy_status->get_targetVersionPrefix(app_id.Get(), &policy))) { |
| AddPolicy(kTargetVersionPrefix, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_targetChannel(app_id.Get(), &policy))) { |
| AddPolicy(kTargetChannel, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_proxyMode(&policy))) { |
| AddPolicy(kProxyMode, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_proxyPacUrl(&policy))) { |
| AddPolicy(kProxyPacUrl, policy.Get(), *policies); |
| } |
| } |
| { |
| Microsoft::WRL::ComPtr<IPolicyStatusValue> policy; |
| if (SUCCEEDED(policy_status->get_proxyServer(&policy))) { |
| AddPolicy(kProxyServer, policy.Get(), *policies); |
| } |
| } |
| |
| return policies; |
| } |
| |
| // Returns the state from GoogleUpdate. Requires GoogleUpdate version 1.3.36.91 |
| // (released 07-02-2021) or newer. |
| std::unique_ptr<GoogleUpdateState> GetGoogleUpdateState( |
| IPolicyStatus3* policy_status) { |
| DCHECK(policy_status); |
| auto state = std::make_unique<GoogleUpdateState>(); |
| base::win::ScopedBstr updater_version; |
| HRESULT last_com_res = |
| policy_status->get_updaterVersion(updater_version.Receive()); |
| if (SUCCEEDED(last_com_res)) { |
| DCHECK(updater_version.Length()); |
| state->version.assign(updater_version.Get(), updater_version.Length()); |
| } |
| |
| DATE last_checked_time; |
| last_com_res = policy_status->get_lastCheckedTime(&last_checked_time); |
| if (SUCCEEDED(last_com_res)) { |
| state->last_checked_time = DateToTime(last_checked_time); |
| } |
| |
| return state; |
| } |
| |
| } // namespace |
| |
| GoogleUpdatePoliciesAndState::GoogleUpdatePoliciesAndState() = default; |
| |
| GoogleUpdatePoliciesAndState::~GoogleUpdatePoliciesAndState() = default; |
| |
| base::Value GetGoogleUpdatePolicyNames() { |
| base::Value::List names; |
| for (const auto& key_value : GetGoogleUpdatePolicySchemas()) { |
| names.Append(base::Value(key_value.first)); |
| } |
| return base::Value(std::move(names)); |
| } |
| |
| policy::PolicyConversions::PolicyToSchemaMap GetGoogleUpdatePolicySchemas() { |
| // TODO(crbug.com/40722467): Use actual schemas. |
| return policy::PolicyConversions::PolicyToSchemaMap{{ |
| {kAutoUpdateCheckPeriodMinutes, policy::Schema()}, |
| {kDownloadPreference, policy::Schema()}, |
| {kForceInstallApps, policy::Schema()}, |
| {kInstallPolicy, policy::Schema()}, |
| {kProxyMode, policy::Schema()}, |
| {kProxyPacUrl, policy::Schema()}, |
| {kProxyServer, policy::Schema()}, |
| {kRollbackToTargetVersion, policy::Schema()}, |
| {kTargetVersionPrefix, policy::Schema()}, |
| {kTargetChannel, policy::Schema()}, |
| {kUpdatePolicy, policy::Schema()}, |
| {kUpdatesSuppressedDurationMin, policy::Schema()}, |
| {kUpdatesSuppressedStartHour, policy::Schema()}, |
| {kUpdatesSuppressedStartMinute, policy::Schema()}, |
| {kCloudPolicyOverridesPlatformPolicy, policy::Schema()}, |
| }}; |
| } |
| |
| std::unique_ptr<GoogleUpdatePoliciesAndState> |
| GetGoogleUpdatePoliciesAndState() { |
| base::win::AssertComInitialized(); |
| Microsoft::WRL::ComPtr<IPolicyStatus3> policy_status3; |
| auto policies_and_state = std::make_unique<GoogleUpdatePoliciesAndState>(); |
| const bool is_system_install = install_static::IsSystemInstall(); |
| Microsoft::WRL::ComPtr<IUnknown> unknown; |
| if (FAILED(::CoCreateInstance(is_system_install |
| ? CLSID_PolicyStatusSystemClass |
| : CLSID_PolicyStatusUserClass, |
| nullptr, CLSCTX_ALL, IID_PPV_ARGS(&unknown)))) { |
| return policies_and_state; |
| } |
| |
| // Chrome queries for the SxS IIDs first, with a fallback to the legacy IID. |
| // Without this change, marshaling can load the typelib from the wrong hive |
| // (HKCU instead of HKLM, or vice-versa). |
| HRESULT hr = unknown.CopyTo(is_system_install ? __uuidof(IPolicyStatus3System) |
| : __uuidof(IPolicyStatus3User), |
| IID_PPV_ARGS_Helper(&policy_status3)); |
| if (FAILED(hr)) { |
| hr = unknown.As(&policy_status3); |
| if (FAILED(hr)) { |
| return policies_and_state; |
| } |
| } |
| |
| policies_and_state->policies = GetGoogleUpdatePolicies(policy_status3.Get()); |
| policies_and_state->state = GetGoogleUpdateState(policy_status3.Get()); |
| |
| return policies_and_state; |
| } |