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