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