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
static char secstore[100];   /* server name */
4
 
5
/* bind in the default network and cs */
6
static int
7
bindnetcs(void)
8
{
9
	int srvfd;
10
 
11
	if(access("/net/tcp", AEXIST) < 0)
12
		bind("#I", "/net", MBEFORE);
13
 
14
	if(access("/net/cs", AEXIST) < 0){
15
		if((srvfd = open("#s/cs", ORDWR)) >= 0){
16
			if(mount(srvfd, -1, "/net", MBEFORE, "") >= 0)
17
				return 0;
18
			close(srvfd);
19
		}
20
		return -1;
21
	}
22
	return 0;
23
}
24
 
25
int
26
_authdial(char *net, char *authdom)
27
{
28
	int fd, vanilla;
29
 
30
	vanilla = net==nil || strcmp(net, "/net")==0;
31
 
32
	if(!vanilla || bindnetcs()>=0)
33
		return authdial(net, authdom);
34
 
35
	/*
36
	 * If we failed to mount /srv/cs, assume that
37
	 * we're still bootstrapping the system and dial
38
	 * the one auth server passed to us on the command line.
39
	 * In normal operation, it is important *not* to do this,
40
	 * because the bootstrap auth server is only good for
41
	 * a single auth domain.
42
	 *
43
	 * The ticket request code should really check the
44
	 * remote authentication domain too.
45
	 */
46
 
47
	/* use the auth server passed to us as an arg */
48
	if(authaddr == nil)
49
		return -1;
50
	fd = dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
51
	if(fd >= 0)
52
		return fd;
53
	return dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
54
}
55
 
56
int
57
secdial(void)
58
{
59
	char *p, buf[80], *f[3];
60
	int fd, nf;
61
 
62
	p = secstore; /* take it from writehostowner, if set there */
63
	if(*p == 0)	  /* else use the authserver */
64
		p = "$auth";
65
 
66
	if(bindnetcs() >= 0)
67
		return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
68
 
69
	/* translate $auth ourselves.
70
	 * authaddr is something like il!host!566 or tcp!host!567.
71
	 * extract host, accounting for a change of format to something
72
	 * like il!host or tcp!host or host.
73
	 */
74
	if(strcmp(p, "$auth")==0){
75
		if(authaddr == nil)
76
			return -1;
77
		safecpy(buf, authaddr, sizeof buf);
78
		nf = getfields(buf, f, nelem(f), 0, "!");
79
		switch(nf){
80
		default:
81
			return -1;
82
		case 1:
83
			p = f[0];
84
			break;
85
		case 2:
86
		case 3:
87
			p = f[1];
88
			break;
89
		}
90
	}
91
	fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
92
	if(fd >= 0)
93
		return fd;
94
	return -1;
95
}
96
/*
97
 *  prompt user for a key.  don't care about memory leaks, runs standalone
98
 */
99
static Attr*
100
promptforkey(char *params)
101
{
102
	char *v;
103
	int fd;
104
	Attr *a, *attr;
105
	char *def;
106
 
107
	fd = open("/dev/cons", ORDWR);
108
	if(fd < 0)
109
		sysfatal("opening /dev/cons: %r");
110
 
111
	attr = _parseattr(params);
112
	fprint(fd, "\n!Adding key:");
113
	for(a=attr; a; a=a->next)
114
		if(a->type != AttrQuery && a->name[0] != '!')
115
			fprint(fd, " %q=%q", a->name, a->val);
116
	fprint(fd, "\n");
117
 
118
	for(a=attr; a; a=a->next){
119
		v = a->name;
120
		if(a->type != AttrQuery || v[0]=='!')
121
			continue;
122
		def = nil;
123
		if(strcmp(v, "user") == 0)
124
			def = getuser();
125
		a->val = readcons(v, def, 0);
126
		if(a->val == nil)
127
			sysfatal("user terminated key input");
128
		a->type = AttrNameval;
129
	}
130
	for(a=attr; a; a=a->next){
131
		v = a->name;
132
		if(a->type != AttrQuery || v[0]!='!')
133
			continue;
134
		def = nil;
135
		if(strcmp(v+1, "user") == 0)
136
			def = getuser();
137
		a->val = readcons(v+1, def, 1);
138
		if(a->val == nil)
139
			sysfatal("user terminated key input");
140
		a->type = AttrNameval;
141
	}
142
	fprint(fd, "!\n");
143
	close(fd);
144
	return attr;
145
}
146
 
