diff options
author | Paul Wolneykien <[email protected]> | 2021-10-15 17:29:51 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2021-10-15 16:29:51 +0200 |
commit | ed6e6065bf0e85b64317b5a34b9f7a36a0c839a6 (patch) | |
tree | 9327a81eb82146d7d43a5ec237040b12e2487de5 | |
parent | a2a282631d9ad88cf5e64f2379c5beb5ab3fab25 (diff) | |
download | mate-screensaver-ed6e6065bf0e85b64317b5a34b9f7a36a0c839a6.tar.bz2 mate-screensaver-ed6e6065bf0e85b64317b5a34b9f7a36a0c839a6.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]>
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | configure.ac | 25 | ||||
-rw-r--r-- | helper/Makefile.am | 27 | ||||
-rw-r--r-- | helper/helper_proto.c | 167 | ||||
-rw-r--r-- | helper/helper_proto.h | 53 | ||||
-rw-r--r-- | helper/pam-helper.c | 289 | ||||
-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 |
10 files changed, 733 insertions, 135 deletions
diff --git a/Makefile.am b/Makefile.am index 7bc464b..eca9048 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,12 @@ DISTCHECK_CONFIGURE_FLAGS = \ --enable-compile-warnings=no \ CFLAGS='-Wno-deprecated-declarations' -SUBDIRS = \ +SUBDIRS = +if BUILTIN_HELPER +SUBDIRS += helper +endif + +SUBDIRS += \ po \ src \ savers \ diff --git a/configure.ac b/configure.ac index 65325cd..7c203ed 100644 --- a/configure.ac +++ b/configure.ac @@ -816,30 +816,29 @@ fi # all in xscreensaver itself; the external program just does auth.) have_passwd_helper=no -with_passwd_helper_req=unspecified +builtin_helper=no AC_ARG_WITH(passwd-helper, [ --with-passwd-helper Include support for an external password verification helper program.], - [with_passwd_helper="$withval"; with_passwd_helper_req="$withval"],[with_passwd_helper=no]) + [with_passwd_helper="$withval"],[with_passwd_helper=no]) # no HANDLE_X_PATH_ARG for this one if test "$enable_locking" = no ; then - with_passwd_helper_req=no with_passwd_helper=no + builtin_helper=no fi case "$with_passwd_helper" in ""|no) : ;; /*) AC_DEFINE_UNQUOTED(PASSWD_HELPER_PROGRAM, "$with_passwd_helper", [Full pathname of password helper application]) + builtin_helper=no have_passwd_helper=yes;; *) echo "error: --with-passwd-helper needs full pathname of helper (not '$with_passwd_helper')." >&2 exit 1 esac -AM_CONDITIONAL(HAVE_PASSWD_HELPER, test x$have_passwd_helper = xyes) -AC_SUBST(HAVE_PASSWD_HELPER) if test "$need_setuid" = yes -a "$have_pam" != yes ; then NEED_SETUID=yes @@ -863,7 +862,9 @@ if test x$enable_authentication_scheme = xpam -a x$have_pam = xno ; then AC_MSG_ERROR(PAM support requested but not available) fi if test x$enable_authentication_scheme = xhelper -a x$have_passwd_helper = xno ; then - AC_MSG_ERROR(Password helper support requested but not available) + builtin_helper=yes + have_passwd_helper=yes + AC_DEFINE_UNQUOTED(PASSWD_HELPER_PROGRAM, [PKGLIBEXECDIR "/mate-screensaver-pam-helper"], [Full pathname of password helper application]) fi if test x$enable_authentication_scheme = xbsdauth -a x$have_bsdauth = xno ; then AC_MSG_ERROR(bsd_auth(3) support requested but not available) @@ -892,6 +893,9 @@ else fi AC_SUBST(AUTH_SCHEME) +AM_CONDITIONAL(HAVE_PASSWD_HELPER, test x$have_passwd_helper = xyes) +AM_CONDITIONAL(BUILTIN_HELPER, test x$builtin_helper = xyes) +AC_SUBST(HAVE_PASSWD_HELPER) dnl --------------------------------------------------------------------------- dnl ConsoleKit @@ -1001,6 +1005,14 @@ if test "x$have_libnotify" = "xyes"; then fi dnl --------------------------------------------------------------------------- +dnl glib headers for pam-helper +dnl --------------------------------------------------------------------------- + +PKG_CHECK_MODULES(PAM_HELPER, + glib-2.0 >= $GLIB_REQUIRED_VERSION) +AC_SUBST(PAM_HELPER_CFLAGS) + +dnl --------------------------------------------------------------------------- dnl Finish dnl --------------------------------------------------------------------------- @@ -1117,6 +1129,7 @@ data/images/cosmos/Makefile savers/Makefile doc/Makefile doc/mate-screensaver.xml +helper/Makefile ]) echo " diff --git a/helper/Makefile.am b/helper/Makefile.am new file mode 100644 index 0000000..7a0ab0a --- /dev/null +++ b/helper/Makefile.am @@ -0,0 +1,27 @@ +## We require new-style dependency handling. +AUTOMAKE_OPTIONS = 1.7 + +noinst_LIBRARIES = libhelper-proto.a + +libhelper_proto_a_CFLAGS = \ + $(PAM_HELPER_CFLAGS) \ + -I$(top_srcdir)/src + +libhelper_proto_a_SOURCES = \ + helper_proto.h \ + helper_proto.c + +pkglibexec_PROGRAMS = mate-screensaver-pam-helper + +mate_screensaver_pam_helper_CFLAGS = \ + $(PAM_HELPER_CFLAGS) \ + -I$(top_srcdir)/src + +mate_screensaver_pam_helper_SOURCES = \ + pam-helper.c + +mate_screensaver_pam_helper_LDADD = \ + libhelper-proto.a + +mate_screensaver_pam_helper_LDFLAGS = \ + $(AUTH_LIBS) diff --git a/helper/helper_proto.c b/helper/helper_proto.c new file mode 100644 index 0000000..3abe263 --- /dev/null +++ b/helper/helper_proto.c @@ -0,0 +1,167 @@ +/* Part of mate-screensaver. + * + * Copyright (c) 2019-2021 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. + */ + +/* Provides functions for two-way communication between the screensaver + * and the helper program. The idea of helper program is to be able to + * run mate-screensaver-dialog without any setuid bits. + */ + +#include "config.h" + +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "helper_proto.h" + +static ssize_t +read_all (int fd, void *buf, size_t count) +{ + ssize_t rd, t_rd = 0; + + if (0 == count) + return 0; + + while (t_rd < count) + { + rd = read (fd, buf + t_rd, count - t_rd); + if (0 == rd) + break; + if (rd < 0) + return rd; + t_rd += rd; + } + + return t_rd; +} + +ssize_t +read_msg (int fd, char *buf, size_t length) +{ + size_t msg_len; + ssize_t rd; + + rd = read_all (fd, &msg_len, sizeof msg_len); + if (rd < 0) + return HELPER_IO_ERR; + if (rd > 0 && rd != sizeof msg_len) + return HELPER_LENGTH_READ_ERR; + + if (msg_len >= length) + return HELPER_TOO_LONG_ERR; + + if (msg_len > 0) + { + rd = read_all (fd, buf, msg_len); + if (rd < 0) + return HELPER_IO_ERR; + if (rd != msg_len) + return HELPER_MSG_READ_ERR; + } + else + rd = 0; + buf[rd] = '\0'; + + return rd; +} + +int +read_prompt (int fd, char *buf, size_t *length) +{ + int msg_type, rd; + + rd = read_all (fd, &msg_type, sizeof msg_type); + if (0 == rd) + return 0; + if (rd < 0) + return HELPER_IO_ERR; + if (rd > 0 && rd != sizeof msg_type) + return HELPER_TYPE_READ_ERR; + + rd = read_msg (fd, buf, *length); + if (rd < 0) + return rd; + + *length = rd; + return msg_type; +} + +static ssize_t +write_all (int fd, const void *buf, size_t count) +{ + ssize_t wt, t_wt = 0; + + if (0 == count) + return 0; + + while (t_wt < count) + { + wt = write (fd, buf + t_wt, count - t_wt); + if (0 == wt) + break; + if (wt < 0) + return wt; + t_wt += wt; + } + + return t_wt; +} + +ssize_t +write_msg (int fd, const void *buf, size_t length) +{ + ssize_t wt; + + wt = write_all (fd, &length, sizeof length); + if (wt < 0) + return HELPER_IO_ERR; + if (wt > 0 && wt != sizeof length) + return HELPER_LENGTH_WRITE_ERR; + + if (length > 0) + { + wt = write_all (fd, buf, length); + if (wt < 0) + return HELPER_IO_ERR; + if (wt != length) + return HELPER_MSG_WRITE_ERR; + } + else + wt = 0; + + return wt; +} + +int +write_prompt (int fd, int msg_type, const void *buf, size_t length) +{ + ssize_t wt; + + wt = write_all (fd, &msg_type, sizeof msg_type); + if (wt < 0) + return HELPER_IO_ERR; + if (wt > 0 && wt != sizeof msg_type) + return HELPER_TYPE_WRITE_ERR; + + wt = write_msg (fd, buf, length); + + return wt; +} diff --git a/helper/helper_proto.h b/helper/helper_proto.h new file mode 100644 index 0000000..b815b52 --- /dev/null +++ b/helper/helper_proto.h @@ -0,0 +1,53 @@ +/* Part of mate-screensaver. + * + * Copyright (c) 2019-2021 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. + */ + +/* Provides functions for two-way communication between the screensaver + * and the helper program. The idea of helper program is to be able to + * run mate-screensaver-dialog without any setuid bits. + */ + +#ifndef __HELPER_PROTO_H +#define __HELPER_PROTO_H + +#include "config.h" + +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define HELPER_IO_ERR -1 + +#define HELPER_LENGTH_READ_ERR -2 +#define HELPER_TOO_LONG_ERR -3 +#define HELPER_MSG_READ_ERR -4 +#define HELPER_TYPE_READ_ERR -5 + +ssize_t read_msg (int fd, char *buf, size_t length); +int read_prompt (int fd, char *buf, size_t *length); + +#define HELPER_LENGTH_WRITE_ERR -6 +#define HELPER_MSG_WRITE_ERR -7 +#define HELPER_TYPE_WRITE_ERR -8 + +ssize_t write_msg (int fd, const void *buf, size_t length); +int write_prompt (int fd, int msg_type, const void *buf, size_t length); + +#endif /* __HELPER_PROTO_H */ diff --git a/helper/pam-helper.c b/helper/pam-helper.c new file mode 100644 index 0000000..c2bd837 --- /dev/null +++ b/helper/pam-helper.c @@ -0,0 +1,289 @@ +/* Part of mate-screensaver. + * + * Copyright (C) 2002 SuSE Linux AG. + * Copyright (c) 2019-2021 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. + */ + +/* + * Set*id helper program for PAM authentication. + * + * It is supposed to be called from mate-screensaver + * in order to communicate with Linux PAM as a privileged proxy. + * The conversation messages from the PAM stack is transmitted to + * mate-screensaver dialog via stdout and the received user replies + * read from stdin are sent back to PAM. + * + * Based on the helper written by [email protected], loosely based on + * unix_chkpwd by Andrew Morgan. + */ + +#include <security/pam_appl.h> +#include <security/_pam_macros.h> + +#include <sys/types.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <pwd.h> +#include <signal.h> +#include <fcntl.h> +#include <ctype.h> +#include <limits.h> + +#include "helper_proto.h" +#include "gs-auth-pam.h" + +#define MAXLEN 1024 + +enum { + UNIX_PASSED = 0, + UNIX_FAILED = 1 +}; + +static char * program_name; + +/* + * Log error messages + */ +static void +_log_err(int err, const char *format,...) +{ + va_list args; + + va_start(args, format); + openlog(program_name, LOG_CONS | LOG_PID, LOG_AUTH); + vsyslog(err, format, args); + va_end(args); + closelog(); +} + +static void +su_sighandler(int sig) +{ + if (sig > 0) { + _log_err(LOG_NOTICE, "caught signal %d.", sig); + exit(sig); + } +} + +/* + * Setup signal handlers + */ +static void +setup_signals(void) +{ + struct sigaction action; + + memset((void *) &action, 0, sizeof(action)); + action.sa_handler = su_sighandler; + action.sa_flags = SA_RESETHAND; + sigaction(SIGILL, &action, NULL); + sigaction(SIGTRAP, &action, NULL); + sigaction(SIGBUS, &action, NULL); + sigaction(SIGSEGV, &action, NULL); + action.sa_handler = SIG_IGN; + action.sa_flags = 0; + sigaction(SIGTERM, &action, NULL); + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGQUIT, &action, NULL); + sigaction(SIGALRM, &action, NULL); +} + +static int +_converse(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + struct pam_response *reply = NULL; + char buf[MAXLEN]; + int num; + int ret = PAM_SUCCESS; + + if (!(reply = malloc(sizeof(*reply) * num_msg))) + return PAM_CONV_ERR; + + for (num = 0; num < num_msg; num++) { + ssize_t wt, rd; + size_t msg_len = strlen(msg[num]->msg); + wt = write_prompt (STDOUT_FILENO, + pam_style_to_gs_style (msg[num]->msg_style), + msg[num]->msg, msg_len); + if (wt < 0 || wt != msg_len) { + _log_err(LOG_ERR, "error writing promt"); + ret = PAM_CONV_ERR; + break; + } + + rd = read_msg (STDIN_FILENO, buf, sizeof (buf)); + if (rd < 0) { + _log_err(LOG_ERR, "error reading reply"); + ret = PAM_CONV_ERR; + break; + } + + reply[num].resp = malloc (rd + 1); + if (!reply[num].resp) + ret = PAM_BUF_ERR; + else { + reply[num].resp_retcode = 0; + memcpy (reply[num].resp, buf, rd); + reply[num].resp[rd] = '\0'; + } + } + + if (ret != PAM_SUCCESS && reply != NULL) { + for (num = 0; num < num_msg; num++) + free (reply[num].resp); + free (reply); + *resp = NULL; + } else + *resp = reply; + + return ret; +} + +static int +_authenticate(const char *service, const char *user) +{ + struct pam_conv conv = { _converse, NULL }; + pam_handle_t *pamh; + int err; + + err = pam_start(service, user, &conv, &pamh); + if (err != PAM_SUCCESS) { + _log_err(LOG_ERR, "pam_start(%s, %s) failed (errno %d)", + service, user, err); + return UNIX_FAILED; + } + + err = pam_authenticate(pamh, 0); + if (err != PAM_SUCCESS) + _log_err(LOG_ERR, "pam_authenticate(%s, %s): %s", + service, user, + pam_strerror(pamh, err)); + + if (err == PAM_SUCCESS) + { + int err2 = pam_setcred(pamh, PAM_REFRESH_CRED); + if (err2 != PAM_SUCCESS) + _log_err(LOG_ERR, "pam_setcred(%s, %s): %s", + service, user, + pam_strerror(pamh, err2)); + /* + * ignore errors on refresh credentials. + * If this did not work we use the old once. + */ + } + + pam_end(pamh, err); + + if (err != PAM_SUCCESS) + return UNIX_FAILED; + return UNIX_PASSED; +} + +static char * +getuidname(uid_t uid) +{ + struct passwd *pw; + static char username[32]; + + pw = getpwuid(uid); + if (pw == NULL) + return NULL; + + strncpy(username, pw->pw_name, sizeof(username)); + username[sizeof(username) - 1] = '\0'; + + endpwent(); + return username; +} + +int +main(int argc, char *argv[]) +{ + const char *program_name; + char *service, *user; + int fd; + uid_t uid; + + uid = getuid(); + + /* + * Make sure standard file descriptors are connected. + */ + while ((fd = open("/dev/null", O_RDWR)) <= 2) + ; + close(fd); + + /* + * Get the program name + */ + if ((program_name = strrchr(argv[0], '/')) != NULL) + program_name++; + else + program_name = argv[0]; + + /* + * Catch or ignore as many signal as possible. + */ + setup_signals(); + + /* + * Check argument list + */ + if (argc < 2 || argc > 3) { + _log_err(LOG_NOTICE, "Bad number of arguments (%d)", argc); + return UNIX_FAILED; + } + + /* + * Get the service name. + */ + service = argv[1]; + + /* + * Discourage users messing around (fat chance) + */ + if (isatty(STDIN_FILENO) && uid != 0) { + _log_err(LOG_NOTICE, + "Inappropriate use of Unix helper binary [UID=%d]", + uid); + fprintf(stderr, + "This binary is not designed for running in this way\n" + "-- the system administrator has been informed\n"); + sleep(10); /* this should discourage/annoy the user */ + return UNIX_FAILED; + } + + /* + * determine the caller's user name + */ + user = getuidname(uid); + if (argc == 3 && strcmp(user, argv[2])) { + user = argv[2]; + /* Discourage use of this program as a + * password cracker */ + if (uid != 0) + sleep(5); + } + return _authenticate(service, user); +} 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 */ |