readpass.c revision 162852
1162852Sdes/* $OpenBSD: readpass.c,v 1.47 2006/08/03 03:34:42 deraadt Exp $ */ 257429Smarkm/* 392555Sdes * Copyright (c) 2001 Markus Friedl. All rights reserved. 457429Smarkm * 557429Smarkm * Redistribution and use in source and binary forms, with or without 657429Smarkm * modification, are permitted provided that the following conditions 757429Smarkm * are met: 857429Smarkm * 1. Redistributions of source code must retain the above copyright 957429Smarkm * notice, this list of conditions and the following disclaimer. 1057429Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157429Smarkm * notice, this list of conditions and the following disclaimer in the 1257429Smarkm * documentation and/or other materials provided with the distribution. 1357429Smarkm * 1492555Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1592555Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1692555Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1792555Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1892555Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1992555Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2092555Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2192555Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2292555Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2392555Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2457429Smarkm */ 2557429Smarkm 2657429Smarkm#include "includes.h" 2757429Smarkm 28162852Sdes#include <sys/types.h> 29162852Sdes#include <sys/wait.h> 30162852Sdes 31162852Sdes#include <errno.h> 32162852Sdes#include <fcntl.h> 33162852Sdes#ifdef HAVE_PATHS_H 34162852Sdes# include <paths.h> 35162852Sdes#endif 36162852Sdes#include <stdarg.h> 37162852Sdes#include <stdio.h> 38162852Sdes#include <stdlib.h> 39162852Sdes#include <string.h> 40162852Sdes#include <unistd.h> 41162852Sdes 4257429Smarkm#include "xmalloc.h" 43137015Sdes#include "misc.h" 4476259Sgreen#include "pathnames.h" 4576259Sgreen#include "log.h" 4657429Smarkm#include "ssh.h" 47162852Sdes#include "uidswap.h" 4857429Smarkm 4992555Sdesstatic char * 5092555Sdesssh_askpass(char *askpass, const char *msg) 5176259Sgreen{ 5276259Sgreen pid_t pid; 5376259Sgreen size_t len; 5492555Sdes char *pass; 5592555Sdes int p[2], status, ret; 5676259Sgreen char buf[1024]; 5776259Sgreen 5876259Sgreen if (fflush(stdout) != 0) 5976259Sgreen error("ssh_askpass: fflush: %s", strerror(errno)); 6076259Sgreen if (askpass == NULL) 6176259Sgreen fatal("internal error: askpass undefined"); 6292555Sdes if (pipe(p) < 0) { 6392555Sdes error("ssh_askpass: pipe: %s", strerror(errno)); 64113908Sdes return NULL; 6592555Sdes } 6692555Sdes if ((pid = fork()) < 0) { 6792555Sdes error("ssh_askpass: fork: %s", strerror(errno)); 68113908Sdes return NULL; 6992555Sdes } 7076259Sgreen if (pid == 0) { 71162852Sdes permanently_drop_suid(getuid()); 7276259Sgreen close(p[0]); 7376259Sgreen if (dup2(p[1], STDOUT_FILENO) < 0) 7476259Sgreen fatal("ssh_askpass: dup2: %s", strerror(errno)); 7576259Sgreen execlp(askpass, askpass, msg, (char *) 0); 7676259Sgreen fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 7776259Sgreen } 7876259Sgreen close(p[1]); 7992555Sdes 8092555Sdes len = ret = 0; 8192555Sdes do { 8292555Sdes ret = read(p[0], buf + len, sizeof(buf) - 1 - len); 8392555Sdes if (ret == -1 && errno == EINTR) 8492555Sdes continue; 8592555Sdes if (ret <= 0) 8692555Sdes break; 8792555Sdes len += ret; 8892555Sdes } while (sizeof(buf) - 1 - len > 0); 8992555Sdes buf[len] = '\0'; 9092555Sdes 9176259Sgreen close(p[0]); 9276259Sgreen while (waitpid(pid, &status, 0) < 0) 9376259Sgreen if (errno != EINTR) 9476259Sgreen break; 9592555Sdes 96113908Sdes if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 97113908Sdes memset(buf, 0, sizeof(buf)); 98113908Sdes return NULL; 99113908Sdes } 100113908Sdes 10192555Sdes buf[strcspn(buf, "\r\n")] = '\0'; 10276259Sgreen pass = xstrdup(buf); 10376259Sgreen memset(buf, 0, sizeof(buf)); 10476259Sgreen return pass; 10576259Sgreen} 10676259Sgreen 10757429Smarkm/* 10892555Sdes * Reads a passphrase from /dev/tty with echo turned off/on. Returns the 10992555Sdes * passphrase (allocated with xmalloc). Exits if EOF is encountered. If 11092555Sdes * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no 11192555Sdes * tty is available 11257429Smarkm */ 11357429Smarkmchar * 11492555Sdesread_passphrase(const char *prompt, int flags) 11557429Smarkm{ 11692555Sdes char *askpass = NULL, *ret, buf[1024]; 11792555Sdes int rppflags, use_askpass = 0, ttyfd; 11876259Sgreen 11992555Sdes rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; 120137015Sdes if (flags & RP_USE_ASKPASS) 121137015Sdes use_askpass = 1; 122137015Sdes else if (flags & RP_ALLOW_STDIN) { 123149749Sdes if (!isatty(STDIN_FILENO)) { 124149749Sdes debug("read_passphrase: stdin is not a tty"); 12576259Sgreen use_askpass = 1; 126149749Sdes } 12776259Sgreen } else { 12892555Sdes rppflags |= RPP_REQUIRE_TTY; 12992555Sdes ttyfd = open(_PATH_TTY, O_RDWR); 13076259Sgreen if (ttyfd >= 0) 13176259Sgreen close(ttyfd); 132149749Sdes else { 133149749Sdes debug("read_passphrase: can't open %s: %s", _PATH_TTY, 134149749Sdes strerror(errno)); 13576259Sgreen use_askpass = 1; 136149749Sdes } 13776259Sgreen } 13876259Sgreen 139137015Sdes if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL) 140137015Sdes return (flags & RP_ALLOW_EOF) ? NULL : xstrdup(""); 141137015Sdes 14276259Sgreen if (use_askpass && getenv("DISPLAY")) { 14376259Sgreen if (getenv(SSH_ASKPASS_ENV)) 14476259Sgreen askpass = getenv(SSH_ASKPASS_ENV); 14576259Sgreen else 14676259Sgreen askpass = _PATH_SSH_ASKPASS_DEFAULT; 147113908Sdes if ((ret = ssh_askpass(askpass, prompt)) == NULL) 148113908Sdes if (!(flags & RP_ALLOW_EOF)) 149113908Sdes return xstrdup(""); 150113908Sdes return ret; 15176259Sgreen } 15276259Sgreen 15398675Sdes if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { 15498675Sdes if (flags & RP_ALLOW_EOF) 15598675Sdes return NULL; 15692555Sdes return xstrdup(""); 15798675Sdes } 15892555Sdes 15992555Sdes ret = xstrdup(buf); 16092555Sdes memset(buf, 'x', sizeof buf); 16192555Sdes return ret; 16257429Smarkm} 163146998Sdes 164146998Sdesint 165146998Sdesask_permission(const char *fmt, ...) 166146998Sdes{ 167146998Sdes va_list args; 168146998Sdes char *p, prompt[1024]; 169146998Sdes int allowed = 0; 170146998Sdes 171146998Sdes va_start(args, fmt); 172146998Sdes vsnprintf(prompt, sizeof(prompt), fmt, args); 173146998Sdes va_end(args); 174146998Sdes 175146998Sdes p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); 176146998Sdes if (p != NULL) { 177146998Sdes /* 178146998Sdes * Accept empty responses and responses consisting 179146998Sdes * of the word "yes" as affirmative. 180146998Sdes */ 181146998Sdes if (*p == '\0' || *p == '\n' || 182146998Sdes strcasecmp(p, "yes") == 0) 183146998Sdes allowed = 1; 184146998Sdes xfree(p); 185146998Sdes } 186146998Sdes 187146998Sdes return (allowed); 188146998Sdes} 189