147
/*
148
 *  send a key to the mounted factotum
149
 */
150
static int
151
sendkey(Attr *attr)
152
{
153
	int fd, rv;
154
	char buf[1024];
155
 
156
	fd = open("/mnt/factotum/ctl", ORDWR);
157
	if(fd < 0)
158
		sysfatal("opening /mnt/factotum/ctl: %r");
159
	rv = fprint(fd, "key %A\n", attr);
160
	read(fd, buf, sizeof buf);
161
	close(fd);
162
	return rv;
163
}
164
 
165
/* askuser */
166
void
167
askuser(char *params)
168
{
169
	Attr *attr;
170
 
171
	attr = promptforkey(params);
172
	if(attr == nil)
173
		sysfatal("no key supplied");
174
	if(sendkey(attr) < 0)
175
		sysfatal("sending key to factotum: %r");
176
}
177
 
178
ulong conftaggen;
179
int
180
canusekey(Fsstate *fss, Key *k)
181
{
182
	int i;
183
 
184
	if(_strfindattr(k->attr, "confirm")){
185
		for(i=0; i<fss->nconf; i++)
186
			if(fss->conf[i].key == k)
187
				return fss->conf[i].canuse;
188
		if(fss->nconf%16 == 0)
189
			fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
190
		fss->conf[fss->nconf].key = k;
191
		k->ref++;
192
		fss->conf[fss->nconf].canuse = -1;
193
		fss->conf[fss->nconf].tag = conftaggen++;
194
		fss->nconf++;
195
		return -1;
196
	}
197
	return 1;
198
}
199
 
200
/* closekey */
201
void
202
closekey(Key *k)
203
{
204
	if(k == nil)
205
		return;
206
	if(--k->ref != 0)
207
		return;
208
	if(k->proto && k->proto->closekey)
209
		(*k->proto->closekey)(k);
210
	_freeattr(k->attr);
211
	_freeattr(k->privattr);
212
	k->attr = (void*)~1;
213
	k->privattr = (void*)~1;
214
	k->proto = nil;
215
	free(k);
216
}
217
 
218
static uchar*
219
pstring(uchar *p, uchar *e, char *s)
220
{
221
	uint n;
222
 
223
	if(p == nil)
224
		return nil;
225
	if(s == nil)
226
		s = "";
227
	n = strlen(s);
228
	if(p+n+BIT16SZ >= e)
229
		return nil;
230
	PBIT16(p, n);
231
	p += BIT16SZ;
232
	memmove(p, s, n);
233
	p += n;
234
	return p;
235
}
236
 
237
static uchar*
238
pcarray(uchar *p, uchar *e, uchar *s, uint n)
239
{
240
	if(p == nil)
241
		return nil;
242
	if(s == nil){
243
		if(n > 0)
244
			sysfatal("pcarray");
245
		s = (uchar*)"";
246
	}
247
	if(p+n+BIT16SZ >= e)
248
		return nil;
249
	PBIT16(p, n);
250
	p += BIT16SZ;
251
	memmove(p, s, n);
252
	p += n;
253
	return p;
254
}
255
 
256
uchar*
257
convAI2M(AuthInfo *ai, uchar *p, int n)
258
{
259
	uchar *e = p+n;
260
 
261
	p = pstring(p, e, ai->cuid);
262
	p = pstring(p, e, ai->suid);
263
	p = pstring(p, e, ai->cap);
264
	p = pcarray(p, e, ai->secret, ai->nsecret);
265
	return p;
266
}
267
 
