diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2012-08-30 09:27:02 +1200 |
---|---|---|
committer | Robert Ancell <robert.ancell@canonical.com> | 2012-08-30 09:27:02 +1200 |
commit | d7b170903f9bca5acf02c1d52cdd8209fcf6b3bf (patch) | |
tree | 26a9c2f15bf4c017aa2137f82126e18fd5994874 | |
parent | 14b05e763d12a3013e50f5b088ea2c04d9dfa38a (diff) | |
parent | c8e18e61ce4a83bb722183d1b873be8a3c8a263d (diff) | |
download | lightdm-d7b170903f9bca5acf02c1d52cdd8209fcf6b3bf.tar.gz |
Add remote sessions
33 files changed, 479 insertions, 89 deletions
@@ -1,3 +1,9 @@ +Overview of changes in lightdm 1.3.3 + + * Add a new remote session type. These sessions create a temporary local + account and authenticate against a remote server. The session is an + application that accesses that remote session (e.g. VNC, RDP etc) + Overview of changes in lightdm 1.3.2 * Handle clearenv() not being defined diff --git a/data/lightdm.conf b/data/lightdm.conf index f3b7d353..c98446f9 100644 --- a/data/lightdm.conf +++ b/data/lightdm.conf @@ -12,6 +12,7 @@ # run-directory = Directory to put running state in # cache-directory = Directory to cache to # xsessions-directory = Directory to find X sessions +# remote-sessions-directory = Directory to find remote sessions # xgreeters-directory = Directory to find X greeters # [LightDM] @@ -26,6 +27,7 @@ #run-directory=/var/run/lightdm #cache-directory=/var/cache/lightdm #xsessions-directory=/usr/share/xsessions +#remote-sessions-directory=/usr/share/lightdm/remote-sessions #xgreeters-directory=/usr/share/xgreeters # diff --git a/liblightdm-gobject/Makefile.am b/liblightdm-gobject/Makefile.am index 8c0ce526..fa7ec56e 100644 --- a/liblightdm-gobject/Makefile.am +++ b/liblightdm-gobject/Makefile.am @@ -5,7 +5,8 @@ liblightdm_gobject_1_la_LIBADD = $(LIBLIGHTDM_GOBJECT_LIBS) liblightdm_gobject_1_la_CFLAGS = $(LIBLIGHTDM_GOBJECT_CFLAGS) \ $(WARN_CFLAGS) \ -DCONFIG_DIR=\"$(sysconfdir)/lightdm\" \ - -DXSESSIONS_DIR=\"$(datadir)/xsessions\" + -DXSESSIONS_DIR=\"$(datadir)/xsessions\" \ + -DREMOTE_SESSIONS_DIR=\"$(pkgdatadir)/remote-sessions\" mainheader_HEADERS = lightdm.h mainheaderdir=$(includedir)/lightdm-gobject-1 diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c index 2d31b84c..b6d1ba77 100644 --- a/liblightdm-gobject/greeter.c +++ b/liblightdm-gobject/greeter.c @@ -80,7 +80,8 @@ typedef enum GREETER_MESSAGE_CONTINUE_AUTHENTICATION, GREETER_MESSAGE_START_SESSION, GREETER_MESSAGE_CANCEL_AUTHENTICATION, - GREETER_MESSAGE_SET_LANGUAGE + GREETER_MESSAGE_SET_LANGUAGE, + GREETER_MESSAGE_AUTHENTICATE_REMOTE } GreeterMessage; /* Messages from the server to the greeter */ @@ -770,7 +771,7 @@ lightdm_greeter_cancel_autologin (LightDMGreeter *greeter) * Starts the authentication procedure for a user. **/ void -lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username) +lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username) { LightDMGreeterPrivate *priv; guint8 message[MAX_MESSAGE_LENGTH]; @@ -832,6 +833,45 @@ lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter) } /** + * lightdm_greeter_authenticate_remote: + * @greeter: A #LightDMGreeter + * @session: The name of a remote session + * @username: (allow-none): A username of #NULL to prompt for a username. + * + * Start authentication for a remote session type. + **/ +void +lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username) +{ + LightDMGreeterPrivate *priv; + guint8 message[MAX_MESSAGE_LENGTH]; + gsize offset = 0; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (priv->connected); + + priv->cancelling_authentication = FALSE; + priv->authenticate_sequence_number++; + priv->in_authentication = TRUE; + priv->is_authenticated = FALSE; + g_free (priv->authentication_user); + priv->authentication_user = NULL; + + if (username) + g_debug ("Starting authentication for remote session %s as user %s...", session, username); + else + g_debug ("Starting authentication for remote session %s...", session); + write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset); + write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset); + write_string (message, MAX_MESSAGE_LENGTH, session, &offset); + write_string (message, MAX_MESSAGE_LENGTH, username, &offset); + write_message (greeter, message, offset); +} + +/** * lightdm_greeter_respond: * @greeter: A #LightDMGreeter * @response: Response to a prompt diff --git a/liblightdm-gobject/liblightdm-gobject-1.vapi b/liblightdm-gobject/liblightdm-gobject-1.vapi index 56aa327e..a9236011 100644 --- a/liblightdm-gobject/liblightdm-gobject-1.vapi +++ b/liblightdm-gobject/liblightdm-gobject-1.vapi @@ -4,6 +4,7 @@ namespace LightDM { public static unowned GLib.List<weak LightDM.Session> get_sessions (); public static unowned GLib.List<weak LightDM.Language> get_languages (); public static unowned GLib.List<weak LightDM.Layout> get_layouts (); + public static unowned GLib.List<weak LightDM.Session> get_remote_sessions (); public static unowned Language get_language (); public static void set_layout (Layout layout); public static unowned Layout get_layout (); @@ -38,6 +39,7 @@ namespace LightDM { public void cancel_autologin (); public void authenticate (string? username = null); public void authenticate_as_guest (); + public void authenticate_remote (string session, string? username); public void respond (string response); public void cancel_authentication (); public bool in_authentication { get; } diff --git a/liblightdm-gobject/lightdm/greeter.h b/liblightdm-gobject/lightdm/greeter.h index dc051b3e..cd26f772 100644 --- a/liblightdm-gobject/lightdm/greeter.h +++ b/liblightdm-gobject/lightdm/greeter.h @@ -98,10 +98,12 @@ gint lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter); void lightdm_greeter_cancel_autologin (LightDMGreeter *greeter); -void lightdm_greeter_authenticate (LightDMGreeter *greeter, const char *username); +void lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username); void lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter); +void lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username); + void lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response); void lightdm_greeter_cancel_authentication (LightDMGreeter *greeter); diff --git a/liblightdm-gobject/lightdm/session.h b/liblightdm-gobject/lightdm/session.h index 3b07bdcd..910205e0 100644 --- a/liblightdm-gobject/lightdm/session.h +++ b/liblightdm-gobject/lightdm/session.h @@ -45,6 +45,8 @@ GType lightdm_session_get_type (void); GList *lightdm_get_sessions (void); +GList *lightdm_get_remote_sessions (void); + const gchar *lightdm_session_get_key (LightDMSession *session); const gchar *lightdm_session_get_name (LightDMSession *session); diff --git a/liblightdm-gobject/session.c b/liblightdm-gobject/session.c index 603ddb7f..476ad9b6 100644 --- a/liblightdm-gobject/session.c +++ b/liblightdm-gobject/session.c @@ -33,7 +33,8 @@ G_DEFINE_TYPE (LightDMSession, lightdm_session, G_TYPE_OBJECT); #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_SESSION, LightDMSessionPrivate) static gboolean have_sessions = FALSE; -static GList *sessions = NULL; +static GList *local_sessions = NULL; +static GList *remote_sessions = NULL; static gint compare_session (gconstpointer a, gconstpointer b) @@ -99,54 +100,24 @@ load_session (GKeyFile *key_file, const gchar *key) if (!priv->comment) priv->comment = g_strdup (""); - sessions = g_list_insert_sorted (sessions, session, compare_session); - g_free (domain); return session; } -static void -update_sessions (void) +static GList * +load_sessions (const gchar *sessions_dir) { GDir *directory; - gboolean result; + GList *sessions = NULL; GError *error = NULL; - GKeyFile *config_key_file = NULL; - gchar *config_path = NULL; - gchar *xsessions_dir = g_strdup (XSESSIONS_DIR); - - if (have_sessions) - return; - - config_path = g_build_filename (CONFIG_DIR, "lightdm.conf", NULL); - config_key_file = g_key_file_new (); - result = g_key_file_load_from_file (config_key_file, config_path, G_KEY_FILE_NONE, &error); - if (error) - g_warning ("Failed to open configuration file: %s", error->message); - g_clear_error (&error); - if (result) - { - gchar *xd_value = g_key_file_get_string (config_key_file, "LightDM", "xsessions-directory", NULL); - if (xd_value) - { - g_free (xsessions_dir); - xsessions_dir = xd_value; - } - } - g_key_file_free (config_key_file); - g_free (config_path); - - directory = g_dir_open (xsessions_dir, 0, &error); + directory = g_dir_open (sessions_dir, 0, &error); if (error) g_warning ("Failed to open sessions directory: %s", error->message); g_clear_error (&error); if (!directory) - { - g_free (xsessions_dir); - return; - } + return NULL; while (TRUE) { @@ -162,7 +133,7 @@ update_sessions (void) if (!g_str_has_suffix (filename, ".desktop")) continue; - path = g_build_filename (xsessions_dir, filename, NULL); + path = g_build_filename (sessions_dir, filename, NULL); key_file = g_key_file_new (); result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error); @@ -178,7 +149,10 @@ update_sessions (void) key = g_strndup (filename, strlen (filename) - strlen (".desktop")); session = load_session (key_file, key); if (session) + { g_debug ("Loaded session %s (%s, %s)", path, GET_PRIVATE (session)->name, GET_PRIVATE (session)->comment); + sessions = g_list_insert_sorted (sessions, session, compare_session); + } else g_debug ("Ignoring session %s", path); g_free (key); @@ -189,7 +163,60 @@ update_sessions (void) } g_dir_close (directory); + + return sessions; +} + +static void +update_sessions (void) +{ + GKeyFile *config_key_file = NULL; + gchar *config_path = NULL; + gchar *xsessions_dir; + gchar *remote_sessions_dir; + gboolean result; + GError *error = NULL; + + if (have_sessions) + return; + + xsessions_dir = g_strdup (XSESSIONS_DIR); + remote_sessions_dir = g_strdup (REMOTE_SESSIONS_DIR); + + /* Use session directory from configuration */ + /* FIXME: This should be sent in the greeter connection */ + config_path = g_build_filename (CONFIG_DIR, "lightdm.conf", NULL); + config_key_file = g_key_file_new (); + result = g_key_file_load_from_file (config_key_file, config_path, G_KEY_FILE_NONE, &error); + if (error) + g_warning ("Failed to open configuration file: %s", error->message); + g_clear_error (&error); + if (result) + { + gchar *value; + + value = g_key_file_get_string (config_key_file, "LightDM", "xsessions-directory", NULL); + if (value) + { + g_free (xsessions_dir); + xsessions_dir = value; + } + + value = g_key_file_get_string (config_key_file, "LightDM", "remote-sessions-directory", NULL); + if (value) + { + g_free (remote_sessions_dir); + remote_sessions_dir = value; + } + } + g_key_file_free (config_key_file); + g_free (config_path); + + local_sessions = load_sessions (xsessions_dir); + remote_sessions = load_sessions (remote_sessions_dir); + g_free (xsessions_dir); + g_free (remote_sessions_dir); have_sessions = TRUE; } @@ -205,7 +232,21 @@ GList * lightdm_get_sessions (void) { update_sessions (); - return sessions; + return local_sessions; +} + +/** + * lightdm_get_remote_sessions: + * + * Get the available remote sessions. + * + * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession + **/ +GList * +lightdm_get_remote_sessions (void) +{ + update_sessions (); + return remote_sessions; } /** diff --git a/liblightdm-qt/QLightDM/greeter.h b/liblightdm-qt/QLightDM/greeter.h index ab296b5e..4c6799e0 100644 --- a/liblightdm-qt/QLightDM/greeter.h +++ b/liblightdm-qt/QLightDM/greeter.h @@ -72,6 +72,7 @@ public slots: bool connectSync(); void authenticate(const QString &username=QString()); void authenticateAsGuest(); + void authenticateRemote(const QString &session=QString(), const QString &username=QString()); void respond(const QString &response); void cancelAuthentication(); void setLanguage (const QString &language); diff --git a/liblightdm-qt/greeter.cpp b/liblightdm-qt/greeter.cpp index 02e8cd8c..2df535b5 100644 --- a/liblightdm-qt/greeter.cpp +++ b/liblightdm-qt/greeter.cpp @@ -117,7 +117,12 @@ void Greeter::authenticateAsGuest() { Q_D(Greeter); lightdm_greeter_authenticate_as_guest(d->ldmGreeter); - +} + +void Greeter::authenticateRemote(const QString &session, const QString &username) +{ + Q_D(Greeter); + lightdm_greeter_authenticate_remote(d->ldmGreeter, session.toLocal8Bit().data(), username.toLocal8Bit().data()); } void Greeter::respond(const QString &response) diff --git a/src/Makefile.am b/src/Makefile.am index 4cf2863a..ba1e544e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -86,6 +86,7 @@ lightdm_CFLAGS = \ -DRUN_DIR=\"$(localstatedir)/run/lightdm\" \ -DCACHE_DIR=\"$(localstatedir)/cache/lightdm\" \ -DXSESSIONS_DIR=\"$(datadir)/xsessions\" \ + -DREMOTE_SESSIONS_DIR=\"$(pkgdatadir)/remote-sessions\" \ -DXGREETERS_DIR=\"$(datadir)/xgreeters\" lightdm_LDADD = \ diff --git a/src/display.c b/src/display.c index 9078c9f5..ec001530 100644 --- a/src/display.c +++ b/src/display.c @@ -35,15 +35,6 @@ enum }; static guint signals[LAST_SIGNAL] = { 0 }; -typedef enum -{ - SESSION_NONE = 0, - SESSION_GREETER_PRE_CONNECT, - SESSION_GREETER, - SESSION_GREETER_AUTHENTICATED, - SESSION_USER -} SessionType; - struct DisplayPrivate { /* Display server */ @@ -62,6 +53,7 @@ struct DisplayPrivate gboolean greeter_is_lock; /* Session requested to log into */ + SessionType user_session_type; gchar *user_session; /* Program to run sessions through */ @@ -220,10 +212,11 @@ display_set_lock_hint (Display *display, gboolean is_lock) } void -display_set_user_session (Display *display, const gchar *session_name) +display_set_user_session (Display *display, SessionType type, const gchar *session_name) { g_return_if_fail (display != NULL); g_free (display->priv->user_session); + display->priv->user_session_type = type; display->priv->user_session = g_strdup (session_name); } @@ -349,7 +342,7 @@ greeter_start_authentication_cb (Greeter *greeter, const gchar *username, Displa } static gboolean -greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display *display) +greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *session_name, Display *display) { /* If no session requested, use the previous one */ if (!session_name && !greeter_get_guest_authenticated (greeter)) @@ -357,6 +350,7 @@ greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display * User *user; user = session_get_user (greeter_get_authentication_session (greeter)); + type = SESSION_TYPE_LOCAL; session_name = user_get_xsession (user); } @@ -364,7 +358,7 @@ greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display * if (session_name) { g_debug ("Using session %s", session_name); - display_set_user_session (display, session_name); + display_set_user_session (display, type, session_name); } /* Stop this display if that session already exists and can switch to it */ @@ -474,7 +468,7 @@ autologin_authentication_complete_cb (Session *session, Display *display) if (session_name) { g_debug ("Autologin using session %s", session_name); - display_set_user_session (display, session_name); + display_set_user_session (display, SESSION_TYPE_LOCAL, session_name); } g_signal_emit (display, signals[START_SESSION], 0, &result); @@ -493,7 +487,7 @@ autologin_authentication_complete_cb (Session *session, Display *display) } static gboolean -autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail) +autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail, gboolean is_guest) { display->priv->start_greeter_if_fail = start_greeter_if_fail; @@ -502,7 +496,7 @@ autologin (Display *display, const gchar *username, const gchar *service, gboole 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); + return session_start (display->priv->session, service, username, TRUE, FALSE, is_guest); } static gboolean @@ -518,7 +512,7 @@ autologin_guest (Display *display, const gchar *service, gboolean start_greeter_ return FALSE; } - result = autologin (display, username, service, start_greeter_if_fail); + result = autologin (display, username, service, start_greeter_if_fail, TRUE); g_free (username); return result; @@ -700,12 +694,16 @@ display_start_session (Display *display) 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"); + if (display->priv->user_session_type == SESSION_TYPE_LOCAL) + { + sessions_dir = config_get_string (config_get_instance (), "LightDM", "xsessions-directory"); + + /* Store this session name so we automatically use it next time */ + user_set_xsession (user, display->priv->user_session); + } + else + sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory"); filename = g_strdup_printf ("%s.desktop", display->priv->user_session); path = g_build_filename (sessions_dir, filename, NULL); g_free (sessions_dir); @@ -777,12 +775,12 @@ display_server_ready_cb (DisplayServer *display_server, Display *display) else if (display->priv->autologin_user) { g_debug ("Automatically logging in user %s", display->priv->autologin_user); - result = autologin (display, display->priv->autologin_user, AUTOLOGIN_SERVICE, TRUE); + result = autologin (display, display->priv->autologin_user, AUTOLOGIN_SERVICE, TRUE, FALSE); } else if (display->priv->select_user_hint) { g_debug ("Logging in user %s", display->priv->select_user_hint); - result = autologin (display, display->priv->select_user_hint, USER_SERVICE, TRUE); + result = autologin (display, display->priv->select_user_hint, USER_SERVICE, TRUE, FALSE); } /* If no session started, start a greeter */ diff --git a/src/display.h b/src/display.h index e6a970b1..23d8c8ba 100644 --- a/src/display.h +++ b/src/display.h @@ -76,7 +76,7 @@ void display_set_show_manual_login_hint (Display *display, gboolean show_manual) void display_set_lock_hint (Display *display, gboolean is_lock); -void display_set_user_session (Display *display, const gchar *session_name); +void display_set_user_session (Display *display, SessionType type, const gchar *session_name); gboolean display_start (Display *display); diff --git a/src/greeter.c b/src/greeter.c index bcdc2ae3..5180fc82 100644 --- a/src/greeter.c +++ b/src/greeter.c @@ -18,6 +18,7 @@ #include "greeter.h" #include "ldm-marshal.h" +#include "configuration.h" enum { CONNECTED, @@ -48,6 +49,9 @@ struct GreeterPrivate /* Sequence number of current PAM session */ guint32 authentication_sequence_number; + /* Remote session name */ + gchar *remote_session; + /* PAM session being constructed by the greeter */ Session *authentication_session; @@ -76,7 +80,8 @@ typedef enum GREETER_MESSAGE_CONTINUE_AUTHENTICATION, GREETER_MESSAGE_START_SESSION, GREETER_MESSAGE_CANCEL_AUTHENTICATION, - GREETER_MESSAGE_SET_LANGUAGE + GREETER_MESSAGE_SET_LANGUAGE, + GREETER_MESSAGE_AUTHENTICATE_REMOTE } GreeterMessage; /* Messages from the server to the greeter */ @@ -293,6 +298,8 @@ authentication_complete_cb (Session *session, Greeter *greeter) static void reset_session (Greeter *greeter) { + g_free (greeter->priv->remote_session); + greeter->priv->remote_session = NULL; if (greeter->priv->authentication_session) { g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter); @@ -329,7 +336,7 @@ handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username) g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter); /* Run the session process */ - session_start (greeter->priv->authentication_session, greeter->priv->pam_service, username, TRUE, TRUE); + session_start (greeter->priv->authentication_session, greeter->priv->pam_service, username, TRUE, TRUE, FALSE); } static void @@ -350,6 +357,84 @@ handle_login_as_guest (Greeter *greeter, guint32 sequence_number) send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS); } +static gchar * +get_remote_session_service (const gchar *session_name) +{ + GKeyFile *session_desktop_file; + gboolean result; + const gchar *c; + gchar *remote_sessions_dir, *filename, *path, *service = NULL; + GError *error = NULL; + + /* Validate session name doesn't contain directory separators */ + for (c = session_name; *c; c++) + { + if (*c == '/') + return NULL; + } + + /* Load the session file */ + session_desktop_file = g_key_file_new (); + filename = g_strdup_printf ("%s.desktop", session_name); + remote_sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory"); + path = g_build_filename (remote_sessions_dir, filename, NULL); + g_free (remote_sessions_dir); + g_free (filename); + 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_free (path); + g_clear_error (&error); + if (result) + service = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-PAM-Service", NULL); + g_key_file_free (session_desktop_file); + + return service; +} + +static void +handle_login_remote (Greeter *greeter, const gchar *session_name, const gchar *username, guint32 sequence_number) +{ + gchar *service; + + if (username[0] == '\0') + { + g_debug ("Greeter start authentication for remote session %s", session_name); + username = NULL; + } + else + g_debug ("Greeter start authentication for remote session %s as user %s", session_name, username); + + reset_session (greeter); + + service = get_remote_session_service (session_name); + if (!service) + { + send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR); + return; + } + + greeter->priv->authentication_sequence_number = sequence_number; + greeter->priv->remote_session = g_strdup (session_name); + g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session); + if (greeter->priv->authentication_session) + { + 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); + + /* Run the session process */ + session_start (greeter->priv->authentication_session, service, username, TRUE, TRUE, TRUE); + } + + g_free (service); + + if (!greeter->priv->authentication_session) + { + send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN); + return; + } +} + static void handle_continue_authentication (Greeter *greeter, gchar **secrets) { @@ -412,10 +497,18 @@ handle_start_session (Greeter *greeter, const gchar *session) gboolean result; guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; + SessionType session_type = SESSION_TYPE_LOCAL; if (strcmp (session, "") == 0) session = NULL; + /* Use session type chosen in remote session */ + if (greeter->priv->remote_session) + { + session_type = SESSION_TYPE_REMOTE; + session = greeter->priv->remote_session; + } + if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session)) { if (session) @@ -423,7 +516,7 @@ handle_start_session (Greeter *greeter, const gchar *session) else g_debug ("Greeter requests default session"); greeter->priv->start_session = TRUE; - g_signal_emit (greeter, signals[START_SESSION], 0, session, &result); + g_signal_emit (greeter, signals[START_SESSION], 0, session_type, session, &result); } else { @@ -569,6 +662,12 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) sequence_number = read_int (greeter, &offset); handle_login_as_guest (greeter, sequence_number); break; + case GREETER_MESSAGE_AUTHENTICATE_REMOTE: + sequence_number = read_int (greeter, &offset); + session_name = read_string (greeter, &offset); + username = read_string (greeter, &offset); + handle_login_remote (greeter, session_name, username, sequence_number); + break; case GREETER_MESSAGE_CONTINUE_AUTHENTICATION: n_secrets = read_int (greeter, &offset); secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1)); @@ -654,7 +753,7 @@ greeter_start (Greeter *greeter, const gchar *service, const gchar *username) fcntl (to_greeter_pipe[1], F_SETFD, FD_CLOEXEC); fcntl (from_greeter_pipe[0], F_SETFD, FD_CLOEXEC); - result = session_start (greeter->priv->session, service, username, FALSE, FALSE); + result = session_start (greeter->priv->session, service, username, FALSE, FALSE, FALSE); /* Close the session ends of the pipe */ close (to_greeter_pipe[0]); @@ -670,7 +769,7 @@ greeter_real_start_authentication (Greeter *greeter, const gchar *username) } static gboolean -greeter_real_start_session (Greeter *greeter, const gchar *session, gboolean is_guest) +greeter_real_start_session (Greeter *greeter, SessionType type, const gchar *session) { return FALSE; } @@ -695,6 +794,7 @@ greeter_finalize (GObject *object) g_free (self->priv->pam_service); g_free (self->priv->read_buffer); g_hash_table_unref (self->priv->hints); + g_free (self->priv->remote_session); if (self->priv->authentication_session) { g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self); @@ -743,8 +843,8 @@ greeter_class_init (GreeterClass *klass) G_STRUCT_OFFSET (GreeterClass, start_session), g_signal_accumulator_true_handled, NULL, - ldm_marshal_BOOLEAN__STRING, - G_TYPE_BOOLEAN, 1, G_TYPE_STRING); + ldm_marshal_BOOLEAN__INT_STRING, + G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_STRING); g_type_class_add_private (klass, sizeof (GreeterPrivate)); } diff --git a/src/greeter.h b/src/greeter.h index 88fb2bc8..27801952 100644 --- a/src/greeter.h +++ b/src/greeter.h @@ -32,7 +32,7 @@ typedef struct GObjectClass parent_class; void (*connected)(Greeter *greeter); Session *(*start_authentication)(Greeter *greeter, const gchar *username); - gboolean (*start_session)(Greeter *greeter, const gchar *session, gboolean is_guest); + gboolean (*start_session)(Greeter *greeter, SessionType type, const gchar *session); } GreeterClass; GType greeter_get_type (void); diff --git a/src/ldm-marshal.list b/src/ldm-marshal.list index 57d376b9..9be211ac 100644 --- a/src/ldm-marshal.list +++ b/src/ldm-marshal.list @@ -1,6 +1,6 @@ VOID:INT,POINTER BOOLEAN:VOID -BOOLEAN:STRING +BOOLEAN:INT,STRING BOOLEAN:OBJECT STRING:VOID OBJECT:VOID diff --git a/src/lightdm.c b/src/lightdm.c index dce89f54..04fb59ef 100644 --- a/src/lightdm.c +++ b/src/lightdm.c @@ -817,6 +817,7 @@ main (int argc, char **argv) gboolean test_mode = FALSE; gchar *pid_path = "/var/run/lightdm.pid"; gchar *xsessions_dir = NULL; + gchar *remote_sessions_dir = NULL; gchar *xgreeters_dir = NULL; gchar *config_dir; gchar *log_dir = NULL; @@ -843,6 +844,9 @@ main (int argc, char **argv) { "xsessions-dir", 0, 0, G_OPTION_ARG_STRING, &xsessions_dir, /* Help string for command line --xsessions-dir flag */ N_("Directory to load X sessions from"), "DIRECTORY" }, + { "remote-sessions-dir", 0, 0, G_OPTION_ARG_STRING, &remote_sessions_dir, + /* Help string for command line --remote-sessions-dir flag */ + N_("Directory to load remote sessions from"), "DIRECTORY" }, { "xgreeters-dir", 0, 0, G_OPTION_ARG_STRING, &xgreeters_dir, /* Help string for command line --xgreeters-dir flag */ N_("Directory to load X greeters from"), "DIRECTORY" }, @@ -952,6 +956,7 @@ main (int argc, char **argv) /* Always use absolute directories as child processes may run from different locations */ xsessions_dir = path_make_absolute (xsessions_dir); + remote_sessions_dir = path_make_absolute (remote_sessions_dir); xgreeters_dir = path_make_absolute (xgreeters_dir); /* If not running as root write output to directories we control */ @@ -1019,6 +1024,8 @@ main (int argc, char **argv) g_free (default_cache_dir); if (!config_has_key (config_get_instance (), "LightDM", "xsessions-directory")) config_set_string (config_get_instance (), "LightDM", "xsessions-directory", XSESSIONS_DIR); + if (!config_has_key (config_get_instance (), "LightDM", "remote-sessions-directory")) + config_set_string (config_get_instance (), "LightDM", "remote-sessions-directory", REMOTE_SESSIONS_DIR); if (!config_has_key (config_get_instance (), "LightDM", "xgreeters-directory")) config_set_string (config_get_instance (), "LightDM", "xgreeters-directory", XGREETERS_DIR); @@ -1035,6 +1042,9 @@ main (int argc, char **argv) if (xsessions_dir) config_set_string (config_get_instance (), "LightDM", "xsessions-directory", xsessions_dir); g_free (xsessions_dir); + if (remote_sessions_dir) + config_set_string (config_get_instance (), "LightDM", "remote-sessions-directory", remote_sessions_dir); + g_free (remote_sessions_dir); if (xgreeters_dir) config_set_string (config_get_instance (), "LightDM", "xgreeters-directory", xgreeters_dir); g_free (xgreeters_dir); @@ -390,7 +390,6 @@ session_stopped_cb (Session *session, Seat *seat) 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); seat->priv->guest_username = NULL; } @@ -496,7 +495,7 @@ switch_to_user_or_start_greeter (Seat *seat, const gchar *username, gboolean use display_set_select_user_hint (display, username, is_guest); if (!session_name) session_name = seat_get_string_property (seat, "user-session"); - display_set_user_session (display, session_name); + display_set_user_session (display, SESSION_TYPE_LOCAL, session_name); seat->priv->displays = g_list_append (seat->priv->displays, display); g_signal_emit (seat, signals[DISPLAY_ADDED], 0, display); diff --git a/src/session.c b/src/session.c index 3bf34d6f..fd2af4cc 100644 --- a/src/session.c +++ b/src/session.c @@ -22,6 +22,7 @@ #include "session.h" #include "configuration.h" #include "console-kit.h" +#include "guest-account.h" enum { GOT_MESSAGES, @@ -46,6 +47,9 @@ struct SessionPrivate /* User to authenticate as */ gchar *username; + /* TRUE if is a guest account */ + gboolean is_guest; + /* User object that matches the current username */ User *user; @@ -235,6 +239,10 @@ session_watch_cb (GPid pid, gint status, gpointer data) g_signal_emit (G_OBJECT (session), signals[STOPPED], 0); + /* Delete account if it is a guest one */ + if (session->priv->is_guest) + guest_account_cleanup (session->priv->username); + /* Drop our reference on the child process, it has terminated */ g_object_unref (session); } @@ -316,7 +324,7 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data) } gboolean -session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive) +session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive, gboolean is_guest) { int version; int to_child_pipe[2], from_child_pipe[2]; @@ -343,6 +351,11 @@ session_start (Session *session, const gchar *service, const gchar *username, gb fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC); fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC); + /* Create the guest account if it is one */ + session->priv->is_guest = is_guest; + if (is_guest && username == NULL) + username = guest_account_setup (); + /* Remember what username we started with - it will be updated by PAM during authentication */ session->priv->username = g_strdup (username); @@ -353,6 +366,7 @@ session_start (Session *session, const gchar *service, const gchar *username, gb g_debug ("Failed to fork session child process: %s", strerror (errno)); return FALSE; } + if (session->priv->pid == 0) { /* Run us again in session child mode */ diff --git a/src/session.h b/src/session.h index a574726a..52a6e9e8 100644 --- a/src/session.h +++ b/src/session.h @@ -43,6 +43,12 @@ typedef struct void (*stopped)(Session *session); } SessionClass; +typedef enum +{ + SESSION_TYPE_LOCAL, + SESSION_TYPE_REMOTE +} SessionType; + #define XDG_SESSION_CLASS_USER "user" #define XDG_SESSION_CLASS_GREETER "greeter" #define XDG_SESSION_CLASS_LOCK_SCREEN "lock-screen" @@ -66,7 +72,7 @@ void session_set_env (Session *session, const gchar *name, const gchar *value); // FIXME: Remove User *session_get_user (Session *session); -gboolean session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive); +gboolean session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive, gboolean is_guest); const gchar *session_get_username (Session *session); diff --git a/tests/Makefile.am b/tests/Makefile.am index 7d87c3ab..9e41117e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -70,6 +70,7 @@ TESTS = \ test-login-gobject-guest-no-setup-script \ test-login-gobject-guest-fail-setup-script \ test-login-gobject-guest-logout \ + test-login-gobject-remote-session \ test-login-python \ test-login-python-manual \ test-login-python-manual-previous-session \ @@ -91,6 +92,7 @@ TESTS = \ test-login-python-guest-no-setup-script \ test-login-python-guest-fail-setup-script \ test-login-python-guest-logout \ + test-login-python-remote-session \ test-login-session-crash \ test-login-xserver-crash \ test-home-dir-on-authenticate \ @@ -147,7 +149,8 @@ TESTS += \ test-login-qt-guest-disabled \ test-login-qt-guest-no-setup-script \ test-login-qt-guest-fail-setup-script \ - test-login-qt-guest-logout + test-login-qt-guest-logout \ + test-login-qt-remote-session endif EXTRA_DIST = \ @@ -214,8 +217,9 @@ EXTRA_DIST = \ scripts/login-pam.conf \ scripts/login-pick-session.conf \ scripts/login-previous-session.conf \ - scripts/login-two-factor.conf \ + scripts/login-remote-session.conf \ scripts/login-session-crash.conf \ + scripts/login-two-factor.conf \ scripts/login-wrong-password.conf \ scripts/login-xserver-crash.conf \ scripts/no-accounts-service.conf \ diff --git a/tests/data/remote-sessions/test-remote.desktop b/tests/data/remote-sessions/test-remote.desktop new file mode 100644 index 00000000..60829d44 --- /dev/null +++ b/tests/data/remote-sessions/test-remote.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Test Remote Session +Comment=LightDM remote test session +Exec=test-session +X-LightDM-PAM-Service=test-remote diff --git a/tests/scripts/autologin-guest-logout.conf b/tests/scripts/autologin-guest-logout.conf index cb1146b5..51a6b9ac 100644 --- a/tests/scripts/autologin-guest-logout.conf +++ b/tests/scripts/autologin-guest-logout.conf @@ -28,12 +28,12 @@ autologin-guest=true # Logout of session #?*SESSION :50 LOGOUT -# Guest account removed -#?GUEST-ACCOUNT REMOVE USERNAME=guest-.* - # X server stops #?XSERVER :50 TERMINATE SIGNAL=15 +# Guest account removed +#?GUEST-ACCOUNT REMOVE USERNAME=guest-.* + # X server starts #?XSERVER :50 START #?XSERVER :50 INDICATE-READY diff --git a/tests/scripts/login-guest-logout.conf b/tests/scripts/login-guest-logout.conf index 27723626..1dcf3ceb 100644 --- a/tests/scripts/login-guest-logout.conf +++ b/tests/scripts/login-guest-logout.conf @@ -38,12 +38,12 @@ minimum-display-number=50 # Logout of session #?*SESSION :50 LOGOUT -# Guest account removed -#?GUEST-ACCOUNT REMOVE USERNAME=guest-.* - # X server stops #?XSERVER :50 TERMINATE SIGNAL=15 +# Guest account removed +#?GUEST-ACCOUNT REMOVE USERNAME=guest-.* + # X server starts #?XSERVER :50 START #?XSERVER :50 INDICATE-READY diff --git a/tests/scripts/login-remote-session.conf b/tests/scripts/login-remote-session.conf new file mode 100644 index 00000000..b24a89f8 --- /dev/null +++ b/tests/scripts/login-remote-session.conf @@ -0,0 +1,50 @@ +# +# Check can login without a username, and is prompted for one +# + +[LightDM] +minimum-display-number=50 + +#?RUNNER DAEMON-START + +# X server starts +#?XSERVER :50 START +#?XSERVER :50 INDICATE-READY + +# LightDM connects to X server +#?XSERVER :50 ACCEPT-CONNECT + +# Greeter starts +#?GREETER :50 START +#?XSERVER :50 ACCEPT-CONNECT +#?GREETER :50 CONNECT-XSERVER +#?GREETER :50 CONNECT-TO-DAEMON +#?GREETER :50 CONNECTED-TO-DAEMON + +# Start remote authentication +#?*GREETER :50 AUTHENTICATE-REMOTE SESSION=test-remote + +# Guest account created +#?GUEST-ACCOUNT ADD USERNAME=guest-.* + +# Get remote credentials +#?GREETER :50 SHOW-PROMPT TEXT="remote-login:" +#?*GREETER :50 RESPOND TEXT="remote-user" +#?GREETER :50 SHOW-PROMPT TEXT="remote-password:" +#?*GREETER :50 RESPOND TEXT="password" +#?GREETER :50 AUTHENTICATION-COMPLETE USERNAME=guest-.* AUTHENTICATED=TRUE +#?*GREETER :50 START-SESSION +#?GREETER :50 TERMINATE SIGNAL=15 + +# Session starts +#?SESSION :50 START USER=guest-.* +#?XSERVER :50 ACCEPT-CONNECT +#?SESSION :50 CONNECT-XSERVER + +# Cleanup +#?*STOP-DAEMON +# Don't know what order they will terminate +#?(SESSION :50 TERMINATE SIGNAL=15|XSERVER :50 TERMINATE SIGNAL=15|GUEST-ACCOUNT REMOVE USERNAME=guest-.*) +#?(SESSION :50 TERMINATE SIGNAL=15|XSERVER :50 TERMINATE SIGNAL=15|GUEST-ACCOUNT REMOVE USERNAME=guest-.*) +#?(SESSION :50 TERMINATE SIGNAL=15|XSERVER :50 TERMINATE SIGNAL=15|GUEST-ACCOUNT REMOVE USERNAME=guest-.*) +#?RUNNER DAEMON-EXIT STATUS=0 diff --git a/tests/src/libsystem.c b/tests/src/libsystem.c index 855f668b..9e137339 100644 --- a/tests/src/libsystem.c +++ b/tests/src/libsystem.c @@ -26,6 +26,8 @@ struct pam_handle { char *service_name; char *user; + char *authtok; + char *ruser; char *tty; char **envlist; struct pam_conv conversation; @@ -435,6 +437,8 @@ pam_start (const char *service_name, const char *user, const struct pam_conv *co handle->service_name = strdup (service_name); handle->user = user ? strdup (user) : NULL; + handle->authtok = NULL; + handle->ruser = NULL; handle->tty = NULL; handle->conversation.conv = conversation->conv; handle->conversation.appdata_ptr = conversation->appdata_ptr; @@ -473,6 +477,68 @@ pam_authenticate (pam_handle_t *pamh, int flags) if (pamh == NULL) return PAM_SYSTEM_ERR; + + if (strcmp (pamh->service_name, "test-remote") == 0) + { + int result; + struct pam_message **msg; + struct pam_response *resp = NULL; + + msg = malloc (sizeof (struct pam_message *) * 1); + msg[0] = malloc (sizeof (struct pam_message)); + msg[0]->msg_style = PAM_PROMPT_ECHO_ON; + msg[0]->msg = "remote-login:"; + result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr); + free (msg[0]); + free (msg); + if (result != PAM_SUCCESS) + return result; + + if (resp == NULL) + return PAM_CONV_ERR; + if (resp[0].resp == NULL) + { + free (resp); + return PAM_CONV_ERR; + } + + if (pamh->ruser) + free (pamh->ruser); + pamh->ruser = strdup (resp[0].resp); + free (resp[0].resp); + free (resp); + + msg = malloc (sizeof (struct pam_message *) * 1); + msg[0] = malloc (sizeof (struct pam_message)); + msg[0]->msg_style = PAM_PROMPT_ECHO_OFF; + msg[0]->msg = "remote-password:"; + result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr); + free (msg[0]); + free (msg); + if (result != PAM_SUCCESS) + return result; + + if (resp == NULL) + return PAM_CONV_ERR; + if (resp[0].resp == NULL) + { + free (resp); + return PAM_CONV_ERR; + } + + if (pamh->authtok) + free (pamh->authtok); + pamh->authtok = strdup (resp[0].resp); + free (resp[0].resp); + free (resp); + + password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0; + + if (password_matches) + return PAM_SUCCESS; + else + return PAM_AUTH_ERR; + } /* Prompt for username */ if (pamh->user == NULL) @@ -738,7 +804,15 @@ pam_get_item (const pam_handle_t *pamh, int item_type, const void **item) case PAM_USER: *item = pamh->user; return PAM_SUCCESS; - + + case PAM_AUTHTOK: + *item = pamh->authtok; + return PAM_SUCCESS; + + case PAM_RUSER: + *item = pamh->ruser; + return PAM_SUCCESS; + case PAM_USER_PROMPT: *item = LOGIN_PROMPT; return PAM_SUCCESS; @@ -911,6 +985,10 @@ pam_end (pam_handle_t *pamh, int pam_status) free (pamh->service_name); if (pamh->user) free (pamh->user); + if (pamh->authtok) + free (pamh->authtok); + if (pamh->ruser) + free (pamh->ruser); if (pamh->tty) free (pamh->tty); free (pamh); diff --git a/tests/src/test-gobject-greeter.c b/tests/src/test-gobject-greeter.c index f5057cfb..e114dd18 100644 --- a/tests/src/test-gobject-greeter.c +++ b/tests/src/test-gobject-greeter.c @@ -65,6 +65,11 @@ request_cb (const gchar *request) lightdm_greeter_authenticate_as_guest (greeter); g_free (r); + r = g_strdup_printf ("GREETER %s AUTHENTICATE-REMOTE SESSION=", getenv ("DISPLAY")); + if (g_str_has_prefix (request, r)) + lightdm_greeter_authenticate_remote (greeter, request + strlen (r), NULL); + g_free (r); + r = g_strdup_printf ("GREETER %s RESPOND TEXT=\"", getenv ("DISPLAY")); if (g_str_has_prefix (request, r)) { diff --git a/tests/src/test-python-greeter b/tests/src/test-python-greeter index fe26af39..87aa6c7a 100755 --- a/tests/src/test-python-greeter +++ b/tests/src/test-python-greeter @@ -45,6 +45,10 @@ def request_cb (channel, condition): if request.startswith (r): greeter.authenticate (request[len(r):]) + r = 'GREETER %s AUTHENTICATE-REMOTE SESSION=' % os.getenv ('DISPLAY') + if request.startswith (r): + greeter.authenticate_remote (request[len(r):], None) + r = 'GREETER %s AUTHENTICATE-GUEST' % os.getenv ('DISPLAY') if request == r: greeter.authenticate_as_guest () diff --git a/tests/src/test-qt-greeter.cpp b/tests/src/test-qt-greeter.cpp index 49b42e08..1019a6ab 100644 --- a/tests/src/test-qt-greeter.cpp +++ b/tests/src/test-qt-greeter.cpp @@ -68,6 +68,11 @@ request_cb (const gchar *request) greeter->authenticateAsGuest (); g_free (r); + r = g_strdup_printf ("GREETER %s AUTHENTICATE-REMOTE SESSION=", getenv ("DISPLAY")); + if (g_str_has_prefix (request, r)) + greeter->authenticateRemote (request + strlen (r), NULL); + g_free (r); + r = g_strdup_printf ("GREETER %s RESPOND TEXT=\"", getenv ("DISPLAY")); if (g_str_has_prefix (request, r)) { diff --git a/tests/src/test-runner.c b/tests/src/test-runner.c index 516a6788..80560158 100644 --- a/tests/src/test-runner.c +++ b/tests/src/test-runner.c @@ -1138,6 +1138,7 @@ run_lightdm () g_string_append (command_line, " --debug"); g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir); g_string_append_printf (command_line, " --xsessions-dir=%s/usr/share/xsessions", temp_dir); + g_string_append_printf (command_line, " --remote-sessions-dir=%s/usr/share/remote-sessions", temp_dir); g_string_append_printf (command_line, " --xgreeters-dir=%s/usr/share/xgreeters", temp_dir); g_print ("Start daemon with command: PATH=%s LD_PRELOAD=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_ROOT=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n", @@ -1302,6 +1303,8 @@ main (int argc, char **argv) /* Copy over the greeter files */ if (system (g_strdup_printf ("cp -r %s/xsessions %s/usr/share", DATADIR, temp_dir))) perror ("Failed to copy xsessions"); + if (system (g_strdup_printf ("cp -r %s/remote-sessions %s/usr/share", DATADIR, temp_dir))) + perror ("Failed to copy remote sessions"); if (system (g_strdup_printf ("cp -r %s/xgreeters %s/usr/share", DATADIR, temp_dir))) perror ("Failed to copy xgreeters"); diff --git a/tests/test-login-gobject-remote-session b/tests/test-login-gobject-remote-session new file mode 100755 index 00000000..833ca04c --- /dev/null +++ b/tests/test-login-gobject-remote-session @@ -0,0 +1,2 @@ +#!/bin/sh +./src/dbus-env ./src/test-runner login-remote-session test-gobject-greeter diff --git a/tests/test-login-python-remote-session b/tests/test-login-python-remote-session new file mode 100755 index 00000000..4ac1a6f6 --- /dev/null +++ b/tests/test-login-python-remote-session @@ -0,0 +1,2 @@ +#!/bin/sh +./src/dbus-env ./src/test-runner login-remote-session test-python-greeter diff --git a/tests/test-login-qt-remote-session b/tests/test-login-qt-remote-session new file mode 100755 index 00000000..427afe47 --- /dev/null +++ b/tests/test-login-qt-remote-session @@ -0,0 +1,2 @@ +#!/bin/sh +./src/dbus-env ./src/test-runner login-remote-session test-qt-greeter |