2.2.0p1 PATCH: ssh/scp/slogin will invoke ssh-askpass

James Ralston qralston+ml.openssh-unix-dev at andrew.cmu.edu
Sun Sep 10 08:31:51 EST 2000


Enclosed is a patch against 2.2.0p1 that teaches ssh (and therefore
slogin and scp) how to invoke ssh-askpass to request a password,
RSA/DSA key passphrase, or an skey challenge response.

I've tested this on Linux (i386), for passwords and RSA/DSA key
passphrases.  I cannot easily test whether the Right Thing will happen
for skey challenge responses; I would appreciate it if someone who
uses skey would apply this patch and see if it works properly.

In the process of making this patch, I fixed a bug in the
ssh_askpass() function (it assumed the string read from the pipe to
ssh-askpass would always contain a trailing newline, which is a false
assumption).

Also, the ssh2_try_passwd() function appears to be broken, in that it
contains partial logic to prompt for the correct password multiple
times, but the flow of execution through the function guarantees that
it can never ask for the password more than once.  I wasn't sure what
was intended here, so my patched version of ssh2_try_passwd() keeps
the same (broken?) logic.

Regards,

-- 
James Ralston, Information Technology
Software Engineering Institute
Carnegie Mellon University, Pittsburgh, PA, USA
-------------- next part --------------
diff -U 3 -N -r ORIG/openssh-2.2.0p1/readpass.c openssh-2.2.0p1/readpass.c
--- ORIG/openssh-2.2.0p1/readpass.c	Thu Jun 22 07:32:32 2000
+++ openssh-2.2.0p1/readpass.c	Sat Sep  9 01:10:07 2000
@@ -117,3 +117,48 @@
 	memset(buf, 0, sizeof(buf));
 	return (p);
 }
+
+/*
+ * Reads a passphrase by calling ssh-askpass.  Returns the passphrase
+ * (allocated with xmalloc), being very careful to ensure that no
+ * other userland buffer is storing the password.
+ */
+char *
+ssh_askpass(char *askpass, char *msg)
+{
+	pid_t pid;
+	size_t len;
+	char *nl, *pass;
+	int p[2], status;
+	char buf[1024];
+
+	if (askpass == NULL)
+		fatal("internal error: askpass undefined");
+	if (pipe(p) < 0)
+		fatal("ssh_askpass: pipe: %s", strerror(errno));
+	if ((pid = fork()) < 0)
+		fatal("ssh_askpass: fork: %s", strerror(errno));
+	if (pid == 0) {
+		close(p[0]);
+		if (dup2(p[1], STDOUT_FILENO) < 0)
+			fatal("ssh_askpass: dup2: %s", strerror(errno));
+		execlp(askpass, askpass, msg, (char *) 0);
+		fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
+	}
+	close(p[1]);
+	len = read(p[0], buf, sizeof buf);
+	close(p[0]);
+	while (waitpid(pid, &status, 0) < 0)
+		if (errno != EINTR)
+			break;
+	if (len <= 1)
+		return xstrdup("");
+	if (! (len == sizeof buf))
+		buf[len] = '\0';
+	nl = strchr(buf, '\n');
+	if (nl)
+		*nl = '\0';
+	pass = xstrdup(buf);
+	memset(buf, 0, sizeof(buf));
+	return pass;
+}
diff -U 3 -N -r ORIG/openssh-2.2.0p1/ssh-add.c openssh-2.2.0p1/ssh-add.c
--- ORIG/openssh-2.2.0p1/ssh-add.c	Mon Aug 28 20:33:51 2000
+++ openssh-2.2.0p1/ssh-add.c	Sat Sep  9 01:10:07 2000
@@ -65,44 +65,6 @@
 		fprintf(stderr, "Failed to remove all identitities.\n");
 }
 
