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