268
int
269
failure(Fsstate *s, char *fmt, ...)
270
{
271
	char e[ERRMAX];
272
	va_list arg;
273
 
274
	if(fmt == nil)
275
		rerrstr(s->err, sizeof(s->err));
276
	else {
277
		va_start(arg, fmt);
278
		vsnprint(e, sizeof e, fmt, arg);
279
		va_end(arg);
280
		strecpy(s->err, s->err+sizeof(s->err), e);
281
		werrstr(e);
282
	}
283
	flog("%d: failure %s", s->seqnum, s->err);
284
	return RpcFailure;
285
}
286
 
287
static int
288
hasqueries(Attr *a)
289
{
290
	for(; a; a=a->next)
291
		if(a->type == AttrQuery)
292
			return 1;
293
	return 0;
294
}
295
 
296
char *ignored[] = {
297
	"role",
298
	"disabled",
299
};
300
 
301
static int
302
ignoreattr(char *s)
303
{
304
	int i;
305
 
306
	for(i=0; i<nelem(ignored); i++)
307
		if(strcmp(ignored[i], s)==0)
308
			return 1;
309
	return 0;
310
}
311
 
312
Keyinfo*
313
mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
314
{
315
	memset(k, 0, sizeof *k);
316
	k->fss = fss;
317
	k->user = fss->sysuser;
318
	if(attr)
319
		k->attr = attr;
320
	else
321
		k->attr = fss->attr;
322
	return k;
323
}
324
 
325
int
326
findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
327
{
328
	int i, s, nmatch;
329
	char buf[1024], *p, *who;
330
	va_list arg;
331
	Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
332
	Key *k;
333
 
334
	*ret = nil;
335
 
336
	who = ki->user;
337
	attr0 = ki->attr;
338
	if(fmt){
339
		va_start(arg, fmt);
340
		vseprint(buf, buf+sizeof buf, fmt, arg);
341
		va_end(arg);
342
		attr1 = _parseattr(buf);
343
	}else
344
		attr1 = nil;
345
 
346
	if(who && strcmp(who, owner) == 0)
347
		who = nil;
348
 
349
	if(who){
350
		snprint(buf, sizeof buf, "owner=%q", who);
351
		attr2 = _parseattr(buf);
352
		attr3 = _parseattr("owner=*");
353
	}else
354
		attr2 = attr3 = nil;
355
 
356
	p = _strfindattr(attr0, "proto");
357
	if(p == nil)
358
		p = _strfindattr(attr1, "proto");
359
	if(p && findproto(p) == nil){
360
		werrstr("unknown protocol %s", p);
361
		_freeattr(attr1);
362
		_freeattr(attr2);
363
		_freeattr(attr3);
364
		return failure(ki->fss, nil);
365
	}
366
 
367
	nmatch = 0; 
368
	for(i=0; i<ring->nkey; i++){
369
		k = ring->key[i];
370
		if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
371
			continue;
372
		if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
373
			/* check ownership */
374
			if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
375
				continue;
376
			if(nmatch++ < ki->skip)
377
				continue;
378
			if(!ki->noconf){
379
				switch(canusekey(ki->fss, k)){
380
				case -1:
381
					_freeattr(attr1);
382
					return RpcConfirm;
383
				case 0:
384
					continue;
385
				case 1:
386
					break;
387
				}
388
			}
389
			_freeattr(attr1);
390
			_freeattr(attr2);
391
			_freeattr(attr3);
392
			k->ref++;
393
			*ret = k;
394
			return RpcOk;
395
		}
396
	}
397
	flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
398
	werrstr("no key matches %A %A", attr0, attr1);
399
	_freeattr(attr2);
400
	_freeattr(attr3);
401
	s = RpcFailure;
402
	if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
403
		if(nmatch == 0){
404
			attr0 = _copyattr(attr0);
405
			for(l=&attr0; *l; l=&(*l)->next)
406
				;
407
			*l = attr1;
408
			for(l=&attr0; *l; ){
409
				if(ignoreattr((*l)->name)){
410
					a = *l;
411
					*l = (*l)->next;
412
					a->next = nil;
413
					_freeattr(a);
414
				}else
415
					l = &(*l)->next;
416
			}
417
			attr0 = sortattr(attr0);
418
			snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
419
			_freeattr(attr0);
420
			attr1 = nil;	/* attr1 was linked to attr0 */
421
		}else
