diff options
Diffstat (limited to 'policy/device_policy_impl.cc')
-rw-r--r-- | policy/device_policy_impl.cc | 283 |
1 files changed, 248 insertions, 35 deletions
diff --git a/policy/device_policy_impl.cc b/policy/device_policy_impl.cc index ec52be6..76b82a1 100644 --- a/policy/device_policy_impl.cc +++ b/policy/device_policy_impl.cc @@ -4,26 +4,34 @@ #include "policy/device_policy_impl.h" +#include <algorithm> #include <memory> +#include <set> +#include <string> #include <base/containers/adapters.h> #include <base/files/file_util.h> +#include <base/json/json_reader.h> #include <base/logging.h> #include <base/macros.h> #include <base/memory/ptr_util.h> +#include <base/time/time.h> +#include <base/values.h> #include <openssl/evp.h> #include <openssl/x509.h> -#include <set> -#include <string> - #include "bindings/chrome_device_policy.pb.h" #include "bindings/device_management_backend.pb.h" #include "policy/policy_util.h" #include "policy/resilient_policy_util.h" +namespace em = enterprise_management; + namespace policy { +// Maximum value of RollbackAllowedMilestones policy. +const int kMaxRollbackAllowedMilestones = 4; + namespace { const char kPolicyPath[] = "/var/lib/whitelist/policy"; const char kPublicKeyPath[] = "/var/lib/whitelist/owner.key"; @@ -93,12 +101,76 @@ std::string DecodeConnectionType(int type) { return kConnectionTypes[type]; } +// TODO(adokar): change type to base::Optional<int> when available. +int ConvertDayOfWeekStringToInt(const std::string& day_of_week_str) { + if (day_of_week_str == "Sunday") return 0; + if (day_of_week_str == "Monday") return 1; + if (day_of_week_str == "Tuesday") return 2; + if (day_of_week_str == "Wednesday") return 3; + if (day_of_week_str == "Thursday") return 4; + if (day_of_week_str == "Friday") return 5; + if (day_of_week_str == "Saturday") return 6; + return -1; +} + +bool DecodeWeeklyTimeFromValue(const base::DictionaryValue& dict_value, + int* day_of_week_out, + base::TimeDelta* time_out) { + std::string day_of_week_str; + if (!dict_value.GetString("day_of_week", &day_of_week_str)) { + LOG(ERROR) << "Day of the week is absent."; + return false; + } + *day_of_week_out = ConvertDayOfWeekStringToInt(day_of_week_str); + if (*day_of_week_out == -1) { + LOG(ERROR) << "Undefined day of the week: " << day_of_week_str; + return false; + } + + int hours; + if (!dict_value.GetInteger("hours", &hours) || hours < 0 || hours > 23) { + LOG(ERROR) << "Hours are absent or are outside of the range [0, 24)."; + return false; + } + + int minutes; + if (!dict_value.GetInteger("minutes", &minutes) || minutes < 0 || + minutes > 59) { + LOG(ERROR) << "Minutes are absent or are outside the range [0, 60)"; + return false; + } + + *time_out = + base::TimeDelta::FromMinutes(minutes) + base::TimeDelta::FromHours(hours); + return true; +} + +std::unique_ptr<base::ListValue> DecodeListValueFromJSON( + const std::string& json_string) { + std::string error; + std::unique_ptr<base::Value> decoded_json = + base::JSONReader::ReadAndReturnError(json_string, + base::JSON_ALLOW_TRAILING_COMMAS, + nullptr, &error); + if (!decoded_json) { + LOG(ERROR) << "Invalid JSON string: " << error; + return nullptr; + } + + std::unique_ptr<base::ListValue> list_val = + base::ListValue::From(std::move(decoded_json)); + if (!list_val) { + LOG(ERROR) << "JSON string is not a list"; + return nullptr; + } + + return list_val; +} + } // namespace DevicePolicyImpl::DevicePolicyImpl() - : policy_path_(kPolicyPath), - keyfile_path_(kPublicKeyPath), - verify_root_ownership_(true) {} + : policy_path_(kPolicyPath), keyfile_path_(kPublicKeyPath) {} DevicePolicyImpl::~DevicePolicyImpl() {} @@ -136,8 +208,7 @@ bool DevicePolicyImpl::GetUserWhitelist( std::vector<std::string>* user_whitelist) const { if (!device_policy_.has_user_whitelist()) return false; - const enterprise_management::UserWhitelistProto& proto = - device_policy_.user_whitelist(); + const em::UserWhitelistProto& proto = device_policy_.user_whitelist(); user_whitelist->clear(); for (int i = 0; i < proto.user_whitelist_size(); i++) user_whitelist->push_back(proto.user_whitelist(i)); @@ -192,8 +263,7 @@ bool DevicePolicyImpl::GetReportVersionInfo(bool* report_version_info) const { if (!device_policy_.has_device_reporting()) return false; - const enterprise_management::DeviceReportingProto& proto = - device_policy_.device_reporting(); + const em::DeviceReportingProto& proto = device_policy_.device_reporting(); if (!proto.has_report_version_info()) return false; @@ -206,8 +276,7 @@ bool DevicePolicyImpl::GetReportActivityTimes( if (!device_policy_.has_device_reporting()) return false; - const enterprise_management::DeviceReportingProto& proto = - device_policy_.device_reporting(); + const em::DeviceReportingProto& proto = device_policy_.device_reporting(); if (!proto.has_report_activity_times()) return false; @@ -219,8 +288,7 @@ bool DevicePolicyImpl::GetReportBootMode(bool* report_boot_mode) const { if (!device_policy_.has_device_reporting()) return false; - const enterprise_management::DeviceReportingProto& proto = - device_policy_.device_reporting(); + const em::DeviceReportingProto& proto = device_policy_.device_reporting(); if (!proto.has_report_boot_mode()) return false; @@ -241,8 +309,7 @@ bool DevicePolicyImpl::GetReleaseChannel(std::string* release_channel) const { if (!device_policy_.has_release_channel()) return false; - const enterprise_management::ReleaseChannelProto& proto = - device_policy_.release_channel(); + const em::ReleaseChannelProto& proto = device_policy_.release_channel(); if (!proto.has_release_channel()) return false; @@ -255,8 +322,7 @@ bool DevicePolicyImpl::GetReleaseChannelDelegated( if (!device_policy_.has_release_channel()) return false; - const enterprise_management::ReleaseChannelProto& proto = - device_policy_.release_channel(); + const em::ReleaseChannelProto& proto = device_policy_.release_channel(); if (!proto.has_release_channel_delegated()) return false; @@ -268,7 +334,7 @@ bool DevicePolicyImpl::GetUpdateDisabled(bool* update_disabled) const { if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (!proto.has_update_disabled()) return false; @@ -282,7 +348,7 @@ bool DevicePolicyImpl::GetTargetVersionPrefix( if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (!proto.has_target_version_prefix()) return false; @@ -291,12 +357,58 @@ bool DevicePolicyImpl::GetTargetVersionPrefix( return true; } +bool DevicePolicyImpl::GetRollbackToTargetVersion( + int* rollback_to_target_version) const { + if (!device_policy_.has_auto_update_settings()) + return false; + + const em::AutoUpdateSettingsProto& proto = + device_policy_.auto_update_settings(); + if (!proto.has_rollback_to_target_version()) + return false; + + *rollback_to_target_version = proto.rollback_to_target_version(); + return true; +} + +bool DevicePolicyImpl::GetRollbackAllowedMilestones( + int* rollback_allowed_milestones) const { + // This policy can be only set for devices which are enterprise enrolled. + if (!install_attributes_reader_->IsLocked()) + return false; + if (install_attributes_reader_->GetAttribute( + InstallAttributesReader::kAttrMode) != + InstallAttributesReader::kDeviceModeEnterprise && + install_attributes_reader_->GetAttribute( + InstallAttributesReader::kAttrMode) != + InstallAttributesReader::kDeviceModeEnterpriseAD) + return false; + + if (device_policy_.has_auto_update_settings()) { + const em::AutoUpdateSettingsProto& proto = + device_policy_.auto_update_settings(); + if (proto.has_rollback_allowed_milestones()) { + // Policy is set, enforce minimum and maximum constraints. + *rollback_allowed_milestones = proto.rollback_allowed_milestones(); + if (*rollback_allowed_milestones < 0) + *rollback_allowed_milestones = 0; + if (*rollback_allowed_milestones > kMaxRollbackAllowedMilestones) + *rollback_allowed_milestones = kMaxRollbackAllowedMilestones; + return true; + } + } + // Policy is not present, use default for enterprise devices. + VLOG(1) << "RollbackAllowedMilestones policy is not set, using default 0."; + *rollback_allowed_milestones = 0; + return true; +} + bool DevicePolicyImpl::GetScatterFactorInSeconds( int64_t* scatter_factor_in_seconds) const { if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (!proto.has_scatter_factor_in_seconds()) return false; @@ -310,7 +422,7 @@ bool DevicePolicyImpl::GetAllowedConnectionTypesForUpdate( if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (proto.allowed_connection_types_size() <= 0) return false; @@ -328,7 +440,7 @@ bool DevicePolicyImpl::GetOpenNetworkConfiguration( if (!device_policy_.has_open_network_configuration()) return false; - const enterprise_management::DeviceOpenNetworkConfigurationProto& proto = + const em::DeviceOpenNetworkConfigurationProto& proto = device_policy_.open_network_configuration(); if (!proto.has_open_network_configuration()) return false; @@ -338,11 +450,11 @@ bool DevicePolicyImpl::GetOpenNetworkConfiguration( } bool DevicePolicyImpl::GetOwner(std::string* owner) const { - // The device is enterprise enrolled iff a request token exists. - if (policy_data_.has_request_token()) { + if (IsEnterpriseManaged()) { *owner = ""; return true; } + if (!policy_data_.has_username()) return false; *owner = policy_data_.username(); @@ -354,7 +466,7 @@ bool DevicePolicyImpl::GetHttpDownloadsEnabled( if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (!proto.has_http_downloads_enabled()) @@ -368,7 +480,7 @@ bool DevicePolicyImpl::GetAuP2PEnabled(bool* au_p2p_enabled) const { if (!device_policy_.has_auto_update_settings()) return false; - const enterprise_management::AutoUpdateSettingsProto& proto = + const em::AutoUpdateSettingsProto& proto = device_policy_.auto_update_settings(); if (!proto.has_p2p_enabled()) @@ -383,7 +495,7 @@ bool DevicePolicyImpl::GetAllowKioskAppControlChromeVersion( if (!device_policy_.has_allow_kiosk_app_control_chrome_version()) return false; - const enterprise_management::AllowKioskAppControlChromeVersionProto& proto = + const em::AllowKioskAppControlChromeVersionProto& proto = device_policy_.allow_kiosk_app_control_chrome_version(); if (!proto.has_allow_kiosk_app_control_chrome_version()) @@ -398,11 +510,11 @@ bool DevicePolicyImpl::GetUsbDetachableWhitelist( std::vector<UsbDeviceId>* usb_whitelist) const { if (!device_policy_.has_usb_detachable_whitelist()) return false; - const enterprise_management::UsbDetachableWhitelistProto& proto = + const em::UsbDetachableWhitelistProto& proto = device_policy_.usb_detachable_whitelist(); usb_whitelist->clear(); for (int i = 0; i < proto.id_size(); i++) { - const ::enterprise_management::UsbDeviceIdProto& id = proto.id(i); + const em::UsbDeviceIdProto& id = proto.id(i); UsbDeviceId dev_id; dev_id.vendor_id = id.has_vendor_id() ? id.vendor_id() : 0; dev_id.product_id = id.has_product_id() ? id.product_id() : 0; @@ -411,12 +523,46 @@ bool DevicePolicyImpl::GetUsbDetachableWhitelist( return true; } +bool DevicePolicyImpl::GetDeviceUpdateStagingSchedule( + std::vector<DayPercentagePair>* staging_schedule_out) const { + staging_schedule_out->clear(); + + if (!device_policy_.has_auto_update_settings()) + return false; + + const em::AutoUpdateSettingsProto &proto = + device_policy_.auto_update_settings(); + + if (!proto.has_staging_schedule()) + return false; + + std::unique_ptr<base::ListValue> list_val = + DecodeListValueFromJSON(proto.staging_schedule()); + if (!list_val) + return false; + + for (base::Value* const& pair_value : *list_val) { + base::DictionaryValue* day_percentage_pair; + if (!pair_value->GetAsDictionary(&day_percentage_pair)) + return false; + int days, percentage; + if (!day_percentage_pair->GetInteger("days", &days) || + !day_percentage_pair->GetInteger("percentage", &percentage)) + return false; + // Limit the percentage to [0, 100] and days to [1, 28]; + staging_schedule_out->push_back({std::max(std::min(days, 28), 1), + std::max(std::min(percentage, 100), 0)}); + } + + return true; +} + bool DevicePolicyImpl::GetAutoLaunchedKioskAppId( std::string* app_id_out) const { if (!device_policy_.has_device_local_accounts()) return false; - const enterprise_management::DeviceLocalAccountsProto& local_accounts = + const em::DeviceLocalAccountsProto& local_accounts = device_policy_.device_local_accounts(); // For auto-launched kiosk apps, the delay needs to be 0. @@ -424,7 +570,7 @@ bool DevicePolicyImpl::GetAutoLaunchedKioskAppId( local_accounts.auto_login_delay() != 0) return false; - for (const enterprise_management::DeviceLocalAccountInfoProto& account : + for (const em::DeviceLocalAccountInfoProto& account : local_accounts.account()) { // If this isn't an auto-login account, move to the next one. if (account.account_id() != local_accounts.auto_login_id()) @@ -433,8 +579,7 @@ bool DevicePolicyImpl::GetAutoLaunchedKioskAppId( // If the auto-launched account is not a kiosk app, bail out, we aren't // running in auto-launched kiosk mode. if (account.type() != - enterprise_management::DeviceLocalAccountInfoProto:: - ACCOUNT_TYPE_KIOSK_APP) { + em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_KIOSK_APP) { return false; } @@ -446,6 +591,74 @@ bool DevicePolicyImpl::GetAutoLaunchedKioskAppId( return false; } +bool DevicePolicyImpl::IsEnterpriseManaged() const { + if (policy_data_.has_management_mode()) + return policy_data_.management_mode() == em::PolicyData::ENTERPRISE_MANAGED; + // Fall back to checking the request token, see management_mode documentation + // in device_management_backend.proto. + return policy_data_.has_request_token(); +} + +bool DevicePolicyImpl::GetSecondFactorAuthenticationMode(int* mode_out) const { + if (!device_policy_.has_device_second_factor_authentication()) + return false; + + const em::DeviceSecondFactorAuthenticationProto& proto = + device_policy_.device_second_factor_authentication(); + + if (!proto.has_mode()) + return false; + + *mode_out = proto.mode(); + return true; +} + +bool DevicePolicyImpl::GetDisallowedTimeIntervals( + std::vector<WeeklyTimeInterval>* intervals_out) const { + intervals_out->clear(); + + if (!device_policy_.has_auto_update_settings()) { + return false; + } + + const em::AutoUpdateSettingsProto& proto = + device_policy_.auto_update_settings(); + + if (!proto.has_disallowed_time_intervals()) { + return false; + } + + std::unique_ptr<base::ListValue> list_val = + DecodeListValueFromJSON(proto.disallowed_time_intervals()); + if (!list_val) + return false; + + for (base::Value* const& interval_value : *list_val) { + base::DictionaryValue* interval_dict; + if (!interval_value->GetAsDictionary(&interval_dict)) { + LOG(ERROR) << "Invalid JSON string given. Interval is not a dict."; + return false; + } + base::DictionaryValue* start; + base::DictionaryValue* end; + if (!interval_dict->GetDictionary("start", &start) || + !interval_dict->GetDictionary("end", &end)) { + LOG(ERROR) << "Interval is missing start/end."; + return false; + } + WeeklyTimeInterval weekly_interval; + if (!DecodeWeeklyTimeFromValue(*start, &weekly_interval.start_day_of_week, + &weekly_interval.start_time) || + !DecodeWeeklyTimeFromValue(*end, &weekly_interval.end_day_of_week, + &weekly_interval.end_time)) { + return false; + } + + intervals_out->push_back(weekly_interval); + } + return true; +} + bool DevicePolicyImpl::VerifyPolicyFile(const base::FilePath& policy_path) { if (!verify_root_ownership_) { return true; @@ -506,7 +719,7 @@ bool DevicePolicyImpl::LoadPolicyFromFile(const base::FilePath& policy_path) { return false; } - bool verify_policy = true; + bool verify_policy = verify_policy_; if (!install_attributes_reader_) { install_attributes_reader_ = std::make_unique<InstallAttributesReader>(); } |