Subject: [PATCH] Don't use getpass (), it is difficult to interrupt 2010-10-08 Miloslav Trmač * src/volume_key.c (get_password): New function. (nss_password_fn, generic_ui_cb, passphrase_ui_cb): Use get_password () instead of getpass (). diff --git a/src/volume_key.c b/src/volume_key.c index abdd838..7f9f391 100644 --- a/src/volume_key.c +++ b/src/volume_key.c @@ -24,6 +24,7 @@ Author: Miloslav Trmač */ #include #include #include +#include #include #include @@ -391,36 +392,93 @@ read_batch_string (void) return res; } +/* Read a password (from /dev/tty if possible). + Return a password for g_free (), or NULL on error. + Unlike getpass(), does not block SIGINT and other signals. (We rely on the + shell to re-enable ECHO on SIGINT.) */ +static char * +get_password (const char *prompt) +{ + FILE *tty, *in_file, *out_file; + char buf[LINE_MAX], *p; + struct termios otermios; + gboolean echo_disabled; + + tty = fopen ("/dev/tty", "r+"); + if (tty != NULL) + { + in_file = tty; + out_file = tty; + } + else + { + in_file = stdin; + out_file = stderr; + } + + fputs (prompt, out_file); + fflush (out_file); + + if (tcgetattr (fileno (in_file), &otermios) != 0) + echo_disabled = FALSE; + else + { + struct termios ntermios; + + ntermios = otermios; + ntermios.c_lflag &= ~ECHO; + echo_disabled = tcsetattr (fileno (in_file), TCSAFLUSH, &ntermios) == 0; + } + + p = fgets(buf, sizeof(buf), in_file); + + if (echo_disabled) + { + (void)tcsetattr (fileno (in_file), TCSAFLUSH, &otermios); + putc ('\n', out_file); + } + + if (tty != NULL) + fclose (tty); + + if (p == NULL) + return NULL; + + p = strchr(buf, '\r'); + if (p != NULL) + *p = '\0'; + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; + + return g_strdup (buf); +} + /* A PK11_SetPaswordFunc handler */ static char * nss_password_fn (PK11SlotInfo *slot, PRBool retry, void *arg) { + char *s, *res; + + (void)arg; if (batch_mode == 0) { - char *prompt, *s; + char *prompt; - (void)arg; if (retry) fprintf (stderr, _("Error, try again.\n")); prompt = g_strdup_printf (_("Enter password for `%s': "), PK11_GetTokenName (slot)); - s = getpass (prompt); + s = get_password (prompt); g_free (prompt); - if (s == NULL) - return NULL; - return PL_strdup (s); } else - { - char *s, *res; - - s = read_batch_string (); - if (s == NULL) - return NULL; - res = PL_strdup (s); - g_free (s); - return res; - } + s = read_batch_string (); + if (s == NULL) + return NULL; + res = PL_strdup (s); + g_free (s); + return res; } /* A "generic" struct libvk_ui callback. */ @@ -435,10 +493,11 @@ generic_ui_cb (void *id, const char *prompt, int echo) char *s, *res; s = g_strdup_printf (_("%s: "), prompt); - res = getpass (s); + res = get_password (s); g_free (s); if (res != NULL && res[0] != '\0') - return g_strdup (res); + return res; + g_free (res); return NULL; } else @@ -487,10 +546,11 @@ passphrase_ui_cb (void *data, const char *prompt, unsigned failed_attempts) return read_batch_string (); } s = g_strdup_printf (_("%s: "), prompt); - res = getpass (s); + res = get_password (s); g_free (s); if (res != NULL && res[0] != '\0') - return g_strdup (res); + return res; + g_free (res); return NULL; } -- 1.7.2.3