422
			ki->fss->keyinfo[0] = '\0';
423
		s = RpcNeedkey;
424
	}
425
	_freeattr(attr1);
426
	if(s == RpcFailure)
427
		return failure(ki->fss, nil);	/* loads error string */
428
	return s;
429
}
430
 
431
int
432
findp9authkey(Key **k, Fsstate *fss)
433
{
434
	char *dom;
435
	Keyinfo ki;
436
 
437
	/*
438
	 * We don't use fss->attr here because we don't
439
	 * care about what the user name is set to, for instance.
440
	 */
441
	mkkeyinfo(&ki, fss, nil);
442
	ki.attr = nil;
443
	ki.user = nil;
444
	if(dom = _strfindattr(fss->attr, "dom"))
445
		return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
446
	else
447
		return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
448
}
449
 
450
Proto*
451
findproto(char *name)
452
{
453
	int i;
454
 
455
	for(i=0; prototab[i]; i++)
456
		if(strcmp(name, prototab[i]->name) == 0)
457
			return prototab[i];
458
	return nil;
459
}
460
 
461
char*
462
getnvramkey(int flag, char **secstorepw)
463
{
464
	char *s;
465
	Nvrsafe safe;
466
	char spw[CONFIGLEN+1];
467
	int i;
468
 
469
	memset(&safe, 0, sizeof safe);
470
	/*
471
	 * readnvram can return -1 meaning nvram wasn't written,
472
	 * but safe still holds good data.
473
	 */
474
	if(readnvram(&safe, flag)<0 && safe.authid[0]==0) 
475
		return nil;
476
 
477
	/*
478
	 *  we're using the config area to hold the secstore
479
	 *  password.  if there's anything there, return it.
480
	 */
481
	memmove(spw, safe.config, CONFIGLEN);
482
	spw[CONFIGLEN] = 0;
483
	if(spw[0] != 0)
484
		*secstorepw = estrdup(spw);
485
 
486
	/*
487
	 *  only use nvram key if it is non-zero
488
	 */
489
	for(i = 0; i < DESKEYLEN; i++)
490
		if(safe.machkey[i] != 0)
491
			break;
492
	if(i == DESKEYLEN)
493
		return nil;
494
 
495
	s = emalloc(512);
496
	fmtinstall('H', encodefmt);
497
	snprint(s, 512, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______", 
498
		safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
499
	writehostowner(safe.authid);
500
 
501
	return s;
502
}
503
 
504
int
505
isclient(char *role)
506
{
507
	if(role == nil){
508
		werrstr("role not specified");
509
		return -1;
510
	}
511
	if(strcmp(role, "server") == 0)
512
		return 0;
513
	if(strcmp(role, "client") == 0)
514
		return 1;
515
	werrstr("unknown role %q", role);
516
	return -1;
517
}
518
 
519
static int
520
hasname(Attr *a0, Attr *a1, char *name)
521
{
522
	return _findattr(a0, name) || _findattr(a1, name);
523
}
524
 
525
static int
526
hasnameval(Attr *a0, Attr *a1, char *name, char *val)
527
{
528
	Attr *a;
529
 
530
	for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
531
		if(strcmp(a->val, val) == 0)
532
			return 1;
533
	for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
534
		if(strcmp(a->val, val) == 0)
535
			return 1;
536
	return 0;
537
}
538
 
539
int
540
matchattr(Attr *pat, Attr *a0, Attr *a1)
541
{
542
	int type;
543
 
544
	for(; pat; pat=pat->next){
545
		type = pat->type;
546
		if(ignoreattr(pat->name))
547
			type = AttrDefault;
548
		switch(type){
549
		case AttrQuery:		/* name=something be present */
550
			if(!hasname(a0, a1, pat->name))
551
				return 0;
552
			break;
553
		case AttrNameval:	/* name=val must be present */
554
			if(!hasnameval(a0, a1, pat->name, pat->val))
555
				return 0;
556
			break;
557
		case AttrDefault:	/* name=val must be present if name=anything is present */
558
			if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
559
				return 0;
560
			break;
561
		}
562
	}
563
	return 1;		
564
}
565
 
566
void
567
memrandom(void *p, int n)
568
{
569
	uchar *cp;
570
 
571
	for(cp = (uchar*)p; n > 0; n--)
572
		*cp++ = fastrand();
573
}
574
 
575
/*
576
 *  keep caphash fd open since opens of it could be disabled
577
 */
578
static int caphashfd;
579
 
580
void
581
initcap(void)
582
{
583
	caphashfd = open("#¤/caphash", OWRITE);
584
//	if(caphashfd < 0)
585
//		fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
586
}
587
 
588
/*
589
 *  create a change uid capability 
590
 */
591
char*
592
mkcap(char *from, char *to)
593
{
594
	uchar rand[20];
595
	char *cap;
596
	char *key;
597
	int nfrom, nto, ncap;
598
	uchar hash[SHA1dlen];
599
 
600
	if(caphashfd < 0)
601
		return nil;
602
 
603
	/* create the capability */
604
	nto = strlen(to);
605
	nfrom = strlen(from);
606
	ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1;
607
	cap = emalloc(ncap);
608
	snprint(cap, ncap, "%s@%s", from, to);
609
	memrandom(rand, sizeof(rand));
610
	key = cap+nfrom+1+nto+1;
611
	enc64(key, sizeof(rand)*3, rand, sizeof(rand));
612
 
613
	/* hash the capability */
614
	hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
615
 
616
	/* give the kernel the hash */
617
	key[-1] = '@';
618
	if(write(caphashfd, hash, SHA1dlen) < 0){
619
		free(cap);
620
		return nil;
621
	}
622
 
623
	return cap;
624
}
625
 
626
int
627
phaseerror(Fsstate *s, char *op)
628
{
629
	char tmp[32];
630
 
631
	werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));	
