17c478bd9Sstevel@tonic-gate /*
2*ef4d27fbSHuie-Ying Lee * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3*ef4d27fbSHuie-Ying Lee * Use is subject to license terms.
4*ef4d27fbSHuie-Ying Lee */
5*ef4d27fbSHuie-Ying Lee
6*ef4d27fbSHuie-Ying Lee /*
77c478bd9Sstevel@tonic-gate * Copyright (c) 2001 Markus Friedl. All rights reserved.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
107c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions
117c478bd9Sstevel@tonic-gate * are met:
127c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
137c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
147c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
157c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
167c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
177c478bd9Sstevel@tonic-gate *
187c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
197c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
207c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
217c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
227c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
237c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
247c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
257c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
267c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
277c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include "includes.h"
317c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: readpass.c,v 1.27 2002/03/26 15:58:46 markus Exp $");
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include "xmalloc.h"
347c478bd9Sstevel@tonic-gate #include "readpass.h"
357c478bd9Sstevel@tonic-gate #include "pathnames.h"
367c478bd9Sstevel@tonic-gate #include "log.h"
377c478bd9Sstevel@tonic-gate #include "ssh.h"
38*ef4d27fbSHuie-Ying Lee #include <langinfo.h>
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate static char *
ssh_askpass(char * askpass,const char * msg)417c478bd9Sstevel@tonic-gate ssh_askpass(char *askpass, const char *msg)
427c478bd9Sstevel@tonic-gate {
437c478bd9Sstevel@tonic-gate pid_t pid;
447c478bd9Sstevel@tonic-gate size_t len;
457c478bd9Sstevel@tonic-gate char *pass;
467c478bd9Sstevel@tonic-gate int p[2], status, ret;
477c478bd9Sstevel@tonic-gate char buf[1024];
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate if (fflush(stdout) != 0)
507c478bd9Sstevel@tonic-gate error("ssh_askpass: fflush: %s", strerror(errno));
517c478bd9Sstevel@tonic-gate if (askpass == NULL)
527c478bd9Sstevel@tonic-gate fatal("internal error: askpass undefined");
537c478bd9Sstevel@tonic-gate if (pipe(p) < 0) {
547c478bd9Sstevel@tonic-gate error("ssh_askpass: pipe: %s", strerror(errno));
557c478bd9Sstevel@tonic-gate return xstrdup("");
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate if ((pid = fork()) < 0) {
587c478bd9Sstevel@tonic-gate error("ssh_askpass: fork: %s", strerror(errno));
597c478bd9Sstevel@tonic-gate return xstrdup("");
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate if (pid == 0) {
627c478bd9Sstevel@tonic-gate seteuid(getuid());
637c478bd9Sstevel@tonic-gate setuid(getuid());
647c478bd9Sstevel@tonic-gate close(p[0]);
657c478bd9Sstevel@tonic-gate if (dup2(p[1], STDOUT_FILENO) < 0)
667c478bd9Sstevel@tonic-gate fatal("ssh_askpass: dup2: %s", strerror(errno));
677c478bd9Sstevel@tonic-gate execlp(askpass, askpass, msg, (char *) 0);
687c478bd9Sstevel@tonic-gate fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate close(p[1]);
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate len = ret = 0;
737c478bd9Sstevel@tonic-gate do {
747c478bd9Sstevel@tonic-gate ret = read(p[0], buf + len, sizeof(buf) - 1 - len);
757c478bd9Sstevel@tonic-gate if (ret == -1 && errno == EINTR)
767c478bd9Sstevel@tonic-gate continue;
777c478bd9Sstevel@tonic-gate if (ret <= 0)
787c478bd9Sstevel@tonic-gate break;
797c478bd9Sstevel@tonic-gate len += ret;
807c478bd9Sstevel@tonic-gate } while (sizeof(buf) - 1 - len > 0);
817c478bd9Sstevel@tonic-gate buf[len] = '\0';
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate close(p[0]);
847c478bd9Sstevel@tonic-gate while (waitpid(pid, &status, 0) < 0)
857c478bd9Sstevel@tonic-gate if (errno != EINTR)
867c478bd9Sstevel@tonic-gate break;
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate buf[strcspn(buf, "\r\n")] = '\0';
897c478bd9Sstevel@tonic-gate pass = xstrdup(buf);
907c478bd9Sstevel@tonic-gate memset(buf, 0, sizeof(buf));
917c478bd9Sstevel@tonic-gate return pass;
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate * Reads a passphrase from /dev/tty with echo turned off/on. Returns the
967c478bd9Sstevel@tonic-gate * passphrase (allocated with xmalloc). Exits if EOF is encountered. If
977c478bd9Sstevel@tonic-gate * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no
987c478bd9Sstevel@tonic-gate * tty is available
997c478bd9Sstevel@tonic-gate */
1007c478bd9Sstevel@tonic-gate char *
read_passphrase(const char * prompt,int flags)1017c478bd9Sstevel@tonic-gate read_passphrase(const char *prompt, int flags)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate char *askpass = NULL, *ret, buf[1024];
1047c478bd9Sstevel@tonic-gate int rppflags, use_askpass = 0, ttyfd;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
1077c478bd9Sstevel@tonic-gate if (flags & RP_ALLOW_STDIN) {
1087c478bd9Sstevel@tonic-gate if (!isatty(STDIN_FILENO))
1097c478bd9Sstevel@tonic-gate use_askpass = 1;
1107c478bd9Sstevel@tonic-gate } else {
1117c478bd9Sstevel@tonic-gate rppflags |= RPP_REQUIRE_TTY;
1127c478bd9Sstevel@tonic-gate ttyfd = open(_PATH_TTY, O_RDWR);
1137c478bd9Sstevel@tonic-gate if (ttyfd >= 0)
1147c478bd9Sstevel@tonic-gate close(ttyfd);
1157c478bd9Sstevel@tonic-gate else
1167c478bd9Sstevel@tonic-gate use_askpass = 1;
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate if (use_askpass && getenv("DISPLAY")) {
1207c478bd9Sstevel@tonic-gate if (getenv(SSH_ASKPASS_ENV))
1217c478bd9Sstevel@tonic-gate askpass = getenv(SSH_ASKPASS_ENV);
1227c478bd9Sstevel@tonic-gate else
1237c478bd9Sstevel@tonic-gate askpass = _PATH_SSH_ASKPASS_DEFAULT;
1247c478bd9Sstevel@tonic-gate return ssh_askpass(askpass, prompt);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) {
1287c478bd9Sstevel@tonic-gate if (flags & RP_ALLOW_EOF)
1297c478bd9Sstevel@tonic-gate return NULL;
1307c478bd9Sstevel@tonic-gate return xstrdup("");
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate ret = xstrdup(buf);
1347c478bd9Sstevel@tonic-gate memset(buf, 'x', sizeof buf);
1357c478bd9Sstevel@tonic-gate return ret;
1367c478bd9Sstevel@tonic-gate }
137*ef4d27fbSHuie-Ying Lee
138*ef4d27fbSHuie-Ying Lee int
ask_permission(const char * fmt,...)139*ef4d27fbSHuie-Ying Lee ask_permission(const char *fmt, ...)
140*ef4d27fbSHuie-Ying Lee {
141*ef4d27fbSHuie-Ying Lee va_list args;
142*ef4d27fbSHuie-Ying Lee char *p, prompt[1024];
143*ef4d27fbSHuie-Ying Lee int allowed = 0;
144*ef4d27fbSHuie-Ying Lee char *yeschar = nl_langinfo(YESSTR);
145*ef4d27fbSHuie-Ying Lee
146*ef4d27fbSHuie-Ying Lee va_start(args, fmt);
147*ef4d27fbSHuie-Ying Lee vsnprintf(prompt, sizeof(prompt), fmt, args);
148*ef4d27fbSHuie-Ying Lee va_end(args);
149*ef4d27fbSHuie-Ying Lee
150*ef4d27fbSHuie-Ying Lee p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF);
151*ef4d27fbSHuie-Ying Lee if (p != NULL) {
152*ef4d27fbSHuie-Ying Lee /*
153*ef4d27fbSHuie-Ying Lee * Accept empty responses and responses consisting
154*ef4d27fbSHuie-Ying Lee * of the word "yes" as affirmative.
155*ef4d27fbSHuie-Ying Lee */
156*ef4d27fbSHuie-Ying Lee if (*p == '\0' || *p == '\n' ||
157*ef4d27fbSHuie-Ying Lee strncasecmp(p, yeschar, 1) == 0)
158*ef4d27fbSHuie-Ying Lee allowed = 1;
159*ef4d27fbSHuie-Ying Lee xfree(p);
160*ef4d27fbSHuie-Ying Lee }
161*ef4d27fbSHuie-Ying Lee
162*ef4d27fbSHuie-Ying Lee return (allowed);
163*ef4d27fbSHuie-Ying Lee }
164