Commit 8575afa0 8575afa0eb3a3f38642e28ec5ab109bc128c62dd by Sergey Poznyakoff

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) <echo_state>: 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.
1 parent 63d1c196
......@@ -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
......
......@@ -8,7 +8,6 @@ autobuild
argp
crypto/des
getline
getpass-gnu
gettext
gitlog-to-changelog
intprops
......
......@@ -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
}
......
......@@ -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) \
......
......@@ -22,6 +22,7 @@
#include <mailutils/sys/stream.h>
#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,
......
......@@ -84,6 +84,7 @@ libmailutils_la_SOURCES = \
folder.c\
freeitem.c\
gdebug.c\
getpass.c\
gocs.c\
hdritr.c\
header.c\
......
......@@ -23,6 +23,9 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#if HAVE_TERMIOS_H
# include <termios.h>
#endif
#include <mailutils/types.h>
#include <mailutils/alloc.h>
......@@ -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:
if (!ptr)
return EINVAL;
else
{
struct mu_buffer_query *qp = ptr;
return mu_stream_get_buffer (str, qp);
}
case MU_IOCTL_SET_TRANSPORT_BUFFER:
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;
}
......
/* 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 <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/stream.h>
#include <mailutils/mutil.h>
#include <mailutils/cstr.h>
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;
}
......@@ -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);
......
......@@ -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;
}
......
......@@ -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)
if (mu_stream_getline (mustrin, &buf, &size, &n) || n == 0)
{
free (buf);
buf = NULL;
size = 0;
return NULL;
}
return buf;
}
......@@ -466,11 +471,21 @@ 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;
}
......@@ -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;
}
......
......@@ -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 <username>\n"), 2 },
" For a user: --modify --user <username>\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) {
while (1)
{
if (ap->passwd)
free (ap->passwd);
p = getpass (_("Password:"));
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 */
p = getpass (_("Confirm :"));
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);
}
}
......