summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--src/Makefile.am4
-rw-r--r--src/display.c736
-rw-r--r--src/greeter.c233
-rw-r--r--src/greeter.h11
-rw-r--r--src/lightdm.c16
-rw-r--r--src/pam-session.c472
-rw-r--r--src/pam-session.h88
-rw-r--r--src/seat-xdmcp-session.c4
-rw-r--r--src/seat-xlocal.c3
-rw-r--r--src/seat-xremote.c3
-rw-r--r--src/seat-xvnc.c3
-rw-r--r--src/seat.c3
-rw-r--r--src/seat.h1
-rw-r--r--src/session-child.c534
-rw-r--r--src/session-child.h17
-rw-r--r--src/session.c789
-rw-r--r--src/session.h58
-rw-r--r--src/xsession.c143
-rw-r--r--tests/Makefile.am8
20 files changed, 1562 insertions, 1566 deletions
diff --git a/NEWS b/NEWS
index db86688b..69c27c6c 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Overview of changes in lightdm 1.1.4
* Change session directory once user permissions are set so it works
on NFS filesystems that don't allow root to access files.
+ * Restructure session code so the PAM authentication is run in it's
+ own process.
Overview of changes in lightdm 1.1.3
diff --git a/src/Makefile.am b/src/Makefile.am
index b66f197e..4cf2863a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,8 +28,6 @@ lightdm_SOURCES = \
lightdm.c \
ldm-marshal.c \
ldm-marshal.h \
- pam-session.c \
- pam-session.h \
plymouth.c \
plymouth.h \
privileges.c \
@@ -48,6 +46,8 @@ lightdm_SOURCES = \
seat-xvnc.h \
session.c \
session.h \
+ session-child.c \
+ session-child.h \
vnc-server.c \
vnc-server.h \
vt.c \
diff --git a/src/display.c b/src/display.c
index f572f3ba..da6949dd 100644
--- a/src/display.c
+++ b/src/display.c
@@ -18,7 +18,6 @@
#include "display.h"
#include "configuration.h"
#include "ldm-marshal.h"
-#include "pam-session.h"
#include "greeter.h"
enum
@@ -71,9 +70,6 @@ struct DisplayPrivate
/* PAM service to authenticate against for automatic logins */
gchar *pam_autologin_service;
- /* TRUE if a session should be started on greeter quit */
- gboolean start_session_on_greeter_quit;
-
/* TRUE if in a user session */
gboolean in_user_session;
@@ -110,8 +106,8 @@ struct DisplayPrivate
G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT);
-static gboolean start_greeter_session (Display *display);
-static gboolean start_user_session (Display *display, PAMSession *authentication);
+static void greeter_session_stopped_cb (Session *session, Display *display);
+static void user_session_stopped_cb (Session *session, Display *display);
Display *
display_new (DisplayServer *display_server)
@@ -138,7 +134,7 @@ display_get_username (Display *display)
if (!display->priv->session || !display->priv->in_user_session)
return NULL;
- return user_get_name (session_get_user (display->priv->session));
+ return session_get_username (display->priv->session);
}
Session *
@@ -212,6 +208,16 @@ display_set_user_session (Display *display, const gchar *session_name)
display->priv->user_session = g_strdup (session_name);
}
+static void
+display_set_is_ready (Display *display)
+{
+ if (display->priv->is_ready)
+ return;
+
+ display->priv->is_ready = TRUE;
+ g_signal_emit (display, signals[READY], 0);
+}
+
static gboolean
switch_to_user (Display *display, User *user)
{
@@ -236,261 +242,14 @@ get_guest_username (Display *display)
return username;
}
-static void
-autologin_authentication_result_cb (PAMSession *authentication, int result, Display *display)
-{
- g_signal_handlers_disconnect_matched (authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
- if (display->priv->stopping)
- return;
-
- gboolean started_session = FALSE;
-
- if (result == PAM_SUCCESS)
- {
- User *user;
- const gchar *session_name;
-
- user = pam_session_get_user (authentication);
-
- if (user)
- {
- g_debug ("User %s authorized", pam_session_get_username (authentication));
-
- session_name = user_get_xsession (user);
- if (session_name)
- {
- g_debug ("Using session %s", session_name);
- display_set_user_session (display, session_name);
- }
-
- started_session = start_user_session (display, authentication);
- if (!started_session)
- g_debug ("Failed to start autologin session");
- }
- else
- g_debug ("User %s was authorized, but no account of that name exists", pam_session_get_username (authentication));
- }
- else
- g_debug ("Autologin failed authentication");
-
- if (!started_session && display->priv->start_greeter_if_fail)
- {
- display_set_autologin_user (display, NULL, FALSE, 0);
- if (display->priv->autologin_user)
- display_set_select_user_hint (display, display->priv->autologin_user, FALSE);
- started_session = start_greeter_session (display);
- }
-
- if (!started_session)
- display_stop (display);
-}
-
-static gboolean
-autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail)
-{
- gboolean result;
- PAMSession *authentication;
- GError *error = NULL;
-
- display->priv->start_greeter_if_fail = start_greeter_if_fail;
-
- display->priv->in_user_session = TRUE;
- authentication = pam_session_new (service, username);
- pam_session_set_interactive (authentication, FALSE);
- g_signal_connect (authentication, "authentication-result", G_CALLBACK (autologin_authentication_result_cb), display);
-
- result = pam_session_authenticate (authentication, &error);
- if (error)
- g_debug ("Failed to start autologin session for %s: %s", username, error->message);
- if (!result)
- {
- g_signal_handlers_disconnect_matched (authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
- g_object_unref (authentication);
- }
- g_clear_error (&error);
-
- return result;
-}
-
-static gboolean
-autologin_guest (Display *display, const gchar *service, gboolean start_greeter_if_fail)
-{
- gchar *username;
- gboolean result;
-
- username = get_guest_username (display);
- if (!username)
- {
- g_debug ("Can't autologin guest, no guest account");
- return FALSE;
- }
-
- result = autologin (display, username, service, start_greeter_if_fail);
- g_free (username);
-
- return result;
-}
-
-static gboolean
-cleanup_after_session (Display *display)
-{
- g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
- g_object_unref (display->priv->session);
- display->priv->session = NULL;
-
- if (display->priv->stopping)
- {
- display_stop (display);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-greeter_session_stopped_cb (Session *session, Display *display)
-{
- gboolean started_session = FALSE;
-
- g_debug ("Greeter quit");
-
- if (cleanup_after_session (display))
- return;
-
- if (!display->priv->display_server)
- return;
-
- /* Start the session for the authenticated user */
- if (display->priv->start_session_on_greeter_quit)
- {
- if (greeter_get_guest_authenticated (display->priv->greeter))
- {
- started_session = autologin_guest (display, display->priv->pam_autologin_service, FALSE);
- if (!started_session)
- g_debug ("Failed to start guest session");
- }
- else
- {
- display->priv->in_user_session = TRUE;
- started_session = start_user_session (display, greeter_get_authentication (display->priv->greeter));
- if (!started_session)
- g_debug ("Failed to start user session");
- }
- }
-
- g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
- g_object_unref (display->priv->greeter);
- display->priv->greeter = NULL;
-
- if (!started_session)
- display_stop (display);
-}
-
-static void
-user_session_stopped_cb (Session *session, Display *display)
-{
- g_debug ("User session quit");
-
- if (cleanup_after_session (display))
- return;
-
- /* This display has ended */
- display_stop (display);
-}
-
static Session *
-create_session (Display *display, PAMSession *authentication, const gchar *session_name, gboolean is_greeter)
+create_session (Display *display)
{
- gchar *sessions_dir, *filename, *path, *command = NULL;
- GKeyFile *session_desktop_file;
- gint argc;
- gchar **argv;
Session *session;
- gboolean result;
- GError *error = NULL;
-
- g_debug ("Starting session %s as user %s", session_name, pam_session_get_username (authentication));
-
- // FIXME: This is X specific, move into xsession.c
- if (is_greeter)
- sessions_dir = config_get_string (config_get_instance (), "LightDM", "xgreeters-directory");
- else
- sessions_dir = config_get_string (config_get_instance (), "LightDM", "xsessions-directory");
- filename = g_strdup_printf ("%s.desktop", session_name);
- path = g_build_filename (sessions_dir, filename, NULL);
- g_free (sessions_dir);
- g_free (filename);
-
- session_desktop_file = g_key_file_new ();
- result = g_key_file_load_from_file (session_desktop_file, path, G_KEY_FILE_NONE, &error);
- if (error)
- g_debug ("Failed to load session file %s: %s:", path, error->message);
- g_clear_error (&error);
- if (result)
- {
- command = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
- if (!command)
- g_debug ("No command in session file %s", path);
- }
- g_key_file_free (session_desktop_file);
- g_free (path);
- if (!command)
- return NULL;
-
- result = g_shell_parse_argv (command, &argc, &argv, &error);
- if (error)
- g_debug ("Invalid session command '%s': %s", command, error->message);
- g_clear_error (&error);
- g_free (command);
- if (!result)
- return NULL;
-
- /* Convert to full path */
- path = g_find_program_in_path (argv[0]);
- if (path)
- {
- g_free (argv[0]);
- argv[0] = path;
- }
- command = g_strjoinv (" ", argv);
-
- if (display->priv->session_wrapper && !is_greeter)
- {
- gchar *wrapper;
-
- wrapper = g_find_program_in_path (display->priv->session_wrapper);
- if (wrapper)
- {
- gchar *t = command;
- command = g_strdup_printf ("%s '%s'", wrapper, command);
- g_free (t);
- g_free (wrapper);
- }
- }
-
- /* for a guest session, run command through the wrapper covered by MAC */
- if (display->priv->autologin_guest)
- {
- gchar *t = command;
- command = g_strdup_printf (PKGLIBEXEC_DIR "/lightdm-guest-session-wrapper %s", command);
- g_debug("Guest session, running session command through wrapper: %s", command);
- g_free (t);
- }
g_signal_emit (display, signals[CREATE_SESSION], 0, &session);
- g_return_val_if_fail (session != NULL, NULL);
-
- if (is_greeter)
- g_signal_connect_after (session, "stopped", G_CALLBACK (greeter_session_stopped_cb), display);
- else
- g_signal_connect_after (session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
- session_set_is_greeter (session, is_greeter);
- session_set_authentication (session, authentication);
- session_set_command (session, command);
- g_free (command);
-
- session_set_env (session, "DESKTOP_SESSION", session_name); // FIXME: Apparently deprecated?
- session_set_env (session, "GDMSESSION", session_name); // FIXME: Not cross-desktop
+ if (!session)
+ return NULL;
/* Connect using the session bus */
if (getuid () != 0)
@@ -524,13 +283,39 @@ create_session (Display *display, PAMSession *authentication, const gchar *sessi
}
static void
-display_set_is_ready (Display *display)
+destroy_session (Display *display)
{
- if (display->priv->is_ready)
+ if (!display->priv->session)
return;
- display->priv->is_ready = TRUE;
- g_signal_emit (display, signals[READY], 0);
+ g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ session_stop (display->priv->session);
+ g_object_unref (display->priv->session);
+ display->priv->session = NULL;
+}
+
+static void
+greeter_authentication_complete_cb (Session *session, Display *display)
+{
+ gboolean result = FALSE;
+
+ if (display->priv->stopping)
+ return;
+
+ if (session_get_is_authenticated (session))
+ {
+ g_debug ("Greeter authorized");
+ g_signal_emit (display, signals[START_GREETER], 0, &result);
+ result = !result;
+ }
+ else
+ g_debug ("Greeter failed authentication");
+
+ if (!result)
+ {
+ g_debug ("Greeter failed to start");
+ display_stop (display);
+ }
}
static void
@@ -541,10 +326,10 @@ greeter_connected_cb (Greeter *greeter, Display *display)
display_set_is_ready (display);
}
-static PAMSession *
+static Session *
greeter_start_authentication_cb (Greeter *greeter, const gchar *username, Display *display)
{
- return pam_session_new (display->priv->pam_service, username);
+ return create_session (display);
}
static gboolean
@@ -555,7 +340,7 @@ greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display *
{
User *user;
- user = pam_session_get_user (greeter_get_authentication (greeter));
+ user = session_get_user (greeter_get_authentication_session (greeter));
session_name = user_get_xsession (user);
}
@@ -577,74 +362,30 @@ greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display *
}
else
{
- if (switch_to_user (display, pam_session_get_user (greeter_get_authentication (display->priv->greeter))))
- return TRUE;
+ if (switch_to_user (display, session_get_user (greeter_get_authentication_session (display->priv->greeter))))
+ return TRUE;
}
/* Stop the greeter, the session will start when the greeter has quit */
g_debug ("Stopping greeter");
- display->priv->start_session_on_greeter_quit = TRUE;
session_stop (display->priv->session);
return TRUE;
}
static gboolean
-start_greeter_session (Display *display)
+start_greeter (Display *display)
{
- User *user;
- gchar *log_dir, *filename, *log_filename;
- PAMSession *authentication;
- gboolean start_result;
-
- g_return_val_if_fail (display->priv->session == NULL, FALSE);
- g_return_val_if_fail (display->priv->greeter == NULL, FALSE);
-
- g_debug ("Starting greeter session");
-
- if (getuid () != 0)
- user = accounts_get_current_user ();
- else
- {
- gchar *greeter_user;
-
- greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
- if (!greeter_user)
- {
- g_warning ("Greeter must not be run as root");
- return FALSE;
- }
-
- user = accounts_get_user_by_name (greeter_user);
- if (!user)
- g_debug ("Unable to start greeter, user %s does not exist", greeter_user);
- g_free (greeter_user);
- if (!user)
- return FALSE;
- }
- display->priv->in_user_session = FALSE;
-
- /* Authenticate as the requested user */
- authentication = pam_session_new (display->priv->pam_service, user_get_name (user));
- g_object_unref (user);
-
- display->priv->session = create_session (display, authentication, display->priv->greeter_session, TRUE);
- g_object_unref (authentication);
-
- if (!display->priv->session)
- return FALSE;
-
- log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
- filename = g_strdup_printf ("%s-greeter.log", display_server_get_name (display->priv->display_server));
- log_filename = g_build_filename (log_dir, filename, NULL);
- g_free (log_dir);
- g_free (filename);
+ gchar *greeter_user;
+ gboolean result;
- g_debug ("Logging to %s", log_filename);
- session_set_log_file (display->priv->session, log_filename, FALSE);
- g_free (log_filename);
+ destroy_session (display);
+ display->priv->session = create_session (display);
+ session_set_class (display->priv->session, XDG_SESSION_CLASS_GREETER);
+ g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (greeter_authentication_complete_cb), display);
- display->priv->greeter = greeter_new (display->priv->session);
+ /* Make communication link to greeter that will run on this session */
+ display->priv->greeter = greeter_new (display->priv->session, display->priv->pam_service);
g_signal_connect (G_OBJECT (display->priv->greeter), "connected", G_CALLBACK (greeter_connected_cb), display);
g_signal_connect (G_OBJECT (display->priv->greeter), "start-authentication", G_CALLBACK (greeter_start_authentication_cb), display);
g_signal_connect (G_OBJECT (display->priv->greeter), "start-session", G_CALLBACK (greeter_start_session_cb), display);
@@ -669,83 +410,310 @@ start_greeter_session (Display *display)
if (display->priv->greeter_is_lock)
greeter_set_hint (display->priv->greeter, "lock-screen", "true");
- start_result = FALSE;
- g_signal_emit (display, signals[START_GREETER], 0, &start_result);
+ /* Run greeter as unprivileged user */
+ if (getuid () != 0)
+ {
+ User *user;
+ user = accounts_get_current_user ();
+ greeter_user = g_strdup (user_get_name (user));
+ g_object_unref (user);
+ }
+ else
+ {
+ greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
+ if (!greeter_user)
+ {
+ g_warning ("Greeter must not be run as root");
+ display_stop (display);
+ return FALSE;
+ }
+ }
+
+ g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (greeter_session_stopped_cb), display);
+ result = session_start (display->priv->session, display->priv->pam_service, greeter_user, FALSE, FALSE);
+ g_free (greeter_user);
+
+ if (!result)
+ display_stop (display);
- return !start_result;
+ return result;
}
-static gboolean
-display_start_greeter (Display *display)
+static void
+autologin_authentication_complete_cb (Session *session, Display *display)
{
- if (!greeter_start (display->priv->greeter))
+ gboolean result = FALSE;
+
+ if (display->priv->stopping)
+ return;
+
+ if (session_get_is_authenticated (session))
{
- g_debug ("Failed to start greeter protocol");
+ const gchar *session_name;
- g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
- g_object_unref (display->priv->greeter);
- display->priv->greeter = NULL;
+ g_debug ("Autologin user %s authorized", session_get_username (session));
- return TRUE;
+ session_name = user_get_xsession (session_get_user (session));
+ if (session_name)
+ {
+ g_debug ("Autologin using session %s", session_name);
+ display_set_user_session (display, session_name);
+ }
+
+ g_signal_emit (display, signals[START_SESSION], 0, &result);
+ result = !result;
}
-
- if (!session_start (SESSION (display->priv->session)))
- {
- g_debug ("Failed to start greeter session");
- return TRUE;
+ else
+ g_debug ("Autologin failed authentication");
+
+ if (!result)
+ {
+ if (display->priv->start_greeter_if_fail)
+ start_greeter (display);
+ else
+ display_stop (display);
}
+}
- return FALSE;
+static gboolean
+autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail)
+{
+ display->priv->start_greeter_if_fail = start_greeter_if_fail;
+
+ display->priv->in_user_session = TRUE;
+ destroy_session (display);
+ display->priv->session = create_session (display);
+ g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (autologin_authentication_complete_cb), display);
+ g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
+ return session_start (display->priv->session, service, username, TRUE, FALSE);
}
static gboolean
-start_user_session (Display *display, PAMSession *authentication)
+autologin_guest (Display *display, const gchar *service, gboolean start_greeter_if_fail)
{
- User *user;
- gchar *log_filename;
+ gchar *username;
gboolean result;
- g_return_val_if_fail (display->priv->session == NULL, FALSE);
+ username = get_guest_username (display);
+ if (!username)
+ {
+ g_debug ("Can't autologin guest, no guest account");
+ return FALSE;
+ }
- g_debug ("Starting user session");
+ result = autologin (display, username, service, start_greeter_if_fail);
+ g_free (username);
- user = pam_session_get_user (authentication);
+ return result;
+}
- /* Update user's xsession setting */
- user_set_xsession (user, display->priv->user_session);
-
- display->priv->session = create_session (display, authentication, display->priv->user_session, FALSE);
+static gchar **
+get_session_command (const gchar *filename)
+{
+ GKeyFile *session_desktop_file;
+ gboolean result;
+ int argc;
+ gchar *command = NULL, **argv, *path;
+ GError *error = NULL;
- if (!display->priv->session)
- return FALSE;
+ /* Read the command from the .desktop file */
+ session_desktop_file = g_key_file_new ();
+ result = g_key_file_load_from_file (session_desktop_file, filename, G_KEY_FILE_NONE, &error);
+ if (error)
+ g_debug ("Failed to load session file %s: %s", filename, error->message);
+ g_clear_error (&error);
+ if (result)
+ {
+ command = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
+ if (!command)
+ g_debug ("No command in session file %s", filename);
+ }
+ g_key_file_free (session_desktop_file);
+
+ if (!command)
+ return NULL;
- // FIXME: Copy old error file
- log_filename = g_build_filename (user_get_home_directory (user), ".xsession-errors", NULL);
+ /* Split command into an array listing and make command absolute */
+ result = g_shell_parse_argv (command, &argc, &argv, &error);
+ if (error)
+ g_debug ("Invalid session command '%s': %s", command, error->message);
+ g_clear_error (&error);
+ g_free (command);
+ if (!result)
+ return NULL;
+ path = g_find_program_in_path (argv[0]);
+ if (path)
+ {
+ g_free (argv[0]);
+ argv[0] = path;
+ }
- /* Delete existing log file if it exists - a bug in 1.0.0 would cause this file to be written as root */
- unlink (log_filename);
+ return argv;
+}
- g_debug ("Logging to %s", log_filename);
- session_set_log_file (display->priv->session, log_filename, TRUE);
- g_free (log_filename);
+static void
+greeter_session_stopped_cb (Session *session, Display *display)
+{
+ gboolean result = FALSE;
+
+ g_debug ("Greeter quit");
+
+ g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ g_object_unref (display->priv->session);
+ display->priv->session = NULL;
+
+ if (display->priv->stopping)
+ {
+ display_stop (display);
+ return;
+ }
+
+ if (!display->priv->display_server)
+ return;
+
+ /* Start the session for the authenticated user */
+ if (greeter_get_start_session (display->priv->greeter))
+ {
+ /* If guest, then start a new autologin guest session (so can setup account) */
+ if (greeter_get_guest_authenticated (display->priv->greeter))
+ result = autologin_guest (display, display->priv->pam_autologin_service, FALSE);
+ /* Otherwise, use the session the greeter has authenticated */
+ else
+ {
+ destroy_session (display);
+ display->priv->session = g_object_ref (greeter_get_authentication_session (display->priv->greeter));
+ g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
+ display->priv->in_user_session = TRUE;
+ g_signal_emit (display, signals[START_SESSION], 0, &result);
+ result = !result;
+ }
+ }
- g_signal_emit (display, signals[START_SESSION], 0, &result);
- result = !result;
+ /* Destroy the greeter */
+ g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ g_object_unref (display->priv->greeter);
+ display->priv->greeter = NULL;
if (!result)
{
- g_object_unref (display->priv->session);
- display->priv->session = NULL;
+ g_debug ("Failed to start greeter");
+ display_stop (display);
}
+}
- return result;
+static gboolean
+display_start_greeter (Display *display)
+{
+ gchar *log_dir, *filename, *log_filename, *sessions_dir, *path;
+ gchar **argv;
+
+ /* Log the output of the greeter to a system location */
+ log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
+ filename = g_strdup_printf ("%s-greeter.log", display_server_get_name (display->priv->display_server));
+ log_filename = g_build_filename (log_dir, filename, NULL);
+ g_free (log_dir);
+ g_free (filename);
+ g_debug ("Logging to %s", log_filename);
+ session_set_log_file (display->priv->session, log_filename);
+ g_free (log_filename);
+
+ /* Load the greeter session information */
+ sessions_dir = config_get_string (config_get_instance (), "LightDM", "xgreeters-directory");
+ filename = g_strdup_printf ("%s.desktop", display->priv->greeter_session);
+ path = g_build_filename (sessions_dir, filename, NULL);
+ g_free (sessions_dir);
+ g_free (filename);
+ argv = get_session_command (path);
+ g_free (path);
+ if (!argv)
+ return TRUE;
+
+ session_run (display->priv->session, argv);
+
+ return FALSE;
+}
+
+static void
+user_session_stopped_cb (Session *session, Display *display)
+{
+ g_debug ("User session quit");
+
+ g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ g_object_unref (display->priv->session);
+ display->priv->session = NULL;
+
+ /* This display has ended */
+ display_stop (display);
+}
+
+static void
+prepend_argv (gchar ***argv, const gchar *value)
+{
+ gchar **old_argv, **new_argv;
+ gint i;
+
+ old_argv = *argv;
+ new_argv = g_malloc (sizeof (gchar *) * (g_strv_length (*argv) + 2));
+ new_argv[0] = g_strdup (value);
+ for (i = 0; old_argv[i]; i++)
+ new_argv[i + 1] = old_argv[i];
+ new_argv[i + 1] = NULL;
+
+ g_free (*argv);
+ *argv = new_argv;
}
static gboolean
display_start_session (Display *display)
{
- if (!session_start (SESSION (display->priv->session)))
+ User *user;
+ gchar *filename, *sessions_dir, *path;
+ gchar **argv;
+
+ user = session_get_user (display->priv->session);
+
+ /* Store this session name so we automatically use it next time */
+ user_set_xsession (user, display->priv->user_session);
+
+ /* Find the command to run for the selected session */
+ // FIXME: This is X specific, move into xsession.c
+ sessions_dir = config_get_string (config_get_instance (), "LightDM", "xsessions-directory");
+ filename = g_strdup_printf ("%s.desktop", display->priv->user_session);
+ path = g_build_filename (sessions_dir, filename, NULL);
+ g_free (sessions_dir);
+ g_free (filename);
+ argv = get_session_command (path);
+ g_free (path);
+ if (!argv)
return TRUE;
+
+ session_set_env (display->priv->session, "DESKTOP_SESSION", display->priv->user_session); // FIXME: Apparently deprecated?
+ session_set_env (display->priv->session, "GDMSESSION", display->priv->user_session); // FIXME: Not cross-desktop
+
+ /* If configured, run sessions through a wrapper */
+ if (display->priv->session_wrapper)
+ {
+ gchar *wrapper = g_find_program_in_path (display->priv->session_wrapper);
+ if (wrapper)
+ prepend_argv (&argv, wrapper);
+ else
+ g_warning ("Session wrapper %s not in the path", display->priv->session_wrapper);
+ g_free (wrapper);
+ }
+
+ /* Run a guest session through the wrapper covered by MAC */
+ if (display->priv->autologin_guest)
+ {
+ gchar *wrapper = g_build_filename (PKGLIBEXEC_DIR, "lightdm-guest-session-wrapper", NULL);
+ g_debug ("Running guest session through wrapper: %s", wrapper);
+ prepend_argv (&argv, wrapper);
+ g_free (wrapper);
+ }
+
+ g_debug ("Starting session %s as user %s", display->priv->user_session, session_get_username (display->priv->session));
+
+ session_run (display->priv->session, argv);
+ g_strfreev (argv);
// FIXME: Wait for session to indicate it is ready (maybe)
display_set_is_ready (display);
@@ -769,8 +737,7 @@ display_server_stopped_cb (DisplayServer *server, Display *display)
static void
display_server_ready_cb (DisplayServer *display_server, Display *display)
{
- gboolean result;
- gboolean started_session = FALSE;
+ gboolean result = FALSE;
g_signal_emit (display, signals[DISPLAY_SERVER_READY], 0, &result);
if (!result)
@@ -783,45 +750,33 @@ display_server_ready_cb (DisplayServer *display_server, Display *display)
if (!display_server_get_start_local_sessions (display_server))
return;
- /* Automatically log in */
+ /* Automatically start requested user session */
+ result = FALSE;
if (display->priv->autologin_guest)
{
g_debug ("Automatically logging in as guest");
- started_session = autologin_guest (display, display->priv->pam_autologin_service, TRUE);
- if (!started_session)
- g_debug ("Failed to autologin as guest");
+ result = autologin_guest (display, display->priv->pam_autologin_service, TRUE);
}
else if (display->priv->autologin_user)
{
g_debug ("Automatically logging in user %s", display->priv->autologin_user);
- started_session = autologin (display, display->priv->autologin_user, display->priv->pam_autologin_service, TRUE);
- if (!started_session)
- g_debug ("Failed to autologin user %s", display->priv->autologin_user);
+ result = autologin (display, display->priv->autologin_user, display->priv->pam_autologin_service, TRUE);
}
else if (display->priv->select_user_hint)
{
g_debug ("Logging in user %s", display->priv->select_user_hint);
- started_session = autologin (display, display->priv->select_user_hint, display->priv->pam_service, TRUE);
- if (!started_session)
- g_debug ("Failed to login user %s", display->priv->select_user_hint);
- }
- else if (display->priv->select_guest_hint)
- {
- g_debug ("Logging in as guest");
- started_session = autologin_guest (display, display->priv->pam_service, TRUE);
- if (!started_session)
- g_debug ("Failed login as guest");
+ result = autologin (display, display->priv->select_user_hint, display->priv->pam_service, TRUE);
}
- /* Finally start a greeter */
- if (!started_session)
+ /* If no session started, start a greeter */
+ if (!result)
{
- started_session = start_greeter_session (display);
- if (!started_session)
- g_debug ("Failed to start greeter");
+ g_debug ("Starting greeter");
+ result = start_greeter (display);
}
- if (!started_session)
+ /* If nothing started, then the display can't work */
+ if (!result)
display_stop (display);
}
@@ -948,15 +903,24 @@ display_finalize (GObject *object)
self = DISPLAY (object);
if (self->priv->display_server)
+ {
+ g_signal_handlers_disconnect_matched (self->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_object_unref (self->priv->display_server);
+ }
g_free (self->priv->greeter_session);
if (self->priv->greeter)
+ {
+ g_signal_handlers_disconnect_matched (self->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_object_unref (self->priv->greeter);
+ }
g_free (self->priv->session_wrapper);
g_free (self->priv->pam_service);
g_free (self->priv->pam_autologin_service);
if (self->priv->session)
+ {
+ g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_object_unref (self->priv->session);
+ }
g_free (self->priv->autologin_user);
g_free (self->priv->select_user_hint);
g_free (self->priv->user_session);
diff --git a/src/greeter.c b/src/greeter.c
index 10fc31fb..434a6bd3 100644
--- a/src/greeter.c
+++ b/src/greeter.c
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include "greeter.h"
#include "ldm-marshal.h"
@@ -31,6 +32,9 @@ struct GreeterPrivate
/* Session running on */
Session *session;
+ /* PAM service to authenticate with */
+ gchar *pam_service;
+
/* Buffer for data read from greeter */
guint8 *read_buffer;
gsize n_read;
@@ -45,7 +49,10 @@ struct GreeterPrivate
guint32 authentication_sequence_number;
/* PAM session being constructed by the greeter */
- PAMSession *authentication;
+ Session *authentication_session;
+
+ /* TRUE if a user has been authenticated and the session requested to start */
+ gboolean start_session;
/* TRUE if can log into guest accounts */
gboolean allow_guest;
@@ -54,6 +61,8 @@ struct GreeterPrivate
gboolean guest_account_authenticated;
/* Communication channels to communicate with */
+ int to_greeter_pipe[2];
+ int from_greeter_pipe[2];
GIOChannel *to_greeter_channel;
GIOChannel *from_greeter_channel;
};
@@ -81,12 +90,42 @@ typedef enum
SERVER_MESSAGE_SESSION_RESULT
} ServerMessage;
+static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data);
+
Greeter *
-greeter_new (Session *session)
+greeter_new (Session *session, const gchar *pam_service)
{
- Greeter *greeter = g_object_new (GREETER_TYPE, NULL);
+ gchar *value;
+ Greeter *greeter;
+ greeter = g_object_new (GREETER_TYPE, NULL);
greeter->priv->session = g_object_ref (session);
+ greeter->priv->pam_service = g_strdup (pam_service);
+
+ /* Create a pipe to talk with the greeter */
+ if (pipe (greeter->priv->to_greeter_pipe) != 0 || pipe (greeter->priv->from_greeter_pipe) != 0)
+ {
+ g_warning ("Failed to create pipes: %s", strerror (errno));
+ //return;
+ }
+ greeter->priv->to_greeter_channel = g_io_channel_unix_new (greeter->priv->to_greeter_pipe[1]);
+ g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
+ greeter->priv->from_greeter_channel = g_io_channel_unix_new (greeter->priv->from_greeter_pipe[0]);
+ g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
+ g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
+ g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
+
+ /* Let the greeter session know how to communicate with the daemon */
+ value = g_strdup_printf ("%d", greeter->priv->from_greeter_pipe[1]);
+ session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
+ g_free (value);
+ value = g_strdup_printf ("%d", greeter->priv->to_greeter_pipe[0]);
+ session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
+ g_free (value);
+
+ /* Don't allow the daemon end of the pipes to be accessed in child processes */
+ fcntl (greeter->priv->to_greeter_pipe[1], F_SETFD, FD_CLOEXEC);
+ fcntl (greeter->priv->from_greeter_pipe[0], F_SETFD, FD_CLOEXEC);
return greeter;
}
@@ -115,15 +154,12 @@ int_length ()
static void
write_message (Greeter *greeter, guint8 *message, gsize message_length)
{
- GIOStatus status;
GError *error = NULL;
- status = g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
+ g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
if (error)
g_warning ("Error writing to greeter: %s", error->message);
g_clear_error (&error);
- if (status == G_IO_STATUS_NORMAL)
- g_debug ("Wrote %zi bytes to greeter", message_length);
g_io_channel_flush (greeter->priv->to_greeter_channel, NULL);
}
@@ -204,30 +240,35 @@ handle_connect (Greeter *greeter, const gchar *version)
}
static void
-pam_messages_cb (PAMSession *authentication, int num_msg, const struct pam_message **msg, Greeter *greeter)
+pam_messages_cb (Session *session, Greeter *greeter)
{
int i;
guint32 size;
guint8 message[MAX_MESSAGE_LENGTH];
+ const struct pam_message *messages;
+ int messages_length;
gsize offset = 0;
int n_prompts = 0;
+ messages = session_get_messages (session);
+ messages_length = session_get_messages_length (session);
+
/* Respond to d-bus query with messages */
- g_debug ("Prompt greeter with %d message(s)", num_msg);
- size = int_length () + string_length (pam_session_get_username (authentication)) + int_length ();
- for (i = 0; i < num_msg; i++)
- size += int_length () + string_length (msg[i]->msg);
+ g_debug ("Prompt greeter with %d message(s)", messages_length);
+ size = int_length () + string_length (session_get_username (session)) + int_length ();
+ for (i = 0; i < messages_length; i++)
+ size += int_length () + string_length (messages[i].msg);
write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
- write_string (message, MAX_MESSAGE_LENGTH, pam_session_get_username (authentication), &offset);
- write_int (message, MAX_MESSAGE_LENGTH, num_msg, &offset);
- for (i = 0; i < num_msg; i++)
+ write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, messages_length, &offset);
+ for (i = 0; i < messages_length; i++)
{
- write_int (message, MAX_MESSAGE_LENGTH, msg[i]->msg_style, &offset);
- write_string (message, MAX_MESSAGE_LENGTH, msg[i]->msg, &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, messages[i].msg_style, &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, messages[i].msg, &offset);
- if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
+ if (messages[i].msg_style == PAM_PROMPT_ECHO_OFF || messages[i].msg_style == PAM_PROMPT_ECHO_ON)
n_prompts++;
}
write_message (greeter, message, offset);
@@ -237,8 +278,8 @@ pam_messages_cb (PAMSession *authentication, int num_msg, const struct pam_messa
if (n_prompts == 0)
{
struct pam_response *response;
- response = calloc (num_msg, sizeof (struct pam_response));
- pam_session_respond (greeter->priv->authentication, response);
+ response = calloc (messages_length, sizeof (struct pam_response));
+ session_respond (greeter->priv->authentication_session, response);
}
}
@@ -256,33 +297,36 @@ send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar
}
static void
-authentication_result_cb (PAMSession *authentication, int result, Greeter *greeter)
+authentication_complete_cb (Session *session, Greeter *greeter)
{
- g_debug ("Authenticate result for user %s: %s", pam_session_get_username (authentication), pam_session_strerror (authentication, result));
+ int result;
+
+ g_debug ("Authenticate result for user %s: %s", session_get_username (session), session_get_authentication_result_string (session));
- if (result == PAM_SUCCESS)
+ result = session_get_authentication_result (session);
+ if (session_get_is_authenticated (session))
{
- if (pam_session_get_user (authentication))
- g_debug ("User %s authorized", pam_session_get_username (authentication));
+ if (session_get_user (session))
+ g_debug ("User %s authorized", session_get_username (session));
else
{
- g_debug ("User %s authorized, but no account of that name exists", pam_session_get_username (authentication));
+ g_debug ("User %s authorized, but no account of that name exists", session_get_username (session));
result = PAM_USER_UNKNOWN;
}
}
- send_end_authentication (greeter, greeter->priv->authentication_sequence_number, pam_session_get_username (authentication), result);
+ send_end_authentication (greeter, greeter->priv->authentication_sequence_number, session_get_username (session), result);
}
static void
reset_session (Greeter *greeter)
{
- if (greeter->priv->authentication)
+ if (greeter->priv->authentication_session)
{
- g_signal_handlers_disconnect_matched (greeter->priv->authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
- pam_session_cancel (greeter->priv->authentication);
- g_object_unref (greeter->priv->authentication);
- greeter->priv->authentication = NULL;
+ g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
+ session_stop (greeter->priv->authentication_session);
+ g_object_unref (greeter->priv->authentication_session);
+ greeter->priv->authentication_session = NULL;
}
greeter->priv->guest_account_authenticated = FALSE;
@@ -291,9 +335,6 @@ reset_session (Greeter *greeter)
static void
handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
{
- gboolean result;
- GError *error = NULL;
-
if (username[0] == '\0')
{
g_debug ("Greeter start authentication");
@@ -305,25 +346,18 @@ handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
reset_session (greeter);
greeter->priv->authentication_sequence_number = sequence_number;
- g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication);
- if (!greeter->priv->authentication)
+ g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
+ if (!greeter->priv->authentication_session)
{
send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
return;
}
- g_signal_connect (G_OBJECT (greeter->priv->authentication), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
- g_signal_connect (G_OBJECT (greeter->priv->authentication), "authentication-result", G_CALLBACK (authentication_result_cb), greeter);
+ g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
+ g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
- pam_session_set_item (greeter->priv->authentication, PAM_TTY,
- session_get_env (greeter->priv->session, "DISPLAY"));
-
- result = pam_session_authenticate (greeter->priv->authentication, &error);
- if (error)
- g_debug ("Failed to start authentication: %s", error->message);
- if (!result)
- send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR);
- g_clear_error (&error);
+ /* Run the session process */
+ session_start (greeter->priv->authentication_session, greeter->priv->pam_service, username, TRUE, TRUE);
}
static void
@@ -347,38 +381,38 @@ handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
static void
handle_continue_authentication (Greeter *greeter, gchar **secrets)
{
- int num_messages;
- const struct pam_message **messages;
+ int messages_length;
+ const struct pam_message *messages;
struct pam_response *response;
int i, j, n_prompts = 0;
/* Not in authentication */
- if (greeter->priv->authentication == NULL)
+ if (greeter->priv->authentication_session == NULL)
return;
- num_messages = pam_session_get_num_messages (greeter->priv->authentication);
- messages = pam_session_get_messages (greeter->priv->authentication);
+ messages_length = session_get_messages_length (greeter->priv->authentication_session);
+ messages = session_get_messages (greeter->priv->authentication_session);
/* Check correct number of responses */
- for (i = 0; i < num_messages; i++)
+ for (i = 0; i < messages_length; i++)
{
- int msg_style = messages[i]->msg_style;
+ int msg_style = messages[i].msg_style;
if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
n_prompts++;
}
if (g_strv_length (secrets) != n_prompts)
{
- pam_session_cancel (greeter->priv->authentication);
+ session_respond_error (greeter->priv->authentication_session, PAM_CONV_ERR);
return;
}
g_debug ("Continue authentication");
/* Build response */
- response = calloc (num_messages, sizeof (struct pam_response));
- for (i = 0, j = 0; i < num_messages; i++)
+ response = calloc (messages_length, sizeof (struct pam_response));
+ for (i = 0, j = 0; i < messages_length; i++)
{
- int msg_style = messages[i]->msg_style;
+ int msg_style = messages[i].msg_style;
if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
{
response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
@@ -386,19 +420,18 @@ handle_continue_authentication (Greeter *greeter, gchar **secrets)
}
}
- pam_session_respond (greeter->priv->authentication, response);
+ session_respond (greeter->priv->authentication_session, response);
}
static void
handle_cancel_authentication (Greeter *greeter)
{
/* Not in authentication */
- if (greeter->priv->authentication == NULL)
+ if (greeter->priv->authentication_session == NULL)
return;
g_debug ("Cancel authentication");
-
- pam_session_cancel (greeter->priv->authentication);
+ reset_session (greeter);
}
static void
@@ -411,12 +444,13 @@ handle_start_session (Greeter *greeter, const gchar *session)
if (strcmp (session, "") == 0)
session = NULL;
- if (greeter->priv->guest_account_authenticated || pam_session_get_is_authenticated (greeter->priv->authentication))
+ if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session))
{
if (session)
g_debug ("Greeter requests session %s", session);
else
- g_debug ("Greeter requests default session");
+ g_debug ("Greeter requests default session");
+ greeter->priv->start_session = TRUE;
g_signal_emit (greeter, signals[START_SESSION], 0, session, &result);
}
else
@@ -435,7 +469,7 @@ handle_set_language (Greeter *greeter, const gchar *language)
{
User *user;
- if (!greeter->priv->guest_account_authenticated && !pam_session_get_is_authenticated (greeter->priv->authentication))
+ if (!greeter->priv->guest_account_authenticated && !session_get_is_authenticated (greeter->priv->authentication_session))
{
g_debug ("Ignoring set language request, user is not authorized");
return;
@@ -449,7 +483,7 @@ handle_set_language (Greeter *greeter, const gchar *language)
}
g_debug ("Greeter sets language %s", language);
- user = pam_session_get_user (greeter->priv->authentication);
+ user = session_get_user (greeter->priv->authentication_session);
user_set_language (user, language);
}
@@ -526,11 +560,6 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
if (status != G_IO_STATUS_NORMAL)
return TRUE;
- g_debug ("Read %zi bytes from greeter", n_read);
- /*for (i = 0; i < n_read; i++)
- g_print ("%02X ", greeter->priv->read_buffer[greeter->priv->n_read+i]);
- g_print ("\n");*/
-
greeter->priv->n_read += n_read;
if (greeter->priv->n_read != n_to_read)
return TRUE;
@@ -601,54 +630,27 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
}
gboolean
-greeter_start (Greeter *greeter)
-{
- int to_greeter_pipe[2], from_greeter_pipe[2];
- gint fd;
- gchar *value;
-
- if (pipe (to_greeter_pipe) != 0 ||
- pipe (from_greeter_pipe) != 0)
- {
- g_warning ("Failed to create pipes: %s", strerror (errno));
- return FALSE;
- }
-
- greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]);
- g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
- greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]);
- g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
- g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
- g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
-
- fd = from_greeter_pipe[1];
- value = g_strdup_printf ("%d", fd);
- session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
- g_free (value);
-
- fd = to_greeter_pipe[0];
- value = g_strdup_printf ("%d", fd);
- session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
- g_free (value);
-
- return TRUE;
-}
-
-gboolean
greeter_get_guest_authenticated (Greeter *greeter)
{
g_return_val_if_fail (greeter != NULL, FALSE);
return greeter->priv->guest_account_authenticated;
}
-PAMSession *
-greeter_get_authentication (Greeter *greeter)
+Session *
+greeter_get_authentication_session (Greeter *greeter)
{
g_return_val_if_fail (greeter != NULL, NULL);
- return greeter->priv->authentication;
+ return greeter->priv->authentication_session;
+}
+
+gboolean
+greeter_get_start_session (Greeter *greeter)
+{
+ g_return_val_if_fail (greeter != NULL, FALSE);
+ return greeter->priv->start_session;
}
-static PAMSession *
+static Session *
greeter_real_start_authentication (Greeter *greeter, const gchar *username)
{
return NULL;
@@ -675,14 +677,15 @@ greeter_finalize (GObject *object)
self = GREETER (object);
+ g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_object_unref (self->priv->session);
+ g_free (self->priv->pam_service);
g_free (self->priv->read_buffer);
g_hash_table_unref (self->priv->hints);
- if (self->priv->authentication)
+ if (self->priv->authentication_session)
{
- g_signal_handlers_disconnect_matched (self->priv->authentication, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
- pam_session_cancel (self->priv->authentication);
- g_object_unref (self->priv->authentication);
+ g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
+ g_object_unref (self->priv->authentication_session);
}
if (self->priv->to_greeter_channel)
g_io_channel_unref (self->priv->to_greeter_channel);
@@ -718,7 +721,7 @@ greeter_class_init (GreeterClass *klass)
g_signal_accumulator_first_wins,
NULL,
ldm_marshal_OBJECT__STRING,
- PAM_SESSION_TYPE, 1, G_TYPE_STRING);
+ SESSION_TYPE, 1, G_TYPE_STRING);
signals[START_SESSION] =
g_signal_new ("start-session",
diff --git a/src/greeter.h b/src/greeter.h
index 4694698e..56eea002 100644
--- a/src/greeter.h
+++ b/src/greeter.h
@@ -13,7 +13,6 @@
#define _GREETER_H_
#include "session.h"
-#include "pam-session.h"
G_BEGIN_DECLS
@@ -32,23 +31,23 @@ typedef struct
{
GObjectClass parent_class;
void (*connected)(Greeter *greeter);
- PAMSession *(*start_authentication)(Greeter *greeter, const gchar *username);
+ Session *(*start_authentication)(Greeter *greeter, const gchar *username);
gboolean (*start_session)(Greeter *greeter, const gchar *session, gboolean is_guest);
} GreeterClass;
GType greeter_get_type (void);
-Greeter *greeter_new (Session *session);
+Greeter *greeter_new (Session *session, const gchar *pam_service);
void greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest);
void greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value);
-gboolean greeter_start (Greeter *greeter);
-
gboolean greeter_get_guest_authenticated (Greeter *greeter);
-PAMSession *greeter_get_authentication (Greeter *greeter);
+Session *greeter_get_authentication_session (Greeter *greeter);
+
+gboolean greeter_get_start_session (Greeter *greeter);
G_END_DECLS
diff --git a/src/lightdm.c b/src/lightdm.c
index c853650a..4bc5c0c1 100644
--- a/src/lightdm.c
+++ b/src/lightdm.c
@@ -27,8 +27,8 @@
#include "seat-xdmcp-session.h"
#include "seat-xvnc.h"
#include "xserver.h"
-#include "pam-session.h"
#include "process.h"
+#include "session-child.h"
static gchar *config_path = NULL;
static GMainLoop *loop = NULL;
@@ -463,7 +463,7 @@ handle_session_get_property (GDBusConnection *connection,
if (g_strcmp0 (property_name, "Seat") == 0)
return g_variant_new_object_path (entry ? entry->parent_path : "");
else if (g_strcmp0 (property_name, "UserName") == 0)
- return g_variant_new_string (user_get_name (session_get_user (session)));
+ return g_variant_new_string (session_get_username (session));
return NULL;
}
@@ -486,7 +486,7 @@ handle_session_call (GDBusConnection *connection,
seat = get_seat_for_session (session);
/* FIXME: Should only allow locks if have a session on this seat */
- seat_lock (seat, user_get_name (session_get_user (session)));
+ seat_lock (seat, session_get_username (session));
g_dbus_method_invocation_return_value (invocation, NULL);
}
}
@@ -534,13 +534,13 @@ start_session_cb (Display *display, Seat *seat)
session = display_get_session (display);
+ /* Set environment variables when session runs */
seat_entry = g_hash_table_lookup (seat_bus_entries, seat);
session_set_env (session, "XDG_SEAT_PATH", seat_entry->path);
-
path = g_strdup_printf ("/org/freedesktop/DisplayManager/Session%d", session_index);
session_index++;
session_set_env (session, "XDG_SESSION_PATH", path);
- g_free (path);
+ g_object_set_data_full (G_OBJECT (session), "XDG_SESSION_PATH", path, g_free);
return FALSE;
}
@@ -568,7 +568,7 @@ session_started_cb (Display *display, Seat *seat)
g_signal_connect (session, "stopped", G_CALLBACK (session_stopped_cb), seat);
seat_entry = g_hash_table_lookup (seat_bus_entries, seat);
- entry = bus_entry_new (session_get_env (session, "XDG_SESSION_PATH"), seat_entry ? seat_entry->path : NULL, "SessionRemoved");
+ entry = bus_entry_new (g_object_get_data (G_OBJECT (session), "XDG_SESSION_PATH"), seat_entry ? seat_entry->path : NULL, "SessionRemoved");
g_hash_table_insert (session_bus_entries, g_object_ref (session), entry);
g_debug ("Registering session with bus path %s", entry->path);
@@ -860,6 +860,10 @@ main (int argc, char **argv)
};
GError *error = NULL;
+ /* When lightdm starts sessions it needs to run itself in a new mode */
+ if (argc >= 2 && strcmp (argv[1], "--session-child") == 0)
+ return session_child_run (argc, argv);
+
g_type_init ();
loop = g_main_loop_new (NULL, FALSE);
diff --git a/src/pam-session.c b/src/pam-session.c
deleted file mode 100644
index 9dead913..00000000
--- a/src/pam-session.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2010-2011 Robert Ancell.
- * Author: Robert Ancell <robert.ancell@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
- * license.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "ldm-marshal.h"
-#include "pam-session.h"
-
-enum {
- AUTHENTICATION_STARTED,
- GOT_MESSAGES,
- AUTHENTICATION_RESULT,
- LAST_SIGNAL
-};
-static guint signals[LAST_SIGNAL] = { 0 };
-
-struct PAMSessionPrivate
-{
- /* Service to authenticate against */
- gchar *service;
-
- /* User being authenticated */
- User *user;
-
- /* TRUE if can handle provide interaction with PAM */
- gboolean interactive;
-
- /* Authentication thread */
- GThread *authentication_thread;
-
- /* TRUE if the thread is being intentionally stopped */
- gboolean stop_thread;
-
- /* Messages requested */
- int num_messages;
- const struct pam_message **messages;
- int authentication_result;
-
- /* Queue to feed responses to the authentication thread */
- GAsyncQueue *authentication_response_queue;
-
- /* Authentication handle */
- pam_handle_t *pam_handle;
-
- /* TRUE if in an authentication */
- gboolean in_authentication;
-
- /* TRUE if is authenticated */
- gboolean is_authenticated;
-
- /* TRUE if in a session */
- gboolean in_session;
-};
-
-G_DEFINE_TYPE (PAMSession, pam_session, G_TYPE_OBJECT);
-
-static int pam_conv_cb (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *app_data);
-
-PAMSession *
-pam_session_new (const gchar *service, const gchar *username)
-{
- PAMSession *self = g_object_new (PAM_SESSION_TYPE, NULL);
- struct pam_conv conversation = { pam_conv_cb, self };
- int result;
-
- self->priv->service = g_strdup (service);
-
- result = pam_start (self->priv->service, username, &conversation, &self->priv->pam_handle);
- g_debug ("pam_start(\"%s\", \"%s\") -> (%p, %d)",
- self->priv->service,
- username,
- self->priv->pam_handle,
- result);
-
- return self;
-}
-
-void
-pam_session_set_interactive (PAMSession *session, gboolean interactive)
-{
- g_return_if_fail (session != NULL);
- session->priv->interactive = interactive;
-}
-
-gboolean
-pam_session_get_interactive (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, FALSE);
- return session->priv->interactive;
-}
-
-gboolean
-pam_session_get_is_authenticated (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, FALSE);
- return session->priv->is_authenticated;
-}
-
-gboolean
-pam_session_set_item (PAMSession *session, int item_type, const gchar *value)
-{
- int result = PAM_SUCCESS;
-
- g_return_val_if_fail (session != NULL, FALSE);
- g_return_val_if_fail (value != NULL, FALSE);
-
- result = pam_set_item (session->priv->pam_handle, item_type, value);
- g_debug ("pam_set_item(%p, %d, \"%s\") -> %d (%s)",
- session->priv->pam_handle,
- item_type,
- value,
- result,
- pam_strerror (session->priv->pam_handle, result));
-
- return result == PAM_SUCCESS;
-}
-
-gboolean
-pam_session_open (PAMSession *session)
-{
- int result = PAM_SUCCESS;
-
- g_return_val_if_fail (session != NULL, FALSE);
-
- session->priv->in_session = TRUE;
-
- if (getuid () == 0)
- {
- result = pam_open_session (session->priv->pam_handle, 0);
- g_debug ("pam_open_session(%p, 0) -> %d (%s)",
- session->priv->pam_handle,
- result,
- pam_strerror (session->priv->pam_handle, result));
- }
-
- return result == PAM_SUCCESS;
-}
-
-gboolean
-pam_session_setup (PAMSession *session)
-{
- int result;
-
- result = pam_setcred (session->priv->pam_handle, PAM_ESTABLISH_CRED);
- g_debug ("pam_setcred(%p, PAM_ESTABLISH_CRED) -> %d (%s)",
- session->priv->pam_handle,
- result,
- pam_strerror (session->priv->pam_handle, result));
-
- return result == PAM_SUCCESS;
-}
-
-gboolean
-pam_session_get_in_session (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, FALSE);
- return session->priv->in_session;
-}
-
-static gboolean
-notify_messages_cb (gpointer data)
-{
- PAMSession *session = data;
-
- g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0, session->priv->num_messages, session->priv->messages);
-
- return FALSE;
-}
-
-static int
-pam_conv_cb (int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *app_data)
-{
- PAMSession *session = app_data;
- struct pam_response *response;
-
- /* For some reason after cancelling we still end up here so check for stop as well */
- if (session->priv->stop_thread)
- return PAM_CONV_ERR;
-
- /* If not interactive then fail the authentication */
- if (!session->priv->interactive)
- return PAM_CONV_ERR;
-
- /* Notify user */
- session->priv->num_messages = num_msg;
- session->priv->messages = msg;
- g_idle_add (notify_messages_cb, session);
-
- /* Wait for response */
- response = g_async_queue_pop (session->priv->authentication_response_queue);
- session->priv->num_messages = 0;
- session->priv->messages = NULL;
-
- /* Cancelled by user */
- if (session->priv->stop_thread)
- return PAM_CONV_ERR;
-
- *resp = response;
-
- return PAM_SUCCESS;
-}
-
-static void
-report_result (PAMSession *session, int result)
-{
- session->priv->in_authentication = FALSE;
- session->priv->is_authenticated = result == PAM_SUCCESS;
- g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_RESULT], 0, result);
-}
-
-static gboolean
-notify_auth_complete_cb (gpointer data)
-{
- PAMSession *session = data;
- int result;
-
- result = session->priv->authentication_result;
- session->priv->authentication_result = 0;
-
- g_thread_join (session->priv->authentication_thread);
- session->priv->authentication_thread = NULL;
- g_async_queue_unref (session->priv->authentication_response_queue);
- session->priv->authentication_response_queue = NULL;
-
- report_result (session, result);
-
- /* Authentication was cancelled */
- if (session->priv->stop_thread)
- pam_session_cancel (session);
-
- /* The thread is complete, drop the reference */
- g_object_unref (session);
-
- return FALSE;
-}
-
-static gpointer
-authenticate_cb (gpointer data)
-{
- PAMSession *session = data;
-
- session->priv->authentication_result = pam_authenticate (session->priv->pam_handle, 0);
- g_debug ("pam_authenticate(%p, 0) -> %d (%s)",
- session->priv->pam_handle,
- session->priv->authentication_result,
- pam_strerror (session->priv->pam_handle, session->priv->authentication_result));
-
- if (session->priv->authentication_result == PAM_SUCCESS)
- {
- session->priv->authentication_result = pam_acct_mgmt (session->priv->pam_handle, 0);
- g_debug ("pam_acct_mgmt(%p, 0) -> %d (%s)",
- session->priv->pam_handle,
- session->priv->authentication_result,
- pam_strerror (session->priv->pam_handle, session->priv->authentication_result));
-
- if (session->priv->authentication_result == PAM_NEW_AUTHTOK_REQD)
- {
- session->priv->authentication_result = pam_chauthtok (session->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
- g_debug ("pam_chauthtok(%p, PAM_CHANGE_EXPIRED_AUTHTOK) -> %d (%s)",
- session->priv->pam_handle,
- session->priv->authentication_result,
- pam_strerror (session->priv->pam_handle, session->priv->authentication_result));
- }
- }
-
- /* Notify user */
- g_idle_add (notify_auth_complete_cb, session);
-
- return NULL;
-}
-
-gboolean
-pam_session_authenticate (PAMSession *session, GError **error)
-{
- g_return_val_if_fail (session != NULL, FALSE);
- g_return_val_if_fail (session->priv->in_authentication == FALSE, FALSE);
- g_return_val_if_fail (session->priv->is_authenticated == FALSE, FALSE);
-
- session->priv->in_authentication = TRUE;
- g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_STARTED], 0);
-
- /* Hold a reference to this object while the thread may access it */
- g_object_ref (session);
-
- /* Start thread */
- session->priv->authentication_response_queue = g_async_queue_new ();
- session->priv->authentication_thread = g_thread_create (authenticate_cb, session, TRUE, error);
- if (!session->priv->authentication_thread)
- return FALSE;
-
- return TRUE;
-}
-
-const gchar *
-pam_session_strerror (PAMSession *session, int error)
-{
- g_return_val_if_fail (session != NULL, NULL);
- return pam_strerror (session->priv->pam_handle, error);
-}
-
-const gchar *
-pam_session_get_username (PAMSession *session)
-{
- const char *username;
- g_return_val_if_fail (session != NULL, NULL);
- pam_get_item (session->priv->pam_handle, PAM_USER, (const void **) &username);
- return username;
-}
-
-User *
-pam_session_get_user (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, NULL);
-
- if (!session->priv->user && pam_session_get_username (session))
- session->priv->user = accounts_get_user_by_name (pam_session_get_username (session));
-
- return session->priv->user;
-}
-
-const struct pam_message **
-pam_session_get_messages (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, NULL);
- return session->priv->messages;
-}
-
-gint
-pam_session_get_num_messages (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, 0);
- return session->priv->num_messages;
-}
-
-void
-pam_session_respond (PAMSession *session, struct pam_response *response)
-{
- g_return_if_fail (session != NULL);
- g_return_if_fail (session->priv->authentication_thread != NULL);
- g_async_queue_push (session->priv->authentication_response_queue, response);
-}
-
-void
-pam_session_cancel (PAMSession *session)
-{
- g_return_if_fail (session != NULL);
-
- /* If authenticating cancel first */
- if (session->priv->authentication_thread)
- {
- session->priv->stop_thread = TRUE;
- g_async_queue_push (session->priv->authentication_response_queue, GINT_TO_POINTER (-1));
- }
-}
-
-const gchar *
-pam_session_getenv (PAMSession *session, const gchar *name)
-{
- g_return_val_if_fail (session != NULL, NULL);
- return pam_getenv (session->priv->pam_handle, name);
-}
-
-gchar **
-pam_session_get_envlist (PAMSession *session)
-{
- g_return_val_if_fail (session != NULL, NULL);
- return pam_getenvlist (session->priv->pam_handle);
-}
-
-void
-pam_session_close (PAMSession *session)
-{
- int result;
-
- g_return_if_fail (session != NULL);
-
- session->priv->in_session = FALSE;
-
- if (getuid () == 0)
- {
- g_return_if_fail (session->priv->pam_handle != NULL);
-
- result = pam_close_session (session->priv->pam_handle, 0);
- g_debug ("pam_close_session(%p) -> %d (%s)",
- session->priv->pam_handle,
- result,
- pam_strerror (session->priv->pam_handle, result));
-
- result = pam_setcred (session->priv->pam_handle, PAM_DELETE_CRED);
- g_debug ("pam_setcred(%p, PAM_DELETE_CRED) -> %d (%s)",
- session->priv->pam_handle,
- result,
- pam_strerror (session->priv->pam_handle, result));
-
- result = pam_end (session->priv->pam_handle, PAM_SUCCESS);
- g_debug ("pam_end(%p) -> %d",
- session->priv->pam_handle,
- result);
-
- session->priv->pam_handle = NULL;
- }
-}
-
-static void
-pam_session_init (PAMSession *session)
-{
- session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, PAM_SESSION_TYPE, PAMSessionPrivate);
- session->priv->interactive = TRUE;
-}
-
-static void
-pam_session_finalize (GObject *object)
-{
- PAMSession *self;
-
- self = PAM_SESSION (object);
-
- g_free (self->priv->service);
- if (self->priv->user)
- g_object_unref (self->priv->user);
- if (self->priv->pam_handle)
- pam_end (self->priv->pam_handle, PAM_SUCCESS);
-
- G_OBJECT_CLASS (pam_session_parent_class)->finalize (object);
-}
-
-static void
-pam_session_class_init (PAMSessionClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = pam_session_finalize;
-
- g_type_class_add_private (klass, sizeof (PAMSessionPrivate));
-
- signals[AUTHENTICATION_STARTED] =
- g_signal_new ("authentication-started",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PAMSessionClass, authentication_started),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- signals[GOT_MESSAGES] =
- g_signal_new ("got-messages",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PAMSessionClass, got_messages),
- NULL, NULL,
- ldm_marshal_VOID__INT_POINTER,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_POINTER);
-
- signals[AUTHENTICATION_RESULT] =
- g_signal_new ("authentication-result",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (PAMSessionClass, authentication_result),
- NULL, NULL,
- g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-}
diff --git a/src/pam-session.h b/src/pam-session.h
deleted file mode 100644
index 2f583696..00000000
--- a/src/pam-session.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2010-2011 Robert Ancell.
- * Author: Robert Ancell <robert.ancell@canonical.com>
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
- * license.
- */
-
-#ifndef _PAM_SESSION_H_
-#define _PAM_SESSION_H_
-
-#include <glib-object.h>
-#include <security/pam_appl.h>
-
-#include "accounts.h"
-
-G_BEGIN_DECLS
-
-#define PAM_SESSION_TYPE (pam_session_get_type())
-#define PAM_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PAM_SESSION_TYPE, PAMSession));
-
-typedef struct PAMSessionPrivate PAMSessionPrivate;
-
-typedef struct
-{
- GObject parent_instance;
- PAMSessionPrivate *priv;
-} PAMSession;
-
-typedef struct
-{
- GObjectClass parent_class;
-
- void (*authentication_started)(PAMSession *pam_session);
- void (*got_messages)(PAMSession *pam_session, int num_msg, const struct pam_message **msg);
- void (*authentication_result)(PAMSession *pam_session, int result);
-} PAMSessionClass;
-
-GType pam_session_get_type (void);
-
-void pam_session_set_use_pam (void);
-
-void pam_session_set_use_passwd_file (gchar *passwd_file);
-
-PAMSession *pam_session_new (const gchar *service, const gchar *username);
-
-void pam_session_set_interactive (PAMSession *session, gboolean interactive);
-
-gboolean pam_session_get_interactive (PAMSession *session);
-
-gboolean pam_session_authenticate (PAMSession *session, GError **error);
-
-gboolean pam_session_get_is_authenticated (PAMSession *session);
-
-gboolean pam_session_set_item (PAMSession *session, int item_type, const gchar *value);
-
-gboolean pam_session_open (PAMSession *session);
-
-gboolean pam_session_setup (PAMSession *session);
-
-gboolean pam_session_get_in_session (PAMSession *session);
-
-const gchar *pam_session_strerror (PAMSession *session, int error);
-
-const gchar *pam_session_get_username (PAMSession *session);
-
-User *pam_session_get_user (PAMSession *session);
-
-const struct pam_message **pam_session_get_messages (PAMSession *session);
-
-gint pam_session_get_num_messages (PAMSession *session);
-
-void pam_session_respond (PAMSession *session, struct pam_response *response);
-
-void pam_session_cancel (PAMSession *session);
-
-const gchar *pam_session_getenv (PAMSession *session, const gchar *name);
-
-gchar **pam_session_get_envlist (PAMSession *session);
-
-void pam_session_close (PAMSession *session);
-
-G_END_DECLS
-
-#endif /* _PAM_SESSION_H_ */
diff --git a/src/seat-xdmcp-session.c b/src/seat-xdmcp-session.c
index 65a95e16..720a3704 100644
--- a/src/seat-xdmcp-session.c
+++ b/src/seat-xdmcp-session.c
@@ -58,9 +58,7 @@ seat_xdmcp_session_create_session (Seat *seat, Display *display)
xserver = XSERVER_REMOTE (display_get_display_server (display));
session = xsession_new (XSERVER (xserver));
- session_set_console_kit_parameter (SESSION (session), "remote-host-name", g_variant_new_string (xserver_get_hostname (XSERVER (xserver))));
- // FIXME: Mark local seats as such
- session_set_console_kit_parameter (SESSION (session), "is-local", g_variant_new_boolean (FALSE));
+ session_set_remote_host_name (SESSION (session), xserver_get_hostname (XSERVER (xserver)));
return SESSION (session);
}
diff --git a/src/seat-xlocal.c b/src/seat-xlocal.c
index 15607ea5..a1fb2e01 100644
--- a/src/seat-xlocal.c
+++ b/src/seat-xlocal.c
@@ -115,9 +115,8 @@ seat_xlocal_create_session (Seat *seat, Display *display)
session = xsession_new (XSERVER (xserver));
tty = g_strdup_printf ("/dev/tty%d", xserver_local_get_vt (xserver));
- session_set_console_kit_parameter (SESSION (session), "x11-display-device", g_variant_new_string (tty));
+ session_set_tty (SESSION (session), tty);
g_free (tty);
- session_set_console_kit_parameter (SESSION (session), "is-local", g_variant_new_boolean (TRUE));
return SESSION (session);
}
diff --git a/src/seat-xremote.c b/src/seat-xremote.c
index d61acc14..252f0cc4 100644
--- a/src/seat-xremote.c
+++ b/src/seat-xremote.c
@@ -53,8 +53,7 @@ seat_xremote_create_session (Seat *seat, Display *display)
xserver = XSERVER_REMOTE (display_get_display_server (display));
session = xsession_new (XSERVER (xserver));
- session_set_console_kit_parameter (SESSION (session), "remote-host-name", g_variant_new_string (xserver_get_hostname (XSERVER (xserver))));
- session_set_console_kit_parameter (SESSION (session), "is-local", g_variant_new_boolean (FALSE));
+ session_set_remote_host_name (SESSION (session), xserver_get_hostname (XSERVER (xserver)));
return SESSION (session);
}
diff --git a/src/seat-xvnc.c b/src/seat-xvnc.c
index de3574ae..eb150c31 100644
--- a/src/seat-xvnc.c
+++ b/src/seat-xvnc.c
@@ -73,9 +73,8 @@ seat_xvnc_create_session (Seat *seat, Display *display)
session = xsession_new (XSERVER (xserver));
address = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (SEAT_XVNC (seat)->priv->connection, NULL));
hostname = g_inet_address_to_string (g_inet_socket_address_get_address (address));
- session_set_console_kit_parameter (SESSION (session), "remote-host-name", g_variant_new_string (hostname));
+ session_set_remote_host_name (SESSION (session), hostname);
g_free (hostname);
- session_set_console_kit_parameter (SESSION (session), "is-local", g_variant_new_boolean (FALSE));
return SESSION (session);
}
diff --git a/src/seat.c b/src/seat.c
index 42b92b23..369aa885 100644
--- a/src/seat.c
+++ b/src/seat.c
@@ -383,7 +383,7 @@ session_stopped_cb (Session *session, Seat *seat)
if (script)
run_script (seat, display, script, session_get_user (session));
- if (seat->priv->guest_username && strcmp (user_get_name (session_get_user (session)), seat->priv->guest_username) == 0)
+ if (seat->priv->guest_username && strcmp (session_get_username (session), seat->priv->guest_username) == 0)
{
guest_account_cleanup (seat->priv->guest_username);
g_free (seat->priv->guest_username);
@@ -429,7 +429,6 @@ display_stopped_cb (Display *display, Seat *seat)
g_object_unref (display);
check_stopped (seat);
-
}
static gboolean
diff --git a/src/seat.h b/src/seat.h
index c5254505..4b4a8d1e 100644
--- a/src/seat.h
+++ b/src/seat.h
@@ -14,6 +14,7 @@
#include <glib-object.h>
#include "display.h"
+#include "process.h"
G_BEGIN_DECLS
diff --git a/src/session-child.c b/src/session-child.c
new file mode 100644
index 00000000..9ea86deb
--- /dev/null
+++ b/src/session-child.c
@@ -0,0 +1,534 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+#include <glib.h>
+#include <security/pam_appl.h>
+
+#include "session-child.h"
+#include "session.h"
+#include "console-kit.h"
+#include "privileges.h"
+#include "xauthority.h"
+
+/* Child process being run */
+static GPid child_pid = 0;
+
+/* Pipe to communicate with daemon */
+static int from_daemon_output = 0;
+static int to_daemon_input = 0;
+
+static gboolean is_interactive;
+static gboolean do_authenticate;
+static pam_handle_t *pam_handle;
+
+/* Maximum length of a string to pass between daemon and session */
+#define MAX_STRING_LENGTH 65535
+
+static void
+write_data (const void *buf, size_t count)
+{
+ if (write (to_daemon_input, buf, count) != count)
+ g_printerr ("Error writing to daemon: %s\n", strerror (errno));
+}
+
+static void
+write_string (const char *value)
+{
+ int length;
+
+ length = value ? strlen (value) : -1;
+ write_data (&length, sizeof (length));
+ if (value)
+ write_data (value, sizeof (char) * length);
+}
+
+static ssize_t
+read_data (void *buf, size_t count)
+{
+ ssize_t n_read;
+
+ n_read = read (from_daemon_output, buf, count);
+ if (n_read < 0)
+ g_printerr ("Error reading from daemon: %s\n", strerror (errno));
+
+ return n_read;
+}
+
+static gchar *
+read_string ()
+{
+ int length;
+ char *value;
+
+ if (read_data (&length, sizeof (length)) <= 0)
+ return NULL;
+ if (length < 0)
+ return NULL;
+ if (length > MAX_STRING_LENGTH)
+ {
+ g_printerr ("Invalid string length %d from daemon\n", length);
+ return NULL;
+ }
+
+ value = g_malloc (sizeof (char) * (length + 1));
+ read_data (value, length);
+ value[length] = '\0';
+
+ return value;
+}
+
+static int
+pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
+{
+ int i, error;
+ gboolean auth_complete = FALSE;
+ gchar *username = NULL;
+
+ /* Cancel authentication if requiring input */
+ if (!is_interactive)
+ {
+ for (i = 0; i < msg_length; i++)
+ {
+ if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
+ {
+ g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
+ return PAM_CONV_ERR;
+ }
+ }
+ }
+
+ /* Check if we changed user */
+ pam_get_item (pam_handle, PAM_USER, (const void **) &username);
+
+ /* Notify the daemon */
+ write_string (username);
+ write_data (&auth_complete, sizeof (auth_complete));
+ write_data (&msg_length, sizeof (msg_length));
+ for (i = 0; i < msg_length; i++)
+ {
+ const struct pam_message *m = msg[i];
+ write_data (&m->msg_style, sizeof (m->msg_style));
+ write_string (m->msg);
+ }
+
+ /* Get response */
+ *resp = calloc (msg_length, sizeof (struct pam_response));
+ read_data (&error, sizeof (error));
+ if (error != PAM_SUCCESS)
+ return error;
+ for (i = 0; i < msg_length; i++)
+ {
+ struct pam_response *r = resp[i];
+ r->resp = read_string ();
+ read_data (&r->resp_retcode, sizeof (r->resp_retcode));
+ }
+
+ return PAM_SUCCESS;
+}
+
+static void
+signal_cb (int signum)
+{
+ /* Pass on signal to child, otherwise just quit */
+ if (child_pid > 0)
+ kill (child_pid, signum);
+ else
+ exit (EXIT_SUCCESS);
+}
+
+int
+session_child_run (int argc, char **argv)
+{
+ struct pam_conv conversation = { pam_conv_cb, NULL };
+ int i, version, fd, result;
+ gboolean auth_complete = TRUE;
+ User *user = NULL;
+ gchar *log_filename;
+ gsize env_length;
+ gsize command_argc;
+ gchar **command_argv;
+ GVariantBuilder ck_parameters;
+ int return_code;
+ int authentication_result;
+ gchar *authentication_result_string;
+ gchar *service;
+ gchar *username;
+ gchar *class;
+ gchar *tty;
+ gchar *remote_host_name;
+ gchar *xdisplay;
+ gchar *xauth_name;
+ XAuthority *xauthority = NULL;
+ gchar *xauth_filename;
+ GDBusConnection *bus;
+ gchar *console_kit_cookie;
+ GError *error = NULL;
+
+ g_type_init ();
+
+ /* Make input non-blocking */
+ fd = open ("/dev/null", O_RDONLY);
+ dup2 (fd, STDIN_FILENO);
+ close (fd);
+
+ /* Close stdout */
+ fd = open ("/dev/null", O_WRONLY);
+ dup2 (fd, STDOUT_FILENO);
+ close (fd);
+
+ /* Get the pipe from the daemon */
+ if (argc != 4)
+ {
+ g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
+ return EXIT_FAILURE;
+ }
+ from_daemon_output = atoi (argv[2]);
+ to_daemon_input = atoi (argv[3]);
+ if (from_daemon_output == 0 || to_daemon_input == 0)
+ {
+ g_printerr ("Invalid LIGHTDM_DAEMON_PIPE\n");
+ return EXIT_FAILURE;
+ }
+ g_unsetenv ("LIGHTDM_DAEMON_PIPE");
+
+ /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
+ read_data (&version, sizeof (version));
+
+ service = read_string ();
+ username = read_string ();
+ read_data (&do_authenticate, sizeof (do_authenticate));
+ read_data (&is_interactive, sizeof (is_interactive));
+ class = read_string ();
+ tty = read_string ();
+ remote_host_name = read_string ();
+ xdisplay = read_string ();
+ xauth_name = read_string ();
+ if (xauth_name)
+ {
+ guint16 xauth_family;
+ guint8 *xauth_address;
+ gsize xauth_address_length;
+ gchar *xauth_number;
+ guint8 *xauth_data;
+ gsize xauth_data_length;
+
+ read_data (&xauth_family, sizeof (xauth_family));
+ read_data (&xauth_address_length, sizeof (xauth_address_length));
+ xauth_address = g_malloc (xauth_address_length);
+ read_data (xauth_address, xauth_address_length);
+ xauth_number = read_string ();
+ read_data (&xauth_data_length, sizeof (xauth_data_length));
+ xauth_data = g_malloc (xauth_data_length);
+ read_data (xauth_data, xauth_data_length);
+
+ xauthority = xauth_new (xauth_family, xauth_address, xauth_address_length, xauth_number, xauth_name, xauth_data, xauth_data_length);
+ }
+
+ /* Setup PAM */
+ result = pam_start (service, username, &conversation, &pam_handle);
+ if (result != PAM_SUCCESS)
+ {
+ g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
+ return EXIT_FAILURE;
+ }
+ if (xdisplay)
+ {
+ pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
+ pam_set_item (pam_handle, PAM_TTY, xdisplay);
+ }
+ else if (tty)
+ pam_set_item (pam_handle, PAM_TTY, tty);
+ if (xauthority)
+ {
+ struct pam_xauth_data value;
+
+ value.name = (char *) xauth_get_authorization_name (xauthority);
+ value.namelen = strlen (xauth_get_authorization_name (xauthority));
+ value.data = (char *) xauth_get_authorization_data (xauthority);
+ value.datalen = xauth_get_authorization_data_length (xauthority);
+ pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
+ }
+
+ /* Authenticate */
+ if (do_authenticate)
+ {
+ const gchar *new_username;
+
+ authentication_result = pam_authenticate (pam_handle, 0);
+
+ /* See what user we ended up as */
+ if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
+ return EXIT_FAILURE;
+ g_free (username);
+ username = g_strdup (new_username);
+
+ /* Check account is valid */
+ if (authentication_result == PAM_SUCCESS)
+ authentication_result = pam_acct_mgmt (pam_handle, 0);
+ if (authentication_result == PAM_NEW_AUTHTOK_REQD)
+ authentication_result = pam_chauthtok (pam_handle, 0);
+ }
+ else
+ authentication_result = PAM_SUCCESS;
+
+ if (authentication_result == PAM_SUCCESS)
+ {
+ /* Fail authentication if user doesn't actually exist */
+ user = accounts_get_user_by_name (username);
+ if (!user)
+ {
+ g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
+ authentication_result = PAM_USER_UNKNOWN;
+ }
+ else
+ {
+ /* Set POSIX variables */
+ pam_putenv (pam_handle, "PATH=/usr/local/bin:/usr/bin:/bin");
+ pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
+ pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
+ pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
+ pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
+ }
+ }
+
+ authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
+
+ /* Report authentication result */
+ write_string (username);
+ write_data (&auth_complete, sizeof (auth_complete));
+ write_data (&authentication_result, sizeof (authentication_result));
+ write_string (authentication_result_string);
+
+ /* Check we got a valid user */
+ if (!username)
+ {
+ g_printerr ("No user selected during authentication\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Stop if we didn't authenticated */
+ if (authentication_result != PAM_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Get the command to run (blocks) */
+ log_filename = read_string ();
+ xauth_filename = read_string ();
+ read_data (&env_length, sizeof (env_length));
+ for (i = 0; i < env_length; i++)
+ pam_putenv (pam_handle, read_string ());
+ read_data (&command_argc, sizeof (command_argc));
+ command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
+ for (i = 0; i < command_argc; i++)
+ command_argv[i] = read_string ();
+ command_argv[i] = NULL;
+
+ /* Redirect stderr to a log file */
+ if (!log_filename)
+ {
+ fd = open ("/dev/null", O_WRONLY);
+ dup2 (fd, STDERR_FILENO);
+ close (fd);
+ }
+ else if (g_path_is_absolute (log_filename))
+ {
+ fd = open (log_filename, O_WRONLY | O_CREAT, 0600);
+ dup2 (fd, STDERR_FILENO);
+ close (fd);
+ }
+
+ /* Set credentials */
+ result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
+
+ /* Open a the session */
+ result = pam_open_session (pam_handle, 0);
+ if (result != PAM_SUCCESS)
+ {
+ g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
+ return EXIT_FAILURE;
+ }
+
+ /* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (error)
+ g_printerr ("Unable to contact system bus: %s", error->message);
+ if (!bus)
+ return EXIT_FAILURE;
+
+ /* Open a Console Kit session */
+ g_variant_builder_init (&ck_parameters, G_VARIANT_TYPE ("(a(sv))"));
+ g_variant_builder_open (&ck_parameters, G_VARIANT_TYPE ("a(sv)"));
+ g_variant_builder_add (&ck_parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
+ if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) == 0)
+ g_variant_builder_add (&ck_parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
+ if (xdisplay)
+ {
+ g_variant_builder_add (&ck_parameters, "(sv)", "x11-display", g_variant_new_string (xdisplay));
+ if (tty)
+ g_variant_builder_add (&ck_parameters, "(sv)", "x11-display-device", g_variant_new_string (tty));
+ }
+ if (remote_host_name)
+ {
+ g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (FALSE));
+ g_variant_builder_add (&ck_parameters, "(sv)", "remote-host-name", g_variant_new_string (remote_host_name));
+ }
+ else
+ g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (TRUE));
+ console_kit_cookie = ck_open_session (&ck_parameters);
+ write_string (console_kit_cookie);
+ if (console_kit_cookie)
+ {
+ gchar *value;
+ value = g_strdup_printf ("XDG_SESSION_COOKIE=%s", console_kit_cookie);
+ pam_putenv (pam_handle, value);
+ g_free (value);
+ }
+
+ /* Write X authority */
+ if (xauthority)
+ {
+ GFile *file;
+ gboolean drop_privileges, result;
+ gchar *value;
+ GError *error = NULL;
+
+ file = g_file_new_for_path (xauth_filename);
+
+ drop_privileges = geteuid () == 0;
+ if (drop_privileges)
+ privileges_drop (user);
+ result = xauth_write (xauthority, XAUTH_WRITE_MODE_REPLACE, file, &error);
+ if (drop_privileges)
+ privileges_reclaim ();
+
+ g_object_unref (file);
+ if (error)
+ g_printerr ("Error writing X authority: %s\n", error->message);
+ g_clear_error (&error);
+ if (!result)
+ return EXIT_FAILURE;
+
+ value = g_strdup_printf ("XAUTHORITY=%s", xauth_filename);
+ pam_putenv (pam_handle, value);
+ g_free (value);
+ }
+
+ /* Catch terminate signal and pass it to the child */
+ signal (SIGTERM, signal_cb);
+
+ /* Run the command as the authenticated user */
+ child_pid = fork ();
+ if (child_pid == 0)
+ {
+ // FIXME: This is not thread safe (particularly the printfs)
+
+ /* Make this process its own session */
+ if (setsid () < 0)
+ g_printerr ("Failed to make process a new session: %s\n", strerror (errno));
+
+ /* Change to this user */
+ if (getuid () == 0)
+ {
+ if (initgroups (username, user_get_gid (user)) < 0)
+ {
+ g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (setgid (user_get_gid (user)) != 0)
+ {
+ g_printerr ("Failed to set group ID to %d: %s\n", user_get_gid (user), strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (setuid (user_get_uid (user)) != 0)
+ {
+ g_printerr ("Failed to set user ID to %d: %s\n", user_get_uid (user), strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ }
+
+ /* Change working directory */
+ /* NOTE: This must be done after the permissions are changed because NFS filesystems can
+ * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
+ * are not system readable then the chdir can fail */
+ if (chdir (user_get_home_directory (user)) != 0)
+ {
+ g_printerr ("Failed to change to home directory %s: %s\n", user_get_home_directory (user), strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ /* Redirect stderr to a log file */
+ if (log_filename && !g_path_is_absolute (log_filename))
+ {
+ fd = open (log_filename, O_WRONLY | O_CREAT, 0600);
+ dup2 (fd, STDERR_FILENO);
+ close (fd);
+ }
+
+ /* Run the command */
+ execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
+ g_printerr ("Failed to run command: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ /* Bail out if failed to fork */
+ if (child_pid < 0)
+ {
+ g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
+ return_code = EXIT_FAILURE;
+ }
+
+ /* Wait for the command to complete (blocks) */
+ if (child_pid > 0)
+ {
+ waitpid (child_pid, &return_code, 0);
+ child_pid = 0;
+ }
+
+ /* Remove X authority */
+ if (xauthority)
+ {
+ GFile *file;
+ gboolean drop_privileges, result;
+ GError *error = NULL;
+
+ file = g_file_new_for_path (xauth_filename);
+
+ drop_privileges = geteuid () == 0;
+ if (drop_privileges)
+ privileges_drop (user);
+ result = xauth_write (xauthority, XAUTH_WRITE_MODE_REMOVE, file, &error);
+ if (drop_privileges)
+ privileges_reclaim ();
+
+ g_object_unref (file);
+ if (error)
+ g_printerr ("Error removing X authority: %s\n", error->message);
+ g_clear_error (&error);
+ if (!result)
+ _exit (EXIT_FAILURE);
+ }
+
+ /* Close the Console Kit session */
+ if (console_kit_cookie)
+ ck_close_session (console_kit_cookie);
+
+ /* Close the session */
+ pam_close_session (pam_handle, 0);
+
+ /* Remove credentials */
+ result = pam_setcred (pam_handle, PAM_DELETE_CRED);
+
+ pam_end (pam_handle, 0);
+ pam_handle = NULL;
+
+ /* Return result of session process to the daemon */
+ return return_code;
+}
diff --git a/src/session-child.h b/src/session-child.h
new file mode 100644
index 00000000..39f32509
--- /dev/null
+++ b/src/session-child.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2010-2011 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#ifndef _SESSION_CHILD_H_
+#define _SESSION_CHILD_H_
+
+int session_child_run (int argc, char **argv);
+
+#endif /* _SESSION_CHILD_H_ */
diff --git a/src/session.c b/src/session.c
index a4bfd2b7..cb300d65 100644
--- a/src/session.c
+++ b/src/session.c
@@ -17,478 +17,600 @@
#include <fcntl.h>
#include <glib/gstdio.h>
#include <grp.h>
+#include <pwd.h>
#include "session.h"
+#include "configuration.h"
#include "console-kit.h"
+enum {
+ GOT_MESSAGES,
+ AUTHENTICATION_COMPLETE,
+ STOPPED,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
struct SessionPrivate
{
- /* File to log to */
- gchar *log_file;
+ /* PID of child process */
+ GPid pid;
+
+ /* Pipes to talk to child */
+ int to_child_input;
+ int from_child_output;
+ GIOChannel *from_child_channel;
+ guint from_child_watch;
+ guint child_watch;
+
+ /* User to authenticate as */
+ gchar *username;
+
+ /* User object that matches the current username */
+ User *user;
- /* TRUE if the log file should be owned by the user */
- gboolean log_file_as_user;
+ /* Messages being requested by PAM */
+ int messages_length;
+ struct pam_message *messages;
- /* Authentication for this session */
- PAMSession *authentication;
+ /* Authentication result from PAM */
+ gboolean authentication_started;
+ gboolean authentication_complete;
+ int authentication_result;
+ gchar *authentication_result_string;
+
+ /* File to log to */
+ gchar *log_filename;
+
+ /* Seat class */
+ gchar *class;
- /* Command to run for this session */
- gchar *command;
+ /* tty this session is running on */
+ gchar *tty;
+
+ /* X display connected to */
+ gchar *xdisplay;
+ XAuthority *xauthority;
+ gboolean xauth_use_system_location;
- /* ConsoleKit parameters for this session */
- GHashTable *console_kit_parameters;
+ /* Remote host this session is being controlled from */
+ gchar *remote_host_name;
- /* ConsoleKit cookie for the session */
+ /* Console kit cookie */
gchar *console_kit_cookie;
- /* TRUE if this is a greeter session */
- gboolean is_greeter;
+ /* Environment to set in child */
+ GList *env;
};
-G_DEFINE_TYPE (Session, session, PROCESS_TYPE);
+/* Maximum length of a string to pass between daemon and session */
+#define MAX_STRING_LENGTH 65535
+
+G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
void
-session_set_log_file (Session *session, const gchar *filename, gboolean as_user)
+session_set_log_file (Session *session, const gchar *filename)
{
g_return_if_fail (session != NULL);
- g_free (session->priv->log_file);
- session->priv->log_file = g_strdup (filename);
- session->priv->log_file_as_user = as_user;
-}
-
-const gchar *
-session_get_log_file (Session *session)
-{
- g_return_val_if_fail (session != NULL, NULL);
- return session->priv->log_file;
+ g_free (session->priv->log_filename);
+ session->priv->log_filename = g_strdup (filename);
}
void
-session_set_authentication (Session *session, PAMSession *authentication)
+session_set_class (Session *session, const gchar *class)
{
g_return_if_fail (session != NULL);
- session->priv->authentication = g_object_ref (authentication);
+ g_free (session->priv->class);
+ session->priv->class = g_strdup (class);
}
-PAMSession *
-session_get_authentication (Session *session)
+void
+session_set_tty (Session *session, const gchar *tty)
{
- g_return_val_if_fail (session != NULL, NULL);
- return session->priv->authentication;
+ g_return_if_fail (session != NULL);
+ g_free (session->priv->tty);
+ session->priv->tty = g_strdup (tty);
}
-User *
-session_get_user (Session *session)
+void
+session_set_xdisplay (Session *session, const gchar *xdisplay)
{
- g_return_val_if_fail (session != NULL, NULL);
- return pam_session_get_user (session->priv->authentication);
+ g_return_if_fail (session != NULL);
+ g_free (session->priv->xdisplay);
+ session->priv->xdisplay = g_strdup (xdisplay);
}
void
-session_set_is_greeter (Session *session, gboolean is_greeter)
+session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
{
g_return_if_fail (session != NULL);
- session->priv->is_greeter = is_greeter;
+ if (session->priv->xauthority)
+ g_object_unref (session->priv->xauthority);
+ session->priv->xauthority = g_object_ref (authority);
+ session->priv->xauth_use_system_location = use_system_location;
}
-gboolean
-session_get_is_greeter (Session *session)
+void
+session_set_remote_host_name (Session *session, const gchar *remote_host_name)
{
- g_return_val_if_fail (session != NULL, FALSE);
- return session->priv->is_greeter;
+ g_return_if_fail (session != NULL);
+ g_free (session->priv->remote_host_name);
+ session->priv->remote_host_name = g_strdup (remote_host_name);
}
void
-session_set_command (Session *session, const gchar *command)
+session_set_env (Session *session, const gchar *name, const gchar *value)
{
g_return_if_fail (session != NULL);
-
- g_free (session->priv->command);
- session->priv->command = g_strdup (command);
+ session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
}
-const gchar *
-session_get_command (Session *session)
+User *
+session_get_user (Session *session)
{
g_return_val_if_fail (session != NULL, NULL);
- return session->priv->command;
-}
-
-static gchar *
-get_absolute_command (const gchar *command)
-{
- gchar **tokens;
- gchar *absolute_binary, *absolute_command = NULL;
-
- tokens = g_strsplit (command, " ", 2);
- absolute_binary = g_find_program_in_path (tokens[0]);
- if (absolute_binary)
- {
- if (tokens[1])
- absolute_command = g_strjoin (" ", absolute_binary, tokens[1], NULL);
- else
- absolute_command = g_strdup (absolute_binary);
- }
- g_free (absolute_binary);
+ if (session->priv->username == NULL)
+ return NULL;
- g_strfreev (tokens);
+ if (!session->priv->user)
+ session->priv->user = accounts_get_user_by_name (session->priv->username);
- return absolute_command;
+ return session->priv->user;
}
static void
-set_env_from_authentication (Session *session, PAMSession *authentication)
+write_data (Session *session, const void *buf, size_t count)
{
- gchar **pam_env;
-
- pam_env = pam_session_get_envlist (authentication);
- if (pam_env)
- {
- gchar *env_string;
- int i;
-
- env_string = g_strjoinv (" ", pam_env);
- g_debug ("PAM returns environment '%s'", env_string);
- g_free (env_string);
-
- for (i = 0; pam_env[i]; i++)
- {
- gchar **pam_env_vars = g_strsplit (pam_env[i], "=", 2);
- if (pam_env_vars && pam_env_vars[0] && pam_env_vars[1])
- session_set_env (session, pam_env_vars[0], pam_env_vars[1]);
- else
- g_warning ("Can't parse PAM environment variable %s", pam_env[i]);
- g_strfreev (pam_env_vars);
- }
- g_strfreev (pam_env);
- }
+ if (write (session->priv->to_child_input, buf, count) != count)
+ g_warning ("Error writing to session: %s", strerror (errno));
}
-void
-session_set_env (Session *session, const gchar *name, const gchar *value)
+static void
+write_string (Session *session, const char *value)
{
- g_return_if_fail (session != NULL);
- g_return_if_fail (name != NULL);
- process_set_env (PROCESS (session), name, value);
+ int length;
+
+ length = value ? strlen (value) : -1;
+ write_data (session, &length, sizeof (length));
+ if (value)
+ write_data (session, value, sizeof (char) * length);
}
-const gchar *
-session_get_env (Session *session, const gchar *name)
+static ssize_t
+read_from_child (Session *session, void *buf, size_t count)
{
- g_return_val_if_fail (session != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
- return process_get_env (PROCESS (session), name);
+ ssize_t n_read;
+ n_read = read (session->priv->from_child_output, buf, count);
+ if (n_read < 0)
+ g_warning ("Error reading from session: %s", strerror (errno));
+ return n_read;
}
-void
-session_set_console_kit_parameter (Session *session, const gchar *name, GVariant *value)
+static gchar *
+read_string_from_child (Session *session)
{
- g_return_if_fail (session != NULL);
- g_return_if_fail (name != NULL);
+ int length;
+ char *value;
+
+ if (read_from_child (session, &length, sizeof (length)) <= 0)
+ return NULL;
+ if (length < 0)
+ return NULL;
+ if (length > MAX_STRING_LENGTH)
+ {
+ g_warning ("Invalid string length %d from child", length);
+ return NULL;
+ }
+
+ value = g_malloc (sizeof (char) * (length + 1));
+ read_from_child (session, value, length);
+ value[length] = '\0';
- g_hash_table_insert (session->priv->console_kit_parameters,
- g_strdup (name), g_variant_ref_sink (value));
+ return value;
}
-const gchar *
-session_get_console_kit_cookie (Session *session)
+static void
+session_watch_cb (GPid pid, gint status, gpointer data)
{
- g_return_val_if_fail (session != NULL, NULL);
- return session->priv->console_kit_cookie;
+ Session *session = data;
+
+ session->priv->pid = 0;
+
+ if (WIFEXITED (status))
+ g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
+ else if (WIFSIGNALED (status))
+ g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
+
+ /* If failed during authentication then report this as an authentication failure */
+ if (session->priv->authentication_started && !session->priv->authentication_complete)
+ {
+ g_debug ("Session %d failed during authentication", pid);
+ session->priv->authentication_complete = TRUE;
+ session->priv->authentication_result = PAM_CONV_ERR;
+ g_free (session->priv->authentication_result_string);
+ session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
+ g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
+ }
+
+ g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
}
-/* Set the LANG variable based on the chosen locale. This is not a great
- * solution, as it will override the locale set in PAM (which is where it
- * should be set). In the case of Ubuntu these will be overridden by setting
- * these variables in ~/.profile */
-static void
-set_locale (Session *session)
+static gboolean
+from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
{
- User *user;
- const gchar *locale;
+ Session *session = data;
+ gchar *username;
+ ssize_t n_read;
+ gboolean auth_complete;
- user = pam_session_get_user (session->priv->authentication);
- locale = user_get_locale (user);
- if (locale)
+ /* Remote end gone */
+ if (condition == G_IO_HUP)
{
- g_debug ("Using locale %s", locale);
- session_set_env (session, "LANG", locale);
+ session->priv->from_child_watch = 0;
+ return FALSE;
}
-}
-/* Insert our own utility directory to PATH
- * This is to provide gdmflexiserver which provides backwards compatibility
- * with GDM.
- * Must be done after set_env_from_authentication because PAM sets PATH.
- * This can be removed when this is no longer required.
- */
-static void
-insert_utility_path (Session *session)
-{
- const gchar *orig_path;
+ /* Get the username currently being authenticated (may change during authentication) */
+ username = read_string_from_child (session);
+ if (g_strcmp0 (username, session->priv->username) != 0)
+ {
+ g_free (session->priv->username);
+ session->priv->username = username;
+ if (session->priv->user)
+ g_object_unref (session->priv->user);
+ session->priv->user = NULL;
+ }
+ else
+ g_free (username);
- orig_path = session_get_env (session, "PATH");
- if (orig_path)
+ /* Check if authentication completed */
+ n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
+ if (n_read < 0)
+ g_debug ("Error reading from child: %s", strerror (errno));
+ if (n_read <= 0)
{
- gchar *path = g_strdup_printf ("%s:%s", PKGLIBEXEC_DIR, orig_path);
- session_set_env (session, "PATH", path);
- g_free (path);
+ session->priv->from_child_watch = 0;
+ return FALSE;
}
-}
-gboolean
-session_start (Session *session)
-{
- User *user;
+ if (auth_complete)
+ {
+ session->priv->authentication_complete = TRUE;
+ read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
+ g_free (session->priv->authentication_result_string);
+ session->priv->authentication_result_string = read_string_from_child (session);
- g_return_val_if_fail (session != NULL, FALSE);
- g_return_val_if_fail (session->priv->authentication != NULL, FALSE);
- g_return_val_if_fail (session->priv->command != NULL, FALSE);
+ g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
- g_debug ("Launching session");
+ /* No longer expect any more messages */
+ session->priv->from_child_watch = 0;
- user = pam_session_get_user (session->priv->authentication);
-
- /* Set POSIX variables */
- session_set_env (session, "PATH", "/usr/local/bin:/usr/bin:/bin");
- session_set_env (session, "USER", user_get_name (user));
- session_set_env (session, "LOGNAME", user_get_name (user));
- session_set_env (session, "HOME", user_get_home_directory (user));
- session_set_env (session, "SHELL", user_get_shell (user));
+ g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
+
+ return FALSE;
+ }
+ else
+ {
+ int i;
+
+ session->priv->messages_length = 0;
+ read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
+ session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
+ for (i = 0; i < session->priv->messages_length; i++)
+ {
+ struct pam_message *m = &session->priv->messages[i];
+ read_from_child (session, &m->msg_style, sizeof (m->msg_style));
+ m->msg = read_string_from_child (session);
+ }
- return SESSION_GET_CLASS (session)->start (session);
+ g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
+
+ g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
+ }
+
+ return TRUE;
}
-static gboolean
-session_real_start (Session *session)
+gboolean
+session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive)
{
- gboolean result;
- gchar *absolute_command;
+ int version;
+ int to_child_pipe[2], from_child_pipe[2];
+ int to_child_output, from_child_input;
+
+ g_return_val_if_fail (session != NULL, FALSE);
+ g_return_val_if_fail (service != NULL, FALSE);
+ g_return_val_if_fail (session->priv->pid == 0, FALSE);
- absolute_command = get_absolute_command (session->priv->command);
- if (!absolute_command)
+ /* Create pipes to talk to the child */
+ if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
{
- g_debug ("Can't launch session %s, not found in path", session->priv->command);
+ g_warning ("Failed to create pipe to communicated with session process: %s", strerror (errno));
return FALSE;
}
- process_set_command (PROCESS (session), absolute_command);
- g_free (absolute_command);
-
- pam_session_open (session->priv->authentication);
-
- /* Open ConsoleKit session */
- if (getuid () == 0)
+ to_child_output = to_child_pipe[0];
+ session->priv->to_child_input = to_child_pipe[1];
+ session->priv->from_child_output = from_child_pipe[0];
+ from_child_input = from_child_pipe[1];
+ session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
+ session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
+
+ /* Don't allow the daemon end of the pipes to be accessed in child processes */
+ fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
+ fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
+
+ /* Remember what username we started with - it will be updated by PAM during authentication */
+ session->priv->username = g_strdup (username);
+
+ /* Run the child */
+ session->priv->pid = fork ();
+ if (session->priv->pid < 0)
{
- GVariantBuilder parameters;
- User *user;
- GHashTableIter iter;
- gpointer key, value;
-
- user = pam_session_get_user (session->priv->authentication);
-
- g_variant_builder_init (&parameters, G_VARIANT_TYPE ("(a(sv))"));
- g_variant_builder_open (&parameters, G_VARIANT_TYPE ("a(sv)"));
- g_variant_builder_add (&parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
- if (session->priv->is_greeter)
- g_variant_builder_add (&parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
- g_hash_table_iter_init (&iter, session->priv->console_kit_parameters);
- while (g_hash_table_iter_next (&iter, &key, &value))
- g_variant_builder_add (&parameters, "(sv)", (gchar *) key, (GVariant *) value);
-
- g_free (session->priv->console_kit_cookie);
- session->priv->console_kit_cookie = ck_open_session (&parameters);
+ g_debug ("Failed to fork session child process: %s", strerror (errno));
+ return FALSE;
}
- else
+ if (session->priv->pid == 0)
{
- g_free (session->priv->console_kit_cookie);
- session->priv->console_kit_cookie = g_strdup (g_getenv ("XDG_SESSION_COOKIE"));
+ /* Run us again in session child mode */
+ execlp ("lightdm",
+ "lightdm",
+ "--session-child",
+ g_strdup_printf ("%d", to_child_output),
+ g_strdup_printf ("%d", from_child_input),
+ NULL);
+ _exit (EXIT_FAILURE);
}
- if (session->priv->console_kit_cookie)
- session_set_env (session, "XDG_SESSION_COOKIE", session->priv->console_kit_cookie);
+ /* Listen for session termination */
+ session->priv->authentication_started = TRUE;
+ session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
- if (!SESSION_GET_CLASS (session)->setup (session))
- return FALSE;
-
- result = process_start (PROCESS (session));
+ /* Close the ends of the pipes we don't need */
+ close (to_child_output);
+ close (from_child_input);
- if (!result)
+ /* Indicate what version of the protocol we are using */
+ version = 0;
+ write_data (session, &version, sizeof (version));
+
+ /* Send configuration */
+ write_string (session, service);
+ write_string (session, username);
+ write_data (session, &do_authenticate, sizeof (do_authenticate));
+ write_data (session, &is_interactive, sizeof (is_interactive));
+ write_string (session, session->priv->class);
+ write_string (session, session->priv->tty);
+ write_string (session, session->priv->remote_host_name);
+ write_string (session, session->priv->xdisplay);
+ if (session->priv->xauthority)
{
- pam_session_close (session->priv->authentication);
- if (getuid () == 0 && session->priv->console_kit_cookie)
- ck_close_session (session->priv->console_kit_cookie);
- }
+ guint16 family;
+ gsize length;
+
+ write_string (session, xauth_get_authorization_name (session->priv->xauthority));
+ family = xauth_get_family (session->priv->xauthority);
+ write_data (session, &family, sizeof (family));
+ length = xauth_get_address_length (session->priv->xauthority);
+ write_data (session, &length, sizeof (length));
+ write_data (session, xauth_get_address (session->priv->xauthority), length);
+ write_string (session, xauth_get_number (session->priv->xauthority));
+ length = xauth_get_authorization_data_length (session->priv->xauthority);
+ write_data (session, &length, sizeof (length));
+ write_data (session, xauth_get_authorization_data (session->priv->xauthority), length);
+ }
+ else
+ write_string (session, NULL);
- return result;
+ g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, service, username);
+
+ return TRUE;
}
-void
-session_lock (Session *session)
-{
- g_return_if_fail (session != NULL);
- if (getuid () == 0)
- ck_lock_session (session->priv->console_kit_cookie);
+const gchar *
+session_get_username (Session *session)
+{
+ g_return_val_if_fail (session != NULL, NULL);
+ return session->priv->username;
}
-void
-session_unlock (Session *session)
-{
- g_return_if_fail (session != NULL);
- if (getuid () == 0)
- ck_unlock_session (session->priv->console_kit_cookie);
+const gchar *
+session_get_console_kit_cookie (Session *session)
+{
+ g_return_val_if_fail (session != NULL, NULL);
+ return session->priv->console_kit_cookie;
}
void
-session_stop (Session *session)
+session_respond (Session *session, struct pam_response *response)
{
+ int i;
+
g_return_if_fail (session != NULL);
- if (process_get_is_running (PROCESS (session)))
+ for (i = 0; i < session->priv->messages_length; i++)
{
- SESSION_GET_CLASS (session)->cleanup (session);
- process_signal (PROCESS (session), SIGTERM);
+ int error = PAM_SUCCESS;
+ write_data (session, &error, sizeof (error));
+ write_string (session, response[i].resp);
+ write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
}
+
+ /* Delete the old messages */
+ for (i = 0; i < session->priv->messages_length; i++)
+ g_free ((char *) session->priv->messages[i].msg);
+ g_free (session->priv->messages);
+ session->priv->messages = NULL;
+ session->priv->messages_length = 0;
}
-gboolean
-session_get_is_stopped (Session *session)
+void
+session_respond_error (Session *session, int error)
{
- g_return_val_if_fail (session != NULL, TRUE);
- return !process_get_is_running (PROCESS (session));
+ g_return_if_fail (session != NULL);
+ g_return_if_fail (error != PAM_SUCCESS);
+
+ write_data (session, &error, sizeof (error));
}
-static gboolean
-session_setup (Session *session)
+int
+session_get_messages_length (Session *session)
{
- return TRUE;
+ g_return_val_if_fail (session != NULL, 0);
+ return session->priv->messages_length;
}
-static void
-session_cleanup (Session *session)
+const struct pam_message *
+session_get_messages (Session *session)
{
+ g_return_val_if_fail (session != NULL, NULL);
+ return session->priv->messages;
}
-static void
-setup_log_file (Session *session)
+gboolean
+session_get_is_authenticated (Session *session)
{
- int fd;
-
- /* Redirect output to logfile */
- if (!session->priv->log_file)
- return;
-
- fd = g_open (session->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fd < 0)
- g_warning ("Failed to open log file %s: %s", session->priv->log_file, g_strerror (errno));
- else
- {
- dup2 (fd, STDERR_FILENO);
- close (fd);
- }
+ g_return_val_if_fail (session != NULL, FALSE);
+ return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
}
-static void
-session_run (Process *process)
+int
+session_get_authentication_result (Session *session)
{
- Session *session = SESSION (process);
- User *user;
- int fd;
+ g_return_val_if_fail (session != NULL, 0);
+ return session->priv->authentication_result;
+}
- /* No input and output */
- fd = g_open ("/dev/null", O_RDONLY);
- dup2 (fd, STDIN_FILENO);
- dup2 (fd, STDOUT_FILENO);
- close (fd);
+const gchar *
+session_get_authentication_result_string (Session *session)
+{
+ g_return_val_if_fail (session != NULL, NULL);
+ return session->priv->authentication_result_string;
+}
- /* Redirect output to logfile */
- if (!session->priv->log_file_as_user)
- setup_log_file (session);
+void
+session_run (Session *session, gchar **argv)
+{
+ gsize i, argc;
+ gchar *command, *filename;
+ GList *link;
- /* Make this process its own session */
- if (setsid () < 0)
- g_warning ("Failed to make process a new session: %s", strerror (errno));
+ g_return_if_fail (session != NULL);
+ g_return_if_fail (session_get_is_authenticated (session));
- user = pam_session_get_user (session->priv->authentication);
+ command = g_strjoinv (" ", argv);
+ g_debug ("Session %d running command %s", session->priv->pid, command);
+ g_free (command);
- /* Change to this user */
- if (getuid () == 0)
+ /* Create authority location */
+ if (session->priv->xauth_use_system_location)
{
- if (initgroups (user_get_name (user), user_get_gid (user)) < 0)
- {
- g_warning ("Failed to initialize supplementary groups for %s: %s", user_get_name (user), strerror (errno));
- _exit (EXIT_FAILURE);
- }
+ gchar *run_dir, *dir;
- if (setgid (user_get_gid (user)) != 0)
- {
- g_warning ("Failed to set group ID to %d: %s", user_get_gid (user), strerror (errno));
- _exit (EXIT_FAILURE);
- }
+ run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
+ dir = g_build_filename (run_dir, session->priv->username, NULL);
+ g_free (run_dir);
- if (setuid (user_get_uid (user)) != 0)
+ g_mkdir_with_parents (dir, S_IRWXU);
+ if (getuid () == 0)
{
- g_warning ("Failed to set user ID to %d: %s", user_get_uid (user), strerror (errno));
- _exit (EXIT_FAILURE);
+ if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
+ g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
}
- }
- /* Change working directory */
- /* NOTE: This must be done after the permissions are changed because NFS filesystems can
- * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
- * are not system readable then the chdir can fail */
- if (chdir (user_get_home_directory (user)) != 0)
- {
- g_warning ("Failed to change to home directory %s: %s", user_get_home_directory (user), strerror (errno));
- _exit (EXIT_FAILURE);
+ filename = g_build_filename (dir, "xauthority", NULL);
+ g_free (dir);
}
+ else
+ filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
+
+ write_string (session, session->priv->log_filename);
+ write_string (session, filename);
+ g_free (filename);
+ argc = g_list_length (session->priv->env);
+ write_data (session, &argc, sizeof (argc));
+ for (link = session->priv->env; link; link = link->next)
+ write_string (session, (gchar *) link->data);
+ argc = g_strv_length (argv);
+ write_data (session, &argc, sizeof (argc));
+ for (i = 0; i < argc; i++)
+ write_string (session, argv[i]);
+
+ session->priv->console_kit_cookie = read_string_from_child (session);
+}
- /* Redirect output to logfile */
- if (session->priv->log_file_as_user)
- setup_log_file (session);
-
- /* Do PAM actions requiring session process */
- pam_session_setup (session->priv->authentication);
- set_env_from_authentication (session, session->priv->authentication);
- set_locale (session);
- insert_utility_path (session);
+void
+session_lock (Session *session)
+{
+ g_return_if_fail (session != NULL);
+ if (getuid () == 0)
+ ck_lock_session (session->priv->console_kit_cookie);
+}
- PROCESS_CLASS (session_parent_class)->run (process);
+void
+session_unlock (Session *session)
+{
+ g_return_if_fail (session != NULL);
+ if (getuid () == 0)
+ ck_unlock_session (session->priv->console_kit_cookie);
}
-static void
-session_stopped (Process *process)
+void
+session_stop (Session *session)
{
- Session *session = SESSION (process);
-
- pam_session_close (session->priv->authentication);
- if (getuid () == 0 && session->priv->console_kit_cookie)
- ck_close_session (session->priv->console_kit_cookie);
+ g_return_if_fail (session != NULL);
+
+ if (session->priv->pid > 0)
+ {
+ g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
+ kill (session->priv->pid, SIGTERM);
+ // FIXME: Handle timeout
+ }
+}
- PROCESS_CLASS (session_parent_class)->stopped (process);
+gboolean
+session_get_is_stopped (Session *session)
+{
+ g_return_val_if_fail (session != NULL, TRUE);
+ return session->priv->pid == 0;
}
static void
session_init (Session *session)
{
session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
- session->priv->console_kit_parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
- process_set_clear_environment (PROCESS (session), TRUE);
}
static void
session_finalize (GObject *object)
{
- Session *self;
-
- self = SESSION (object);
-
- g_free (self->priv->log_file);
- if (self->priv->authentication)
- g_object_unref (self->priv->authentication);
- g_free (self->priv->command);
- g_hash_table_unref (self->priv->console_kit_parameters);
+ Session *self = SESSION (object);
+ int i;
+
+ if (self->priv->pid)
+ kill (self->priv->pid, SIGKILL);
+ if (self->priv->from_child_channel)
+ g_io_channel_unref (self->priv->from_child_channel);
+ if (self->priv->from_child_watch)
+ g_source_remove (self->priv->from_child_watch);
+ if (self->priv->child_watch)
+ g_source_remove (self->priv->child_watch);
+ g_free (self->priv->username);
+ if (self->priv->user)
+ g_object_unref (self->priv->user);
+ for (i = 0; i < self->priv->messages_length; i++)
+ g_free ((char *) self->priv->messages[i].msg);
+ g_free (self->priv->messages);
+ g_free (self->priv->authentication_result_string);
+ g_free (self->priv->log_filename);
+ g_free (self->priv->class);
+ g_free (self->priv->tty);
+ g_free (self->priv->xdisplay);
+ if (self->priv->xauthority)
+ g_object_unref (self->priv->xauthority);
+ g_free (self->priv->remote_host_name);
g_free (self->priv->console_kit_cookie);
+ g_list_free_full (self->priv->env, g_free);
G_OBJECT_CLASS (session_parent_class)->finalize (object);
}
@@ -497,14 +619,35 @@ static void
session_class_init (SessionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- ProcessClass *process_class = PROCESS_CLASS (klass);
- klass->start = session_real_start;
- klass->setup = session_setup;
- klass->cleanup = session_cleanup;
- process_class->run = session_run;
- process_class->stopped = session_stopped;
object_class->finalize = session_finalize;
g_type_class_add_private (klass, sizeof (SessionPrivate));
+
+ signals[GOT_MESSAGES] =
+ g_signal_new ("got-messages",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SessionClass, got_messages),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[AUTHENTICATION_COMPLETE] =
+ g_signal_new ("authentication-complete",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SessionClass, authentication_complete),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[STOPPED] =
+ g_signal_new ("stopped",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SessionClass, stopped),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
diff --git a/src/session.h b/src/session.h
index b9e11e7d..a574726a 100644
--- a/src/session.h
+++ b/src/session.h
@@ -12,9 +12,12 @@
#ifndef _SESSION_H_
#define _SESSION_H_
-#include "process.h"
+#include <glib-object.h>
+
+#include <security/pam_appl.h>
+
#include "accounts.h"
-#include "pam-session.h"
+#include "xauthority.h"
G_BEGIN_DECLS
@@ -27,48 +30,63 @@ typedef struct SessionPrivate SessionPrivate;
typedef struct
{
- Process parent_instance;
+ GObject parent_instance;
SessionPrivate *priv;
} Session;
typedef struct
{
- ProcessClass parent_class;
+ GObjectClass parent_class;
- gboolean (*start)(Session *session);
- gboolean (*setup)(Session *session);
- void (*cleanup)(Session *session);
+ void (*got_messages)(Session *session);
+ void (*authentication_complete)(Session *session);
+ void (*stopped)(Session *session);
} SessionClass;
+#define XDG_SESSION_CLASS_USER "user"
+#define XDG_SESSION_CLASS_GREETER "greeter"
+#define XDG_SESSION_CLASS_LOCK_SCREEN "lock-screen"
+
GType session_get_type (void);
-void session_set_log_file (Session *session, const gchar *filename, gboolean as_user);
+void session_set_log_file (Session *session, const gchar *filename);
+
+void session_set_class (Session *session, const gchar *class);
+
+void session_set_tty (Session *session, const gchar *tty);
-const gchar *session_get_log_file (Session *session);
+void session_set_xdisplay (Session *session, const gchar *xdisplay);
-void session_set_authentication (Session *session, PAMSession *authentication);
+void session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location);
-PAMSession *session_get_authentication (Session *session);
+void session_set_remote_host_name (Session *session, const gchar *remote_host_name);
+void session_set_env (Session *session, const gchar *name, const gchar *value);
+
+// FIXME: Remove
User *session_get_user (Session *session);
-void session_set_is_greeter (Session *session, gboolean is_greeter);
+gboolean session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive);
-gboolean session_get_is_greeter (Session *session);
+const gchar *session_get_username (Session *session);
-void session_set_command (Session *session, const gchar *command);
+const gchar *session_get_console_kit_cookie (Session *session);
-const gchar *session_get_command (Session *session);
+void session_respond (Session *session, struct pam_response *response);
-void session_set_env (Session *process, const gchar *name, const gchar *value);
+void session_respond_error (Session *session, int error);
-const gchar *session_get_env (Session *session, const gchar *name);
+int session_get_messages_length (Session *session);
-void session_set_console_kit_parameter (Session *session, const gchar *name, GVariant *value);
+const struct pam_message *session_get_messages (Session *session);
-const gchar *session_get_console_kit_cookie (Session *session);
+gboolean session_get_is_authenticated (Session *session);
+
+int session_get_authentication_result (Session *session);
+
+const gchar *session_get_authentication_result_string (Session *session);
-gboolean session_start (Session *session);
+void session_run (Session *session, gchar **argv);
void session_lock (Session *session);
diff --git a/src/xsession.c b/src/xsession.c
index 1b61e4a2..0c0b99df 100644
--- a/src/xsession.c
+++ b/src/xsession.c
@@ -22,11 +22,6 @@ struct XSessionPrivate
{
/* X server connected to */
XServer *xserver;
-
- /* X Authority */
- gboolean authority_in_system_dir;
- XAuthority *authority;
- GFile *authority_file;
};
G_DEFINE_TYPE (XSession, xsession, SESSION_TYPE);
@@ -34,128 +29,21 @@ G_DEFINE_TYPE (XSession, xsession, SESSION_TYPE);
XSession *
xsession_new (XServer *xserver)
{
- XSession *session = g_object_new (XSESSION_TYPE, NULL);
+ XSession *session;
+ XAuthority *authority;
+ session = g_object_new (XSESSION_TYPE, NULL);
session->priv->xserver = g_object_ref (xserver);
- return session;
-}
-
-static gboolean
-xsession_start (Session *session)
-{
- XSession *xsession = XSESSION (session);
- PAMSession *authentication;
- gchar *hostname;
-
- authentication = session_get_authentication (session);
- pam_session_set_item (authentication, PAM_TTY, xserver_get_address (xsession->priv->xserver));
-
- session_set_console_kit_parameter (session, "x11-display", g_variant_new_string (xserver_get_address (xsession->priv->xserver)));
- hostname = xserver_get_hostname (xsession->priv->xserver);
- if (hostname)
- {
- session_set_console_kit_parameter (session, "remote-host-name", g_variant_new_string (hostname));
- session_set_console_kit_parameter (session, "is-local", g_variant_new_boolean (FALSE));
- }
-
- session_set_env (session, "DISPLAY", xserver_get_address (xsession->priv->xserver));
-
- return SESSION_CLASS (xsession_parent_class)->start (session);
-}
-
-static gboolean
-xsession_setup (Session *session)
-{
- XSession *xsession = XSESSION (session);
-
- if (xserver_get_authority (xsession->priv->xserver))
- {
- gchar *path;
- gboolean drop_privileges, result;
- GError *error = NULL;
-
- xsession->priv->authority = g_object_ref (xserver_get_authority (xsession->priv->xserver));
-
- xsession->priv->authority_in_system_dir = config_get_boolean (config_get_instance (), "LightDM", "user-authority-in-system-dir");
- if (xsession->priv->authority_in_system_dir)
- {
- gchar *run_dir, *dir;
-
- run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
- dir = g_build_filename (run_dir, user_get_name (session_get_user (session)), NULL);
- g_free (run_dir);
-
- g_mkdir_with_parents (dir, S_IRWXU);
- if (getuid () == 0)
- {
- if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
- g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
- }
-
- path = g_build_filename (dir, "xauthority", NULL);
- g_free (dir);
- }
- else
- path = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
-
- session_set_env (session, "XAUTHORITY", path);
- xsession->priv->authority_file = g_file_new_for_path (path);
-
- drop_privileges = geteuid () == 0;
- if (drop_privileges)
- privileges_drop (session_get_user (SESSION (session)));
- g_debug ("Adding session authority to %s", path);
- result = xauth_write (xsession->priv->authority, XAUTH_WRITE_MODE_REPLACE, xsession->priv->authority_file, &error);
- if (drop_privileges)
- privileges_reclaim ();
- if (error)
- g_warning ("Failed to write authority: %s", error->message);
- g_clear_error (&error);
- g_free (path);
-
- if (!result)
- return FALSE;
- }
-
- return SESSION_CLASS (xsession_parent_class)->setup (session);
-}
+ session_set_env (SESSION (session), "DISPLAY", xserver_get_address (xserver));
+ session_set_tty (SESSION (session), xserver_get_address (xserver));
+ session_set_xdisplay (SESSION (session), xserver_get_address (xserver));
+ authority = xserver_get_authority (xserver);
+ if (authority)
+ session_set_xauthority (SESSION (session), authority, config_get_boolean (config_get_instance (), "LightDM", "user-authority-in-system-dir"));
+ session_set_log_file (SESSION (session), ".xsession-errors");
-static void
-xsession_remove_authority (XSession *session)
-{
- if (session->priv->authority_file)
- {
- gboolean drop_privileges;
- gchar *path;
-
- drop_privileges = geteuid () == 0;
- if (drop_privileges)
- privileges_drop (session_get_user (SESSION (session)));
-
- path = g_file_get_path (session->priv->authority_file);
- g_debug ("Removing session authority from %s", path);
- g_free (path);
- xauth_write (session->priv->authority, XAUTH_WRITE_MODE_REMOVE, session->priv->authority_file, NULL);
-
- if (drop_privileges)
- privileges_reclaim ();
-
- g_object_unref (session->priv->authority_file);
- session->priv->authority_file = NULL;
- }
- if (session->priv->authority)
- {
- g_object_unref (session->priv->authority);
- session->priv->authority = NULL;
- }
-}
-
-static void
-xsession_cleanup (Session *session)
-{
- xsession_remove_authority (XSESSION (session));
- SESSION_CLASS (xsession_parent_class)->cleanup (session);
+ return session;
}
static void
@@ -171,13 +59,8 @@ xsession_finalize (GObject *object)
self = XSESSION (object);
- xsession_remove_authority (self);
if (self->priv->xserver)
g_object_unref (self->priv->xserver);
- if (self->priv->authority)
- g_object_unref (self->priv->authority);
- if (self->priv->authority_file)
- g_object_unref (self->priv->authority_file);
G_OBJECT_CLASS (xsession_parent_class)->finalize (object);
}
@@ -186,11 +69,7 @@ static void
xsession_class_init (XSessionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- SessionClass *session_class = SESSION_CLASS (klass);
- session_class->start = xsession_start;
- session_class->setup = xsession_setup;
- session_class->cleanup = xsession_cleanup;
object_class->finalize = xsession_finalize;
g_type_class_add_private (klass, sizeof (XSessionPrivate));
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 932aaa62..e9a893e8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -10,9 +10,11 @@ TESTS = \
test-autologin \
test-autologin-invalid-user \
test-autologin-invalid-session \
+ test-autologin-crash-authenticate \
test-autologin-xserver-crash \
test-autologin-session-crash \
test-autologin-password \
+ test-autologin-new-authtok \
test-autologin-denied \
test-autologin-expired \
test-autologin-logout \
@@ -33,6 +35,7 @@ TESTS = \
test-language \
test-no-language \
test-language-no-accounts-service \
+ test-login-crash-authenticate \
test-login-gobject \
test-login-gobject-manual \
test-login-gobject-manual-previous-session \
@@ -90,11 +93,6 @@ TESTS = \
test-console-kit \
test-no-console-kit
-# FIXME: These fail, fixed in session-refactor3 branch
-# test-autologin-crash-authenticate
-# test-autologin-new-authtok
-# test-login-crash-authenticate
-
# test-session-exit-error
# test-greeter-no-exit
# test-gobject-change-password