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);
}