URI:
       treadnvram.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       treadnvram.c (7384B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <authsrv.h>
            4 
            5 static long        finddosfile(int, char*);
            6 
            7 static int
            8 check(void *x, int len, uchar sum, char *msg)
            9 {
           10         if(nvcsum(x, len) == sum)
           11                 return 0;
           12         memset(x, 0, len);
           13         fprint(2, "%s\n", msg);
           14         return 1;
           15 }
           16 
           17 /*
           18  *  get key info out of nvram.  since there isn't room in the PC's nvram use
           19  *  a disk partition there.
           20  */
           21 static struct {
           22         char *cputype;
           23         char *file;
           24         int off;
           25         int len;
           26 } nvtab[] = {
           27         "sparc", "#r/nvram", 1024+850, sizeof(Nvrsafe),
           28         "pc", "#S/sdC0/nvram", 0, sizeof(Nvrsafe),
           29         "pc", "#S/sdC0/9fat", -1, sizeof(Nvrsafe),
           30         "pc", "#S/sdC1/nvram", 0, sizeof(Nvrsafe),
           31         "pc", "#S/sdC1/9fat", -1, sizeof(Nvrsafe),
           32         "pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe),
           33         "pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe),
           34         "pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe),
           35         "pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe),
           36         "pc", "#f/fd0disk", -1, 512,        /* 512: #f requires whole sector reads */
           37         "pc", "#f/fd1disk", -1, 512,
           38         "mips", "#r/nvram", 1024+900, sizeof(Nvrsafe),
           39         "power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe),
           40         "power", "#r/nvram", 4352, sizeof(Nvrsafe),        /* OK for MTX-604e */
           41         "debug", "/tmp/nvram", 0, sizeof(Nvrsafe),
           42 };
           43 
           44 static char*
           45 xreadcons(char *prompt, char *def, int secret, char *buf, int nbuf)
           46 {
           47         char *p;
           48 
           49         p = readcons(prompt, def, secret);
           50         if(p == nil)
           51                 return nil;
           52         strecpy(buf, buf+nbuf, p);
           53         memset(p, 0, strlen(p));
           54         free(p);
           55         return buf;
           56 }
           57 
           58 /*
           59  *  get key info out of nvram.  since there isn't room in the PC's nvram use
           60  *  a disk partition there.
           61  */
           62 int
           63 readnvram(Nvrsafe *safep, int flag)
           64 {
           65         char buf[1024], in[128], *cputype, *nvrfile, *nvrlen, *nvroff, *v[2];
           66         int fd, err, i, safeoff, safelen;
           67         Nvrsafe *safe;
           68 
           69         err = 0;
           70         memset(safep, 0, sizeof(*safep));
           71 
           72         nvrfile = getenv("nvram");
           73         cputype = getenv("cputype");
           74         if(cputype == nil)
           75                 cputype = "mips";
           76         if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0)
           77                 cputype = "pc";
           78 
           79         fd = -1;
           80         safeoff = -1;
           81         safelen = -1;
           82         if(nvrfile != nil){
           83                 /* accept device and device!file */
           84                 i = gettokens(nvrfile, v, nelem(v), "!");
           85                 fd = open(v[0], ORDWR);
           86                 safelen = sizeof(Nvrsafe);
           87                 if(strstr(v[0], "/9fat") == nil)
           88                         safeoff = 0;
           89                 nvrlen = getenv("nvrlen");
           90                 if(nvrlen != nil)
           91                         safelen = atoi(nvrlen);
           92                 nvroff = getenv("nvroff");
           93                 if(nvroff != nil){
           94                         if(strcmp(nvroff, "dos") == 0)
           95                                 safeoff = -1;
           96                         else
           97                                 safeoff = atoi(nvroff);
           98                 }
           99                 if(safeoff < 0 && fd >= 0){
          100                         safelen = 512;
          101                         safeoff = finddosfile(fd, i == 2 ? v[1] : "plan9.nvr");
          102                         if(safeoff < 0){
          103                                 close(fd);
          104                                 fd = -1;
          105                         }
          106                 }
          107                 free(nvrfile);
          108                 if(nvrlen != nil)
          109                         free(nvrlen);
          110                 if(nvroff != nil)
          111                         free(nvroff);
          112         }else{
          113                 for(i=0; i<nelem(nvtab); i++){
          114                         if(strcmp(cputype, nvtab[i].cputype) != 0)
          115                                 continue;
          116                         if((fd = open(nvtab[i].file, ORDWR)) < 0)
          117                                 continue;
          118                         safeoff = nvtab[i].off;
          119                         safelen = nvtab[i].len;
          120                         if(safeoff == -1){
          121                                 safeoff = finddosfile(fd, "plan9.nvr");
          122                                 if(safeoff < 0){
          123                                         close(fd);
          124                                         fd = -1;
          125                                         continue;
          126                                 }
          127                         }
          128                         break;
          129                 }
          130         }
          131 
          132         if(fd < 0
          133         || seek(fd, safeoff, 0) < 0
          134         || read(fd, buf, safelen) != safelen){
          135                 err = 1;
          136                 if(flag&(NVwrite|NVwriteonerr))
          137                         fprint(2, "can't read nvram: %r\n");
          138                 memset(safep, 0, sizeof(*safep));
          139                 safe = safep;
          140         }else{
          141                 memmove(safep, buf, sizeof *safep);
          142                 safe = safep;
          143 
          144                 err |= check(safe->machkey, DESKEYLEN, safe->machsum, "bad nvram key");
          145 /*                err |= check(safe->config, CONFIGLEN, safe->configsum, "bad secstore key"); */
          146                 err |= check(safe->authid, ANAMELEN, safe->authidsum, "bad authentication id");
          147                 err |= check(safe->authdom, DOMLEN, safe->authdomsum, "bad authentication domain");
          148         }
          149 
          150         if((flag&NVwrite) || (err && (flag&NVwriteonerr))){
          151                 xreadcons("authid", nil, 0, safe->authid, sizeof(safe->authid));
          152                 xreadcons("authdom", nil, 0, safe->authdom, sizeof(safe->authdom));
          153                 xreadcons("secstore key", nil, 1, safe->config, sizeof(safe->config));
          154                 for(;;){
          155                         if(xreadcons("password", nil, 1, in, sizeof in) == nil)
          156                                 goto Out;
          157                         if(passtokey(safe->machkey, in))
          158                                 break;
          159                 }
          160                 safe->machsum = nvcsum(safe->machkey, DESKEYLEN);
          161                 safe->configsum = nvcsum(safe->config, CONFIGLEN);
          162                 safe->authidsum = nvcsum(safe->authid, sizeof(safe->authid));
          163                 safe->authdomsum = nvcsum(safe->authdom, sizeof(safe->authdom));
          164                 memmove(buf, safe, sizeof *safe);
          165                 if(seek(fd, safeoff, 0) < 0
          166                 || write(fd, buf, safelen) != safelen){
          167                         fprint(2, "can't write key to nvram: %r\n");
          168                         err = 1;
          169                 }else
          170                         err = 0;
          171         }
          172 Out:
          173         close(fd);
          174         return err ? -1 : 0;
          175 }
          176 
          177 typedef struct Dosboot        Dosboot;
          178 struct Dosboot{
          179         uchar        magic[3];        /* really an xx86 JMP instruction */
          180         uchar        version[8];
          181         uchar        sectsize[2];
          182         uchar        clustsize;
          183         uchar        nresrv[2];
          184         uchar        nfats;
          185         uchar        rootsize[2];
          186         uchar        volsize[2];
          187         uchar        mediadesc;
          188         uchar        fatsize[2];
          189         uchar        trksize[2];
          190         uchar        nheads[2];
          191         uchar        nhidden[4];
          192         uchar        bigvolsize[4];
          193         uchar        driveno;
          194         uchar        reserved0;
          195         uchar        bootsig;
          196         uchar        volid[4];
          197         uchar        label[11];
          198         uchar        type[8];
          199 };
          200 #define        GETSHORT(p) (((p)[1]<<8) | (p)[0])
          201 #define        GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p)))
          202 
          203 typedef struct Dosdir        Dosdir;
          204 struct Dosdir
          205 {
          206         char        name[8];
          207         char        ext[3];
          208         uchar        attr;
          209         uchar        reserved[10];
          210         uchar        time[2];
          211         uchar        date[2];
          212         uchar        start[2];
          213         uchar        length[4];
          214 };
          215 
          216 static char*
          217 dosparse(char *from, char *to, int len)
          218 {
          219         char c;
          220 
          221         memset(to, ' ', len);
          222         if(from == 0)
          223                 return 0;
          224         while(len-- > 0){
          225                 c = *from++;
          226                 if(c == '.')
          227                         return from;
          228                 if(c == 0)
          229                         break;
          230                 if(c >= 'a' && c <= 'z')
          231                         *to++ = c + 'A' - 'a';
          232                 else
          233                         *to++ = c;
          234         }
          235         return 0;
          236 }
          237 
          238 /*
          239  *  return offset of first file block
          240  *
          241  *  This is a very simplistic dos file system.  It only
          242  *  works on floppies, only looks in the root, and only
          243  *  returns a pointer to the first block of a file.
          244  *
          245  *  This exists for cpu servers that have no hard disk
          246  *  or nvram to store the key on.
          247  *
          248  *  Please don't make this any smarter: it stays resident
          249  *  and I'ld prefer not to waste the space on something that
          250  *  runs only at boottime -- presotto.
          251  */
          252 static long
          253 finddosfile(int fd, char *file)
          254 {
          255         uchar secbuf[512];
          256         char name[8];
          257         char ext[3];
          258         Dosboot        *b;
          259         Dosdir *root, *dp;
          260         int nroot, sectsize, rootoff, rootsects, n;
          261 
          262         /* dos'ize file name */
          263         file = dosparse(file, name, 8);
          264         dosparse(file, ext, 3);
          265 
          266         /* read boot block, check for sanity */
          267         b = (Dosboot*)secbuf;
          268         if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf))
          269                 return -1;
          270         if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90)
          271                 return -1;
          272         sectsize = GETSHORT(b->sectsize);
          273         if(sectsize != 512)
          274                 return -1;
          275         rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize;
          276         if(seek(fd, rootoff, 0) < 0)
          277                 return -1;
          278         nroot = GETSHORT(b->rootsize);
          279         rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize;
          280         if(rootsects <= 0 || rootsects > 64)
          281                 return -1;
          282 
          283         /*
          284          *  read root. it is contiguous to make stuff like
          285          *  this easier
          286          */
          287         root = malloc(rootsects*sectsize);
          288         if(read(fd, root, rootsects*sectsize) != rootsects*sectsize)
          289                 return -1;
          290         n = -1;
          291         for(dp = root; dp < &root[nroot]; dp++)
          292                 if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){
          293                         n = GETSHORT(dp->start);
          294                         break;
          295                 }
          296         free(root);
          297 
          298         if(n < 0)
          299                 return -1;
          300 
          301         /*
          302          *  dp->start is in cluster units, not sectors.  The first
          303          *  cluster is cluster 2 which starts immediately after the
          304          *  root directory
          305          */
          306         return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize;
          307 }