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