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