/* 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,}; 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; voidkillpid(void){ if(pid != 0){ postnote(PNPROC, pid, "kill"); pid = 0; }} voideof(void){ if(!authok) sysfatal("eof: %r"); killpid(); longjmp(reconnect, 1);} voidrecv(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; } }} voidsend(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; } }} intdigestauth(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; send("lblb[__b[____", 0x13, 4, 1+strlen(user) + 2 + 1+strlen(url) + 4, strlen(user), user, strlen(user), strlen(url), url, strlen(url)); recv("lbl", &reply, &ok, &n); if(reply != 0x114 || ok != 4 || n == 0) return -1; /* not supported */ recv("b", &n); recv("[", realm, n); realm[n] = '\0'; recv("b", &n); recv("[", nonce, n); nonce[n] = '\0'; recv("b", &n); recv("[", qop, n); qop[n] = '\0'; genrandom((uchar*)resp, 32); snprint(cnonce, sizeof(cnonce), "%.32H", resp); snprint(nc, sizeof(nc), "%8.8ud", ++counter); n = snprint(chal, sizeof(chal), "%s:%s:%s:%s %s %s", nonce, nc, cnonce, qop, method, url); n = auth_respond(chal, n, ouser, sizeof(ouser), resp, sizeof(resp), auth_getkey, "proto=httpdigest role=client server=%q realm=%q user=%q", server, realm, user); if(n < 0) sysfatal("auth_respond: %r"); send("lblb[b[b[b[b[b[b[b[", 0x13, 4, 1+strlen(ouser)+1+strlen(realm)+1+strlen(nonce)+1+strlen(url)+ 1+strlen(cnonce)+1+strlen(nc)+1+n+1+strlen(qop), strlen(ouser), ouser, strlen(ouser), strlen(realm), realm, strlen(realm), strlen(nonce), nonce, strlen(nonce), strlen(url), url, strlen(url), strlen(cnonce), cnonce, strlen(cnonce), strlen(nc), nc, strlen(nc), n, resp, n, strlen(qop), qop, strlen(qop)); /* can get timeout/tls error here, so enable restart once we have the key */ authok = 1; recv("lb*", &reply, &ok); if(reply != 0x14 && ok != 4){ authok = 0; sysfatal("bad digest auth reply: %x %x", reply, ok); } return 0;} voidplainauth(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);} voidauth(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);} voidusage(void){ fprint(2, "usage: %s [-TRrk] [-u user] host\n", argv0); exits("usage");} voidmain(int argc, char *argv[]){ fmtinstall('[', encodefmt); fmtinstall('H', encodefmt); ARGBEGIN { case 'u': user = EARGF(usage()); break; case 'T': tls = 0; break; case 'R': raw = 0; break; case 'r': raw = 1; break; case 'k': kvm = 1; break; default: usage(); } ARGEND; if(argc != 1) usage(); if(kvm) goto Connect; 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); } Connect: fd = dial(netmkaddr(argv[0], "tcp", tls ? "16995" : "16994"), nil, nil, nil); if(fd < 0) sysfatal("dial: %r"); 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); if(setjmp(reconnect)){ Bterm(&bin); Bterm(&bout); close(fd); goto Connect; } 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); 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, 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 sol 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", 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);}
/* 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,
};
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;
void
killpid(void)
{
if(pid != 0){
postnote(PNPROC, pid, "kill");
pid = 0;
}
}
void
eof(void)
{
if(!authok) sysfatal("eof: %r");
killpid();
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;
}
}
}
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;
send("lblb[__b[____", 0x13, 4,
1+strlen(user) + 2 + 1+strlen(url) + 4,
strlen(user), user, strlen(user),
strlen(url), url, strlen(url));
recv("lbl", &reply, &ok, &n);
if(reply != 0x114 || ok != 4 || n == 0)
return -1; /* not supported */
recv("b", &n);
recv("[", realm, n);
realm[n] = '\0';
recv("b", &n);
recv("[", nonce, n);
nonce[n] = '\0';
recv("b", &n);
recv("[", qop, n);
qop[n] = '\0';
genrandom((uchar*)resp, 32);
snprint(cnonce, sizeof(cnonce), "%.32H", resp);
snprint(nc, sizeof(nc), "%8.8ud", ++counter);
n = snprint(chal, sizeof(chal), "%s:%s:%s:%s %s %s", nonce, nc, cnonce, qop, method, url);
n = auth_respond(chal, n, ouser, sizeof(ouser), resp, sizeof(resp), auth_getkey,
"proto=httpdigest role=client server=%q realm=%q user=%q", server, realm, user);
if(n < 0)
sysfatal("auth_respond: %r");
send("lblb[b[b[b[b[b[b[b[", 0x13, 4,
1+strlen(ouser)+1+strlen(realm)+1+strlen(nonce)+1+strlen(url)+
1+strlen(cnonce)+1+strlen(nc)+1+n+1+strlen(qop),
strlen(ouser), ouser, strlen(ouser),
strlen(realm), realm, strlen(realm),
strlen(nonce), nonce, strlen(nonce),
strlen(url), url, strlen(url),
strlen(cnonce), cnonce, strlen(cnonce),
strlen(nc), nc, strlen(nc),
n, resp, n,
strlen(qop), qop, strlen(qop));
/* can get timeout/tls error here, so enable restart once we have the key */
authok = 1;
recv("lb*", &reply, &ok);
if(reply != 0x14 && ok != 4){
authok = 0;
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 [-TRrk] [-u user] host\n", argv0);
exits("usage");
}
void
main(int argc, char *argv[])
{
fmtinstall('[', encodefmt);
fmtinstall('H', encodefmt);
ARGBEGIN {
case 'u':
user = EARGF(usage());
break;
case 'T':
tls = 0;
break;
case 'R':
raw = 0;
break;
case 'r':
raw = 1;
break;
case 'k':
kvm = 1;
break;
default:
usage();
} ARGEND;
if(argc != 1)
usage();
if(kvm)
goto Connect;
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);
}
Connect:
fd = dial(netmkaddr(argv[0], "tcp", tls ? "16995" : "16994"), nil, nil, nil);
if(fd < 0)
sysfatal("dial: %r");
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);
if(setjmp(reconnect)){
Bterm(&bin);
Bterm(&bout);
close(fd);
goto Connect;
}
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);
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,
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 sol 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", 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);
}