Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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*
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
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
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
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
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
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
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
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
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
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