-char *
-ssh_askpass(char *askpass, char *msg)
-{
-	pid_t pid;
-	size_t len;
-	char *nl, *pass;
-	int p[2], status;
-	char buf[1024];
-
-	if (askpass == NULL)
-		fatal("internal error: askpass undefined");
-	if (pipe(p) < 0)
-		fatal("ssh_askpass: pipe: %s", strerror(errno));
-	if ((pid = fork()) < 0)
-		fatal("ssh_askpass: fork: %s", strerror(errno));
-	if (pid == 0) {
-		close(p[0]);
-		if (dup2(p[1], STDOUT_FILENO) < 0)
-			fatal("ssh_askpass: dup2: %s", strerror(errno));
-		execlp(askpass, askpass, msg, (char *) 0);
-		fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
-	}
-	close(p[1]);
-	len = read(p[0], buf, sizeof buf);
-	close(p[0]);
-	while (waitpid(pid, &status, 0) < 0)
-		if (errno != EINTR)
-			break;
-	if (len <= 1)
-		return xstrdup("");
-	nl = strchr(buf, '\n');
-	if (nl)
-		*nl = '\0';
-	pass = xstrdup(buf);
-	memset(buf, 0, sizeof(buf));
-	return pass;
-}
-
 void
 add_file(AuthenticationConnection *ac, const char *filename)
 {
diff -U 3 -N -r ORIG/openssh-2.2.0p1/ssh.h openssh-2.2.0p1/ssh.h
--- ORIG/openssh-2.2.0p1/ssh.h	Tue Aug 22 20:46:25 2000
+++ openssh-2.2.0p1/ssh.h	Sat Sep  9 01:10:07 2000
@@ -426,6 +426,12 @@
  */
 char   *read_passphrase(const char *prompt, int from_stdin);
 
+/*
+ * Reads a passphrase by calling ssh-askpass.  Returns the passphrase
+ * (allocated with xmalloc), being very careful to ensure that no
+ * other userland buffer is storing the password.
+ */
+char	*ssh_askpass(char *askpass, char *msg);
 
 /*------------ Definitions for logging. -----------------------*/
 
diff -U 3 -N -r ORIG/openssh-2.2.0p1/sshconnect1.c openssh-2.2.0p1/sshconnect1.c
--- ORIG/openssh-2.2.0p1/sshconnect1.c	Tue Aug 22 20:46:25 2000
+++ openssh-2.2.0p1/sshconnect1.c	Sat Sep  9 01:13:35 2000
@@ -191,6 +191,8 @@
 	char *passphrase, *comment;
 	int type, i;
 	int plen, clen;
+	int interactive = isatty(STDIN_FILENO);
+	char *askpass = NULL;
 
 	/* Try to load identification for the authentication key. */
 	public = key_new(KEY_RSA);
@@ -244,7 +246,15 @@
 		snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ",
 		    comment);
 		if (!options.batch_mode)
