From 8575afa0eb3a3f38642e28ec5ab109bc128c62dd Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Tue, 5 Oct 2010 21:53:39 +0300 Subject: Implement echo control on fd streams. Implement mu_getpass function. * configure.ac: Test for tcgetattr and tcsetattr. * gnulib.modules (getpass-gnu): Remove. * include/mailutils/mutil.h (mu_getpass): New proto. * include/mailutils/stream.h (MU_IOCTL_GET_ECHO) (MU_IOCTL_SET_ECHO): New ioctls. * include/mailutils/sys/file_stream.h (_MU_FILE_STREAM_ECHO_OFF): New flag. (_mu_file_stream) : New member. * libmailutils/getpass.c: New file. * libmailutils/Makefile.am (libmailutils_la_SOURCES): Add getpass.c. * libmailutils/file_stream.c (fd_done): Free echo_state. (fd_ioctl): Implement MU_IOCTL_GET_ECHO and MU_IOCTL_SET_ECHO. * mu/mu.h (mustrin): New extern. * mu/pop.c (com_pass): Use mu_getpass. * mu/shell.c (mustrin): New variable. (readline): Use mu_stream_getline instead of getline. (mutool_shell): Create mustrin. * pop3d/popauth.c (options): Fix typo. (fill_pass): Use mu_getpass. --- configure.ac | 2 +- gnulib.modules | 1 - include/mailutils/mutil.h | 2 + include/mailutils/stream.h | 3 ++ include/mailutils/sys/file_stream.h | 4 +- libmailutils/Makefile.am | 1 + libmailutils/file_stream.c | 94 +++++++++++++++++++++++++++++++++---- libmailutils/getpass.c | 59 +++++++++++++++++++++++ mu/mu.h | 2 +- mu/pop.c | 35 +++----------- mu/shell.c | 28 ++++++++--- pop3d/popauth.c | 68 ++++++++++++++++++++------- 12 files changed, 236 insertions(+), 63 deletions(-) create mode 100644 libmailutils/getpass.c diff --git a/configure.ac b/configure.ac index 509a56991..796c4687a 100644 --- a/configure.ac +++ b/configure.ac @@ -515,7 +515,7 @@ extern char *strsignal (int); ]) AC_CHECK_FUNCS(mkstemp sigaction sysconf getdelim setreuid \ - setresuid seteuid setlocale vfork _exit) + setresuid seteuid setlocale vfork _exit tcgetattr tcsetattr) AC_FUNC_FSEEKO AC_FUNC_SETVBUF_REVERSED diff --git a/gnulib.modules b/gnulib.modules index 4368cf7c2..66399597e 100644 --- a/gnulib.modules +++ b/gnulib.modules @@ -8,7 +8,6 @@ autobuild argp crypto/des getline -getpass-gnu gettext gitlog-to-changelog intprops diff --git a/include/mailutils/mutil.h b/include/mailutils/mutil.h index 7acc021cf..86d2243e7 100644 --- a/include/mailutils/mutil.h +++ b/include/mailutils/mutil.h @@ -157,6 +157,8 @@ extern int mu_stream_flags_to_mode (int flags, int isdir); extern int mu_parse_stream_perm_string (int *pmode, const char *str, const char **endp); +extern int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, + char **passptr); #ifdef __cplusplus } diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index c076ade11..d951f3425 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -74,6 +74,9 @@ enum mu_buffer_type #define MU_IOCTL_GET_TRANSPORT_BUFFER 10 #define MU_IOCTL_SET_TRANSPORT_BUFFER 11 +#define MU_IOCTL_GET_ECHO 12 +#define MU_IOCTL_SET_ECHO 13 + #define MU_TRANSPORT_INPUT 0 #define MU_TRANSPORT_OUTPUT 1 #define MU_TRANSPORT_VALID_TYPE(n) \ diff --git a/include/mailutils/sys/file_stream.h b/include/mailutils/sys/file_stream.h index 70c576ab7..581d28941 100644 --- a/include/mailutils/sys/file_stream.h +++ b/include/mailutils/sys/file_stream.h @@ -21,7 +21,8 @@ #include #include -#define _MU_FILE_STREAM_TEMP 0x01 +#define _MU_FILE_STREAM_TEMP 0x01 +#define _MU_FILE_STREAM_ECHO_OFF 0x02 struct _mu_file_stream { @@ -29,6 +30,7 @@ struct _mu_file_stream int fd; int flags; char *filename; + void *echo_state; }; int _mu_file_stream_create (struct _mu_file_stream **pstream, size_t size, diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index e05edd883..3f083e01d 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -84,6 +84,7 @@ libmailutils_la_SOURCES = \ folder.c\ freeitem.c\ gdebug.c\ + getpass.c\ gocs.c\ hdritr.c\ header.c\ diff --git a/libmailutils/file_stream.c b/libmailutils/file_stream.c index 247768c25..578f4829e 100644 --- a/libmailutils/file_stream.c +++ b/libmailutils/file_stream.c @@ -23,6 +23,9 @@ #include #include #include +#if HAVE_TERMIOS_H +# include +#endif #include #include @@ -183,6 +186,8 @@ fd_done (struct _mu_stream *str) fd_close (str); if (fstr->filename) free (fstr->filename); + if (fstr->echo_state) + free (fstr->echo_state); } const char * @@ -194,6 +199,10 @@ fd_error_string (struct _mu_stream *str, int rc) return mu_strerror (rc); } +#ifndef TCSASOFT +# define TCSASOFT 0 +#endif + static int fd_ioctl (struct _mu_stream *str, int code, void *ptr) { @@ -218,17 +227,86 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr) break; case MU_IOCTL_GET_TRANSPORT_BUFFER: - { - struct mu_buffer_query *qp = ptr; - return mu_stream_get_buffer (str, qp); - } + if (!ptr) + return EINVAL; + else + { + struct mu_buffer_query *qp = ptr; + return mu_stream_get_buffer (str, qp); + } case MU_IOCTL_SET_TRANSPORT_BUFFER: - { - struct mu_buffer_query *qp = ptr; - return mu_stream_set_buffer (str, qp->buftype, qp->bufsize); - } + if (!ptr) + return EINVAL; + else + { + struct mu_buffer_query *qp = ptr; + return mu_stream_set_buffer (str, qp->buftype, qp->bufsize); + } + + case MU_IOCTL_SET_ECHO: + if (!ptr) + return EINVAL; + else + { + int status; + struct termios t; + int state = *(int*)ptr; +#if HAVE_TCGETATTR + if (state == 0) + { + if (fstr->flags & _MU_FILE_STREAM_ECHO_OFF) + return 0; + status = tcgetattr (fstr->fd, &t); + if (status == 0) + { + fstr->echo_state = malloc (sizeof (t)); + if (!fstr->echo_state) + return ENOMEM; + memcpy (fstr->echo_state, &t, sizeof (t)); + + t.c_lflag &= ~(ECHO | ISIG); + status = tcsetattr (fstr->fd, TCSAFLUSH | TCSASOFT, &t); + if (status == 0) + fstr->flags |= _MU_FILE_STREAM_ECHO_OFF; + } + if (status) + { + status = errno; + if (fstr->echo_state) + { + free (fstr->echo_state); + fstr->echo_state = NULL; + } + } + } + else + { + if (!(fstr->flags & _MU_FILE_STREAM_ECHO_OFF)) + return 0; + if (tcsetattr (fstr->fd, TCSAFLUSH | TCSASOFT, fstr->echo_state)) + status = errno; + else + { + status = 0; + free (fstr->echo_state); + fstr->echo_state = NULL; + fstr->flags &= ~_MU_FILE_STREAM_ECHO_OFF; + } + } + return status; +#else + return ENOSYS; +#endif + } + case MU_IOCTL_GET_ECHO: + if (!ptr) + return EINVAL; + else + *(int*)ptr = fstr->flags & _MU_FILE_STREAM_ECHO_OFF; + break; + default: return ENOSYS; } diff --git a/libmailutils/getpass.c b/libmailutils/getpass.c new file mode 100644 index 000000000..8a37c52cc --- /dev/null +++ b/libmailutils/getpass.c @@ -0,0 +1,59 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2004, + 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include +#include + +int +mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt, + char **passptr) +{ + int status; + int echo_state = 0; + size_t size = 0; + char *buf = NULL; + + status = mu_stream_write (out, prompt, strlen (prompt), NULL); + if (status) + return status; + mu_stream_flush (out); + status = mu_stream_ioctl (in, MU_IOCTL_SET_ECHO, &echo_state); + if (status == 0) + echo_state = 1; + status = mu_stream_getline (in, &buf, &size, NULL); + if (echo_state) + { + mu_stream_ioctl (in, MU_IOCTL_SET_ECHO, &echo_state); + mu_stream_write (out, "\n", 1, NULL); + } + if (status == 0) + { + mu_rtrim_cset (buf, "\n"); + *passptr = buf; + } + return 0; +} + diff --git a/mu/mu.h b/mu/mu.h index 8ae5fc1d2..26d5d59ca 100644 --- a/mu/mu.h +++ b/mu/mu.h @@ -38,6 +38,6 @@ int mutool_acl (int argc, char **argv); extern char *mutool_shell_prompt; extern mu_vartab_t mutool_prompt_vartab; extern int mutool_shell_interactive; -extern mu_stream_t mustrout; +extern mu_stream_t mustrin, mustrout; int mutool_shell (const char *name, struct mutool_command *cmd); mu_stream_t mutool_open_pager (void); diff --git a/mu/pop.c b/mu/pop.c index 59fed1517..b3a1592f9 100644 --- a/mu/pop.c +++ b/mu/pop.c @@ -454,42 +454,18 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) return mu_pop3_noop (pop3); } -static void -echo_off (struct termios *stored_settings) -{ - struct termios new_settings; - tcgetattr (0, stored_settings); - new_settings = *stored_settings; - new_settings.c_lflag &= (~ECHO); - tcsetattr (0, TCSANOW, &new_settings); -} - -static void -echo_on (struct termios *stored_settings) -{ - tcsetattr (0, TCSANOW, stored_settings); -} - static int com_pass (int argc, char **argv) { int status; - char pass[256]; - char *pwd; + char *pwd, *passbuf = NULL; if (argc == 1) { - struct termios stored_settings; - - printf ("passwd:"); - fflush (stdout); - echo_off (&stored_settings); - fgets (pass, sizeof pass, stdin); - echo_on (&stored_settings); - putchar ('\n'); - fflush (stdout); - pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */ - pwd = pass; + status = mu_getpass (mustrin, mustrout, "Password:", &passbuf); + if (status) + return status; + pwd = passbuf; } else pwd = argv[1]; @@ -499,6 +475,7 @@ com_pass (int argc, char **argv) pop_session_status = pop_session_logged_in; pop_prompt_vartab (); } + free (passbuf); return status; } diff --git a/mu/shell.c b/mu/shell.c index 4abaef4dc..1ca73e79a 100644 --- a/mu/shell.c +++ b/mu/shell.c @@ -33,7 +33,7 @@ char *mutool_shell_prompt; mu_vartab_t mutool_prompt_vartab; int mutool_shell_interactive; -mu_stream_t mustrout; +mu_stream_t mustrin, mustrout; static char * expand_prompt () @@ -370,8 +370,13 @@ readline (char *prompt) mu_stream_printf (mustrout, "%s", prompt); fflush (stdout); } - if (getline (&buf, &size, stdin) <= 0) - return NULL; + if (mu_stream_getline (mustrin, &buf, &size, &n) || n == 0) + { + free (buf); + buf = NULL; + size = 0; + return NULL; + } return buf; } @@ -466,14 +471,24 @@ mutool_shell (const char *name, struct mutool_command *cmd) size_t n; char *(*input_line) (); + rc = mu_stdio_stream_create (&mustrin, MU_STDIN_FD, + MU_STREAM_READ); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", + "MU_STDIN_FD", rc); + return 1; + } + rc = mu_stdio_stream_create (&mustrout, MU_STDOUT_FD, MU_STREAM_WRITE); if (rc) { - mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", "1", rc); + mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", + "MU_STDOUT_FD", rc); return 1; - } - + } + mutool_shell_interactive = isatty (0); input_line = mutool_shell_interactive ? input_line_interactive : input_line_script; @@ -521,6 +536,7 @@ mutool_shell (const char *name, struct mutool_command *cmd) } if (mutool_shell_interactive) finish_readline (); + mu_stream_destroy (&mustrin); mu_stream_destroy (&mustrout); return 0; } diff --git a/pop3d/popauth.c b/pop3d/popauth.c index 9f73d60ed..f8505f949 100644 --- a/pop3d/popauth.c +++ b/pop3d/popauth.c @@ -74,7 +74,7 @@ static struct argp_option options[] = { NULL, 0, NULL, 0, N_("Default action is:\n" " For the file owner: --list\n" - " For a user: --modify --username \n"), 2 }, + " For a user: --modify --user \n"), 2 }, { NULL, 0, NULL, 0, N_("Options are:"), 3 }, { "file", 'f', N_("FILE"), 0, N_("read input from FILE (default stdin)"), 3 }, @@ -105,7 +105,7 @@ set_db_perms (struct argp_state *astate, char *opt, int *pperm) { int perm = 0; - if (mu_isdigit(opt[0])) + if (mu_isdigit (opt[0])) { char *p; perm = strtoul (opt, &p, 8); @@ -446,21 +446,57 @@ fill_pass (struct action_data *ap) if (!ap->passwd) { char *p; + mu_stream_t in, out; + int rc; + + rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", + "MU_STDIN_FD", rc); + return; + } + + rc = mu_stdio_stream_create (&out, MU_STDOUT_FD, MU_STREAM_WRITE); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", + "MU_STDOUT_FD", rc); + return; + } - while (1) { - if (ap->passwd) - free (ap->passwd); - p = getpass (_("Password:")); - if (!p) - exit (EX_DATAERR); - ap->passwd = strdup (p); - /* TRANSLATORS: Please try to format this string so that it has - the same length as the translation of 'Password:' above */ - p = getpass (_("Confirm :")); - if (strcmp (ap->passwd, p) == 0) - break; - mu_error (_("Passwords differ. Please retry.")); - } + while (1) + { + if (ap->passwd) + free (ap->passwd); + rc = mu_getpass (in, out, _("Password:"), &p); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_getpass", NULL, rc); + exit (EX_DATAERR); + } + + if (!p) + exit (EX_DATAERR); + + ap->passwd = strdup (p); + /* TRANSLATORS: Please try to format this string so that it has + the same length as the translation of 'Password:' above */ + rc = mu_getpass (in, out, _("Confirm :"), &p); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_getpass", NULL, rc); + exit (EX_DATAERR); + } + + if (!p) + exit (EX_DATAERR); + if (strcmp (ap->passwd, p) == 0) + break; + mu_error (_("Passwords differ. Please retry.")); + } + mu_stream_destroy (&in); + mu_stream_destroy (&out); } } -- cgit v1.2.1