X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/5260325f3150ad441f310d31239beeb765f716ed..25616c132251df1782c4edcb873f8acba345fc97:/readpass.c diff --git a/readpass.c b/readpass.c index f5b4802e..fc7629c3 100644 --- a/readpass.c +++ b/readpass.c @@ -1,113 +1,138 @@ /* - * - * readpass.c - * - * Author: Tatu Ylonen - * - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - * All rights reserved - * - * Created: Mon Jul 10 22:08:59 1995 ylo - * - * Functions for reading passphrases and passwords. - * + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$Id$"); +RCSID("$OpenBSD: readpass.c,v 1.29 2004/05/08 00:21:31 djm Exp $"); #include "xmalloc.h" +#include "misc.h" +#include "pathnames.h" +#include "log.h" #include "ssh.h" -/* Saved old terminal mode for read_passphrase. */ -static struct termios saved_tio; +static char * +ssh_askpass(char *askpass, const char *msg) +{ + pid_t pid; + size_t len; + char *pass; + int p[2], status, ret; + char buf[1024]; -/* Old interrupt signal handler for read_passphrase. */ -static void (*old_handler) (int sig) = NULL; + if (fflush(stdout) != 0) + error("ssh_askpass: fflush: %s", strerror(errno)); + if (askpass == NULL) + fatal("internal error: askpass undefined"); + if (pipe(p) < 0) { + error("ssh_askpass: pipe: %s", strerror(errno)); + return NULL; + } + if ((pid = fork()) < 0) { + error("ssh_askpass: fork: %s", strerror(errno)); + return NULL; + } + if (pid == 0) { + seteuid(getuid()); + setuid(getuid()); + close(p[0]); + if (dup2(p[1], STDOUT_FILENO) < 0) + fatal("ssh_askpass: dup2: %s", strerror(errno)); + execlp(askpass, askpass, msg, (char *) 0); + fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); + } + close(p[1]); -/* Interrupt signal handler for read_passphrase. */ + len = ret = 0; + do { + ret = read(p[0], buf + len, sizeof(buf) - 1 - len); + if (ret == -1 && errno == EINTR) + continue; + if (ret <= 0) + break; + len += ret; + } while (sizeof(buf) - 1 - len > 0); + buf[len] = '\0'; -void -intr_handler(int sig) -{ - /* Restore terminal modes. */ - tcsetattr(fileno(stdin), TCSANOW, &saved_tio); - /* Restore the old signal handler. */ - signal(sig, old_handler); - /* Resend the signal, with the old handler. */ - kill(getpid(), sig); -} + close(p[0]); + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; -/* Reads a passphrase from /dev/tty with echo turned off. Returns the - passphrase (allocated with xmalloc). Exits if EOF is encountered. - The passphrase if read from stdin if from_stdin is true (as is the - case with ssh-keygen). */ + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + memset(buf, 0, sizeof(buf)); + return NULL; + } + buf[strcspn(buf, "\r\n")] = '\0'; + pass = xstrdup(buf); + memset(buf, 0, sizeof(buf)); + return pass; +} + +/* + * Reads a passphrase from /dev/tty with echo turned off/on. Returns the + * passphrase (allocated with xmalloc). Exits if EOF is encountered. If + * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no + * tty is available + */ char * -read_passphrase(const char *prompt, int from_stdin) +read_passphrase(const char *prompt, int flags) { - char buf[1024], *cp; - struct termios tio; - FILE *f; + char *askpass = NULL, *ret, buf[1024]; + int rppflags, use_askpass = 0, ttyfd; - if (from_stdin) - f = stdin; - else { - /* Read the passphrase from /dev/tty to make it possible - to ask it even when stdin has been redirected. */ - f = fopen("/dev/tty", "r"); - if (!f) { - /* No controlling terminal and no DISPLAY. Nowhere to read. */ - fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n"); - exit(1); - } + rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; + if (flags & RP_ALLOW_STDIN) { + if (!isatty(STDIN_FILENO)) + use_askpass = 1; + } else { + rppflags |= RPP_REQUIRE_TTY; + ttyfd = open(_PATH_TTY, O_RDWR); + if (ttyfd >= 0) + close(ttyfd); + else + use_askpass = 1; } - /* Display the prompt (on stderr because stdout might be redirected). */ - fflush(stdout); - fprintf(stderr, "%s", prompt); - fflush(stderr); - - /* Get terminal modes. */ - tcgetattr(fileno(f), &tio); - saved_tio = tio; - /* Save signal handler and set the new handler. */ - old_handler = signal(SIGINT, intr_handler); - - /* Set new terminal modes disabling all echo. */ - tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - tcsetattr(fileno(f), TCSANOW, &tio); + if (use_askpass && getenv("DISPLAY")) { + if (getenv(SSH_ASKPASS_ENV)) + askpass = getenv(SSH_ASKPASS_ENV); + else + askpass = _PATH_SSH_ASKPASS_DEFAULT; + if ((ret = ssh_askpass(askpass, prompt)) == NULL) + if (!(flags & RP_ALLOW_EOF)) + return xstrdup(""); + return ret; + } - /* Read the passphrase from the terminal. */ - if (fgets(buf, sizeof(buf), f) == NULL) { - /* Got EOF. Just exit. */ - /* Restore terminal modes. */ - tcsetattr(fileno(f), TCSANOW, &saved_tio); - /* Restore the signal handler. */ - signal(SIGINT, old_handler); - /* Print a newline (the prompt probably didn\'t have one). */ - fprintf(stderr, "\n"); - /* Close the file. */ - if (f != stdin) - fclose(f); - exit(1); + if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { + if (flags & RP_ALLOW_EOF) + return NULL; + return xstrdup(""); } - /* Restore terminal modes. */ - tcsetattr(fileno(f), TCSANOW, &saved_tio); - /* Restore the signal handler. */ - (void) signal(SIGINT, old_handler); - /* Remove newline from the passphrase. */ - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - /* Allocate a copy of the passphrase. */ - cp = xstrdup(buf); - /* Clear the buffer so we don\'t leave copies of the passphrase - laying around. */ - memset(buf, 0, sizeof(buf)); - /* Print a newline since the prompt probably didn\'t have one. */ - fprintf(stderr, "\n"); - /* Close the file. */ - if (f != stdin) - fclose(f); - return cp; + + ret = xstrdup(buf); + memset(buf, 'x', sizeof buf); + return ret; }