shithub: riscv

Download patch

ref: 2e714ffe7c3dd2d0a449622189df4efc69a9adba
parent: bef681b892d4aac23279f30013bc28041ef25bd0
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Apr 20 18:28:21 EDT 2017

ssh: implement password and keyboard-interactive authentication methods

--- a/sys/src/cmd/ssh.c
+++ b/sys/src/cmd/ssh.c
@@ -3,6 +3,7 @@
 #include <mp.h>
 #include <libsec.h>
 #include <auth.h>
+#include <authsrv.h>
 
 enum {
 	MSG_DISCONNECT = 1,
@@ -24,6 +25,8 @@
 	MSG_USERAUTH_BANNER,
 
 	MSG_USERAUTH_PK_OK = 60,
+	MSG_USERAUTH_INFO_REQUEST = 60,
+	MSG_USERAUTH_INFO_RESPONSE = 61,
 
 	MSG_GLOBAL_REQUEST = 80,
 	MSG_REQUEST_SUCCESS,
@@ -59,9 +62,10 @@
 
 int nsid;
 uchar sid[256];
+char thumb[2*SHA2_256dlen+1];
 
 int fd, intr, raw, debug;
-char *user, *status, *host, *cmd;
+char *user, *service, *status, *host, *cmd;
 
 Oneway recv, send;
 void dispatch(void);
@@ -302,7 +306,8 @@
 			if(n < 0 && wasintr()){
 				n = 0;
 				continue;
-			}
+			} else if(n == 0)
+				werrstr("eof");
 			break;
 		}
 	}
@@ -481,7 +486,7 @@
 
 	uchar cookie[16], x[32], yc[32], z[32], k[32+1], h[SHA2_256dlen], *ys, *ks, *sig;
 	uchar k12[2*ChachaKeylen];
-	int nk, nys, nks, nsig;
+	int i, nk, nys, nks, nsig;
 	DigestState *ds;
 	mpint *S, *K;
 	RSApub *pub;
@@ -558,6 +563,14 @@
 	ds = hashstr(yc, 32, ds);
 	ds = hashstr(ys, 32, ds);
 
+	sha2_256(ks, nks, h, nil);
+	i = snprint(thumb, sizeof(thumb), "%.*[", sizeof(h), h);
+	while(i > 0 && thumb[i-1] == '=')
+		thumb[--i] = '\0';
+
+if(debug)
+	fprint(2, "host fingerprint: %s\n", thumb);
+
 	if((pub = ssh2rsapub(ks, nks)) == nil)
 		sysfatal("bad server public key");
 	if((S = ssh2rsasig(sig, nsig)) == nil)
@@ -605,10 +618,9 @@
 }
 
 int
