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