blob: 8fc327895be95167b142f640380b8f0af61e2125 [file] [log] [blame]
// Copyright 2016 The Chromium OS 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 "authpolicy/policy/device_policy_encoder.h"
#include <memory>
#include <utility>
#include <base/json/json_reader.h>
#include <base/strings/string_number_conversions.h>
#include <components/policy/core/common/registry_dict.h>
#include <dbus/shill/dbus-constants.h>
#include "authpolicy/policy/policy_encoder_helper.h"
#include "bindings/chrome_device_policy.pb.h"
#include "bindings/policy_constants.h"
namespace em = enterprise_management;
namespace policy {
constexpr std::pair<const char*, int> kConnectionTypes[] = {
std::make_pair(
shill::kTypeEthernet,
em::AutoUpdateSettingsProto_ConnectionType_CONNECTION_TYPE_ETHERNET),
std::make_pair(
shill::kTypeWifi,
em::AutoUpdateSettingsProto_ConnectionType_CONNECTION_TYPE_WIFI),
std::make_pair(
shill::kTypeWimax,
em::AutoUpdateSettingsProto_ConnectionType_CONNECTION_TYPE_WIMAX),
std::make_pair(
shill::kTypeBluetooth,
em::AutoUpdateSettingsProto_ConnectionType_CONNECTION_TYPE_BLUETOOTH),
std::make_pair(
shill::kTypeCellular,
em::AutoUpdateSettingsProto_ConnectionType_CONNECTION_TYPE_CELLULAR)};
constexpr size_t kConnectionTypesSize = arraysize(kConnectionTypes);
static_assert(
em::AutoUpdateSettingsProto_ConnectionType_ConnectionType_ARRAYSIZE ==
static_cast<int>(kConnectionTypesSize),
"Add all values here");
namespace {
// Translates string connection types to enums.
bool DecodeConnectionType(const std::string& value,
em::AutoUpdateSettingsProto_ConnectionType* type) {
DCHECK(type);
for (size_t n = 0; n < arraysize(kConnectionTypes); ++n) {
if (value.compare(kConnectionTypes[n].first) == 0) {
int int_type = kConnectionTypes[n].second;
DCHECK(em::AutoUpdateSettingsProto_ConnectionType_IsValid(int_type));
*type = static_cast<em::AutoUpdateSettingsProto_ConnectionType>(int_type);
return true;
}
}
LOG(ERROR) << "Invalid connection type '" << value << "'.";
return false;
}
// Parses the |json| string to a base::DictionaryValue. Returns nullptr on error
// and sets the |error| string.
std::unique_ptr<base::DictionaryValue> JsonToDictionary(const std::string& json,
std::string* error) {
DCHECK(error);
std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, error);
if (!root)
return nullptr; // |error| is set by ReadAndReturnError().
std::unique_ptr<base::DictionaryValue> dict_value =
base::DictionaryValue::From(std::move(root));
if (!dict_value)
*error = "JSON is not a dictionary: '" + json + "'";
return dict_value;
}
} // namespace
void DevicePolicyEncoder::EncodePolicy(
em::ChromeDeviceSettingsProto* policy) const {
EncodeLoginPolicies(policy);
EncodeNetworkPolicies(policy);
EncodeReportingPolicies(policy);
EncodeAutoUpdatePolicies(policy);
EncodeAccessibilityPolicies(policy);
EncodeGenericPolicies(policy);
}
void DevicePolicyEncoder::EncodeLoginPolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeBoolean(key::kDeviceGuestModeEnabled, [policy](bool value) {
policy->mutable_guest_mode_enabled()->set_guest_mode_enabled(value);
});
EncodeBoolean(key::kDeviceRebootOnShutdown, [policy](bool value) {
policy->mutable_reboot_on_shutdown()->set_reboot_on_shutdown(value);
});
EncodeBoolean(key::kDeviceShowUserNamesOnSignin, [policy](bool value) {
policy->mutable_show_user_names()->set_show_user_names(value);
});
EncodeBoolean(key::kDeviceAllowNewUsers, [policy](bool value) {
policy->mutable_allow_new_users()->set_allow_new_users(value);
});
EncodeStringList(key::kDeviceUserWhitelist,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_user_whitelist();
list->clear_user_whitelist();
for (const std::string& value : values)
list->add_user_whitelist(value);
});
EncodeBoolean(key::kDeviceEphemeralUsersEnabled, [policy](bool value) {
policy->mutable_ephemeral_users_enabled()->set_ephemeral_users_enabled(
value);
});
// TODO(ljusten): It is not clear how to map the DeviceLocalAccounts policy
// to DeviceLocalAccountsProto accounts. The former is a string with no json
// schema, the latter is a struct with id, type and kiosk info.
HandleUnsupported(key::kDeviceLocalAccounts);
EncodeString(
key::kDeviceLocalAccountAutoLoginId, [policy](const std::string& value) {
policy->mutable_device_local_accounts()->set_auto_login_id(value);
});
EncodeInteger(key::kDeviceLocalAccountAutoLoginDelay, [policy](int value) {
policy->mutable_device_local_accounts()->set_auto_login_delay(value);
});
EncodeBoolean(
key::kDeviceLocalAccountAutoLoginBailoutEnabled, [policy](bool value) {
policy->mutable_device_local_accounts()->set_enable_auto_login_bailout(
value);
});
EncodeBoolean(key::kDeviceLocalAccountPromptForNetworkWhenOffline,
[policy](bool value) {
policy->mutable_device_local_accounts()
->set_prompt_for_network_when_offline(value);
});
EncodeBoolean(key::kSupervisedUsersEnabled, [policy](bool value) {
policy->mutable_supervised_users_settings()->set_supervised_users_enabled(
value);
});
EncodeBoolean(key::kDeviceTransferSAMLCookies, [policy](bool value) {
policy->mutable_saml_settings()->set_transfer_saml_cookies(value);
});
EncodeInteger(key::kLoginAuthenticationBehavior, [policy](int value) {
policy->mutable_login_authentication_behavior()
->set_login_authentication_behavior(
static_cast<em::LoginAuthenticationBehaviorProto_LoginBehavior>(
value));
});
EncodeBoolean(key::kDeviceAllowBluetooth, [policy](bool value) {
policy->mutable_allow_bluetooth()->set_allow_bluetooth(value);
});
EncodeStringList(key::kLoginVideoCaptureAllowedUrls,
[policy](const std::vector<std::string>& values) {
auto list =
policy->mutable_login_video_capture_allowed_urls();
list->clear_urls();
for (const std::string& value : values)
list->add_urls(value);
});
EncodeStringList(key::kDeviceLoginScreenAppInstallList,
[policy](const std::vector<std::string>& values) {
auto list =
policy->mutable_device_login_screen_app_install_list();
list->clear_device_login_screen_app_install_list();
for (const std::string& value : values)
list->add_device_login_screen_app_install_list(value);
});
EncodeStringList(key::kDeviceLoginScreenLocales,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_login_screen_locales();
list->clear_login_screen_locales();
for (const std::string& value : values)
list->add_login_screen_locales(value);
});
EncodeStringList(key::kDeviceLoginScreenInputMethods,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_login_screen_input_methods();
list->clear_login_screen_input_methods();
for (const std::string& value : values)
list->add_login_screen_input_methods(value);
});
}
void DevicePolicyEncoder::EncodeNetworkPolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeBoolean(key::kDeviceDataRoamingEnabled, [policy](bool value) {
policy->mutable_data_roaming_enabled()->set_data_roaming_enabled(value);
});
EncodeString(
key::kNetworkThrottlingEnabled, [policy](const std::string& value) {
std::string error;
std::unique_ptr<base::DictionaryValue> dict_value =
JsonToDictionary(value, &error);
bool enabled;
int upload_rate_kbits, download_rate_kbits;
if (!dict_value || !dict_value->GetBoolean("enabled", &enabled) ||
!dict_value->GetInteger("upload_rate_kbits", &upload_rate_kbits) ||
!dict_value->GetInteger("download_rate_kbits",
&download_rate_kbits)) {
LOG(ERROR) << "Invalid JSON string '"
<< (!error.empty() ? error : value) << "' for policy '"
<< key::kNetworkThrottlingEnabled
<< "', ignoring. Expected: "
<< "'{\"enabled\"=<true/false>, \"upload_rate_kbits\""
<< "=<kbits>, \"download_rate_kbits\"=<kbits>}'.";
return;
}
em::NetworkThrottlingEnabledProto* entry =
policy->mutable_network_throttling();
entry->set_enabled(enabled);
entry->set_upload_rate_kbits(upload_rate_kbits);
entry->set_download_rate_kbits(download_rate_kbits);
});
EncodeString(key::kDeviceOpenNetworkConfiguration,
[policy](const std::string& value) {
policy->mutable_open_network_configuration()
->set_open_network_configuration(value);
});
}
void DevicePolicyEncoder::EncodeReportingPolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeBoolean(key::kReportDeviceVersionInfo, [policy](bool value) {
policy->mutable_device_reporting()->set_report_version_info(value);
});
EncodeBoolean(key::kReportDeviceActivityTimes, [policy](bool value) {
policy->mutable_device_reporting()->set_report_activity_times(value);
});
EncodeBoolean(key::kReportDeviceBootMode, [policy](bool value) {
policy->mutable_device_reporting()->set_report_boot_mode(value);
});
EncodeBoolean(key::kReportDeviceLocation, [policy](bool value) {
policy->mutable_device_reporting()->set_report_location(value);
});
EncodeBoolean(key::kReportDeviceNetworkInterfaces, [policy](bool value) {
policy->mutable_device_reporting()->set_report_network_interfaces(value);
});
EncodeBoolean(key::kReportDeviceUsers, [policy](bool value) {
policy->mutable_device_reporting()->set_report_users(value);
});
EncodeBoolean(key::kReportDeviceHardwareStatus, [policy](bool value) {
policy->mutable_device_reporting()->set_report_hardware_status(value);
});
EncodeBoolean(key::kReportDeviceSessionStatus, [policy](bool value) {
policy->mutable_device_reporting()->set_report_session_status(value);
});
EncodeBoolean(key::kReportUploadFrequency, [policy](bool value) {
policy->mutable_device_reporting()->set_device_status_frequency(value);
});
EncodeBoolean(key::kHeartbeatEnabled, [policy](bool value) {
policy->mutable_device_heartbeat_settings()->set_heartbeat_enabled(value);
});
EncodeInteger(key::kHeartbeatFrequency, [policy](int value) {
policy->mutable_device_heartbeat_settings()->set_heartbeat_frequency(value);
});
EncodeBoolean(key::kLogUploadEnabled, [policy](bool value) {
policy->mutable_device_log_upload_settings()->set_system_log_upload_enabled(
value);
});
}
void DevicePolicyEncoder::EncodeAutoUpdatePolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeString(key::kChromeOsReleaseChannel,
[policy](const std::string& value) {
policy->mutable_release_channel()->set_release_channel(value);
});
EncodeBoolean(key::kChromeOsReleaseChannelDelegated, [policy](bool value) {
policy->mutable_release_channel()->set_release_channel_delegated(value);
});
EncodeBoolean(key::kDeviceAutoUpdateDisabled, [policy](bool value) {
policy->mutable_auto_update_settings()->set_update_disabled(value);
});
EncodeString(
key::kDeviceTargetVersionPrefix, [policy](const std::string& value) {
policy->mutable_auto_update_settings()->set_target_version_prefix(
value);
});
// target_version_display_name is not actually a policy, but a display
// string for target_version_prefix, so we ignore it. It seems to be
// unreferenced as well.
EncodeInteger(key::kDeviceUpdateScatterFactor, [policy](int value) {
policy->mutable_auto_update_settings()->set_scatter_factor_in_seconds(
value);
});
EncodeStringList(key::kDeviceUpdateAllowedConnectionTypes,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_auto_update_settings();
list->clear_allowed_connection_types();
for (const std::string& value : values) {
em::AutoUpdateSettingsProto_ConnectionType type;
if (DecodeConnectionType(value, &type))
list->add_allowed_connection_types(type);
}
});
EncodeBoolean(key::kDeviceUpdateHttpDownloadsEnabled, [policy](bool value) {
policy->mutable_auto_update_settings()->set_http_downloads_enabled(value);
});
EncodeBoolean(key::kRebootAfterUpdate, [policy](bool value) {
policy->mutable_auto_update_settings()->set_reboot_after_update(value);
});
EncodeBoolean(key::kDeviceAutoUpdateP2PEnabled, [policy](bool value) {
policy->mutable_auto_update_settings()->set_p2p_enabled(value);
});
EncodeBoolean(key::kAllowKioskAppControlChromeVersion, [policy](bool value) {
policy->mutable_allow_kiosk_app_control_chrome_version()
->set_allow_kiosk_app_control_chrome_version(value);
});
}
void DevicePolicyEncoder::EncodeAccessibilityPolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeBoolean(key::kDeviceLoginScreenDefaultLargeCursorEnabled,
[policy](bool value) {
policy->mutable_accessibility_settings()
->set_login_screen_default_large_cursor_enabled(value);
});
EncodeBoolean(key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
[policy](bool value) {
policy->mutable_accessibility_settings()
->set_login_screen_default_spoken_feedback_enabled(value);
});
EncodeBoolean(key::kDeviceLoginScreenDefaultHighContrastEnabled,
[policy](bool value) {
policy->mutable_accessibility_settings()
->set_login_screen_default_high_contrast_enabled(value);
});
EncodeInteger(
key::kDeviceLoginScreenDefaultScreenMagnifierType, [policy](int value) {
policy->mutable_accessibility_settings()
->set_login_screen_default_screen_magnifier_type(
static_cast<em::AccessibilitySettingsProto_ScreenMagnifierType>(
value));
});
EncodeBoolean(
key::kDeviceLoginScreenDefaultVirtualKeyboardEnabled,
[policy](bool value) {
policy->mutable_accessibility_settings()
->set_login_screen_default_virtual_keyboard_enabled(value);
});
}
void DevicePolicyEncoder::EncodeGenericPolicies(
em::ChromeDeviceSettingsProto* policy) const {
EncodeInteger(key::kDevicePolicyRefreshRate, [policy](int value) {
policy->mutable_device_policy_refresh_rate()
->set_device_policy_refresh_rate(value);
});
EncodeBoolean(key::kDeviceMetricsReportingEnabled, [policy](bool value) {
policy->mutable_metrics_enabled()->set_metrics_enabled(value);
});
EncodeString(key::kSystemTimezone, [policy](const std::string& value) {
policy->mutable_system_timezone()->set_timezone(value);
});
EncodeInteger(key::kSystemTimezoneAutomaticDetection, [policy](int value) {
policy->mutable_system_timezone()->set_timezone_detection_type(
static_cast<em::SystemTimezoneProto_AutomaticTimezoneDetectionType>(
value));
});
EncodeBoolean(key::kSystemUse24HourClock, [policy](bool value) {
policy->mutable_use_24hour_clock()->set_use_24hour_clock(value);
});
EncodeBoolean(
key::kDeviceAllowRedeemChromeOsRegistrationOffers, [policy](bool value) {
policy->mutable_allow_redeem_offers()->set_allow_redeem_offers(value);
});
EncodeInteger(key::kUptimeLimit, [policy](int value) {
policy->mutable_uptime_limit()->set_uptime_limit(value);
});
EncodeStringList(key::kDeviceStartUpFlags,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_start_up_flags();
list->clear_flags();
for (const std::string& value : values)
list->add_flags(value);
});
EncodeString(key::kDeviceVariationsRestrictParameter,
[policy](const std::string& value) {
policy->mutable_variations_parameter()->set_parameter(value);
});
EncodeBoolean(key::kAttestationEnabledForDevice, [policy](bool value) {
policy->mutable_attestation_settings()->set_attestation_enabled(value);
});
EncodeBoolean(
key::kAttestationForContentProtectionEnabled, [policy](bool value) {
policy->mutable_attestation_settings()->set_content_protection_enabled(
value);
});
EncodeString(key::kDeviceLoginScreenPowerManagement,
[policy](const std::string& value) {
policy->mutable_login_screen_power_management()
->set_login_screen_power_management(value);
});
EncodeBoolean(key::kDeviceBlockDevmode, [policy](bool value) {
policy->mutable_system_settings()->set_block_devmode(value);
});
EncodeInteger(key::kExtensionCacheSize, [policy](int value) {
policy->mutable_extension_cache_size()->set_extension_cache_size(value);
});
EncodeString(key::kDeviceLoginScreenDomainAutoComplete,
[policy](const std::string& value) {
policy->mutable_login_screen_domain_auto_complete()
->set_login_screen_domain_auto_complete(value);
});
EncodeInteger(key::kDisplayRotationDefault, [policy](int value) {
policy->mutable_display_rotation_default()->set_display_rotation_default(
static_cast<em::DisplayRotationDefaultProto_Rotation>(value));
});
EncodeStringList(
key::kUsbDetachableWhitelist,
[policy](const std::vector<std::string>& values) {
auto list = policy->mutable_usb_detachable_whitelist();
list->clear_id();
for (const std::string& value : values) {
std::string error;
std::unique_ptr<base::DictionaryValue> dict_value =
JsonToDictionary(value, &error);
int vid, pid;
if (!dict_value || !dict_value->GetInteger("vendor_id", &vid) ||
!dict_value->GetInteger("product_id", &pid)) {
LOG(ERROR) << "Invalid JSON string '"
<< (!error.empty() ? error : value) << "' for policy '"
<< key::kUsbDetachableWhitelist
<< "', ignoring. Expected: "
<< "'{\"vendor_id\"=<vid>, \"product_id\"=<pid>}'.";
continue;
}
em::UsbDeviceIdProto* entry = list->add_id();
entry->set_vendor_id(vid);
entry->set_product_id(pid);
}
});
EncodeBoolean(key::kDeviceQuirksDownloadEnabled, [policy](bool value) {
policy->mutable_quirks_download_enabled()->set_quirks_download_enabled(
value);
});
EncodeString(key::kDeviceWallpaperImage, [policy](const std::string& value) {
policy->mutable_device_wallpaper_image()->set_device_wallpaper_image(value);
});
}
void DevicePolicyEncoder::EncodeBoolean(
const char* policy_name, const BooleanPolicyCallback& set_policy) const {
// Try to get policy value from dict.
const base::Value* value = dict_->GetValue(policy_name);
if (!value)
return;
// Get actual value, doing type conversion if necessary.
bool bool_value;
if (!GetAsBoolean(value, &bool_value)) {
PrintConversionError(value, "boolean", policy_name);
return;
}
LOG_IF(INFO, log_policy_values_)
<< " bool " << policy_name << " = " << (bool_value ? "true" : "false");
// Create proto and set value.
set_policy(bool_value);
}
void DevicePolicyEncoder::EncodeInteger(
const char* policy_name, const IntegerPolicyCallback& set_policy) const {
// Try to get policy value from dict.
const base::Value* value = dict_->GetValue(policy_name);
if (!value)
return;
// Get actual value, doing type conversion if necessary.
int int_value;
if (!GetAsInteger(value, &int_value)) {
PrintConversionError(value, "integer", policy_name);
return;
}
LOG_IF(INFO, log_policy_values_)
<< " int " << policy_name << " = " << int_value;
// Create proto and set value.
set_policy(int_value);
}
void DevicePolicyEncoder::EncodeString(
const char* policy_name, const StringPolicyCallback& set_policy) const {
// Try to get policy value from dict.
const base::Value* value = dict_->GetValue(policy_name);
if (!value)
return;
// Get actual value, doing type conversion if necessary.
std::string string_value;
if (!GetAsString(value, &string_value)) {
PrintConversionError(value, "string", policy_name);
return;
}
LOG_IF(INFO, log_policy_values_)
<< " str " << policy_name << " = " << string_value;
// Create proto and set value.
set_policy(string_value);
}
void DevicePolicyEncoder::EncodeStringList(
const char* policy_name, const StringListPolicyCallback& set_policy) const {
// Try to get policy key from dict.
const RegistryDict* key = dict_->GetKey(policy_name);
if (!key)
return;
// Get and check all values. Do this in advance to prevent partial writes.
std::vector<std::string> string_values;
for (int index = 0; /* empty */; ++index) {
std::string indexStr = base::IntToString(index + 1);
const base::Value* value = key->GetValue(indexStr);
if (!value)
break;
std::string string_value;
if (!GetAsString(value, &string_value)) {
PrintConversionError(value, "string", policy_name, &indexStr);
return;
}
string_values.push_back(string_value);
}
if (log_policy_values_ && LOG_IS_ON(INFO)) {
LOG(INFO) << " strlist " << policy_name;
for (const std::string& value : string_values)
LOG(INFO) << " " << value;
}
// Create proto and set values.
set_policy(string_values);
}
void DevicePolicyEncoder::HandleUnsupported(const char* policy_name) const {
// Try to get policy value from dict.
const base::Value* value = dict_->GetValue(policy_name);
if (!value)
return;
LOG_IF(INFO, log_policy_values_)
<< "Ignoring unsupported policy '" << policy_name << "'.";
}
} // namespace policy