-auth(char *username, char *servicename)
+pubkeyauth(void)
 {
-	static char sshuserauth[] = "ssh-userauth";
-	static char publickey[] = "publickey";
+	static char authmeth[] = "publickey";
 
 	uchar pk[4096], sig[4096];
 	int npk, nsig;
@@ -619,14 +631,8 @@
 	AuthRpc *rpc;
 	RSApub *pub;
 
-	sendpkt("bs", MSG_SERVICE_REQUEST, sshuserauth, sizeof(sshuserauth)-1);
-Next0:	switch(recvpkt()){
-	default:
-		dispatch();
-		goto Next0;
-	case MSG_SERVICE_ACCEPT:
-		break;
-	}
+if(debug)
+	fprint(2, "%s...\n", authmeth);
 
 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
 		return -1;
@@ -657,9 +663,9 @@
 		npk = rsapub2ssh(pub, pk, sizeof(pk));
 
 		sendpkt("bsssbss", MSG_USERAUTH_REQUEST,
-			username, strlen(username),
-			servicename, strlen(servicename),
-			publickey, sizeof(publickey)-1,
+			user, strlen(user),
+			service, strlen(service),
+			authmeth, sizeof(authmeth)-1,
 			0,
 			sshrsa, sizeof(sshrsa)-1,
 			pk, npk);
@@ -678,9 +684,9 @@
 		n = pack(send.b, sizeof(send.b), "sbsssbss",
 			sid, nsid,
 			MSG_USERAUTH_REQUEST,
-			username, strlen(username),
-			servicename, strlen(servicename),
-			publickey, sizeof(publickey)-1,
+			user, strlen(user),
+			service, strlen(service),
+			authmeth, sizeof(authmeth)-1,
 			1,
 			sshrsa, sizeof(sshrsa)-1,
 			pk, npk);
@@ -699,9 +705,9 @@
 
 		/* send final userauth request with the signature */
 		sendpkt("bsssbsss", MSG_USERAUTH_REQUEST,
-			username, strlen(username),
-			servicename, strlen(servicename),
-			publickey, sizeof(publickey)-1,
+			user, strlen(user),
+			service, strlen(service),
+			authmeth, sizeof(authmeth)-1,
 			1,
 			sshrsa, sizeof(sshrsa)-1,
 			pk, npk,
@@ -726,6 +732,132 @@
 	return -1;	
 }
 
+int
+passauth(void)
+{
+	static char authmeth[] = "password";
+	UserPasswd *up;
+
+if(debug)
+	fprint(2, "%s...\n", authmeth);
+
+	up = auth_getuserpasswd(auth_getkey, "proto=pass servive=ssh user=%q server=%q thumb=%q",
+		user, host, thumb);
+	if(up == nil)
+		return -1;
+
+	sendpkt("bsssbs", MSG_USERAUTH_REQUEST,
+		user, strlen(user),
+		service, strlen(service),
+		authmeth, sizeof(authmeth)-1,
+		0,
+		up->passwd, strlen(up->passwd));
+
+	memset(up->passwd, 0, strlen(up->passwd));
+	free(up);
+
+Next0:	switch(recvpkt()){
+	default:
+		dispatch();
+		goto Next0;
+	case MSG_USERAUTH_FAILURE:
+		werrstr("%s authentication failed", authmeth);
+		return -1;
+	case MSG_USERAUTH_SUCCESS:
+		return 0;
+	}
+}
+
+int
+kbintauth(void)
+{
+	static char authmeth[] = "keyboard-interactive";
+
+	char *name, *inst, *s, *a;
+	int fd, i, n, m;
+	int nquest, echo;
+	uchar *ans, *answ;
+
+if(debug)
+	fprint(2, "%s...\n", authmeth);
+
+	sendpkt("bsssss", MSG_USERAUTH_REQUEST,
+		user, strlen(user),
+		service, strlen(service),
+		authmeth, sizeof(authmeth)-1,
+		"", 0,
+		"", 0);
+
+Next0:	switch(recvpkt()){
+	default:
+		dispatch();
+		goto Next0;
+	case MSG_USERAUTH_FAILURE:
+		werrstr("%s authentication failed", authmeth);
+		return -1;
+	case MSG_USERAUTH_SUCCESS:
+		return 0;
+	case MSG_USERAUTH_INFO_REQUEST:
+		break;
+	}
+
+	if((fd = open("/dev/cons", OWRITE)) < 0)
+		return -1;
+
+	if(unpack(recv.r, recv.w-recv.r, "_ss.", &name, &n, &inst, &m, &recv.r) < 0)
+		sysfatal("bad info request: name, inst");
+
+	while(n > 0 && strchr("\r\n\t ", name[n-1]) != nil)
+		n--;
+	while(m > 0 && strchr("\r\n\t ", inst[m-1]) != nil)
+		m--;
+
+	if(n > 0)
+		fprint(fd, "%.*s\n", n, name);
+	if(m > 0)
+		fprint(fd, "%.*s\n", m, inst);
+
+	/* lang, nprompt */
+	if(unpack(recv.r, recv.w-recv.r, "su.", &s, &n, &nquest, &recv.r) < 0)
+		sysfatal("bad info request: lang, #quest");
+
+	ans = answ = nil;
+	for(i = 0; i < nquest; i++){
+		if(unpack(recv.r, recv.w-recv.r, "sb.", &s, &n, &echo, &recv.r) < 0)
+			sysfatal("bad info request: question [%d]", i);
+
+		while(n > 0 && strchr("\r\n\t :", s[n-1]) != nil)
+			n--;
+		s[n] = '\0';
+
+		if((a = readcons(s, nil, !echo)) == nil)
+			sysfatal("readcons: %r");
+
+		n = answ - ans;
+		m = strlen(a)+4;
+		if((s = realloc(ans, n + m)) == nil)
+			sysfatal("realloc: %r");
+		ans = (uchar*)s;
+		answ = ans+n;
+		answ += pack(answ, m, "s", a, m-4);
+	}
+
+	sendpkt("bu[", MSG_USERAUTH_INFO_RESPONSE, i, ans, answ - ans);
+	free(ans);
+	close(fd);
+
+Next1:	switch(recvpkt()){
+	default:
+		dispatch();
+		goto Next1;
+	case MSG_USERAUTH_FAILURE:
+		werrstr("%s authentication failed", authmeth);
+		return -1;
+	case MSG_USERAUTH_SUCCESS:
+		return 0;
+	}
+}
+
 void
 dispatch(void)
 {
@@ -886,6 +1018,7 @@
 	quotefmtinstall();
 	fmtinstall('B', mpfmt);
 	fmtinstall('H', encodefmt);
+	fmtinstall('[', encodefmt);
 
 	s = getenv("TERM");
 	raw = s != nil && strcmp(s, "dumb") != 0;
@@ -940,9 +1073,21 @@
 	recv.v = strdup(recv.v);
 
 	kex(0);
+
 	if(user == nil)
 		user = getuser();
-	if(auth(user, "ssh-connection") < 0)
+	service = "ssh-connection";
+
+	sendpkt("bs", MSG_SERVICE_REQUEST, "ssh-userauth", 12);
+Next0:	switch(recvpkt()){
+	default:
+		dispatch();
+		goto Next0;
+	case MSG_SERVICE_ACCEPT:
+		break;
+	}
+
+	if(pubkeyauth() < 0 && passauth() < 0 && kbintauth() < 0)
 		sysfatal("auth: %r");
 
 	/* open hailing frequencies */
@@ -952,10 +1097,10 @@
 		sizeof(buf),
 		sizeof(buf));
 
-Next0:	switch(recvpkt()){
+Next1:	switch(recvpkt()){
 	default:
 		dispatch();
-		goto Next0;
+		goto Next1;
 	case MSG_CHANNEL_OPEN_FAILURE:
 		if(unpack(recv.r, recv.w-recv.r, "_uus", &c, &b, &s, &n) < 0)
 			n = strlen(s = "???");