632
	return RpcPhase;
633
}
634
 
635
char*
636
phasename(Fsstate *fss, int phase, char *tmp)
637
{
638
	char *name;
639
 
640
	if(fss->phase == Broken)
641
		name = "Broken";
642
	else if(phase == Established)
643
		name = "Established";
644
	else if(phase == Notstarted)
645
		name = "Notstarted";
646
	else if(phase < 0 || phase >= fss->maxphase
647
	|| (name = fss->phasename[phase]) == nil){
648
		sprint(tmp, "%d", phase);
649
		name = tmp;
650
	}
651
	return name;
652
}
653
 
654
static int
655
outin(char *prompt, char *def, int len)
656
{
657
	char *s;
658
 
659
	s = readcons(prompt, def, 0);
660
	if(s == nil)
661
		return -1;
662
	if(s == nil)
663
		sysfatal("s==nil???");
664
	strncpy(def, s, len);
665
	def[len-1] = 0;
666
	free(s);
667
	return strlen(def);
668
}
669
 
670
/*
671
 *  get host owner and set it
672
 */
673
void
674
promptforhostowner(void)
675
{
676
	char owner[64], *p;
677
 
678
	/* hack for bitsy; can't prompt during boot */
679
	if(p = getenv("user")){
680
		writehostowner(p);
681
		free(p);
682
		return;
683
	}
684
	free(p);
685
 
686
	strcpy(owner, "none");
687
	do{
688
		outin("user", owner, sizeof(owner));
689
	} while(*owner == 0);
690
	writehostowner(owner);
691
}
692
 
693
char*
694
estrappend(char *s, char *fmt, ...)
695
{
696
	char *t;
697
	va_list arg;
698
 
699
	va_start(arg, fmt);
700
	t = vsmprint(fmt, arg);
701
	if(t == nil)
702
		sysfatal("out of memory");
703
	va_end(arg);
704
	s = erealloc(s, strlen(s)+strlen(t)+1);
705
	strcat(s, t);
706
	free(t);
707
	return s;
708
}
709
 
710
 
711
/*
712
 *  prompt for a string with a possible default response
713
 */
