diff options
author | Paul Wolneykien <[email protected]> | 2021-10-15 17:29:51 +0300 |
---|---|---|
committer | raveit65 <[email protected]> | 2021-10-15 17:00:00 +0200 |
commit | ec813dffa59d30fa30ab3e4932095337b5813132 (patch) | |
tree | a427410801bfde4236011bb626b60b681c3f2be3 /src | |
parent | e7ef128c33d62c01617bc642d5a8053e4a49126a (diff) | |
download | mate-screensaver-ec813dffa59d30fa30ab3e4932095337b5813132.tar.bz2 mate-screensaver-ec813dffa59d30fa30ab3e4932095337b5813132.tar.xz |
Prompt-driven auth. helper
By the term "prompt-driven" I mean two-way conversation between the
screensaver dialog and the PAM stack. As you probably know, PAM works
by conversation with a dialog program asking the user to enter
something in answer to each message it sends. In the most conventional
case, the only question is "Password:" and the password is the only
data the user enters. But in general, the number of questions and
messages are not limited to that.
The previous support of PAM helper (gs-auth-helper.c) was written and
worked for the mentioned "only password" authentication scheme. For
other schemes it wasn't enough. New implementation fixes that
limitation.
Same as the previous version of gs-auth-helper.c, the new version uses
pipe interface for interprocess communication and synchronization.
However, unlike the previous version, new version uses two pipes
instead of a single pipe: the first one is used to transfer
prompt text from PAM via the helper to the screensaver dialog, and the
second one is used to transfer the user input from the dialog to
helper (and then the helper replies with it back to PAM). Having that
bidirectional prompt/reply channel it is possible to make as many
prompt/reply passes as required by PAM.
The present helper program (see the helper/ dir) is based on the
helper written by [email protected], which is in turn loosely based on
unix_chkpwd by Andrew Morgan.
All new code is untabified under the assumption the tab width is 8.
Signed-off-by: Paul Wolneykien <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/gs-auth-helper.c | 202 | ||||
-rw-r--r-- | src/gs-auth-pam.c | 28 | ||||
-rw-r--r-- | src/gs-auth-pam.h | 54 |
4 files changed, 172 insertions, 128 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index f26612b..244b653 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = 1.7 NULL = -saverdir = $(libexecdir)/mate-screensaver +saverdir = $(pkglibexecdir) themesdir = $(pkgdatadir)/themes AM_CPPFLAGS = \ @@ -21,6 +21,7 @@ AM_CPPFLAGS = \ -DDATADIR=\""$(datadir)"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DMATELOCALEDIR=\""$(datadir)/locale"\" \ + -DPKGLIBEXECDIR=\""$(pkglibexecdir)"\" \ -DSAVERDIR=\""$(saverdir)"\" \ -DTHEMESDIR=\""$(themesdir)"\" \ -DGTKBUILDERDIR=\"$(pkgdatadir)\" \ @@ -69,6 +70,7 @@ mate_screensaver_command_LDADD = \ AUTH_SOURCES = \ gs-auth.h \ + gs-auth-pam.h \ gs-auth-@[email protected] \ $(NULL) @@ -99,6 +101,11 @@ test_passwd_LDADD = \ $(AUTH_LIBS) \ $(NULL) +if HAVE_PASSWD_HELPER +test_passwd_LDADD += \ + ../helper/libhelper-proto.a +endif + test_watcher_SOURCES = \ test-watcher.c \ gs-watcher.h \ @@ -161,6 +168,13 @@ mate_screensaver_dialog_LDADD = \ $(LIBNOTIFY_LIBS) \ $(NULL) +if HAVE_PASSWD_HELPER +mate_screensaver_dialog_LDADD += \ + ../helper/libhelper-proto.a +../helper/libhelper-proto.a: + $(MAKE) -C ../helper +endif + BUILT_SOURCES = \ gs-marshal.c \ gs-marshal.h \ diff --git a/src/gs-auth-helper.c b/src/gs-auth-helper.c index acc6958..8396135 100644 --- a/src/gs-auth-helper.c +++ b/src/gs-auth-helper.c @@ -51,6 +51,9 @@ #include "gs-auth.h" #include "subprocs.h" +#include "../helper/helper_proto.h" +#define MAXLEN 1024 + static gboolean verbose_enabled = FALSE; GQuark @@ -79,85 +82,105 @@ gs_auth_get_verbose (void) static gboolean ext_run (const char *user, - const char *typed_passwd, - gboolean verbose) + GSAuthMessageFunc func, + gpointer data) { - int pfd[2], status; - pid_t pid; - - if (pipe (pfd) < 0) - { - return 0; - } - - if (verbose) - { - g_message ("ext_run (%s, %s)", - PASSWD_HELPER_PROGRAM, user); - } - - block_sigchld (); - - if ((pid = fork ()) < 0) - { - close (pfd [0]); - close (pfd [1]); - return FALSE; - } - - if (pid == 0) - { - close (pfd [1]); - if (pfd [0] != 0) - { - dup2 (pfd [0], 0); - } - - /* Helper is invoked as helper service-name [user] */ - execlp (PASSWD_HELPER_PROGRAM, PASSWD_HELPER_PROGRAM, "mate-screensaver", user, NULL); - if (verbose) - { - g_message ("%s: %s", PASSWD_HELPER_PROGRAM, g_strerror (errno)); - } - - exit (1); - } - - close (pfd [0]); - - /* Write out password to helper process */ - if (!typed_passwd) - { - typed_passwd = ""; - } - write (pfd [1], typed_passwd, strlen (typed_passwd)); - close (pfd [1]); - - while (waitpid (pid, &status, 0) < 0) - { - if (errno == EINTR) - { - continue; - } - - if (verbose) - { - g_message ("ext_run: waitpid failed: %s\n", - g_strerror (errno)); - } - - unblock_sigchld (); - return FALSE; - } - - unblock_sigchld (); - - if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) - { - return FALSE; - } - - return TRUE; + int pfd[2], r_pfd[2], status; + pid_t pid; + gboolean verbose = gs_auth_get_verbose (); + + if (pipe (pfd) < 0 || pipe (r_pfd) < 0) + { + return FALSE; + } + + if (verbose) + { + g_message ("ext_run (%s, %s)", + PASSWD_HELPER_PROGRAM, user); + } + + block_sigchld (); + + if ((pid = fork ()) < 0) + { + close (pfd [0]); + close (pfd [1]); + close (r_pfd [0]); + close (r_pfd [1]); + return FALSE; + } + + if (pid == 0) + { + close (pfd [1]); + close (r_pfd [0]); + if (pfd [0] != 0) + { + dup2 (pfd [0], 0); + } + if (r_pfd [1] != 1) + { + dup2 (r_pfd [1], 1); + } + + /* Helper is invoked as helper service-name [user] */ + execlp (PASSWD_HELPER_PROGRAM, PASSWD_HELPER_PROGRAM, "mate-screensaver", user, NULL); + if (verbose) + { + g_message ("%s: %s", PASSWD_HELPER_PROGRAM, g_strerror (errno)); + } + + exit (1); + } + + close (pfd [0]); + close (r_pfd [1]); + + gboolean ret = FALSE; + while (waitpid (pid, &status, WNOHANG) == 0) + { + int msg_type; + char buf[MAXLEN]; + size_t msg_len = MAXLEN; + + msg_type = read_prompt (r_pfd [0], buf, &msg_len); + if (0 == msg_type) continue; + if (msg_type < 0) + { + g_message ("Error reading prompt (%d)", msg_type); + ret = FALSE; + goto exit; + } + + char *input = NULL; + func (msg_type, buf, &input, data); + + unsigned int input_len = input ? strlen (input) : 0; + ssize_t wt; + + wt = write_msg (pfd [1], input, input_len); + if (wt < 0) + { + g_message ("Error writing prompt reply (%li)", wt); + ret = FALSE; + goto exit; + } + } + + close (pfd [1]); + close (r_pfd [0]); + unblock_sigchld (); + + if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) + { + ret = FALSE; + } + else + ret = TRUE; + + exit: + return ret; } gboolean @@ -167,28 +190,7 @@ gs_auth_verify_user (const char *username, gpointer data, GError **error) { - gboolean res = FALSE; - char *password; - - password = NULL; - - /* ask for the password for user */ - if (func != NULL) - { - func (GS_AUTH_MESSAGE_PROMPT_ECHO_OFF, - "Password: ", - &password, - data); - } - - if (password == NULL) - { - return FALSE; - } - - res = ext_run (username, password, gs_auth_get_verbose ()); - - return res; + return ext_run (username, func, data); } gboolean diff --git a/src/gs-auth-pam.c b/src/gs-auth-pam.c index bad98af..734b80c 100644 --- a/src/gs-auth-pam.c +++ b/src/gs-auth-pam.c @@ -46,6 +46,7 @@ #include <gtk/gtk.h> #include "gs-auth.h" +#include "gs-auth-pam.h" #include "subprocs.h" @@ -126,33 +127,6 @@ gs_auth_get_verbose (void) return verbose_enabled; } -static GSAuthMessageStyle -pam_style_to_gs_style (int pam_style) -{ - GSAuthMessageStyle style; - - switch (pam_style) - { - case PAM_PROMPT_ECHO_ON: - style = GS_AUTH_MESSAGE_PROMPT_ECHO_ON; - break; - case PAM_PROMPT_ECHO_OFF: - style = GS_AUTH_MESSAGE_PROMPT_ECHO_OFF; - break; - case PAM_ERROR_MSG: - style = GS_AUTH_MESSAGE_ERROR_MSG; - break; - case PAM_TEXT_INFO: - style = GS_AUTH_MESSAGE_TEXT_INFO; - break; - default: - g_assert_not_reached (); - break; - } - - return style; -} - static gboolean auth_message_handler (GSAuthMessageStyle style, const char *msg, diff --git a/src/gs-auth-pam.h b/src/gs-auth-pam.h new file mode 100644 index 0000000..1d8a66f --- /dev/null +++ b/src/gs-auth-pam.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (c) 2019 Paul Wolneykien <[email protected]> + * + * 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 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#ifndef __GS_AUTH_PAM_H +#define __GS_AUTH_PAM_H + +#include "gs-auth.h" + +G_BEGIN_DECLS + +static inline GSAuthMessageStyle +pam_style_to_gs_style (int pam_style) +{ + GSAuthMessageStyle style; + + switch (pam_style) + { + case PAM_PROMPT_ECHO_ON: + style = GS_AUTH_MESSAGE_PROMPT_ECHO_ON; + break; + case PAM_PROMPT_ECHO_OFF: + style = GS_AUTH_MESSAGE_PROMPT_ECHO_OFF; + break; + case PAM_ERROR_MSG: + style = GS_AUTH_MESSAGE_ERROR_MSG; + break; + default /* PAM_TEXT_INFO */: + style = GS_AUTH_MESSAGE_TEXT_INFO; + } + + return style; +} + +G_END_DECLS + +#endif /* __GS_AUTH_PAM_H */ |