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