From fe3cac9350720323373c8c0654e6c893f81a1625 Mon Sep 17 00:00:00 2001 From: kkz Date: Fri, 30 Jul 2021 13:54:16 +0800 Subject: [PATCH] Add a uniontech patch to support multi-pipe mode --- 9001-multi-pipe-mode.patch | 527 +++++++++++++++++++++++++++++++++++++ lightdm.spec | 8 +- 2 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 9001-multi-pipe-mode.patch diff --git a/9001-multi-pipe-mode.patch b/9001-multi-pipe-mode.patch new file mode 100644 index 0000000..7e41e6b --- /dev/null +++ b/9001-multi-pipe-mode.patch @@ -0,0 +1,527 @@ +From 709db95bff5d88ed2d9d5911e8050cacb4f46921 Mon Sep 17 00:00:00 2001 +From: panchenbo +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 + #include + #include ++#include + + #if HAVE_LIBAUDIT + #include +@@ -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 + diff --git a/lightdm.spec b/lightdm.spec index 902728b..59ffb55 100644 --- a/lightdm.spec +++ b/lightdm.spec @@ -7,7 +7,7 @@ Name: lightdm Summary: A cross-desktop Display Manager Version: 1.30.0 -Release: 9 +Release: 10 # library/bindings are LGPLv2 or LGPLv3, the rest GPLv3+ License: (LGPLv2 or LGPLv3) and GPLv3+ @@ -38,6 +38,9 @@ Patch0: lightdm-1.25.1-disable_dmrc.patch # Upstream commits +# UnionTech patchs +Patch9001: 9001-multi-pipe-mode.patch + BuildRequires: gettext BuildRequires: gnome-common BuildRequires: gtk-doc itstool @@ -307,6 +310,9 @@ fi %changelog +* Fri Jul 30 2021 zhaoshuang - 1.30.0-10 +- Add a uniontech patch to support multi-pipe mode + * Tun Jun 08 2021 zhanglin - 1.30.0-9 - Remove pam_console dependency -- Gitee