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 cputype = strdup("pc"); 143 144 fd = -1; 145 safeoff = -1; 146 safelen = -1; 147 if(nvrfile != nil){ 148 /* accept device and device!file */ 149 i = gettokens(nvrfile, v, nelem(v), "!"); 150 fd = open(v[0], ORDWR); 151 if (fd < 0) 152 fd = open(v[0], OREAD); 153 safelen = sizeof(Nvrsafe); 154 if(strstr(v[0], "/9fat") == nil) 155 safeoff = 0; 156 nvrlen = getenv("nvrlen"); 157 if(nvrlen != nil) 158 safelen = atoi(nvrlen); 159 nvroff = getenv("nvroff"); 160 if(nvroff != nil) 161 if(strcmp(nvroff, "dos") == 0) 162 safeoff = -1; 163 else 164 safeoff = atoi(nvroff); 165 if(safeoff < 0 && fd >= 0){ 166 safelen = 512; 167 safeoff = finddosfile(fd, i == 2? v[1]: "plan9.nvr"); 168 if(safeoff < 0){ /* didn't find plan9.nvr? */ 169 close(fd); 170 fd = -1; 171 } 172 } 173 free(nvroff); 174 free(nvrlen); 175 free(nvrfile); 176 }else 177 for(i=0; i<nelem(nvtab); i++){ 178 if(strcmp(cputype, nvtab[i].cputype) != 0) 179 continue; 180 if((fd = open(nvtab[i].file, ORDWR)) < 0) 181 continue; 182 safeoff = nvtab[i].off; 183 safelen = nvtab[i].len; 184 if(safeoff == -1){ 185 safeoff = finddosfile(fd, "plan9.nvr"); 186 if(safeoff < 0){ /* didn't find plan9.nvr? */ 187 close(fd); 188 fd = -1; 189 continue; 190 } 191 } 192 break; 193 } 194 free(cputype); 195 locp->fd = fd; 196 locp->safelen = safelen; 197 locp->safeoff = safeoff; 198 } 199 200 /* 201 * get key info out of nvram. since there isn't room in the PC's nvram use 202 * a disk partition there. 203 */ 204 int 205 readnvram(Nvrsafe *safep, int flag) 206 { 207 int err; 208 char buf[512], in[128]; /* 512 for floppy i/o */ 209 Nvrsafe *safe; 210 Nvrwhere loc; 211 212 err = 0; 213 safe = (Nvrsafe*)buf; 214 memset(&loc, 0, sizeof loc); 215 findnvram(&loc); 216 if (loc.safelen < 0) 217 loc.safelen = sizeof *safe; 218 else if (loc.safelen > sizeof buf) 219 loc.safelen = sizeof buf; 220 if (loc.safeoff < 0) { 221 fprint(2, "readnvram: couldn't find nvram\n"); 222 if(!(flag&NVwritemem)) 223 memset(safep, 0, sizeof(*safep)); 224 safe = safep; 225 /* 226 * allow user to type the data for authentication, 227 * even if there's no nvram to store it in. 228 */ 229 } 230 231 if(flag&NVwritemem) 232 safe = safep; 233 else { 234 memset(safep, 0, sizeof(*safep)); 235 if(loc.fd < 0 236 || seek(loc.fd, loc.safeoff, 0) < 0 237 || read(loc.fd, buf, loc.safelen) != loc.safelen){ 238 err = 1; 239 if(flag&(NVwrite|NVwriteonerr)) 240 fprint(2, "can't read nvram: %r\n"); 241 /* start from scratch */ 242 memset(safep, 0, sizeof(*safep)); 243 safe = safep; 244 }else{ 245 *safep = *safe; /* overwrite arg with data read */ 246 safe = safep; 247 248 /* verify data read */ 249 err |= check(safe->machkey, DESKEYLEN, safe->machsum, 250 "bad nvram key"); 251 // err |= check(safe->config, CONFIGLEN, safe->configsum, 252 // "bad secstore key"); 253 err |= check(safe->authid, ANAMELEN, safe->authidsum, 254 "bad authentication id"); 255 err |= check(safe->authdom, DOMLEN, safe->authdomsum, 256 "bad authentication domain"); 257 if(err == 0) 258 if(safe->authid[0]==0 || safe->authdom[0]==0){ 259 fprint(2, "empty nvram authid or authdom\n"); 260 err = 1; 261 } 262 } 263 } 264 265 if((flag&(NVwrite|NVwritemem)) || (err && (flag&NVwriteonerr))){ 266 if (!(flag&NVwritemem)) { 267 readcons("authid", nil, 0, safe->authid, 268 sizeof safe->authid); 269 readcons("authdom", nil, 0, safe->authdom, 270 sizeof safe->authdom); 271 readcons("secstore key", nil, 1, safe->config, 272 sizeof safe->config); 273 for(;;){ 274 if(readcons("password", nil, 1, in, sizeof in) 275 == nil) 276 goto Out; 277 if(passtokey(safe->machkey, in)) 278 break; 279 } 280 } 281 282 // safe->authsum = nvcsum(safe->authkey, DESKEYLEN); 283 safe->machsum = nvcsum(safe->machkey, DESKEYLEN); 284 safe->configsum = nvcsum(safe->config, CONFIGLEN); 285 safe->authidsum = nvcsum(safe->authid, sizeof safe->authid); 286 safe->authdomsum = nvcsum(safe->authdom, sizeof safe->authdom); 287 288 *(Nvrsafe*)buf = *safe; 289 if(loc.fd < 0 290 || seek(loc.fd, loc.safeoff, 0) < 0 291 || write(loc.fd, buf, loc.safelen) != loc.safelen){ 292 fprint(2, "can't write key to nvram: %r\n"); 293 err = 1; 294 }else 295 err = 0; 296 } 297 Out: 298 if (loc.fd >= 0) 299 close(loc.fd); 300 return err? -1: 0; 301 } 302 303 typedef struct Dosboot Dosboot; 304 struct Dosboot{ 305 uchar magic[3]; /* really an xx86 JMP instruction */ 306 uchar version[8]; 307 uchar sectsize[2]; 308 uchar clustsize; 309 uchar nresrv[2]; 310 uchar nfats; 311 uchar rootsize[2]; 312 uchar volsize[2]; 313 uchar mediadesc; 314 uchar fatsize[2]; 315 uchar trksize[2]; 316 uchar nheads[2]; 317 uchar nhidden[4]; 318 uchar bigvolsize[4]; 319 uchar driveno; 320 uchar reserved0; 321 uchar bootsig; 322 uchar volid[4]; 323 uchar label[11]; 324 uchar type[8]; 325 }; 326 #define GETSHORT(p) (((p)[1]<<8) | (p)[0]) 327 #define GETLONG(p) ((GETSHORT((p)+2) << 16) | GETSHORT((p))) 328 329 typedef struct Dosdir Dosdir; 330 struct Dosdir 331 { 332 char name[8]; 333 char ext[3]; 334 uchar attr; 335 uchar reserved[10]; 336 uchar time[2]; 337 uchar date[2]; 338 uchar start[2]; 339 uchar length[4]; 340 }; 341 342 static char* 343 dosparse(char *from, char *to, int len) 344 { 345 char c; 346 347 memset(to, ' ', len); 348 if(from == 0) 349 return 0; 350 while(len-- > 0){ 351 c = *from++; 352 if(c == '.') 353 return from; 354 if(c == 0) 355 break; 356 if(c >= 'a' && c <= 'z') 357 *to++ = c + 'A' - 'a'; 358 else 359 *to++ = c; 360 } 361 return 0; 362 } 363 364 /* 365 * return offset of first file block 366 * 367 * This is a very simplistic dos file system. It only 368 * works on floppies, only looks in the root, and only 369 * returns a pointer to the first block of a file. 370 * 371 * This exists for cpu servers that have no hard disk 372 * or nvram to store the key on. 373 * 374 * Please don't make this any smarter: it stays resident 375 * and I'ld prefer not to waste the space on something that 376 * runs only at boottime -- presotto. 377 */ 378 static long 379 finddosfile(int fd, char *file) 380 { 381 uchar secbuf[512]; 382 char name[8]; 383 char ext[3]; 384 Dosboot *b; 385 Dosdir *root, *dp; 386 int nroot, sectsize, rootoff, rootsects, n; 387 388 /* dos'ize file name */ 389 file = dosparse(file, name, 8); 390 dosparse(file, ext, 3); 391 392 /* read boot block, check for sanity */ 393 b = (Dosboot*)secbuf; 394 if(read(fd, secbuf, sizeof(secbuf)) != sizeof(secbuf)) 395 return -1; 396 if(b->magic[0] != 0xEB || b->magic[1] != 0x3C || b->magic[2] != 0x90) 397 return -1; 398 sectsize = GETSHORT(b->sectsize); 399 if(sectsize != 512) 400 return -1; 401 rootoff = (GETSHORT(b->nresrv) + b->nfats*GETSHORT(b->fatsize)) * sectsize; 402 if(seek(fd, rootoff, 0) < 0) 403 return -1; 404 nroot = GETSHORT(b->rootsize); 405 rootsects = (nroot*sizeof(Dosdir)+sectsize-1)/sectsize; 406 if(rootsects <= 0 || rootsects > 64) 407 return -1; 408 409 /* 410 * read root. it is contiguous to make stuff like 411 * this easier 412 */ 413 root = malloc(rootsects*sectsize); 414 if(read(fd, root, rootsects*sectsize) != rootsects*sectsize) 415 return -1; 416 n = -1; 417 for(dp = root; dp < &root[nroot]; dp++) 418 if(memcmp(name, dp->name, 8) == 0 && memcmp(ext, dp->ext, 3) == 0){ 419 n = GETSHORT(dp->start); 420 break; 421 } 422 free(root); 423 424 if(n < 0) 425 return -1; 426 427 /* 428 * dp->start is in cluster units, not sectors. The first 429 * cluster is cluster 2 which starts immediately after the 430 * root directory 431 */ 432 return rootoff + rootsects*sectsize + (n-2)*sectsize*b->clustsize; 433 } 434 435