diff --git a/0001-user-accounts-Don-t-access-user-before-it-s-loaded.patch b/0001-user-accounts-Don-t-access-user-before-it-s-loaded.patch new file mode 100644 index 0000000..5b0636b --- /dev/null +++ b/0001-user-accounts-Don-t-access-user-before-it-s-loaded.patch @@ -0,0 +1,250 @@ +From 7cdf07d0a00ac7322971f9a96a7d5b9945cd50f6 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 16 Feb 2023 11:17:26 -0500 +Subject: [PATCH] user-accounts: Don't access user before it's loaded + +libaccountsservice documents that it is undefined to access an +ActUser object's properties before the 'is-loaded' property is +set to try. + +Control-center unfortunately sometimes accesses objects that +aren't fully loaded, leading to log spew and memory corruption. + +This commit fixes the problem by setting up a signal handler +to listen for the is-loaded notification when necessary. +--- + panels/user-accounts/cc-user-panel.c | 31 ++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/panels/user-accounts/cc-user-panel.c b/panels/user-accounts/cc-user-panel.c +index 612bd21fa..e5b620d2c 100644 +--- a/panels/user-accounts/cc-user-panel.c ++++ b/panels/user-accounts/cc-user-panel.c +@@ -72,60 +72,61 @@ struct _CcUserPanel { + GtkSwitch *account_type_switch; + GtkWidget *add_user_button; + GtkListBoxRow *autologin_row; + GtkSwitch *autologin_switch; + GtkButton *back_button; + CcListRow *fingerprint_row; + GtkStack *full_name_stack; + GtkLabel *full_name_label; + GtkToggleButton *full_name_edit_button; + GtkEntry *full_name_entry; + CcListRow *language_row; + CcListRow *last_login_row; + GtkWidget *no_users_box; + GtkRevealer *notification_revealer; + AdwPreferencesGroup *other_users; + GtkListBox *other_users_listbox; + GtkLabel *password_button_label; + #ifdef HAVE_MALCONTENT + GtkLabel *parental_controls_button_label; + GtkListBoxRow *parental_controls_row; + #endif + CcListRow *password_row; + CcPermissionInfobar *permission_infobar; + GtkButton *remove_user_button; + GtkStack *stack; + AdwAvatar *user_avatar; + GtkMenuButton *user_avatar_edit_button; + GtkOverlay *users_overlay; + + ActUser *selected_user; ++ ActUser *pending_show_user; + GPermission *permission; + CcLanguageChooser *language_chooser; + GListStore *other_users_model; + GtkFlattenListModel *other_users_flat_model; + + CcAvatarChooser *avatar_chooser; + + CcFingerprintManager *fingerprint_manager; + }; + + CC_PANEL_REGISTER (CcUserPanel, cc_user_panel) + + static void show_restart_notification (CcUserPanel *self, const gchar *locale); + + typedef struct { + CcUserPanel *self; + GCancellable *cancellable; + gchar *login; + } AsyncDeleteData; + + static void + async_delete_data_free (AsyncDeleteData *data) + { + g_clear_object (&data->self); + g_clear_object (&data->cancellable); + g_clear_pointer (&data->login, g_free); + g_slice_free (AsyncDeleteData, data); + } + + G_DEFINE_AUTOPTR_CLEANUP_FUNC (AsyncDeleteData, async_delete_data_free) +@@ -806,71 +807,100 @@ update_fingerprint_row_state (CcUserPanel *self, GParamSpec *spec, CcFingerprint + { + CcFingerprintState state = cc_fingerprint_manager_get_state (fingerprint_manager); + + if (state != CC_FINGERPRINT_STATE_UPDATING) { + gtk_widget_set_visible (GTK_WIDGET (self->fingerprint_row), + state != CC_FINGERPRINT_STATE_NONE); + } + + gtk_widget_set_sensitive (GTK_WIDGET (self->fingerprint_row), + state != CC_FINGERPRINT_STATE_UPDATING); + + if (state == CC_FINGERPRINT_STATE_ENABLED) + cc_list_row_set_secondary_label (self->fingerprint_row, _("Enabled")); + else if (state == CC_FINGERPRINT_STATE_DISABLED) + cc_list_row_set_secondary_label (self->fingerprint_row, _("Disabled")); + } + + static void + show_or_hide_back_button (CcUserPanel *self) + { + gboolean show; + gboolean folded; + + g_object_get(self, "folded", &folded, NULL); + + show = folded || act_user_get_uid (self->selected_user) != getuid(); + + gtk_widget_set_visible (GTK_WIDGET (self->back_button), show); + } + ++static void ++on_pending_show_user_is_loaded (ActUser *user, ++ GParamSpec *param, ++ CcUserPanel *self) ++{ ++ if (!act_user_is_loaded (user)) { ++ return; ++ } ++ ++ show_user (user, self); ++} ++ + static void + show_user (ActUser *user, CcUserPanel *self) + { + g_autofree gchar *lang = NULL; + g_autofree gchar *name = NULL; + gboolean show, enable; + ActUser *current; + #ifdef HAVE_MALCONTENT + g_autofree gchar *malcontent_control_path = NULL; + #endif + ++ if (self->pending_show_user != NULL) { ++ g_signal_handlers_disconnect_by_func (G_OBJECT (self->pending_show_user), ++ on_pending_show_user_is_loaded, ++ self); ++ g_clear_object (&self->pending_show_user); ++ } ++ ++ if (!act_user_is_loaded (user)) { ++ g_set_object (&self->pending_show_user, user); ++ g_signal_connect_object (G_OBJECT (self->pending_show_user), ++ "notify::is-loaded", ++ G_CALLBACK (on_pending_show_user_is_loaded), ++ self, ++ 0); ++ return; ++ } ++ + g_set_object (&self->selected_user, user); + + setup_avatar_for_user (self->user_avatar, user); + cc_avatar_chooser_set_user (self->avatar_chooser, user); + + gtk_label_set_label (self->full_name_label, get_real_or_user_name (user)); + gtk_editable_set_text (GTK_EDITABLE (self->full_name_entry), gtk_label_get_label (self->full_name_label)); + gtk_widget_set_tooltip_text (GTK_WIDGET (self->full_name_label), get_real_or_user_name (user)); + + g_signal_handlers_block_by_func (self->full_name_edit_button, full_name_edit_button_toggled, self); + gtk_stack_set_visible_child (self->full_name_stack, GTK_WIDGET (self->full_name_label)); + gtk_toggle_button_set_active (self->full_name_edit_button, FALSE); + g_signal_handlers_unblock_by_func (self->full_name_edit_button, full_name_edit_button_toggled, self); + + enable = (act_user_get_account_type (user) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR); + gtk_switch_set_active (self->account_type_switch, enable); + + gtk_label_set_label (self->password_button_label, get_password_mode_text (user)); + enable = act_user_is_local_account (user); + gtk_widget_set_sensitive (GTK_WIDGET (self->password_button_label), enable); + + g_signal_handlers_block_by_func (self->autologin_switch, autologin_changed, self); + gtk_switch_set_active (self->autologin_switch, act_user_get_automatic_login (user)); + g_signal_handlers_unblock_by_func (self->autologin_switch, autologin_changed, self); + gtk_widget_set_sensitive (GTK_WIDGET (self->autologin_switch), get_autologin_possible (user)); + + lang = g_strdup (act_user_get_language (user)); + if (lang && *lang != '\0') { + name = gnome_get_language_from_locale (lang, NULL); + } else { +@@ -1508,60 +1538,61 @@ cc_user_panel_init (CcUserPanel *self) + + /* register types that the builder might need */ + type = cc_permission_infobar_get_type (); + + gtk_widget_init_template (GTK_WIDGET (self)); + + self->um = act_user_manager_get_default (); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/user-accounts/user-accounts-dialog.css"); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + self->login_screen_settings = settings_or_null ("org.gnome.login-screen"); + + setup_main_window (self); + + g_signal_connect_swapped (self, + "notify::folded", + G_CALLBACK (show_or_hide_back_button), + self); + } + + static void + cc_user_panel_dispose (GObject *object) + { + CcUserPanel *self = CC_USER_PANEL (object); + + g_clear_object (&self->selected_user); ++ g_clear_object (&self->pending_show_user); + g_clear_object (&self->login_screen_settings); + g_clear_pointer ((GtkWindow **)&self->language_chooser, gtk_window_destroy); + g_clear_object (&self->permission); + + G_OBJECT_CLASS (cc_user_panel_parent_class)->dispose (object); + } + + static const char * + cc_user_panel_get_help_uri (CcPanel *panel) + { + return "help:gnome-help/user-accounts"; + } + + static void + cc_user_panel_class_init (CcUserPanelClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + object_class->dispose = cc_user_panel_dispose; + object_class->constructed = cc_user_panel_constructed; + + panel_class->get_help_uri = cc_user_panel_get_help_uri; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/user-accounts/cc-user-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_settings_box); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_type_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_type_switch); +-- +2.39.2 + diff --git a/gnome-control-center.spec b/gnome-control-center.spec index ec81252..d9b0ce6 100644 --- a/gnome-control-center.spec +++ b/gnome-control-center.spec @@ -19,6 +19,7 @@ Summary: Utilities to configure the GNOME desktop License: GPLv2+ and CC-BY-SA URL: https://gitlab.gnome.org/GNOME/gnome-control-center/ Source0: https://download.gnome.org/sources/%{name}/44/%{name}-%{tarball_version}.tar.xz +Patch0: 0001-user-accounts-Don-t-access-user-before-it-s-loaded.patch BuildRequires: desktop-file-utils BuildRequires: docbook-style-xsl libxslt