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); ...@@ -515,7 +515,7 @@ extern char *strsignal (int);
515 ]) 515 ])
516 516
517 AC_CHECK_FUNCS(mkstemp sigaction sysconf getdelim setreuid \ 517 AC_CHECK_FUNCS(mkstemp sigaction sysconf getdelim setreuid \
518 setresuid seteuid setlocale vfork _exit) 518 setresuid seteuid setlocale vfork _exit tcgetattr tcsetattr)
519 519
520 AC_FUNC_FSEEKO 520 AC_FUNC_FSEEKO
521 AC_FUNC_SETVBUF_REVERSED 521 AC_FUNC_SETVBUF_REVERSED
......
...@@ -8,7 +8,6 @@ autobuild ...@@ -8,7 +8,6 @@ autobuild
8 argp 8 argp
9 crypto/des 9 crypto/des
10 getline 10 getline
11 getpass-gnu
12 gettext 11 gettext
13 gitlog-to-changelog 12 gitlog-to-changelog
14 intprops 13 intprops
......
...@@ -157,6 +157,8 @@ extern int mu_stream_flags_to_mode (int flags, int isdir); ...@@ -157,6 +157,8 @@ extern int mu_stream_flags_to_mode (int flags, int isdir);
157 extern int mu_parse_stream_perm_string (int *pmode, const char *str, 157 extern int mu_parse_stream_perm_string (int *pmode, const char *str,
158 const char **endp); 158 const char **endp);
159 159
160 extern int mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt,
161 char **passptr);
160 162
161 #ifdef __cplusplus 163 #ifdef __cplusplus
162 } 164 }
......
...@@ -74,6 +74,9 @@ enum mu_buffer_type ...@@ -74,6 +74,9 @@ enum mu_buffer_type
74 #define MU_IOCTL_GET_TRANSPORT_BUFFER 10 74 #define MU_IOCTL_GET_TRANSPORT_BUFFER 10
75 #define MU_IOCTL_SET_TRANSPORT_BUFFER 11 75 #define MU_IOCTL_SET_TRANSPORT_BUFFER 11
76 76
77 #define MU_IOCTL_GET_ECHO 12
78 #define MU_IOCTL_SET_ECHO 13
79
77 #define MU_TRANSPORT_INPUT 0 80 #define MU_TRANSPORT_INPUT 0
78 #define MU_TRANSPORT_OUTPUT 1 81 #define MU_TRANSPORT_OUTPUT 1
79 #define MU_TRANSPORT_VALID_TYPE(n) \ 82 #define MU_TRANSPORT_VALID_TYPE(n) \
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
21 #include <mailutils/stream.h> 21 #include <mailutils/stream.h>
22 #include <mailutils/sys/stream.h> 22 #include <mailutils/sys/stream.h>
23 23
24 #define _MU_FILE_STREAM_TEMP 0x01 24 #define _MU_FILE_STREAM_TEMP 0x01
25 #define _MU_FILE_STREAM_ECHO_OFF 0x02
25 26
26 struct _mu_file_stream 27 struct _mu_file_stream
27 { 28 {
...@@ -29,6 +30,7 @@ struct _mu_file_stream ...@@ -29,6 +30,7 @@ struct _mu_file_stream
29 int fd; 30 int fd;
30 int flags; 31 int flags;
31 char *filename; 32 char *filename;
33 void *echo_state;
32 }; 34 };
33 35
34 int _mu_file_stream_create (struct _mu_file_stream **pstream, size_t size, 36 int _mu_file_stream_create (struct _mu_file_stream **pstream, size_t size,
......
...@@ -84,6 +84,7 @@ libmailutils_la_SOURCES = \ ...@@ -84,6 +84,7 @@ libmailutils_la_SOURCES = \
84 folder.c\ 84 folder.c\
85 freeitem.c\ 85 freeitem.c\
86 gdebug.c\ 86 gdebug.c\
87 getpass.c\
87 gocs.c\ 88 gocs.c\
88 hdritr.c\ 89 hdritr.c\
89 header.c\ 90 header.c\
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
23 #include <unistd.h> 23 #include <unistd.h>
24 #include <fcntl.h> 24 #include <fcntl.h>
25 #include <sys/stat.h> 25 #include <sys/stat.h>
26 #if HAVE_TERMIOS_H
27 # include <termios.h>
28 #endif
26 29
27 #include <mailutils/types.h> 30 #include <mailutils/types.h>
28 #include <mailutils/alloc.h> 31 #include <mailutils/alloc.h>
...@@ -183,6 +186,8 @@ fd_done (struct _mu_stream *str) ...@@ -183,6 +186,8 @@ fd_done (struct _mu_stream *str)
183 fd_close (str); 186 fd_close (str);
184 if (fstr->filename) 187 if (fstr->filename)
185 free (fstr->filename); 188 free (fstr->filename);
189 if (fstr->echo_state)
190 free (fstr->echo_state);
186 } 191 }
187 192
188 const char * 193 const char *
...@@ -194,6 +199,10 @@ fd_error_string (struct _mu_stream *str, int rc) ...@@ -194,6 +199,10 @@ fd_error_string (struct _mu_stream *str, int rc)
194 return mu_strerror (rc); 199 return mu_strerror (rc);
195 } 200 }
196 201
202 #ifndef TCSASOFT
203 # define TCSASOFT 0
204 #endif
205
197 static int 206 static int
198 fd_ioctl (struct _mu_stream *str, int code, void *ptr) 207 fd_ioctl (struct _mu_stream *str, int code, void *ptr)
199 { 208 {
...@@ -218,17 +227,86 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr) ...@@ -218,17 +227,86 @@ fd_ioctl (struct _mu_stream *str, int code, void *ptr)
218 break; 227 break;
219 228
220 case MU_IOCTL_GET_TRANSPORT_BUFFER: 229 case MU_IOCTL_GET_TRANSPORT_BUFFER:
221 { 230 if (!ptr)
222 struct mu_buffer_query *qp = ptr; 231 return EINVAL;
223 return mu_stream_get_buffer (str, qp); 232 else
224 } 233 {
234 struct mu_buffer_query *qp = ptr;
235 return mu_stream_get_buffer (str, qp);
236 }
225 237
226 case MU_IOCTL_SET_TRANSPORT_BUFFER: 238 case MU_IOCTL_SET_TRANSPORT_BUFFER:
227 { 239 if (!ptr)
228 struct mu_buffer_query *qp = ptr; 240 return EINVAL;
229 return mu_stream_set_buffer (str, qp->buftype, qp->bufsize); 241 else
230 } 242 {
243 struct mu_buffer_query *qp = ptr;
244 return mu_stream_set_buffer (str, qp->buftype, qp->bufsize);
245 }
246
247 case MU_IOCTL_SET_ECHO:
248 if (!ptr)
249 return EINVAL;
250 else
251 {
252 int status;
253 struct termios t;
254 int state = *(int*)ptr;
255 #if HAVE_TCGETATTR
256 if (state == 0)
257 {
258 if (fstr->flags & _MU_FILE_STREAM_ECHO_OFF)
259 return 0;
260 status = tcgetattr (fstr->fd, &t);
261 if (status == 0)
262 {
263 fstr->echo_state = malloc (sizeof (t));
264 if (!fstr->echo_state)
265 return ENOMEM;
266 memcpy (fstr->echo_state, &t, sizeof (t));
267
268 t.c_lflag &= ~(ECHO | ISIG);
269 status = tcsetattr (fstr->fd, TCSAFLUSH | TCSASOFT, &t);
270 if (status == 0)
271 fstr->flags |= _MU_FILE_STREAM_ECHO_OFF;
272 }
273 if (status)
274 {
275 status = errno;
276 if (fstr->echo_state)
277 {
278 free (fstr->echo_state);
279 fstr->echo_state = NULL;
280 }
281 }
282 }
283 else
284 {
285 if (!(fstr->flags & _MU_FILE_STREAM_ECHO_OFF))
286 return 0;
287 if (tcsetattr (fstr->fd, TCSAFLUSH | TCSASOFT, fstr->echo_state))
288 status = errno;
289 else
290 {
291 status = 0;
292 free (fstr->echo_state);
293 fstr->echo_state = NULL;
294 fstr->flags &= ~_MU_FILE_STREAM_ECHO_OFF;
295 }
296 }
297 return status;
298 #else
299 return ENOSYS;
300 #endif
301 }
231 302
303 case MU_IOCTL_GET_ECHO:
304 if (!ptr)
305 return EINVAL;
306 else
307 *(int*)ptr = fstr->flags & _MU_FILE_STREAM_ECHO_OFF;
308 break;
309
232 default: 310 default:
233 return ENOSYS; 311 return ENOSYS;
234 } 312 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2004,
3 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <mailutils/types.h>
26 #include <mailutils/stream.h>
27 #include <mailutils/mutil.h>
28 #include <mailutils/cstr.h>
29
30 int
31 mu_getpass (mu_stream_t in, mu_stream_t out, const char *prompt,
32 char **passptr)
33 {
34 int status;
35 int echo_state = 0;
36 size_t size = 0;
37 char *buf = NULL;
38
39 status = mu_stream_write (out, prompt, strlen (prompt), NULL);
40 if (status)
41 return status;
42 mu_stream_flush (out);
43 status = mu_stream_ioctl (in, MU_IOCTL_SET_ECHO, &echo_state);
44 if (status == 0)
45 echo_state = 1;
46 status = mu_stream_getline (in, &buf, &size, NULL);
47 if (echo_state)
48 {
49 mu_stream_ioctl (in, MU_IOCTL_SET_ECHO, &echo_state);
50 mu_stream_write (out, "\n", 1, NULL);
51 }
52 if (status == 0)
53 {
54 mu_rtrim_cset (buf, "\n");
55 *passptr = buf;
56 }
57 return 0;
58 }
59
...@@ -38,6 +38,6 @@ int mutool_acl (int argc, char **argv); ...@@ -38,6 +38,6 @@ int mutool_acl (int argc, char **argv);
38 extern char *mutool_shell_prompt; 38 extern char *mutool_shell_prompt;
39 extern mu_vartab_t mutool_prompt_vartab; 39 extern mu_vartab_t mutool_prompt_vartab;
40 extern int mutool_shell_interactive; 40 extern int mutool_shell_interactive;
41 extern mu_stream_t mustrout; 41 extern mu_stream_t mustrin, mustrout;
42 int mutool_shell (const char *name, struct mutool_command *cmd); 42 int mutool_shell (const char *name, struct mutool_command *cmd);
43 mu_stream_t mutool_open_pager (void); 43 mu_stream_t mutool_open_pager (void);
......
...@@ -454,42 +454,18 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) ...@@ -454,42 +454,18 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
454 return mu_pop3_noop (pop3); 454 return mu_pop3_noop (pop3);
455 } 455 }
456 456
457 static void
458 echo_off (struct termios *stored_settings)
459 {
460 struct termios new_settings;
461 tcgetattr (0, stored_settings);
462 new_settings = *stored_settings;
463 new_settings.c_lflag &= (~ECHO);
464 tcsetattr (0, TCSANOW, &new_settings);
465 }
466
467 static void
468 echo_on (struct termios *stored_settings)
469 {
470 tcsetattr (0, TCSANOW, stored_settings);
471 }
472
473 static int 457 static int
474 com_pass (int argc, char **argv) 458 com_pass (int argc, char **argv)
475 { 459 {
476 int status; 460 int status;
477 char pass[256]; 461 char *pwd, *passbuf = NULL;
478 char *pwd;
479 462
480 if (argc == 1) 463 if (argc == 1)
481 { 464 {
482 struct termios stored_settings; 465 status = mu_getpass (mustrin, mustrout, "Password:", &passbuf);
483 466 if (status)
484 printf ("passwd:"); 467 return status;
485 fflush (stdout); 468 pwd = passbuf;
486 echo_off (&stored_settings);
487 fgets (pass, sizeof pass, stdin);
488 echo_on (&stored_settings);
489 putchar ('\n');
490 fflush (stdout);
491 pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */
492 pwd = pass;
493 } 469 }
494 else 470 else
495 pwd = argv[1]; 471 pwd = argv[1];
...@@ -499,6 +475,7 @@ com_pass (int argc, char **argv) ...@@ -499,6 +475,7 @@ com_pass (int argc, char **argv)
499 pop_session_status = pop_session_logged_in; 475 pop_session_status = pop_session_logged_in;
500 pop_prompt_vartab (); 476 pop_prompt_vartab ();
501 } 477 }
478 free (passbuf);
502 return status; 479 return status;
503 } 480 }
504 481
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
33 char *mutool_shell_prompt; 33 char *mutool_shell_prompt;
34 mu_vartab_t mutool_prompt_vartab; 34 mu_vartab_t mutool_prompt_vartab;
35 int mutool_shell_interactive; 35 int mutool_shell_interactive;
36 mu_stream_t mustrout; 36 mu_stream_t mustrin, mustrout;
37 37
38 static char * 38 static char *
39 expand_prompt () 39 expand_prompt ()
...@@ -370,8 +370,13 @@ readline (char *prompt) ...@@ -370,8 +370,13 @@ readline (char *prompt)
370 mu_stream_printf (mustrout, "%s", prompt); 370 mu_stream_printf (mustrout, "%s", prompt);
371 fflush (stdout); 371 fflush (stdout);
372 } 372 }
373 if (getline (&buf, &size, stdin) <= 0) 373 if (mu_stream_getline (mustrin, &buf, &size, &n) || n == 0)
374 return NULL; 374 {
375 free (buf);
376 buf = NULL;
377 size = 0;
378 return NULL;
379 }
375 return buf; 380 return buf;
376 } 381 }
377 382
...@@ -466,14 +471,24 @@ mutool_shell (const char *name, struct mutool_command *cmd) ...@@ -466,14 +471,24 @@ mutool_shell (const char *name, struct mutool_command *cmd)
466 size_t n; 471 size_t n;
467 char *(*input_line) (); 472 char *(*input_line) ();
468 473
474 rc = mu_stdio_stream_create (&mustrin, MU_STDIN_FD,
475 MU_STREAM_READ);
476 if (rc)
477 {
478 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
479 "MU_STDIN_FD", rc);
480 return 1;
481 }
482
469 rc = mu_stdio_stream_create (&mustrout, MU_STDOUT_FD, 483 rc = mu_stdio_stream_create (&mustrout, MU_STDOUT_FD,
470 MU_STREAM_WRITE); 484 MU_STREAM_WRITE);
471 if (rc) 485 if (rc)
472 { 486 {
473 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", "1", rc); 487 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
488 "MU_STDOUT_FD", rc);
474 return 1; 489 return 1;
475 } 490 }
476 491
477 mutool_shell_interactive = isatty (0); 492 mutool_shell_interactive = isatty (0);
478 input_line = mutool_shell_interactive ? 493 input_line = mutool_shell_interactive ?
479 input_line_interactive : input_line_script; 494 input_line_interactive : input_line_script;
...@@ -521,6 +536,7 @@ mutool_shell (const char *name, struct mutool_command *cmd) ...@@ -521,6 +536,7 @@ mutool_shell (const char *name, struct mutool_command *cmd)
521 } 536 }
522 if (mutool_shell_interactive) 537 if (mutool_shell_interactive)
523 finish_readline (); 538 finish_readline ();
539 mu_stream_destroy (&mustrin);
524 mu_stream_destroy (&mustrout); 540 mu_stream_destroy (&mustrout);
525 return 0; 541 return 0;
526 } 542 }
......
...@@ -74,7 +74,7 @@ static struct argp_option options[] = ...@@ -74,7 +74,7 @@ static struct argp_option options[] =
74 { NULL, 0, NULL, 0, 74 { NULL, 0, NULL, 0,
75 N_("Default action is:\n" 75 N_("Default action is:\n"
76 " For the file owner: --list\n" 76 " For the file owner: --list\n"
77 " For a user: --modify --username <username>\n"), 2 }, 77 " For a user: --modify --user <username>\n"), 2 },
78 78
79 { NULL, 0, NULL, 0, N_("Options are:"), 3 }, 79 { NULL, 0, NULL, 0, N_("Options are:"), 3 },
80 { "file", 'f', N_("FILE"), 0, N_("read input from FILE (default stdin)"), 3 }, 80 { "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) ...@@ -105,7 +105,7 @@ set_db_perms (struct argp_state *astate, char *opt, int *pperm)
105 { 105 {
106 int perm = 0; 106 int perm = 0;
107 107
108 if (mu_isdigit(opt[0])) 108 if (mu_isdigit (opt[0]))
109 { 109 {
110 char *p; 110 char *p;
111 perm = strtoul (opt, &p, 8); 111 perm = strtoul (opt, &p, 8);
...@@ -446,21 +446,57 @@ fill_pass (struct action_data *ap) ...@@ -446,21 +446,57 @@ fill_pass (struct action_data *ap)
446 if (!ap->passwd) 446 if (!ap->passwd)
447 { 447 {
448 char *p; 448 char *p;
449 mu_stream_t in, out;
450 int rc;
451
452 rc = mu_stdio_stream_create (&in, MU_STDIN_FD, MU_STREAM_READ);
453 if (rc)
454 {
455 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
456 "MU_STDIN_FD", rc);
457 return;
458 }
459
460 rc = mu_stdio_stream_create (&out, MU_STDOUT_FD, MU_STREAM_WRITE);
461 if (rc)
462 {
463 mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create",
464 "MU_STDOUT_FD", rc);
465 return;
466 }
449 467
450 while (1) { 468 while (1)
451 if (ap->passwd) 469 {
452 free (ap->passwd); 470 if (ap->passwd)
453 p = getpass (_("Password:")); 471 free (ap->passwd);
454 if (!p) 472 rc = mu_getpass (in, out, _("Password:"), &p);
455 exit (EX_DATAERR); 473 if (rc)
456 ap->passwd = strdup (p); 474 {
457 /* TRANSLATORS: Please try to format this string so that it has 475 mu_diag_funcall (MU_DIAG_ERROR, "mu_getpass", NULL, rc);
458 the same length as the translation of 'Password:' above */ 476 exit (EX_DATAERR);
459 p = getpass (_("Confirm :")); 477 }
460 if (strcmp (ap->passwd, p) == 0) 478
461 break; 479 if (!p)
462 mu_error (_("Passwords differ. Please retry.")); 480 exit (EX_DATAERR);
463 } 481
482 ap->passwd = strdup (p);
483 /* TRANSLATORS: Please try to format this string so that it has
484 the same length as the translation of 'Password:' above */
485 rc = mu_getpass (in, out, _("Confirm :"), &p);
486 if (rc)
487 {
488 mu_diag_funcall (MU_DIAG_ERROR, "mu_getpass", NULL, rc);
489 exit (EX_DATAERR);
490 }
491
492 if (!p)
493 exit (EX_DATAERR);
494 if (strcmp (ap->passwd, p) == 0)
495 break;
496 mu_error (_("Passwords differ. Please retry."));
497 }
498 mu_stream_destroy (&in);
499 mu_stream_destroy (&out);
464 } 500 }
465 } 501 }
466 502
......