Projects
Eulaceura:Mainline
lightdm
_service:obs_scm:9001-multi-pipe-mode.patch
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:9001-multi-pipe-mode.patch of Package lightdm
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 | 99 +++++++++++++++++++++++++++++----- src/session.c | 100 +++++++++++++++++++++++++++++++++-- src/session.h | 8 +++ 5 files changed, 201 insertions(+), 20 deletions(-) diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c index f8bc685..d22e8dd 100644 --- a/liblightdm-gobject/greeter.c +++ b/liblightdm-gobject/greeter.c @@ -650,7 +650,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); @@ -711,6 +710,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 75fe9ff..4a4d0e1 100644 --- a/src/greeter.c +++ b/src/greeter.c @@ -402,6 +402,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) @@ -656,8 +657,8 @@ handle_continue_authentication (Greeter *greeter, gchar **secrets) if (priv->authentication_session == NULL) return; - size_t messages_length = session_get_messages_length (priv->authentication_session); - const struct pam_message *messages = session_get_messages (priv->authentication_session); + size_t messages_length = session_get_prompt_messages_length (priv->authentication_session); + const struct pam_message *messages = session_get_prompt_messages (priv->authentication_session); /* We may have already sent SERVER_MESSAGE_END_AUTHENTICATION, but the greeter may not have digested it yet. */ if (priv->have_sent_end_authentication) { @@ -675,7 +676,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; } @@ -695,7 +696,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 112daab..0372fc6 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,27 @@ 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; } @@ -126,6 +170,10 @@ pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response 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); gboolean auth_complete = FALSE; @@ -141,17 +189,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; @@ -263,22 +333,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; @@ -331,7 +403,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 fce12a0..c257429 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 */ size_t messages_length; struct pam_message *messages; + /* Prompt Messages being requested by PAM */ + size_t 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 %zi 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 (size_t 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)); +} + size_t session_get_messages_length (Session *session) { @@ -735,6 +813,22 @@ session_get_messages (Session *session) return priv->messages; } +size_t +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; +} + gboolean session_get_is_authenticated (Session *session) { diff --git a/src/session.h b/src/session.h index e1130e8..995cceb 100644 --- a/src/session.h +++ b/src/session.h @@ -124,12 +124,20 @@ 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); + size_t session_get_messages_length (Session *session); const struct pam_message *session_get_messages (Session *session); +size_t 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.33.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2