From c3f39b437f6ef32174f322bd107071cdf1379d12 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 18 Apr 2016 16:09:08 -0400 Subject: [PATCH 1/2] worker: run PostLogin/PreSession scripts later Right now we run them while the login screen is still up, so they have no way of showing UI to the user. This commit moves them until after the login screen is torn down. --- daemon/gdm-session-worker.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index acc826b..e07d32e 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -1793,60 +1793,78 @@ out: } static gboolean gdm_session_worker_start_session (GdmSessionWorker *worker, GError **error) { struct passwd *passwd_entry; pid_t session_pid; int error_code; gdm_get_pwent_for_name (worker->priv->username, &passwd_entry); if (worker->priv->is_program_session) { g_debug ("GdmSessionWorker: opening session for program '%s'", worker->priv->arguments[0]); } else { g_debug ("GdmSessionWorker: opening user session with program '%s'", worker->priv->arguments[0]); } error_code = PAM_SUCCESS; #ifdef ENABLE_WAYLAND_SUPPORT /* If we're in new vt mode, jump to the new vt now. There's no need to jump for * the other two modes: in the logind case, the session will activate itself when * ready, and in the reuse server case, we're already on the correct VT. */ if (worker->priv->display_mode == GDM_SESSION_DISPLAY_MODE_NEW_VT) { jump_to_vt (worker, worker->priv->session_vt); } #endif + if (!worker->priv->is_program_session && !run_script (worker, GDMCONFDIR "/PostLogin")) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "Failed to execute PostLogin script"); + error_code = PAM_ABORT; + goto out; + } + + if (!worker->priv->is_program_session && !run_script (worker, GDMCONFDIR "/PreSession")) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "Failed to execute PreSession script"); + error_code = PAM_ABORT; + goto out; + } + session_pid = fork (); if (session_pid < 0) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_OPENING_SESSION, "%s", g_strerror (errno)); error_code = PAM_ABORT; goto out; } if (session_pid == 0) { const char * const * environment; char *home_dir; int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1; gboolean has_journald = FALSE; sigset_t mask; /* Leak the TTY into the session as stdin so that it stays open * without any races. */ if (worker->priv->session_tty_fd > 0) { dup2 (worker->priv->session_tty_fd, STDIN_FILENO); close (worker->priv->session_tty_fd); worker->priv->session_tty_fd = -1; } else { stdin_fd = open ("/dev/null", O_RDWR); dup2 (stdin_fd, STDIN_FILENO); close (stdin_fd); } @@ -2186,93 +2204,77 @@ gdm_session_worker_open_session (GdmSessionWorker *worker, g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED); g_assert (geteuid () == 0); switch (worker->priv->display_mode) { case GDM_SESSION_DISPLAY_MODE_REUSE_VT: if (!set_up_for_current_vt (worker, error)) { return FALSE; } break; #ifdef ENABLE_WAYLAND_SUPPORT case GDM_SESSION_DISPLAY_MODE_NEW_VT: case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: if (!set_up_for_new_vt (worker)) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_OPENING_SESSION, "Unable to open VT"); return FALSE; } break; #endif } flags = 0; if (worker->priv->is_program_session) { flags |= PAM_SILENT; } - if (!run_script (worker, GDMCONFDIR "/PostLogin")) { - g_set_error (error, - GDM_SESSION_WORKER_ERROR, - GDM_SESSION_WORKER_ERROR_OPENING_SESSION, - "Failed to execute PostLogin script"); - return FALSE; - } - error_code = pam_open_session (worker->priv->pam_handle, flags); if (error_code != PAM_SUCCESS) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_OPENING_SESSION, "%s", pam_strerror (worker->priv->pam_handle, error_code)); goto out; } g_debug ("GdmSessionWorker: state SESSION_OPENED"); worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED; #ifdef WITH_SYSTEMD session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID"); #endif - /* FIXME: should we do something here? - * Note that error return status from PreSession script should - * be ignored in the case of a X-GDM-BypassXsession session, which can - * be checked by calling: - * gdm_session_bypasses_xsession (session) - */ - run_script (worker, GDMCONFDIR "/PreSession"); - #ifdef WITH_CONSOLE_KIT register_ck_session (worker); if (session_id == NULL) { session_id = get_ck_session_id (worker); } #endif if (session_id != NULL) { g_free (worker->priv->session_id); worker->priv->session_id = session_id; } out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } gdm_session_worker_get_username (worker, NULL); gdm_session_auditor_report_login (worker->priv->auditor); return TRUE; } static void gdm_session_worker_set_server_address (GdmSessionWorker *worker, const char *address) { g_free (worker->priv->server_address); -- 2.8.1 From ebc5a37f8f4a287df4255cbcdf5d51f7a8fe9b44 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 19 Apr 2016 11:02:08 -0400 Subject: [PATCH 2/2] manager: handle session failing to start Right now if a session fails really early in the start up process, we fail to handle it. This commit fixes that. --- daemon/gdm-manager.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index 33064ea..72ea968 100644 --- a/daemon/gdm-manager.c +++ b/daemon/gdm-manager.c @@ -1475,60 +1475,69 @@ on_session_started (GdmSession *session, session_id = gdm_session_get_session_id (session); g_object_set (GDM_SLAVE (slave), "session-id", session_id, NULL); } } static void remove_user_session (GdmManager *manager, GdmSession *session) { GList *node; GdmDisplay *display; display = get_display_for_user_session (session); if (display != NULL) { gdm_display_unmanage (display); gdm_display_finish (display); } node = g_list_find (manager->priv->user_sessions, session); if (node != NULL) { manager->priv->user_sessions = g_list_delete_link (manager->priv->user_sessions, node); gdm_session_close (session); g_object_unref (session); } } static void +on_session_start_failed (GdmSession *session, + const char *service_name, + GdmManager *manager) +{ + g_debug ("GdmManager: session failed to start"); + remove_user_session (manager, session); +} + +static void on_user_session_exited (GdmSession *session, int code, GdmManager *manager) { g_debug ("GdmManager: session exited with status %d", code); remove_user_session (manager, session); } static void on_user_session_died (GdmSession *session, int signal_number, GdmManager *manager) { g_debug ("GdmManager: session died with signal %s", strsignal (signal_number)); remove_user_session (manager, session); } static char * query_ck_for_display_device (GdmManager *manager, GdmDisplay *display) { char *out; char *command; char *display_name = NULL; int status; gboolean res; GError *error; g_object_get (G_OBJECT (display), "x11-display-name", &display_name, @@ -1894,60 +1903,64 @@ create_seed_session_for_display (GdmManager *manager, manager); g_signal_connect (session, "client-connected", G_CALLBACK (on_session_client_connected), manager); g_signal_connect (session, "client-disconnected", G_CALLBACK (on_session_client_disconnected), manager); g_signal_connect (session, "cancelled", G_CALLBACK (on_session_cancelled), manager); g_signal_connect (session, "conversation-started", G_CALLBACK (on_session_conversation_started), manager); g_signal_connect (session, "conversation-stopped", G_CALLBACK (on_session_conversation_stopped), manager); g_signal_connect (session, "session-opened", G_CALLBACK (on_session_opened), manager); g_signal_connect (session, "session-started", G_CALLBACK (on_session_started), manager); g_signal_connect (session, + "session-start-failed", + G_CALLBACK (on_session_start_failed), + manager); + g_signal_connect (session, "session-exited", G_CALLBACK (on_user_session_exited), manager); g_signal_connect (session, "session-died", G_CALLBACK (on_user_session_died), manager); g_object_set_data (G_OBJECT (session), "gdm-display", display); g_object_set_data_full (G_OBJECT (display), "gdm-seed-session", g_object_ref (session), (GDestroyNotify) g_object_unref); start_autologin_conversation_if_necessary (manager, display, session); } static void on_display_added (GdmDisplayStore *display_store, const char *id, GdmManager *manager) { GdmDisplay *display; display = gdm_display_store_lookup (display_store, id); if (display != NULL) { g_dbus_object_manager_server_export (manager->priv->object_manager, gdm_display_get_object_skeleton (display)); g_signal_connect (display, "notify::status", G_CALLBACK (on_display_status_changed), manager); g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id); -- 2.8.1