code: plan9front

Download patch

ref: 1a4e03cf93872eb78f498af8afd5d8c7d6143178
parent: 8597051d6460da881c0501c7036dc229dc3101ca
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 3 00:19:46 EDT 2022

ip/sol: kvm (vnc) redirect, bring back plain authentication as a fallback (when unsupported)

--- a/sys/man/8/sol
+++ b/sys/man/8/sol
@@ -4,7 +4,7 @@
 .SH SYNOPSIS
 .B ip/sol
 [
-.B -rR
+.B -TRrk
 ] [
 .B -u
 .I user
@@ -15,12 +15,10 @@
 serial-over-lan interface of intel AMT
 enabled machines.
 .PP
-The protocol runs over tcp port 16995 and
-and is protected using TLS.
+The protocol runs over tcp ports 16994/16995 and
+and is optinally protected using TLS.
 .PP
-For authentication, a
-.B proto=httpdigest
-key with a username and password is required.
+For authentication, a username and password is required.
 The default username, unless
 given by the
 .B -u
@@ -30,6 +28,10 @@
 factotum.
 .PP
 The
+.B -T
+flag disables TLS encryption (enabled by default).
+.PP
+The
 .B -r
 and
 .B -R
@@ -39,9 +41,20 @@
 By default, raw mode is enabled when the
 .B $TERM
 environment variable has been set.
+.PP
+The
+.B -k
+flag connects to the VNC port instead.
+.SH EXAMPLE
+Connect to the KVM port with
+.IR vnc(1):
+.IP
+.EX
+execnet && vnc 'exec!ip/sol -k host'
+.EE
 .SH SOURCE
 .B /sys/src/cmd/ip/sol.c
 .SH "SEE ALSO"
-.IR ssh (1),
-.IR consolefs (4),
+.IR execnet (4),
+.IR vncv (1),
 .IR factotum (4)
--- a/sys/src/cmd/ip/sol.c
+++ b/sys/src/cmd/ip/sol.c
@@ -15,7 +15,10 @@
 	HEATBEAT_INTERVAL = 5000,
 };
 
-int authok = 0, pid = 0, raw = -1, fd = -1;
+char *user = "admin";
+int authok = 0, pid = 0, raw = -1, kvm = 0, fd = -1, tls = 1;
+int reply, ok, n;
+char buf[MAX_TRANSMIT_BUFFER];
 Biobuf bin, bout;
 jmp_buf reconnect;
 
@@ -123,12 +126,11 @@
 	}
 }
 
-void
+int
 digestauth(char *server, char *user, char *method, char *url)
 {
 	char realm[256+1], nonce[256+1], qop[256+1], nc[10], cnonce[32+1], chal[1024], resp[1024], ouser[256];
 	static uint counter;
-	int reply, ok, n;
 	
 	send("lblb[__b[____", 0x13, 4,
 		1+strlen(user) + 2 + 1+strlen(url) + 4,
@@ -136,7 +138,7 @@
 		strlen(url), url, strlen(url));
 	recv("lbl", &reply, &ok, &n);
 	if(reply != 0x114 || ok != 4 || n == 0)
-		sysfatal("bad auth reply: %x %x", reply, ok);
+		return -1;	/* not supported */
 
 	recv("b", &n);
 	recv("[", realm, n);
@@ -173,13 +175,46 @@
 		strlen(qop), qop, strlen(qop));
 	recv("lb*", &reply, &ok);
 	if(reply != 0x14 && ok != 4)
-		sysfatal("bad auth reply: %x %x", reply, ok);
+		sysfatal("bad digest auth reply: %x %x", reply, ok);
+	return 0;
 }
 
 void
+plainauth(char *user, char *pass)
+{
+	send("lblb[b[", 0x13, 1,
+		strlen(user)+1+strlen(pass)+1, 
+		strlen(user), user, strlen(user),
+		strlen(pass), pass, strlen(pass));
+	recv("lb*", &reply, &ok);
+	if(reply != 0x14 || ok != 1)
+		sysfatal("bad password auth reply: %x %x", reply, ok);
+}
+
+void
+auth(char *server, char *user)
+{
+	static UserPasswd *up = nil;
+
+	if(up == nil){
+		if(digestauth(server, user, "POST", "/RedirectionService") == 0)
+			return;
+
+		/* if digest auth not supported, get plaintext password */
+		up = auth_getuserpasswd(auth_getkey,
+			"proto=pass service=sol user=%q server=%q",
+			user, server);
+		if(up == nil)
+			sysfatal("auth_getuserpasswd: %r");
+		longjmp(reconnect, 1);
+	}	
+	plainauth(up->user, up->passwd);
+}
+
+void
 usage(void)
 {
-	fprint(2, "usage: %s [-Rr] [-u user] host\n", argv0);
+	fprint(2, "usage: %s [-TRrk] [-u user] host\n", argv0);
 	exits("usage");
 }
 
