readpass.c revision 113908
157429Smarkm/* 292555Sdes * Copyright (c) 2001 Markus Friedl. All rights reserved. 357429Smarkm * 457429Smarkm * Redistribution and use in source and binary forms, with or without 557429Smarkm * modification, are permitted provided that the following conditions 657429Smarkm * are met: 757429Smarkm * 1. Redistributions of source code must retain the above copyright 857429Smarkm * notice, this list of conditions and the following disclaimer. 957429Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1057429Smarkm * notice, this list of conditions and the following disclaimer in the 1157429Smarkm * documentation and/or other materials provided with the distribution. 1257429Smarkm * 1392555Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1492555Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1592555Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1692555Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1792555Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1892555Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1992555Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2092555Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2192555Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2292555Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2357429Smarkm */ 2457429Smarkm 2557429Smarkm#include "includes.h" 26113908SdesRCSID("$OpenBSD: readpass.c,v 1.28 2003/01/23 13:50:27 markus Exp $"); 2757429Smarkm 2857429Smarkm#include "xmalloc.h" 2976259Sgreen#include "readpass.h" 3076259Sgreen#include "pathnames.h" 3176259Sgreen#include "log.h" 3257429Smarkm#include "ssh.h" 3357429Smarkm 3492555Sdesstatic char * 3592555Sdesssh_askpass(char *askpass, const char *msg) 3676259Sgreen{ 3776259Sgreen pid_t pid; 3876259Sgreen size_t len; 3992555Sdes char *pass; 4092555Sdes int p[2], status, ret; 4176259Sgreen char buf[1024]; 4276259Sgreen 4376259Sgreen if (fflush(stdout) != 0) 4476259Sgreen error("ssh_askpass: fflush: %s", strerror(errno)); 4576259Sgreen if (askpass == NULL) 4676259Sgreen fatal("internal error: askpass undefined"); 4792555Sdes if (pipe(p) < 0) { 4892555Sdes error("ssh_askpass: pipe: %s", strerror(errno)); 49113908Sdes return NULL; 5092555Sdes } 5192555Sdes if ((pid = fork()) < 0) { 5292555Sdes error("ssh_askpass: fork: %s", strerror(errno)); 53113908Sdes return NULL; 5492555Sdes } 5576259Sgreen if (pid == 0) { 5676259Sgreen seteuid(getuid()); 5776259Sgreen setuid(getuid()); 5876259Sgreen close(p[0]); 5976259Sgreen if (dup2(p[1], STDOUT_FILENO) < 0) 6076259Sgreen fatal("ssh_askpass: dup2: %s", strerror(errno)); 6176259Sgreen execlp(askpass, askpass, msg, (char *) 0); 6276259Sgreen fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 6376259Sgreen } 6476259Sgreen close(p[1]); 6592555Sdes 6692555Sdes len = ret = 0; 6792555Sdes do { 6892555Sdes ret = read(p[0], buf + len, sizeof(buf) - 1 - len); 6992555Sdes if (ret == -1 && errno == EINTR) 7092555Sdes continue; 7192555Sdes if (ret <= 0) 7292555Sdes break; 7392555Sdes len += ret; 7492555Sdes } while (sizeof(buf) - 1 - len > 0); 7592555Sdes buf[len] = '\0'; 7692555Sdes 7776259Sgreen close(p[0]); 7876259Sgreen while (waitpid(pid, &status, 0) < 0) 7976259Sgreen if (errno != EINTR) 8076259Sgreen break; 8192555Sdes 82113908Sdes if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 83113908Sdes memset(buf, 0, sizeof(buf)); 84113908Sdes return NULL; 85113908Sdes } 86113908Sdes 8792555Sdes buf[strcspn(buf, "\r\n")] = '\0'; 8876259Sgreen pass = xstrdup(buf); 8976259Sgreen memset(buf, 0, sizeof(buf)); 9076259Sgreen return pass; 9176259Sgreen} 9276259Sgreen 9357429Smarkm/* 9492555Sdes * Reads a passphrase from /dev/tty with echo turned off/on. Returns the 9592555Sdes * passphrase (allocated with xmalloc). Exits if EOF is encountered. If 9692555Sdes * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no 9792555Sdes * tty is available 9857429Smarkm */ 9957429Smarkmchar * 10092555Sdesread_passphrase(const char *prompt, int flags) 10157429Smarkm{ 10292555Sdes char *askpass = NULL, *ret, buf[1024]; 10392555Sdes int rppflags, use_askpass = 0, ttyfd; 10476259Sgreen 10592555Sdes rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; 10692555Sdes if (flags & RP_ALLOW_STDIN) { 10776259Sgreen if (!isatty(STDIN_FILENO)) 10876259Sgreen use_askpass = 1; 10976259Sgreen } else { 11092555Sdes rppflags |= RPP_REQUIRE_TTY; 11192555Sdes ttyfd = open(_PATH_TTY, O_RDWR); 11276259Sgreen if (ttyfd >= 0) 11376259Sgreen close(ttyfd); 11476259Sgreen else 11576259Sgreen use_askpass = 1; 11676259Sgreen } 11776259Sgreen 11876259Sgreen if (use_askpass && getenv("DISPLAY")) { 11976259Sgreen if (getenv(SSH_ASKPASS_ENV)) 12076259Sgreen askpass = getenv(SSH_ASKPASS_ENV); 12176259Sgreen else 12276259Sgreen askpass = _PATH_SSH_ASKPASS_DEFAULT; 123113908Sdes if ((ret = ssh_askpass(askpass, prompt)) == NULL) 124113908Sdes if (!(flags & RP_ALLOW_EOF)) 125113908Sdes return xstrdup(""); 126113908Sdes return ret; 12776259Sgreen } 12876259Sgreen 12998675Sdes if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { 13098675Sdes if (flags & RP_ALLOW_EOF) 13198675Sdes return NULL; 13292555Sdes return xstrdup(""); 13398675Sdes } 13492555Sdes 13592555Sdes ret = xstrdup(buf); 13692555Sdes memset(buf, 'x', sizeof buf); 13792555Sdes return ret; 13857429Smarkm} 139