plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

readnvram.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 }