ip/sol: add intel AMT serial-over-lan console program
This commit is contained in:
parent
4daf4ffdbe
commit
ca60e03c5b
3 changed files with 324 additions and 0 deletions
46
sys/man/8/sol
Normal file
46
sys/man/8/sol
Normal file
|
@ -0,0 +1,46 @@
|
|||
.TH SOL 8
|
||||
.SH NAME
|
||||
sol - Intel AMT serial-over-lan console
|
||||
.SH SYNOPSIS
|
||||
.B ip/sol
|
||||
[
|
||||
.B -rR
|
||||
] [
|
||||
.B -u
|
||||
.I user
|
||||
]
|
||||
.I host
|
||||
.SH DESCRIPTION
|
||||
This program provides remote access to the
|
||||
serial-over-lan interface of intel AMT
|
||||
enabled machines.
|
||||
.PP
|
||||
The protocol runs over tcp port 16995 and
|
||||
and is protected using TLS.
|
||||
.PP
|
||||
For authentication, a username and password
|
||||
is required. The default username, unless
|
||||
given by the
|
||||
.B -u
|
||||
.I user
|
||||
argument, is "admin".
|
||||
The password will be prompted and kept in
|
||||
factotum, tagged with the servers x509
|
||||
crtificate thumbprint.
|
||||
.PP
|
||||
The
|
||||
.B -r
|
||||
and
|
||||
.B -R
|
||||
flags enable or disable the use of /dev/cons
|
||||
in raw mode instead of just reading and writing
|
||||
standard input and output.
|
||||
By default, raw mode is enabled when the
|
||||
.B $TERM
|
||||
environment variable has been set.
|
||||
.SH SOURCE
|
||||
.B /sys/src/cmd/ip/sol.c
|
||||
.SH "SEE ALSO"
|
||||
.IR ssh (1),
|
||||
.IR consolefs (4),
|
||||
.IR factotum (4)
|
|
@ -27,6 +27,7 @@ TARG = 6in4\
|
|||
torrent\
|
||||
udpecho\
|
||||
socksd\
|
||||
sol\
|
||||
wol\
|
||||
|
||||
DIRS=ftpfs cifsd dhcpd httpd ipconfig ppp snoopy
|
||||
|
|
277
sys/src/cmd/ip/sol.c
Normal file
277
sys/src/cmd/ip/sol.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/* intel amt serial-over-lan console */
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <libsec.h>
|
||||
#include <auth.h>
|
||||
|
||||
enum {
|
||||
MAX_TRANSMIT_BUFFER = 15000,
|
||||
TRANSMIT_BUFFER_TIMEOUT = 100,
|
||||
TRANSMIT_OVERFLOW_TIMEOUT = 0,
|
||||
HOST_SESSION_RX_TIMEOUT = 60000,
|
||||
HOST_FIFO_RX_FLUSH_TIMEOUT = 0,
|
||||
HEATBEAT_INTERVAL = 5000,
|
||||
};
|
||||
|
||||
int pid = 0, raw = -1, fd = -1;
|
||||
char thumbfile[] = "/sys/lib/tls/amt";
|
||||
|
||||
Biobuf bin, bout;
|
||||
jmp_buf reconnect;
|
||||
|
||||
void
|
||||
killpid(void)
|
||||
{
|
||||
postnote(PNPROC, pid, "kill");
|
||||
}
|
||||
|
||||
void
|
||||
eof(void)
|
||||
{
|
||||
if(pid == 0) sysfatal("eof: %r");
|
||||
killpid();
|
||||
pid = 0;
|
||||
longjmp(reconnect, 1);
|
||||
}
|
||||
|
||||
void
|
||||
recv(char *fmt, ...)
|
||||
{
|
||||
uchar buf[4];
|
||||
va_list a;
|
||||
void *s;
|
||||
int n;
|
||||
|
||||
va_start(a, fmt);
|
||||
for(;;){
|
||||
switch(*fmt++){
|
||||
case '\0':
|
||||
va_end(a);
|
||||
return;
|
||||
case '*':
|
||||
Bflush(&bin);
|
||||
break;
|
||||
case '_':
|
||||
if(Bread(&bin, buf, 1) != 1) eof();
|
||||
break;
|
||||
case 'b':
|
||||
if(Bread(&bin, buf, 1) != 1) eof();
|
||||
*va_arg(a, int*) = (uint)buf[0];
|
||||
break;
|
||||
case 'w':
|
||||
if(Bread(&bin, buf, 2) != 2) eof();
|
||||
*va_arg(a, int*) = (uint)buf[0] | (uint)buf[1] << 8;
|
||||
break;
|
||||
case 'l':
|
||||
if(Bread(&bin, buf, 4) != 4) eof();
|
||||
*va_arg(a, int*) = (uint)buf[0] | (uint)buf[1] << 8 | (uint)buf[2] << 16 | (uint)buf[3] << 24;
|
||||
break;
|
||||
case '[':
|
||||
s = va_arg(a, void*);
|
||||
n = va_arg(a, int);
|
||||
if(n && Bread(&bin, s, n) != n) eof();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
send(char *fmt, ...)
|
||||
{
|
||||
uchar buf[4];
|
||||
va_list a;
|
||||
void *s;
|
||||
int n;
|
||||
|
||||
va_start(a, fmt);
|
||||
for(;;){
|
||||
switch(*fmt++){
|
||||
case '\0':
|
||||
Bflush(&bout);
|
||||
va_end(a);
|
||||
return;
|
||||
case '_':
|
||||
buf[0] = 0;
|
||||
Bwrite(&bout, buf, 1);
|
||||
break;
|
||||
case 'b':
|
||||
buf[0] = va_arg(a, int);
|
||||
Bwrite(&bout, buf, 1);
|
||||
break;
|
||||
case 'w':
|
||||
n = va_arg(a, int);
|
||||
buf[0] = n;
|
||||
buf[1] = n >> 8;
|
||||
Bwrite(&bout, buf, 2);
|
||||
break;
|
||||
case 'l':
|
||||
n = va_arg(a, int);
|
||||
buf[0] = n;
|
||||
buf[1] = n >> 8;
|
||||
buf[2] = n >> 16;
|
||||
buf[3] = n >> 24;
|
||||
Bwrite(&bout, buf, 4);
|
||||
break;
|
||||
case '[':
|
||||
s = va_arg(a, char*);
|
||||
n = va_arg(a, int);
|
||||
if(n) Bwrite(&bout, s, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: %s [-Rr] [-u user] host\n", argv0);
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
uchar thumb[SHA2_256dlen], buf[MAX_TRANSMIT_BUFFER];
|
||||
TLSconn tls;
|
||||
char *user = "admin";
|
||||
UserPasswd *up = nil;
|
||||
int reply, ok, n;
|
||||
|
||||
fmtinstall('[', encodefmt);
|
||||
fmtinstall('H', encodefmt);
|
||||
|
||||
ARGBEGIN {
|
||||
case 'u':
|
||||
user = EARGF(usage());
|
||||
break;
|
||||
case 'R':
|
||||
raw = 0;
|
||||
break;
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
} ARGEND;
|
||||
|
||||
if(argc != 1)
|
||||
usage();
|
||||
|
||||
if(raw < 0) {
|
||||
char *term = getenv("TERM");
|
||||
raw = term && *term;
|
||||
free(term);
|
||||
}
|
||||
|
||||
if(raw){
|
||||
close(0);
|
||||
if(open("/dev/cons", OREAD) != 0)
|
||||
sysfatal("open: %r");
|
||||
close(1);
|
||||
if(open("/dev/cons", OWRITE) != 1)
|
||||
sysfatal("open: %r");
|
||||
dup(1, 2);
|
||||
fd = open("/dev/consctl", OWRITE);
|
||||
if(fd >= 0)
|
||||
write(fd, "rawon", 5);
|
||||
}
|
||||
|
||||
Reconnect:
|
||||
fd = dial(netmkaddr(argv[0], "tcp", "16995"), 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");
|
||||
sha2_256(tls.cert, tls.certlen, buf, nil);
|
||||
free(tls.cert);
|
||||
free(tls.sessionID);
|
||||
memset(&tls, 0, sizeof(tls));
|
||||
|
||||
if(up == nil){
|
||||
memmove(thumb, buf, sizeof(thumb));
|
||||
up = auth_getuserpasswd(auth_getkey,
|
||||
"proto=pass service=sol user=%q server=%q thumb='%.*['",
|
||||
user, argv[0], sizeof(thumb), thumb);
|
||||
if(up == nil)
|
||||
sysfatal("auth_getuserpasswd: %r");
|
||||
close(fd);
|
||||
goto Reconnect;
|
||||
}
|
||||
|
||||
if(memcmp(buf, thumb, sizeof(thumb)) != 0)
|
||||
sysfatal("certificate thumb changed: %.*[, expected %.*[",
|
||||
sizeof(thumb), buf, sizeof(thumb), thumb);
|
||||
|
||||
Binit(&bin, fd, OREAD);
|
||||
Binit(&bout, fd, OWRITE);
|
||||
if(setjmp(reconnect)){
|
||||
Bterm(&bin);
|
||||
Bterm(&bout);
|
||||
close(fd);
|
||||
goto Reconnect;
|
||||
}
|
||||
|
||||
send("l[", 0x10, "SOL ", 4);
|
||||
recv("lb*", &reply, &ok);
|
||||
if(reply != 0x11 || ok != 1)
|
||||
sysfatal("bad session reply: %x %x", reply, ok);
|
||||
|
||||
send("lblb[b[", 0x13, 1,
|
||||
strlen(up->user)+1+strlen(up->passwd)+1,
|
||||
strlen(up->user), up->user, strlen(up->user),
|
||||
strlen(up->passwd), up->passwd, strlen(up->passwd));
|
||||
recv("lb*", &reply, &ok);
|
||||
if(reply != 0x14 || ok != 1)
|
||||
sysfatal("bad auth reply: %x %x", reply, ok);
|
||||
|
||||
send("l____wwwwww____", 0x20,
|
||||
MAX_TRANSMIT_BUFFER,
|
||||
TRANSMIT_BUFFER_TIMEOUT,
|
||||
TRANSMIT_OVERFLOW_TIMEOUT,
|
||||
HOST_SESSION_RX_TIMEOUT,
|
||||
HOST_FIFO_RX_FLUSH_TIMEOUT,
|
||||
HEATBEAT_INTERVAL);
|
||||
recv("lb*", &reply, &ok);
|
||||
if(reply != 0x21 || ok != 1)
|
||||
sysfatal("bad redirection reply: %x %x", reply, ok);
|
||||
|
||||
pid = fork();
|
||||
if(pid == 0){
|
||||
pid = getppid();
|
||||
atexit(killpid);
|
||||
for(;;){
|
||||
n = read(0, buf, sizeof(buf));
|
||||
if(n < 0)
|
||||
sysfatal("read: %r");
|
||||
if(n == 0)
|
||||
break;
|
||||
send("l____w[", 0x28, n, buf, n);
|
||||
}
|
||||
} else {
|
||||
atexit(killpid);
|
||||
for(;;){
|
||||
recv("l", &reply);
|
||||
switch(reply){
|
||||
default:
|
||||
sysfatal("unknown reply %x\n", reply);
|
||||
break;
|
||||
case 0x2a:
|
||||
recv("____w", &n);
|
||||
recv("[", buf, n);
|
||||
if(write(1, buf, n) != n)
|
||||
break;
|
||||
break;
|
||||
case 0x24:
|
||||
case 0x2b:
|
||||
recv("*");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
exits(nil);
|
||||
}
|
Loading…
Reference in a new issue