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