lightdm/9001-multi-pipe-mode.patch

528 lines
19 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 709db95bff5d88ed2d9d5911e8050cacb4f46921 Mon Sep 17 00:00:00 2001
From: panchenbo <panchenbo@uniontech.com>
Date: Sun, 25 Apr 2021 18:28:22 +0800
Subject: [PATCH] multi-pipe mode
---
liblightdm-gobject/greeter.c | 5 +-
src/greeter.c | 9 ++--
src/session-child.c | 100 ++++++++++++++++++++++++++++++-----
src/session.c | 100 +++++++++++++++++++++++++++++++++--
src/session.h | 7 +++
5 files changed, 200 insertions(+), 21 deletions(-)
diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c
index fd1763c..78c3981 100644
--- a/liblightdm-gobject/greeter.c
+++ b/liblightdm-gobject/greeter.c
@@ -652,7 +652,6 @@ handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize me
g_list_free_full (priv->responses_received, g_free);
priv->responses_received = NULL;
- priv->n_responses_waiting = 0;
guint32 n_messages = read_int (message, message_length, offset);
g_debug ("Prompt user with %d message(s)", n_messages);
@@ -713,6 +712,8 @@ handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize messa
priv->is_authenticated = (return_code == 0);
priv->in_authentication = FALSE;
+ // reset
+ priv->n_responses_waiting = 0;
g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
}
@@ -1330,6 +1331,8 @@ lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username, GE
priv->cancelling_authentication = FALSE;
priv->authenticate_sequence_number++;
priv->in_authentication = TRUE;
+ // reset
+ priv->n_responses_waiting = 0;
priv->is_authenticated = FALSE;
if (username != priv->authentication_user)
{
diff --git a/src/greeter.c b/src/greeter.c
index 383e1f8..fc4850d 100644
--- a/src/greeter.c
+++ b/src/greeter.c
@@ -394,6 +394,7 @@ pam_messages_cb (Session *session, Greeter *greeter)
}
write_message (greeter, message, offset);
+ g_debug ("Prompt greeter with %d n_prompts", n_prompts);
/* Continue immediately if nothing to respond with */
// FIXME: Should probably give the greeter a chance to ack the message
if (n_prompts == 0)
@@ -645,8 +646,8 @@ handle_continue_authentication (Greeter *greeter, gchar **secrets)
if (priv->authentication_session == NULL)
return;
- int messages_length = session_get_messages_length (priv->authentication_session);
- const struct pam_message *messages = session_get_messages (priv->authentication_session);
+ int messages_length = session_get_prompt_messages_length (priv->authentication_session);
+ const struct pam_message *messages = session_get_prompt_messages (priv->authentication_session);
/* Check correct number of responses */
int n_prompts = 0;
@@ -658,7 +659,7 @@ handle_continue_authentication (Greeter *greeter, gchar **secrets)
}
if (g_strv_length (secrets) != n_prompts)
{
- session_respond_error (priv->authentication_session, PAM_CONV_ERR);
+ session_prompt_respond_error (priv->authentication_session, PAM_CONV_ERR);
return;
}
@@ -678,7 +679,7 @@ handle_continue_authentication (Greeter *greeter, gchar **secrets)
}
}
- session_respond (priv->authentication_session, response);
+ session_prompt_respond (priv->authentication_session, response);
for (int i = 0; i < messages_length; i++)
secure_free (greeter, response[i].resp);
diff --git a/src/session-child.c b/src/session-child.c
index eef51e4..64716b2 100644
--- a/src/session-child.c
+++ b/src/session-child.c
@@ -16,6 +16,7 @@
#include <utmp.h>
#include <utmpx.h>
#include <sys/mman.h>
+#include <pthread.h>
#if HAVE_LIBAUDIT
#include <libaudit.h>
@@ -37,6 +38,8 @@ static GPid child_pid = 0;
/* Pipe to communicate with daemon */
static int from_daemon_output = 0;
static int to_daemon_input = 0;
+/* Pipe to prompt with daemon */
+static int from_daemon_output_prompt = 0;
static gboolean is_interactive;
static gboolean do_authenticate;
@@ -72,6 +75,16 @@ read_data (void *buf, size_t count)
return n_read;
}
+static ssize_t
+read_prompt_data (void *buf, size_t count)
+{
+ ssize_t n_read = read (from_daemon_output_prompt, buf, count);
+ if (n_read < 0)
+ g_printerr ("Error reading prompt from daemon: %s\n", strerror (errno));
+
+ return n_read;
+}
+
static gchar *
read_string_full (void* (*alloc_fn)(size_t n))
{
@@ -93,12 +106,34 @@ read_string_full (void* (*alloc_fn)(size_t n))
return value;
}
+static gchar *
+read_prompt_string_full (void* (*alloc_fn)(size_t n))
+{
+ int length;
+ if (read_prompt_data (&length, sizeof (length)) <= 0)
+ return NULL;
+ if (length < 0)
+ return NULL;
+ if (length > MAX_STRING_LENGTH)
+ {
+ g_printerr ("Invalid string length %d from daemon\n", length);
+ return NULL;
+ }
+
+ gchar *value = (*alloc_fn) (sizeof (gchar) * (length + 1));
+ read_prompt_data (value, length);
+ value[length] = '\0';
+
+ return value;
+}
+
static gchar *
read_string (void)
{
return read_string_full (g_malloc);
}
+pthread_mutex_t mutex_msg;
static int
pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
{
@@ -106,18 +141,26 @@ pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response
if (authentication_complete)
return PAM_SUCCESS;
- /* Cancel authentication if requiring input */
- if (!is_interactive)
+ // 将普通消息和PAM_PROMPT_ECHO_X的消息分开从lightdm中读取回复内容时使用不同的管道
+ // 因为在lightdm的实现中处理PAM_PROMPT_ECHO_X时会一直等待greeter的消息而其他消息则会立即给出响应结果
+ int n_prompts = 0;
+
+ for (int i = 0; i < msg_length; i++)
{
- for (int i = 0; i < msg_length; i++)
+ if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
{
- if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
+ /* Cancel authentication if requiring input */
+ if (!is_interactive)
{
g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
return PAM_CONV_ERR;
}
- }
+ ++n_prompts;
+ }
+ }
+ if (!is_interactive)
+ {
/* Ignore informational messages */
return PAM_SUCCESS;
}
@@ -125,6 +168,10 @@ pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response
/* Check if we changed user */
gchar *username = NULL;
pam_get_item (pam_handle, PAM_USER, (const void **) &username);
+
+ // lock for pam
+ // 在pam模块中可能使用多线程调用此函数加锁是为了保证消息在管道中的相对顺序
+ pthread_mutex_lock(&mutex_msg);
/* Notify the daemon */
write_string (username);
@@ -140,17 +187,39 @@ pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response
/* Get response */
int error;
- read_data (&error, sizeof (error));
- if (error != PAM_SUCCESS)
+ if (n_prompts) {
+ // 只为普通消息加锁,如果 PAM_PROMPT_ECHO_X 类型的消息也从多个线程发送则可能存在风险
+ // unlock for read message
+ pthread_mutex_unlock(&mutex_msg);
+ read_prompt_data (&error, sizeof (error));
+ } else {
+ read_data (&error, sizeof (error));
+ }
+ if (error != PAM_SUCCESS) {
+ if (!n_prompts) {
+ // unlock for read message
+ pthread_mutex_unlock(&mutex_msg);
+ }
return error;
+ }
struct pam_response *response = calloc (msg_length, sizeof (struct pam_response));
for (int i = 0; i < msg_length; i++)
{
struct pam_response *r = &response[i];
// callers of this function inside pam will expect to be able to call
// free() on the strings we give back. So alloc with malloc.
- r->resp = read_string_full (malloc);
- read_data (&r->resp_retcode, sizeof (r->resp_retcode));
+ if (n_prompts) {
+ r->resp = read_prompt_string_full (malloc);
+ read_prompt_data (&r->resp_retcode, sizeof (r->resp_retcode));
+ } else {
+ r->resp = read_string_full (malloc);
+ read_data (&r->resp_retcode, sizeof (r->resp_retcode));
+ }
+ }
+
+ if (!n_prompts) {
+ // unlock for read message
+ pthread_mutex_unlock(&mutex_msg);
}
*resp = response;
@@ -262,22 +331,24 @@ session_child_run (int argc, char **argv)
close (fd);
/* Get the pipe from the daemon */
- if (argc != 4)
+ if (argc != 5)
{
- g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
+ g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD INPUTFD_PROMPT\n");
return EXIT_FAILURE;
}
from_daemon_output = atoi (argv[2]);
to_daemon_input = atoi (argv[3]);
- if (from_daemon_output == 0 || to_daemon_input == 0)
+ from_daemon_output_prompt = atoi (argv[4]);
+ if (from_daemon_output == 0 || to_daemon_input == 0 || from_daemon_output_prompt == 0)
{
- g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
+ g_printerr ("Invalid file descriptors %s %s %s\n", argv[2], argv[3], argv[4]);
return EXIT_FAILURE;
}
/* Don't let these pipes leak to the command we will run */
fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
+ fcntl (from_daemon_output_prompt, F_SETFD, FD_CLOEXEC);
/* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
int version;
@@ -330,7 +401,10 @@ session_child_run (int argc, char **argv)
{
const gchar *new_username;
+ // init mutex for pam_conv_cb
+ pthread_mutex_init(&mutex_msg, 0);
authentication_result = pam_authenticate (pam_handle, 0);
+ pthread_mutex_destroy(&mutex_msg);
/* See what user we ended up as */
if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
diff --git a/src/session.c b/src/session.c
index 2ea9352..12ae60a 100644
--- a/src/session.c
+++ b/src/session.c
@@ -52,6 +52,7 @@ typedef struct
/* Pipes to talk to child */
int to_child_input;
int from_child_output;
+ int to_child_prompt_input;
GIOChannel *from_child_channel;
guint from_child_watch;
guint child_watch;
@@ -77,6 +78,9 @@ typedef struct
/* Messages being requested by PAM */
int messages_length;
struct pam_message *messages;
+ /* Prompt Messages being requested by PAM */
+ int prompt_messages_length;
+ struct pam_message *prompt_messages;
/* Authentication result from PAM */
gboolean authentication_started;
@@ -382,6 +386,14 @@ write_data (Session *session, const void *buf, size_t count)
l_warning (session, "Error writing to session: %s", strerror (errno));
}
+static void
+write_prompt_data (Session *session, const void *buf, size_t count)
+{
+ SessionPrivate *priv = session_get_instance_private (session);
+ if (write (priv->to_child_prompt_input, buf, count) != count)
+ l_warning (session, "Error writing prompt to session: %s", strerror (errno));
+}
+
static void
write_string (Session *session, const char *value)
{
@@ -391,6 +403,15 @@ write_string (Session *session, const char *value)
write_data (session, value, sizeof (char) * length);
}
+static void
+write_prompt_string (Session *session, const char *value)
+{
+ int length = value ? strlen (value) : -1;
+ write_prompt_data (session, &length, sizeof (length));
+ if (value)
+ write_prompt_data (session, value, sizeof (char) * length);
+}
+
static void
write_xauth (Session *session, XAuthority *x_authority)
{
@@ -534,6 +555,8 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
}
else
{
+ gboolean n_prompts = 0;
+
priv->messages_length = 0;
read_from_child (session, &priv->messages_length, sizeof (priv->messages_length));
priv->messages = calloc (priv->messages_length, sizeof (struct pam_message));
@@ -542,6 +565,13 @@ from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
struct pam_message *m = &priv->messages[i];
read_from_child (session, &m->msg_style, sizeof (m->msg_style));
m->msg = read_string_from_child (session);
+ if (m->msg_style == PAM_PROMPT_ECHO_OFF || m->msg_style == PAM_PROMPT_ECHO_ON)
+ ++n_prompts;
+ }
+ // for prompt message
+ if (n_prompts) {
+ priv->prompt_messages_length = priv->messages_length;
+ priv->prompt_messages = priv->messages;
}
l_debug (session, "Got %d message(s) from PAM", priv->messages_length);
@@ -585,15 +615,17 @@ session_real_start (Session *session)
display_server_connect_session (priv->display_server, session);
/* Create pipes to talk to the child */
- int to_child_pipe[2], from_child_pipe[2];
- if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
+ int to_child_pipe[2], from_child_pipe[2], to_child_prompt_pipe[2];
+ if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0 || pipe (to_child_prompt_pipe) < 0)
{
g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
return FALSE;
}
int to_child_output = to_child_pipe[0];
+ int to_child_prompt_output = to_child_prompt_pipe[0];
priv->to_child_input = to_child_pipe[1];
priv->from_child_output = from_child_pipe[0];
+ priv->to_child_prompt_input = to_child_prompt_pipe[1];
int from_child_input = from_child_pipe[1];
priv->from_child_channel = g_io_channel_unix_new (priv->from_child_output);
priv->from_child_watch = g_io_add_watch (priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
@@ -601,6 +633,7 @@ session_real_start (Session *session)
/* Don't allow the daemon end of the pipes to be accessed in child processes */
fcntl (priv->to_child_input, F_SETFD, FD_CLOEXEC);
fcntl (priv->from_child_output, F_SETFD, FD_CLOEXEC);
+ fcntl (priv->to_child_prompt_input, F_SETFD, FD_CLOEXEC);
/* Create the guest account if it is one */
if (priv->is_guest && priv->username == NULL)
@@ -613,6 +646,7 @@ session_real_start (Session *session)
/* Run the child */
g_autofree gchar *arg0 = g_strdup_printf ("%d", to_child_output);
g_autofree gchar *arg1 = g_strdup_printf ("%d", from_child_input);
+ g_autofree gchar *arg2 = g_strdup_printf ("%d", to_child_prompt_output);
priv->pid = fork ();
if (priv->pid == 0)
{
@@ -620,7 +654,7 @@ session_real_start (Session *session)
execlp ("lightdm",
"lightdm",
"--session-child",
- arg0, arg1, NULL);
+ arg0, arg1, arg2, NULL);
_exit (EXIT_FAILURE);
}
@@ -642,6 +676,7 @@ session_real_start (Session *session)
/* Close the ends of the pipes we don't need */
close (to_child_output);
close (from_child_input);
+ close (to_child_prompt_output);
/* Indicate what version of the protocol we are using */
int version = 3;
@@ -702,6 +737,11 @@ session_respond (Session *session, struct pam_response *response)
write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
}
+ if (priv->messages == priv->prompt_messages) {
+ l_warning (session, "%s", "Current message is prompt message");
+ return;
+ }
+
/* Delete the old messages */
for (int i = 0; i < priv->messages_length; i++)
g_free ((char *) priv->messages[i].msg);
@@ -710,6 +750,35 @@ session_respond (Session *session, struct pam_response *response)
priv->messages_length = 0;
}
+void
+session_prompt_respond (Session *session, struct pam_response *response)
+{
+ SessionPrivate *priv = session_get_instance_private (session);
+
+ g_return_if_fail (session != NULL);
+
+ int error = PAM_SUCCESS;
+ write_prompt_data (session, &error, sizeof (error));
+ for (int i = 0; i < priv->prompt_messages_length; i++)
+ {
+ write_prompt_string (session, response[i].resp);
+ write_prompt_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
+ }
+
+ // clear
+ if (priv->messages == priv->prompt_messages) {
+ priv->messages = NULL;
+ priv->messages_length = 0;
+ }
+
+ /* Delete the old messages */
+ for (int i = 0; i < priv->prompt_messages_length; i++)
+ g_free ((char *) priv->prompt_messages[i].msg);
+ g_free (priv->prompt_messages);
+ priv->prompt_messages = NULL;
+ priv->prompt_messages_length = 0;
+}
+
void
session_respond_error (Session *session, int error)
{
@@ -719,6 +788,15 @@ session_respond_error (Session *session, int error)
write_data (session, &error, sizeof (error));
}
+void
+session_prompt_respond_error (Session *session, int error)
+{
+ g_return_if_fail (session != NULL);
+ g_return_if_fail (error != PAM_SUCCESS);
+
+ write_prompt_data (session, &error, sizeof (error));
+}
+
int
session_get_messages_length (Session *session)
{
@@ -727,6 +805,22 @@ session_get_messages_length (Session *session)
return priv->messages_length;
}
+int
+session_get_prompt_messages_length(Session *session)
+{
+ SessionPrivate *priv = session_get_instance_private (session);
+ g_return_val_if_fail (session != NULL, 0);
+ return priv->prompt_messages_length;
+}
+
+const struct pam_message *
+session_get_prompt_messages(Session *session)
+{
+ SessionPrivate *priv = session_get_instance_private (session);
+ g_return_val_if_fail (session != NULL, NULL);
+ return priv->prompt_messages;
+}
+
const struct pam_message *
session_get_messages (Session *session)
{
diff --git a/src/session.h b/src/session.h
index 350cf3b..de15ae4 100644
--- a/src/session.h
+++ b/src/session.h
@@ -124,12 +124,19 @@ const gchar *session_get_console_kit_cookie (Session *session);
void session_respond (Session *session, struct pam_response *response);
+void session_prompt_respond (Session *session, struct pam_response *response);
+
void session_respond_error (Session *session, int error);
+void session_prompt_respond_error (Session *session, int error);
+
int session_get_messages_length (Session *session);
const struct pam_message *session_get_messages (Session *session);
+int session_get_prompt_messages_length (Session *session);
+const struct pam_message *session_get_prompt_messages (Session *session);
+
gboolean session_get_is_authenticated (Session *session);
int session_get_authentication_result (Session *session);
--
2.20.1