summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2016-06-29 15:15:44 +1200
committerRobert Ancell <robert.ancell@canonical.com>2016-06-29 15:15:44 +1200
commit56d22cc50e4b8ecd96e6c828b2d4e3c3a5efae51 (patch)
treebc0b9334e111f05ec9efca2646b53b3d83c641e8
parent420353d31b89352674a08d0e7dd48f0486019e5c (diff)
downloadlightdm-git-56d22cc50e4b8ecd96e6c828b2d4e3c3a5efae51.tar.gz
Allow greeters to run in-session
-rw-r--r--liblightdm-gobject/greeter.c113
-rw-r--r--src/Makefile.am2
-rw-r--r--src/greeter-session.c42
-rw-r--r--src/greeter-socket.c152
-rw-r--r--src/greeter-socket.h50
-rw-r--r--src/greeter.c37
-rw-r--r--src/greeter.h8
-rw-r--r--src/seat.c70
-rw-r--r--src/session-config.c11
-rw-r--r--src/session-config.h2
-rw-r--r--src/session.c57
-rw-r--r--src/session.h15
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/data/sessions/greeter.desktop5
-rw-r--r--tests/scripts/session-greeter.conf59
-rw-r--r--tests/src/Makefile.am3
-rw-r--r--tests/src/libsystem.c106
-rw-r--r--tests/src/test-session.c65
-rwxr-xr-xtests/test-session-greeter2
19 files changed, 665 insertions, 137 deletions
diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c
index 5e6996d3..6c279b2c 100644
--- a/liblightdm-gobject/greeter.c
+++ b/liblightdm-gobject/greeter.c
@@ -12,6 +12,8 @@
#include <stdlib.h>
#include <string.h>
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
#include <security/pam_appl.h>
#include "lightdm/greeter.h"
@@ -50,6 +52,9 @@ typedef struct
/* TRUE if the daemon can reuse this greeter */
gboolean resettable;
+ /* Socket connection to daemon */
+ GSocket *socket;
+
/* Channel to write to daemon */
GIOChannel *to_server_channel;
@@ -141,6 +146,8 @@ static void request_iface_init (GAsyncResultIface *iface);
#define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init));
+static gboolean from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data);
+
GType
lightdm_prompt_type_get_type (void)
{
@@ -347,6 +354,66 @@ get_message_length (guint8 *message, gsize message_length)
}
static gboolean
+connect_to_daemon (LightDMGreeter *greeter)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ const gchar *to_server_fd, *from_server_fd, *pipe_path;
+ GError *error = NULL;
+
+ if (priv->to_server_channel || priv->from_server_channel)
+ return TRUE;
+
+ /* Use private connection if one exists */
+ to_server_fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
+ from_server_fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
+ pipe_path = g_getenv ("LIGHTDM_GREETER_PIPE");
+ if (to_server_fd && from_server_fd)
+ {
+ priv->to_server_channel = g_io_channel_unix_new (atoi (to_server_fd));
+ priv->from_server_channel = g_io_channel_unix_new (atoi (from_server_fd));
+ }
+ else if (pipe_path)
+ {
+ GSocketAddress *address;
+ gboolean result;
+
+ priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
+ if (!priv->socket)
+ return FALSE;
+
+ address = g_unix_socket_address_new (pipe_path);
+ result = g_socket_connect (priv->socket, address, NULL, &error);
+ g_object_unref (address);
+ if (!result)
+ {
+ g_warning ("Failed to connect to greeter socket %s: %s", pipe_path, error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ priv->from_server_channel = g_io_channel_unix_new (g_socket_get_fd (priv->socket));
+ priv->to_server_channel = g_io_channel_ref (priv->from_server_channel);
+ }
+ else
+ {
+ g_warning ("Unable to determine socket to daemon");
+ return FALSE;
+ }
+
+ g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
+
+ if (!g_io_channel_set_encoding (priv->to_server_channel, NULL, &error) ||
+ !g_io_channel_set_encoding (priv->from_server_channel, NULL, &error))
+ {
+ g_warning ("Failed to set encoding on from server channel to binary: %s", error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
@@ -355,7 +422,7 @@ send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
GError *error = NULL;
guint32 stated_length;
- if (!priv->to_server_channel)
+ if (!connect_to_daemon (greeter))
return FALSE;
/* Double check that we're sending well-formed messages. If we say we're
@@ -381,6 +448,8 @@ send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
if (error)
g_warning ("Error writing to daemon: %s", error->message);
g_clear_error (&error);
+ if (status == G_IO_STATUS_AGAIN)
+ continue;
if (status != G_IO_STATUS_NORMAL)
return FALSE;
data_length -= n_written;
@@ -660,8 +729,8 @@ recv_message (LightDMGreeter *greeter, gsize *length, gboolean block)
guint8 *buffer;
GError *error = NULL;
- if (!priv->from_server_channel)
- return NULL;
+ if (!connect_to_daemon (greeter))
+ return FALSE;
/* Read the header, or the whole message if we already have that */
n_to_read = HEADER_SIZE;
@@ -679,7 +748,12 @@ recv_message (LightDMGreeter *greeter, gsize *length, gboolean block)
if (error)
g_warning ("Error reading from server: %s", error->message);
g_clear_error (&error);
- if (status != G_IO_STATUS_NORMAL)
+ if (status == G_IO_STATUS_AGAIN)
+ {
+ if (block)
+ continue;
+ }
+ else if (status != G_IO_STATUS_NORMAL)
break;
g_debug ("Read %zi bytes from daemon", n_read);
@@ -1590,39 +1664,9 @@ static void
lightdm_greeter_init (LightDMGreeter *greeter)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
- const gchar *fd;
priv->read_buffer = g_malloc (HEADER_SIZE);
priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
- if (fd)
- {
- GError *error = NULL;
-
- priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
- g_io_channel_set_encoding (priv->to_server_channel, NULL, &error);
- if (error)
- g_warning ("Failed to set encoding on to server channel to binary: %s\n", error->message);
- g_clear_error (&error);
- }
- else
- g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
-
- fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
- if (fd)
- {
- GError *error = NULL;
-
- priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
- g_io_channel_set_encoding (priv->from_server_channel, NULL, &error);
- if (error)
- g_warning ("Failed to set encoding on from server channel to binary: %s\n", error->message);
- g_clear_error (&error);
- g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
- }
- else
- g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
}
static void
@@ -1699,6 +1743,7 @@ lightdm_greeter_finalize (GObject *object)
LightDMGreeter *self = LIGHTDM_GREETER (object);
LightDMGreeterPrivate *priv = GET_PRIVATE (self);
+ g_clear_object (&priv->socket);
if (priv->to_server_channel)
g_io_channel_unref (priv->to_server_channel);
if (priv->from_server_channel)
diff --git a/src/Makefile.am b/src/Makefile.am
index dc6d40dc..849ba1d3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,6 +14,8 @@ lightdm_SOURCES = \
greeter.h \
greeter-session.c \
greeter-session.h \
+ greeter-socket.c \
+ greeter-socket.h \
guest-account.c \
guest-account.h \
lightdm.c \
diff --git a/src/greeter-session.c b/src/greeter-session.c
index 0241dbdf..862253a0 100644
--- a/src/greeter-session.c
+++ b/src/greeter-session.c
@@ -13,6 +13,7 @@
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include "greeter-session.h"
@@ -42,27 +43,46 @@ greeter_session_get_greeter (GreeterSession *session)
}
static gboolean
-setup_cb (Greeter *greeter, int input_fd, int output_fd, gpointer user_data)
+greeter_session_start (Session *session)
{
- Session *session = user_data;
+ GreeterSession *s = GREETER_SESSION (session);
+ int to_greeter_pipe[2], from_greeter_pipe[2];
+ int to_greeter_input, to_greeter_output, from_greeter_input, from_greeter_output;
gchar *value;
+ gboolean result;
+
+ /* Create a pipe to talk with the greeter */
+ if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0)
+ {
+ g_warning ("Failed to create pipes: %s", strerror (errno));
+ return FALSE;
+ }
+
+ to_greeter_input = to_greeter_pipe[1];
+ to_greeter_output = to_greeter_pipe[0];
+ from_greeter_input = from_greeter_pipe[1];
+ from_greeter_output = from_greeter_pipe[0];
+ greeter_set_file_descriptors (s->priv->greeter, to_greeter_input, from_greeter_output);
+
+ /* Don't allow the daemon end of the pipes to be accessed in child processes */
+ fcntl (to_greeter_input, F_SETFD, FD_CLOEXEC);
+ fcntl (from_greeter_output, F_SETFD, FD_CLOEXEC);
/* Let the greeter session know how to communicate with the daemon */
- value = g_strdup_printf ("%d", input_fd);
+ value = g_strdup_printf ("%d", from_greeter_input);
session_set_env (session, "LIGHTDM_TO_SERVER_FD", value);
g_free (value);
- value = g_strdup_printf ("%d", output_fd);
+ value = g_strdup_printf ("%d", to_greeter_output);
session_set_env (session, "LIGHTDM_FROM_SERVER_FD", value);
g_free (value);
- return SESSION_CLASS (greeter_session_parent_class)->start (session);
-}
+ result = SESSION_CLASS (greeter_session_parent_class)->start (session);
-static gboolean
-greeter_session_start (Session *session)
-{
- GreeterSession *s = GREETER_SESSION (session);
- return greeter_start (s->priv->greeter, setup_cb, session);
+ /* Close the session ends of the pipe */
+ close (from_greeter_input);
+ close (to_greeter_output);
+
+ return result;
}
static void
diff --git a/src/greeter-socket.c b/src/greeter-socket.c
new file mode 100644
index 00000000..4e2b7a33
--- /dev/null
+++ b/src/greeter-socket.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2010-2016 Canonical Ltd.
+ *
+ * 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 <config.h>
+
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
+
+#include "greeter-socket.h"
+
+enum {
+ CREATE_GREETER,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct GreeterSocketPrivate
+{
+ /* Path of socket to use */
+ gchar *path;
+
+ /* Listening UNIX socket */
+ GSocket *socket;
+
+ /* Source for listening for connections */
+ GSource *source;
+
+ /* Socket to greeter */
+ GSocket *greeter_socket;
+
+ /* Greeter connected on this socket */
+ Greeter *greeter;
+};
+
+G_DEFINE_TYPE (GreeterSocket, greeter_socket, G_TYPE_OBJECT);
+
+GreeterSocket *
+greeter_socket_new (const gchar *path)
+{
+ GreeterSocket *socket;
+
+ socket = g_object_new (GREETER_SOCKET_TYPE, NULL);
+ socket->priv->path = g_strdup (path);
+
+ return socket;
+}
+
+static gboolean
+greeter_connect_cb (GSocket *s, GIOCondition condition, GreeterSocket *socket)
+{
+ GSocket *new_socket;
+ GError *error = NULL;
+
+ new_socket = g_socket_accept (socket->priv->socket, NULL, &error);
+ if (error)
+ g_warning ("Failed to accept greeter connection: %s", error->message);
+ g_clear_error (&error);
+ if (!new_socket)
+ return G_SOURCE_CONTINUE;
+
+ /* Greeter already connected */
+ if (socket->priv->greeter)
+ {
+ g_socket_close (new_socket, NULL);
+ g_object_unref (new_socket);
+ return G_SOURCE_CONTINUE;
+ }
+
+ socket->priv->greeter_socket = new_socket;
+ g_signal_emit (socket, signals[CREATE_GREETER], 0, &socket->priv->greeter);
+ greeter_set_file_descriptors (socket->priv->greeter, g_socket_get_fd (new_socket), g_socket_get_fd (new_socket));
+
+ return G_SOURCE_CONTINUE;
+}
+
+gboolean
+greeter_socket_start (GreeterSocket *socket, GError **error)
+{
+ GSocketAddress *address;
+ gboolean result;
+
+ g_return_val_if_fail (socket != NULL, FALSE);
+ g_return_val_if_fail (socket->priv->socket == NULL, FALSE);
+
+ socket->priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
+ if (!socket->priv->socket)
+ return FALSE;
+
+ unlink (socket->priv->path);
+ address = g_unix_socket_address_new (socket->priv->path);
+ result = g_socket_bind (socket->priv->socket, address, FALSE, error);
+ g_object_unref (address);
+ if (!result)
+ return FALSE;
+ if (!g_socket_listen (socket->priv->socket, error))
+ return FALSE;
+
+ socket->priv->source = g_socket_create_source (socket->priv->socket, G_IO_IN, NULL);
+ g_source_set_callback (socket->priv->source, (GSourceFunc) greeter_connect_cb, socket, NULL);
+ g_source_attach (socket->priv->source, NULL);
+
+ return TRUE;
+}
+
+static void
+greeter_socket_init (GreeterSocket *socket)
+{
+ socket->priv = G_TYPE_INSTANCE_GET_PRIVATE (socket, GREETER_SOCKET_TYPE, GreeterSocketPrivate);
+}
+
+static void
+greeter_socket_finalize (GObject *object)
+{
+ GreeterSocket *self = GREETER_SOCKET (object);
+
+ if (self->priv->path)
+ unlink (self->priv->path);
+ g_free (self->priv->path);
+ g_clear_object (&self->priv->socket);
+ g_clear_object (&self->priv->source);
+ g_clear_object (&self->priv->greeter_socket);
+ g_clear_object (&self->priv->greeter);
+
+ G_OBJECT_CLASS (greeter_socket_parent_class)->finalize (object);
+}
+
+static void
+greeter_socket_class_init (GreeterSocketClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = greeter_socket_finalize;
+
+ signals[CREATE_GREETER] =
+ g_signal_new (GREETER_SOCKET_SIGNAL_CREATE_GREETER,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GreeterSocketClass, create_greeter),
+ g_signal_accumulator_first_wins,
+ NULL,
+ NULL,
+ GREETER_TYPE, 0);
+
+ g_type_class_add_private (klass, sizeof (GreeterSocketPrivate));
+}
diff --git a/src/greeter-socket.h b/src/greeter-socket.h
new file mode 100644
index 00000000..da490bad
--- /dev/null
+++ b/src/greeter-socket.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010-2016 Canonical Ltd.
+ *
+ * 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 GREETER_SOCKET_H_
+#define GREETER_SOCKET_H_
+
+#include <glib-object.h>
+
+#include "greeter.h"
+
+G_BEGIN_DECLS
+
+#define GREETER_SOCKET_TYPE (greeter_socket_get_type())
+#define GREETER_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GREETER_SOCKET_TYPE, GreeterSocket))
+#define GREETER_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GREETER_SOCKET_TYPE, GreeterSocketClass))
+#define GREETER_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GREETER_SOCKET_TYPE, GreeterSocketClass))
+#define IS_GREETER_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GREETER_SOCKET_TYPE))
+
+#define GREETER_SOCKET_SIGNAL_CREATE_GREETER "create-greeter"
+
+typedef struct GreeterSocketPrivate GreeterSocketPrivate;
+
+typedef struct
+{
+ GObject parent_instance;
+ GreeterSocketPrivate *priv;
+} GreeterSocket;
+
+typedef struct
+{
+ GObjectClass parent_class;
+ Greeter *(*create_greeter)(GreeterSocket *socket);
+} GreeterSocketClass;
+
+GType greeter_socket_get_type (void);
+
+GreeterSocket *greeter_socket_new (const gchar *path);
+
+gboolean greeter_socket_start (GreeterSocket *socket, GError **error);
+
+G_END_DECLS
+
+#endif /* GREETER_SOCKET_H_ */
diff --git a/src/greeter.c b/src/greeter.c
index 72eaa2e7..4534ee2f 100644
--- a/src/greeter.c
+++ b/src/greeter.c
@@ -12,8 +12,6 @@
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
#include <gcrypt.h>
#include "greeter.h"
@@ -118,29 +116,22 @@ greeter_new (void)
return g_object_new (GREETER_TYPE, NULL);
}
-gboolean
-greeter_start (Greeter *greeter, gboolean (*setup_child_cb)(Greeter *greeter, int input_fd, int output_fd, gpointer user_data), gpointer user_data)
+void
+greeter_set_file_descriptors (Greeter *greeter, int to_greeter_fd, int from_greeter_fd)
{
- int to_greeter_pipe[2], from_greeter_pipe[2];
- int to_greeter_output, from_greeter_input;
- gboolean result;
GError *error = NULL;
- /* Create a pipe to talk with the greeter */
- if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0)
- {
- g_warning ("Failed to create pipes: %s", strerror (errno));
- return FALSE;
- }
- to_greeter_output = to_greeter_pipe[0];
- greeter->priv->to_greeter_input = to_greeter_pipe[1];
+ g_return_if_fail (greeter != NULL);
+ g_return_if_fail (greeter->priv->to_greeter_input < 0);
+ g_return_if_fail (greeter->priv->from_greeter_output < 0);
+
+ greeter->priv->to_greeter_input = to_greeter_fd;
greeter->priv->to_greeter_channel = g_io_channel_unix_new (greeter->priv->to_greeter_input);
g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, &error);
if (error)
g_warning ("Failed to set encoding on to greeter channel to binary: %s\n", error->message);
g_clear_error (&error);
- greeter->priv->from_greeter_output = from_greeter_pipe[0];
- from_greeter_input = from_greeter_pipe[1];
+ greeter->priv->from_greeter_output = from_greeter_fd;
greeter->priv->from_greeter_channel = g_io_channel_unix_new (greeter->priv->from_greeter_output);
g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, &error);
if (error)
@@ -148,18 +139,6 @@ greeter_start (Greeter *greeter, gboolean (*setup_child_cb)(Greeter *greeter, in
g_clear_error (&error);
g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
greeter->priv->from_greeter_watch = g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
-
- /* Don't allow the daemon end of the pipes to be accessed in child processes */
- fcntl (greeter->priv->to_greeter_input, F_SETFD, FD_CLOEXEC);
- fcntl (greeter->priv->from_greeter_output, F_SETFD, FD_CLOEXEC);
-
- result = setup_child_cb (greeter, from_greeter_input, to_greeter_output, user_data);
-
- /* Close the session ends of the pipe */
- close (from_greeter_input);
- close (to_greeter_output);
-
- return result;
}
void
diff --git a/src/greeter.h b/src/greeter.h
index a48a6d43..19ddf86c 100644
--- a/src/greeter.h
+++ b/src/greeter.h
@@ -11,6 +11,8 @@
#ifndef GREETER_H_
#define GREETER_H_
+typedef struct Greeter Greeter;
+
#include "session.h"
G_BEGIN_DECLS
@@ -31,11 +33,11 @@ G_BEGIN_DECLS
typedef struct GreeterPrivate GreeterPrivate;
-typedef struct
+struct Greeter
{
GObject parent_instance;
GreeterPrivate *priv;
-} Greeter;
+};
typedef struct
{
@@ -49,7 +51,7 @@ GType greeter_get_type (void);
Greeter *greeter_new (void);
-gboolean greeter_start (Greeter *greeter, gboolean (*setup_child_cb)(Greeter *greeter, int input_fd, int output_fd, gpointer user_data), gpointer user_data);
+void greeter_set_file_descriptors (Greeter *greeter, int to_greeter_fd, int from_greeter_fd);
void greeter_stop (Greeter *greeter);
diff --git a/src/seat.c b/src/seat.c
index 4732b6f1..e8d4cd00 100644
--- a/src/seat.c
+++ b/src/seat.c
@@ -1243,34 +1243,36 @@ greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *sessi
/* If can re-use the display server, stop the greeter first */
greeter_session = get_greeter_session (seat, greeter);
- display_server = session_get_display_server (greeter_session);
- if (!greeter_get_resettable (greeter) &&
- can_share_display_server (seat, display_server) &&
- strcmp (display_server_get_session_type (display_server), session_get_session_type (session)) == 0)
+ if (greeter_session)
{
- l_debug (seat, "Stopping greeter; display server will be re-used for user session");
+ display_server = session_get_display_server (greeter_session);
+ if (display_server &&
+ !greeter_get_resettable (greeter) &&
+ can_share_display_server (seat, display_server) &&
+ strcmp (display_server_get_session_type (display_server), session_get_session_type (session)) == 0)
+ {
+ l_debug (seat, "Stopping greeter; display server will be re-used for user session");
- /* Run on the same display server after the greeter has stopped */
- session_set_display_server (session, display_server);
+ /* Run on the same display server after the greeter has stopped */
+ session_set_display_server (session, display_server);
- /* Stop the greeter */
- session_stop (greeter_session);
+ /* Stop the greeter */
+ session_stop (greeter_session);
- return TRUE;
+ return TRUE;
+ }
}
+
/* Otherwise start a new display server for this session */
- else
+ display_server = create_display_server (seat, session);
+ session_set_display_server (session, display_server);
+ if (!start_display_server (seat, display_server))
{
- display_server = create_display_server (seat, session);
- session_set_display_server (session, display_server);
- if (!start_display_server (seat, display_server))
- {
- l_debug (seat, "Failed to start display server for new session");
- return FALSE;
- }
-
- return TRUE;
+ l_debug (seat, "Failed to start display server for new session");
+ return FALSE;
}
+
+ return TRUE;
}
static GreeterSession *
@@ -1873,9 +1875,35 @@ seat_real_create_greeter_session (Seat *seat)
}
static Session *
+create_session_cb (Greeter *greeter, Seat *seat)
+{
+ return create_session (seat, FALSE);
+}
+
+static Greeter *
+create_greeter_cb (Session *session, Seat *seat)
+{
+ Greeter *greeter;
+
+ greeter = greeter_new ();
+ greeter_set_pam_services (greeter,
+ seat_get_string_property (seat, "pam-service"),
+ seat_get_string_property (seat, "pam-autologin-service"));
+ g_signal_connect (greeter, GREETER_SIGNAL_CREATE_SESSION, G_CALLBACK (create_session_cb), seat);
+ g_signal_connect (greeter, GREETER_SIGNAL_START_SESSION, G_CALLBACK (greeter_start_session_cb), seat);
+
+ return greeter;
+}
+
+static Session *
seat_real_create_session (Seat *seat)
{
- return session_new ();
+ Session *session;
+
+ session = session_new ();
+ g_signal_connect (session, SESSION_SIGNAL_CREATE_GREETER, G_CALLBACK (create_greeter_cb), seat);
+
+ return session;
}
static void
diff --git a/src/session-config.c b/src/session-config.c
index 34f3a970..43073ea9 100644
--- a/src/session-config.c
+++ b/src/session-config.c
@@ -24,6 +24,9 @@ struct SessionConfigPrivate
/* Compositor command to run (for type mir-container) */
gchar *compositor_command;
+
+ /* TRUE if can run a greeter inside the session */
+ gboolean allow_greeter;
};
G_DEFINE_TYPE (SessionConfig, session_config, G_TYPE_OBJECT);
@@ -68,6 +71,7 @@ session_config_new_from_file (const gchar *filename, const gchar *default_sessio
}
}
config->priv->compositor_command = g_key_file_get_string (desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-System-Compositor-Command", NULL);
+ config->priv->allow_greeter = g_key_file_get_boolean (desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-Allow-Greeter", NULL);
g_key_file_free (desktop_file);
@@ -102,6 +106,13 @@ session_config_get_compositor_command (SessionConfig *config)
return config->priv->compositor_command;
}
+gboolean
+session_config_get_allow_greeter (SessionConfig *config)
+{
+ g_return_val_if_fail (config != NULL, FALSE);
+ return config->priv->allow_greeter;
+}
+
static void
session_config_init (SessionConfig *config)
{
diff --git a/src/session-config.h b/src/session-config.h
index aea59599..827d3f5e 100644
--- a/src/session-config.h
+++ b/src/session-config.h
@@ -46,6 +46,8 @@ gchar **session_config_get_desktop_names (SessionConfig *config);
const gchar *session_config_get_compositor_command (SessionConfig *config);
+gboolean session_config_get_allow_greeter (SessionConfig *config);
+
G_END_DECLS
#endif /* SESSION_CONFIG_H_ */
diff --git a/src/session.c b/src/session.c
index 86cc0ae6..92a59bbd 100644
--- a/src/session.c
+++ b/src/session.c
@@ -27,8 +27,10 @@
#include "login1.h"
#include "guest-account.h"
#include "shared-data-manager.h"
+#include "greeter-socket.h"
enum {
+ CREATE_GREETER,
GOT_MESSAGES,
AUTHENTICATION_COMPLETE,
STOPPED,
@@ -94,6 +96,9 @@ struct SessionPrivate
XAuthority *x_authority;
gboolean x_authority_use_system_location;
+ /* Socket to allow greeters to connect to (if allowed) */
+ GreeterSocket *greeter_socket;
+
/* Remote host this session is being controlled from */
gchar *remote_host_name;
@@ -151,7 +156,7 @@ const gchar *
session_get_session_type (Session *session)
{
g_return_val_if_fail (session != NULL, NULL);
- return session_config_get_session_type (session_get_config (session));
+ return session_config_get_session_type (session->priv->config);
}
void
@@ -551,6 +556,14 @@ session_get_is_started (Session *session)
return session->priv->pid != 0;
}
+static Greeter *
+create_greeter_cb (GreeterSocket *socket, Session *session)
+{
+ Greeter *greeter;
+ g_signal_emit (session, signals[CREATE_GREETER], 0, &greeter);
+ return greeter;
+}
+
static gboolean
session_real_start (Session *session)
{
@@ -589,6 +602,38 @@ session_real_start (Session *session)
return FALSE;
}
+ /* Open socket to allow in-session greeter */
+ if (session->priv->config && session_config_get_allow_greeter (session->priv->config))
+ {
+ gchar *run_dir, *dir, *path;
+ GError *error = NULL;
+
+ 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 (g_mkdir_with_parents (dir, S_IRWXU) < 0)
+ l_warning (session, "Failed to create greeter socket dir %s: %s", dir, strerror (errno));
+ if (getuid () == 0)
+ {
+ if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
+ l_warning (session, "Failed to set ownership of greeter socket dir: %s", strerror (errno));
+ }
+
+ path = g_build_filename (dir, "greeter-socket", NULL);
+ session->priv->greeter_socket = greeter_socket_new (path);
+ g_signal_connect (session->priv->greeter_socket, GREETER_SOCKET_SIGNAL_CREATE_GREETER, G_CALLBACK (create_greeter_cb), session);
+ session_set_env (session, "LIGHTDM_GREETER_PIPE", path);
+ g_free (path);
+ g_free (dir);
+
+ if (!greeter_socket_start (session->priv->greeter_socket, &error))
+ {
+ l_warning (session, "Failed to start greeter socket: %s\n", error->message);
+ g_clear_error (&error);
+ }
+ }
+
/* Run the child */
arg0 = g_strdup_printf ("%d", to_child_output);
arg1 = g_strdup_printf ("%d", from_child_input);
@@ -975,6 +1020,16 @@ session_class_init (SessionClass *klass)
g_type_class_add_private (klass, sizeof (SessionPrivate));
+ signals[CREATE_GREETER] =
+ g_signal_new (SESSION_SIGNAL_CREATE_GREETER,
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SessionClass, create_greeter),
+ g_signal_accumulator_first_wins,
+ NULL,
+ NULL,
+ GREETER_TYPE, 0);
+
signals[GOT_MESSAGES] =
g_signal_new (SESSION_SIGNAL_GOT_MESSAGES,
G_TYPE_FROM_CLASS (klass),
diff --git a/src/session.h b/src/session.h
index 5f57885a..320ac496 100644
--- a/src/session.h
+++ b/src/session.h
@@ -18,12 +18,19 @@
typedef struct Session Session;
+typedef enum
+{
+ SESSION_TYPE_LOCAL,
+ SESSION_TYPE_REMOTE
+} SessionType;
+
#include "session-config.h"
#include "display-server.h"
#include "accounts.h"
#include "x-authority.h"
#include "logger.h"
#include "log-file.h"
+#include "greeter.h"
G_BEGIN_DECLS
@@ -32,6 +39,7 @@ G_BEGIN_DECLS
#define SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SESSION_TYPE, SessionClass))
#define SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SESSION_TYPE, SessionClass))
+#define SESSION_SIGNAL_CREATE_GREETER "create-greeter"
#define SESSION_SIGNAL_GOT_MESSAGES "got-messages"
#define SESSION_SIGNAL_AUTHENTICATION_COMPLETE "authentication-complete"
#define SESSION_SIGNAL_STOPPED "stopped"
@@ -52,17 +60,12 @@ typedef struct
void (*run)(Session *session);
void (*stop)(Session *session);
+ Greeter *(*create_greeter)(Session *session);
void (*got_messages)(Session *session);
void (*authentication_complete)(Session *session);
void (*stopped)(Session *session);
} SessionClass;
-typedef enum
-{
- SESSION_TYPE_LOCAL,
- SESSION_TYPE_REMOTE
-} SessionType;
-
GType session_get_type (void);
Session *session_new (void);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 88b91b71..e46019ac 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -166,6 +166,7 @@ TESTS = \
test-switch-to-user-logout-inactive \
test-switch-to-user-resettable \
test-switch-to-users \
+ test-session-greeter \
test-vnc-login \
test-vnc-command \
test-vnc-dimensions \
@@ -382,6 +383,7 @@ EXTRA_DIST = \
data/keys.conf \
data/sessions/alternative.desktop \
data/sessions/default.desktop \
+ data/sessions/greeter.desktop \
data/sessions/mir.desktop \
data/sessions/mir-container.desktop \
data/sessions/named.desktop \
@@ -536,6 +538,7 @@ EXTRA_DIST = \
scripts/script-hook-greeter-setup-missing.conf \
scripts/script-hook-session-setup-fail.conf \
scripts/script-hook-session-setup-missing.conf \
+ scripts/session-greeter.conf \
scripts/session-stdout.conf \
scripts/session-stderr.conf \
scripts/session-stderr-multi-write.conf \
diff --git a/tests/data/sessions/greeter.desktop b/tests/data/sessions/greeter.desktop
new file mode 100644
index 00000000..9937c0c4
--- /dev/null
+++ b/tests/data/sessions/greeter.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=Test Session with greeter
+Comment=LightDM test session that can run a greeter inside
+Exec=test-session
+X-LightDM-Allow-Greeter=true
diff --git a/tests/scripts/session-greeter.conf b/tests/scripts/session-greeter.conf
new file mode 100644
index 00000000..b18d4d50
--- /dev/null
+++ b/tests/scripts/session-greeter.conf
@@ -0,0 +1,59 @@
+#
+# Check can run greeter inside session
+#
+
+[Seat:*]
+autologin-user=have-password1
+user-session=greeter
+
+#?*START-DAEMON
+#?RUNNER DAEMON-START
+
+# X server starts
+#?XSERVER-0 START VT=7 SEAT=seat0
+
+# Daemon connects when X server is ready
+#?*XSERVER-0 INDICATE-READY
+#?XSERVER-0 INDICATE-READY
+#?XSERVER-0 ACCEPT-CONNECT
+
+# Session starts
+#?SESSION-X-0 START XDG_SEAT=seat0 XDG_VTNR=7 XDG_GREETER_DATA_DIR=.*/have-password1 XDG_SESSION_TYPE=x11 XDG_SESSION_DESKTOP=greeter USER=have-password1
+#?LOGIN1 ACTIVATE-SESSION SESSION=c0
+#?XSERVER-0 ACCEPT-CONNECT
+#?SESSION-X-0 CONNECT-XSERVER
+
+# Start greeter inside session
+#?*SESSION-X-0 GREETER-START
+#?SESSION-X-0 GREETER-STARTED
+
+# Log into account with a password
+#?*SESSION-X-0 GREETER-AUTHENTICATE USERNAME=have-password2
+#?SESSION-X-0 GREETER-SHOW-PROMPT TEXT="Password:"
+#?*SESSION-X-0 GREETER-RESPOND TEXT="password"
+#?SESSION-X-0 GREETER-AUTHENTICATION-COMPLETE USERNAME=have-password2 AUTHENTICATED=TRUE
+#?*SESSION-X-0 GREETER-START-SESSION
+
+# New X server starts
+#?XSERVER-1 START VT=8 SEAT=seat0
+#?*XSERVER-1 INDICATE-READY
+#?XSERVER-1 INDICATE-READY
+#?XSERVER-1 ACCEPT-CONNECT
+
+# New session starts
+#?SESSION-X-1 START XDG_SEAT=seat0 XDG_VTNR=8 XDG_GREETER_DATA_DIR=.*/have-password2 XDG_SESSION_TYPE=x11 XDG_SESSION_DESKTOP=greeter USER=have-password2
+#?XSERVER-1 ACCEPT-CONNECT
+#?SESSION-X-1 CONNECT-XSERVER
+
+# Switch to new session
+#?VT ACTIVATE VT=8
+#?LOGIN1 LOCK-SESSION SESSION=c0
+#?LOGIN1 ACTIVATE-SESSION SESSION=c1
+
+# Cleanup
+#?*STOP-DAEMON
+#?SESSION-X-0 TERMINATE SIGNAL=15
+#?XSERVER-1 TERMINATE SIGNAL=15
+#?SESSION-X-1 TERMINATE SIGNAL=15
+#?XSERVER-0 TERMINATE SIGNAL=15
+#?RUNNER DAEMON-EXIT STATUS=0
diff --git a/tests/src/Makefile.am b/tests/src/Makefile.am
index d769f027..bd42022e 100644
--- a/tests/src/Makefile.am
+++ b/tests/src/Makefile.am
@@ -195,11 +195,14 @@ test_qt5_greeter_LDADD = \
test_session_SOURCES = test-session.c status.c status.h
test_session_CFLAGS = \
+ -I$(top_srcdir)/liblightdm-gobject \
$(WARN_CFLAGS) \
$(GLIB_CFLAGS) \
$(GIO_UNIX_CFLAGS) \
$(XCB_CFLAGS)
test_session_LDADD = \
+ -L$(top_builddir)/liblightdm-gobject \
+ -llightdm-gobject-1 \
$(GLIB_LIBS) \
$(GIO_UNIX_LIBS) \
$(XCB_LIBS)
diff --git a/tests/src/libsystem.c b/tests/src/libsystem.c
index 43d83fb7..78e77bb4 100644
--- a/tests/src/libsystem.c
+++ b/tests/src/libsystem.c
@@ -11,6 +11,7 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <pwd.h>
#include <unistd.h>
@@ -616,35 +617,48 @@ int
bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
int port = 0, redirected_port = 0;
+ const char *path;
int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
const struct sockaddr *modified_addr = addr;
- struct sockaddr_in temp_addr;
- struct sockaddr_in6 temp_addr6;
+ struct sockaddr_in temp_addr_in;
+ struct sockaddr_in6 temp_addr_in6;
+ struct sockaddr_un temp_addr_un;
int retval;
_bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
switch (addr->sa_family)
{
+ case AF_UNIX:
+ path = ((const struct sockaddr_un *) addr)->sun_path;
+ if (path[0] != '\0')
+ {
+ gchar *new_path = redirect_path (path);
+ memcpy (&temp_addr_un, addr, sizeof (struct sockaddr_un));
+ strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+ g_free (new_path);
+ modified_addr = (struct sockaddr *) &temp_addr_un;
+ }
+ break;
case AF_INET:
port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
redirected_port = find_port_redirect (port);
- memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
- modified_addr = (struct sockaddr *) &temp_addr;
+ memcpy (&temp_addr_in, addr, sizeof (struct sockaddr_in));
+ modified_addr = (struct sockaddr *) &temp_addr_in;
if (redirected_port != 0)
- temp_addr.sin_port = htons (redirected_port);
+ temp_addr_in.sin_port = htons (redirected_port);
else
- temp_addr.sin_port = 0;
+ temp_addr_in.sin_port = 0;
break;
case AF_INET6:
port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
redirected_port = find_port_redirect (port);
- memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
- modified_addr = (struct sockaddr *) &temp_addr6;
+ memcpy (&temp_addr_in6, addr, sizeof (struct sockaddr_in6));
+ modified_addr = (struct sockaddr *) &temp_addr_in6;
if (redirected_port != 0)
- temp_addr6.sin6_port = htons (redirected_port);
+ temp_addr_in6.sin6_port = htons (redirected_port);
else
- temp_addr6.sin6_port = 0;
+ temp_addr_in6.sin6_port = 0;
break;
}
@@ -654,20 +668,20 @@ bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
switch (addr->sa_family)
{
case AF_INET:
- temp_addr_len = sizeof (temp_addr);
- getsockname (sockfd, &temp_addr, &temp_addr_len);
+ temp_addr_len = sizeof (temp_addr_in);
+ getsockname (sockfd, &temp_addr_in, &temp_addr_len);
if (redirected_port == 0)
{
- redirected_port = ntohs (temp_addr.sin_port);
+ redirected_port = ntohs (temp_addr_in.sin_port);
add_port_redirect (port, redirected_port);
}
break;
case AF_INET6:
- temp_addr_len = sizeof (temp_addr6);
- getsockname (sockfd, &temp_addr6, &temp_addr_len);
+ temp_addr_len = sizeof (temp_addr_in6);
+ getsockname (sockfd, &temp_addr_in6, &temp_addr_len);
if (redirected_port == 0)
{
- redirected_port = ntohs (temp_addr6.sin6_port);
+ redirected_port = ntohs (temp_addr_in6.sin6_port);
add_port_redirect (port, redirected_port);
}
break;
@@ -676,27 +690,42 @@ bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
return retval;
}
+#include <ctype.h>
+
int
connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
int port, redirected_port;
+ const char *path;
const struct sockaddr *modified_addr = addr;
- struct sockaddr_in temp_addr;
- struct sockaddr_in6 temp_addr6;
+ struct sockaddr_in temp_addr_in;
+ struct sockaddr_in6 temp_addr_in6;
+ struct sockaddr_un temp_addr_un;
int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
_connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
switch (addr->sa_family)
{
+ case AF_UNIX:
+ path = ((const struct sockaddr_un *) addr)->sun_path;
+ if (path[0] != '\0')
+ {
+ gchar *new_path = redirect_path (path);
+ memcpy (&temp_addr_un, addr, addrlen);
+ strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+ g_free (new_path);
+ modified_addr = (struct sockaddr *) &temp_addr_un;
+ }
+ break;
case AF_INET:
port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
redirected_port = find_port_redirect (port);
if (redirected_port != 0)
{
- memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
- temp_addr.sin_port = htons (redirected_port);
- modified_addr = (struct sockaddr *) &temp_addr;
+ memcpy (&temp_addr_in, addr, sizeof (struct sockaddr_in));
+ temp_addr_in.sin_port = htons (redirected_port);
+ modified_addr = (struct sockaddr *) &temp_addr_in;
}
break;
case AF_INET6:
@@ -704,9 +733,9 @@ connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
redirected_port = find_port_redirect (port);
if (redirected_port != 0)
{
- memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
- temp_addr6.sin6_port = htons (redirected_port);
- modified_addr = (struct sockaddr *) &temp_addr6;
+ memcpy (&temp_addr_in6, addr, sizeof (struct sockaddr_in6));
+ temp_addr_in6.sin6_port = htons (redirected_port);
+ modified_addr = (struct sockaddr *) &temp_addr_in6;
}
break;
}
@@ -718,23 +747,36 @@ ssize_t
sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
int port, redirected_port;
+ const char *path;
const struct sockaddr *modified_addr = dest_addr;
- struct sockaddr_in temp_addr;
- struct sockaddr_in6 temp_addr6;
+ struct sockaddr_in temp_addr_in;
+ struct sockaddr_in6 temp_addr_in6;
+ struct sockaddr_un temp_addr_un;
ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
_sendto = (ssize_t (*)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "sendto");
switch (dest_addr->sa_family)
{
+ case AF_UNIX:
+ path = ((const struct sockaddr_un *) dest_addr)->sun_path;
+ if (path[0] != '\0')
+ {
+ gchar *new_path = redirect_path (path);
+ memcpy (&temp_addr_un, dest_addr, sizeof (struct sockaddr_un));
+ strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+ g_free (new_path);
+ modified_addr = (struct sockaddr *) &temp_addr_un;
+ }
+ break;
case AF_INET:
port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
redirected_port = find_port_redirect (port);
if (redirected_port != 0)
{
- memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in));
- temp_addr.sin_port = htons (redirected_port);
- modified_addr = (struct sockaddr *) &temp_addr;
+ memcpy (&temp_addr_in, dest_addr, sizeof (struct sockaddr_in));
+ temp_addr_in.sin_port = htons (redirected_port);
+ modified_addr = (struct sockaddr *) &temp_addr_in;
}
break;
case AF_INET6:
@@ -742,9 +784,9 @@ sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockadd
redirected_port = find_port_redirect (port);
if (redirected_port != 0)
{
- memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6));
- temp_addr6.sin6_port = htons (redirected_port);
- modified_addr = (struct sockaddr *) &temp_addr6;
+ memcpy (&temp_addr_in6, dest_addr, sizeof (struct sockaddr_in6));
+ temp_addr_in6.sin6_port = htons (redirected_port);
+ modified_addr = (struct sockaddr *) &temp_addr_in6;
}
break;
}
diff --git a/tests/src/test-session.c b/tests/src/test-session.c
index 1455d73f..88be15ec 100644
--- a/tests/src/test-session.c
+++ b/tests/src/test-session.c
@@ -11,6 +11,7 @@
#include <gio/gio.h>
#include <glib-unix.h>
#include <glib/gstdio.h>
+#include <lightdm/greeter.h>
#include "status.h"
@@ -24,6 +25,8 @@ static GKeyFile *config;
static xcb_connection_t *connection;
+static LightDMGreeter *greeter = NULL;
+
static gboolean
sigint_cb (gpointer user_data)
{
@@ -41,8 +44,36 @@ sigterm_cb (gpointer user_data)
}
static void
+show_message_cb (LightDMGreeter *greeter, const gchar *text, LightDMMessageType type)
+{
+ status_notify ("%s GREETER-SHOW-MESSAGE TEXT=\"%s\"", session_id, text);
+}
+
+static void
+show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type)
+{
+ status_notify ("%s GREETER-SHOW-PROMPT TEXT=\"%s\"", session_id, text);
+}
+
+static void
+authentication_complete_cb (LightDMGreeter *greeter)
+{
+ if (lightdm_greeter_get_authentication_user (greeter))
+ status_notify ("%s GREETER-AUTHENTICATION-COMPLETE USERNAME=%s AUTHENTICATED=%s",
+ session_id,
+ lightdm_greeter_get_authentication_user (greeter),
+ lightdm_greeter_get_is_authenticated (greeter) ? "TRUE" : "FALSE");
+ else
+ status_notify ("%s GREETER-AUTHENTICATION-COMPLETE AUTHENTICATED=%s",
+ session_id,
+ lightdm_greeter_get_is_authenticated (greeter) ? "TRUE" : "FALSE");
+}
+
+static void
request_cb (const gchar *name, GHashTable *params)
{
+ GError *error = NULL;
+
if (!name)
{
g_main_loop_quit (loop);
@@ -224,6 +255,40 @@ request_cb (const gchar *name, GHashTable *params)
else
status_notify ("%s WRITE-SHARED-DATA ERROR=NO_XDG_GREETER_DATA_DIR", session_id);
}
+
+ else if (strcmp (name, "GREETER-START") == 0)
+ {
+ GError *error = NULL;
+
+ g_assert (greeter == NULL);
+ greeter = lightdm_greeter_new ();
+ g_signal_connect (greeter, LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE, G_CALLBACK (show_message_cb), NULL);
+ g_signal_connect (greeter, LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT, G_CALLBACK (show_prompt_cb), NULL);
+ g_signal_connect (greeter, LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (authentication_complete_cb), NULL);
+ if (lightdm_greeter_connect_to_daemon_sync (greeter, &error))
+ status_notify ("%s GREETER-STARTED", session_id);
+ else
+ status_notify ("%s GREETER-FAILED", session_id);
+ }
+
+ else if (strcmp (name, "GREETER-AUTHENTICATE") == 0)
+ {
+ lightdm_greeter_authenticate (greeter, g_hash_table_lookup (params, "USERNAME"));
+ }
+
+ else if (strcmp (name, "GREETER-RESPOND") == 0)
+ {
+ lightdm_greeter_respond (greeter, g_hash_table_lookup (params, "TEXT"));
+ }
+
+ else if (strcmp (name, "GREETER-START-SESSION") == 0)
+ {
+ if (!lightdm_greeter_start_session_sync (greeter, g_hash_table_lookup (params, "SESSION"), &error))
+ {
+ status_notify ("%s FAIL-START-SESSION ERROR=%s", session_id, error->message);
+ g_clear_error (&error);
+ }
+ }
}
int
diff --git a/tests/test-session-greeter b/tests/test-session-greeter
new file mode 100755
index 00000000..6b53f429
--- /dev/null
+++ b/tests/test-session-greeter
@@ -0,0 +1,2 @@
+#!/bin/sh
+./src/dbus-env ./src/test-runner session-greeter test-gobject-greeter