From 612c0dc268280dbc8f9f72451441399defaf7e96 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 7 Sep 2018 15:15:55 -0400 Subject: [PATCH] More initial setup fixes Resolves: #1625572 --- ...tial-setup-post-work-in-manager-code.patch | 694 ++++++++++++++++++ gdm.spec | 8 +- 2 files changed, 701 insertions(+), 1 deletion(-) create mode 100644 0001-manager-do-initial-setup-post-work-in-manager-code.patch diff --git a/0001-manager-do-initial-setup-post-work-in-manager-code.patch b/0001-manager-do-initial-setup-post-work-in-manager-code.patch new file mode 100644 index 0000000..be484d3 --- /dev/null +++ b/0001-manager-do-initial-setup-post-work-in-manager-code.patch @@ -0,0 +1,694 @@ +From 692613bc996f5ab090a1fb605ae8dd50c6bb81bf Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 6 Sep 2018 19:31:50 -0400 +Subject: [PATCH] manager: do initial-setup post work in manager code + +Right now we do the initial-setup related post work +when stopping the greeter, but the problem is we delay +stopping the greeter now until after the user session +is started. + +That post-work needs to be done before the user session +is started. + +This commit moves the code to a more logical place. +--- + daemon/gdm-display.c | 132 ------------------------------------------- + daemon/gdm-manager.c | 132 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 132 insertions(+), 132 deletions(-) + +diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c +index 5e193f2f5..511a5ca3f 100644 +--- a/daemon/gdm-display.c ++++ b/daemon/gdm-display.c +@@ -22,61 +22,60 @@ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + #include + + #include "gdm-common.h" + #include "gdm-display.h" + #include "gdm-display-glue.h" + #include "gdm-display-access-file.h" + #include "gdm-launch-environment.h" + + #include "gdm-settings-direct.h" + #include "gdm-settings-keys.h" + + #include "gdm-launch-environment.h" + #include "gdm-dbus-util.h" + +-#define INITIAL_SETUP_USERNAME "gnome-initial-setup" + #define GNOME_SESSION_SESSIONS_PATH DATADIR "/gnome-session/sessions" + + #define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate)) + + struct GdmDisplayPrivate + { + char *id; + char *seat_id; + char *session_id; + char *session_class; + char *session_type; + + char *remote_hostname; + int x11_display_number; + char *x11_display_name; + int status; + time_t creation_time; + GTimer *server_timer; + + char *x11_cookie; + gsize x11_cookie_size; + GdmDisplayAccessFile *access_file; + + guint finish_idle_id; + + xcb_connection_t *xcb_connection; + int xcb_screen_number; + + GDBusConnection *connection; + GdmDisplayAccessFile *user_access_file; +@@ -100,131 +99,60 @@ enum { + PROP_0, + PROP_ID, + PROP_STATUS, + PROP_SEAT_ID, + PROP_SESSION_ID, + PROP_SESSION_CLASS, + PROP_SESSION_TYPE, + PROP_REMOTE_HOSTNAME, + PROP_X11_DISPLAY_NUMBER, + PROP_X11_DISPLAY_NAME, + PROP_X11_COOKIE, + PROP_X11_AUTHORITY_FILE, + PROP_IS_CONNECTED, + PROP_IS_LOCAL, + PROP_LAUNCH_ENVIRONMENT, + PROP_IS_INITIAL, + PROP_ALLOW_TIMED_LOGIN, + PROP_HAVE_EXISTING_USER_ACCOUNTS, + PROP_DOING_INITIAL_SETUP, + }; + + static void gdm_display_class_init (GdmDisplayClass *klass); + static void gdm_display_init (GdmDisplay *self); + static void gdm_display_finalize (GObject *object); + static void queue_finish (GdmDisplay *self); + static void _gdm_display_set_status (GdmDisplay *self, + int status); + static gboolean wants_initial_setup (GdmDisplay *self); + G_DEFINE_ABSTRACT_TYPE (GdmDisplay, gdm_display, G_TYPE_OBJECT) + +-static gboolean +-chown_file (GFile *file, +- uid_t uid, +- gid_t gid, +- GError **error) +-{ +- if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_UID, uid, +- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, +- NULL, error)) { +- return FALSE; +- } +- if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_GID, gid, +- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, +- NULL, error)) { +- return FALSE; +- } +- return TRUE; +-} +- +-static gboolean +-chown_recursively (GFile *dir, +- uid_t uid, +- gid_t gid, +- GError **error) +-{ +- GFile *file = NULL; +- GFileInfo *info = NULL; +- GFileEnumerator *enumerator = NULL; +- gboolean retval = FALSE; +- +- if (chown_file (dir, uid, gid, error) == FALSE) { +- goto out; +- } +- +- enumerator = g_file_enumerate_children (dir, +- G_FILE_ATTRIBUTE_STANDARD_TYPE"," +- G_FILE_ATTRIBUTE_STANDARD_NAME, +- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, +- NULL, error); +- if (!enumerator) { +- goto out; +- } +- +- while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) { +- file = g_file_get_child (dir, g_file_info_get_name (info)); +- +- if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { +- if (chown_recursively (file, uid, gid, error) == FALSE) { +- goto out; +- } +- } else if (chown_file (file, uid, gid, error) == FALSE) { +- goto out; +- } +- +- g_clear_object (&file); +- g_clear_object (&info); +- } +- +- if (*error) { +- goto out; +- } +- +- retval = TRUE; +-out: +- g_clear_object (&file); +- g_clear_object (&info); +- g_clear_object (&enumerator); +- +- return retval; +-} +- + GQuark + gdm_display_error_quark (void) + { + static GQuark ret = 0; + if (ret == 0) { + ret = g_quark_from_static_string ("gdm_display_error"); + } + + return ret; + } + + time_t + gdm_display_get_creation_time (GdmDisplay *self) + { + g_return_val_if_fail (GDM_IS_DISPLAY (self), 0); + + return self->priv->creation_time; + } + + int + gdm_display_get_status (GdmDisplay *self) + { + g_return_val_if_fail (GDM_IS_DISPLAY (self), 0); + + return self->priv->status; + } + + const char * + gdm_display_get_session_id (GdmDisplay *self) + { +@@ -1631,145 +1559,85 @@ gdm_display_start_greeter_session (GdmDisplay *self) + G_CALLBACK (on_launch_environment_session_stopped), + self, 0); + g_signal_connect_object (self->priv->launch_environment, + "exited", + G_CALLBACK (on_launch_environment_session_exited), + self, 0); + g_signal_connect_object (self->priv->launch_environment, + "died", + G_CALLBACK (on_launch_environment_session_died), + self, 0); + + if (auth_file != NULL) { + g_object_set (self->priv->launch_environment, + "x11-authority-file", auth_file, + NULL); + } + + gdm_launch_environment_start (self->priv->launch_environment); + + session = gdm_launch_environment_get_session (self->priv->launch_environment); + g_object_set (G_OBJECT (session), + "display-is-initial", self->priv->is_initial, + NULL); + + g_free (display_name); + g_free (seat_id); + g_free (hostname); + g_free (auth_file); + } + +-static void +-chown_initial_setup_home_dir (void) +-{ +- GFile *dir; +- GError *error; +- char *gis_dir_path; +- char *gis_uid_path; +- char *gis_uid_contents; +- struct passwd *pwe; +- uid_t uid; +- +- if (!gdm_get_pwent_for_name (INITIAL_SETUP_USERNAME, &pwe)) { +- g_warning ("Unknown user %s", INITIAL_SETUP_USERNAME); +- return; +- } +- +- gis_dir_path = g_strdup (pwe->pw_dir); +- +- gis_uid_path = g_build_filename (gis_dir_path, +- "gnome-initial-setup-uid", +- NULL); +- if (!g_file_get_contents (gis_uid_path, &gis_uid_contents, NULL, NULL)) { +- g_warning ("Unable to read %s", gis_uid_path); +- goto out; +- } +- +- uid = (uid_t) atoi (gis_uid_contents); +- pwe = getpwuid (uid); +- if (uid == 0 || pwe == NULL) { +- g_warning ("UID '%s' in %s is not valid", gis_uid_contents, gis_uid_path); +- goto out; +- } +- +- error = NULL; +- dir = g_file_new_for_path (gis_dir_path); +- if (!chown_recursively (dir, pwe->pw_uid, pwe->pw_gid, &error)) { +- g_warning ("Failed to change ownership for %s: %s", gis_dir_path, error->message); +- g_error_free (error); +- } +- g_object_unref (dir); +-out: +- g_free (gis_uid_contents); +- g_free (gis_uid_path); +- g_free (gis_dir_path); +-} +- + void + gdm_display_stop_greeter_session (GdmDisplay *self) + { + GError *error = NULL; + + if (self->priv->launch_environment != NULL) { + + g_signal_handlers_disconnect_by_func (self->priv->launch_environment, + G_CALLBACK (on_launch_environment_session_opened), + self); + g_signal_handlers_disconnect_by_func (self->priv->launch_environment, + G_CALLBACK (on_launch_environment_session_started), + self); + g_signal_handlers_disconnect_by_func (self->priv->launch_environment, + G_CALLBACK (on_launch_environment_session_stopped), + self); + g_signal_handlers_disconnect_by_func (self->priv->launch_environment, + G_CALLBACK (on_launch_environment_session_exited), + self); + g_signal_handlers_disconnect_by_func (self->priv->launch_environment, + G_CALLBACK (on_launch_environment_session_died), + self); + gdm_launch_environment_stop (self->priv->launch_environment); + g_clear_object (&self->priv->launch_environment); + } +- +- if (self->priv->doing_initial_setup) { +- chown_initial_setup_home_dir (); +- +- if (!g_file_set_contents (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT, +- "1", +- 1, +- &error)) { +- g_warning ("GdmDisplay: Could not write initial-setup-done marker to %s: %s", +- ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT, +- error->message); +- g_clear_error (&error); +- } +- } + } + + static xcb_window_t + get_root_window (xcb_connection_t *connection, + int screen_number) + { + xcb_screen_t *screen = NULL; + xcb_screen_iterator_t iter; + + iter = xcb_setup_roots_iterator (xcb_get_setup (connection)); + while (iter.rem) { + if (screen_number == 0) + screen = iter.data; + screen_number--; + xcb_screen_next (&iter); + } + + if (screen != NULL) { + return screen->root; + } + + return XCB_WINDOW_NONE; + } + + static void + gdm_display_set_windowpath (GdmDisplay *self) + { + /* setting WINDOWPATH for clients */ + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply = NULL; +diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c +index 20a9ba7d7..c37135f44 100644 +--- a/daemon/gdm-manager.c ++++ b/daemon/gdm-manager.c +@@ -35,60 +35,61 @@ + #include + + #include + + #include + + #include "gdm-common.h" + + #include "gdm-dbus-util.h" + #include "gdm-manager.h" + #include "gdm-manager-glue.h" + #include "gdm-display-store.h" + #include "gdm-display-factory.h" + #include "gdm-launch-environment.h" + #include "gdm-local-display.h" + #include "gdm-local-display-factory.h" + #include "gdm-session.h" + #include "gdm-session-record.h" + #include "gdm-settings-direct.h" + #include "gdm-settings-keys.h" + #include "gdm-xdmcp-display-factory.h" + #include "gdm-xdmcp-chooser-display.h" + + #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate)) + + #define GDM_DBUS_PATH "/org/gnome/DisplayManager" + #define GDM_MANAGER_PATH GDM_DBUS_PATH "/Manager" + #define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays" + + #define INITIAL_SETUP_USERNAME "gnome-initial-setup" ++#define ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT GDM_RUN_DIR "/gdm.ran-initial-setup" + + typedef struct + { + GdmManager *manager; + GdmSession *session; + char *service_name; + guint idle_id; + } StartUserSessionOperation; + + struct GdmManagerPrivate + { + GdmDisplayStore *display_store; + GdmLocalDisplayFactory *local_factory; + #ifdef HAVE_LIBXDMCP + GdmXdmcpDisplayFactory *xdmcp_factory; + #endif + GList *user_sessions; + GHashTable *transient_sessions; + GHashTable *open_reauthentication_requests; + gboolean xdmcp_enabled; + + gboolean started; + gboolean show_local_greeter; + + GDBusConnection *connection; + GDBusObjectManagerServer *object_manager; + + #ifdef WITH_PLYMOUTH + guint plymouth_is_running : 1; + #endif +@@ -1552,130 +1553,261 @@ start_user_session (GdmManager *manager, + + destroy_start_user_session_operation (operation); + } + + static void + create_display_for_user_session (GdmManager *self, + GdmSession *session, + const char *session_id) + { + GdmDisplay *display; + /* at the moment we only create GdmLocalDisplay objects on seat0 */ + const char *seat_id = "seat0"; + + display = gdm_local_display_new (); + + g_object_set (G_OBJECT (display), + "session-class", "user", + "seat-id", seat_id, + "session-id", session_id, + NULL); + gdm_display_store_add (self->priv->display_store, + display); + g_object_set_data (G_OBJECT (session), "gdm-display", display); + g_object_set_data_full (G_OBJECT (display), + "gdm-user-session", + g_object_ref (session), + (GDestroyNotify) + clean_user_session); + } + ++static gboolean ++chown_file (GFile *file, ++ uid_t uid, ++ gid_t gid, ++ GError **error) ++{ ++ if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_UID, uid, ++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, ++ NULL, error)) { ++ return FALSE; ++ } ++ if (!g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_GID, gid, ++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, ++ NULL, error)) { ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++static gboolean ++chown_recursively (GFile *dir, ++ uid_t uid, ++ gid_t gid, ++ GError **error) ++{ ++ GFile *file = NULL; ++ GFileInfo *info = NULL; ++ GFileEnumerator *enumerator = NULL; ++ gboolean retval = FALSE; ++ ++ if (chown_file (dir, uid, gid, error) == FALSE) { ++ goto out; ++ } ++ ++ enumerator = g_file_enumerate_children (dir, ++ G_FILE_ATTRIBUTE_STANDARD_TYPE"," ++ G_FILE_ATTRIBUTE_STANDARD_NAME, ++ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, ++ NULL, error); ++ if (!enumerator) { ++ goto out; ++ } ++ ++ while ((info = g_file_enumerator_next_file (enumerator, NULL, error)) != NULL) { ++ file = g_file_get_child (dir, g_file_info_get_name (info)); ++ ++ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { ++ if (chown_recursively (file, uid, gid, error) == FALSE) { ++ goto out; ++ } ++ } else if (chown_file (file, uid, gid, error) == FALSE) { ++ goto out; ++ } ++ ++ g_clear_object (&file); ++ g_clear_object (&info); ++ } ++ ++ if (*error) { ++ goto out; ++ } ++ ++ retval = TRUE; ++out: ++ g_clear_object (&file); ++ g_clear_object (&info); ++ g_clear_object (&enumerator); ++ ++ return retval; ++} ++ ++static void ++chown_initial_setup_home_dir (void) ++{ ++ GFile *dir; ++ GError *error; ++ char *gis_dir_path; ++ char *gis_uid_path; ++ char *gis_uid_contents; ++ struct passwd *pwe; ++ uid_t uid; ++ ++ if (!gdm_get_pwent_for_name (INITIAL_SETUP_USERNAME, &pwe)) { ++ g_warning ("Unknown user %s", INITIAL_SETUP_USERNAME); ++ return; ++ } ++ ++ gis_dir_path = g_strdup (pwe->pw_dir); ++ ++ gis_uid_path = g_build_filename (gis_dir_path, ++ "gnome-initial-setup-uid", ++ NULL); ++ if (!g_file_get_contents (gis_uid_path, &gis_uid_contents, NULL, NULL)) { ++ g_warning ("Unable to read %s", gis_uid_path); ++ goto out; ++ } ++ ++ uid = (uid_t) atoi (gis_uid_contents); ++ pwe = getpwuid (uid); ++ if (uid == 0 || pwe == NULL) { ++ g_warning ("UID '%s' in %s is not valid", gis_uid_contents, gis_uid_path); ++ goto out; ++ } ++ ++ error = NULL; ++ dir = g_file_new_for_path (gis_dir_path); ++ if (!chown_recursively (dir, pwe->pw_uid, pwe->pw_gid, &error)) { ++ g_warning ("Failed to change ownership for %s: %s", gis_dir_path, error->message); ++ g_error_free (error); ++ } ++ g_object_unref (dir); ++out: ++ g_free (gis_uid_contents); ++ g_free (gis_uid_path); ++ g_free (gis_dir_path); ++} ++ + static gboolean + on_start_user_session (StartUserSessionOperation *operation) + { + GdmManager *self = operation->manager; + gboolean migrated; + gboolean fail_if_already_switched = TRUE; + gboolean doing_initial_setup = FALSE; + GdmDisplay *display; + const char *session_id; + #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + g_autofree char *display_session_type = NULL; + #endif + + g_debug ("GdmManager: start or jump to session"); + + /* If there's already a session running, jump to it. + * If the only session running is the one we just opened, + * start a session on it. + */ + migrated = switch_to_compatible_user_session (operation->manager, operation->session, fail_if_already_switched); + + g_debug ("GdmManager: migrated: %d", migrated); + if (migrated) { + /* We don't stop the manager here because + when Xorg exits it switches to the VT it was + started from. That interferes with fast + user switching. */ + gdm_session_reset (operation->session); + destroy_start_user_session_operation (operation); + goto out; + } + + display = get_display_for_user_session (operation->session); + + g_object_get (G_OBJECT (display), + "doing-initial-setup", &doing_initial_setup, + #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + "session-type", &display_session_type, + #endif + NULL); + + session_id = gdm_session_get_conversation_session_id (operation->session, + operation->service_name); + + if (gdm_session_get_display_mode (operation->session) == GDM_SESSION_DISPLAY_MODE_REUSE_VT) { + /* In this case, the greeter's display is morphing into + * the user session display. Kill the greeter on this session + * and let the user session follow the same display. */ + gdm_display_stop_greeter_session (display); + g_object_set (G_OBJECT (display), + "session-class", "user", + "session-id", session_id, + NULL); + } else { + uid_t allowed_uid; + + g_object_ref (display); + if (doing_initial_setup) { ++ g_autoptr(GError) error = NULL; ++ + #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER) + if (g_strcmp0 (display_session_type, "wayland") == 0) { + g_debug ("GdmManager: closing down initial setup display in background"); + g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL); + } + #endif + if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) { + g_debug ("GdmManager: closing down initial setup display"); + gdm_display_stop_greeter_session (display); + gdm_display_unmanage (display); + gdm_display_finish (display); + } ++ ++ chown_initial_setup_home_dir (); ++ ++ if (!g_file_set_contents (ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT, ++ "1", ++ 1, ++ &error)) { ++ g_warning ("GdmDisplay: Could not write initial-setup-done marker to %s: %s", ++ ALREADY_RAN_INITIAL_SETUP_ON_THIS_BOOT, ++ error->message); ++ g_clear_error (&error); ++ } + } else { + g_debug ("GdmManager: session has its display server, reusing our server for another login screen"); + } + + /* The user session is going to follow the session worker + * into the new display. Untie it from this display and + * create a new session for a future user login. */ + allowed_uid = gdm_session_get_allowed_user (operation->session); + g_object_set_data (G_OBJECT (display), "gdm-user-session", NULL); + g_object_set_data (G_OBJECT (operation->session), "gdm-display", NULL); + create_user_session_for_display (operation->manager, display, allowed_uid); + + if (g_strcmp0 (operation->service_name, "gdm-autologin") == 0) { + /* remove the unused prepared greeter display since we're not going + * to have a greeter */ + gdm_display_store_remove (self->priv->display_store, display); + g_object_unref (display); + } + + /* Give the user session a new display object for bookkeeping purposes */ + create_display_for_user_session (operation->manager, + operation->session, + session_id); + } + + start_user_session (operation->manager, operation); + + out: + return G_SOURCE_REMOVE; + } +-- +2.17.1 + diff --git a/gdm.spec b/gdm.spec index c20ef13..afb800a 100644 --- a/gdm.spec +++ b/gdm.spec @@ -10,7 +10,7 @@ Name: gdm Epoch: 1 Version: 3.30.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: The GNOME Display Manager License: GPLv2+ @@ -19,6 +19,8 @@ Source0: http://download.gnome.org/sources/gdm/3.29/gdm-%{version}.tar.xz Source1: org.gnome.login-screen.gschema.override Patch0: 0001-Honor-initial-setup-being-disabled-by-distro-install.patch +Patch11: 0001-manager-do-initial-setup-post-work-in-manager-code.patch + Patch99: system-dconf.patch BuildRequires: pam-devel >= 0:%{pam_version} @@ -319,6 +321,10 @@ fi %{_libdir}/pkgconfig/gdm-pam-extensions.pc %changelog +* Fri Sep 07 2018 Ray Strode - 3.30.0-2 +- More initial setup fixes + Resolves: #1625572 + * Tue Sep 04 2018 Ray Strode - 3.30.0-1 - Update to 3.30.0 - Fixes initial setup