Line |
Branch |
Exec |
Source |
1 |
|
|
/* cc-firmware-security-page.c |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2021 Red Hat, Inc |
4 |
|
|
* |
5 |
|
|
* This program is free software; you can redistribute it and/or modify |
6 |
|
|
* it under the terms of the GNU General Public License as published by |
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
8 |
|
|
* (at your option) any later version. |
9 |
|
|
* |
10 |
|
|
* This program is distributed in the hope that it will be useful, |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
* GNU General Public License for more details. |
14 |
|
|
* |
15 |
|
|
* You should have received a copy of the GNU General Public License |
16 |
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>. |
17 |
|
|
* |
18 |
|
|
* Author: Kate Hsuan <hpa@redhat.com> |
19 |
|
|
* |
20 |
|
|
* SPDX-License-Identifier: GPL-2.0-or-later |
21 |
|
|
*/ |
22 |
|
|
|
23 |
|
|
#include "shell/cc-application.h" |
24 |
|
|
|
25 |
|
|
#include "cc-firmware-security-page.h" |
26 |
|
|
#include "cc-firmware-security-dialog.h" |
27 |
|
|
#include "cc-firmware-security-boot-dialog.h" |
28 |
|
|
#include "cc-firmware-security-help-dialog.h" |
29 |
|
|
#include "cc-firmware-security-utils.h" |
30 |
|
|
#include "cc-hostname.h" |
31 |
|
|
#include "cc-util.h" |
32 |
|
|
|
33 |
|
|
#include <gio/gdesktopappinfo.h> |
34 |
|
|
#include <glib/gi18n.h> |
35 |
|
|
|
36 |
|
|
struct _CcFirmwareSecurityPage |
37 |
|
|
{ |
38 |
|
|
AdwNavigationPage parent_instance; |
39 |
|
|
|
40 |
|
|
GtkButton *hsi_button; |
41 |
|
|
GtkButton *secure_boot_button; |
42 |
|
|
|
43 |
|
|
/* Stack */ |
44 |
|
|
GtkWidget *panel_stack; |
45 |
|
|
|
46 |
|
|
/* HSI button */ |
47 |
|
|
GtkWidget *hsi_grid; |
48 |
|
|
|
49 |
|
|
GtkWidget *hsi_circle_box; |
50 |
|
|
GtkWidget *hsi_circle_number; |
51 |
|
|
GtkWidget *hsi_icon; |
52 |
|
|
|
53 |
|
|
GtkWidget *hsi_label; |
54 |
|
|
GtkWidget *hsi_description; |
55 |
|
|
|
56 |
|
|
/* secure boot button */ |
57 |
|
|
GtkWidget *secure_boot_button_grid; |
58 |
|
|
GtkWidget *secure_boot_icon; |
59 |
|
|
GtkWidget *secure_boot_label; |
60 |
|
|
GtkWidget *secure_boot_description; |
61 |
|
|
|
62 |
|
|
/* event listbox */ |
63 |
|
|
GtkWidget *firmware_security_log_listbox; |
64 |
|
|
GtkWidget *firmware_security_log_stack; |
65 |
|
|
GtkWidget *firmware_security_log_pgroup; |
66 |
|
|
|
67 |
|
|
GCancellable *cancellable; |
68 |
|
|
guint timeout_id; |
69 |
|
|
|
70 |
|
|
GDBusProxy *bus_proxy; |
71 |
|
|
GDBusProxy *properties_bus_proxy; |
72 |
|
|
|
73 |
|
|
GHashTable *hsi1_dict; |
74 |
|
|
GHashTable *hsi2_dict; |
75 |
|
|
GHashTable *hsi3_dict; |
76 |
|
|
GHashTable *hsi4_dict; |
77 |
|
|
GHashTable *runtime_dict; |
78 |
|
|
GString *event_log_output; |
79 |
|
|
|
80 |
|
|
guint hsi_number; |
81 |
|
|
SecureBootState secure_boot_state; |
82 |
|
|
}; |
83 |
|
|
|
84 |
|
✗ |
G_DEFINE_TYPE (CcFirmwareSecurityPage, cc_firmware_security_page, ADW_TYPE_NAVIGATION_PAGE) |
85 |
|
|
|
86 |
|
|
static void |
87 |
|
|
set_hsi_button_view (CcFirmwareSecurityPage *self); |
88 |
|
|
|
89 |
|
|
static void |
90 |
|
✗ |
set_secure_boot_button_view (CcFirmwareSecurityPage *self) |
91 |
|
|
{ |
92 |
|
|
FwupdSecurityAttr *attr; |
93 |
|
✗ |
guint64 sb_flags = 0; |
94 |
|
✗ |
guint64 pk_flags = 0; |
95 |
|
|
|
96 |
|
|
/* get HSI-1 flags if set */ |
97 |
|
✗ |
attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); |
98 |
|
✗ |
if (attr != NULL) |
99 |
|
✗ |
sb_flags = attr->flags; |
100 |
|
✗ |
attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_PK); |
101 |
|
✗ |
if (attr != NULL) |
102 |
|
✗ |
pk_flags = attr->flags; |
103 |
|
|
|
104 |
|
|
/* enabled and valid */ |
105 |
|
✗ |
if ((sb_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0 && |
106 |
|
✗ |
(pk_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0) |
107 |
|
|
{ |
108 |
|
✗ |
self->secure_boot_state = SECURE_BOOT_STATE_ACTIVE; |
109 |
|
|
} |
110 |
|
✗ |
else if ((sb_flags & FWUPD_SECURITY_ATTR_RESULT_ENABLED) > 0) |
111 |
|
|
{ |
112 |
|
✗ |
self->secure_boot_state = SECURE_BOOT_STATE_PROBLEMS; |
113 |
|
|
} |
114 |
|
|
else |
115 |
|
|
{ |
116 |
|
✗ |
self->secure_boot_state = SECURE_BOOT_STATE_INACTIVE; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* update UI */ |
120 |
|
✗ |
if (self->secure_boot_state == SECURE_BOOT_STATE_ACTIVE) |
121 |
|
|
{ |
122 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Active")); |
123 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Protected against malicious software when the device starts.")); |
124 |
|
✗ |
gtk_image_set_from_icon_name (GTK_IMAGE (self->secure_boot_icon), "channel-secure-symbolic"); |
125 |
|
✗ |
gtk_widget_add_css_class (self->secure_boot_icon, "good"); |
126 |
|
|
} |
127 |
|
✗ |
else if (self->secure_boot_state == SECURE_BOOT_STATE_PROBLEMS) |
128 |
|
|
{ |
129 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot has Problems")); |
130 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Some protection when the device is started.")); |
131 |
|
✗ |
gtk_widget_add_css_class (self->secure_boot_icon, "error"); |
132 |
|
|
} |
133 |
|
|
else |
134 |
|
|
{ |
135 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Off")); |
136 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("No protection when the device is started.")); |
137 |
|
✗ |
gtk_widget_add_css_class (self->secure_boot_icon, "error"); |
138 |
|
|
} |
139 |
|
✗ |
} |
140 |
|
|
|
141 |
|
|
static gchar * |
142 |
|
✗ |
fu_security_attr_get_description_for_eventlog (FwupdSecurityAttr *attr) |
143 |
|
|
{ |
144 |
|
✗ |
GString *str = g_string_new (attr->description); |
145 |
|
|
|
146 |
|
|
/* nothing to do */ |
147 |
|
✗ |
if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) |
148 |
|
✗ |
return g_string_free (str, FALSE); |
149 |
|
|
|
150 |
|
✗ |
if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM && |
151 |
|
✗ |
attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) |
152 |
|
|
{ |
153 |
|
✗ |
g_string_append_printf (str, "\n\n%s", |
154 |
|
|
/* TRANSLATORS: this is to explain an event that has already happened */ |
155 |
|
|
_("This issue could have been caused by a change in UEFI firmware " |
156 |
|
|
"settings, an operating system configuration change, or because of " |
157 |
|
|
"malicious software on this system.")); |
158 |
|
|
} |
159 |
|
✗ |
else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) |
160 |
|
|
{ |
161 |
|
✗ |
g_string_append_printf (str, "\n\n%s", |
162 |
|
|
/* TRANSLATORS: this is to explain an event that has already happened */ |
163 |
|
|
_("This issue could have been caused by a change in the UEFI firmware " |
164 |
|
|
"settings, or because of malicious software on this system.")); |
165 |
|
|
} |
166 |
|
✗ |
else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS) |
167 |
|
|
{ |
168 |
|
✗ |
g_string_append_printf (str, "\n\n%s", |
169 |
|
|
/* TRANSLATORS: this is to explain an event that has already happened */ |
170 |
|
|
_("This issue could have been caused by an operating system configuration " |
171 |
|
|
"change, or because of malicious software on this system.")); |
172 |
|
|
} |
173 |
|
|
|
174 |
|
✗ |
return g_string_free (str, FALSE); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
static void |
178 |
|
✗ |
parse_event_variant_iter (CcFirmwareSecurityPage *self, |
179 |
|
|
GVariantIter *iter) |
180 |
|
|
{ |
181 |
|
✗ |
g_autofree gchar *date_string = NULL; |
182 |
|
✗ |
g_autoptr (GDateTime) date = NULL; |
183 |
|
✗ |
g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter); |
184 |
|
|
GtkWidget *row; |
185 |
|
|
|
186 |
|
|
/* unknown to us */ |
187 |
|
✗ |
if (attr->appstream_id == NULL || attr->title == NULL) |
188 |
|
✗ |
return; |
189 |
|
|
|
190 |
|
|
/* skip events that have either been added or removed with no prior value */ |
191 |
|
✗ |
if (attr->result == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN || |
192 |
|
✗ |
attr->result_fallback == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) |
193 |
|
✗ |
return; |
194 |
|
|
|
195 |
|
|
/* build new row */ |
196 |
|
✗ |
row = adw_expander_row_new (); |
197 |
|
✗ |
if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) |
198 |
|
|
{ |
199 |
|
✗ |
adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "emblem-ok"); |
200 |
|
✗ |
gtk_widget_add_css_class (row, "success-icon"); |
201 |
|
|
} |
202 |
|
|
else |
203 |
|
|
{ |
204 |
|
✗ |
adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "process-stop"); |
205 |
|
✗ |
gtk_widget_add_css_class (row, "error-icon"); |
206 |
|
|
} |
207 |
|
|
|
208 |
|
✗ |
if (attr->description != NULL) |
209 |
|
|
{ |
210 |
|
✗ |
GtkWidget *subrow = adw_action_row_new (); |
211 |
|
✗ |
g_autofree gchar *str = fu_security_attr_get_description_for_eventlog (attr); |
212 |
|
✗ |
adw_action_row_set_subtitle (ADW_ACTION_ROW (subrow), str); |
213 |
|
✗ |
adw_expander_row_add_row (ADW_EXPANDER_ROW (row), subrow); |
214 |
|
|
} |
215 |
|
|
else |
216 |
|
|
{ |
217 |
|
✗ |
adw_expander_row_set_enable_expansion (ADW_EXPANDER_ROW (row), FALSE); |
218 |
|
✗ |
gtk_widget_add_css_class (row, "hide-arrow"); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
✗ |
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), attr->title); |
222 |
|
|
|
223 |
|
✗ |
g_string_append (self->event_log_output, " "); |
224 |
|
✗ |
date = g_date_time_new_from_unix_local (attr->timestamp); |
225 |
|
✗ |
date_string = g_date_time_format (date, "%Y-%m-%d %H:%M:%S"); |
226 |
|
|
/* TRANSLATOR: this is the date in "%Y-%m-%d %H:%M:%S" format, |
227 |
|
|
for example: 2022-08-01 22:48:00 */ |
228 |
|
✗ |
g_string_append_printf (self->event_log_output, _("%1$s"), date_string); |
229 |
|
✗ |
g_string_append (self->event_log_output, " "); |
230 |
|
✗ |
hsi_report_title_print_padding (attr->title, self->event_log_output, 30); |
231 |
|
|
|
232 |
|
✗ |
if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) |
233 |
|
|
/* TRANSLATOR: This is the text event status output when the event status is "success" */ |
234 |
|
✗ |
g_string_append (self->event_log_output, _("Pass")); |
235 |
|
|
else |
236 |
|
|
/* TRANSLATOR: This is the text event status output when the event status is not "success" */ |
237 |
|
✗ |
g_string_overwrite (self->event_log_output, self->event_log_output->len-2, _("! Fail")); |
238 |
|
|
|
239 |
|
✗ |
g_string_append (self->event_log_output, " "); |
240 |
|
✗ |
g_string_append_printf (self->event_log_output, _("(%1$s → %2$s)"), |
241 |
|
✗ |
fwupd_security_attr_result_to_string (attr->result_fallback), |
242 |
|
✗ |
fwupd_security_attr_result_to_string (attr->result)); |
243 |
|
✗ |
g_string_append (self->event_log_output, "\n"); |
244 |
|
|
|
245 |
|
✗ |
adw_expander_row_set_subtitle (ADW_EXPANDER_ROW (row), date_string); |
246 |
|
✗ |
adw_preferences_group_add (ADW_PREFERENCES_GROUP (self->firmware_security_log_pgroup), GTK_WIDGET (row)); |
247 |
|
|
|
248 |
|
✗ |
adw_view_stack_set_visible_child_name (ADW_VIEW_STACK (self->firmware_security_log_stack), "events-page"); |
249 |
|
|
} |
250 |
|
|
|
251 |
|
|
static void |
252 |
|
✗ |
parse_variant_iter (CcFirmwareSecurityPage *self, |
253 |
|
|
GVariantIter *iter) |
254 |
|
|
{ |
255 |
|
✗ |
g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter); |
256 |
|
✗ |
const gchar *appstream_id = attr->appstream_id; |
257 |
|
|
|
258 |
|
|
/* invalid */ |
259 |
|
✗ |
if (appstream_id == NULL) |
260 |
|
✗ |
return; |
261 |
|
|
|
262 |
|
|
/* skip obsoleted */ |
263 |
|
✗ |
if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_OBSOLETED) |
264 |
|
✗ |
return; |
265 |
|
|
|
266 |
|
|
/* in fwupd <= 1.8.3 org.fwupd.hsi.Uefi.SecureBoot was incorrectly marked as HSI-0, |
267 |
|
|
* so lower the HSI number forcefully if this attribute failed -- the correct thing |
268 |
|
|
* to do of course is to update fwupd to a newer build */ |
269 |
|
✗ |
if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0 && |
270 |
|
✗ |
(attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) == 0) |
271 |
|
|
{ |
272 |
|
✗ |
self->hsi_number = 0; |
273 |
|
✗ |
set_hsi_button_view (self); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
/* insert into correct hash table */ |
277 |
|
✗ |
switch (attr->hsi_level) |
278 |
|
|
{ |
279 |
|
✗ |
case 1: |
280 |
|
✗ |
g_hash_table_insert (self->hsi1_dict, |
281 |
|
✗ |
g_strdup (appstream_id), |
282 |
|
|
g_steal_pointer (&attr)); |
283 |
|
✗ |
break; |
284 |
|
✗ |
case 2: |
285 |
|
✗ |
g_hash_table_insert (self->hsi2_dict, |
286 |
|
✗ |
g_strdup (appstream_id), |
287 |
|
|
g_steal_pointer (&attr)); |
288 |
|
✗ |
break; |
289 |
|
✗ |
case 3: |
290 |
|
✗ |
g_hash_table_insert (self->hsi3_dict, |
291 |
|
✗ |
g_strdup (appstream_id), |
292 |
|
|
g_steal_pointer (&attr)); |
293 |
|
✗ |
break; |
294 |
|
✗ |
case 4: |
295 |
|
✗ |
g_hash_table_insert (self->hsi4_dict, |
296 |
|
✗ |
g_strdup (appstream_id), |
297 |
|
|
g_steal_pointer (&attr)); |
298 |
|
✗ |
break; |
299 |
|
✗ |
default: |
300 |
|
✗ |
g_hash_table_insert (self->runtime_dict, |
301 |
|
✗ |
g_strdup (appstream_id), |
302 |
|
|
g_steal_pointer (&attr)); |
303 |
|
|
} |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
static void |
307 |
|
✗ |
parse_data_from_variant (CcFirmwareSecurityPage *self, |
308 |
|
|
GVariant *value, |
309 |
|
|
const gboolean is_event) |
310 |
|
|
{ |
311 |
|
|
const gchar *type_string; |
312 |
|
✗ |
g_autoptr (GVariantIter) iter = NULL; |
313 |
|
|
|
314 |
|
✗ |
type_string = g_variant_get_type_string (value); |
315 |
|
✗ |
if (g_strcmp0 (type_string, "(a{sv})") == 0) |
316 |
|
|
{ |
317 |
|
✗ |
g_variant_get (value, "(a{sv})", &iter); |
318 |
|
✗ |
if (is_event) |
319 |
|
✗ |
parse_event_variant_iter (self, iter); |
320 |
|
|
else |
321 |
|
✗ |
parse_variant_iter (self, iter); |
322 |
|
|
} |
323 |
|
✗ |
else if (g_strcmp0 (type_string, "a{sv}") == 0) |
324 |
|
|
{ |
325 |
|
✗ |
g_variant_get (value, "a{sv}", &iter); |
326 |
|
✗ |
if (is_event) |
327 |
|
✗ |
parse_event_variant_iter (self, iter); |
328 |
|
|
else |
329 |
|
✗ |
parse_variant_iter (self, iter); |
330 |
|
|
} |
331 |
|
|
else |
332 |
|
|
{ |
333 |
|
✗ |
g_warning ("type %s not known", type_string); |
334 |
|
|
} |
335 |
|
✗ |
} |
336 |
|
|
|
337 |
|
|
static void |
338 |
|
✗ |
parse_array_from_variant (CcFirmwareSecurityPage *self, |
339 |
|
|
GVariant *value, |
340 |
|
|
const gboolean is_event) |
341 |
|
|
{ |
342 |
|
|
gsize sz; |
343 |
|
✗ |
g_autoptr (GVariant) untuple = NULL; |
344 |
|
|
|
345 |
|
✗ |
untuple = g_variant_get_child_value (value, 0); |
346 |
|
✗ |
sz = g_variant_n_children (untuple); |
347 |
|
✗ |
for (guint i = 0; i < sz; i++) |
348 |
|
|
{ |
349 |
|
✗ |
g_autoptr (GVariant) data = NULL; |
350 |
|
✗ |
data = g_variant_get_child_value (untuple, i); |
351 |
|
✗ |
if (is_event) |
352 |
|
✗ |
parse_data_from_variant (self, data, TRUE); |
353 |
|
|
else |
354 |
|
✗ |
parse_data_from_variant (self, data, FALSE); |
355 |
|
|
} |
356 |
|
✗ |
} |
357 |
|
|
|
358 |
|
|
static void |
359 |
|
✗ |
on_bus_event_done_cb (GObject *source, |
360 |
|
|
GAsyncResult *res, |
361 |
|
|
gpointer user_data) |
362 |
|
|
{ |
363 |
|
✗ |
g_autoptr (GError) error = NULL; |
364 |
|
✗ |
g_autoptr (GVariant) val = NULL; |
365 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
366 |
|
|
|
367 |
|
✗ |
val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); |
368 |
|
✗ |
if (val == NULL) |
369 |
|
|
{ |
370 |
|
✗ |
g_warning ("failed to get Security Attribute Event: %s", error->message); |
371 |
|
✗ |
return; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
✗ |
parse_array_from_variant (self, val, TRUE); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
static void |
378 |
|
✗ |
show_loading_page (CcFirmwareSecurityPage *self, const gchar *page_name) |
379 |
|
|
{ |
380 |
|
✗ |
gtk_stack_set_visible_child_name (GTK_STACK (self->panel_stack), page_name); |
381 |
|
✗ |
} |
382 |
|
|
|
383 |
|
|
static int |
384 |
|
✗ |
on_timeout_cb (gpointer user_data) |
385 |
|
|
{ |
386 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
387 |
|
✗ |
show_loading_page (self, "panel_show"); |
388 |
|
✗ |
self->timeout_id = 0; |
389 |
|
✗ |
return 0; |
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
static int |
393 |
|
✗ |
on_timeout_unavaliable (gpointer user_data) |
394 |
|
|
{ |
395 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
396 |
|
✗ |
show_loading_page (self, "panel_unavailable"); |
397 |
|
✗ |
self->timeout_id = 0; |
398 |
|
✗ |
return 0; |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
static void |
402 |
|
✗ |
on_bus_done (GObject *source, |
403 |
|
|
GAsyncResult *res, |
404 |
|
|
gpointer user_data) |
405 |
|
|
{ |
406 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
407 |
|
✗ |
g_autoptr (GError) error = NULL; |
408 |
|
✗ |
g_autoptr (GVariant) val = NULL; |
409 |
|
|
|
410 |
|
✗ |
val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); |
411 |
|
✗ |
if (val == NULL) |
412 |
|
|
{ |
413 |
|
✗ |
self->timeout_id = g_timeout_add (1500, on_timeout_unavaliable, self); |
414 |
|
✗ |
return; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
✗ |
parse_array_from_variant (self, val, FALSE); |
418 |
|
✗ |
set_secure_boot_button_view (self); |
419 |
|
✗ |
self->timeout_id = g_timeout_add (1500, on_timeout_cb, self); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
static void |
423 |
|
✗ |
on_bus_ready_cb (GObject *source_object, |
424 |
|
|
GAsyncResult *res, |
425 |
|
|
gpointer user_data) |
426 |
|
|
{ |
427 |
|
✗ |
g_autoptr (GError) error = NULL; |
428 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
429 |
|
|
|
430 |
|
✗ |
self->bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); |
431 |
|
✗ |
if (self->bus_proxy == NULL) |
432 |
|
|
{ |
433 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
434 |
|
✗ |
g_warning ("failed to connect fwupd: %s", error->message); |
435 |
|
|
|
436 |
|
✗ |
return; |
437 |
|
|
} |
438 |
|
|
|
439 |
|
✗ |
g_dbus_proxy_call (self->bus_proxy, |
440 |
|
|
"GetHostSecurityAttrs", |
441 |
|
|
NULL, |
442 |
|
|
G_DBUS_CALL_FLAGS_NONE, |
443 |
|
|
-1, |
444 |
|
|
self->cancellable, |
445 |
|
|
on_bus_done, |
446 |
|
|
self); |
447 |
|
✗ |
g_dbus_proxy_call (self->bus_proxy, |
448 |
|
|
"GetHostSecurityEvents", |
449 |
|
|
g_variant_new ("(u)", |
450 |
|
|
100), |
451 |
|
|
G_DBUS_CALL_FLAGS_NONE, |
452 |
|
|
-1, |
453 |
|
|
self->cancellable, |
454 |
|
|
on_bus_event_done_cb, |
455 |
|
|
self); |
456 |
|
|
} |
457 |
|
|
|
458 |
|
|
static void |
459 |
|
✗ |
on_hsi_button_clicked_cb (CcFirmwareSecurityPage *self) |
460 |
|
|
{ |
461 |
|
|
GtkWidget *dialog; |
462 |
|
|
|
463 |
|
✗ |
dialog = cc_firmware_security_dialog_new (self->hsi_number, |
464 |
|
|
self->hsi1_dict, |
465 |
|
|
self->hsi2_dict, |
466 |
|
|
self->hsi3_dict, |
467 |
|
|
self->hsi4_dict, |
468 |
|
|
self->runtime_dict, |
469 |
|
|
self->event_log_output); |
470 |
|
✗ |
adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (self)); |
471 |
|
✗ |
} |
472 |
|
|
|
473 |
|
|
static void |
474 |
|
✗ |
on_secure_boot_button_clicked_cb (CcFirmwareSecurityPage *self) |
475 |
|
|
{ |
476 |
|
|
GtkWidget *boot_dialog; |
477 |
|
|
|
478 |
|
✗ |
boot_dialog = cc_firmware_security_boot_dialog_new (self->secure_boot_state); |
479 |
|
✗ |
adw_dialog_present (ADW_DIALOG (boot_dialog), GTK_WIDGET (self)); |
480 |
|
✗ |
} |
481 |
|
|
|
482 |
|
|
static void |
483 |
|
✗ |
on_fw_help_button_clicked_cb (CcFirmwareSecurityPage *self) |
484 |
|
|
{ |
485 |
|
|
GtkWidget *help_dialog; |
486 |
|
|
|
487 |
|
✗ |
help_dialog = cc_firmware_security_help_dialog_new (); |
488 |
|
✗ |
adw_dialog_present (ADW_DIALOG (help_dialog), GTK_WIDGET (self)); |
489 |
|
✗ |
} |
490 |
|
|
|
491 |
|
|
static void |
492 |
|
✗ |
set_hsi_button_view_contain (CcFirmwareSecurityPage *self, |
493 |
|
|
guint hsi_number, |
494 |
|
|
gchar *title, |
495 |
|
|
const gchar *description) |
496 |
|
|
{ |
497 |
|
✗ |
switch (hsi_number) |
498 |
|
|
{ |
499 |
|
✗ |
case 0: |
500 |
|
✗ |
gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi_icon), "dialog-warning-symbolic"); |
501 |
|
✗ |
gtk_widget_add_css_class (self->hsi_icon, "error"); |
502 |
|
✗ |
break; |
503 |
|
✗ |
case 1: |
504 |
|
✗ |
gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi_icon), "channel-secure-symbolic"); |
505 |
|
✗ |
gtk_widget_add_css_class (self->hsi_icon, "warning"); |
506 |
|
✗ |
break; |
507 |
|
✗ |
case 2: |
508 |
|
|
case 3: |
509 |
|
|
case 4: |
510 |
|
✗ |
gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi_icon), "security-high-symbolic"); |
511 |
|
✗ |
gtk_widget_add_css_class (self->hsi_icon, "good"); |
512 |
|
✗ |
break; |
513 |
|
✗ |
default: |
514 |
|
✗ |
gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi_icon), "dialog-question-symbolic"); |
515 |
|
✗ |
gtk_widget_add_css_class (self->hsi_icon, "neutral"); |
516 |
|
✗ |
break; |
517 |
|
|
} |
518 |
|
|
|
519 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->hsi_label), title); |
520 |
|
✗ |
gtk_label_set_text (GTK_LABEL (self->hsi_description), description); |
521 |
|
✗ |
} |
522 |
|
|
|
523 |
|
|
static void |
524 |
|
✗ |
set_hsi_button_view (CcFirmwareSecurityPage *self) |
525 |
|
|
{ |
526 |
|
✗ |
switch (self->hsi_number) |
527 |
|
|
{ |
528 |
|
✗ |
case 0: |
529 |
|
✗ |
set_hsi_button_view_contain (self, |
530 |
|
|
self->hsi_number, |
531 |
|
|
/* TRANSLATORS: in reference to firmware protection: 0/4 stars */ |
532 |
|
✗ |
_("Security Checks Failed"), |
533 |
|
✗ |
_("Hardware does not pass basic security checks.")); |
534 |
|
✗ |
break; |
535 |
|
✗ |
case 1: |
536 |
|
✗ |
set_hsi_button_view_contain (self, |
537 |
|
|
self->hsi_number, |
538 |
|
|
/* TRANSLATORS: in reference to firmware protection: 1/4 stars */ |
539 |
|
✗ |
_("Basic Security Checks Passed"), |
540 |
|
✗ |
_("Hardware has a basic level of protection.")); |
541 |
|
✗ |
break; |
542 |
|
✗ |
case 2: |
543 |
|
|
case 3: |
544 |
|
|
case 4: |
545 |
|
|
case 5: |
546 |
|
✗ |
set_hsi_button_view_contain (self, |
547 |
|
|
self->hsi_number, |
548 |
|
|
/* TRANSLATORS: in reference to firmware protection: 2~4 stars */ |
549 |
|
✗ |
_("Protected"), |
550 |
|
✗ |
_("Hardware has a strong level of protection.")); |
551 |
|
✗ |
break; |
552 |
|
✗ |
case G_MAXUINT: |
553 |
|
✗ |
set_hsi_button_view_contain (self, |
554 |
|
|
self->hsi_number, |
555 |
|
|
/* TRANSLATORS: in reference to firmware protection: ??? stars */ |
556 |
|
✗ |
_("Security Checks Unavailable"), |
557 |
|
✗ |
_("Security levels are not available for this device.")); |
558 |
|
✗ |
break; |
559 |
|
✗ |
default: |
560 |
|
✗ |
g_warning ("incorrect HSI number %u", self->hsi_number); |
561 |
|
|
} |
562 |
|
✗ |
} |
563 |
|
|
|
564 |
|
|
static void |
565 |
|
✗ |
on_properties_bus_done_cb (GObject *source, |
566 |
|
|
GAsyncResult *res, |
567 |
|
|
gpointer user_data) |
568 |
|
|
{ |
569 |
|
✗ |
g_autoptr (GError) error = NULL; |
570 |
|
✗ |
g_autoptr (GVariant) val = NULL; |
571 |
|
✗ |
const gchar *hsi_str = NULL; |
572 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
573 |
|
|
|
574 |
|
✗ |
val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); |
575 |
|
✗ |
if (val == NULL) |
576 |
|
|
{ |
577 |
|
✗ |
g_warning ("failed to get HSI number"); |
578 |
|
✗ |
return; |
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
/* parse value */ |
582 |
|
✗ |
hsi_str = g_variant_get_data (val); |
583 |
|
✗ |
if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:INVALID")) |
584 |
|
|
{ |
585 |
|
✗ |
self->hsi_number = G_MAXUINT; |
586 |
|
|
} |
587 |
|
✗ |
else if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:")) |
588 |
|
|
{ |
589 |
|
✗ |
self->hsi_number = g_ascii_strtoll (hsi_str + 4, NULL, 10); |
590 |
|
|
} |
591 |
|
✗ |
set_hsi_button_view (self); |
592 |
|
|
} |
593 |
|
|
|
594 |
|
|
static void |
595 |
|
✗ |
on_properties_bus_ready_cb (GObject *source_object, |
596 |
|
|
GAsyncResult *res, |
597 |
|
|
gpointer user_data) |
598 |
|
|
{ |
599 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (user_data); |
600 |
|
✗ |
g_autoptr (GError) error = NULL; |
601 |
|
|
|
602 |
|
✗ |
self->properties_bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); |
603 |
|
✗ |
if (self->properties_bus_proxy == NULL) |
604 |
|
|
{ |
605 |
|
✗ |
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
606 |
|
✗ |
g_warning ("failed to connect fwupd: %s", error->message); |
607 |
|
|
|
608 |
|
✗ |
return; |
609 |
|
|
} |
610 |
|
|
|
611 |
|
✗ |
g_dbus_proxy_call (self->properties_bus_proxy, |
612 |
|
|
"Get", |
613 |
|
|
g_variant_new ("(ss)", |
614 |
|
|
"org.freedesktop.fwupd", |
615 |
|
|
"HostSecurityId"), |
616 |
|
|
G_DBUS_CALL_FLAGS_NONE, |
617 |
|
|
-1, |
618 |
|
|
self->cancellable, |
619 |
|
|
on_properties_bus_done_cb, |
620 |
|
|
self); |
621 |
|
|
} |
622 |
|
|
|
623 |
|
|
static void |
624 |
|
✗ |
update_page_visibility (CcFirmwareSecurityPage *self) |
625 |
|
|
{ |
626 |
|
|
CcHostname *hostname; |
627 |
|
✗ |
gboolean visible = TRUE; |
628 |
|
✗ |
g_autofree gchar *chassis_type = NULL; |
629 |
|
|
|
630 |
|
✗ |
hostname = cc_hostname_get_default (); |
631 |
|
✗ |
chassis_type = cc_hostname_get_chassis_type (hostname); |
632 |
|
✗ |
if (cc_hostname_is_vm_chassis (hostname) || g_strcmp0 (chassis_type, "") == 0) |
633 |
|
✗ |
visible = FALSE; |
634 |
|
|
|
635 |
|
✗ |
gtk_widget_set_visible (GTK_WIDGET (self), visible); |
636 |
|
✗ |
g_debug ("Firmware Security page visible: %s as chassis was %s", |
637 |
|
|
visible ? "yes" : "no", |
638 |
|
|
chassis_type); |
639 |
|
✗ |
} |
640 |
|
|
|
641 |
|
|
static void |
642 |
|
✗ |
cc_firmware_security_page_finalize (GObject *object) |
643 |
|
|
{ |
644 |
|
✗ |
CcFirmwareSecurityPage *self = CC_FIRMWARE_SECURITY_PAGE (object); |
645 |
|
|
|
646 |
|
✗ |
g_clear_pointer (&self->hsi1_dict, g_hash_table_unref); |
647 |
|
✗ |
g_clear_pointer (&self->hsi2_dict, g_hash_table_unref); |
648 |
|
✗ |
g_clear_pointer (&self->hsi3_dict, g_hash_table_unref); |
649 |
|
✗ |
g_clear_pointer (&self->hsi4_dict, g_hash_table_unref); |
650 |
|
✗ |
g_clear_pointer (&self->runtime_dict, g_hash_table_unref); |
651 |
|
✗ |
g_string_free (self->event_log_output, TRUE); |
652 |
|
|
|
653 |
|
✗ |
g_clear_object (&self->bus_proxy); |
654 |
|
✗ |
g_clear_object (&self->properties_bus_proxy); |
655 |
|
|
|
656 |
|
✗ |
g_cancellable_cancel (self->cancellable); |
657 |
|
✗ |
g_clear_object (&self->cancellable); |
658 |
|
|
|
659 |
|
✗ |
if (self->timeout_id) |
660 |
|
✗ |
g_clear_handle_id (&self->timeout_id, g_source_remove); |
661 |
|
|
|
662 |
|
✗ |
G_OBJECT_CLASS (cc_firmware_security_page_parent_class)->finalize (object); |
663 |
|
✗ |
} |
664 |
|
|
|
665 |
|
|
|
666 |
|
|
static void |
667 |
|
✗ |
cc_firmware_security_page_class_init (CcFirmwareSecurityPageClass *klass) |
668 |
|
|
{ |
669 |
|
✗ |
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
670 |
|
✗ |
GObjectClass *object_class = G_OBJECT_CLASS (klass); |
671 |
|
|
|
672 |
|
✗ |
object_class->finalize = cc_firmware_security_page_finalize; |
673 |
|
|
|
674 |
|
✗ |
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/privacy/firmware-security/cc-firmware-security-page.ui"); |
675 |
|
|
|
676 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, firmware_security_log_pgroup); |
677 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, firmware_security_log_stack); |
678 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, hsi_button); |
679 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, hsi_description); |
680 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, hsi_icon); |
681 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, hsi_label); |
682 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, secure_boot_button); |
683 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, secure_boot_description); |
684 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, secure_boot_icon); |
685 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, secure_boot_label); |
686 |
|
✗ |
gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityPage, panel_stack); |
687 |
|
|
|
688 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_hsi_button_clicked_cb); |
689 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_secure_boot_button_clicked_cb); |
690 |
|
✗ |
gtk_widget_class_bind_template_callback (widget_class, on_fw_help_button_clicked_cb); |
691 |
|
✗ |
} |
692 |
|
|
|
693 |
|
|
static void |
694 |
|
✗ |
cc_firmware_security_page_init (CcFirmwareSecurityPage *self) |
695 |
|
|
{ |
696 |
|
✗ |
gtk_widget_init_template (GTK_WIDGET (self)); |
697 |
|
|
|
698 |
|
✗ |
update_page_visibility (self); |
699 |
|
|
|
700 |
|
✗ |
self->hsi1_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); |
701 |
|
✗ |
self->hsi2_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); |
702 |
|
✗ |
self->hsi3_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); |
703 |
|
✗ |
self->hsi4_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); |
704 |
|
✗ |
self->runtime_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); |
705 |
|
✗ |
self->event_log_output = g_string_new (NULL); |
706 |
|
✗ |
self->cancellable = g_cancellable_new (); |
707 |
|
|
|
708 |
|
✗ |
load_custom_css ("/org/gnome/control-center/privacy/firmware-security/security-level.css"); |
709 |
|
|
|
710 |
|
✗ |
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, |
711 |
|
|
G_DBUS_PROXY_FLAGS_NONE, |
712 |
|
|
NULL, |
713 |
|
|
"org.freedesktop.fwupd", |
714 |
|
|
"/", |
715 |
|
|
"org.freedesktop.DBus.Properties", |
716 |
|
|
self->cancellable, |
717 |
|
|
on_properties_bus_ready_cb, |
718 |
|
|
self); |
719 |
|
✗ |
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, |
720 |
|
|
G_DBUS_PROXY_FLAGS_NONE, |
721 |
|
|
NULL, |
722 |
|
|
"org.freedesktop.fwupd", |
723 |
|
|
"/", |
724 |
|
|
"org.freedesktop.fwupd", |
725 |
|
|
self->cancellable, |
726 |
|
|
on_bus_ready_cb, |
727 |
|
|
self); |
728 |
|
✗ |
} |
729 |
|
|
|