From 4180d05ba41196e0633252de26750bb19f3a6da8 Mon Sep 17 00:00:00 2001 From: rsc Date: Thu, 17 Jun 2004 03:28:08 +0000 Subject: these do work --- src/libauthsrv/readnvram.c | 370 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 src/libauthsrv/readnvram.c (limited to 'src/libauthsrv/readnvram.c') diff --git a/src/libauthsrv/readnvram.c b/src/libauthsrv/readnvram.c new file mode 100644 index 00000000..e48a5761 --- /dev/null +++ b/src/libauthsrv/readnvram.c @@ -0,0 +1,370 @@ +#include +#include +#include + +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; imachkey, 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; +} + -- cgit v1.2.3