1*e4a9863fSDag-Erling Smørgrav /* $OpenBSD: readpass.c,v 1.49 2013/05/17 00:13:14 djm Exp $ */ 2511b41d2SMark Murray /* 3ae1f160dSDag-Erling Smørgrav * Copyright (c) 2001 Markus Friedl. All rights reserved. 4511b41d2SMark Murray * 5511b41d2SMark Murray * Redistribution and use in source and binary forms, with or without 6511b41d2SMark Murray * modification, are permitted provided that the following conditions 7511b41d2SMark Murray * are met: 8511b41d2SMark Murray * 1. Redistributions of source code must retain the above copyright 9511b41d2SMark Murray * notice, this list of conditions and the following disclaimer. 10511b41d2SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 11511b41d2SMark Murray * notice, this list of conditions and the following disclaimer in the 12511b41d2SMark Murray * documentation and/or other materials provided with the distribution. 13511b41d2SMark Murray * 14ae1f160dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15ae1f160dSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16ae1f160dSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17ae1f160dSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18ae1f160dSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19ae1f160dSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20ae1f160dSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21ae1f160dSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22ae1f160dSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23ae1f160dSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24511b41d2SMark Murray */ 25511b41d2SMark Murray 26511b41d2SMark Murray #include "includes.h" 27761efaa7SDag-Erling Smørgrav 28761efaa7SDag-Erling Smørgrav #include <sys/types.h> 29761efaa7SDag-Erling Smørgrav #include <sys/wait.h> 30761efaa7SDag-Erling Smørgrav 31761efaa7SDag-Erling Smørgrav #include <errno.h> 32761efaa7SDag-Erling Smørgrav #include <fcntl.h> 33761efaa7SDag-Erling Smørgrav #ifdef HAVE_PATHS_H 34761efaa7SDag-Erling Smørgrav # include <paths.h> 35761efaa7SDag-Erling Smørgrav #endif 364a421b63SDag-Erling Smørgrav #include <signal.h> 37761efaa7SDag-Erling Smørgrav #include <stdarg.h> 38761efaa7SDag-Erling Smørgrav #include <stdio.h> 39761efaa7SDag-Erling Smørgrav #include <stdlib.h> 40761efaa7SDag-Erling Smørgrav #include <string.h> 41761efaa7SDag-Erling Smørgrav #include <unistd.h> 42ae1f160dSDag-Erling Smørgrav 43511b41d2SMark Murray #include "xmalloc.h" 44d74d50a8SDag-Erling Smørgrav #include "misc.h" 451e8db6e2SBrian Feldman #include "pathnames.h" 461e8db6e2SBrian Feldman #include "log.h" 471e8db6e2SBrian Feldman #include "ssh.h" 48761efaa7SDag-Erling Smørgrav #include "uidswap.h" 491e8db6e2SBrian Feldman 50ae1f160dSDag-Erling Smørgrav static char * 51ae1f160dSDag-Erling Smørgrav ssh_askpass(char *askpass, const char *msg) 521e8db6e2SBrian Feldman { 534a421b63SDag-Erling Smørgrav pid_t pid, ret; 541e8db6e2SBrian Feldman size_t len; 55ae1f160dSDag-Erling Smørgrav char *pass; 564a421b63SDag-Erling Smørgrav int p[2], status; 571e8db6e2SBrian Feldman char buf[1024]; 584a421b63SDag-Erling Smørgrav void (*osigchld)(int); 591e8db6e2SBrian Feldman 601e8db6e2SBrian Feldman if (fflush(stdout) != 0) 611e8db6e2SBrian Feldman error("ssh_askpass: fflush: %s", strerror(errno)); 621e8db6e2SBrian Feldman if (askpass == NULL) 631e8db6e2SBrian Feldman fatal("internal error: askpass undefined"); 64ae1f160dSDag-Erling Smørgrav if (pipe(p) < 0) { 65ae1f160dSDag-Erling Smørgrav error("ssh_askpass: pipe: %s", strerror(errno)); 66d0c8c0bcSDag-Erling Smørgrav return NULL; 67ae1f160dSDag-Erling Smørgrav } 684a421b63SDag-Erling Smørgrav osigchld = signal(SIGCHLD, SIG_DFL); 69ae1f160dSDag-Erling Smørgrav if ((pid = fork()) < 0) { 70ae1f160dSDag-Erling Smørgrav error("ssh_askpass: fork: %s", strerror(errno)); 714a421b63SDag-Erling Smørgrav signal(SIGCHLD, osigchld); 72d0c8c0bcSDag-Erling Smørgrav return NULL; 73ae1f160dSDag-Erling Smørgrav } 741e8db6e2SBrian Feldman if (pid == 0) { 75761efaa7SDag-Erling Smørgrav permanently_drop_suid(getuid()); 761e8db6e2SBrian Feldman close(p[0]); 771e8db6e2SBrian Feldman if (dup2(p[1], STDOUT_FILENO) < 0) 781e8db6e2SBrian Feldman fatal("ssh_askpass: dup2: %s", strerror(errno)); 791e8db6e2SBrian Feldman execlp(askpass, askpass, msg, (char *) 0); 801e8db6e2SBrian Feldman fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 811e8db6e2SBrian Feldman } 821e8db6e2SBrian Feldman close(p[1]); 83ae1f160dSDag-Erling Smørgrav 844a421b63SDag-Erling Smørgrav len = 0; 85ae1f160dSDag-Erling Smørgrav do { 864a421b63SDag-Erling Smørgrav ssize_t r = read(p[0], buf + len, sizeof(buf) - 1 - len); 874a421b63SDag-Erling Smørgrav 884a421b63SDag-Erling Smørgrav if (r == -1 && errno == EINTR) 89ae1f160dSDag-Erling Smørgrav continue; 904a421b63SDag-Erling Smørgrav if (r <= 0) 91ae1f160dSDag-Erling Smørgrav break; 924a421b63SDag-Erling Smørgrav len += r; 93ae1f160dSDag-Erling Smørgrav } while (sizeof(buf) - 1 - len > 0); 94ae1f160dSDag-Erling Smørgrav buf[len] = '\0'; 95ae1f160dSDag-Erling Smørgrav 961e8db6e2SBrian Feldman close(p[0]); 974a421b63SDag-Erling Smørgrav while ((ret = waitpid(pid, &status, 0)) < 0) 981e8db6e2SBrian Feldman if (errno != EINTR) 991e8db6e2SBrian Feldman break; 1004a421b63SDag-Erling Smørgrav signal(SIGCHLD, osigchld); 1014a421b63SDag-Erling Smørgrav if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { 102d0c8c0bcSDag-Erling Smørgrav memset(buf, 0, sizeof(buf)); 103d0c8c0bcSDag-Erling Smørgrav return NULL; 104d0c8c0bcSDag-Erling Smørgrav } 105d0c8c0bcSDag-Erling Smørgrav 106ae1f160dSDag-Erling Smørgrav buf[strcspn(buf, "\r\n")] = '\0'; 1071e8db6e2SBrian Feldman pass = xstrdup(buf); 1081e8db6e2SBrian Feldman memset(buf, 0, sizeof(buf)); 1091e8db6e2SBrian Feldman return pass; 1101e8db6e2SBrian Feldman } 1111e8db6e2SBrian Feldman 112511b41d2SMark Murray /* 113ae1f160dSDag-Erling Smørgrav * Reads a passphrase from /dev/tty with echo turned off/on. Returns the 114ae1f160dSDag-Erling Smørgrav * passphrase (allocated with xmalloc). Exits if EOF is encountered. If 115ae1f160dSDag-Erling Smørgrav * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no 116ae1f160dSDag-Erling Smørgrav * tty is available 1175b9b2fafSBrian Feldman */ 118511b41d2SMark Murray char * 119ae1f160dSDag-Erling Smørgrav read_passphrase(const char *prompt, int flags) 120511b41d2SMark Murray { 121ae1f160dSDag-Erling Smørgrav char *askpass = NULL, *ret, buf[1024]; 122ae1f160dSDag-Erling Smørgrav int rppflags, use_askpass = 0, ttyfd; 1231e8db6e2SBrian Feldman 124ae1f160dSDag-Erling Smørgrav rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; 125d74d50a8SDag-Erling Smørgrav if (flags & RP_USE_ASKPASS) 126d74d50a8SDag-Erling Smørgrav use_askpass = 1; 127d74d50a8SDag-Erling Smørgrav else if (flags & RP_ALLOW_STDIN) { 128043840dfSDag-Erling Smørgrav if (!isatty(STDIN_FILENO)) { 129043840dfSDag-Erling Smørgrav debug("read_passphrase: stdin is not a tty"); 1301e8db6e2SBrian Feldman use_askpass = 1; 131043840dfSDag-Erling Smørgrav } 1321e8db6e2SBrian Feldman } else { 133ae1f160dSDag-Erling Smørgrav rppflags |= RPP_REQUIRE_TTY; 134ae1f160dSDag-Erling Smørgrav ttyfd = open(_PATH_TTY, O_RDWR); 1351e8db6e2SBrian Feldman if (ttyfd >= 0) 1361e8db6e2SBrian Feldman close(ttyfd); 137043840dfSDag-Erling Smørgrav else { 138043840dfSDag-Erling Smørgrav debug("read_passphrase: can't open %s: %s", _PATH_TTY, 139043840dfSDag-Erling Smørgrav strerror(errno)); 1401e8db6e2SBrian Feldman use_askpass = 1; 1411e8db6e2SBrian Feldman } 142043840dfSDag-Erling Smørgrav } 1431e8db6e2SBrian Feldman 144d74d50a8SDag-Erling Smørgrav if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL) 145d74d50a8SDag-Erling Smørgrav return (flags & RP_ALLOW_EOF) ? NULL : xstrdup(""); 146d74d50a8SDag-Erling Smørgrav 1471e8db6e2SBrian Feldman if (use_askpass && getenv("DISPLAY")) { 1481e8db6e2SBrian Feldman if (getenv(SSH_ASKPASS_ENV)) 1491e8db6e2SBrian Feldman askpass = getenv(SSH_ASKPASS_ENV); 1501e8db6e2SBrian Feldman else 1511e8db6e2SBrian Feldman askpass = _PATH_SSH_ASKPASS_DEFAULT; 152d0c8c0bcSDag-Erling Smørgrav if ((ret = ssh_askpass(askpass, prompt)) == NULL) 153d0c8c0bcSDag-Erling Smørgrav if (!(flags & RP_ALLOW_EOF)) 154d0c8c0bcSDag-Erling Smørgrav return xstrdup(""); 155d0c8c0bcSDag-Erling Smørgrav return ret; 1561e8db6e2SBrian Feldman } 1571e8db6e2SBrian Feldman 158545d5ecaSDag-Erling Smørgrav if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { 159545d5ecaSDag-Erling Smørgrav if (flags & RP_ALLOW_EOF) 160545d5ecaSDag-Erling Smørgrav return NULL; 161ae1f160dSDag-Erling Smørgrav return xstrdup(""); 162545d5ecaSDag-Erling Smørgrav } 163ae1f160dSDag-Erling Smørgrav 164ae1f160dSDag-Erling Smørgrav ret = xstrdup(buf); 165ae1f160dSDag-Erling Smørgrav memset(buf, 'x', sizeof buf); 166ae1f160dSDag-Erling Smørgrav return ret; 167511b41d2SMark Murray } 1685e8dbd04SDag-Erling Smørgrav 1695e8dbd04SDag-Erling Smørgrav int 1705e8dbd04SDag-Erling Smørgrav ask_permission(const char *fmt, ...) 1715e8dbd04SDag-Erling Smørgrav { 1725e8dbd04SDag-Erling Smørgrav va_list args; 1735e8dbd04SDag-Erling Smørgrav char *p, prompt[1024]; 1745e8dbd04SDag-Erling Smørgrav int allowed = 0; 1755e8dbd04SDag-Erling Smørgrav 1765e8dbd04SDag-Erling Smørgrav va_start(args, fmt); 1775e8dbd04SDag-Erling Smørgrav vsnprintf(prompt, sizeof(prompt), fmt, args); 1785e8dbd04SDag-Erling Smørgrav va_end(args); 1795e8dbd04SDag-Erling Smørgrav 1805e8dbd04SDag-Erling Smørgrav p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); 1815e8dbd04SDag-Erling Smørgrav if (p != NULL) { 1825e8dbd04SDag-Erling Smørgrav /* 1835e8dbd04SDag-Erling Smørgrav * Accept empty responses and responses consisting 1845e8dbd04SDag-Erling Smørgrav * of the word "yes" as affirmative. 1855e8dbd04SDag-Erling Smørgrav */ 1865e8dbd04SDag-Erling Smørgrav if (*p == '\0' || *p == '\n' || 1875e8dbd04SDag-Erling Smørgrav strcasecmp(p, "yes") == 0) 1885e8dbd04SDag-Erling Smørgrav allowed = 1; 189*e4a9863fSDag-Erling Smørgrav free(p); 1905e8dbd04SDag-Erling Smørgrav } 1915e8dbd04SDag-Erling Smørgrav 1925e8dbd04SDag-Erling Smørgrav return (allowed); 1935e8dbd04SDag-Erling Smørgrav } 194