1 #include "dat.h"
2
3 int askforkeys = 1;
4 char *authaddr;
5 int debug;
6 int doprivate = 1;
7 int gflag;
8 char *owner;
9 int kflag;
10 char *mtpt = "/mnt";
11 Keyring *ring;
12 char *service;
13 int sflag;
14 int uflag;
15
16 extern Srv fs;
17 static void notifyf(void*, char*);
18 static void private(void);
19
20 char Easproto[] = "auth server protocol botch";
21 char Ebadarg[] = "invalid argument";
22 char Ebadkey[] = "bad key";
23 char Enegotiation[] = "negotiation failed, no common protocols or keys";
24 char Etoolarge[] = "rpc too large";
25
26 Proto*
27 prototab[] =
28 {
29 &apop,
30 &chap,
31 &cram,
32 &httpdigest,
33 &mschap,
34 &p9any,
35 &p9cr,
36 &p9sk1,
37 &p9sk2,
38 &pass,
39 /* &srs, */
40 &rsa,
41 &vnc,
42 &wep,
43 &wpapsk,
44 nil,
45 };
46
47 void
usage(void)48 usage(void)
49 {
50 fprint(2, "usage: %s [-DSdknpu] [-a authaddr] [-m mtpt] [-s service]\n",
51 argv0);
52 fprint(2, "or %s -g 'params'\n", argv0);
53 exits("usage");
54 }
55
56 void
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59 int i, trysecstore;
60 char err[ERRMAX], *s;
61 Dir d;
62 Proto *p;
63 char *secstorepw;
64
65 trysecstore = 1;
66 secstorepw = nil;
67
68 ARGBEGIN{
69 case 'D':
70 chatty9p++;
71 break;
72 case 'S': /* server: read nvram, no prompting for keys */
73 askforkeys = 0;
74 trysecstore = 0;
75 sflag = 1;
76 break;
77 case 'a':
78 authaddr = EARGF(usage());
79 break;
80 case 'd':
81 debug = 1;
82 doprivate = 0;
83 break;
84 case 'g': /* get: prompt for key for name and domain */
85 gflag = 1;
86 break;
87 case 'k': /* reinitialize nvram */
88 kflag = 1;
89 break;
90 case 'm': /* set default mount point */
91 mtpt = EARGF(usage());
92 break;
93 case 'n':
94 trysecstore = 0;
95 break;
96 case 'p':
97 doprivate = 0;
98 break;
99 case 's': /* set service name */
100 service = EARGF(usage());
101 break;
102 case 'u': /* user: set hostowner */
103 uflag = 1;
104 break;
105 default:
106 usage();
107 }ARGEND
108
109 if(argc != 0 && !gflag)
110 usage();
111 if(doprivate)
112 private();
113
114 initcap();
115
116 quotefmtinstall();
117 fmtinstall('A', _attrfmt);
118 fmtinstall('N', attrnamefmt);
119 fmtinstall('H', encodefmt);
120
121 ring = emalloc(sizeof(*ring));
122 notify(notifyf);
123
124 if(gflag){
125 if(argc != 1)
126 usage();
127 askuser(argv[0]);
128 exits(nil);
129 }
130
131 for(i=0; prototab[i]; i++){
132 p = prototab[i];
133 if(p->name == nil)
134 sysfatal("protocol %d has no name", i);
135 if(p->init == nil)
136 sysfatal("protocol %s has no init", p->name);
137 if(p->write == nil)
138 sysfatal("protocol %s has no write", p->name);
139 if(p->read == nil)
140 sysfatal("protocol %s has no read", p->name);
141 if(p->close == nil)
142 sysfatal("protocol %s has no close", p->name);
143 if(p->keyprompt == nil)
144 p->keyprompt = "";
145 }
146
147 if(sflag){
148 s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
149 if(s == nil)
150 fprint(2, "factotum warning: cannot read nvram: %r\n");
151 else if(ctlwrite(s, 0) < 0)
152 fprint(2, "factotum warning: cannot add nvram key: %r\n");
153 if(secstorepw != nil)
154 trysecstore = 1;
155 if (s != nil) {
156 memset(s, 0, strlen(s));
157 free(s);
158 }
159 } else if(uflag)
160 promptforhostowner();
161 owner = getuser();
162
163 if(trysecstore){
164 if(havesecstore() == 1){
165 while(secstorefetch(secstorepw) < 0){
166 rerrstr(err, sizeof err);
167 if(strcmp(err, "cancel") == 0)
168 break;
169 fprint(2, "factotum: secstorefetch: %r\n");
170 fprint(2, "Enter an empty password to quit.\n");
171 free(secstorepw);
172 secstorepw = nil; /* just try nvram pw once */
173 }
174 }else{
175 /*
176 rerrstr(err, sizeof err);
177 if(*err)
178 fprint(2, "factotum: havesecstore: %r\n");
179 */
180 }
181 }
182
183 postmountsrv(&fs, service, mtpt, MBEFORE);
184 if(service){
185 nulldir(&d);
186 d.mode = 0666;
187 s = emalloc(10+strlen(service));
188 strcpy(s, "/srv/");
189 strcat(s, service);
190 if(dirwstat(s, &d) < 0)
191 fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
192 free(s);
193 }
194 exits(nil);
195 }
196
197 char *pmsg = "Warning! %s can't protect itself from debugging: %r\n";
198 char *smsg = "Warning! %s can't turn off swapping: %r\n";
199
200 /* don't allow other processes to debug us and steal keys */
201 static void
private(void)202 private(void)
203 {
204 int fd;
205 char buf[64];
206
207 snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
208 fd = open(buf, OWRITE);
209 if(fd < 0){
210 fprint(2, pmsg, argv0);
211 return;
212 }
213 if(fprint(fd, "private") < 0)
214 fprint(2, pmsg, argv0);
215 if(fprint(fd, "noswap") < 0)
216 fprint(2, smsg, argv0);
217 close(fd);
218 }
219
220 static void
notifyf(void *,char * s)221 notifyf(void*, char *s)
222 {
223 if(strncmp(s, "interrupt", 9) == 0)
224 noted(NCONT);
225 noted(NDFLT);
226 }
227
228 enum
229 {
230 Qroot,
231 Qfactotum,
232 Qrpc,
233 Qkeylist,
234 Qprotolist,
235 Qconfirm,
236 Qlog,
237 Qctl,
238 Qneedkey,
239 };
240
241 Qid
mkqid(int type,int path)242 mkqid(int type, int path)
243 {
244 Qid q;
245
246 q.type = type;
247 q.path = path;
248 q.vers = 0;
249 return q;
250 }
251
252 static void
fsattach(Req * r)253 fsattach(Req *r)
254 {
255 r->fid->qid = mkqid(QTDIR, Qroot);
256 r->ofcall.qid = r->fid->qid;
257 respond(r, nil);
258 }
259
260 static struct {
261 char *name;
262 int qidpath;
263 ulong perm;
264 } dirtab[] = {
265 "confirm", Qconfirm, 0600|DMEXCL, /* we know this is slot #0 below */
266 "needkey", Qneedkey, 0600|DMEXCL, /* we know this is slot #1 below */
267 "ctl", Qctl, 0644,
268 "rpc", Qrpc, 0666,
269 "proto", Qprotolist, 0444,
270 "log", Qlog, 0400|DMEXCL,
271 };
272 static int inuse[nelem(dirtab)];
273 int *confirminuse = &inuse[0];
274 int *needkeyinuse = &inuse[1];
275
276 static void
fillstat(Dir * dir,char * name,int type,int path,ulong perm)277 fillstat(Dir *dir, char *name, int type, int path, ulong perm)
278 {
279 dir->name = estrdup(name);
280 dir->uid = estrdup(owner);
281 dir->gid = estrdup(owner);
282 dir->mode = perm;
283 dir->length = 0;
284 dir->qid = mkqid(type, path);
285 dir->atime = time(0);
286 dir->mtime = time(0);
287 dir->muid = estrdup("");
288 }
289
290 static int
rootdirgen(int n,Dir * dir,void *)291 rootdirgen(int n, Dir *dir, void*)
292 {
293 if(n > 0)
294 return -1;
295 fillstat(dir, "factotum", QTDIR, Qfactotum, DMDIR|0555);
296 return 0;
297 }
298
299 static int
fsdirgen(int n,Dir * dir,void *)300 fsdirgen(int n, Dir *dir, void*)
301 {
302 if(n >= nelem(dirtab))
303 return -1;
304 fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
305 return 0;
306 }
307
308 static char*
fswalk1(Fid * fid,char * name,Qid * qid)309 fswalk1(Fid *fid, char *name, Qid *qid)
310 {
311 int i;
312
313 switch((ulong)fid->qid.path){
314 default:
315 return "cannot happen";
316 case Qroot:
317 if(strcmp(name, "factotum") == 0){
318 *qid = mkqid(QTDIR, Qfactotum);
319 fid->qid = *qid;
320 return nil;
321 }
322 if(strcmp(name, "..") == 0){
323 *qid = fid->qid;
324 return nil;
325 }
326 return "not found";
327 case Qfactotum:
328 for(i=0; i<nelem(dirtab); i++)
329 if(strcmp(name, dirtab[i].name) == 0){
330 *qid = mkqid(0, dirtab[i].qidpath);
331 fid->qid = *qid;
332 return nil;
333 }
334 if(strcmp(name, "..") == 0){
335 *qid = mkqid(QTDIR, Qroot);
336 fid->qid = *qid;
337 return nil;
338 }
339 return "not found";
340 }
341 }
342
343 static void
fsstat(Req * r)344 fsstat(Req *r)
345 {
346 int i;
347 ulong path;
348
349 path = r->fid->qid.path;
350 if(path == Qroot){
351 fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
352 respond(r, nil);
353 return;
354 }
355 if(path == Qfactotum){
356 fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
357 respond(r, nil);
358 return;
359 }
360 for(i=0; i<nelem(dirtab); i++)
361 if(dirtab[i].qidpath == path){
362 fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
363 respond(r, nil);
364 return;
365 }
366 respond(r, "file not found");
367 }
368
369 static void
fsopen(Req * r)370 fsopen(Req *r)
371 {
372 int i, *p, perm;
373 static int need[4] = {4, 2, 6, 1};
374 int n;
375 Fsstate *fss;
376
377 p = nil;
378 for(i=0; i<nelem(dirtab); i++)
379 if(dirtab[i].qidpath == r->fid->qid.path)
380 break;
381 if(i < nelem(dirtab)){
382 if(dirtab[i].perm & DMEXCL)
383 p = &inuse[i];
384 if(strcmp(r->fid->uid, owner) == 0)
385 perm = dirtab[i].perm>>6;
386 else
387 perm = dirtab[i].perm;
388 }else
389 perm = 5;
390
391 n = need[r->ifcall.mode&3];
392 if((r->ifcall.mode&~(3|OTRUNC)) || ((perm&n) != n)){
393 respond(r, "permission denied");
394 return;
395 }
396 if(p){
397 if(*p){
398 respond(r, "file in use");
399 return;
400 }
401 (*p)++;
402 }
403
404 r->fid->aux = fss = emalloc(sizeof(Fsstate));
405 fss->phase = Notstarted;
406 fss->sysuser = r->fid->uid;
407 fss->attr = nil;
408 strcpy(fss->err, "factotum/fs.c no error");
409 respond(r, nil);
410 }
411
412 static void
fsdestroyfid(Fid * fid)413 fsdestroyfid(Fid *fid)
414 {
415 int i;
416 Fsstate *fss;
417
418 if(fid->omode != -1){
419 for(i=0; i<nelem(dirtab); i++)
420 if(dirtab[i].qidpath == fid->qid.path)
421 if(dirtab[i].perm&DMEXCL)
422 inuse[i] = 0;
423 }
424
425 fss = fid->aux;
426 if(fss == nil)
427 return;
428 if(fss->ps)
429 (*fss->proto->close)(fss);
430 _freeattr(fss->attr);
431 free(fss);
432 }
433
434 static int
readlist(int off,int (* gen)(int,char *,uint,Fsstate *),Req * r,Fsstate * fss)435 readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
436 {
437 char *a, *ea;
438 int n;
439
440 a = r->ofcall.data;
441 ea = a+r->ifcall.count;
442 for(;;){
443 n = (*gen)(off, a, ea-a, fss);
444 if(n == 0){
445 r->ofcall.count = a - (char*)r->ofcall.data;
446 return off;
447 }
448 a += n;
449 off++;
450 }
451 }
452
453 enum { Nearend = 2, }; /* at least room for \n and NUL */
454
455 /* result in `a', of `n' bytes maximum */
456 static int
keylist(int i,char * a,uint n,Fsstate * fss)457 keylist(int i, char *a, uint n, Fsstate *fss)
458 {
459 int wb;
460 Keyinfo ki;
461 Key *k;
462 static char zero[Nearend];
463
464 k = nil;
465 mkkeyinfo(&ki, fss, nil);
466 ki.attr = nil;
467 ki.skip = i;
468 ki.usedisabled = 1;
469 if(findkey(&k, &ki, "") != RpcOk)
470 return 0;
471
472 memset(a + n - Nearend, 0, Nearend);
473 wb = snprint(a, n, "key %A %N\n", k->attr, k->privattr);
474 closekey(k);
475 if (wb >= n - 1 && a[n - 2] != '\n' && a[n - 2] != '\0') {
476 /* line won't fit in `a', so just truncate */
477 strcpy(a + n - 2, "\n");
478 return 0;
479 }
480 return wb;
481 }
482
483 static int
protolist(int i,char * a,uint n,Fsstate * fss)484 protolist(int i, char *a, uint n, Fsstate *fss)
485 {
486 USED(fss);
487
488 if(i >= nelem(prototab)-1)
489 return 0;
490 if(strlen(prototab[i]->name)+1 > n)
491 return 0;
492 n = strlen(prototab[i]->name)+1;
493 memmove(a, prototab[i]->name, n-1);
494 a[n-1] = '\n';
495 return n;
496 }
497
498 static void
fsread(Req * r)499 fsread(Req *r)
500 {
501 Fsstate *s;
502
503 s = r->fid->aux;
504 switch((ulong)r->fid->qid.path){
505 default:
506 respond(r, "bug in fsread");
507 break;
508 case Qroot:
509 dirread9p(r, rootdirgen, nil);
510 respond(r, nil);
511 break;
512 case Qfactotum:
513 dirread9p(r, fsdirgen, nil);
514 respond(r, nil);
515 break;
516 case Qrpc:
517 rpcread(r);
518 break;
519 case Qneedkey:
520 needkeyread(r);
521 break;
522 case Qconfirm:
523 confirmread(r);
524 break;
525 case Qlog:
526 logread(r);
527 break;
528 case Qctl:
529 s->listoff = readlist(s->listoff, keylist, r, s);
530 respond(r, nil);
531 break;
532 case Qprotolist:
533 s->listoff = readlist(s->listoff, protolist, r, s);
534 respond(r, nil);
535 break;
536 }
537 }
538
539 static void
fswrite(Req * r)540 fswrite(Req *r)
541 {
542 int ret;
543 char err[ERRMAX], *s;
544
545 switch((ulong)r->fid->qid.path){
546 default:
547 respond(r, "bug in fswrite");
548 break;
549 case Qrpc:
550 rpcwrite(r);
551 break;
552 case Qneedkey:
553 case Qconfirm:
554 case Qctl:
555 s = emalloc(r->ifcall.count+1);
556 memmove(s, r->ifcall.data, r->ifcall.count);
557 s[r->ifcall.count] = '\0';
558 switch((ulong)r->fid->qid.path){
559 default:
560 abort();
561 case Qneedkey:
562 ret = needkeywrite(s);
563 break;
564 case Qconfirm:
565 ret = confirmwrite(s);
566 break;
567 case Qctl:
568 ret = ctlwrite(s, 0);
569 break;
570 }
571 free(s);
572 if(ret < 0){
573 rerrstr(err, sizeof err);
574 respond(r, err);
575 }else{
576 r->ofcall.count = r->ifcall.count;
577 respond(r, nil);
578 }
579 break;
580 }
581 }
582
583 static void
fsflush(Req * r)584 fsflush(Req *r)
585 {
586 confirmflush(r->oldreq);
587 needkeyflush(r->oldreq);
588 logflush(r->oldreq);
589 respond(r, nil);
590 }
591
592 Srv fs = {
593 .attach= fsattach,
594 .walk1= fswalk1,
595 .open= fsopen,
596 .read= fsread,
597 .write= fswrite,
598 .stat= fsstat,
599 .flush= fsflush,
600 .destroyfid= fsdestroyfid,
601 };
602
603