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