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