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/sdD0/nvram", 0, sizeof(Nvrsafe), 33 "pc", "#S/sdD0/9fat", -1, sizeof(Nvrsafe), 34 "pc", "#S/sdE0/nvram", 0, sizeof(Nvrsafe), 35 "pc", "#S/sdE0/9fat", -1, sizeof(Nvrsafe), 36 "pc", "#S/sdF0/nvram", 0, sizeof(Nvrsafe), 37 "pc", "#S/sdF0/9fat", -1, sizeof(Nvrsafe), 38 "pc", "#S/sd00/nvram", 0, sizeof(Nvrsafe), 39 "pc", "#S/sd00/9fat", -1, sizeof(Nvrsafe), 40 "pc", "#S/sd01/nvram", 0, sizeof(Nvrsafe), 41 "pc", "#S/sd01/9fat", -1, sizeof(Nvrsafe), 42 "pc", "#f/fd0disk", -1, 512, /* 512: #f requires whole sector reads */ 43 "pc", "#f/fd1disk", -1, 512, 44 "mips", "#r/nvram", 1024+900, sizeof(Nvrsafe), 45 "power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe), 46 "power", "#r/nvram", 4352, sizeof(Nvrsafe), /* OK for MTX-604e */ 47 "power", "/nvram", 0, sizeof(Nvrsafe), /* OK for Ucu */ 48 "arm", "#F/flash/flash0", 0x100000, sizeof(Nvrsafe), 49 "debug", "/tmp/nvram", 0, sizeof(Nvrsafe), 50 }; 51 52 static char* 53 readcons(char *prompt, char *def, int raw, char *buf, int nbuf) 54 { 55 int fdin, fdout, ctl, n, m; 56 char line[10]; 57 58 fdin = open("/dev/cons", OREAD); 59 if(fdin < 0) 60 fdin = 0; 61 fdout = open("/dev/cons", OWRITE); 62 if(fdout < 0) 63 fdout = 1; 64 if(def != nil) 65 fprint(fdout, "%s[%s]: ", prompt, def); 66 else 67 fprint(fdout, "%s: ", prompt); 68 if(raw){ 69 ctl = open("/dev/consctl", OWRITE); 70 if(ctl >= 0) 71 write(ctl, "rawon", 5); 72 } else 73 ctl = -1; 74 75 m = 0; 76 for(;;){ 77 n = read(fdin, line, 1); 78 if(n == 0){ 79 close(ctl); 80 werrstr("readcons: EOF"); 81 return nil; 82 } 83 if(n < 0){ 84 close(ctl); 85 werrstr("can't read cons"); 86 return nil; 87 } 88 if(line[0] == 0x7f) 89 exits(0); 90 if(n == 0 || line[0] == '\n' || line[0] == '\r'){ 91 if(raw){ 92 write(ctl, "rawoff", 6); 93 write(fdout, "\n", 1); 94 close(ctl); 95 } 96 buf[m] = '\0'; 97 if(buf[0]=='\0' && def) 98 strcpy(buf, def); 99 return buf; 100 } 101 if(line[0] == '\b'){ 102 if(m > 0) 103 m--; 104 }else if(line[0] == 0x15){ /* ^U: line kill */ 105 m = 0; 106 if(def != nil) 107 fprint(fdout, "%s[%s]: ", prompt, def); 108 else 109 fprint(fdout, "%s: ", prompt); 110 }else{ 111 if(m >= nbuf-1){ 112 fprint(fdout, "line too long\n"); 113 m = 0; 114 if(def != nil) 115 fprint(fdout, "%s[%s]: ", prompt, def); 116 else 117 fprint(fdout, "%s: ", prompt); 118 }else 119 buf[m++] = line[0]; 120 } 121 } 122 } 123 124 typedef struct { 125 int fd; 126 int safeoff; 127 int safelen; 128 } Nvrwhere; 129 130 /* returns with *locp filled in and locp->fd open, if possible */ 131 static void 132 findnvram(Nvrwhere *locp) 133 { 134 char *cputype, *nvrfile, *nvrlen, *nvroff, *v[2]; 135 int fd, i, safeoff, safelen; 136 137 nvrfile = getenv("nvram"); 138 cputype = getenv("cputype"); 139 if(cputype == nil) 140 cputype = strdup("mips"); 141 if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) { 142 free(cputype); 143 cputype = strdup("pc"); 144 } 145 146 fd = -1; 147 safeoff = -1; 148 safelen = -1; 149 if(nvrfile != nil && *nvrfile != '\0'){ 150 /* accept device and device!file */ 151 i = gettokens(nvrfile, v, nelem(v), "!"); 152 if (i < 1) { 153 i = 1; 154 v[0] = ""; 155 v[1] = nil; 156 } 157 fd = open(v[0], ORDWR); 158 if (fd < 0) 159 fd = open(v[0], OREAD); 160 safelen = sizeof(Nvrsafe); 161 if(strstr(v[0], "/9fat") == nil) 162 safeoff = 0; 163 nvrlen = getenv("nvrlen"); 164 if(nvrlen != nil) 165 safelen = atoi(nvrlen); 166 nvroff = getenv("nvroff"); 167 if(nvroff != nil) 168 if(strcmp(nvroff, "dos") == 0) 169 safeoff = -1; 170 else 171 safeoff = atoi(nvroff); 172 if(safeoff < 0 && fd >= 0){ 173 safelen = 512; 174 safeoff = finddosfile(fd, i == 2? v[1]: "plan9.nvr"); 175 if(safeoff < 0){ /* didn't find plan9.nvr? */ 176 close(fd); 177 fd = -1; 178 } 179 } 180 free(nvroff); 181 free(nvrlen); 182 }else 183 for(i=0; i<nelem(nvtab); i++){ 184 if(strcmp(cputype, nvtab[i].cputype) != 0) 185 continue; 186 if((fd = open(nvtab[i].file, ORDWR)) < 0) 187 continue; 188 safeoff = nvtab[i].off; 189 safelen = nvtab[i].len; 190 if(safeoff == -1){ 191 safeoff = finddosfile(fd, "plan9.nvr"); 192 if(safeoff < 0){ /* didn't find plan9.nvr? */ 193 close(fd); 194 fd = -1; 195 continue; 196 } 197 } 198 break; 199 } 200 free(nvrfile); 201 free(cputype); 202 locp->fd = fd; 203 locp->safelen = safelen; 204 locp->safeoff = safeoff; 205 } 206 207 /* 208 * get key info out of nvram. since there isn't room in the PC's nvram use 209 * a disk partition there. 210 */ 211 int 212 readnvram(Nvrsafe *safep, int flag) 213 { 214 int err; 215 char buf[512], in[128]; /* 512 for floppy i/o */ 216 Nvrsafe *safe; 217 Nvrwhere loc; 218 219 err = 0; 220 safe = (Nvrsafe*)buf; 221 memset(&loc, 0, sizeof loc); 222 findnvram(&loc); 223 if (loc.safelen < 0) 224 loc.safelen = sizeof *safe; 225 else if (loc.safelen > sizeof buf) 226 loc.safelen = sizeof buf; 227 if (loc.safeoff < 0) { 228 fprint(2, "readnvram: couldn't find nvram\n"); 229 if(!(flag&NVwritemem)) 230 memset(safep, 0, sizeof(*safep)); 231 safe = safep; 232 /* 233 * allow user to type the data for authentication, 234 * even if there's no nvram to store it in. 235 */ 236 } 237 238 if(flag&NVwritemem) 239 safe = safep; 240 else { 241 memset(safep, 0, sizeof(*safep)); 242 if(loc.fd < 0 243 || seek(loc.fd, loc.safeoff, 0) < 0 244 || read(loc.fd, buf, loc.safelen) != loc.safelen){ 245 err = 1; 246 if(flag&(NVwrite|NVwriteonerr)) 247 fprint(2, "can't read nvram: %r\n"); 248 /* start from scratch */ 249 memset(safep, 0, sizeof(*safep)); 250 safe = safep; 251 }else{ 252 *safep = *safe; /* overwrite arg with data read */ 253 safe = safep; 254 255 /* verify data read */ 256 err |= check(safe->machkey, DESKEYLEN, safe->machsum, 257 "bad nvram key"); 258 // err |= check(safe->config, CONFIGLEN, safe->configsum, 259 // "bad secstore key"); 260 err |= check(safe->authid, ANAMELEN, safe->authidsum, 261 "bad authentication id"); 262 err |= check(safe->authdom, DOMLEN, safe->authdomsum, 263 "bad authentication domain"); 264 if(err == 0) 265 if(safe->authid[0]==0 || safe->authdom[0]==0){ 266 fprint(2, "empty nvram authid or authdom\n"); 267 err = 1; 268 } 269 } 270 } 271 272 if((flag&(NVwrite|NVwritemem)) || (err && (flag&NVwriteonerr))){ 273 if (!(flag&NVwritemem)) { 274 readcons("authid", nil, 0, safe->authid, 275 sizeof safe->authid); 276 readcons("authdom", nil, 0, safe->authdom, 277 sizeof safe->authdom); 278 readcons("secstore key", nil, 1, safe->config, 279 sizeof safe->config); 280 for(;;){ 281 if(readcons("password", nil, 1, in, sizeof in) 282 == nil) 283 goto Out; 284 if(passtokey(safe->machkey, in)) 285 break; 286 } 287 } 288 289 // safe->authsum = nvcsum(safe->authkey, DESKEYLEN); 290 safe->machsum = nvcsum(safe->machkey, DESKEYLEN); 291 safe->configsum = nvcsum(safe->config, CONFIGLEN); 292 safe->authidsum = nvcsum(safe->authid, sizeof safe->authid); 293 safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom); 294 295 *(Nvrsafe*)buf = *safe; 296 if(loc.fd < 0 297 || seek(loc.fd, loc.safeoff, 0) < 0 298 || write(loc.fd, buf, loc.safelen) != loc.safelen){ 299 fprint(2, "can't write key to nvram: %r\n"); 300 err = 1; 301 }else 302 err = 0; 303 } 304 Out: 305 if (loc.fd >= 0) 306 close(loc.fd); 307 return err? -1: 0; 308 } 309 310 typedef struct Dosboot Dosboot; 311 struct Dosboot{ 312 uchar magic[3]; /* really an xx86 JMP instruction */ 313 uchar version[8]; 314 uchar sectsize[2]; 315 uchar clustsize; 316 uchar nresrv[2]; 317 uchar nfats; 318 uchar rootsize[2]; 319 uchar volsize[2]; 320 uchar mediadesc; 321 uchar fatsize[2]; 322 uchar trksize[2]; 323 uchar nheads[2]; 324 uchar nhidden[4]; 325 uchar bigvolsize[4]; 326 uchar driveno; 327 uchar reserved0; 328 uchar bootsig; 329 uchar volid[4]; 330 uchar label[11]; 331 uchar type[8]; 332 }; 333 #define GETSHORT(p) (((p)[1]<<8) | (p)[0]) 334 #define GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p))) 335 336 typedef struct Dosdir Dosdir; 337 struct Dosdir 338 { 339 char name[8]; 340 char ext[3]; 341 uchar attr; 342 uchar reserved[10]; 343 uchar time[2]; 344 uchar date[2]; 345 uchar start[2]; 346 uchar length[4]; 347 }; 348 349 static char* 350 dosparse(char *from, char *to, int len) 351 { 352 char c; 353 354 memset(to, ' ', len); 355 if(from == 0) 356 return 0; 357 while(len-- > 0){ 358 c = *from++; 359 if(c == '.') 360 return from; 361 if(c == 0) 362 break; 363 if(c >= 'a' && c <= 'z') 364 *to++ = c + 'A' - 'a'; 365 else 366 *to++ = c; 367 } 368 return 0; 369 } 370 371 /* 372 * return offset of first file block 373 * 374 * This is a very simplistic dos file system. It only 375 * works on floppies, only looks in the root, and only 376 * returns a pointer to the first block of a file. 377 * 378 * This exists for cpu servers that have no hard disk 379 * or nvram to store the key on. 380 * 381 * Please don't make this any smarter: it stays resident 382 * and I'ld prefer not to waste the space on something that 383 * runs only at boottime -- presotto. 384 */ 385 static long 386 finddosfile(int fd, char *file) 387 { 388 uchar secbuf[512]; 389 char name[8]; 390 char ext[3]; 391 Dosboot *b; 392 Dosdir *root, *dp; 393 int nroot, sectsize, rootoff, rootsects, n; 394 395 /* dos'ize file name */ 396 file = dosparse(file, name, 8); 397 dosparse(file, ext, 3); 398 399 /* read boot block, check for sanity */ 400 b = (Dosboot*)secbuf; 401 if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf)) 402 return -1; 403 if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90) 404 return -1; 405 sectsize = GETSHORT(b->sectsize); 406 if(sectsize != 512) 407 return -1; 408 rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize; 409 if(seek(fd, rootoff, 0) < 0) 410 return -1; 411 nroot = GETSHORT(b->rootsize); 412 rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize; 413 if(rootsects <= 0 || rootsects > 64) 414 return -1; 415 416 /* 417 * read root. it is contiguous to make stuff like 418 * this easier 419 */ 420 root = malloc(rootsects*sectsize); 421 if(read(fd, root, rootsects*sectsize) != rootsects*sectsize) 422 return -1; 423 n = -1; 424 for(dp = root; dp < &root[nroot]; dp++) 425 if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){ 426 n = GETSHORT(dp->start); 427 break; 428 } 429 free(root); 430 431 if(n < 0) 432 return -1; 433 434 /* 435 * dp->start is in cluster units, not sectors. The first 436 * cluster is cluster 2 which starts immediately after the 437 * root directory 438 */ 439 return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize; 440 } 441 442