@@ -186,11 +221,6 @@
 void
 main(int argc, char *argv[])
 {
-	uchar buf[MAX_TRANSMIT_BUFFER];
-	TLSconn tls;
-	char  *user = "admin";
-	int reply, ok, n;
-
 	fmtinstall('[', encodefmt);
 	fmtinstall('H', encodefmt);
 
@@ -198,6 +228,9 @@
 	case 'u':
 		user = EARGF(usage());
 		break;
+	case 'T':
+		tls = 0;
+		break;
 	case 'R':
 		raw = 0;
 		break;
@@ -204,6 +237,9 @@
 	case 'r':
 		raw = 1;
 		break;
+	case 'k':
+		kvm = 1;
+		break;
 	default:
 		usage();
 	} ARGEND;
@@ -211,6 +247,9 @@
 	if(argc != 1)
 		usage();
 
+	if(kvm)
+		goto Connect;
+
 	if(raw < 0) {
 		char *term = getenv("TERM");
 		raw = term && *term;
@@ -230,19 +269,23 @@
 			write(fd, "rawon", 5);
 	}
 
-Reconnect:
-	fd = dial(netmkaddr(argv[0], "tcp", "16995"), nil, nil, nil);
+Connect:
+	fd = dial(netmkaddr(argv[0], "tcp", tls ? "16995" : "16994"), nil, nil, nil);
 	if(fd < 0)
 		sysfatal("dial: %r");
 
-	memset(&tls, 0, sizeof(tls));
-	fd = tlsClient(fd, &tls);
-	if(fd < 0)
-		sysfatal("tls client: %r");
-	free(tls.cert);
-	free(tls.sessionID);
-	memset(&tls, 0, sizeof(tls));
+	if(tls){
+		TLSconn conn;
 
+		memset(&conn, 0, sizeof(conn));
+		fd = tlsClient(fd, &conn);
+		if(fd < 0)
+			sysfatal("tls: %r");
+		free(conn.cert);
+		free(conn.sessionID);
+		memset(&conn, 0, sizeof(conn));
+	}
+
 	authok = 0;
 	Binit(&bin, fd, OREAD);
 	Binit(&bout, fd, OWRITE);
@@ -250,17 +293,52 @@
 		Bterm(&bin);
 		Bterm(&bout);
 		close(fd);
-		goto Reconnect;
+		goto Connect;
 	}
 
-	send("l[", 0x10, "SOL ", 4);
+	if(kvm)
+		send("l[", 0x110, "KVMR", 4);
+	else
+		send("l[", 0x10, "SOL ", 4);
+
 	recv("lb*", &reply, &ok);
 	if(reply != 0x11 || ok != 1)
 		sysfatal("bad session reply: %x %x", reply, ok);
 
-	digestauth(argv[0], user, "POST", "/RedirectionService");
+	auth(argv[0], user);
 	authok = 1;
 
+	/* kvm port redirect */
+	if(kvm){
+		int from, to;
+
+		send("b_______", 0x40);
+		if(read(fd, buf, 8) != 8 || buf[0] != 0x41)
+			sysfatal("bad redirection reply: %x %x", reply, ok);
+
+		pid = fork();
+		if(pid == 0){
+			pid = getppid();
+			from = 0;
+			to = fd;
+		} else {
+			from = fd;
+			to = 1;
+		}
+		atexit(killpid);
+		for(;;){
+			n = read(from, buf, sizeof(buf));
+			if(n < 0)
+				sysfatal("read: %r");
+			if(n == 0)
+				break;
+			if(write(to, buf, n) != n)
+				sysfatal("write: %r");
+		}
+		exits(nil);
+	}
+
+	/* serial over lan */
 	send("l____wwwwww____", 0x20,
 		MAX_TRANSMIT_BUFFER,
 		TRANSMIT_BUFFER_TIMEOUT,
@@ -270,7 +348,7 @@
 		HEATBEAT_INTERVAL);
 	recv("lb*", &reply, &ok);
 	if(reply != 0x21 || ok != 1)
-		sysfatal("bad redirection reply: %x %x", reply, ok);
+		sysfatal("bad sol reply: %x %x", reply, ok);
 
 	pid = fork();
 	if(pid == 0){
@@ -305,5 +383,6 @@
 			}
 		}
 	}
+
 	exits(nil);
 }