- markus@cvs.openbsd.org 2002/05/23 19:24:30
     [authfile.c authfile.h pathnames.h ssh.c sshconnect.c sshconnect.h
      sshconnect1.c sshconnect2.c ssh-keysign.8 ssh-keysign.c Makefile.in]
     add /usr/libexec/ssh-keysign: a setuid helper program for hostbased
     authentication in protocol v2 (needs to access the hostkeys).

Note: Makefile.in untested.  Will test after merge is finished.
diff --git a/sshconnect2.c b/sshconnect2.c
index 1ee92ab..2736856 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.99 2002/03/26 15:58:46 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.100 2002/05/23 19:24:30 markus Exp $");
 
 #include "ssh.h"
 #include "ssh2.h"
@@ -45,6 +45,8 @@
 #include "match.h"
 #include "dispatch.h"
 #include "canohost.h"
+#include "msg.h"
+#include "pathnames.h"
 
 /* import */
 extern char *client_version_string;
@@ -154,8 +156,7 @@
 	int last_key_hint;
 	AuthenticationConnection *agent;
 	/* hostbased */
-	Key **keys;
-	int nkeys;
+	Sensitive *sensitive;
 	/* kbd-interactive */
 	int info_req_seen;
 };
@@ -215,7 +216,7 @@
 
 void
 ssh_userauth2(const char *local_user, const char *server_user, char *host,
-    Key **keys, int nkeys)
+    Sensitive *sensitive)
 {
 	Authctxt authctxt;
 	int type;
@@ -255,8 +256,7 @@
 	authctxt.success = 0;
 	authctxt.method = authmethod_lookup("none");
 	authctxt.authlist = NULL;
-	authctxt.keys = keys;
-	authctxt.nkeys = nkeys;
+	authctxt.sensitive = sensitive;
 	authctxt.info_req_seen = 0;
 	if (authctxt.method == NULL)
 		fatal("ssh_userauth2: internal error: cannot send userauth none request");
@@ -893,6 +893,75 @@
 	packet_send();
 }
 
+static int
+ssh_keysign(
+    Key *key,
+    u_char **sigp, u_int *lenp,
+    u_char *data, u_int datalen)
+{
+	Buffer b;
+	pid_t pid;
+	int to[2], from[2], status, version = 1;
+
+	debug("ssh_keysign called");
+
+	if (fflush(stdout) != 0)
+		error("ssh_keysign: fflush: %s", strerror(errno));
+	if (pipe(to) < 0) {
+		error("ssh_keysign: pipe: %s", strerror(errno));
+		return -1;
+	}
+	if (pipe(from) < 0) {
+		error("ssh_keysign: pipe: %s", strerror(errno));
+		return -1;
+	}
+	if ((pid = fork()) < 0) {
+		error("ssh_keysign: fork: %s", strerror(errno));
+		return -1;
+	}
+	if (pid == 0) {
+		seteuid(getuid());
+		setuid(getuid());
+		close(from[0]);
+		if (dup2(from[1], STDOUT_FILENO) < 0)
+			fatal("ssh_keysign: dup2: %s", strerror(errno));
+		close(to[1]);
+		if (dup2(to[0], STDIN_FILENO) < 0)
+			fatal("ssh_keysign: dup2: %s", strerror(errno));
+		execlp(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
+		fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
+		    strerror(errno));
+	}
+	close(from[1]);
+	close(to[0]);
+
+	buffer_init(&b);
+	buffer_put_string(&b, data, datalen);
+	msg_send(to[1], version, &b);
+
+	if (msg_recv(from[0], &b) < 0) {
+		debug("ssh_keysign: no reply");
+		buffer_clear(&b);
+		return -1;
+	}
+	if (buffer_get_char(&b) != version) {
+		debug("ssh_keysign: bad version");
+		buffer_clear(&b);
+		return -1;
+	}
+	*sigp = buffer_get_string(&b, lenp);
+	buffer_clear(&b);
+
+	close(from[0]);
+	close(to[1]);
+
+        while (waitpid(pid, &status, 0) < 0)
+                if (errno != EINTR)
+                        break;
+
+	return 0;
+}
+
 /*
  * this will be move to an external program (ssh-keysign) ASAP. ssh-keysign
  * will be setuid-root and the sbit can be removed from /usr/bin/ssh.
@@ -901,6 +970,7 @@
 userauth_hostbased(Authctxt *authctxt)
 {
 	Key *private = NULL;
+	Sensitive *sensitive = authctxt->sensitive;
 	Buffer b;
 	u_char *signature, *blob;
 	char *chost, *pkalg, *p;
@@ -909,12 +979,12 @@
 	int ok, i, len, found = 0;
 
 	/* check for a useful key */
-	for (i = 0; i < authctxt->nkeys; i++) {
-		private = authctxt->keys[i];
+	for (i = 0; i < sensitive->nkeys; i++) {
+		private = sensitive->keys[i];
 		if (private && private->type != KEY_RSA1) {
 			found = 1;
 			/* we take and free the key */
-			authctxt->keys[i] = NULL;
+			sensitive->keys[i] = NULL;
 			break;
 		}
 	}
@@ -956,7 +1026,12 @@
 #ifdef DEBUG_PK
 	buffer_dump(&b);
 #endif
-	ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+	if (sensitive->external_keysign)
+		ok = ssh_keysign(private, &signature, &slen,
+		    buffer_ptr(&b), buffer_len(&b));
+	else
+		ok = key_sign(private, &signature, &slen,
+		    buffer_ptr(&b), buffer_len(&b));
 	key_free(private);
 	buffer_free(&b);
 	if (ok != 0) {