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

This commit is contained in:
cinap_lenrek 2022-04-03 04:19:46 +00:00
parent 8597051d64
commit 1a4e03cf93
2 changed files with 124 additions and 32 deletions

View file

@ -4,7 +4,7 @@ sol - Intel AMT serial-over-lan console
.SH SYNOPSIS .SH SYNOPSIS
.B ip/sol .B ip/sol
[ [
.B -rR .B -TRrk
] [ ] [
.B -u .B -u
.I user .I user
@ -15,12 +15,10 @@ This program provides remote access to the
serial-over-lan interface of intel AMT serial-over-lan interface of intel AMT
enabled machines. enabled machines.
.PP .PP
The protocol runs over tcp port 16995 and The protocol runs over tcp ports 16994/16995 and
and is protected using TLS. and is optinally protected using TLS.
.PP .PP
For authentication, a For authentication, a username and password is required.
.B proto=httpdigest
key with a username and password is required.
The default username, unless The default username, unless
given by the given by the
.B -u .B -u
@ -30,6 +28,10 @@ The password will be prompted and kept in
factotum. factotum.
.PP .PP
The The
.B -T
flag disables TLS encryption (enabled by default).
.PP
The
.B -r .B -r
and and
.B -R .B -R
@ -39,9 +41,20 @@ standard input and output.
By default, raw mode is enabled when the By default, raw mode is enabled when the
.B $TERM .B $TERM
environment variable has been set. 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 .SH SOURCE
.B /sys/src/cmd/ip/sol.c .B /sys/src/cmd/ip/sol.c
.SH "SEE ALSO" .SH "SEE ALSO"
.IR ssh (1), .IR execnet (4),
.IR consolefs (4), .IR vncv (1),
.IR factotum (4) .IR factotum (4)

View file

@ -15,7 +15,10 @@ enum {
HEATBEAT_INTERVAL = 5000, 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; Biobuf bin, bout;
jmp_buf reconnect; jmp_buf reconnect;
@ -123,12 +126,11 @@ send(char *fmt, ...)
} }
} }
void int
digestauth(char *server, char *user, char *method, char *url) 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]; char realm[256+1], nonce[256+1], qop[256+1], nc[10], cnonce[32+1], chal[1024], resp[1024], ouser[256];
static uint counter; static uint counter;
int reply, ok, n;
send("lblb[__b[____", 0x13, 4, send("lblb[__b[____", 0x13, 4,
1+strlen(user) + 2 + 1+strlen(url) + 4, 1+strlen(user) + 2 + 1+strlen(url) + 4,
@ -136,7 +138,7 @@ digestauth(char *server, char *user, char *method, char *url)
strlen(url), url, strlen(url)); strlen(url), url, strlen(url));
recv("lbl", &reply, &ok, &n); recv("lbl", &reply, &ok, &n);
if(reply != 0x114 || ok != 4 || n == 0) if(reply != 0x114 || ok != 4 || n == 0)
sysfatal("bad auth reply: %x %x", reply, ok); return -1; /* not supported */
recv("b", &n); recv("b", &n);
recv("[", realm, n); recv("[", realm, n);
@ -173,24 +175,52 @@ digestauth(char *server, char *user, char *method, char *url)
strlen(qop), qop, strlen(qop)); strlen(qop), qop, strlen(qop));
recv("lb*", &reply, &ok); recv("lb*", &reply, &ok);
if(reply != 0x14 && ok != 4) 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 void
usage(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"); exits("usage");
} }
void void
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
uchar buf[MAX_TRANSMIT_BUFFER];
TLSconn tls;
char *user = "admin";
int reply, ok, n;
fmtinstall('[', encodefmt); fmtinstall('[', encodefmt);
fmtinstall('H', encodefmt); fmtinstall('H', encodefmt);
@ -198,12 +228,18 @@ main(int argc, char *argv[])
case 'u': case 'u':
user = EARGF(usage()); user = EARGF(usage());
break; break;
case 'T':
tls = 0;
break;
case 'R': case 'R':
raw = 0; raw = 0;
break; break;
case 'r': case 'r':
raw = 1; raw = 1;
break; break;
case 'k':
kvm = 1;
break;
default: default:
usage(); usage();
} ARGEND; } ARGEND;
@ -211,6 +247,9 @@ main(int argc, char *argv[])
if(argc != 1) if(argc != 1)
usage(); usage();
if(kvm)
goto Connect;
if(raw < 0) { if(raw < 0) {
char *term = getenv("TERM"); char *term = getenv("TERM");
raw = term && *term; raw = term && *term;
@ -230,18 +269,22 @@ main(int argc, char *argv[])
write(fd, "rawon", 5); write(fd, "rawon", 5);
} }
Reconnect: Connect:
fd = dial(netmkaddr(argv[0], "tcp", "16995"), nil, nil, nil); fd = dial(netmkaddr(argv[0], "tcp", tls ? "16995" : "16994"), nil, nil, nil);
if(fd < 0) if(fd < 0)
sysfatal("dial: %r"); sysfatal("dial: %r");
memset(&tls, 0, sizeof(tls)); if(tls){
fd = tlsClient(fd, &tls); TLSconn conn;
if(fd < 0)
sysfatal("tls client: %r"); memset(&conn, 0, sizeof(conn));
free(tls.cert); fd = tlsClient(fd, &conn);
free(tls.sessionID); if(fd < 0)
memset(&tls, 0, sizeof(tls)); sysfatal("tls: %r");
free(conn.cert);
free(conn.sessionID);
memset(&conn, 0, sizeof(conn));
}
authok = 0; authok = 0;
Binit(&bin, fd, OREAD); Binit(&bin, fd, OREAD);
@ -250,17 +293,52 @@ Reconnect:
Bterm(&bin); Bterm(&bin);
Bterm(&bout); Bterm(&bout);
close(fd); 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); recv("lb*", &reply, &ok);
if(reply != 0x11 || ok != 1) if(reply != 0x11 || ok != 1)
sysfatal("bad session reply: %x %x", reply, ok); sysfatal("bad session reply: %x %x", reply, ok);
digestauth(argv[0], user, "POST", "/RedirectionService"); auth(argv[0], user);
authok = 1; 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, send("l____wwwwww____", 0x20,
MAX_TRANSMIT_BUFFER, MAX_TRANSMIT_BUFFER,
TRANSMIT_BUFFER_TIMEOUT, TRANSMIT_BUFFER_TIMEOUT,
@ -270,7 +348,7 @@ Reconnect:
HEATBEAT_INTERVAL); HEATBEAT_INTERVAL);
recv("lb*", &reply, &ok); recv("lb*", &reply, &ok);
if(reply != 0x21 || ok != 1) if(reply != 0x21 || ok != 1)
sysfatal("bad redirection reply: %x %x", reply, ok); sysfatal("bad sol reply: %x %x", reply, ok);
pid = fork(); pid = fork();
if(pid == 0){ if(pid == 0){
@ -305,5 +383,6 @@ Reconnect:
} }
} }
} }
exits(nil); exits(nil);
} }