xref: /titanic_50/usr/src/cmd/ssh/libssh/common/readpass.c (revision ef4d27fba69298571e509867dd27ea8bca349ec9)
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