- markus@cvs.openbsd.org 2001/04/12 19:15:26
     [auth-rhosts.c auth.h auth2.c buffer.c canohost.c canohost.h
      compat.c compat.h hostfile.c pathnames.h readconf.c readconf.h
      servconf.c servconf.h ssh.c sshconnect.c sshconnect.h sshconnect1.c
      sshconnect2.c sshd_config]
     implement HostbasedAuthentication (= RhostRSAAuthentication for ssh v2)
     similar to RhostRSAAuthentication unless you enable (the experimental)
     HostbasedUsesNameFromPacketOnly option.  please test. :)
diff --git a/sshconnect2.c b/sshconnect2.c
index da5b714..9a1d257 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.67 2001/04/05 10:42:56 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.68 2001/04/12 19:15:25 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/md5.h>
@@ -53,6 +53,7 @@
 #include "readpass.h"
 #include "match.h"
 #include "dispatch.h"
+#include "canohost.h"
 
 /* import */
 extern char *client_version_string;
@@ -147,15 +148,20 @@
 
 struct Authctxt {
 	const char *server_user;
+	const char *local_user;
 	const char *host;
 	const char *service;
-	AuthenticationConnection *agent;
 	Authmethod *method;
 	int success;
 	char *authlist;
+	/* pubkey */
 	Key *last_key;
 	sign_cb_fn *last_key_sign;
 	int last_key_hint;
+	AuthenticationConnection *agent;
+	/* hostbased */
+	Key **keys;
+	int nkeys;
 };
 struct Authmethod {
 	char	*name;		/* string to compare against server's list */
@@ -175,6 +181,7 @@
 int	userauth_pubkey(Authctxt *authctxt);
 int	userauth_passwd(Authctxt *authctxt);
 int	userauth_kbdint(Authctxt *authctxt);
+int	userauth_hostbased(Authctxt *authctxt);
 
 void	userauth(Authctxt *authctxt, char *authlist);
 
@@ -200,6 +207,10 @@
 		userauth_kbdint,
 		&options.kbd_interactive_authentication,
 		&options.batch_mode},
+	{"hostbased",
+		userauth_hostbased,
+		&options.hostbased_authentication,
+		NULL},
 	{"none",
 		userauth_none,
 		NULL,
@@ -208,7 +219,8 @@
 };
 
 void
-ssh_userauth2(const char *server_user, char *host)
+ssh_userauth2(const char *local_user, const char *server_user, char *host,
+    Key **keys, int nkeys)
 {
 	Authctxt authctxt;
 	int type;
@@ -242,11 +254,14 @@
 	/* setup authentication context */
 	authctxt.agent = ssh_get_authentication_connection();
 	authctxt.server_user = server_user;
+	authctxt.local_user = local_user;
 	authctxt.host = host;
 	authctxt.service = "ssh-connection";		/* service name */
 	authctxt.success = 0;
 	authctxt.method = authmethod_lookup("none");
 	authctxt.authlist = NULL;
+	authctxt.keys = keys;
+	authctxt.nkeys = nkeys;
 	if (authctxt.method == NULL)
 		fatal("ssh_userauth2: internal error: cannot send userauth none request");
 
@@ -786,6 +801,96 @@
 	packet_send();
 }
 
+/*
+ * 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.
+ */
+int
+userauth_hostbased(Authctxt *authctxt)
+{
+	Key *private = NULL;
+	Buffer b;
+	u_char *signature, *blob;
+	char *chost, *pkalg, *p;
+	u_int blen, slen;
+	int ok, i, found = 0;
+
+	p = get_local_name(packet_get_connection_in());
+	if (p == NULL) {
+		error("userauth_hostbased: cannot get local ipaddr/name");
+		return 0;
+	}
+	chost = xstrdup(p);
+	debug2("userauth_hostbased: chost %s", chost);
+	/* check for a useful key */
+	for (i = 0; i < authctxt->nkeys; i++) {
+		private = authctxt->keys[i];
+		if (private && private->type != KEY_RSA1) {
+			found = 1;
+			/* we take and free the key */
+			authctxt->keys[i] = NULL;
+			break;
+		}
+	}
+	if (!found) {
+		xfree(chost);
+		return 0;
+	}
+	if (key_to_blob(private, &blob, &blen) == 0) {
+		key_free(private);
+		xfree(chost);
+		return 0;
+	}
+	pkalg = xstrdup(key_ssh_name(private));
+	buffer_init(&b);
+	if (datafellows & SSH_OLD_SESSIONID) {
+		buffer_append(&b, session_id2, session_id2_len);
+	} else {
+		buffer_put_string(&b, session_id2, session_id2_len);
+	}
+	/* construct data */
+	buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
+	buffer_put_cstring(&b, authctxt->server_user);
+	buffer_put_cstring(&b,
+	    datafellows & SSH_BUG_HBSERVICE ?
+	    "ssh-userauth" :
+	    authctxt->service);
+	buffer_put_cstring(&b, authctxt->method->name);
+	buffer_put_cstring(&b, pkalg);
+	buffer_put_string(&b, blob, blen);
+	buffer_put_cstring(&b, chost);
+	buffer_put_cstring(&b, authctxt->local_user);
+#ifdef DEBUG_PK
+	buffer_dump(&b);
+#endif
+	debug2("xxx: chost %s", chost);
+	ok = key_sign(private, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
+	key_free(private);
+	buffer_free(&b);
+	if (ok != 0) {
+		error("key_sign failed");
+		xfree(chost);
+		xfree(pkalg);
+		return 0;
+	}
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+	packet_put_cstring(authctxt->server_user);
+	packet_put_cstring(authctxt->service);
+	packet_put_cstring(authctxt->method->name);
+	packet_put_cstring(pkalg);
+	packet_put_string(blob, blen);
+	packet_put_cstring(chost);
+	packet_put_cstring(authctxt->local_user);
+	packet_put_string(signature, slen);
+	memset(signature, 's', slen);
+	xfree(signature);
+	xfree(chost);
+	xfree(pkalg);
+
+	packet_send();
+	return 1;
+}
+
 /* find auth method */
 
 /*