From d99f12385d6b04023cbe17f3f6fc2a917066c6e8 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 20 Dec 2018 14:51:38 -0500 Subject: [PATCH 1/3] manager: allow multiple xdmcp logins for the same user --- common/gdm-settings-keys.h | 1 + daemon/gdm-manager.c | 71 ++++++++++++++++++++++++++++---------- data/gdm.schemas.in | 5 +++ 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/common/gdm-settings-keys.h b/common/gdm-settings-keys.h index f0059b5cf..33676a851 100644 --- a/common/gdm-settings-keys.h +++ b/common/gdm-settings-keys.h @@ -28,37 +28,38 @@ G_BEGIN_DECLS #define GDM_KEY_USER "daemon/User" #define GDM_KEY_GROUP "daemon/Group" #define GDM_KEY_AUTO_LOGIN_ENABLE "daemon/AutomaticLoginEnable" #define GDM_KEY_AUTO_LOGIN_USER "daemon/AutomaticLogin" #define GDM_KEY_TIMED_LOGIN_ENABLE "daemon/TimedLoginEnable" #define GDM_KEY_TIMED_LOGIN_USER "daemon/TimedLogin" #define GDM_KEY_TIMED_LOGIN_DELAY "daemon/TimedLoginDelay" #define GDM_KEY_INITIAL_SETUP_ENABLE "daemon/InitialSetupEnable" #define GDM_KEY_WAYLAND_ENABLE "daemon/WaylandEnable" #define GDM_KEY_DEBUG "debug/Enable" #define GDM_KEY_INCLUDE "greeter/Include" #define GDM_KEY_EXCLUDE "greeter/Exclude" #define GDM_KEY_INCLUDE_ALL "greeter/IncludeAll" #define GDM_KEY_DISALLOW_TCP "security/DisallowTCP" #define GDM_KEY_ALLOW_REMOTE_AUTOLOGIN "security/AllowRemoteAutoLogin" #define GDM_KEY_XDMCP_ENABLE "xdmcp/Enable" #define GDM_KEY_SHOW_LOCAL_GREETER "xdmcp/ShowLocalGreeter" #define GDM_KEY_MAX_PENDING "xdmcp/MaxPending" #define GDM_KEY_MAX_SESSIONS "xdmcp/MaxSessions" #define GDM_KEY_MAX_WAIT "xdmcp/MaxWait" #define GDM_KEY_DISPLAYS_PER_HOST "xdmcp/DisplaysPerHost" #define GDM_KEY_UDP_PORT "xdmcp/Port" #define GDM_KEY_INDIRECT "xdmcp/HonorIndirect" #define GDM_KEY_MAX_WAIT_INDIRECT "xdmcp/MaxWaitIndirect" #define GDM_KEY_PING_INTERVAL "xdmcp/PingIntervalSeconds" #define GDM_KEY_WILLING "xdmcp/Willing" +#define GDM_KEY_ALLOW_MULTIPLE_SESSIONS_PER_USER "xdmcp/AllowMultipleSessionsPerUser" #define GDM_KEY_MULTICAST "chooser/Multicast" #define GDM_KEY_MULTICAST_ADDR "chooser/MulticastAddr" G_END_DECLS #endif /* _GDM_SETTINGS_KEYS_H */ diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index 9c10adff3..b96295ab6 100644 --- a/daemon/gdm-manager.c +++ b/daemon/gdm-manager.c @@ -566,93 +566,106 @@ get_display_and_details_for_bus_sender (GdmManager *self, *out_tty = get_tty_for_session_id (session_id, &error); if (error != NULL) { g_debug ("GdmManager: Error while retrieving tty for session: %s", error->message); g_clear_error (&error); } } display = gdm_display_store_find (self->priv->display_store, lookup_by_session_id, (gpointer) session_id); out: if (out_display != NULL) { *out_display = display; } g_free (session_id); } static gboolean switch_to_compatible_user_session (GdmManager *manager, GdmSession *session, gboolean fail_if_already_switched) { gboolean res; gboolean ret; const char *username; const char *seat_id; - const char *ssid_to_activate; + const char *ssid_to_activate = NULL; GdmSession *existing_session; ret = FALSE; username = gdm_session_get_username (session); seat_id = gdm_session_get_display_seat_id (session); - if (!fail_if_already_switched) { - session = NULL; - } + if (!fail_if_already_switched) + ssid_to_activate = gdm_session_get_session_id (session); - existing_session = find_session_for_user_on_seat (manager, username, seat_id, session); + if (ssid_to_activate == NULL) { + if (!seat_id || !sd_seat_can_multi_session (seat_id)) { + g_debug ("GdmManager: unable to activate existing sessions from login screen unless on seat0"); + goto out; + } - if (existing_session != NULL) { - ssid_to_activate = gdm_session_get_session_id (existing_session); - if (seat_id != NULL) { - res = gdm_activate_session_by_id (manager->priv->connection, seat_id, ssid_to_activate); - if (! res) { - g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate); - goto out; - } + if (!fail_if_already_switched) { + session = NULL; } - res = session_unlock (manager, ssid_to_activate); - if (!res) { - /* this isn't fatal */ - g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate); + existing_session = find_session_for_user_on_seat (manager, username, seat_id, session); + + if (existing_session != NULL) { + ssid_to_activate = gdm_session_get_session_id (existing_session); } - } else { + } + + if (ssid_to_activate == NULL) { goto out; } + if (seat_id != NULL) { + res = gdm_activate_session_by_id (manager->priv->connection, seat_id, ssid_to_activate); + if (! res) { + g_debug ("GdmManager: unable to activate session: %s", ssid_to_activate); + goto out; + } + } + + res = session_unlock (manager, ssid_to_activate); + if (!res) { + /* this isn't fatal */ + g_debug ("GdmManager: unable to unlock session: %s", ssid_to_activate); + } + ret = TRUE; out: return ret; } static GdmDisplay * get_display_for_user_session (GdmSession *session) { return g_object_get_data (G_OBJECT (session), "gdm-display"); } static GdmSession * get_user_session_for_display (GdmDisplay *display) { if (display == NULL) { return NULL; } return g_object_get_data (G_OBJECT (display), "gdm-user-session"); } static gboolean add_session_record (GdmManager *manager, GdmSession *session, GPid pid, SessionRecord record) { const char *username; char *display_name, *hostname, *display_device; @@ -1089,92 +1102,114 @@ open_temporary_reauthentication_channel (GdmManager *self, g_signal_connect (session, "client-disconnected", G_CALLBACK (on_reauthentication_client_disconnected), self); g_signal_connect (session, "client-rejected", G_CALLBACK (on_reauthentication_client_rejected), self); g_signal_connect (session, "cancelled", G_CALLBACK (on_reauthentication_cancelled), self); g_signal_connect (session, "conversation-started", G_CALLBACK (on_reauthentication_conversation_started), self); g_signal_connect (session, "conversation-stopped", G_CALLBACK (on_reauthentication_conversation_stopped), self); g_signal_connect (session, "verification-complete", G_CALLBACK (on_reauthentication_verification_complete), self); address = gdm_session_get_server_address (session); return g_strdup (address); } +static gboolean +remote_users_can_log_in_more_than_once (GdmManager *manager) +{ + gboolean enabled; + + enabled = FALSE; + + gdm_settings_direct_get_boolean (GDM_KEY_ALLOW_MULTIPLE_SESSIONS_PER_USER, &enabled); + + g_debug ("GdmDisplay: Remote users allowed to log in more than once: %s", enabled? "yes" : "no"); + + return enabled; +} + static gboolean gdm_manager_handle_open_reauthentication_channel (GdmDBusManager *manager, GDBusMethodInvocation *invocation, const char *username) { GdmManager *self = GDM_MANAGER (manager); const char *sender; GdmDisplay *display = NULL; GdmSession *session; GDBusConnection *connection; char *seat_id = NULL; char *session_id = NULL; GPid pid = 0; uid_t uid = (uid_t) -1; gboolean is_login_screen = FALSE; gboolean is_remote = FALSE; g_debug ("GdmManager: trying to open reauthentication channel for user %s", username); sender = g_dbus_method_invocation_get_sender (invocation); connection = g_dbus_method_invocation_get_connection (invocation); get_display_and_details_for_bus_sender (self, connection, sender, &display, &seat_id, &session_id, NULL, &pid, &uid, &is_login_screen, &is_remote); if (session_id == NULL || pid == 0 || uid == (uid_t) -1) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, _("No session available")); return TRUE; } + if (is_login_screen && is_remote && remote_users_can_log_in_more_than_once (self)) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "Login screen creates new sessions for remote connections"); + return TRUE; + } + if (is_login_screen) { g_debug ("GdmManager: looking for login screen session for user %s on seat %s", username, seat_id); session = find_session_for_user_on_seat (self, username, seat_id, NULL); } else { g_debug ("GdmManager: looking for user session on display"); session = get_user_session_for_display (display); } if (session != NULL && gdm_session_is_running (session)) { gdm_session_start_reauthentication (session, pid, uid); g_hash_table_insert (self->priv->open_reauthentication_requests, GINT_TO_POINTER (pid), invocation); } else if (is_login_screen) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, "Login screen only allowed to open reauthentication channels for running sessions"); return TRUE; } else { char *address; address = open_temporary_reauthentication_channel (self, seat_id, session_id, pid, uid, is_remote); diff --git a/data/gdm.schemas.in b/data/gdm.schemas.in index 255bff023..86059c02e 100644 --- a/data/gdm.schemas.in +++ b/data/gdm.schemas.in @@ -102,33 +102,38 @@ xdmcp/DisplaysPerHost i 1 xdmcp/Port i 177 xdmcp/HonorIndirect b true xdmcp/MaxWaitIndirect i 30 xdmcp/PingIntervalSeconds i 0 xdmcp/Willing s @gdmconfdir@/Xwilling + + xdmcp/AllowMultipleSessionsPerUser + b + false + -- 2.31.1