summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2012-08-30 09:27:02 +1200
committerRobert Ancell <robert.ancell@canonical.com>2012-08-30 09:27:02 +1200
commitd7b170903f9bca5acf02c1d52cdd8209fcf6b3bf (patch)
tree26a9c2f15bf4c017aa2137f82126e18fd5994874
parent14b05e763d12a3013e50f5b088ea2c04d9dfa38a (diff)
parentc8e18e61ce4a83bb722183d1b873be8a3c8a263d (diff)
downloadlightdm-d7b170903f9bca5acf02c1d52cdd8209fcf6b3bf.tar.gz
Add remote sessions
-rw-r--r--NEWS6
-rw-r--r--data/lightdm.conf2
-rw-r--r--liblightdm-gobject/Makefile.am3
-rw-r--r--liblightdm-gobject/greeter.c44
-rw-r--r--liblightdm-gobject/liblightdm-gobject-1.vapi2
-rw-r--r--liblightdm-gobject/lightdm/greeter.h4
-rw-r--r--liblightdm-gobject/lightdm/session.h2
-rw-r--r--liblightdm-gobject/session.c117
-rw-r--r--liblightdm-qt/QLightDM/greeter.h1
-rw-r--r--liblightdm-qt/greeter.cpp7
-rw-r--r--src/Makefile.am1
-rw-r--r--src/display.c44
-rw-r--r--src/display.h2
-rw-r--r--src/greeter.c114
-rw-r--r--src/greeter.h2
-rw-r--r--src/ldm-marshal.list2
-rw-r--r--src/lightdm.c10
-rw-r--r--src/seat.c3
-rw-r--r--src/session.c16
-rw-r--r--src/session.h8
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/data/remote-sessions/test-remote.desktop5
-rw-r--r--tests/scripts/autologin-guest-logout.conf6
-rw-r--r--tests/scripts/login-guest-logout.conf6
-rw-r--r--tests/scripts/login-remote-session.conf50
-rw-r--r--tests/src/libsystem.c80
-rw-r--r--tests/src/test-gobject-greeter.c5
-rwxr-xr-xtests/src/test-python-greeter4
-rw-r--r--tests/src/test-qt-greeter.cpp5
-rw-r--r--tests/src/test-runner.c3
-rwxr-xr-xtests/test-login-gobject-remote-session2
-rwxr-xr-xtests/test-login-python-remote-session2
-rwxr-xr-xtests/test-login-qt-remote-session2
33 files changed, 479 insertions, 89 deletions
diff --git a/NEWS b/NEWS
index 7d354f75..b4efe936 100644
--- a/NEWS
+++ b/NEWS
@@ -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);
diff --git a/src/seat.c b/src/seat.c
index 685cf3d0..f055f389 100644
--- a/src/seat.c
+++ b/src/seat.c
@@ -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