Commit Diff


commit - be8b315d1522fa1c109a49435c1638bafd838b91
commit + 4180d05ba41196e0633252de26750bb19f3a6da8
blob - /dev/null
blob + ea9e0c9ef816d788a3877593d1558119294c9a9f (mode 644)
--- /dev/null
+++ src/libauthsrv/_asgetticket.c
@@ -0,0 +1,16 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+static char *pbmsg = "AS protocol botch";
+
+int
+_asgetticket(int fd, char *trbuf, char *tbuf)
+{
+	if(write(fd, trbuf, TICKREQLEN) < 0){
+		close(fd);
+		werrstr(pbmsg);
+		return -1;
+	}
+	return _asrdresp(fd, tbuf, 2*TICKETLEN);
+}
blob - /dev/null
blob + 8a7daf8cceb1a3b9a71b44af25de340a55f0432b (mode 644)
--- /dev/null
+++ src/libauthsrv/_asrdresp.c
@@ -0,0 +1,56 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+static char *pbmsg = "AS protocol botch";
+
+int
+_asrdresp(int fd, char *buf, int len)
+{
+	int n;
+	char error[64];
+
+	if(read(fd, buf, 1) != 1){
+		werrstr(pbmsg);
+		return -1;
+	}
+
+	n = len;
+	switch(buf[0]){
+	case AuthOK:
+		if(readn(fd, buf, len) != len){
+			werrstr(pbmsg);
+			return -1;
+		}
+		break;
+	case AuthErr:
+		if(readn(fd, error, sizeof error) != sizeof error){
+			werrstr(pbmsg);
+			return -1;
+		}
+		error[sizeof error-1] = '\0';
+		werrstr("remote: %s", error);
+		return -1;
+	case AuthOKvar:
+		if(readn(fd, error, 5) != 5){
+			werrstr(pbmsg);
+			return -1;
+		}
+		error[5] = 0;
+		n = atoi(error);
+		if(n <= 0 || n > len){
+			werrstr(pbmsg);
+			return -1;
+		}
+		memset(buf, 0, len);
+		if(readn(fd, buf, n) != n){
+			werrstr(pbmsg);
+			return -1;
+		}
+		break;
+	default:
+		werrstr(pbmsg);
+		return -1;
+	}
+	return n;
+}
blob - /dev/null
blob + 5e608058582e8f6e28801f1ced753fab035a9fa9 (mode 644)
--- /dev/null
+++ src/libauthsrv/authdial.c
@@ -0,0 +1,31 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+#include <bio.h>
+#include <ndb.h>
+
+int
+authdial(char *netroot, char *dom)
+{
+	char *p;
+	int rv;
+	
+	if(dom != nil){
+		/* look up an auth server in an authentication domain */
+		p = csgetvalue(netroot, "authdom", dom, "auth", nil);
+
+		/* if that didn't work, just try the IP domain */
+		if(p == nil)
+			p = csgetvalue(netroot, "dom", dom, "auth", nil);
+		if(p == nil){
+			werrstr("no auth server found for %s", dom);
+			return -1;
+		}
+		rv = dial(netmkaddr(p, netroot, "ticket"), 0, 0, 0);
+		free(p);
+		return rv;
+	} else {
+		/* look for one relative to my machine */
+		return dial(netmkaddr("$auth", netroot, "ticket"), 0, 0, 0);
+	}
+}
blob - /dev/null
blob + 2799cbf562e8941b6d0ddc0dd818e0db096b4cee (mode 644)
--- /dev/null
+++ src/libauthsrv/convA2M.c
@@ -0,0 +1,25 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		*p++ = f->x
+#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
+#define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(p, f->x, n); p += n
+
+int
+convA2M(Authenticator *f, char *ap, char *key)
+{
+	int n;
+	uchar *p;
+
+	p = (uchar*)ap;
+	CHAR(num);
+	STRING(chal, CHALLEN);
+	LONG(id);
+	n = p - (uchar*)ap;
+	if(key)
+		encrypt(key, ap, n);
+	return n;
+}
blob - /dev/null
blob + 3d58f9b593748e9ad36dae74c0aedcbb2ac85c23 (mode 644)
--- /dev/null
+++ src/libauthsrv/convM2A.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		f->x = *p++
+#define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
+#define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(f->x, p, n); p += n
+
+void
+convM2A(char *ap, Authenticator *f, char *key)
+{
+	uchar *p;
+
+	if(key)
+		decrypt(key, ap, AUTHENTLEN);
+	p = (uchar*)ap;
+	CHAR(num);
+	STRING(chal, CHALLEN);
+	LONG(id);
+	USED(p);
+}
blob - /dev/null
blob + 21df5b508d4d406b4ac56ac7b275384e1e88ea73 (mode 644)
--- /dev/null
+++ src/libauthsrv/convM2PR.c
@@ -0,0 +1,28 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		f->x = *p++
+#define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
+#define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(f->x, p, n); p += n
+
+void
+convM2PR(char *ap, Passwordreq *f, char *key)
+{
+	uchar *p;
+
+	p = (uchar*)ap;
+	if(key)
+		decrypt(key, ap, PASSREQLEN);
+	CHAR(num);
+	STRING(old, ANAMELEN);
+	f->old[ANAMELEN-1] = 0;
+	STRING(new, ANAMELEN);
+	f->new[ANAMELEN-1] = 0;
+	CHAR(changesecret);
+	STRING(secret, SECRETLEN);
+	f->secret[SECRETLEN-1] = 0;
+	USED(p);
+}
blob - /dev/null
blob + 372825a872ac39dc29500518363db2bc11bf1e6b (mode 644)
--- /dev/null
+++ src/libauthsrv/convM2T.c
@@ -0,0 +1,28 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		f->x = *p++
+#define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
+#define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(f->x, p, n); p += n
+
+void
+convM2T(char *ap, Ticket *f, char *key)
+{
+	uchar *p;
+
+	if(key)
+		decrypt(key, ap, TICKETLEN);
+	p = (uchar*)ap;
+	CHAR(num);
+	STRING(chal, CHALLEN);
+	STRING(cuid, ANAMELEN);
+	f->cuid[ANAMELEN-1] = 0;
+	STRING(suid, ANAMELEN);
+	f->suid[ANAMELEN-1] = 0;
+	STRING(key, DESKEYLEN);
+	USED(p);
+}
+
blob - /dev/null
blob + ffad75c771e757f999ebe8773e513a3893b0a0cf (mode 644)
--- /dev/null
+++ src/libauthsrv/convM2TR.c
@@ -0,0 +1,28 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		f->x = *p++
+#define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
+#define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(f->x, p, n); p += n
+
+void
+convM2TR(char *ap, Ticketreq *f)
+{
+	uchar *p;
+
+	p = (uchar*)ap;
+	CHAR(type);
+	STRING(authid, ANAMELEN);
+	f->authid[ANAMELEN-1] = 0;
+	STRING(authdom, DOMLEN);
+	f->authdom[DOMLEN-1] = 0;
+	STRING(chal, CHALLEN);
+	STRING(hostid, ANAMELEN);
+	f->hostid[ANAMELEN-1] = 0;
+	STRING(uid, ANAMELEN);
+	f->uid[ANAMELEN-1] = 0;
+	USED(p);
+}
blob - /dev/null
blob + 8b2422f1b5e2064e6655b777972a2547f9bdc2a6 (mode 644)
--- /dev/null
+++ src/libauthsrv/convPR2M.c
@@ -0,0 +1,28 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		*p++ = f->x
+#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
+#define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(p, f->x, n); p += n
+
+int
+convPR2M(Passwordreq *f, char *ap, char *key)
+{
+	int n;
+	uchar *p;
+
+	p = (uchar*)ap;
+	CHAR(num);
+	STRING(old, ANAMELEN);
+	STRING(new, ANAMELEN);
+	CHAR(changesecret);
+	STRING(secret, SECRETLEN);
+	n = p - (uchar*)ap;
+	if(key)
+		encrypt(key, ap, n);
+	return n;
+}
+
blob - /dev/null
blob + 810ba5c6795372b540a025e42db4d09debf62f01 (mode 644)
--- /dev/null
+++ src/libauthsrv/convT2M.c
@@ -0,0 +1,27 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		*p++ = f->x
+#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
+#define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(p, f->x, n); p += n
+
+int
+convT2M(Ticket *f, char *ap, char *key)
+{
+	int n;
+	uchar *p;
+
+	p = (uchar*)ap;
+	CHAR(num);
+	STRING(chal, CHALLEN);
+	STRING(cuid, ANAMELEN);
+	STRING(suid, ANAMELEN);
+	STRING(key, DESKEYLEN);
+	n = p - (uchar*)ap;
+	if(key)
+		encrypt(key, ap, n);
+	return n;
+}
blob - /dev/null
blob + 3a7610a713808d3e0c72a95e4d6519a3564fb1a3 (mode 644)
--- /dev/null
+++ src/libauthsrv/convTR2M.c
@@ -0,0 +1,27 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+#define	CHAR(x)		*p++ = f->x
+#define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
+#define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
+#define	LONG(x)		VLONG(f->x)
+#define	STRING(x,n)	memmove(p, f->x, n); p += n
+
+int
+convTR2M(Ticketreq *f, char *ap)
+{
+	int n;
+	uchar *p;
+
+	p = (uchar*)ap;
+	CHAR(type);
+	STRING(authid, 28);	/* BUG */
+	STRING(authdom, DOMLEN);
+	STRING(chal, CHALLEN);
+	STRING(hostid, 28);	/* BUG */
+	STRING(uid, 28);	/* BUG */
+	n = p - (uchar*)ap;
+	return n;
+}
+
blob - /dev/null
blob + a69cc942d7d92ca0f05592e66639b03956e446c2 (mode 644)
--- /dev/null
+++ src/libauthsrv/mkfile
@@ -0,0 +1,25 @@
+PLAN9=../..
+<$PLAN9/src/mkhdr
+
+LIB=libauthsrv.a
+OFILES=\
+	_asgetticket.$O\
+	_asrdresp.$O\
+#	authdial.$O\
+	convA2M.$O\
+	convM2A.$O\
+	convM2PR.$O\
+	convM2T.$O\
+	convM2TR.$O\
+	convPR2M.$O\
+	convT2M.$O\
+	convTR2M.$O\
+	nvcsum.$O\
+	opasstokey.$O\
+	passtokey.$O\
+	readnvram.$O\
+
+HFILES=\
+	$PLAN9/include/authsrv.h\
+
+<$PLAN9/src/mksyslib
blob - /dev/null
blob + 306d7f7edc6f0975f5468ea0722be5fd3ff5bc95 (mode 644)
--- /dev/null
+++ src/libauthsrv/nvcsum.c
@@ -0,0 +1,16 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+
+uchar
+nvcsum(void *vmem, int n)
+{
+	uchar *mem, sum;
+	int i;
+
+	sum = 9;
+	mem = vmem;
+	for(i = 0; i < n; i++)
+		sum += mem[i];
+	return sum;
+}
blob - /dev/null
blob + d263d4b76985d9cd1b983a690080621162ff8e69 (mode 644)
--- /dev/null
+++ src/libauthsrv/opasstokey.c
@@ -0,0 +1,29 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+int
+opasstokey(char *key, char *p)
+{
+	uchar t[10];
+	int c, n;
+
+	n = strlen(p);
+	memset(t, ' ', sizeof t);
+	if(n < 5)
+		return 0;
+	if(n > 10)
+		n = 10;
+	strncpy((char*)t, p, n);
+	if(n >= 9){
+		c = p[8] & 0xf;
+		if(n == 10)
+			c += p[9] << 4;
+		for(n = 0; n < 8; n++)
+			if(c & (1 << n))
+				t[n] -= ' ';
+	}
+	for(n = 0; n < 7; n++)
+		key[n] = (t[n] >> n) + (t[n+1] << (8 - (n+1)));
+	return 1;
+}
blob - /dev/null
blob + 8e267ce4cf8e7df77c07ac6db1cce37aa9e3281c (mode 644)
--- /dev/null
+++ src/libauthsrv/passtokey.c
@@ -0,0 +1,33 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+int
+passtokey(char *key, char *p)
+{
+	uchar buf[ANAMELEN], *t;
+	int i, n;
+
+	n = strlen(p);
+	if(n >= ANAMELEN)
+		n = ANAMELEN-1;
+	memset(buf, ' ', 8);
+	t = buf;
+	strncpy((char*)t, p, n);
+	t[n] = 0;
+	memset(key, 0, DESKEYLEN);
+	for(;;){
+		for(i = 0; i < DESKEYLEN; i++)
+			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
+		if(n <= 8)
+			return 1;
+		n -= 8;
+		t += 8;
+		if(n < 8){
+			t -= 8 - n;
+			n = 8;
+		}
+		encrypt(key, t, 8);
+	}
+	return 1;	/* not reached */
+}
blob - /dev/null
blob + e48a576156a71333952c0802a64b795453ce1504 (mode 644)
--- /dev/null
+++ src/libauthsrv/readnvram.c
@@ -0,0 +1,370 @@
+#include <u.h>
+#include <libc.h>
+#include <authsrv.h>
+
+static long	finddosfile(int, char*);
+
+static int
+check(void *x, int len, uchar sum, char *msg)
+{
+	if(nvcsum(x, len) == sum)
+		return 0;
+	memset(x, 0, len);
+	fprint(2, "%s\n", msg);
+	return 1;
+}
+
+/*
+ *  get key info out of nvram.  since there isn't room in the PC's nvram use
+ *  a disk partition there.
+ */
+static struct {
+	char *cputype;
+	char *file;
+	int off;
+	int len;
+} nvtab[] = {
+	"sparc", "#r/nvram", 1024+850, sizeof(Nvrsafe),
+	"pc", "#S/sdC0/nvram", 0, sizeof(Nvrsafe),
+	"pc", "#S/sdC0/9fat", -1, sizeof(Nvrsafe),
+	"pc", "#S/sdC1/nvram", 0, sizeof(Nvrsafe),
+	"pc", "#S/sdC1/9fat", -1, sizeof(Nvrsafe),
+	"pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe),
+	"pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe),
+	"pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe),
+	"pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe),
+	"pc", "#f/fd0disk", -1, 512,	/* 512: #f requires whole sector reads */
+	"pc", "#f/fd1disk", -1, 512,
+	"mips", "#r/nvram", 1024+900, sizeof(Nvrsafe),
+	"power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe),
+	"power", "#r/nvram", 4352, sizeof(Nvrsafe),	/* OK for MTX-604e */
+	"debug", "/tmp/nvram", 0, sizeof(Nvrsafe),
+};
+
+static char*
+readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
+{
+	int fdin, fdout, ctl, n, m;
+	char line[10];
+
+	fdin = open("/dev/cons", OREAD);
+	if(fdin < 0)
+		fdin = 0;
+	fdout = open("/dev/cons", OWRITE);
+	if(fdout < 0)
+		fdout = 1;
+	if(def != nil)
+		fprint(fdout, "%s[%s]: ", prompt, def);
+	else
+		fprint(fdout, "%s: ", prompt);
+	if(raw){
+		ctl = open("/dev/consctl", OWRITE);
+		if(ctl >= 0)
+			write(ctl, "rawon", 5);
+	} else
+		ctl = -1;
+
+	m = 0;
+	for(;;){
+		n = read(fdin, line, 1);
+		if(n == 0){
+			close(ctl);
+			werrstr("readcons: EOF");
+			return nil;
+		}
+		if(n < 0){
+			close(ctl);
+			werrstr("can't read cons");
+			return nil;
+		}
+		if(line[0] == 0x7f)
+			exits(0);
+		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
+			if(raw){
+				write(ctl, "rawoff", 6);
+				write(fdout, "\n", 1);
+				close(ctl);
+			}
+			buf[m] = '\0';
+			if(buf[0]=='\0' && def)
+				strcpy(buf, def);
+			return buf;
+		}
+		if(line[0] == '\b'){
+			if(m > 0)
+				m--;
+		}else if(line[0] == 0x15){	/* ^U: line kill */
+			m = 0;
+			if(def != nil)
+				fprint(fdout, "%s[%s]: ", prompt, def);
+			else
+				fprint(fdout, "%s: ", prompt);
+		}else{
+			if(m >= nbuf-1){
+				fprint(fdout, "line too long\n");
+				m = 0;
+				if(def != nil)
+					fprint(fdout, "%s[%s]: ", prompt, def);
+				else
+					fprint(fdout, "%s: ", prompt);
+			}else
+				buf[m++] = line[0];
+		}
+	}
+	return buf;	/* how does this happen */
+}
+
+
+/*
+ *  get key info out of nvram.  since there isn't room in the PC's nvram use
+ *  a disk partition there.
+ */
+int
+readnvram(Nvrsafe *safep, int flag)
+{
+	char buf[1024], in[128], *cputype, *nvrfile, *nvrlen, *nvroff, *v[2];
+	int fd, err, i, safeoff, safelen;
+	Nvrsafe *safe;
+
+	err = 0;
+	memset(safep, 0, sizeof(*safep));
+
+	nvrfile = getenv("nvram");
+	cputype = getenv("cputype");
+	if(cputype == nil)
+		cputype = "mips";
+	if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0)
+		cputype = "pc";
+
+	safe = (Nvrsafe*)buf;
+
+	fd = -1;
+	safeoff = -1;
+	safelen = -1;
+	if(nvrfile != nil){
+		/* accept device and device!file */
+		i = gettokens(nvrfile, v, nelem(v), "!");
+		fd = open(v[0], ORDWR);
+		safelen = sizeof(Nvrsafe);
+		if(strstr(v[0], "/9fat") == nil)
+			safeoff = 0;
+		nvrlen = getenv("nvrlen");
+		if(nvrlen != nil)
+			safelen = atoi(nvrlen);
+		nvroff = getenv("nvroff");
+		if(nvroff != nil){
+			if(strcmp(nvroff, "dos") == 0)
+				safeoff = -1;
+			else
+				safeoff = atoi(nvroff);
+		}
+		if(safeoff < 0 && fd >= 0){
+			safelen = 512;
+			safeoff = finddosfile(fd, i == 2 ? v[1] : "plan9.nvr");
+			if(safeoff < 0){
+				close(fd);
+				fd = -1;
+			}
+		}
+		free(nvrfile);
+		if(nvrlen != nil)
+			free(nvrlen);
+		if(nvroff != nil)
+			free(nvroff);
+	}else{
+		for(i=0; i<nelem(nvtab); i++){
+			if(strcmp(cputype, nvtab[i].cputype) != 0)
+				continue;
+			if((fd = open(nvtab[i].file, ORDWR)) < 0)
+				continue;
+			safeoff = nvtab[i].off;
+			safelen = nvtab[i].len;
+			if(safeoff == -1){
+				safeoff = finddosfile(fd, "plan9.nvr");
+				if(safeoff < 0){
+					close(fd);
+					fd = -1;
+					continue;
+				}
+			}
+			break;
+		}
+	}
+
+	if(fd < 0
+	|| seek(fd, safeoff, 0) < 0
+	|| read(fd, buf, safelen) != safelen){
+		err = 1;
+		if(flag&(NVwrite|NVwriteonerr))
+			fprint(2, "can't read nvram: %r\n");
+		memset(safep, 0, sizeof(*safep));
+		safe = safep;
+	}else{
+		*safep = *safe;
+		safe = safep;
+
+		err |= check(safe->machkey, DESKEYLEN, safe->machsum, "bad nvram key");
+//		err |= check(safe->config, CONFIGLEN, safe->configsum, "bad secstore key");
+		err |= check(safe->authid, ANAMELEN, safe->authidsum, "bad authentication id");
+		err |= check(safe->authdom, DOMLEN, safe->authdomsum, "bad authentication domain");
+	}
+
+	if((flag&NVwrite) || (err && (flag&NVwriteonerr))){
+		readcons("authid", nil, 0, safe->authid, sizeof(safe->authid));
+		readcons("authdom", nil, 0, safe->authdom, sizeof(safe->authdom));
+		readcons("secstore key", nil, 1, safe->config, sizeof(safe->config));
+		for(;;){
+			if(readcons("password", nil, 1, in, sizeof in) == nil)
+				goto Out;
+			if(passtokey(safe->machkey, in))
+				break;
+		}
+		safe->machsum = nvcsum(safe->machkey, DESKEYLEN);
+		safe->configsum = nvcsum(safe->config, CONFIGLEN);
+		safe->authidsum = nvcsum(safe->authid, sizeof(safe->authid));
+		safe->authdomsum = nvcsum(safe->authdom, sizeof(safe->authdom));
+		*(Nvrsafe*)buf = *safe;
+		if(seek(fd, safeoff, 0) < 0
+		|| write(fd, buf, safelen) != safelen){
+			fprint(2, "can't write key to nvram: %r\n");
+			err = 1;
+		}else
+			err = 0;
+	}
+Out:
+	close(fd);
+	return err ? -1 : 0;
+}
+
+typedef struct Dosboot	Dosboot;
+struct Dosboot{
+	uchar	magic[3];	/* really an xx86 JMP instruction */
+	uchar	version[8];
+	uchar	sectsize[2];
+	uchar	clustsize;
+	uchar	nresrv[2];
+	uchar	nfats;
+	uchar	rootsize[2];
+	uchar	volsize[2];
+	uchar	mediadesc;
+	uchar	fatsize[2];
+	uchar	trksize[2];
+	uchar	nheads[2];
+	uchar	nhidden[4];
+	uchar	bigvolsize[4];
+	uchar	driveno;
+	uchar	reserved0;
+	uchar	bootsig;
+	uchar	volid[4];
+	uchar	label[11];
+	uchar	type[8];
+};
+#define	GETSHORT(p) (((p)[1]<<8) | (p)[0])
+#define	GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p)))
+
+typedef struct Dosdir	Dosdir;
+struct Dosdir
+{
+	char	name[8];
+	char	ext[3];
+	uchar	attr;
+	uchar	reserved[10];
+	uchar	time[2];
+	uchar	date[2];
+	uchar	start[2];
+	uchar	length[4];
+};
+
+static char*
+dosparse(char *from, char *to, int len)
+{
+	char c;
+
+	memset(to, ' ', len);
+	if(from == 0)
+		return 0;
+	while(len-- > 0){
+		c = *from++;
+		if(c == '.')
+			return from;
+		if(c == 0)
+			break;
+		if(c >= 'a' && c <= 'z')
+			*to++ = c + 'A' - 'a';
+		else
+			*to++ = c;
+	}
+	return 0;
+}
+
+/*
+ *  return offset of first file block
+ *
+ *  This is a very simplistic dos file system.  It only
+ *  works on floppies, only looks in the root, and only
+ *  returns a pointer to the first block of a file.
+ *
+ *  This exists for cpu servers that have no hard disk
+ *  or nvram to store the key on.
+ *
+ *  Please don't make this any smarter: it stays resident
+ *  and I'ld prefer not to waste the space on something that
+ *  runs only at boottime -- presotto.
+ */
+static long
+finddosfile(int fd, char *file)
+{
+	uchar secbuf[512];
+	char name[8];
+	char ext[3];
+	Dosboot	*b;
+	Dosdir *root, *dp;
+	int nroot, sectsize, rootoff, rootsects, n;
+
+	/* dos'ize file name */
+	file = dosparse(file, name, 8);
+	dosparse(file, ext, 3);
+
+	/* read boot block, check for sanity */
+	b = (Dosboot*)secbuf;
+	if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf))
+		return -1;
+	if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90)
+		return -1;
+	sectsize = GETSHORT(b->sectsize);
+	if(sectsize != 512)
+		return -1;
+	rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize;
+	if(seek(fd, rootoff, 0) < 0)
+		return -1;
+	nroot = GETSHORT(b->rootsize);
+	rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize;
+	if(rootsects <= 0 || rootsects > 64)
+		return -1;
+
+	/* 
+	 *  read root. it is contiguous to make stuff like
+	 *  this easier
+	 */
+	root = malloc(rootsects*sectsize);
+	if(read(fd, root, rootsects*sectsize) != rootsects*sectsize)
+		return -1;
+	n = -1;
+	for(dp = root; dp < &root[nroot]; dp++)
+		if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){
+			n = GETSHORT(dp->start);
+			break;
+		}
+	free(root);
+
+	if(n < 0)
+		return -1;
+
+	/*
+	 *  dp->start is in cluster units, not sectors.  The first
+	 *  cluster is cluster 2 which starts immediately after the
+	 *  root directory
+	 */
+	return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize;
+}
+