| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/settings/device_settings_provider.h" |
| |
| #include <memory.h> |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "ash/components/settings/cros_settings_names.h" |
| #include "ash/constants/ash_features.h" |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/callback_helpers.h" |
| #include "base/check.h" |
| #include "base/containers/contains.h" |
| #include "base/json/json_reader.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/syslog_logging.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/values.h" |
| #include "chrome/browser/ash/ownership/owner_settings_service_ash.h" |
| #include "chrome/browser/ash/policy/core/device_policy_decoder.h" |
| #include "chrome/browser/ash/policy/handlers/system_proxy_handler.h" |
| #include "chrome/browser/ash/policy/off_hours/off_hours_proto_parser.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chrome/browser/ash/settings/device_settings_cache.h" |
| #include "chrome/browser/ash/settings/hardware_data_usage_controller.h" |
| #include "chrome/browser/ash/settings/stats_reporting_controller.h" |
| #include "chrome/browser/ash/tpm_firmware_update.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/tpm/install_attributes.h" |
| #include "components/policy/core/common/chrome_schema.h" |
| #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
| #include "components/policy/core/common/schema.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/policy/proto/device_management_backend.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/re2/src/re2/re2.h" |
| |
| using google::protobuf::RepeatedField; |
| using google::protobuf::RepeatedPtrField; |
| |
| namespace em = enterprise_management; |
| |
| namespace ash { |
| |
| namespace { |
| |
| // List of settings handled by the DeviceSettingsProvider. |
| const char* const kKnownSettings[] = { |
| kAccountsPrefAllowGuest, |
| kAccountsPrefAllowNewUser, |
| kAccountsPrefFamilyLinkAccountsAllowed, |
| kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, |
| kAccountsPrefDeviceLocalAccountAutoLoginDelay, |
| kAccountsPrefDeviceLocalAccountAutoLoginId, |
| kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline, |
| kAccountsPrefDeviceLocalAccounts, |
| kAccountsPrefEphemeralUsersEnabled, |
| kAccountsPrefLoginScreenDomainAutoComplete, |
| kAccountsPrefShowUserNamesOnSignIn, |
| kAccountsPrefTransferSAMLCookies, |
| kAccountsPrefUsers, |
| kAllowBluetooth, |
| kAllowedConnectionTypesForUpdate, |
| kAllowRedeemChromeOsRegistrationOffers, |
| kAttestationForContentProtectionEnabled, |
| kBorealisAllowedForDevice, |
| kCastReceiverName, |
| kDeviceAllowedBluetoothServices, |
| kDeviceAttestationEnabled, |
| kDeviceAutoUpdateTimeRestrictions, |
| kDeviceCrostiniArcAdbSideloadingAllowed, |
| kDeviceDisabled, |
| kDeviceDisabledMessage, |
| kDeviceDisplayResolution, |
| kDeviceDockMacAddressSource, |
| kDeviceHostnameTemplate, |
| kDeviceHostnameUserConfigurable, |
| kDeviceLoginScreenInputMethods, |
| kDeviceLoginScreenLocales, |
| kDeviceLoginScreenSystemInfoEnforced, |
| kDeviceMinimumVersion, |
| kDeviceMinimumVersionAueMessage, |
| kDevicePeripheralDataAccessEnabled, |
| kDeviceShowLowDiskSpaceNotification, |
| kDeviceShowNumericKeyboardForPassword, |
| kDeviceOffHours, |
| kDeviceOwner, |
| kDevicePrintersAccessMode, |
| kDevicePrintersBlocklist, |
| kDevicePrintersAllowlist, |
| kDevicePowerwashAllowed, |
| kDeviceQuirksDownloadEnabled, |
| kDeviceRebootOnUserSignout, |
| kDeviceRestrictedManagedGuestSessionEnabled, |
| kDeviceScheduledReboot, |
| kDeviceScheduledUpdateCheck, |
| kDeviceSecondFactorAuthenticationMode, |
| kDeviceUnaffiliatedCrostiniAllowed, |
| kDeviceWebBasedAttestationAllowedUrls, |
| kDeviceWiFiAllowed, |
| kDeviceWilcoDtcAllowed, |
| kDisplayRotationDefault, |
| kEnableDeviceGranularReporting, |
| kExtensionCacheSize, |
| kFeatureFlags, |
| kHeartbeatEnabled, |
| kHeartbeatFrequency, |
| kKioskCRXManifestUpdateURLIgnored, |
| kLoginAuthenticationBehavior, |
| kLoginVideoCaptureAllowedUrls, |
| kPluginVmAllowed, |
| kPolicyMissingMitigationMode, |
| kRebootOnShutdown, |
| kReleaseChannel, |
| kReleaseChannelDelegated, |
| kReleaseLtsTag, |
| kDeviceChannelDowngradeBehavior, |
| kReportDeviceActivityTimes, |
| kReportDeviceAudioStatus, |
| kReportDeviceAudioStatusCheckingRateMs, |
| kReportDeviceBluetoothInfo, |
| kReportDeviceBoardStatus, |
| kReportDeviceBootMode, |
| kReportDeviceCrashReportInfo, |
| kReportDeviceCpuInfo, |
| kReportDeviceFanInfo, |
| kReportDeviceHardwareStatus, |
| kReportDeviceLocation, |
| kReportDevicePowerStatus, |
| kReportDeviceStorageStatus, |
| kReportDeviceNetworkConfiguration, |
| kReportDeviceNetworkInterfaces, |
| kReportDeviceNetworkStatus, |
| kReportDeviceNetworkTelemetryCollectionRateMs, |
| kReportDeviceNetworkTelemetryEventCheckingRateMs, |
| kReportDeviceSessionStatus, |
| kReportDeviceSecurityStatus, |
| kReportDeviceTimezoneInfo, |
| kReportDeviceGraphicsStatus, |
| kReportDeviceMemoryInfo, |
| kReportDeviceBacklightInfo, |
| kReportDeviceUsers, |
| kReportDeviceVersionInfo, |
| kReportDeviceVpdInfo, |
| kReportDeviceAppInfo, |
| kReportDeviceSystemInfo, |
| kReportDevicePrintJobs, |
| kReportDeviceLoginLogout, |
| kReportOsUpdateStatus, |
| kReportRunningKioskApp, |
| kReportUploadFrequency, |
| kRevenEnableDeviceHWDataUsage, |
| kSamlLoginAuthenticationType, |
| kServiceAccountIdentity, |
| kSignedDataRoamingEnabled, |
| kStatsReportingPref, |
| kSystemLogUploadEnabled, |
| kSystemProxySettings, |
| kSystemTimezonePolicy, |
| kSystemUse24HourClock, |
| kTargetVersionPrefix, |
| kTPMFirmwareUpdateSettings, |
| kUnaffiliatedArcAllowed, |
| kUpdateDisabled, |
| kUsbDetachableAllowlist, |
| kVariationsRestrictParameter, |
| kVirtualMachinesAllowed, |
| }; |
| |
| constexpr char InvalidCombinationsOfAllowedUsersPoliciesHistogram[] = |
| "Login.InvalidCombinationsOfAllowedUsersPolicies"; |
| |
| // Re-use the DecodeJsonStringAndNormalize from device_policy_decoder.h |
| // here to decode the json string and validate it against |policy_name|'s |
| // schema. If the json string is valid, the decoded base::Value will be stored |
| // as |setting_name| in |pref_value_map|. The error can be ignored here since it |
| // is already reported during decoding in device_policy_decoder.cc. |
| void SetJsonDeviceSetting(const std::string& setting_name, |
| const std::string& policy_name, |
| const std::string& json_string, |
| PrefValueMap* pref_value_map) { |
| std::string error; |
| absl::optional<base::Value> decoded_json = |
| policy::DecodeJsonStringAndNormalize(json_string, policy_name, &error); |
| if (decoded_json.has_value()) { |
| pref_value_map->SetValue(setting_name, std::move(decoded_json.value())); |
| } |
| } |
| |
| // Puts the policy value into the settings store if only it matches the regex |
| // pattern. |
| void SetSettingWithValidatingRegex(const std::string& policy_name, |
| const std::string& policy_value, |
| const std::string& pattern, |
| PrefValueMap* pref_value_map) { |
| if (RE2::FullMatch(policy_value, pattern)) |
| pref_value_map->SetString(policy_name, policy_value); |
| } |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| enum class AllowedUsersPoliciesInvalidState { |
| AllowlistNotPresentAndAllowNewUsersTrue = 0, |
| AllowlistNotPresentAndAllowNewUsersFalse = 1, |
| AllowlistEmptyAndAllowNewUsersNotPresent = 2, |
| AllowlistNonEmptyAndAllowNewUsersNotPresent = 3, |
| kMaxValue = AllowlistNonEmptyAndAllowNewUsersNotPresent |
| }; |
| |
| // Returns the value of the allow_new_users (DeviceAllowNewUsers) device |
| // policy or an empty absl::optional if the policy was not set. |
| absl::optional<bool> GetAllowNewUsers( |
| const em::ChromeDeviceSettingsProto& policy) { |
| if (!policy.has_allow_new_users() || |
| !policy.allow_new_users().has_allow_new_users()) |
| return absl::nullopt; |
| return absl::optional<bool>{policy.allow_new_users().allow_new_users()}; |
| } |
| |
| // Returns: |
| // - an empty absl::optional if the user_allowlist outer wrapper message is |
| // not present |
| // - true if the user_allowlist outer wrapper message is present and the |
| // user_allowlist inner list is empty |
| // - false if the user_allowlist outer wrapper message is present and the |
| // user_allowlist inner list has at least one element. |
| absl::optional<bool> GetIsEmptyAllowList( |
| const em::ChromeDeviceSettingsProto& policy) { |
| if (!policy.has_user_allowlist()) |
| return absl::nullopt; |
| return absl::optional<bool>{policy.user_allowlist().user_allowlist_size() == |
| 0}; |
| } |
| |
| // Decodes the allow_new_users (DeviceAllowNewUsers) and user_allowlist |
| // (DeviceUserAllowlist) policies and the guest_mode_enabled |
| // (DeviceGuestModeEnabled) policy. |
| void DecodeAllowedUsers(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| auto allow_new_users = GetAllowNewUsers(policy); |
| auto is_empty_allowlist = GetIsEmptyAllowList(policy); |
| |
| if (allow_new_users.has_value() && allow_new_users.value() && |
| is_empty_allowlist.has_value() && is_empty_allowlist.value()) { |
| // Allow any user to sign in |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); |
| } else if (allow_new_users.has_value() && !allow_new_users.value() && |
| is_empty_allowlist.has_value() && !is_empty_allowlist.value()) { |
| // Restrict sign in to a list of users |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, false); |
| } else if (allow_new_users.has_value() && !allow_new_users.value() && |
| is_empty_allowlist.has_value() && is_empty_allowlist.value()) { |
| // Do not allow any user to sign in |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, false); |
| } else if (!allow_new_users.has_value() && !is_empty_allowlist.has_value()) { |
| // If policies haven't been touched, behavior is similar |
| // to allow any user to sign in |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); |
| } else if (allow_new_users.has_value() && allow_new_users.value() && |
| is_empty_allowlist.has_value() && !is_empty_allowlist.value()) { |
| // Some consumer devices out there already have this |
| // combination of policies configured, the behavior is |
| // similar to the first case: Allow any user to sign in |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); |
| } else { |
| // If for some reason we encounter a combination other than |
| // the 5 above, we simply default to allowing everyone to sign in |
| new_values_cache->SetBoolean(kAccountsPrefAllowNewUser, true); |
| |
| // Record which of the 4 invalid states we received |
| if (!is_empty_allowlist.has_value() && allow_new_users.has_value()) { |
| base::UmaHistogramEnumeration( |
| InvalidCombinationsOfAllowedUsersPoliciesHistogram, |
| allow_new_users.value() |
| ? AllowedUsersPoliciesInvalidState:: |
| AllowlistNotPresentAndAllowNewUsersTrue |
| : AllowedUsersPoliciesInvalidState:: |
| AllowlistNotPresentAndAllowNewUsersFalse); |
| } else if (is_empty_allowlist.has_value() && !allow_new_users.has_value()) { |
| base::UmaHistogramEnumeration( |
| InvalidCombinationsOfAllowedUsersPoliciesHistogram, |
| is_empty_allowlist.value() |
| ? AllowedUsersPoliciesInvalidState:: |
| AllowlistEmptyAndAllowNewUsersNotPresent |
| : AllowedUsersPoliciesInvalidState:: |
| AllowlistNonEmptyAndAllowNewUsersNotPresent); |
| } |
| } |
| |
| new_values_cache->SetBoolean( |
| kAccountsPrefAllowGuest, |
| !policy.has_guest_mode_enabled() || |
| !policy.guest_mode_enabled().has_guest_mode_enabled() || |
| policy.guest_mode_enabled().guest_mode_enabled()); |
| } |
| |
| void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| // For all our boolean settings the following is applicable: |
| // true is default permissive value and false is safe prohibitive value. |
| // Exceptions: |
| // kAccountsPrefEphemeralUsersEnabled has a default value of false. |
| // kAccountsPrefTransferSAMLCookies has a default value of false. |
| // kAccountsPrefFamilyLinkAccountsAllowed has a default value of false. |
| |
| // Value of DeviceFamilyLinkAccountsAllowed policy does not affect |
| // |kAccountsPrefAllowNewUser| setting. Family Link accounts are only |
| // allowed if user allowlist is enforced. |
| DecodeAllowedUsers(policy, new_values_cache); |
| |
| bool user_allowlist_enforced = |
| ((policy.has_user_whitelist() && |
| policy.user_whitelist().user_whitelist_size() > 0) || |
| (policy.has_user_allowlist() && |
| policy.user_allowlist().user_allowlist_size() > 0)); |
| new_values_cache->SetBoolean( |
| kAccountsPrefFamilyLinkAccountsAllowed, |
| features::IsFamilyLinkOnSchoolDeviceEnabled() && |
| user_allowlist_enforced && |
| policy.has_family_link_accounts_allowed() && |
| policy.family_link_accounts_allowed() |
| .has_family_link_accounts_allowed() && |
| policy.family_link_accounts_allowed().family_link_accounts_allowed()); |
| |
| new_values_cache->SetBoolean( |
| kRebootOnShutdown, |
| policy.has_reboot_on_shutdown() && |
| policy.reboot_on_shutdown().has_reboot_on_shutdown() && |
| policy.reboot_on_shutdown().reboot_on_shutdown()); |
| |
| new_values_cache->SetBoolean( |
| kAccountsPrefShowUserNamesOnSignIn, |
| !policy.has_show_user_names() || |
| !policy.show_user_names().has_show_user_names() || |
| policy.show_user_names().show_user_names()); |
| |
| new_values_cache->SetBoolean( |
| kAccountsPrefEphemeralUsersEnabled, |
| policy.has_ephemeral_users_enabled() && |
| policy.ephemeral_users_enabled().has_ephemeral_users_enabled() && |
| policy.ephemeral_users_enabled().ephemeral_users_enabled()); |
| |
| std::vector<base::Value> list; |
| const em::UserAllowlistProto& allowlist_proto = policy.user_allowlist(); |
| if (policy.user_allowlist().user_allowlist_size() > 0) { |
| const RepeatedPtrField<std::string>& allowlist = |
| allowlist_proto.user_allowlist(); |
| for (const std::string& value : allowlist) { |
| list.push_back(base::Value(value)); |
| } |
| } else { |
| const em::UserWhitelistProto& whitelist_proto = policy.user_whitelist(); |
| const RepeatedPtrField<std::string>& whitelist = |
| whitelist_proto.user_whitelist(); |
| for (const std::string& value : whitelist) { |
| list.push_back(base::Value(value)); |
| } |
| } |
| |
| new_values_cache->SetValue(kAccountsPrefUsers, base::Value(std::move(list))); |
| |
| std::vector<base::Value> account_list; |
| const em::DeviceLocalAccountsProto device_local_accounts_proto = |
| policy.device_local_accounts(); |
| const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts = |
| device_local_accounts_proto.account(); |
| RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry; |
| for (const em::DeviceLocalAccountInfoProto& entry : accounts) { |
| base::Value entry_dict(base::Value::Type::DICTIONARY); |
| if (entry.has_type()) { |
| if (entry.has_account_id()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyId, |
| base::Value(entry.account_id())); |
| } |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyType, |
| base::Value(entry.type())); |
| if (entry.kiosk_app().has_app_id()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyKioskAppId, |
| base::Value(entry.kiosk_app().app_id())); |
| } |
| if (entry.kiosk_app().has_update_url()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL, |
| base::Value(entry.kiosk_app().update_url())); |
| } |
| if (entry.android_kiosk_app().has_package_name()) { |
| entry_dict.SetKey( |
| kAccountsPrefDeviceLocalAccountsKeyArcKioskPackage, |
| base::Value(entry.android_kiosk_app().package_name())); |
| } |
| if (entry.android_kiosk_app().has_class_name()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyArcKioskClass, |
| base::Value(entry.android_kiosk_app().class_name())); |
| } |
| if (entry.android_kiosk_app().has_action()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyArcKioskAction, |
| base::Value(entry.android_kiosk_app().action())); |
| } |
| if (entry.android_kiosk_app().has_display_name()) { |
| entry_dict.SetKey( |
| kAccountsPrefDeviceLocalAccountsKeyArcKioskDisplayName, |
| base::Value(entry.android_kiosk_app().display_name())); |
| } |
| if (entry.web_kiosk_app().has_url()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyWebKioskUrl, |
| base::Value(entry.web_kiosk_app().url())); |
| } |
| if (entry.web_kiosk_app().has_title()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyWebKioskTitle, |
| base::Value(entry.web_kiosk_app().title())); |
| } |
| if (entry.web_kiosk_app().has_icon_url()) { |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyWebKioskIconUrl, |
| base::Value(entry.web_kiosk_app().icon_url())); |
| } |
| } else if (entry.has_deprecated_public_session_id()) { |
| // Deprecated public session specification. |
| entry_dict.SetKey(kAccountsPrefDeviceLocalAccountsKeyId, |
| base::Value(entry.deprecated_public_session_id())); |
| entry_dict.SetKey( |
| kAccountsPrefDeviceLocalAccountsKeyType, |
| base::Value( |
| em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_PUBLIC_SESSION)); |
| } |
| account_list.push_back(std::move(entry_dict)); |
| } |
| new_values_cache->SetValue(kAccountsPrefDeviceLocalAccounts, |
| base::Value(std::move(account_list))); |
| |
| if (policy.has_device_local_accounts()) { |
| if (policy.device_local_accounts().has_auto_login_id()) { |
| new_values_cache->SetString( |
| kAccountsPrefDeviceLocalAccountAutoLoginId, |
| policy.device_local_accounts().auto_login_id()); |
| } |
| if (policy.device_local_accounts().has_auto_login_delay()) { |
| new_values_cache->SetInteger( |
| kAccountsPrefDeviceLocalAccountAutoLoginDelay, |
| policy.device_local_accounts().auto_login_delay()); |
| } |
| } |
| |
| new_values_cache->SetBoolean( |
| kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, |
| policy.device_local_accounts().enable_auto_login_bailout()); |
| new_values_cache->SetBoolean( |
| kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline, |
| policy.device_local_accounts().prompt_for_network_when_offline()); |
| |
| if (policy.has_feature_flags()) { |
| std::vector<base::Value> feature_flags_list; |
| for (const std::string& entry : policy.feature_flags().feature_flags()) { |
| feature_flags_list.push_back(base::Value(entry)); |
| } |
| if (!feature_flags_list.empty()) { |
| new_values_cache->SetValue(kFeatureFlags, |
| base::Value(std::move(feature_flags_list))); |
| } |
| } |
| |
| if (policy.has_saml_settings()) { |
| new_values_cache->SetBoolean( |
| kAccountsPrefTransferSAMLCookies, |
| policy.saml_settings().transfer_saml_cookies()); |
| } |
| |
| // The behavior when policy is not set and when it is set to an empty string |
| // is the same. Thus lets add policy only if it is set and its value is not |
| // an empty string. |
| if (policy.has_login_screen_domain_auto_complete() && |
| policy.login_screen_domain_auto_complete() |
| .has_login_screen_domain_auto_complete() && |
| !policy.login_screen_domain_auto_complete() |
| .login_screen_domain_auto_complete() |
| .empty()) { |
| SetSettingWithValidatingRegex(kAccountsPrefLoginScreenDomainAutoComplete, |
| policy.login_screen_domain_auto_complete() |
| .login_screen_domain_auto_complete(), |
| policy::hostNameRegex, new_values_cache); |
| } |
| |
| if (policy.has_login_authentication_behavior() && |
| policy.login_authentication_behavior() |
| .has_login_authentication_behavior()) { |
| new_values_cache->SetInteger( |
| kLoginAuthenticationBehavior, |
| policy.login_authentication_behavior().login_authentication_behavior()); |
| } |
| |
| if (policy.has_login_video_capture_allowed_urls()) { |
| std::vector<base::Value> list; |
| const em::LoginVideoCaptureAllowedUrlsProto& |
| login_video_capture_allowed_urls_proto = |
| policy.login_video_capture_allowed_urls(); |
| for (const auto& value : login_video_capture_allowed_urls_proto.urls()) { |
| list.push_back(base::Value(value)); |
| } |
| new_values_cache->SetValue(kLoginVideoCaptureAllowedUrls, |
| base::Value(std::move(list))); |
| } |
| |
| if (policy.has_login_screen_locales()) { |
| std::vector<base::Value> locales; |
| const em::LoginScreenLocalesProto& login_screen_locales( |
| policy.login_screen_locales()); |
| for (const auto& locale : login_screen_locales.login_screen_locales()) |
| locales.push_back(base::Value(locale)); |
| new_values_cache->SetValue(kDeviceLoginScreenLocales, |
| base::Value(std::move(locales))); |
| } |
| |
| if (policy.has_login_screen_input_methods()) { |
| std::vector<base::Value> input_methods; |
| const em::LoginScreenInputMethodsProto& login_screen_input_methods( |
| policy.login_screen_input_methods()); |
| for (const auto& input_method : |
| login_screen_input_methods.login_screen_input_methods()) |
| input_methods.push_back(base::Value(input_method)); |
| new_values_cache->SetValue(kDeviceLoginScreenInputMethods, |
| base::Value(std::move(input_methods))); |
| } |
| |
| if (policy.has_device_login_screen_system_info_enforced() && |
| policy.device_login_screen_system_info_enforced().has_value()) { |
| new_values_cache->SetBoolean( |
| kDeviceLoginScreenSystemInfoEnforced, |
| policy.device_login_screen_system_info_enforced().value()); |
| } |
| |
| if (policy.has_device_show_numeric_keyboard_for_password() && |
| policy.device_show_numeric_keyboard_for_password().has_value()) { |
| new_values_cache->SetBoolean( |
| kDeviceShowNumericKeyboardForPassword, |
| policy.device_show_numeric_keyboard_for_password().value()); |
| } |
| |
| if (policy.has_saml_login_authentication_type() && |
| policy.saml_login_authentication_type() |
| .has_saml_login_authentication_type()) { |
| new_values_cache->SetInteger(kSamlLoginAuthenticationType, |
| policy.saml_login_authentication_type() |
| .saml_login_authentication_type()); |
| } |
| |
| if (policy.has_device_web_based_attestation_allowed_urls()) { |
| const em::StringListPolicyProto& container( |
| policy.device_web_based_attestation_allowed_urls()); |
| |
| base::Value urls(base::Value::Type::LIST); |
| for (const std::string& entry : container.value().entries()) { |
| urls.Append(entry); |
| } |
| |
| new_values_cache->SetValue(kDeviceWebBasedAttestationAllowedUrls, |
| std::move(urls)); |
| } |
| |
| if (policy.has_kiosk_crx_manifest_update_url_ignored()) { |
| const em::BooleanPolicyProto& container( |
| policy.kiosk_crx_manifest_update_url_ignored()); |
| |
| if (container.has_value()) { |
| new_values_cache->SetValue(kKioskCRXManifestUpdateURLIgnored, |
| base::Value(container.value())); |
| } |
| } |
| } |
| |
| void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| // kSignedDataRoamingEnabled has a default value of false. |
| new_values_cache->SetBoolean( |
| kSignedDataRoamingEnabled, |
| policy.has_data_roaming_enabled() && |
| policy.data_roaming_enabled().has_data_roaming_enabled() && |
| policy.data_roaming_enabled().data_roaming_enabled()); |
| if (policy.has_system_proxy_settings()) { |
| const em::SystemProxySettingsProto& settings_proto( |
| policy.system_proxy_settings()); |
| if (settings_proto.has_system_proxy_settings()) { |
| SetJsonDeviceSetting( |
| kSystemProxySettings, policy::key::kSystemProxySettings, |
| settings_proto.system_proxy_settings(), new_values_cache); |
| } |
| } |
| } |
| |
| void DecodeAutoUpdatePolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| if (policy.has_auto_update_settings()) { |
| const em::AutoUpdateSettingsProto& au_settings_proto = |
| policy.auto_update_settings(); |
| if (au_settings_proto.has_update_disabled()) { |
| new_values_cache->SetBoolean(kUpdateDisabled, |
| au_settings_proto.update_disabled()); |
| } |
| |
| if (au_settings_proto.has_target_version_prefix()) { |
| new_values_cache->SetString(kTargetVersionPrefix, |
| au_settings_proto.target_version_prefix()); |
| } |
| |
| const RepeatedField<int>& allowed_connection_types = |
| au_settings_proto.allowed_connection_types(); |
| std::vector<base::Value> list; |
| for (int value : allowed_connection_types) { |
| list.push_back(base::Value(value)); |
| } |
| if (!list.empty()) { |
| new_values_cache->SetValue(kAllowedConnectionTypesForUpdate, |
| base::Value(std::move(list))); |
| } |
| |
| if (au_settings_proto.has_disallowed_time_intervals()) { |
| SetJsonDeviceSetting(kDeviceAutoUpdateTimeRestrictions, |
| policy::key::kDeviceAutoUpdateTimeRestrictions, |
| au_settings_proto.disallowed_time_intervals(), |
| new_values_cache); |
| } |
| |
| if (au_settings_proto.has_channel_downgrade_behavior()) { |
| new_values_cache->SetValue( |
| kDeviceChannelDowngradeBehavior, |
| base::Value(au_settings_proto.channel_downgrade_behavior())); |
| } |
| } |
| |
| if (policy.has_device_scheduled_update_check()) { |
| const em::DeviceScheduledUpdateCheckProto& scheduled_update_check_policy = |
| policy.device_scheduled_update_check(); |
| if (scheduled_update_check_policy |
| .has_device_scheduled_update_check_settings()) { |
| SetJsonDeviceSetting(kDeviceScheduledUpdateCheck, |
| policy::key::kDeviceScheduledUpdateCheck, |
| scheduled_update_check_policy |
| .device_scheduled_update_check_settings(), |
| new_values_cache); |
| } |
| } |
| } |
| |
| void DecodeReportingPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| if (policy.has_device_reporting()) { |
| const em::DeviceReportingProto& reporting_policy = |
| policy.device_reporting(); |
| if (reporting_policy.has_enable_granular_reporting()) { |
| new_values_cache->SetBoolean( |
| kEnableDeviceGranularReporting, |
| reporting_policy.enable_granular_reporting()); |
| } |
| if (reporting_policy.has_report_version_info()) { |
| new_values_cache->SetBoolean(kReportDeviceVersionInfo, |
| reporting_policy.report_version_info()); |
| } |
| if (reporting_policy.has_report_activity_times()) { |
| new_values_cache->SetBoolean(kReportDeviceActivityTimes, |
| reporting_policy.report_activity_times()); |
| } |
| if (reporting_policy.has_report_audio_status()) { |
| new_values_cache->SetBoolean(kReportDeviceAudioStatus, |
| reporting_policy.report_audio_status()); |
| } |
| if (reporting_policy.has_report_boot_mode()) { |
| new_values_cache->SetBoolean(kReportDeviceBootMode, |
| reporting_policy.report_boot_mode()); |
| } |
| if (reporting_policy.has_report_crash_report_info()) { |
| new_values_cache->SetBoolean(kReportDeviceCrashReportInfo, |
| reporting_policy.report_crash_report_info()); |
| } |
| if (reporting_policy.has_report_network_configuration()) { |
| new_values_cache->SetBoolean( |
| kReportDeviceNetworkConfiguration, |
| reporting_policy.report_network_configuration()); |
| } |
| if (reporting_policy.has_report_network_interfaces()) { |
| new_values_cache->SetBoolean( |
| kReportDeviceNetworkInterfaces, |
| reporting_policy.report_network_interfaces()); |
| } |
| if (reporting_policy.has_report_network_status()) { |
| new_values_cache->SetBoolean(kReportDeviceNetworkStatus, |
| reporting_policy.report_network_status()); |
| } |
| if (reporting_policy.has_report_users()) { |
| new_values_cache->SetBoolean(kReportDeviceUsers, |
| reporting_policy.report_users()); |
| } |
| if (reporting_policy.has_report_hardware_status()) { |
| new_values_cache->SetBoolean(kReportDeviceHardwareStatus, |
| reporting_policy.report_hardware_status()); |
| } |
| if (reporting_policy.has_report_session_status()) { |
| new_values_cache->SetBoolean(kReportDeviceSessionStatus, |
| reporting_policy.report_session_status()); |
| } |
| if (reporting_policy.has_report_security_status()) { |
| new_values_cache->SetBoolean(kReportDeviceSecurityStatus, |
| reporting_policy.report_security_status()); |
| } |
| if (reporting_policy.has_report_graphics_status()) { |
| new_values_cache->SetBoolean(kReportDeviceGraphicsStatus, |
| reporting_policy.report_graphics_status()); |
| } |
| if (reporting_policy.has_report_os_update_status()) { |
| new_values_cache->SetBoolean(kReportOsUpdateStatus, |
| reporting_policy.report_os_update_status()); |
| } |
| if (reporting_policy.has_report_running_kiosk_app()) { |
| new_values_cache->SetBoolean(kReportRunningKioskApp, |
| reporting_policy.report_running_kiosk_app()); |
| } |
| if (reporting_policy.has_report_power_status()) { |
| new_values_cache->SetBoolean(kReportDevicePowerStatus, |
| reporting_policy.report_power_status()); |
| } |
| if (reporting_policy.has_report_storage_status()) { |
| new_values_cache->SetBoolean(kReportDeviceStorageStatus, |
| reporting_policy.report_storage_status()); |
| } |
| if (reporting_policy.has_report_board_status()) { |
| new_values_cache->SetBoolean(kReportDeviceBoardStatus, |
| reporting_policy.report_board_status()); |
| } |
| if (reporting_policy.has_device_status_frequency()) { |
| new_values_cache->SetInteger(kReportUploadFrequency, |
| reporting_policy.device_status_frequency()); |
| } |
| if (reporting_policy.has_report_cpu_info()) { |
| new_values_cache->SetBoolean(kReportDeviceCpuInfo, |
| reporting_policy.report_cpu_info()); |
| } |
| if (reporting_policy.has_report_timezone_info()) { |
| new_values_cache->SetBoolean(kReportDeviceTimezoneInfo, |
| reporting_policy.report_timezone_info()); |
| } |
| if (reporting_policy.has_report_memory_info()) { |
| new_values_cache->SetBoolean(kReportDeviceMemoryInfo, |
| reporting_policy.report_memory_info()); |
| } |
| if (reporting_policy.has_report_backlight_info()) { |
| new_values_cache->SetBoolean(kReportDeviceBacklightInfo, |
| reporting_policy.report_backlight_info()); |
| } |
| if (reporting_policy.has_report_app_info()) { |
| new_values_cache->SetBoolean(kReportDeviceAppInfo, |
| reporting_policy.report_app_info()); |
| } |
| if (reporting_policy.has_report_bluetooth_info()) { |
| new_values_cache->SetBoolean(kReportDeviceBluetoothInfo, |
| reporting_policy.report_bluetooth_info()); |
| } |
| if (reporting_policy.has_report_fan_info()) { |
| new_values_cache->SetBoolean(kReportDeviceFanInfo, |
| reporting_policy.report_fan_info()); |
| } |
| if (reporting_policy.has_report_vpd_info()) { |
| new_values_cache->SetBoolean(kReportDeviceVpdInfo, |
| reporting_policy.report_vpd_info()); |
| } |
| if (reporting_policy.has_report_system_info()) { |
| new_values_cache->SetBoolean(kReportDeviceSystemInfo, |
| reporting_policy.report_system_info()); |
| } |
| if (reporting_policy.has_report_print_jobs()) { |
| new_values_cache->SetBoolean(kReportDevicePrintJobs, |
| reporting_policy.report_print_jobs()); |
| } |
| if (reporting_policy.has_report_login_logout()) { |
| new_values_cache->SetBoolean(kReportDeviceLoginLogout, |
| reporting_policy.report_login_logout()); |
| } |
| if (reporting_policy.has_report_crd_sessions()) { |
| new_values_cache->SetBoolean(kReportCRDSessions, |
| reporting_policy.report_crd_sessions()); |
| } |
| if (reporting_policy.has_report_network_telemetry_collection_rate_ms()) { |
| new_values_cache->SetInteger( |
| kReportDeviceNetworkTelemetryCollectionRateMs, |
| reporting_policy.report_network_telemetry_collection_rate_ms()); |
| } |
| if (reporting_policy |
| .has_report_network_telemetry_event_checking_rate_ms()) { |
| new_values_cache->SetInteger( |
| kReportDeviceNetworkTelemetryEventCheckingRateMs, |
| reporting_policy.report_network_telemetry_event_checking_rate_ms()); |
| } |
| if (reporting_policy.has_report_device_audio_status_checking_rate_ms()) { |
| new_values_cache->SetInteger( |
| kReportDeviceAudioStatusCheckingRateMs, |
| reporting_policy.report_device_audio_status_checking_rate_ms()); |
| } |
| } |
| } |
| |
| void DecodeHeartbeatPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| if (!policy.has_device_heartbeat_settings()) |
| return; |
| |
| const em::DeviceHeartbeatSettingsProto& heartbeat_policy = |
| policy.device_heartbeat_settings(); |
| if (heartbeat_policy.has_heartbeat_enabled()) { |
| new_values_cache->SetBoolean(kHeartbeatEnabled, |
| heartbeat_policy.heartbeat_enabled()); |
| } |
| if (heartbeat_policy.has_heartbeat_frequency()) { |
| new_values_cache->SetInteger(kHeartbeatFrequency, |
| heartbeat_policy.heartbeat_frequency()); |
| } |
| } |
| |
| void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| if (policy.has_metrics_enabled() && |
| policy.metrics_enabled().has_metrics_enabled()) { |
| new_values_cache->SetBoolean(kStatsReportingPref, |
| policy.metrics_enabled().metrics_enabled()); |
| } else { |
| // If the policy is missing, default to reporting enabled on enterprise- |
| // enrolled devices, c.f. crbug/456186. |
| new_values_cache->SetBoolean( |
| kStatsReportingPref, |
| chromeos::InstallAttributes::Get()->IsEnterpriseManaged()); |
| } |
| |
| if (!policy.has_release_channel() || |
| !policy.release_channel().has_release_channel()) { |
| // Default to an invalid channel (will be ignored). |
| new_values_cache->SetString(kReleaseChannel, ""); |
| } else { |
| new_values_cache->SetString(kReleaseChannel, |
| policy.release_channel().release_channel()); |
| } |
| |
| new_values_cache->SetBoolean( |
| kReleaseChannelDelegated, |
| policy.has_release_channel() && |
| policy.release_channel().has_release_channel_delegated() && |
| policy.release_channel().release_channel_delegated()); |
| |
| if (policy.has_release_channel()) { |
| if (policy.release_channel().has_release_lts_tag()) { |
| new_values_cache->SetString(kReleaseLtsTag, |
| policy.release_channel().release_lts_tag()); |
| } |
| } |
| |
| if (policy.has_system_timezone()) { |
| if (policy.system_timezone().has_timezone()) { |
| new_values_cache->SetString(kSystemTimezonePolicy, |
| policy.system_timezone().timezone()); |
| } |
| } |
| |
| if (policy.has_use_24hour_clock()) { |
| if (policy.use_24hour_clock().has_use_24hour_clock()) { |
| new_values_cache->SetBoolean( |
| kSystemUse24HourClock, policy.use_24hour_clock().use_24hour_clock()); |
| } |
| } |
| |
| if (policy.has_allow_redeem_offers() && |
| policy.allow_redeem_offers().has_allow_redeem_offers()) { |
| new_values_cache->SetBoolean( |
| kAllowRedeemChromeOsRegistrationOffers, |
| policy.allow_redeem_offers().allow_redeem_offers()); |
| } else { |
| new_values_cache->SetBoolean(kAllowRedeemChromeOsRegistrationOffers, true); |
| } |
| |
| if (policy.has_variations_parameter()) { |
| new_values_cache->SetString(kVariationsRestrictParameter, |
| policy.variations_parameter().parameter()); |
| } |
| |
| new_values_cache->SetBoolean( |
| kDeviceAttestationEnabled, |
| policy.attestation_settings().attestation_enabled()); |
| |
| if (policy.has_attestation_settings() && |
| policy.attestation_settings().has_content_protection_enabled()) { |
| new_values_cache->SetBoolean( |
| kAttestationForContentProtectionEnabled, |
| policy.attestation_settings().content_protection_enabled()); |
| } else { |
| new_values_cache->SetBoolean(kAttestationForContentProtectionEnabled, true); |
| } |
| |
| bool is_device_pci_peripheral_data_access_enabled = false; |
| if (policy.has_device_pci_peripheral_data_access_enabled_v2()) { |
| const em::DevicePciPeripheralDataAccessEnabledProtoV2& container( |
| policy.device_pci_peripheral_data_access_enabled_v2()); |
| if (container.has_enabled()) { |
| is_device_pci_peripheral_data_access_enabled = container.enabled(); |
| } |
| } |
| new_values_cache->SetBoolean(kDevicePeripheralDataAccessEnabled, |
| is_device_pci_peripheral_data_access_enabled); |
| |
| if (policy.has_extension_cache_size() && |
| policy.extension_cache_size().has_extension_cache_size()) { |
| new_values_cache->SetInteger( |
| kExtensionCacheSize, |
| policy.extension_cache_size().extension_cache_size()); |
| } |
| |
| if (policy.has_display_rotation_default() && |
| policy.display_rotation_default().has_display_rotation_default()) { |
| new_values_cache->SetInteger( |
| kDisplayRotationDefault, |
| policy.display_rotation_default().display_rotation_default()); |
| } |
| |
| if (policy.has_device_display_resolution() && |
| policy.device_display_resolution().has_device_display_resolution()) { |
| SetJsonDeviceSetting( |
| kDeviceDisplayResolution, policy::key::kDeviceDisplayResolution, |
| policy.device_display_resolution().device_display_resolution(), |
| new_values_cache); |
| } else { |
| // Set empty value if policy is missing, to make sure that webui |
| // will receive setting update. |
| new_values_cache->SetValue(kDeviceDisplayResolution, |
| base::Value(base::Value::Type::DICTIONARY)); |
| } |
| |
| if (policy.has_allow_bluetooth() && |
| policy.allow_bluetooth().has_allow_bluetooth()) { |
| new_values_cache->SetBoolean(kAllowBluetooth, |
| policy.allow_bluetooth().allow_bluetooth()); |
| } else { |
| new_values_cache->SetBoolean(kAllowBluetooth, true); |
| } |
| |
| if (policy.has_device_wifi_allowed() && |
| policy.device_wifi_allowed().has_device_wifi_allowed()) { |
| new_values_cache->SetBoolean( |
| kDeviceWiFiAllowed, policy.device_wifi_allowed().device_wifi_allowed()); |
| } else { |
| new_values_cache->SetBoolean(kDeviceWiFiAllowed, true); |
| } |
| |
| if (policy.has_quirks_download_enabled() && |
| policy.quirks_download_enabled().has_quirks_download_enabled()) { |
| new_values_cache->SetBoolean( |
| kDeviceQuirksDownloadEnabled, |
| policy.quirks_download_enabled().quirks_download_enabled()); |
| } |
| |
| if (policy.has_device_off_hours()) { |
| auto off_hours_policy = policy::off_hours::ConvertOffHoursProtoToValue( |
| policy.device_off_hours()); |
| if (off_hours_policy) |
| new_values_cache->SetValue( |
| kDeviceOffHours, |
| base::Value::FromUniquePtrValue(std::move(off_hours_policy))); |
| } |
| |
| if (policy.has_tpm_firmware_update_settings()) { |
| new_values_cache->SetValue(kTPMFirmwareUpdateSettings, |
| base::Value::FromUniquePtrValue( |
| tpm_firmware_update::DecodeSettingsProto( |
| policy.tpm_firmware_update_settings()))); |
| } |
| |
| if (policy.has_device_minimum_version()) { |
| const em::StringPolicyProto& container(policy.device_minimum_version()); |
| if (container.has_value()) { |
| SetJsonDeviceSetting(kDeviceMinimumVersion, |
| policy::key::kDeviceMinimumVersion, |
| container.value(), new_values_cache); |
| } |
| } |
| |
| if (policy.has_device_minimum_version_aue_message()) { |
| const em::StringPolicyProto& container( |
| policy.device_minimum_version_aue_message()); |
| if (container.has_value()) { |
| new_values_cache->SetValue(kDeviceMinimumVersionAueMessage, |
| base::Value(container.value())); |
| } |
| } |
| |
| if (policy.has_cast_receiver_name()) { |
| const em::CastReceiverNameProto& container(policy.cast_receiver_name()); |
| if (container.has_name()) { |
| new_values_cache->SetValue(kCastReceiverName, |
| base::Value(container.name())); |
| } |
| } |
| |
| if (policy.has_unaffiliated_arc_allowed()) { |
| const em::UnaffiliatedArcAllowedProto& container( |
| policy.unaffiliated_arc_allowed()); |
| if (container.has_unaffiliated_arc_allowed()) { |
| new_values_cache->SetValue( |
| kUnaffiliatedArcAllowed, |
| base::Value(container.unaffiliated_arc_allowed())); |
| } |
| } |
| |
| if (policy.has_network_hostname()) { |
| const em::NetworkHostnameProto& container(policy.network_hostname()); |
| if (container.has_device_hostname_template() && |
| !container.device_hostname_template().empty()) { |
| new_values_cache->SetString(kDeviceHostnameTemplate, |
| container.device_hostname_template()); |
| } |
| } |
| |
| if (policy.has_hostname_user_configurable()) { |
| const em::HostnameUserConfigurableProto& container( |
| policy.hostname_user_configurable()); |
| if (container.has_device_hostname_user_configurable()) { |
| new_values_cache->SetBoolean( |
| kDeviceHostnameUserConfigurable, |
| container.device_hostname_user_configurable()); |
| } |
| } |
| |
| if (policy.virtual_machines_allowed().has_virtual_machines_allowed()) { |
| new_values_cache->SetBoolean( |
| kVirtualMachinesAllowed, |
| policy.virtual_machines_allowed().virtual_machines_allowed()); |
| } |
| |
| if (policy.has_device_unaffiliated_crostini_allowed()) { |
| const em::DeviceUnaffiliatedCrostiniAllowedProto& container( |
| policy.device_unaffiliated_crostini_allowed()); |
| if (container.has_device_unaffiliated_crostini_allowed()) { |
| new_values_cache->SetValue( |
| kDeviceUnaffiliatedCrostiniAllowed, |
| base::Value(container.device_unaffiliated_crostini_allowed())); |
| } |
| } |
| |
| if (policy.has_plugin_vm_allowed()) { |
| const em::PluginVmAllowedProto& container(policy.plugin_vm_allowed()); |
| if (container.has_plugin_vm_allowed()) { |
| new_values_cache->SetValue(kPluginVmAllowed, |
| base::Value(container.plugin_vm_allowed())); |
| } |
| } |
| |
| // Default value of the policy in case it's missing. |
| int access_mode = em::DevicePrintersAccessModeProto::ACCESS_MODE_ALL; |
| // Use DevicePrintersAccessMode policy if present, otherwise Native version. |
| if (policy.has_device_printers_access_mode() && |
| policy.device_printers_access_mode().has_access_mode()) { |
| access_mode = policy.device_printers_access_mode().access_mode(); |
| if (!em::DevicePrintersAccessModeProto::AccessMode_IsValid(access_mode)) { |
| LOG(ERROR) << "Unrecognized device native printers access mode"; |
| // If the policy is outside the range of allowed values, default to |
| // AllowAll. |
| access_mode = em::DevicePrintersAccessModeProto::ACCESS_MODE_ALL; |
| } |
| } else if (policy.has_native_device_printers_access_mode() && |
| policy.native_device_printers_access_mode().has_access_mode()) { |
| access_mode = policy.native_device_printers_access_mode().access_mode(); |
| if (!em::DevicePrintersAccessModeProto::AccessMode_IsValid(access_mode)) { |
| LOG(ERROR) << "Unrecognized device native printers access mode"; |
| // If the policy is outside the range of allowed values, default to |
| // AllowAll. |
| access_mode = em::DevicePrintersAccessModeProto::ACCESS_MODE_ALL; |
| } |
| } |
| new_values_cache->SetInteger(kDevicePrintersAccessMode, access_mode); |
| |
| // Use Blocklist policy if present, otherwise Blacklist version. |
| if (policy.has_device_printers_blocklist()) { |
| base::Value list(base::Value::Type::LIST); |
| const em::DevicePrintersBlocklistProto& proto( |
| policy.device_printers_blocklist()); |
| for (const auto& id : proto.blocklist()) |
| list.Append(id); |
| new_values_cache->SetValue(kDevicePrintersBlocklist, std::move(list)); |
| } else if (policy.has_native_device_printers_blacklist()) { |
| base::Value list(base::Value::Type::LIST); |
| const em::DeviceNativePrintersBlacklistProto& proto( |
| policy.native_device_printers_blacklist()); |
| for (const auto& id : proto.blacklist()) |
| list.Append(id); |
| new_values_cache->SetValue(kDevicePrintersBlocklist, std::move(list)); |
| } |
| |
| // Use Allowlist policy if present, otherwise Whitelist version. |
| if (policy.has_device_printers_allowlist()) { |
| base::Value list(base::Value::Type::LIST); |
| const em::DevicePrintersAllowlistProto& proto( |
| policy.device_printers_allowlist()); |
| for (const auto& id : proto.allowlist()) |
| list.Append(id); |
| new_values_cache->SetValue(kDevicePrintersAllowlist, std::move(list)); |
| } else if (policy.has_native_device_printers_whitelist()) { |
| base::Value list(base::Value::Type::LIST); |
| const em::DeviceNativePrintersWhitelistProto& proto( |
| policy.native_device_printers_whitelist()); |
| for (const auto& id : proto.whitelist()) |
| list.Append(id); |
| new_values_cache->SetValue(kDevicePrintersAllowlist, std::move(list)); |
| } |
| |
| if (policy.has_device_reboot_on_user_signout()) { |
| const em::DeviceRebootOnUserSignoutProto& container( |
| policy.device_reboot_on_user_signout()); |
| if (container.has_reboot_on_signout_mode()) { |
| new_values_cache->SetValue( |
| kDeviceRebootOnUserSignout, |
| base::Value(container.reboot_on_signout_mode())); |
| } |
| } |
| |
| if (policy.has_device_wilco_dtc_allowed()) { |
| const em::DeviceWilcoDtcAllowedProto& container( |
| policy.device_wilco_dtc_allowed()); |
| if (container.has_device_wilco_dtc_allowed()) { |
| new_values_cache->SetValue( |
| kDeviceWilcoDtcAllowed, |
| base::Value(container.device_wilco_dtc_allowed())); |
| } |
| } |
| |
| int dock_mac_address_source = |
| em::DeviceDockMacAddressSourceProto::DOCK_NIC_MAC_ADDRESS; |
| if (policy.has_device_dock_mac_address_source() && |
| policy.device_dock_mac_address_source().has_source()) { |
| dock_mac_address_source = policy.device_dock_mac_address_source().source(); |
| } |
| new_values_cache->SetInteger(kDeviceDockMacAddressSource, |
| dock_mac_address_source); |
| |
| if (policy.has_device_second_factor_authentication() && |
| policy.device_second_factor_authentication().has_mode()) { |
| new_values_cache->SetInteger( |
| kDeviceSecondFactorAuthenticationMode, |
| policy.device_second_factor_authentication().mode()); |
| } |
| |
| // Default value of the policy in case it's missing. |
| bool is_powerwash_allowed = true; |
| if (policy.has_device_powerwash_allowed()) { |
| const em::DevicePowerwashAllowedProto& container( |
| policy.device_powerwash_allowed()); |
| if (container.has_device_powerwash_allowed()) { |
| is_powerwash_allowed = container.device_powerwash_allowed(); |
| } |
| } |
| new_values_cache->SetBoolean(kDevicePowerwashAllowed, is_powerwash_allowed); |
| |
| if (policy.has_device_crostini_arc_adb_sideloading_allowed()) { |
| const em::DeviceCrostiniArcAdbSideloadingAllowedProto& container( |
| policy.device_crostini_arc_adb_sideloading_allowed()); |
| if (container.has_mode()) { |
| new_values_cache->SetValue(kDeviceCrostiniArcAdbSideloadingAllowed, |
| base::Value(container.mode())); |
| } |
| } |
| |
| // Default value of the policy in case it's missing. |
| bool show_low_disk_space_notification = true; |
| // Disable the notification by default for enrolled devices. |
| if (chromeos::InstallAttributes::Get()->IsEnterpriseManaged()) |
| show_low_disk_space_notification = false; |
| if (policy.has_device_show_low_disk_space_notification()) { |
| const em::DeviceShowLowDiskSpaceNotificationProto& container( |
| policy.device_show_low_disk_space_notification()); |
| if (container.has_device_show_low_disk_space_notification()) { |
| show_low_disk_space_notification = |
| container.device_show_low_disk_space_notification(); |
| } |
| } |
| new_values_cache->SetBoolean(kDeviceShowLowDiskSpaceNotification, |
| show_low_disk_space_notification); |
| |
| if (policy.has_usb_detachable_allowlist() && |
| policy.usb_detachable_allowlist().id_size() > 0) { |
| const em::UsbDetachableAllowlistProto& container = |
| policy.usb_detachable_allowlist(); |
| base::Value allowlist(base::Value::Type::LIST); |
| for (const auto& entry : container.id()) { |
| base::Value ids(base::Value::Type::DICTIONARY); |
| if (entry.has_vendor_id() && entry.has_product_id()) { |
| ids.SetIntKey(kUsbDetachableAllowlistKeyVid, entry.vendor_id()); |
| ids.SetIntKey(kUsbDetachableAllowlistKeyPid, entry.product_id()); |
| } |
| allowlist.Append(std::move(ids)); |
| } |
| new_values_cache->SetValue(kUsbDetachableAllowlist, std::move(allowlist)); |
| } else if (policy.has_usb_detachable_whitelist()) { |
| const em::UsbDetachableWhitelistProto& container = |
| policy.usb_detachable_whitelist(); |
| base::Value allowlist(base::Value::Type::LIST); |
| for (const auto& entry : container.id()) { |
| base::Value ids(base::Value::Type::DICTIONARY); |
| if (entry.has_vendor_id() && entry.has_product_id()) { |
| ids.SetIntKey(kUsbDetachableAllowlistKeyVid, entry.vendor_id()); |
| ids.SetIntKey(kUsbDetachableAllowlistKeyPid, entry.product_id()); |
| } |
| allowlist.Append(std::move(ids)); |
| } |
| new_values_cache->SetValue(kUsbDetachableAllowlist, std::move(allowlist)); |
| } |
| |
| if (policy.has_device_borealis_allowed()) { |
| const em::DeviceBorealisAllowedProto& container( |
| policy.device_borealis_allowed()); |
| if (container.has_allowed()) { |
| new_values_cache->SetValue(kBorealisAllowedForDevice, |
| base::Value(container.allowed())); |
| } |
| } |
| |
| if (policy.has_device_allowed_bluetooth_services()) { |
| base::Value list(base::Value::Type::LIST); |
| const em::DeviceAllowedBluetoothServicesProto& container( |
| policy.device_allowed_bluetooth_services()); |
| for (const auto& service_uuid : container.allowlist()) |
| list.Append(service_uuid); |
| new_values_cache->SetValue(kDeviceAllowedBluetoothServices, |
| std::move(list)); |
| } |
| |
| if (policy.has_device_scheduled_reboot()) { |
| const em::DeviceScheduledRebootProto& scheduled_reboot_policy = |
| policy.device_scheduled_reboot(); |
| if (scheduled_reboot_policy.has_device_scheduled_reboot_settings()) { |
| SetJsonDeviceSetting( |
| kDeviceScheduledReboot, policy::key::kDeviceScheduledReboot, |
| scheduled_reboot_policy.device_scheduled_reboot_settings(), |
| new_values_cache); |
| } |
| } |
| |
| if (policy.has_device_restricted_managed_guest_session_enabled()) { |
| const em::DeviceRestrictedManagedGuestSessionEnabledProto& container( |
| policy.device_restricted_managed_guest_session_enabled()); |
| if (container.has_enabled()) { |
| new_values_cache->SetValue(kDeviceRestrictedManagedGuestSessionEnabled, |
| base::Value(container.enabled())); |
| } |
| } |
| |
| bool reven_enable_device_hw_data_usage = |
| policy.has_hardware_data_usage_enabled() && |
| policy.hardware_data_usage_enabled().has_hardware_data_usage_enabled() && |
| policy.hardware_data_usage_enabled().hardware_data_usage_enabled(); |
| new_values_cache->SetBoolean(kRevenEnableDeviceHWDataUsage, |
| reven_enable_device_hw_data_usage); |
| } |
| |
| void DecodeLogUploadPolicies(const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| if (!policy.has_device_log_upload_settings()) |
| return; |
| |
| const em::DeviceLogUploadSettingsProto& log_upload_policy = |
| policy.device_log_upload_settings(); |
| if (log_upload_policy.has_system_log_upload_enabled()) { |
| new_values_cache->SetBoolean(kSystemLogUploadEnabled, |
| log_upload_policy.system_log_upload_enabled()); |
| } |
| } |
| |
| void DecodeDeviceState(const em::PolicyData& policy_data, |
| PrefValueMap* new_values_cache) { |
| if (!policy_data.has_device_state()) |
| return; |
| |
| const em::DeviceState& device_state = policy_data.device_state(); |
| |
| if (device_state.device_mode() == em::DeviceState::DEVICE_MODE_DISABLED) |
| new_values_cache->SetBoolean(kDeviceDisabled, true); |
| if (device_state.has_disabled_state() && |
| device_state.disabled_state().has_message()) { |
| new_values_cache->SetString(kDeviceDisabledMessage, |
| device_state.disabled_state().message()); |
| } |
| } |
| |
| } // namespace |
| |
| DeviceSettingsProvider::DeviceSettingsProvider( |
| const NotifyObserversCallback& notify_cb, |
| DeviceSettingsService* device_settings_service, |
| PrefService* local_state) |
| : CrosSettingsProvider(notify_cb), |
| device_settings_service_(device_settings_service), |
| local_state_(local_state), |
| trusted_status_(TEMPORARILY_UNTRUSTED), |
| ownership_status_(device_settings_service_->GetOwnershipStatus()) { |
| device_settings_service_->AddObserver(this); |
| if (!UpdateFromService()) { |
| // Make sure we have at least the cache data immediately. |
| RetrieveCachedData(); |
| } |
| } |
| |
| DeviceSettingsProvider::~DeviceSettingsProvider() { |
| if (device_settings_service_->GetOwnerSettingsService()) |
| device_settings_service_->GetOwnerSettingsService()->RemoveObserver(this); |
| device_settings_service_->RemoveObserver(this); |
| } |
| |
| // static |
| bool DeviceSettingsProvider::IsDeviceSetting(const std::string& name) { |
| return base::Contains(kKnownSettings, name); |
| } |
| |
| // static |
| void DeviceSettingsProvider::DecodePolicies( |
| const em::ChromeDeviceSettingsProto& policy, |
| PrefValueMap* new_values_cache) { |
| DecodeLoginPolicies(policy, new_values_cache); |
| DecodeNetworkPolicies(policy, new_values_cache); |
| DecodeAutoUpdatePolicies(policy, new_values_cache); |
| DecodeReportingPolicies(policy, new_values_cache); |
| DecodeHeartbeatPolicies(policy, new_values_cache); |
| DecodeGenericPolicies(policy, new_values_cache); |
| DecodeLogUploadPolicies(policy, new_values_cache); |
| } |
| |
| void DeviceSettingsProvider::DoSet(const std::string& path, |
| const base::Value& in_value) { |
| // Make sure that either the current user is the device owner or the |
| // device doesn't have an owner yet. |
| if (!(device_settings_service_->HasPrivateOwnerKey() || |
| ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE)) { |
| LOG(WARNING) << "Changing settings from non-owner, setting=" << path; |
| |
| // Revert UI change. |
| NotifyObservers(path); |
| return; |
| } |
| |
| if (!IsDeviceSetting(path)) { |
| NOTREACHED() << "Try to set unhandled cros setting " << path; |
| return; |
| } |
| |
| if (device_settings_service_->HasPrivateOwnerKey()) { |
| // Directly set setting through OwnerSettingsService. |
| ownership::OwnerSettingsService* service = |
| device_settings_service_->GetOwnerSettingsService(); |
| if (!service->Set(path, in_value)) { |
| NotifyObservers(path); |
| return; |
| } |
| } else { |
| // Temporary store new setting in |
| // |device_settings_|. |device_settings_| will be stored on a disk |
| // as soon as an ownership of device the will be taken. |
| OwnerSettingsServiceAsh::UpdateDeviceSettings(path, in_value, |
| device_settings_); |
| em::PolicyData data; |
| data.set_username(device_settings_service_->GetUsername()); |
| CHECK(device_settings_.SerializeToString(data.mutable_policy_value())); |
| |
| // Set the cache to the updated value. |
| UpdateValuesCache(data, device_settings_, TEMPORARILY_UNTRUSTED); |
| |
| if (!device_settings_cache::Store(data, local_state_)) { |
| LOG(ERROR) << "Couldn't store to the temp storage."; |
| NotifyObservers(path); |
| return; |
| } |
| } |
| } |
| |
| void DeviceSettingsProvider::OwnershipStatusChanged() { |
| DeviceSettingsService::OwnershipStatus new_ownership_status = |
| device_settings_service_->GetOwnershipStatus(); |
| |
| if (device_settings_service_->GetOwnerSettingsService()) |
| device_settings_service_->GetOwnerSettingsService()->AddObserver(this); |
| |
| // If the device just became owned, write the settings accumulated in the |
| // cache to device settings proper. It is important that writing only happens |
| // in this case, as during normal operation, the contents of the cache should |
| // never overwrite actual device settings. |
| if (new_ownership_status == DeviceSettingsService::OWNERSHIP_TAKEN && |
| ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE) { |
| if (device_settings_service_->HasPrivateOwnerKey()) { |
| // There shouldn't be any pending writes, since the cache writes are all |
| // immediate. |
| DCHECK(!store_callback_factory_.HasWeakPtrs()); |
| |
| trusted_status_ = TEMPORARILY_UNTRUSTED; |
| // Apply the locally-accumulated device settings on top of the initial |
| // settings from the service and write back the result. |
| if (device_settings_service_->device_settings()) { |
| em::ChromeDeviceSettingsProto new_settings( |
| *device_settings_service_->device_settings()); |
| new_settings.MergeFrom(device_settings_); |
| device_settings_.Swap(&new_settings); |
| } |
| |
| std::unique_ptr<em::PolicyData> policy(new em::PolicyData()); |
| policy->set_username(device_settings_service_->GetUsername()); |
| CHECK(device_settings_.SerializeToString(policy->mutable_policy_value())); |
| if (!device_settings_service_->GetOwnerSettingsService() |
| ->CommitTentativeDeviceSettings(std::move(policy))) { |
| LOG(ERROR) << "Can't store policy"; |
| } |
| |
| // TODO(https://crbug.com/433840): Some of the above code can be |
| // simplified or removed, once the DoSet function is removed - then there |
| // will be no pending writes. This is because the only values that need to |
| // be written as a pending write is kStatsReportingPref and |
| // kEnableDeviceHWDataUsage, and those are now handled by the Controllers |
| // - see below. Once DoSet is removed and there are no pending writes that |
| // are being maintained by DeviceSettingsProvider, this code for updating |
| // the signed settings for the new owner should probably be moved outside |
| // of DeviceSettingsProvider. |
| |
| StatsReportingController::Get()->OnOwnershipTaken( |
| device_settings_service_->GetOwnerSettingsService()); |
| HWDataUsageController::Get()->OnOwnershipTaken( |
| device_settings_service_->GetOwnerSettingsService()); |
| } else if (chromeos::InstallAttributes::Get()->IsEnterpriseManaged()) { |
| StatsReportingController::Get()->ClearPendingValue(); |
| HWDataUsageController::Get()->ClearPendingValue(); |
| } |
| } |
| |
| ownership_status_ = new_ownership_status; |
| } |
| |
| void DeviceSettingsProvider::DeviceSettingsUpdated() { |
| if (!store_callback_factory_.HasWeakPtrs()) |
| UpdateAndProceedStoring(); |
| } |
| |
| void DeviceSettingsProvider::OnDeviceSettingsServiceShutdown() { |
| device_settings_service_ = nullptr; |
| } |
| |
| void DeviceSettingsProvider::OnTentativeChangesInPolicy( |
| const em::PolicyData& policy_data) { |
| em::ChromeDeviceSettingsProto device_settings; |
| CHECK(device_settings.ParseFromString(policy_data.policy_value())); |
| UpdateValuesCache(policy_data, device_settings, TEMPORARILY_UNTRUSTED); |
| } |
| |
| void DeviceSettingsProvider::RetrieveCachedData() { |
| em::PolicyData policy_data; |
| if (!device_settings_cache::Retrieve(&policy_data, local_state_) || |
| !device_settings_.ParseFromString(policy_data.policy_value())) { |
| VLOG(1) << "Can't retrieve temp store, possibly not created yet."; |
| } |
| |
| UpdateValuesCache(policy_data, device_settings_, trusted_status_); |
| } |
| |
| void DeviceSettingsProvider::UpdateValuesCache( |
| const em::PolicyData& policy_data, |
| const em::ChromeDeviceSettingsProto& settings, |
| TrustedStatus trusted_status) { |
| PrefValueMap new_values_cache; |
| |
| // Determine whether device is managed. See PolicyData::management_mode docs |
| // for details. |
| bool managed = false; |
| if (policy_data.has_management_mode()) { |
| managed = |
| (policy_data.management_mode() == em::PolicyData::ENTERPRISE_MANAGED); |
| } else { |
| managed = policy_data.has_request_token(); |
| } |
| |
| // If the device is not managed, we set the device owner value. |
| if (policy_data.has_username() && !managed) |
| new_values_cache.SetString(kDeviceOwner, policy_data.username()); |
| |
| if (policy_data.has_service_account_identity()) { |
| new_values_cache.SetString(kServiceAccountIdentity, |
| policy_data.service_account_identity()); |
| } |
| |
| DecodePolicies(settings, &new_values_cache); |
| DecodeDeviceState(policy_data, &new_values_cache); |
| |
| // Collect all notifications but send them only after we have swapped the |
| // cache so that if somebody actually reads the cache will be already valid. |
| std::vector<std::string> notifications; |
| // Go through the new values and verify in the old ones. |
| auto iter = new_values_cache.begin(); |
| for (; iter != new_values_cache.end(); ++iter) { |
| const base::Value* old_value; |
| if (!values_cache_.GetValue(iter->first, &old_value) || |
| *old_value != iter->second) { |
| notifications.push_back(iter->first); |
| } |
| } |
| // Now check for values that have been removed from the policy blob. |
| for (iter = values_cache_.begin(); iter != values_cache_.end(); ++iter) { |
| const base::Value* value; |
| if (!new_values_cache.GetValue(iter->first, &value)) |
| notifications.push_back(iter->first); |
| } |
| // Swap and notify. |
| values_cache_.Swap(&new_values_cache); |
| trusted_status_ = trusted_status; |
| for (size_t i = 0; i < notifications.size(); ++i) |
| NotifyObservers(notifications[i]); |
| } |
| |
| bool DeviceSettingsProvider::MitigateMissingPolicy() { |
| // First check if the device has been owned already and if not exit |
| // immediately. |
| if (chromeos::InstallAttributes::Get()->GetMode() != |
| policy::DEVICE_MODE_CONSUMER) |
| return false; |
| |
| // If we are here the policy file were corrupted or missing. This can happen |
| // because we are migrating Pre R11 device to the new secure policies or there |
| // was an attempt to circumvent policy system. In this case we should populate |
| // the policy cache with "safe-mode" defaults which should allow the owner to |
| // log in but lock the device for anyone else until the policy blob has been |
| // recreated by the session manager. |
| LOG(ERROR) << "Corruption of the policy data has been detected." |
| << "Switching to \"safe-mode\" policies until the owner logs in " |
| << "to regenerate the policy data."; |
| base::UmaHistogramBoolean("Enterprise.DeviceSettings.MissingPolicyMitigated", |
| true); |
| |
| device_settings_.Clear(); |
| device_settings_.mutable_allow_new_users()->set_allow_new_users(true); |
| device_settings_.mutable_user_allowlist()->clear_user_allowlist(); |
| device_settings_.mutable_guest_mode_enabled()->set_guest_mode_enabled(true); |
| em::PolicyData empty_policy_data; |
| UpdateValuesCache(empty_policy_data, device_settings_, TRUSTED); |
| values_cache_.SetBoolean(kPolicyMissingMitigationMode, true); |
| |
| return true; |
| } |
| |
| const base::Value* DeviceSettingsProvider::Get(const std::string& path) const { |
| if (IsDeviceSetting(path)) { |
| const base::Value* value; |
| if (values_cache_.GetValue(path, &value)) |
| return value; |
| } else { |
| NOTREACHED() << "Trying to get non cros setting."; |
| } |
| |
| return NULL; |
| } |
| |
| DeviceSettingsProvider::TrustedStatus |
| DeviceSettingsProvider::PrepareTrustedValues(base::OnceClosure* callback) { |
| TrustedStatus status = RequestTrustedEntity(); |
| if (status == TEMPORARILY_UNTRUSTED && *callback) |
| callbacks_.push_back(std::move(*callback)); |
| return status; |
| } |
| |
| bool DeviceSettingsProvider::HandlesSetting(const std::string& path) const { |
| return IsDeviceSetting(path); |
| } |
| |
| DeviceSettingsProvider::TrustedStatus |
| DeviceSettingsProvider::RequestTrustedEntity() { |
| if (ownership_status_ == DeviceSettingsService::OWNERSHIP_NONE) |
| return TRUSTED; |
| return trusted_status_; |
| } |
| |
| void DeviceSettingsProvider::UpdateAndProceedStoring() { |
| // Re-sync the cache from the service. |
| UpdateFromService(); |
| } |
| |
| bool DeviceSettingsProvider::UpdateFromService() { |
| bool settings_loaded = false; |
| base::UmaHistogramEnumeration("Enterprise.DeviceSettings.UpdatedStatus", |
| device_settings_service_->status()); |
| switch (device_settings_service_->status()) { |
| case DeviceSettingsService::STORE_SUCCESS: { |
| const em::PolicyData* policy_data = |
| device_settings_service_->policy_data(); |
| const em::ChromeDeviceSettingsProto* device_settings = |
| device_settings_service_->device_settings(); |
| if (policy_data && device_settings) { |
| if (!device_settings_cache::Store(*policy_data, local_state_)) { |
| LOG(ERROR) << "Couldn't update the local state cache."; |
| } |
| UpdateValuesCache(*policy_data, *device_settings, TRUSTED); |
| device_settings_ = *device_settings; |
| |
| settings_loaded = true; |
| } else { |
| // Initial policy load is still pending. |
| trusted_status_ = TEMPORARILY_UNTRUSTED; |
| } |
| break; |
| } |
| case DeviceSettingsService::STORE_NO_POLICY: |
| if (MitigateMissingPolicy()) |
| break; |
| [[fallthrough]]; |
| case DeviceSettingsService::STORE_KEY_UNAVAILABLE: |
| VLOG(1) << "No policies present yet, will use the temp storage."; |
| trusted_status_ = PERMANENTLY_UNTRUSTED; |
| break; |
| case DeviceSettingsService::STORE_VALIDATION_ERROR: |
| case DeviceSettingsService::STORE_INVALID_POLICY: |
| case DeviceSettingsService::STORE_OPERATION_FAILED: { |
| DeviceSettingsService::Status status = device_settings_service_->status(); |
| LOG(ERROR) << "Failed to retrieve cros policies. Reason: " << status |
| << " (" << DeviceSettingsService::StatusToString(status) |
| << ")"; |
| trusted_status_ = PERMANENTLY_UNTRUSTED; |
| break; |
| } |
| } |
| |
| // Notify the observers we are done. |
| std::vector<base::OnceClosure> callbacks; |
| callbacks.swap(callbacks_); |
| for (auto& callback : callbacks) |
| std::move(callback).Run(); |
| |
| return settings_loaded; |
| } |
| |
| } // namespace ash |