To reduce the amount of technical information to ordinary users, the panel and technical descriptions are simplified and reduced. The major revision is shown as follows: 1. The result of the check items view is removed and the detailed information can be found by copying them to the clipboard and pasting them to any place the users want. 2. The security status is only shown in the security dialog. All the bottoms are removed. 3. The loading spinner is added when the panel is launched. 4. A "status unavailable" page is added for the system which fwupd is unable to determine the security level. Signed-off-by: Kate Hsuan <hpa@redhat.com>
449 lines
17 KiB
C
449 lines
17 KiB
C
/* cc-firmware-security-dialog.c
|
|
*
|
|
* Copyright (C) 2021 Red Hat, Inc
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Kate Hsuan <hpa@redhat.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib/gi18n-lib.h>
|
|
#include <glibtop/fsusage.h>
|
|
#include <glibtop/mountlist.h>
|
|
#include <glibtop/mem.h>
|
|
#include <glibtop/sysinfo.h>
|
|
|
|
#include "cc-firmware-security-panel.h"
|
|
#include "cc-firmware-security-dialog.h"
|
|
#include "cc-firmware-security-utils.h"
|
|
|
|
struct _CcFirmwareSecurityDialog
|
|
{
|
|
AdwWindow parent;
|
|
|
|
GtkWidget *firmware_security_dialog_icon;
|
|
|
|
|
|
|
|
GtkWidget *firmware_security_dialog_title_label;
|
|
GtkWidget *firmware_security_dialog_body_label;
|
|
GtkWidget *firmware_security_dialog_min_row;
|
|
GtkWidget *firmware_security_dialog_basic_row;
|
|
GtkWidget *firmware_security_dialog_extend_row;
|
|
GtkWidget *firmware_security_dialog_hsi1_pg;
|
|
GtkWidget *firmware_security_dialog_hsi2_pg;
|
|
GtkWidget *firmware_security_dialog_hsi3_pg;
|
|
AdwLeaflet *leaflet;
|
|
AdwWindowTitle *second_page_title;
|
|
AdwToastOverlay *toast_overlay;
|
|
|
|
gboolean is_created;
|
|
|
|
GHashTable *hsi1_dict;
|
|
GHashTable *hsi2_dict;
|
|
GHashTable *hsi3_dict;
|
|
GHashTable *hsi4_dict;
|
|
GHashTable *runtime_dict;
|
|
|
|
GString *event_log_str;
|
|
|
|
guint hsi_number;
|
|
};
|
|
|
|
G_DEFINE_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, ADW_TYPE_WINDOW)
|
|
|
|
static void
|
|
set_dialog_item_layer1 (CcFirmwareSecurityDialog *self,
|
|
const gchar *icon_name,
|
|
const gchar *title,
|
|
const gchar *body)
|
|
{
|
|
g_autofree gchar *str = NULL;
|
|
|
|
gtk_image_set_from_icon_name (GTK_IMAGE (self->firmware_security_dialog_icon), icon_name);
|
|
gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_title_label), title);
|
|
gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_body_label), body);
|
|
|
|
if (self->hsi_number == G_MAXUINT)
|
|
{
|
|
gtk_widget_add_css_class (self->firmware_security_dialog_icon, "neutral");
|
|
return;
|
|
}
|
|
|
|
switch (self->hsi_number)
|
|
{
|
|
case 0:
|
|
gtk_widget_add_css_class (self->firmware_security_dialog_icon, "error");
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
gtk_widget_add_css_class (self->firmware_security_dialog_icon, "good");
|
|
break;
|
|
default:
|
|
gtk_widget_add_css_class (self->firmware_security_dialog_icon, "neutral");
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_dialog (CcFirmwareSecurityDialog *self)
|
|
{
|
|
switch (self->hsi_number)
|
|
{
|
|
case 0:
|
|
set_dialog_item_layer1 (self,
|
|
"dialog-warning-symbolic",
|
|
_("Checks Failed"),
|
|
/* TRANSLATORS: This is the description to describe the failure on
|
|
checking the security items. */
|
|
_("Hardware does not pass checks. "
|
|
"This means that you are not protected against common hardware security issues."
|
|
"\n\n"
|
|
"It may be possible to resolve hardware security issues by updating your firmware or changing device configuration options. "
|
|
"However, failures can stem from the physical hardware itself, and may not be reversible."));
|
|
break;
|
|
|
|
case 1:
|
|
gtk_window_set_default_size (GTK_WINDOW (&self->parent), 380, 380);
|
|
set_dialog_item_layer1 (self,
|
|
"emblem-default-symbolic",
|
|
_("Checks Passed"),
|
|
/* TRANSLATORS: This description describes the device passing the
|
|
minimum requirement of security check.*/
|
|
_("Hardware meets security requirements. "
|
|
"This device has protection against common hardware security threats."));
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
gtk_window_set_default_size (GTK_WINDOW (&self->parent), 400, 390);
|
|
set_dialog_item_layer1 (self,
|
|
"security-high-symbolic",
|
|
_("Protected"),
|
|
/* TRANSLATOR: This description describes the devices passing
|
|
the extended security check. */
|
|
_("Device hardware meets security requirements. "
|
|
"This device has protection against a range of the most common hardware security threats."));
|
|
break;
|
|
|
|
default:
|
|
gtk_window_set_default_size (GTK_WINDOW (&self->parent), 400, 390);
|
|
set_dialog_item_layer1 (self,
|
|
"dialog-question-symbolic",
|
|
_("Checks Unavailable"),
|
|
/* TRANSLATORS: When the security result is unavailable, this description is shown. */
|
|
_("Device security checks are not available for this device. "
|
|
"It is not possible to tell whether it meets security requirements."));
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_fw_back_button_clicked_cb (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
CcFirmwareSecurityDialog *self = CC_FIRMWARE_SECURITY_DIALOG (data);
|
|
|
|
adw_leaflet_navigate (self->leaflet, ADW_NAVIGATION_DIRECTION_BACK);
|
|
|
|
gtk_widget_set_visible (self->firmware_security_dialog_hsi1_pg, FALSE);
|
|
gtk_widget_set_visible (self->firmware_security_dialog_hsi2_pg, FALSE);
|
|
gtk_widget_set_visible (self->firmware_security_dialog_hsi3_pg, FALSE);
|
|
}
|
|
|
|
static gchar *
|
|
get_os_name (void)
|
|
{
|
|
g_autofree gchar *name = NULL;
|
|
g_autofree gchar *version_id = NULL;
|
|
g_autofree gchar *pretty_name = NULL;
|
|
|
|
name = g_get_os_info (G_OS_INFO_KEY_NAME);
|
|
version_id = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
|
|
pretty_name = g_get_os_info (G_OS_INFO_KEY_PRETTY_NAME);
|
|
|
|
if (pretty_name)
|
|
return g_steal_pointer (&pretty_name);
|
|
else if (name && version_id)
|
|
return g_strdup_printf ("%s %s", name, version_id);
|
|
else
|
|
return g_strdup (_("Unknown"));
|
|
}
|
|
|
|
static gchar*
|
|
cpu_get_model ()
|
|
{
|
|
gchar *model;
|
|
const glibtop_sysinfo * sysinfo;
|
|
|
|
glibtop_init();
|
|
sysinfo = glibtop_get_sysinfo ();
|
|
model = g_strdup (g_hash_table_lookup (sysinfo->cpuinfo [1].values, "model name"));
|
|
glibtop_close ();
|
|
|
|
return model;
|
|
}
|
|
|
|
static gchar*
|
|
fwupd_get_property (const char *property_name)
|
|
{
|
|
g_autoptr(GDBusConnection) connection = NULL;
|
|
g_autoptr(GError) error = NULL;
|
|
g_autoptr(GVariant) inner = NULL;
|
|
g_autoptr(GVariant) variant = NULL;
|
|
const gchar *ret_property;
|
|
|
|
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
if (!connection)
|
|
{
|
|
g_warning ("system bus not available: %s", error->message);
|
|
return NULL;
|
|
}
|
|
variant = g_dbus_connection_call_sync (connection,
|
|
"org.freedesktop.fwupd",
|
|
"/",
|
|
"org.freedesktop.DBus.Properties",
|
|
"Get",
|
|
g_variant_new ("(ss)",
|
|
"org.freedesktop.fwupd",
|
|
property_name),
|
|
NULL,
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1,
|
|
NULL,
|
|
&error);
|
|
if (!variant)
|
|
{
|
|
g_warning ("Cannot get org.freedesktop.fwupd: %s", error->message);
|
|
return NULL;
|
|
}
|
|
g_variant_get (variant, "(v)", &inner);
|
|
ret_property = g_variant_get_string (inner, NULL);
|
|
|
|
return g_strdup (ret_property);
|
|
}
|
|
|
|
static void
|
|
on_hsi_detail_button_clicked_cb (GtkWidget *widget,
|
|
gpointer *data)
|
|
{
|
|
CcFirmwareSecurityDialog *self = CC_FIRMWARE_SECURITY_DIALOG (data);
|
|
GdkClipboard *clip_board;
|
|
GdkDisplay *display;
|
|
g_autoptr (GList) hash_keys;
|
|
g_autoptr (GString) result_str;
|
|
g_autofree gchar *date_string = NULL;
|
|
g_autoptr (GDateTime) date = NULL;
|
|
g_autofree gchar *fwupd_ver = NULL;
|
|
g_autofree gchar *vendor = NULL;
|
|
g_autofree gchar *product = NULL;
|
|
g_autofree gchar *os_name = NULL;
|
|
g_autofree gchar *hsi_level = NULL;
|
|
g_autofree gchar *cpu_model = NULL;
|
|
const gchar *hsi_result;
|
|
g_autoptr (GString) tmp_str;
|
|
|
|
GHashTable *hsi_dict = NULL;
|
|
|
|
tmp_str = g_string_new (NULL);
|
|
|
|
result_str = g_string_new (NULL);
|
|
|
|
g_string_append (result_str, _("Device Security Report"));
|
|
g_string_append (result_str, "\n======================\n\n");
|
|
|
|
g_string_append (result_str, _("Report details"));
|
|
g_string_append (result_str, "\n");
|
|
|
|
g_string_append (result_str, " ");
|
|
hsi_report_title_print_padding (_("Date generated:"), result_str, 0);
|
|
date = g_date_time_new_now_local ();
|
|
date_string = g_date_time_format (date, "%Y-%m-%d %H:%M:%S");
|
|
|
|
g_string_append_printf (result_str, "%s\n", date_string);
|
|
|
|
g_string_append (result_str, " ");
|
|
/* TRANSLATOR: This is the title for showing the version of fwupd service. */
|
|
hsi_report_title_print_padding (_("fwupd version:"), result_str, 00);
|
|
fwupd_ver = fwupd_get_property ("DaemonVersion");
|
|
g_string_append_printf (result_str, "%s", fwupd_ver);
|
|
g_string_append (result_str, "\n\n");
|
|
|
|
g_string_append (result_str, "System details");
|
|
g_string_append (result_str, "\n");
|
|
|
|
g_string_append (result_str, " ");
|
|
hsi_report_title_print_padding (_("Hardware model:"), result_str, 0);
|
|
vendor = fwupd_get_property ("HostVendor");
|
|
product = fwupd_get_property ("HostProduct");
|
|
g_string_append_printf (result_str, "%s %s\n", vendor, product);
|
|
|
|
g_string_append (result_str, " ");
|
|
/* TRANSLATOR: "Processor" indicates the CPU model name. */
|
|
hsi_report_title_print_padding (_("Processor:"), result_str, 0);
|
|
cpu_model = cpu_get_model ();
|
|
g_string_append_printf (result_str, "%s\n", cpu_model);
|
|
|
|
g_string_append (result_str, " ");
|
|
/* TRANSLATOR: "OS" indicates the OS name, ex: Fedora 38. */
|
|
hsi_report_title_print_padding (_("OS:"), result_str, 0);
|
|
os_name = get_os_name ();
|
|
g_string_append_printf (result_str, "%s\n", os_name);
|
|
|
|
g_string_append (result_str, " ");
|
|
/* TRANSLATOR: This is the title for device security level. */
|
|
hsi_report_title_print_padding (_("Security level:"), result_str, 0);
|
|
hsi_level = fwupd_get_property ("HostSecurityId");
|
|
g_string_append_printf (result_str, "%s\n", hsi_level);
|
|
g_string_append (result_str, "\n");
|
|
|
|
for (int i = 1; i <=5; i++)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 1:
|
|
hsi_dict = self->hsi1_dict;
|
|
break;
|
|
case 2:
|
|
hsi_dict = self->hsi2_dict;
|
|
break;
|
|
case 3:
|
|
hsi_dict = self->hsi3_dict;
|
|
break;
|
|
case 4:
|
|
hsi_dict = self->hsi4_dict;
|
|
break;
|
|
case 5:
|
|
hsi_dict = self->runtime_dict;
|
|
}
|
|
|
|
if (i <= 4)
|
|
{
|
|
g_string_append_printf (result_str, "HSI-");
|
|
g_string_append_printf (result_str, "%i ", i);
|
|
/* TRANSLATOR: This is the postfix of "HSI-n Tests" title. */
|
|
g_string_append (result_str, _("Tests"));
|
|
g_string_append (result_str, "\n");
|
|
}
|
|
else
|
|
{
|
|
g_string_append (result_str, _("Runtime Tests"));
|
|
g_string_append (result_str, "\n");
|
|
}
|
|
|
|
hash_keys = g_hash_table_get_keys (hsi_dict);
|
|
for (GList *item = g_list_first (hash_keys); item != NULL; item = g_list_next (item))
|
|
{
|
|
FwupdSecurityAttr *attr = g_hash_table_lookup (hsi_dict, item->data);
|
|
if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0)
|
|
continue;
|
|
if (attr->title == NULL)
|
|
continue;
|
|
g_string_printf (tmp_str, "%s:", attr->title);
|
|
g_string_append (result_str, " ");
|
|
hsi_report_title_print_padding (tmp_str->str, result_str, 0);
|
|
if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
|
|
{
|
|
/* Passed */
|
|
/* TRANSLATOR: If the status for security attribute is success, "Pass " is shown. */
|
|
g_string_append (result_str, _("Pass"));
|
|
g_string_append (result_str, " ");
|
|
}
|
|
else
|
|
{
|
|
/* Failed */
|
|
/* TRANSLATOR: If the status for security attribute is success, "! Fail " is shown. */
|
|
result_str = g_string_overwrite (result_str, result_str->len-2, _("! Fail"));
|
|
g_string_append (result_str, " ");
|
|
}
|
|
hsi_result = fwupd_security_attr_result_to_string (attr->result);
|
|
if (hsi_result) {
|
|
g_string_append_printf (result_str, "(%s)", hsi_result);
|
|
}
|
|
g_string_append (result_str, "\n");
|
|
}
|
|
g_string_append (result_str, "\n");
|
|
}
|
|
|
|
g_string_append (result_str, _("Host security events"));
|
|
g_string_append (result_str, "\n");
|
|
g_string_append (result_str, self->event_log_str->str);
|
|
g_string_append (result_str, "\n");
|
|
g_string_append (result_str, _("For information on the contents of this report, see https://fwupd.github.io/hsi.html"));
|
|
|
|
display = gdk_display_get_default ();
|
|
clip_board = gdk_display_get_clipboard (display);
|
|
gdk_clipboard_set_text (clip_board, result_str->str);
|
|
adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (_("Report copied to clipboard")));
|
|
}
|
|
|
|
static void
|
|
cc_firmware_security_dialog_class_init (CcFirmwareSecurityDialogClass *klass)
|
|
{
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-dialog.ui");
|
|
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_icon);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_title_label);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_body_label);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi1_pg);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi2_pg);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi3_pg);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, leaflet);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, second_page_title);
|
|
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, toast_overlay);
|
|
|
|
gtk_widget_class_bind_template_callback (widget_class, on_fw_back_button_clicked_cb);
|
|
gtk_widget_class_bind_template_callback (widget_class, on_hsi_detail_button_clicked_cb);
|
|
}
|
|
|
|
static void
|
|
cc_firmware_security_dialog_init (CcFirmwareSecurityDialog *dialog)
|
|
{
|
|
gtk_widget_init_template (GTK_WIDGET (dialog));
|
|
load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css");
|
|
}
|
|
|
|
GtkWidget *
|
|
cc_firmware_security_dialog_new (guint hsi_number,
|
|
GHashTable *hsi1_dict,
|
|
GHashTable *hsi2_dict,
|
|
GHashTable *hsi3_dict,
|
|
GHashTable *hsi4_dict,
|
|
GHashTable *runtime_dict,
|
|
GString *event_log_str)
|
|
{
|
|
CcFirmwareSecurityDialog *dialog;
|
|
|
|
dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_DIALOG, NULL);
|
|
dialog->hsi_number = hsi_number;
|
|
dialog->is_created = FALSE;
|
|
dialog->hsi1_dict = hsi1_dict;
|
|
dialog->hsi2_dict = hsi2_dict;
|
|
dialog->hsi3_dict = hsi3_dict;
|
|
dialog->hsi4_dict = hsi4_dict;
|
|
dialog->runtime_dict = runtime_dict;
|
|
dialog->event_log_str = event_log_str;
|
|
update_dialog (dialog);
|
|
|
|
return GTK_WIDGET (dialog);
|
|
}
|