#include <stdlib.h>
#include <string.h>
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
#include <security/pam_appl.h>
#include "lightdm/greeter.h"
/* 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;
connect_to_daemon (LightDMGreeter *greeter, GError **error)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
- const gchar *to_server_fd, *from_server_fd;
+ const gchar *to_server_fd, *from_server_fd, *pipe_path;
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");
- if (!to_server_fd || !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)
+ 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_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_CONNECTION_FAILED,
"Unable to determine socket to daemon");
return FALSE;
}
- 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));
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) ||
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)
greeter.h \
greeter-session.c \
greeter-session.h \
+ greeter-socket.c \
+ greeter-socket.h \
guest-account.c \
guest-account.h \
lightdm.c \
#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include "greeter-session.h"
}
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
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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_ */
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
#include <gcrypt.h>
#include "greeter.h"
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)
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
#ifndef GREETER_H_
#define GREETER_H_
+typedef struct Greeter Greeter;
+
#include "session.h"
G_BEGIN_DECLS
typedef struct GreeterPrivate GreeterPrivate;
-typedef struct
+struct Greeter
{
GObject parent_instance;
GreeterPrivate *priv;
-} Greeter;
+};
typedef struct
{
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);
/* 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 *
return greeter_session_new ();
}
+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
/* Command to run */
gchar *command;
+
+ /* TRUE if can run a greeter inside the session */
+ gboolean allow_greeter;
};
G_DEFINE_TYPE (SessionConfig, session_config, G_TYPE_OBJECT);
config->priv->desktop_names[1] = 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);
return config->priv->desktop_names;
}
+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)
{
gchar **session_config_get_desktop_names (SessionConfig *config);
+gboolean session_config_get_allow_greeter (SessionConfig *config);
+
G_END_DECLS
#endif /* SESSION_CONFIG_H_ */
#include "login1.h"
#include "guest-account.h"
#include "shared-data-manager.h"
+#include "greeter-socket.h"
enum {
+ CREATE_GREETER,
GOT_MESSAGES,
AUTHENTICATION_COMPLETE,
STOPPED,
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;
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
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)
{
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);
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),
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
#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"
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);
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 \
data/keys.conf \
data/sessions/alternative.desktop \
data/sessions/default.desktop \
+ data/sessions/greeter.desktop \
data/sessions/mir.desktop \
data/sessions/named.desktop \
data/sessions/named-legacy.desktop \
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 \
--- /dev/null
+[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
--- /dev/null
+#
+# 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=/home/bob/bzr/lightdm/session-greeter/install/var/lib/lightdm-data/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
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)
#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>
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;
}
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;
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:
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;
}
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:
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;
}
#include <gio/gio.h>
#include <glib-unix.h>
#include <glib/gstdio.h>
+#include <lightdm/greeter.h>
#include "status.h"
static xcb_connection_t *connection;
+static LightDMGreeter *greeter = NULL;
+
static gboolean
sigint_cb (gpointer user_data)
{
return TRUE;
}
+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);
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 ERROR=%s", session_id, error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ else if (strcmp (name, "GREETER-AUTHENTICATE") == 0)
+ {
+ if (!lightdm_greeter_authenticate (greeter, g_hash_table_lookup (params, "USERNAME"), &error))
+ {
+ status_notify ("%s FAIL-AUTHENTICATE ERROR=%s", session_id, error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ else if (strcmp (name, "GREETER-RESPOND") == 0)
+ {
+ if (!lightdm_greeter_respond (greeter, g_hash_table_lookup (params, "TEXT"), &error))
+ {
+ status_notify ("%s FAIL-RESPOND ERROR=%s", session_id, error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ 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
--- /dev/null
+#!/bin/sh
+./src/dbus-env ./src/test-runner session-greeter test-gobject-greeter