* prompter.c (krb5_prompter_posix): Rewrite to no longer use
authorTom Yu <tlyu@mit.edu>
Wed, 5 Feb 2003 03:57:22 +0000 (03:57 +0000)
committerTom Yu <tlyu@mit.edu>
Wed, 5 Feb 2003 03:57:22 +0000 (03:57 +0000)
longjmp(), as well as to get a non-buffered stdio stream on stdin
to avoid passwords staying around in stdio buffers.  This does
have the side effect of possibly losing pre-buffered input from an
application that reads from stdin using stdio functions prior to
calling the prompter, but hopefully those are rare.

ticket: 673
ticket: 680

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15151 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/ChangeLog
src/lib/krb5/configure.in
src/lib/krb5/os/ChangeLog
src/lib/krb5/os/prompter.c

index f1d3ddea3ffece72c402b7008731ea0288c2f373..4d7faca6d434ea53b362ed9a58014cb42c1e3658 100644 (file)
@@ -1,3 +1,8 @@
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+       * configure.in: Add KRB5_SIGTYPE and CHECK_SIGNALS for
+       os/prompter.c.
+
 2003-01-10  Ken Raeburn  <raeburn@mit.edu>
 
        * configure.in: Don't explicitly invoke AC_PROG_INSTALL.
index 53f626124389fae4cc11b35eb586daa1b0ee161c..3d83a182337223702594c1550afe7274ff52bbb2 100644 (file)
@@ -14,6 +14,8 @@ AC_REPLACE_FUNCS(vfprintf vsprintf strdup strcasecmp strerror memmove daemon get
 KRB5_AC_REGEX_FUNCS
 KRB5_NEED_PROTO([#include <time.h>],strptime)
 dnl
+KRB5_SIGTYPE
+CHECK_SIGNALS
 KRB5_SOCKADDR_SA_LEN
 KRB5_GETPEERNAME_ARGS
 KRB5_GETSOCKNAME_ARGS
index c58460300354f532aa6c342ef9c03980fc429bb7..0eb356f00ba0df8197e7235a0950db7114ffc02d 100644 (file)
@@ -1,3 +1,12 @@
+2003-02-04  Tom Yu  <tlyu@mit.edu>
+
+       * prompter.c (krb5_prompter_posix): Rewrite to no longer use
+       longjmp(), as well as to get a non-buffered stdio stream on stdin
+       to avoid passwords staying around in stdio buffers.  This does
+       have the side effect of possibly losing pre-buffered input from an
+       application that reads from stdin using stdio functions prior to
+       calling the prompter, but hopefully those are rare.
+
 2003-01-10  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in: Add AC_SUBST_FILE marker for libobj_frag.
index 21292944e4ce201bacced139959efca465ea4194..3e4503216d055ae8ce571fb8a5fb3007991346c6 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #include <signal.h>
-#include <setjmp.h>
+#include <limits.h>
+/* Is vxworks broken w.r.t. termios? --tlyu */
 #ifdef __vxworks
 #define ECHO_PASSWORD
 #endif
 
-#ifndef ECHO_PASSWORD
 #include <termios.h>
-#endif /* ECHO_PASSWORD */
 
-static jmp_buf pwd_jump;
+static void    catch_signals(void);
+static void    restore_signals(void);
+static krb5_sigtype    intrfunc(int sig);
 
-static krb5_sigtype
-intr_routine(int signo)
-{
-    longjmp(pwd_jump, 1);
-    /*NOTREACHED*/
-}
+static krb5_error_code setup_tty(int);
+static krb5_error_code restore_tty(void);
+
+#ifdef POSIX_SIGNALS
+static struct sigaction osigint;
+#else
+static krb5_sigtype (*osigint)();
+#endif
+
+static volatile int got_int;
 
 krb5_error_code KRB5_CALLCONV
-krb5_prompter_posix(krb5_context context,
-                   void *data,
-                   const char *name,
-                   const char *banner,
-                   int num_prompts,
-                   krb5_prompt prompts[])
+krb5_prompter_posix(
+    krb5_context       context,
+    void               *data,
+    const char         *name,
+    const char         *banner,
+    int                        num_prompts,
+    krb5_prompt                prompts[])
 {
-    /* adapted from Kerberos v5 krb5_read_password() */
+    int                fd, i, scratchchar;
+    FILE       *fp;
+    char       *retp;
+    krb5_error_code    errcode;
 
-    register char *ptr;
-    int scratchchar;
-    krb5_sigtype (*volatile ointrfunc)();
-    volatile krb5_error_code errcode;
-    volatile int i = 0;
-#ifndef ECHO_PASSWORD
-    struct termios echo_control, save_control;
-    volatile int fd;
-#endif
+    errcode = KRB5_LIBOS_CANTREADPWD;
 
     if (name) {
        fputs(name, stdout);
        fputs("\n", stdout);
     }
-
     if (banner) {
        fputs(banner, stdout);
        fputs("\n", stdout);
     }
 
-    if (setjmp(pwd_jump)) {
-       errcode = KRB5_LIBOS_PWDINTR;   /* we were interrupted... */
+    /*
+     * Get a non-buffered stream on stdin.
+     */
+    fp = NULL;
+    fd = dup(STDIN_FILENO);
+    if (fd < 0)
+       return KRB5_LIBOS_CANTREADPWD;
+    fp = fdopen(fd, "r");
+    if (fp == NULL)
+       goto cleanup;
+    if (setvbuf(fp, NULL, _IONBF, 0))
        goto cleanup;
-    }
-    /* save intrfunc */
-    ointrfunc = signal(SIGINT, intr_routine);
-
-    for (i=0; i<num_prompts; i++) {
-#ifndef ECHO_PASSWORD
-       if (prompts[i].hidden) {
-           /* get the file descriptor associated with stdin */
-           fd = fileno(stdin);
-
-           if (isatty(fd) == 1) {
-               if (tcgetattr(fd, &echo_control) == -1)
-                   return errno;
-
-               save_control = echo_control;
-               echo_control.c_lflag &= ~(ECHO|ECHONL);
-
-               if (tcsetattr(fd, TCSANOW, &echo_control) == -1)
-                   return errno;
-           }
-       }
-#endif /* ECHO_PASSWORD */
 
+    for (i = 0; i < num_prompts; i++) {
+       errcode = KRB5_LIBOS_CANTREADPWD;
+       /* fgets() takes int, but krb5_data.length is unsigned. */
+       if (prompts[i].reply->length > INT_MAX)
+           goto cleanup;
        /* put out the prompt */
-       (void) fputs(prompts[i].prompt,stdout);
-       (void) fputs(": ",stdout);
-       (void) fflush(stdout);
-       (void) memset(prompts[i].reply->data, 0, prompts[i].reply->length);
+       (void)fputs(prompts[i].prompt, stdout);
+       (void)fputs(": ", stdout);
+       (void)fflush(stdout);
+       (void)memset(prompts[i].reply->data, 0, prompts[i].reply->length);
 
-       if (fgets(prompts[i].reply->data, (int) prompts[i].reply->length, stdin)
-           == NULL) {
+       errcode = setup_tty(prompts[i].hidden);
+       if (errcode) {
            if (prompts[i].hidden)
-               (void) putchar('\n');
-           errcode = KRB5_LIBOS_CANTREADPWD;
-           goto cleanup;
+               putchar('\n');
+           break;
        }
+       got_int = 0;
+       retp = fgets(prompts[i].reply->data, (int)prompts[i].reply->length,
+                    fp);
        if (prompts[i].hidden)
-           (void) putchar('\n');
-       /* fgets always null-terminates the returned string */
+           putchar('\n');
+       if (retp == NULL) {
+           if (got_int)
+               errcode = KRB5_LIBOS_PWDINTR;
+           else
+               errcode = KRB5_LIBOS_CANTREADPWD;
+           restore_tty();
+           break;
+       }
 
        /* replace newline with null */
-       if ((ptr = strchr(prompts[i].reply->data, '\n')))
-           *ptr = '\0';
-       else /* flush rest of input line */
+       retp = strchr(prompts[i].reply->data, '\n');
+       if (retp != NULL)
+           *retp = '\0';
+       else {
+           /* flush rest of input line */
            do {
-               scratchchar = getchar();
+               scratchchar = getc(fp);
            } while (scratchchar != EOF && scratchchar != '\n');
-    
+       }
+
+       errcode = restore_tty();
+       if (errcode)
+           break;
        prompts[i].reply->length = strlen(prompts[i].reply->data);
+    }
+cleanup:
+    if (fp != NULL)
+       fclose(fp);
+    else if (fd >= 0)
+       close(fd);
 
-#ifndef ECHO_PASSWORD
-       if (prompts[i].hidden && (isatty(fd) == 1))
-           if ((tcsetattr(fd, TCSANOW, &save_control) == -1) &&
-               (errcode == 0))
-               return errno;
+    return errcode;
+}
+
+static krb5_sigtype intrfunc(int sig)
+{
+    got_int = 1;
+}
+
+static void
+catch_signals(void)
+{
+#ifdef POSIX_SIGNALS
+    struct sigaction sa;
+
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = intrfunc;
+    sigaction(SIGINT, &sa, &osigint);
+#else
+    osigint = signal(SIGINT, intrfunc);
 #endif
-    }
+}
 
-    errcode = 0;
+static void
+restore_signals(void)
+{
+#ifdef POSIX_SIGNALS
+    sigaction(SIGINT, &osigint, NULL);
+#else
+    signal(SIGINT, osigint);
+#endif
+}
 
-cleanup:
-    (void) signal(SIGINT, ointrfunc);
-#ifndef ECHO_PASSWORD
-    if (i < num_prompts) {
-       if (prompts[i].hidden) {
-           (void)putchar('\n');
-           if (isatty(fd) == 1) {
-               if ((tcsetattr(fd, TCSANOW, &save_control) == -1
-                    && errcode == 0))
-                   return errno;
-           }
+static struct termios saveparm;
+
+static krb5_error_code
+setup_tty(int hidden)
+{
+    krb5_error_code    ret;
+    struct termios     tparm;
+
+    ret = KRB5_LIBOS_CANTREADPWD;
+    catch_signals();
+    do {
+       if (!isatty(STDIN_FILENO)) {
+           ret = 0;
+           break;
        }
-    }
+       if (tcgetattr(STDIN_FILENO, &tparm) < 0)
+           break;
+       saveparm = tparm;
+#ifndef ECHO_PASSWORD
+       if (hidden)
+           tparm.c_lflag &= ~(ECHO|ECHONL);
 #endif
-    return(errcode);
+       tparm.c_lflag |= ISIG|ICANON;
+       if (tcsetattr(STDIN_FILENO, TCSANOW, &tparm) < 0)
+           break;
+       ret = 0;
+    } while (0);
+    /* If we're losing, restore signal handlers. */
+    if (ret)
+       restore_signals();
+    return ret;
+}
+
+static krb5_error_code
+restore_tty(void)
+{
+    int ret;
+
+    ret = 0;
+    if (isatty(STDIN_FILENO)) {
+       ret = tcsetattr(STDIN_FILENO, TCSANOW, &saveparm);
+       if (ret < 0)
+           ret = KRB5_LIBOS_CANTREADPWD;
+       else
+           ret = 0;
+    }
+    restore_signals();
+    return ret;
 }
+
 #else /* non-Cygwin Windows, or Mac */
 
 #if defined(_WIN32)