-			passphrase = read_passphrase(buf, 0);
+			if (!interactive && getenv("DISPLAY")) {
+				if (getenv(SSH_ASKPASS_ENV))
+					askpass = getenv(SSH_ASKPASS_ENV);
+				else
+					askpass = SSH_ASKPASS_DEFAULT;
+				passphrase = ssh_askpass(askpass, buf);
+			} else {
+				passphrase = read_passphrase(buf, 0);
+			}
 		else {
 			debug("Will not query passphrase for %.100s in batch mode.",
 			      comment);
@@ -602,6 +612,9 @@
 	int payload_len;
 	unsigned int clen;
 	char *challenge, *response;
+	int interactive = isatty(STDIN_FILENO);
+	char *askpass = NULL;
+	char buf[300];
 
 	debug("Doing skey authentication.");
 
@@ -625,13 +638,30 @@
 	if (options.cipher == SSH_CIPHER_NONE)
 		log("WARNING: Encryption is disabled! "
 		    "Reponse will be transmitted in clear text.");
-	fprintf(stderr, "%s\n", challenge);
+	if (!interactive && getenv("DISPLAY")) {
+		if (getenv(SSH_ASKPASS_ENV))
+			askpass = getenv(SSH_ASKPASS_ENV);
+		else
+			askpass = SSH_ASKPASS_DEFAULT;
+		snprintf(buf, sizeof buf, 
+		    "Challenge: \"%s\"; enter response:", challenge);
+	} else {
+		fprintf(stderr, "%s\n", challenge);
+	}
 	xfree(challenge);
 	fflush(stderr);
 	for (i = 0; i < options.number_of_password_prompts; i++) {
-		if (i != 0)
-			error("Permission denied, please try again.");
-		response = read_passphrase("Response: ", 0);
+		if (!interactive && getenv("DISPLAY")) {
+			if (i != 0)
+				response = ssh_askpass(askpass, 
+				    "Permission denied, please try again:");
+			else
+				response = ssh_askpass(askpass, buf);
+		} else {
+			if (i != 0)
+				error("Permission denied, please try again.");
+			response = read_passphrase("Response: ", 0);
+		}
 		packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
 		packet_put_string(response, strlen(response));
 		memset(response, 0, strlen(response));
@@ -657,14 +687,31 @@
 {
 	int type, i, payload_len;
 	char *password;
+	int interactive = isatty(STDIN_FILENO);
+	char *askpass = NULL;
 
 	debug("Doing password authentication.");
 	if (options.cipher == SSH_CIPHER_NONE)
 		log("WARNING: Encryption is disabled! Password will be transmitted in clear text.");
+	if (!interactive && getenv("DISPLAY")) {
+		if (getenv(SSH_ASKPASS_ENV)) {
+			askpass = getenv(SSH_ASKPASS_ENV);
+		} else {
+			askpass = SSH_ASKPASS_DEFAULT;
+		}
+	}
 	for (i = 0; i < options.number_of_password_prompts; i++) {
-		if (i != 0)
-			error("Permission denied, please try again.");
-		password = read_passphrase(prompt, 0);
+		if (!interactive && getenv("DISPLAY")) {
+			if (i != 0)
+				password = ssh_askpass(askpass,
+				    "Permission denied, please try again:");
+			else
+				password = ssh_askpass(askpass, prompt);
+		} else {
+			if (i != 0)
+				error("Permission denied, please try again.");
+			password = read_passphrase(prompt, 0);
+		}
 		packet_start(SSH_CMSG_AUTH_PASSWORD);
 		packet_put_string(password, strlen(password));
 		memset(password, 0, strlen(password));
diff -U 3 -N -r ORIG/openssh-2.2.0p1/sshconnect2.c openssh-2.2.0p1/sshconnect2.c
--- ORIG/openssh-2.2.0p1/sshconnect2.c	Tue Aug 22 20:46:25 2000
+++ openssh-2.2.0p1/sshconnect2.c	Sat Sep  9 01:10:30 2000
@@ -264,16 +264,30 @@
 	static int attempt = 0;
 	char prompt[80];
 	char *password;
+	int interactive = isatty(STDIN_FILENO);
+	char *askpass = NULL;
 
 	if (attempt++ >= options.number_of_password_prompts)
 		return 0;
-
-	if(attempt != 1)
-		error("Permission denied, please try again.");
-
+	if (!interactive && getenv("DISPLAY")) {
+		if (getenv(SSH_ASKPASS_ENV))
+			askpass = getenv(SSH_ASKPASS_ENV);
+		else
+			askpass = SSH_ASKPASS_DEFAULT;
+	}
 	snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
 	    server_user, host);
-	password = read_passphrase(prompt, 0);
+	if (!interactive && getenv("DISPLAY")) {
+		if (attempt != 1)
+			password = ssh_askpass(askpass,
+			    "Permission denied, please try again:");
+		else
+			password = ssh_askpass(askpass, prompt);
+	} else {
+		if (attempt != 1)
+			error("Permission denied, please try again.");
+		password = read_passphrase(prompt, 0);
+	}
 	packet_start(SSH2_MSG_USERAUTH_REQUEST);
 	packet_put_cstring(server_user);
 	packet_put_cstring(service);
@@ -374,6 +388,8 @@
 	Key *k;
 	int ret = 0;
 	struct stat st;
+	int interactive = isatty(STDIN_FILENO);
+	char *askpass = NULL;
 
 	if (stat(filename, &st) != 0) {
 		debug("key does not exist: %s", filename);
@@ -389,7 +405,15 @@
 		snprintf(prompt, sizeof prompt,
 		     "Enter passphrase for DSA key '%.100s': ",
 		     filename);
-		passphrase = read_passphrase(prompt, 0);
+		if (!interactive && getenv("DISPLAY")) {
+			if (getenv(SSH_ASKPASS_ENV))
+				askpass = getenv(SSH_ASKPASS_ENV);
+			else
+				askpass = SSH_ASKPASS_DEFAULT;
+			passphrase = ssh_askpass(askpass, prompt);
+		} else {
+			passphrase = read_passphrase(prompt, 0);
+		}
 		success = load_private_key(filename, passphrase, k, NULL);
 		memset(passphrase, 0, strlen(passphrase));
 		xfree(passphrase);


More information about the openssh-unix-dev mailing list