xref: /plan9/sys/src/cmd/auth/factotum/util.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
1 #include "dat.h"
2 
3 static char secstore[100];   /* server name */
4 
5 /* bind in the default network and cs */
6 static int
bindnetcs(void)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
_authdial(char * net,char * authdom)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
secdial(void)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*
promptforkey(char * params)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
sendkey(Attr * attr)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
askuser(char * params)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
canusekey(Fsstate * fss,Key * k)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
closekey(Key * k)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*
pstring(uchar * p,uchar * e,char * s)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*
pcarray(uchar * p,uchar * e,uchar * s,uint n)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*
convAI2M(AuthInfo * ai,uchar * p,int n)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
failure(Fsstate * s,char * fmt,...)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
hasqueries(Attr * a)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
ignoreattr(char * s)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*
mkkeyinfo(Keyinfo * k,Fsstate * fss,Attr * attr)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
findkey(Key ** ret,Keyinfo * ki,char * fmt,...)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
findp9authkey(Key ** k,Fsstate * fss)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*
findproto(char * name)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*
getnvramkey(int flag,char ** secstorepw)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
isclient(char * role)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
hasname(Attr * a0,Attr * a1,char * name)520 hasname(Attr *a0, Attr *a1, char *name)
521 {
522 	return _findattr(a0, name) || _findattr(a1, name);
523 }
524 
525 static int
hasnameval(Attr * a0,Attr * a1,char * name,char * val)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
matchattr(Attr * pat,Attr * a0,Attr * a1)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
memrandom(void * p,int n)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
initcap(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*
mkcap(char * from,char * to)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
phaseerror(Fsstate * s,char * op)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*
phasename(Fsstate * fss,int phase,char * tmp)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
outin(char * prompt,char * def,int len)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
promptforhostowner(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*
estrappend(char * s,char * fmt,...)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*
readcons(char * prompt,char * def,int raw)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
replacekey(Key * kn,int before)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*
safecpy(char * to,char * from,int n)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*
setattr(Attr * a,char * fmt,...)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*
setattrs(Attr * a,Attr * b)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
setmalloctaghere(void * v)887 setmalloctaghere(void *v)
888 {
889 	setmalloctag(v, getcallerpc(&v));
890 }
891 
892 Attr*
sortattr(Attr * a)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
toosmall(Fsstate * fss,uint n)944 toosmall(Fsstate *fss, uint n)
945 {
946 	fss->rpc.nwant = n;
947 	return RpcToosmall;
948 }
949 
950 void
writehostowner(char * owner)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
attrnamefmt(Fmt * fmt)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
disablekey(Key * k)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 }
1004