readpass.c revision 137015
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" 26137015SdesRCSID("$OpenBSD: readpass.c,v 1.30 2004/06/17 15:10:14 djm Exp $"); 2757429Smarkm 2857429Smarkm#include "xmalloc.h" 29137015Sdes#include "misc.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; 106137015Sdes if (flags & RP_USE_ASKPASS) 107137015Sdes use_askpass = 1; 108137015Sdes else if (flags & RP_ALLOW_STDIN) { 10976259Sgreen if (!isatty(STDIN_FILENO)) 11076259Sgreen use_askpass = 1; 11176259Sgreen } else { 11292555Sdes rppflags |= RPP_REQUIRE_TTY; 11392555Sdes ttyfd = open(_PATH_TTY, O_RDWR); 11476259Sgreen if (ttyfd >= 0) 11576259Sgreen close(ttyfd); 11676259Sgreen else 11776259Sgreen use_askpass = 1; 11876259Sgreen } 11976259Sgreen 120137015Sdes if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL) 121137015Sdes return (flags & RP_ALLOW_EOF) ? NULL : xstrdup(""); 122137015Sdes 12376259Sgreen if (use_askpass && getenv("DISPLAY")) { 12476259Sgreen if (getenv(SSH_ASKPASS_ENV)) 12576259Sgreen askpass = getenv(SSH_ASKPASS_ENV); 12676259Sgreen else 12776259Sgreen askpass = _PATH_SSH_ASKPASS_DEFAULT; 128113908Sdes if ((ret = ssh_askpass(askpass, prompt)) == NULL) 129113908Sdes if (!(flags & RP_ALLOW_EOF)) 130113908Sdes return xstrdup(""); 131113908Sdes return ret; 13276259Sgreen } 13376259Sgreen 13498675Sdes if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { 13598675Sdes if (flags & RP_ALLOW_EOF) 13698675Sdes return NULL; 13792555Sdes return xstrdup(""); 13898675Sdes } 13992555Sdes 14092555Sdes ret = xstrdup(buf); 14192555Sdes memset(buf, 'x', sizeof buf); 14292555Sdes return ret; 14357429Smarkm} 144