1264377Sdes/* $OpenBSD: readpass.c,v 1.50 2014/02/02 03:44:31 djm 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 36221420Sdes#include <signal.h> 37162852Sdes#include <stdarg.h> 38162852Sdes#include <stdio.h> 39162852Sdes#include <stdlib.h> 40162852Sdes#include <string.h> 41162852Sdes#include <unistd.h> 42162852Sdes 4357429Smarkm#include "xmalloc.h" 44137015Sdes#include "misc.h" 4576259Sgreen#include "pathnames.h" 4676259Sgreen#include "log.h" 4757429Smarkm#include "ssh.h" 48162852Sdes#include "uidswap.h" 4957429Smarkm 5092555Sdesstatic char * 5192555Sdesssh_askpass(char *askpass, const char *msg) 5276259Sgreen{ 53221420Sdes pid_t pid, ret; 5476259Sgreen size_t len; 5592555Sdes char *pass; 56221420Sdes int p[2], status; 5776259Sgreen char buf[1024]; 58221420Sdes void (*osigchld)(int); 5976259Sgreen 6076259Sgreen if (fflush(stdout) != 0) 6176259Sgreen error("ssh_askpass: fflush: %s", strerror(errno)); 6276259Sgreen if (askpass == NULL) 6376259Sgreen fatal("internal error: askpass undefined"); 6492555Sdes if (pipe(p) < 0) { 6592555Sdes error("ssh_askpass: pipe: %s", strerror(errno)); 66113908Sdes return NULL; 6792555Sdes } 68221420Sdes osigchld = signal(SIGCHLD, SIG_DFL); 6992555Sdes if ((pid = fork()) < 0) { 7092555Sdes error("ssh_askpass: fork: %s", strerror(errno)); 71221420Sdes signal(SIGCHLD, osigchld); 72113908Sdes return NULL; 7392555Sdes } 7476259Sgreen if (pid == 0) { 75162852Sdes permanently_drop_suid(getuid()); 7676259Sgreen close(p[0]); 7776259Sgreen if (dup2(p[1], STDOUT_FILENO) < 0) 7876259Sgreen fatal("ssh_askpass: dup2: %s", strerror(errno)); 7976259Sgreen execlp(askpass, askpass, msg, (char *) 0); 8076259Sgreen fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 8176259Sgreen } 8276259Sgreen close(p[1]); 8392555Sdes 84221420Sdes len = 0; 8592555Sdes do { 86221420Sdes ssize_t r = read(p[0], buf + len, sizeof(buf) - 1 - len); 87221420Sdes 88221420Sdes if (r == -1 && errno == EINTR) 8992555Sdes continue; 90221420Sdes if (r <= 0) 9192555Sdes break; 92221420Sdes len += r; 9392555Sdes } while (sizeof(buf) - 1 - len > 0); 9492555Sdes buf[len] = '\0'; 9592555Sdes 9676259Sgreen close(p[0]); 97221420Sdes while ((ret = waitpid(pid, &status, 0)) < 0) 9876259Sgreen if (errno != EINTR) 9976259Sgreen break; 100221420Sdes signal(SIGCHLD, osigchld); 101221420Sdes if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { 102264377Sdes explicit_bzero(buf, sizeof(buf)); 103113908Sdes return NULL; 104113908Sdes } 105113908Sdes 10692555Sdes buf[strcspn(buf, "\r\n")] = '\0'; 10776259Sgreen pass = xstrdup(buf); 108264377Sdes explicit_bzero(buf, sizeof(buf)); 10976259Sgreen return pass; 11076259Sgreen} 11176259Sgreen 11257429Smarkm/* 11392555Sdes * Reads a passphrase from /dev/tty with echo turned off/on. Returns the 11492555Sdes * passphrase (allocated with xmalloc). Exits if EOF is encountered. If 11592555Sdes * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no 11692555Sdes * tty is available 11757429Smarkm */ 11857429Smarkmchar * 11992555Sdesread_passphrase(const char *prompt, int flags) 12057429Smarkm{ 12192555Sdes char *askpass = NULL, *ret, buf[1024]; 12292555Sdes int rppflags, use_askpass = 0, ttyfd; 12376259Sgreen 12492555Sdes rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; 125137015Sdes if (flags & RP_USE_ASKPASS) 126137015Sdes use_askpass = 1; 127137015Sdes else if (flags & RP_ALLOW_STDIN) { 128149749Sdes if (!isatty(STDIN_FILENO)) { 129149749Sdes debug("read_passphrase: stdin is not a tty"); 13076259Sgreen use_askpass = 1; 131149749Sdes } 13276259Sgreen } else { 13392555Sdes rppflags |= RPP_REQUIRE_TTY; 13492555Sdes ttyfd = open(_PATH_TTY, O_RDWR); 13576259Sgreen if (ttyfd >= 0) 13676259Sgreen close(ttyfd); 137149749Sdes else { 138149749Sdes debug("read_passphrase: can't open %s: %s", _PATH_TTY, 139149749Sdes strerror(errno)); 14076259Sgreen use_askpass = 1; 141149749Sdes } 14276259Sgreen } 14376259Sgreen 144137015Sdes if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL) 145137015Sdes return (flags & RP_ALLOW_EOF) ? NULL : xstrdup(""); 146137015Sdes 14776259Sgreen if (use_askpass && getenv("DISPLAY")) { 14876259Sgreen if (getenv(SSH_ASKPASS_ENV)) 14976259Sgreen askpass = getenv(SSH_ASKPASS_ENV); 15076259Sgreen else 15176259Sgreen askpass = _PATH_SSH_ASKPASS_DEFAULT; 152113908Sdes if ((ret = ssh_askpass(askpass, prompt)) == NULL) 153113908Sdes if (!(flags & RP_ALLOW_EOF)) 154113908Sdes return xstrdup(""); 155113908Sdes return ret; 15676259Sgreen } 15776259Sgreen 15898675Sdes if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { 15998675Sdes if (flags & RP_ALLOW_EOF) 16098675Sdes return NULL; 16192555Sdes return xstrdup(""); 16298675Sdes } 16392555Sdes 16492555Sdes ret = xstrdup(buf); 165264377Sdes explicit_bzero(buf, sizeof(buf)); 16692555Sdes return ret; 16757429Smarkm} 168146998Sdes 169146998Sdesint 170146998Sdesask_permission(const char *fmt, ...) 171146998Sdes{ 172146998Sdes va_list args; 173146998Sdes char *p, prompt[1024]; 174146998Sdes int allowed = 0; 175146998Sdes 176146998Sdes va_start(args, fmt); 177146998Sdes vsnprintf(prompt, sizeof(prompt), fmt, args); 178146998Sdes va_end(args); 179146998Sdes 180146998Sdes p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); 181146998Sdes if (p != NULL) { 182146998Sdes /* 183146998Sdes * Accept empty responses and responses consisting 184146998Sdes * of the word "yes" as affirmative. 185146998Sdes */ 186146998Sdes if (*p == '\0' || *p == '\n' || 187146998Sdes strcasecmp(p, "yes") == 0) 188146998Sdes allowed = 1; 189255767Sdes free(p); 190146998Sdes } 191146998Sdes 192146998Sdes return (allowed); 193146998Sdes} 194