714
char*
715
readcons(char *prompt, char *def, int raw)
716
{
717
	int fdin, fdout, ctl, n;
718
	char line[10];
719
	char *s;
720
 
721
	fdin = open("/dev/cons", OREAD);
722
	if(fdin < 0)
723
		fdin = 0;
724
	fdout = open("/dev/cons", OWRITE);
725
	if(fdout < 0)
726
		fdout = 1;
727
	if(def != nil)
728
		fprint(fdout, "%s[%s]: ", prompt, def);
729
	else
730
		fprint(fdout, "%s: ", prompt);
731
	if(raw){
732
		ctl = open("/dev/consctl", OWRITE);
733
		if(ctl >= 0)
734
			write(ctl, "rawon", 5);
735
	} else
736
		ctl = -1;
737
	s = estrdup("");
738
	for(;;){
739
		n = read(fdin, line, 1);
740
		if(n == 0){
741
		Error:
742
			close(fdin);
743
			close(fdout);
744
			if(ctl >= 0)
745
				close(ctl);
746
			free(s);
747
			return nil;
748
		}
749
		if(n < 0)
750
			goto Error;
751
		if(line[0] == 0x7f)
752
			goto Error;
753
		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
754
			if(raw){
755
				write(ctl, "rawoff", 6);
756
				write(fdout, "\n", 1);
757
			}
758
			close(ctl);
759
			close(fdin);
760
			close(fdout);
761
			if(*s == 0 && def != nil)
762
				s = estrappend(s, "%s", def);
763
			return s;
764
		}
765
		if(line[0] == '\b'){
766
			if(strlen(s) > 0)
767
				s[strlen(s)-1] = 0;
768
		} else if(line[0] == 0x15) {	/* ^U: line kill */
769
			if(def != nil)
770
				fprint(fdout, "\n%s[%s]: ", prompt, def);
771
			else
772
				fprint(fdout, "\n%s: ", prompt);
773
 
774
			s[0] = 0;
775
		} else {
776
			s = estrappend(s, "%c", line[0]);
777
		}
778
	}
779
}
780
 
781
/*
782
 * Insert a key into the keyring.
783
 * If the public attributes are identical to some other key, replace that one.
784
 */
785
int
786
replacekey(Key *kn, int before)
787
{
788
	int i;
789
	Key *k;
790
 
791
	for(i=0; i<ring->nkey; i++){
792
		k = ring->key[i];
793
		if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
794
			closekey(k);
795
			kn->ref++;
796
			ring->key[i] = kn;
797
			return 0;
798
		}
799
	}
800
	if(ring->nkey%16 == 0)
801
		ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
802
	kn->ref++;
803
	if(before){
804
		memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
805
		ring->key[0] = kn;
806
		ring->nkey++;
807
	}else
808
		ring->key[ring->nkey++] = kn;
809
	return 0;
810
}
811
 
812
char*
813
safecpy(char *to, char *from, int n)
814
{
815
	memset(to, 0, n);
816
	if(n == 1)
817
		return to;
818
	if(from==nil)
819
		sysfatal("safecpy called with from==nil, pc=%#p",
820
			getcallerpc(&to));
821
	strncpy(to, from, n-1);
822
	return to;
823
}
824
 
825
Attr*
826
setattr(Attr *a, char *fmt, ...)
827
{
828
	char buf[1024];
829
	va_list arg;
830
	Attr *b;
831
 
832
	va_start(arg, fmt);
833
	vseprint(buf, buf+sizeof buf, fmt, arg);
834
	va_end(arg);
835
	b = _parseattr(buf);
836
	a = setattrs(a, b);
837
	setmalloctag(a, getcallerpc(&a));
838
	_freeattr(b);
839
	return a;
840
}
841
 
842
/*
843
 *  add attributes in list b to list a.  If any attributes are in
844
 *  both lists, replace those in a by those in b.
845
 */
