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 }