| // Copyright 2020 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/enterprise/signals/device_info_fetcher_linux.h" |
| |
| #if defined(USE_GIO) |
| #include <gio/gio.h> |
| #endif // defined(USE_GIO) |
| #include <sys/stat.h> |
| #include <sys/sysmacros.h> |
| |
| #include <string> |
| |
| #include "base/environment.h" |
| #include "base/files/dir_reader_posix.h" |
| #include "base/files/file.h" |
| #include "base/files/file_util.h" |
| #include "base/nix/xdg_util.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/system/sys_info.h" |
| #include "net/base/network_interfaces.h" |
| |
| using SettingValue = enterprise_signals::DeviceInfo::SettingValue; |
| |
| namespace enterprise_signals { |
| |
| namespace { |
| |
| std::string GetDeviceModel() { |
| return base::SysInfo::HardwareModelName(); |
| } |
| |
| std::string GetOsVersion() { |
| base::FilePath os_release_file("/etc/os-release"); |
| std::string release_info; |
| base::StringPairs values; |
| if (base::PathExists(os_release_file) && |
| base::ReadFileToStringWithMaxSize(os_release_file, &release_info, 8192) && |
| base::SplitStringIntoKeyValuePairs(release_info, '=', '\n', &values)) { |
| auto version_id = std::find_if(values.begin(), values.end(), [](auto v) { |
| return v.first == "VERSION_ID"; |
| }); |
| if (version_id != values.end()) { |
| return std::string( |
| base::TrimString(version_id->second, "\"", base::TRIM_ALL)); |
| } |
| } |
| return base::SysInfo::OperatingSystemVersion(); |
| } |
| |
| std::string GetDeviceHostName() { |
| return net::GetHostName(); |
| } |
| |
| std::string GetSerialNumber() { |
| return std::string(); |
| } |
| |
| // Implements the logic from the native client setup script. It reads the |
| // setting value straight from gsettings but picks the schema relevant to the |
| // currently active desktop environment. |
| // The current implementation support Gnone and Cinnamon only. |
| SettingValue GetScreenlockSecured() { |
| #if defined(USE_GIO) |
| static constexpr char kLockScreenKey[] = "lock-enabled"; |
| |
| std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| const base::nix::DesktopEnvironment desktop_env = |
| base::nix::GetDesktopEnvironment(env.get()); |
| if (desktop_env != base::nix::DESKTOP_ENVIRONMENT_CINNAMON && |
| desktop_env != base::nix::DESKTOP_ENVIRONMENT_GNOME) { |
| return SettingValue::UNKNOWN; |
| } |
| |
| const std::string settings_schema = base::StringPrintf( |
| "org.%s.desktop.screensaver", |
| desktop_env == base::nix::DESKTOP_ENVIRONMENT_CINNAMON ? "cinnamon" |
| : "gnome"); |
| |
| GSettingsSchema* screensaver_schema = g_settings_schema_source_lookup( |
| g_settings_schema_source_get_default(), settings_schema.c_str(), FALSE); |
| GSettings* screensaver_settings = nullptr; |
| if (!screensaver_schema || |
| !g_settings_schema_has_key(screensaver_schema, kLockScreenKey)) { |
| return SettingValue::UNKNOWN; |
| } |
| screensaver_settings = g_settings_new(settings_schema.c_str()); |
| if (!screensaver_settings) |
| return SettingValue::UNKNOWN; |
| gboolean lock_screen_enabled = |
| g_settings_get_boolean(screensaver_settings, kLockScreenKey); |
| g_object_unref(screensaver_settings); |
| |
| return lock_screen_enabled ? SettingValue::ENABLED : SettingValue::DISABLED; |
| #else |
| return SettingValue::UNKNOWN; |
| #endif // defined(USE_GIO) |
| } |
| |
| // Implements the logic from the native host installation script. First find the |
| // root device identifier, then locate its parent and get its type. |
| SettingValue GetDiskEncrypted() { |
| struct stat info; |
| // First figure out the device identifier. Fail fast if this fails. |
| if (stat("/", &info) != 0) |
| return SettingValue::UNKNOWN; |
| int dev_major = major(info.st_dev); |
| // The parent identifier will have the same major and minor 0. If and only if |
| // it is a dm device can it also be an encrypted device (as evident from the |
| // source code of the lsblk command). |
| base::FilePath dev_uuid( |
| base::StringPrintf("/sys/dev/block/%d:0/dm/uuid", dev_major)); |
| std::string uuid; |
| if (base::PathExists(dev_uuid)) { |
| if (base::ReadFileToStringWithMaxSize(dev_uuid, &uuid, 1024)) { |
| // The device uuid starts with the driver type responsible for it. If it |
| // is the "crypt" driver then it is an encrypted device. |
| bool is_encrypted = base::StartsWith( |
| uuid, "crypt-", base::CompareCase::INSENSITIVE_ASCII); |
| return is_encrypted ? SettingValue::ENABLED : SettingValue::DISABLED; |
| } |
| return SettingValue::UNKNOWN; |
| } |
| return SettingValue::DISABLED; |
| } |
| |
| std::vector<std::string> GetMacAddresses() { |
| std::vector<std::string> result; |
| base::DirReaderPosix reader("/sys/class/net"); |
| if (!reader.IsValid()) |
| return result; |
| while (reader.Next()) { |
| std::string name = reader.name(); |
| if (name == "." || name == "..") |
| continue; |
| std::string address; |
| base::FilePath address_file( |
| base::StringPrintf("/sys/class/net/%s/address", name.c_str())); |
| // Filter out the loopback interface here. |
| if (!base::PathExists(address_file) || |
| !base::ReadFileToStringWithMaxSize(address_file, &address, 1024) || |
| base::StartsWith(address, "00:00:00:00:00:00", |
| base::CompareCase::SENSITIVE)) { |
| continue; |
| } |
| |
| base::TrimWhitespaceASCII(address, base::TrimPositions::TRIM_TRAILING, |
| &address); |
| result.push_back(address); |
| } |
| return result; |
| } |
| |
| } // namespace |
| |
| DeviceInfoFetcherLinux::DeviceInfoFetcherLinux() = default; |
| |
| DeviceInfoFetcherLinux::~DeviceInfoFetcherLinux() = default; |
| |
| DeviceInfo DeviceInfoFetcherLinux::Fetch() { |
| DeviceInfo device_info; |
| device_info.os_name = "linux"; |
| device_info.os_version = GetOsVersion(); |
| device_info.device_host_name = GetDeviceHostName(); |
| device_info.device_model = GetDeviceModel(); |
| device_info.serial_number = GetSerialNumber(); |
| device_info.screen_lock_secured = GetScreenlockSecured(); |
| device_info.disk_encrypted = GetDiskEncrypted(); |
| device_info.mac_addresses = GetMacAddresses(); |
| return device_info; |
| } |
| |
| } // namespace enterprise_signals |