846
Attr*
847
setattrs(Attr *a, Attr *b)
848
{
849
	int found;
850
	Attr **l, *freea;
851
 
852
	for(; b; b=b->next){
853
		found = 0;
854
		for(l=&a; *l; ){
855
			if(strcmp(b->name, (*l)->name) == 0){
856
				switch(b->type){
857
				case AttrNameval:
858
					if(!found){
859
						found = 1;
860
						free((*l)->val);
861
						(*l)->val = estrdup(b->val);
862
						(*l)->type = AttrNameval;
863
						l = &(*l)->next;
864
					}else{
865
						freea = *l;
866
						*l = (*l)->next;
867
						freea->next = nil;
868
						_freeattr(freea);
869
					}
870
					break;
871
				case AttrQuery:
872
					goto continue2;
873
				}
874
			}else
875
				l = &(*l)->next;
876
		}
877
		if(found == 0){
878
			*l = _mkattr(b->type, b->name, b->val, nil);
879
			setmalloctag(*l, getcallerpc(&a));
880
		}
881
continue2:;
882
	}
883
	return a;		
884
}
885
 
886
void
887
setmalloctaghere(void *v)
888
{
889
	setmalloctag(v, getcallerpc(&v));
890
}
891
 
892
Attr*
893
sortattr(Attr *a)
894
{
895
	int i;
896
	Attr *anext, *a0, *a1, **l;
897
 
898
	if(a == nil || a->next == nil)
899
		return a;
900
 
901
	/* cut list in halves */
902
	a0 = nil;
903
	a1 = nil;
904
	i = 0;
905
	for(; a; a=anext){
906
		anext = a->next;
907
		if(i++%2){
908
			a->next = a0;
909
			a0 = a;
910
		}else{
911
			a->next = a1;
912
			a1 = a;
913
		}
914
	}
915
 
916
	/* sort */
917
	a0 = sortattr(a0);
918
	a1 = sortattr(a1);
919
 
920
	/* merge */
921
	l = &a;
922
	while(a0 || a1){
923
		if(a1==nil){
924
			anext = a0;
925
			a0 = a0->next;
926
		}else if(a0==nil){
927
			anext = a1;
928
			a1 = a1->next;
929
		}else if(strcmp(a0->name, a1->name) < 0){
930
			anext = a0;
931
			a0 = a0->next;
932
		}else{
933
			anext = a1;
934
			a1 = a1->next;
935
		}
936
		*l = anext;
937
		l = &(*l)->next;
938
	}
939
	*l = nil;
940
	return a;
941
}
942
 
943
int
944
toosmall(Fsstate *fss, uint n)
945
{
946
	fss->rpc.nwant = n;
947
	return RpcToosmall;
948
}
949
 
950
void
951
writehostowner(char *owner)
952
{
953
	int fd;
954
	char *s;
955
 
956
	if((s = strchr(owner,'@')) != nil){
957
		*s++ = 0;
958
		strncpy(secstore, s, (sizeof secstore)-1);
959
	}
960
	fd = open("#c/hostowner", OWRITE);
961
	if(fd >= 0){
962
		if(fprint(fd, "%s", owner) < 0)
963
			fprint(2, "factotum: setting #c/hostowner to %q: %r\n",
964
				owner);
965
		close(fd);
966
	}
967
}
968
 
969
int
970
attrnamefmt(Fmt *fmt)
971
{
972
	char *b, buf[1024], *ebuf;
973
	Attr *a;
974
 
975
	ebuf = buf+sizeof buf;
976
	b = buf;
977
	strcpy(buf, " ");
978
	for(a=va_arg(fmt->args, Attr*); a; a=a->next){
979
		if(a->name == nil)
980
			continue;
981
		b = seprint(b, ebuf, " %q?", a->name);
982
	}
983
	return fmtstrcpy(fmt, buf+1);
984
}
985
 
986
void
987
disablekey(Key *k)
988
{
989
	Attr *a;
990
 
991
	if(sflag)	/* not on servers */
992
		return;
993
	for(a=k->attr; a; a=a->next){
994
		if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
995
			return;
996
		if(a->next == nil)
997
			break;
998
	}
999
	if(a)
1000
		a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
1001
	else
1002
		k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil);	/* not reached: always a proto attribute */
1003
}