xref: /plan9/sys/src/cmd/auth/factotum/util.c (revision 6b8bc68243dff965faa99f64fe710965ebee6f8f)
19a747e4fSDavid du Colombier #include "dat.h"
29a747e4fSDavid du Colombier 
39a747e4fSDavid du Colombier static char secstore[100];   /* server name */
49a747e4fSDavid du Colombier 
59a747e4fSDavid du Colombier /* bind in the default network and cs */
69a747e4fSDavid du Colombier static int
79a747e4fSDavid du Colombier bindnetcs(void)
89a747e4fSDavid du Colombier {
99a747e4fSDavid du Colombier 	int srvfd;
109a747e4fSDavid du Colombier 
11d9306527SDavid du Colombier 	if(access("/net/tcp", AEXIST) < 0)
129a747e4fSDavid du Colombier 		bind("#I", "/net", MBEFORE);
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier 	if(access("/net/cs", AEXIST) < 0){
159a747e4fSDavid du Colombier 		if((srvfd = open("#s/cs", ORDWR)) >= 0){
169a747e4fSDavid du Colombier 			if(mount(srvfd, -1, "/net", MBEFORE, "") >= 0)
179a747e4fSDavid du Colombier 				return 0;
189a747e4fSDavid du Colombier 			close(srvfd);
199a747e4fSDavid du Colombier 		}
209a747e4fSDavid du Colombier 		return -1;
219a747e4fSDavid du Colombier 	}
229a747e4fSDavid du Colombier 	return 0;
239a747e4fSDavid du Colombier }
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier int
269a747e4fSDavid du Colombier _authdial(char *net, char *authdom)
279a747e4fSDavid du Colombier {
289a747e4fSDavid du Colombier 	int fd;
299a747e4fSDavid du Colombier 	int vanilla;
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier 	vanilla = net==nil || strcmp(net, "/net")==0;
329a747e4fSDavid du Colombier 
339a747e4fSDavid du Colombier 	if(!vanilla || bindnetcs()>=0)
349a747e4fSDavid du Colombier 		return authdial(net, authdom);
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier 	/* use the auth sever passed to us as an arg */
379a747e4fSDavid du Colombier 	if(authaddr == nil)
389a747e4fSDavid du Colombier 		return -1;
399a747e4fSDavid du Colombier 	fd = dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
409a747e4fSDavid du Colombier 	if(fd >= 0)
419a747e4fSDavid du Colombier 		return fd;
429a747e4fSDavid du Colombier 	return dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
439a747e4fSDavid du Colombier }
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier int
469a747e4fSDavid du Colombier secdial(void)
479a747e4fSDavid du Colombier {
489a747e4fSDavid du Colombier 	char *p, buf[80], *f[3];
499a747e4fSDavid du Colombier 	int fd, nf;
509a747e4fSDavid du Colombier 
519a747e4fSDavid du Colombier 	p = secstore; /* take it from writehostowner, if set there */
529a747e4fSDavid du Colombier 	if(*p == 0)	  /* else use the authserver */
539a747e4fSDavid du Colombier 		p = "$auth";
549a747e4fSDavid du Colombier 
559a747e4fSDavid du Colombier 	if(bindnetcs() >= 0)
569a747e4fSDavid du Colombier 		return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier 	/* translate $auth ourselves.
599a747e4fSDavid du Colombier 	 * authaddr is something like il!host!566 or tcp!host!567.
609a747e4fSDavid du Colombier 	 * extract host, accounting for a change of format to something
619a747e4fSDavid du Colombier 	 * like il!host or tcp!host or host.
629a747e4fSDavid du Colombier 	 */
639a747e4fSDavid du Colombier 	if(strcmp(p, "$auth")==0){
649a747e4fSDavid du Colombier 		if(authaddr == nil)
659a747e4fSDavid du Colombier 			return -1;
669a747e4fSDavid du Colombier 		safecpy(buf, authaddr, sizeof buf);
679a747e4fSDavid du Colombier 		nf = getfields(buf, f, nelem(f), 0, "!");
689a747e4fSDavid du Colombier 		switch(nf){
699a747e4fSDavid du Colombier 		default:
709a747e4fSDavid du Colombier 			return -1;
719a747e4fSDavid du Colombier 		case 1:
729a747e4fSDavid du Colombier 			p = f[0];
739a747e4fSDavid du Colombier 			break;
749a747e4fSDavid du Colombier 		case 2:
759a747e4fSDavid du Colombier 		case 3:
769a747e4fSDavid du Colombier 			p = f[1];
779a747e4fSDavid du Colombier 			break;
789a747e4fSDavid du Colombier 		}
799a747e4fSDavid du Colombier 	}
809a747e4fSDavid du Colombier 	fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
819a747e4fSDavid du Colombier 	if(fd >= 0)
829a747e4fSDavid du Colombier 		return fd;
839a747e4fSDavid du Colombier 	return -1;
849a747e4fSDavid du Colombier }
859a747e4fSDavid du Colombier /*
869a747e4fSDavid du Colombier  *  prompt user for a key.  don't care about memory leaks, runs standalone
879a747e4fSDavid du Colombier  */
889a747e4fSDavid du Colombier static Attr*
899a747e4fSDavid du Colombier promptforkey(char *params)
909a747e4fSDavid du Colombier {
919a747e4fSDavid du Colombier 	char *v;
929a747e4fSDavid du Colombier 	int fd;
939a747e4fSDavid du Colombier 	Attr *a, *attr;
949a747e4fSDavid du Colombier 	char *def;
959a747e4fSDavid du Colombier 
969a747e4fSDavid du Colombier 	fd = open("/dev/cons", ORDWR);
979a747e4fSDavid du Colombier 	if(fd < 0)
989a747e4fSDavid du Colombier 		sysfatal("opening /dev/cons: %r");
999a747e4fSDavid du Colombier 
1009a747e4fSDavid du Colombier 	attr = _parseattr(params);
1019a747e4fSDavid du Colombier 	fprint(fd, "\n!Adding key:");
1029a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next)
1032ebbfa15SDavid du Colombier 		if(a->type != AttrQuery && a->name[0] != '!')
1042ebbfa15SDavid du Colombier 			fprint(fd, " %q=%q", a->name, a->val);
1059a747e4fSDavid du Colombier 	fprint(fd, "\n");
1069a747e4fSDavid du Colombier 
1079a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next){
1082ebbfa15SDavid du Colombier 		v = a->name;
1099a747e4fSDavid du Colombier 		if(a->type != AttrQuery || v[0]=='!')
1109a747e4fSDavid du Colombier 			continue;
1119a747e4fSDavid du Colombier 		def = nil;
1129a747e4fSDavid du Colombier 		if(strcmp(v, "user") == 0)
1139a747e4fSDavid du Colombier 			def = getuser();
1149a747e4fSDavid du Colombier 		a->val = readcons(v, def, 0);
1159a747e4fSDavid du Colombier 		if(a->val == nil)
1169a747e4fSDavid du Colombier 			sysfatal("user terminated key input");
1179a747e4fSDavid du Colombier 		a->type = AttrNameval;
1189a747e4fSDavid du Colombier 	}
1199a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next){
1202ebbfa15SDavid du Colombier 		v = a->name;
1219a747e4fSDavid du Colombier 		if(a->type != AttrQuery || v[0]!='!')
1229a747e4fSDavid du Colombier 			continue;
1239a747e4fSDavid du Colombier 		def = nil;
1249a747e4fSDavid du Colombier 		if(strcmp(v+1, "user") == 0)
1259a747e4fSDavid du Colombier 			def = getuser();
1269a747e4fSDavid du Colombier 		a->val = readcons(v+1, def, 1);
1279a747e4fSDavid du Colombier 		if(a->val == nil)
1289a747e4fSDavid du Colombier 			sysfatal("user terminated key input");
1299a747e4fSDavid du Colombier 		a->type = AttrNameval;
1309a747e4fSDavid du Colombier 	}
1319a747e4fSDavid du Colombier 	fprint(fd, "!\n");
1329a747e4fSDavid du Colombier 	close(fd);
1339a747e4fSDavid du Colombier 	return attr;
1349a747e4fSDavid du Colombier }
1359a747e4fSDavid du Colombier 
1369a747e4fSDavid du Colombier /*
1379a747e4fSDavid du Colombier  *  send a key to the mounted factotum
1389a747e4fSDavid du Colombier  */
1399a747e4fSDavid du Colombier static int
1409a747e4fSDavid du Colombier sendkey(Attr *attr)
1419a747e4fSDavid du Colombier {
1429a747e4fSDavid du Colombier 	int fd, rv;
1439a747e4fSDavid du Colombier 	char buf[1024];
1449a747e4fSDavid du Colombier 
1459a747e4fSDavid du Colombier 	fd = open("/mnt/factotum/ctl", ORDWR);
1469a747e4fSDavid du Colombier 	if(fd < 0)
1479a747e4fSDavid du Colombier 		sysfatal("opening /mnt/factotum/ctl: %r");
1489a747e4fSDavid du Colombier 	rv = fprint(fd, "key %A\n", attr);
1499a747e4fSDavid du Colombier 	read(fd, buf, sizeof buf);
1509a747e4fSDavid du Colombier 	close(fd);
1519a747e4fSDavid du Colombier 	return rv;
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier 
1549a747e4fSDavid du Colombier /* askuser */
1559a747e4fSDavid du Colombier void
1569a747e4fSDavid du Colombier askuser(char *params)
1579a747e4fSDavid du Colombier {
1589a747e4fSDavid du Colombier 	Attr *attr;
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier 	attr = promptforkey(params);
1619a747e4fSDavid du Colombier 	if(attr == nil)
1629a747e4fSDavid du Colombier 		sysfatal("no key supplied");
1639a747e4fSDavid du Colombier 	if(sendkey(attr) < 0)
1649a747e4fSDavid du Colombier 		sysfatal("sending key to factotum: %r");
1659a747e4fSDavid du Colombier }
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier ulong conftaggen;
1689a747e4fSDavid du Colombier int
1699a747e4fSDavid du Colombier canusekey(Fsstate *fss, Key *k)
1709a747e4fSDavid du Colombier {
1719a747e4fSDavid du Colombier 	int i;
1729a747e4fSDavid du Colombier 
1732ebbfa15SDavid du Colombier 	if(_strfindattr(k->attr, "confirm")){
1749a747e4fSDavid du Colombier 		for(i=0; i<fss->nconf; i++)
1759a747e4fSDavid du Colombier 			if(fss->conf[i].key == k)
1769a747e4fSDavid du Colombier 				return fss->conf[i].canuse;
1779a747e4fSDavid du Colombier 		if(fss->nconf%16 == 0)
1789a747e4fSDavid du Colombier 			fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
1799a747e4fSDavid du Colombier 		fss->conf[fss->nconf].key = k;
1809a747e4fSDavid du Colombier 		k->ref++;
1819a747e4fSDavid du Colombier 		fss->conf[fss->nconf].canuse = -1;
1829a747e4fSDavid du Colombier 		fss->conf[fss->nconf].tag = conftaggen++;
1839a747e4fSDavid du Colombier 		fss->nconf++;
1849a747e4fSDavid du Colombier 		return -1;
1859a747e4fSDavid du Colombier 	}
1869a747e4fSDavid du Colombier 	return 1;
1879a747e4fSDavid du Colombier }
1889a747e4fSDavid du Colombier 
1899a747e4fSDavid du Colombier /* closekey */
1909a747e4fSDavid du Colombier void
1919a747e4fSDavid du Colombier closekey(Key *k)
1929a747e4fSDavid du Colombier {
1939a747e4fSDavid du Colombier 	if(k == nil)
1949a747e4fSDavid du Colombier 		return;
1959a747e4fSDavid du Colombier 	if(--k->ref != 0)
1969a747e4fSDavid du Colombier 		return;
197d9306527SDavid du Colombier 	if(k->proto && k->proto->closekey)
198d9306527SDavid du Colombier 		(*k->proto->closekey)(k);
1999a747e4fSDavid du Colombier 	_freeattr(k->attr);
2009a747e4fSDavid du Colombier 	_freeattr(k->privattr);
2019a747e4fSDavid du Colombier 	k->attr = (void*)~1;
2029a747e4fSDavid du Colombier 	k->privattr = (void*)~1;
2039a747e4fSDavid du Colombier 	k->proto = nil;
2049a747e4fSDavid du Colombier 	free(k);
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier 
2079a747e4fSDavid du Colombier static uchar*
2089a747e4fSDavid du Colombier pstring(uchar *p, uchar *e, char *s)
2099a747e4fSDavid du Colombier {
2109a747e4fSDavid du Colombier 	uint n;
2119a747e4fSDavid du Colombier 
2129a747e4fSDavid du Colombier 	if(p == nil)
2139a747e4fSDavid du Colombier 		return nil;
2149a747e4fSDavid du Colombier 	if(s == nil)
2159a747e4fSDavid du Colombier 		s = "";
2169a747e4fSDavid du Colombier 	n = strlen(s);
2179a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2189a747e4fSDavid du Colombier 		return nil;
2199a747e4fSDavid du Colombier 	PBIT16(p, n);
2209a747e4fSDavid du Colombier 	p += BIT16SZ;
2219a747e4fSDavid du Colombier 	memmove(p, s, n);
2229a747e4fSDavid du Colombier 	p += n;
2239a747e4fSDavid du Colombier 	return p;
2249a747e4fSDavid du Colombier }
2259a747e4fSDavid du Colombier 
2269a747e4fSDavid du Colombier static uchar*
2279a747e4fSDavid du Colombier pcarray(uchar *p, uchar *e, uchar *s, uint n)
2289a747e4fSDavid du Colombier {
2299a747e4fSDavid du Colombier 	if(p == nil)
2309a747e4fSDavid du Colombier 		return nil;
2319a747e4fSDavid du Colombier 	if(s == nil){
2329a747e4fSDavid du Colombier 		if(n > 0)
2339a747e4fSDavid du Colombier 			sysfatal("pcarray");
2349a747e4fSDavid du Colombier 		s = (uchar*)"";
2359a747e4fSDavid du Colombier 	}
2369a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2379a747e4fSDavid du Colombier 		return nil;
2389a747e4fSDavid du Colombier 	PBIT16(p, n);
2399a747e4fSDavid du Colombier 	p += BIT16SZ;
2409a747e4fSDavid du Colombier 	memmove(p, s, n);
2419a747e4fSDavid du Colombier 	p += n;
2429a747e4fSDavid du Colombier 	return p;
2439a747e4fSDavid du Colombier }
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier uchar*
2469a747e4fSDavid du Colombier convAI2M(AuthInfo *ai, uchar *p, int n)
2479a747e4fSDavid du Colombier {
2489a747e4fSDavid du Colombier 	uchar *e = p+n;
2499a747e4fSDavid du Colombier 
2509a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cuid);
2519a747e4fSDavid du Colombier 	p = pstring(p, e, ai->suid);
2529a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cap);
2539a747e4fSDavid du Colombier 	p = pcarray(p, e, ai->secret, ai->nsecret);
2549a747e4fSDavid du Colombier 	return p;
2559a747e4fSDavid du Colombier }
2569a747e4fSDavid du Colombier 
2579a747e4fSDavid du Colombier int
2589a747e4fSDavid du Colombier failure(Fsstate *s, char *fmt, ...)
2599a747e4fSDavid du Colombier {
2609a747e4fSDavid du Colombier 	char e[ERRMAX];
2619a747e4fSDavid du Colombier 	va_list arg;
2629a747e4fSDavid du Colombier 
2639a747e4fSDavid du Colombier 	if(fmt == nil)
2649a747e4fSDavid du Colombier 		rerrstr(s->err, sizeof(s->err));
2659a747e4fSDavid du Colombier 	else {
2669a747e4fSDavid du Colombier 		va_start(arg, fmt);
2679a747e4fSDavid du Colombier 		snprint(e, sizeof e, fmt, arg);
2689a747e4fSDavid du Colombier 		va_end(arg);
2699a747e4fSDavid du Colombier 		strecpy(s->err, s->err+sizeof(s->err), e);
2709a747e4fSDavid du Colombier 		errstr(e, sizeof e);
2719a747e4fSDavid du Colombier 	}
2729a747e4fSDavid du Colombier 	flog("%d: failure %s", s->seqnum, s->err);
2739a747e4fSDavid du Colombier 	return RpcFailure;
2749a747e4fSDavid du Colombier }
2759a747e4fSDavid du Colombier 
2769a747e4fSDavid du Colombier static int
2779a747e4fSDavid du Colombier hasqueries(Attr *a)
2789a747e4fSDavid du Colombier {
2799a747e4fSDavid du Colombier 	for(; a; a=a->next)
2809a747e4fSDavid du Colombier 		if(a->type == AttrQuery)
2819a747e4fSDavid du Colombier 			return 1;
2829a747e4fSDavid du Colombier 	return 0;
2839a747e4fSDavid du Colombier }
2849a747e4fSDavid du Colombier 
2859a747e4fSDavid du Colombier char *ignored[] = {
2869a747e4fSDavid du Colombier 	"role",
287260f7b65SDavid du Colombier 	"disabled",
2889a747e4fSDavid du Colombier };
2899a747e4fSDavid du Colombier 
2909a747e4fSDavid du Colombier static int
2919a747e4fSDavid du Colombier ignoreattr(char *s)
2929a747e4fSDavid du Colombier {
2939a747e4fSDavid du Colombier 	int i;
2949a747e4fSDavid du Colombier 
2959a747e4fSDavid du Colombier 	for(i=0; i<nelem(ignored); i++)
2969a747e4fSDavid du Colombier 		if(strcmp(ignored[i], s)==0)
2979a747e4fSDavid du Colombier 			return 1;
2989a747e4fSDavid du Colombier 	return 0;
2999a747e4fSDavid du Colombier }
3009a747e4fSDavid du Colombier 
301260f7b65SDavid du Colombier Keyinfo*
302260f7b65SDavid du Colombier mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
303260f7b65SDavid du Colombier {
304260f7b65SDavid du Colombier 	memset(k, 0, sizeof *k);
305260f7b65SDavid du Colombier 	k->fss = fss;
306260f7b65SDavid du Colombier 	k->user = fss->sysuser;
307*6b8bc682SDavid du Colombier 	if(attr)
308260f7b65SDavid du Colombier 		k->attr = attr;
309*6b8bc682SDavid du Colombier 	else
310*6b8bc682SDavid du Colombier 		k->attr = fss->attr;
311260f7b65SDavid du Colombier 	return k;
312260f7b65SDavid du Colombier }
313260f7b65SDavid du Colombier 
3149a747e4fSDavid du Colombier int
315260f7b65SDavid du Colombier findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
3169a747e4fSDavid du Colombier {
3179a747e4fSDavid du Colombier 	int i, s, nmatch;
318260f7b65SDavid du Colombier 	char buf[1024], *p, *who;
3199a747e4fSDavid du Colombier 	va_list arg;
320260f7b65SDavid du Colombier 	Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
3219a747e4fSDavid du Colombier 	Key *k;
3229a747e4fSDavid du Colombier 
3239a747e4fSDavid du Colombier 	*ret = nil;
3249a747e4fSDavid du Colombier 
325260f7b65SDavid du Colombier 	who = ki->user;
326260f7b65SDavid du Colombier 	attr0 = ki->attr;
3279a747e4fSDavid du Colombier 	if(fmt){
3289a747e4fSDavid du Colombier 		va_start(arg, fmt);
3299a747e4fSDavid du Colombier 		vseprint(buf, buf+sizeof buf, fmt, arg);
3309a747e4fSDavid du Colombier 		va_end(arg);
3319a747e4fSDavid du Colombier 		attr1 = _parseattr(buf);
3329a747e4fSDavid du Colombier 	}else
3339a747e4fSDavid du Colombier 		attr1 = nil;
3349a747e4fSDavid du Colombier 
335fb7f0c93SDavid du Colombier 	if(who && strcmp(who, owner) == 0)
336fb7f0c93SDavid du Colombier 		who = nil;
337fb7f0c93SDavid du Colombier 
338fb7f0c93SDavid du Colombier 	if(who){
339fb7f0c93SDavid du Colombier 		snprint(buf, sizeof buf, "owner=%q", who);
340fb7f0c93SDavid du Colombier 		attr2 = _parseattr(buf);
341fb7f0c93SDavid du Colombier 		attr3 = _parseattr("owner=*");
342fb7f0c93SDavid du Colombier 	}else
343fb7f0c93SDavid du Colombier 		attr2 = attr3 = nil;
344fb7f0c93SDavid du Colombier 
3452ebbfa15SDavid du Colombier 	p = _strfindattr(attr0, "proto");
3469a747e4fSDavid du Colombier 	if(p == nil)
3472ebbfa15SDavid du Colombier 		p = _strfindattr(attr1, "proto");
3489a747e4fSDavid du Colombier 	if(p && findproto(p) == nil){
3499a747e4fSDavid du Colombier 		werrstr("unknown protocol %s", p);
3509a747e4fSDavid du Colombier 		_freeattr(attr1);
351260f7b65SDavid du Colombier 		return failure(ki->fss, nil);
3529a747e4fSDavid du Colombier 	}
3539a747e4fSDavid du Colombier 
3549a747e4fSDavid du Colombier 	nmatch = 0;
3559a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
3569a747e4fSDavid du Colombier 		k = ring->key[i];
357260f7b65SDavid du Colombier 		if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
358260f7b65SDavid du Colombier 			continue;
3599a747e4fSDavid du Colombier 		if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
360fb7f0c93SDavid du Colombier 			/* check ownership */
361fb7f0c93SDavid du Colombier 			if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
362fb7f0c93SDavid du Colombier 				continue;
363260f7b65SDavid du Colombier 			if(nmatch++ < ki->skip)
3649a747e4fSDavid du Colombier 				continue;
365260f7b65SDavid du Colombier 			if(!ki->noconf){
366260f7b65SDavid du Colombier 				switch(canusekey(ki->fss, k)){
3679a747e4fSDavid du Colombier 				case -1:
3689a747e4fSDavid du Colombier 					_freeattr(attr1);
3699a747e4fSDavid du Colombier 					return RpcConfirm;
3709a747e4fSDavid du Colombier 				case 0:
3719a747e4fSDavid du Colombier 					continue;
3729a747e4fSDavid du Colombier 				case 1:
3739a747e4fSDavid du Colombier 					break;
3749a747e4fSDavid du Colombier 				}
3759a747e4fSDavid du Colombier 			}
3769a747e4fSDavid du Colombier 			_freeattr(attr1);
3779a747e4fSDavid du Colombier 			k->ref++;
3789a747e4fSDavid du Colombier 			*ret = k;
3799a747e4fSDavid du Colombier 			return RpcOk;
3809a747e4fSDavid du Colombier 		}
3819a747e4fSDavid du Colombier 	}
382260f7b65SDavid du Colombier 	flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
3839a747e4fSDavid du Colombier 	werrstr("no key matches %A %A", attr0, attr1);
3849a747e4fSDavid du Colombier 	s = RpcFailure;
385fb7f0c93SDavid du Colombier 	if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
3869a747e4fSDavid du Colombier 		if(nmatch == 0){
3879a747e4fSDavid du Colombier 			attr0 = _copyattr(attr0);
3889a747e4fSDavid du Colombier 			for(l=&attr0; *l; l=&(*l)->next)
3899a747e4fSDavid du Colombier 				;
3909a747e4fSDavid du Colombier 			*l = attr1;
3919a747e4fSDavid du Colombier 			for(l=&attr0; *l; ){
3922ebbfa15SDavid du Colombier 				if(ignoreattr((*l)->name)){
3939a747e4fSDavid du Colombier 					a = *l;
3949a747e4fSDavid du Colombier 					*l = (*l)->next;
3959a747e4fSDavid du Colombier 					a->next = nil;
3969a747e4fSDavid du Colombier 					_freeattr(a);
3979a747e4fSDavid du Colombier 				}else
3989a747e4fSDavid du Colombier 					l = &(*l)->next;
3999a747e4fSDavid du Colombier 			}
4009a747e4fSDavid du Colombier 			attr0 = sortattr(attr0);
401260f7b65SDavid du Colombier 			snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
4029a747e4fSDavid du Colombier 			_freeattr(attr0);
4039a747e4fSDavid du Colombier 			attr1 = nil;	/* attr1 was linked to attr0 */
4049a747e4fSDavid du Colombier 		}else
405260f7b65SDavid du Colombier 			ki->fss->keyinfo[0] = '\0';
4069a747e4fSDavid du Colombier 		s = RpcNeedkey;
4079a747e4fSDavid du Colombier 	}
4089a747e4fSDavid du Colombier 	_freeattr(attr1);
4099a747e4fSDavid du Colombier 	if(s == RpcFailure)
410260f7b65SDavid du Colombier 		return failure(ki->fss, nil);	/* loads error string */
4119a747e4fSDavid du Colombier 	return s;
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier 
4149a747e4fSDavid du Colombier int
4159a747e4fSDavid du Colombier findp9authkey(Key **k, Fsstate *fss)
4169a747e4fSDavid du Colombier {
4179a747e4fSDavid du Colombier 	char *dom;
418260f7b65SDavid du Colombier 	Keyinfo ki;
4199a747e4fSDavid du Colombier 
4209a747e4fSDavid du Colombier 	/*
4219a747e4fSDavid du Colombier 	 * We don't use fss->attr here because we don't
4229a747e4fSDavid du Colombier 	 * care about what the user name is set to, for instance.
4239a747e4fSDavid du Colombier 	 */
424260f7b65SDavid du Colombier 	mkkeyinfo(&ki, fss, nil);
425260f7b65SDavid du Colombier 	ki.attr = nil;
426260f7b65SDavid du Colombier 	ki.user = nil;
4272ebbfa15SDavid du Colombier 	if(dom = _strfindattr(fss->attr, "dom"))
428260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
4299a747e4fSDavid du Colombier 	else
430260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
4319a747e4fSDavid du Colombier }
4329a747e4fSDavid du Colombier 
4339a747e4fSDavid du Colombier Proto*
4349a747e4fSDavid du Colombier findproto(char *name)
4359a747e4fSDavid du Colombier {
4369a747e4fSDavid du Colombier 	int i;
4379a747e4fSDavid du Colombier 
4389a747e4fSDavid du Colombier 	for(i=0; prototab[i]; i++)
4399a747e4fSDavid du Colombier 		if(strcmp(name, prototab[i]->name) == 0)
4409a747e4fSDavid du Colombier 			return prototab[i];
4419a747e4fSDavid du Colombier 	return nil;
4429a747e4fSDavid du Colombier }
4439a747e4fSDavid du Colombier 
4449a747e4fSDavid du Colombier char*
4459a747e4fSDavid du Colombier getnvramkey(int flag, char **secstorepw)
4469a747e4fSDavid du Colombier {
4479a747e4fSDavid du Colombier 	char *s;
4489a747e4fSDavid du Colombier 	Nvrsafe safe;
4499a747e4fSDavid du Colombier 	char spw[CONFIGLEN+1];
4509a747e4fSDavid du Colombier 	int i;
4519a747e4fSDavid du Colombier 
4529a747e4fSDavid du Colombier 	memset(&safe, 0, sizeof safe);
4539a747e4fSDavid du Colombier 	/*
4549a747e4fSDavid du Colombier 	 * readnvram can return -1 meaning nvram wasn't written,
4559a747e4fSDavid du Colombier 	 * but safe still holds good data.
4569a747e4fSDavid du Colombier 	 */
4579a747e4fSDavid du Colombier 	if(readnvram(&safe, flag)<0 && safe.authid[0]=='0')
4589a747e4fSDavid du Colombier 		return nil;
4599a747e4fSDavid du Colombier 
4609a747e4fSDavid du Colombier 	/*
4619a747e4fSDavid du Colombier 	 *  we're using the config area to hold the secstore
4629a747e4fSDavid du Colombier 	 *  password.  if there's anything there, return it.
4639a747e4fSDavid du Colombier 	 */
4649a747e4fSDavid du Colombier 	memmove(spw, safe.config, CONFIGLEN);
4659a747e4fSDavid du Colombier 	spw[CONFIGLEN] = 0;
4669a747e4fSDavid du Colombier 	if(spw[0] != 0)
4679a747e4fSDavid du Colombier 		*secstorepw = estrdup(spw);
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	/*
4709a747e4fSDavid du Colombier 	 *  only use nvram key if it is non-zero
4719a747e4fSDavid du Colombier 	 */
4729a747e4fSDavid du Colombier 	for(i = 0; i < DESKEYLEN; i++)
4739a747e4fSDavid du Colombier 		if(safe.machkey[i] != 0)
4749a747e4fSDavid du Colombier 			break;
4759a747e4fSDavid du Colombier 	if(i == DESKEYLEN)
4769a747e4fSDavid du Colombier 		return nil;
4779a747e4fSDavid du Colombier 
4789a747e4fSDavid du Colombier 	s = emalloc(512);
4799a747e4fSDavid du Colombier 	fmtinstall('H', encodefmt);
4809a747e4fSDavid du Colombier 	sprint(s, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
4819a747e4fSDavid du Colombier 		safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
4829a747e4fSDavid du Colombier 	writehostowner(safe.authid);
4839a747e4fSDavid du Colombier 
4849a747e4fSDavid du Colombier 	return s;
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier 
4879a747e4fSDavid du Colombier int
4889a747e4fSDavid du Colombier isclient(char *role)
4899a747e4fSDavid du Colombier {
4909a747e4fSDavid du Colombier 	if(role == nil){
4919a747e4fSDavid du Colombier 		werrstr("role not specified");
4929a747e4fSDavid du Colombier 		return -1;
4939a747e4fSDavid du Colombier 	}
4949a747e4fSDavid du Colombier 	if(strcmp(role, "server") == 0)
4959a747e4fSDavid du Colombier 		return 0;
4969a747e4fSDavid du Colombier 	if(strcmp(role, "client") == 0)
4979a747e4fSDavid du Colombier 		return 1;
4989a747e4fSDavid du Colombier 	werrstr("unknown role %q", role);
4999a747e4fSDavid du Colombier 	return -1;
5009a747e4fSDavid du Colombier }
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier static int
5039a747e4fSDavid du Colombier hasname(Attr *a0, Attr *a1, char *name)
5049a747e4fSDavid du Colombier {
5059a747e4fSDavid du Colombier 	return _findattr(a0, name) || _findattr(a1, name);
5069a747e4fSDavid du Colombier }
5079a747e4fSDavid du Colombier 
5089a747e4fSDavid du Colombier static int
5099a747e4fSDavid du Colombier hasnameval(Attr *a0, Attr *a1, char *name, char *val)
5109a747e4fSDavid du Colombier {
5119a747e4fSDavid du Colombier 	Attr *a;
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier 	for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
5142ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5159a747e4fSDavid du Colombier 			return 1;
5169a747e4fSDavid du Colombier 	for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
5172ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5189a747e4fSDavid du Colombier 			return 1;
5199a747e4fSDavid du Colombier 	return 0;
5209a747e4fSDavid du Colombier }
5219a747e4fSDavid du Colombier 
5229a747e4fSDavid du Colombier int
5239a747e4fSDavid du Colombier matchattr(Attr *pat, Attr *a0, Attr *a1)
5249a747e4fSDavid du Colombier {
5259a747e4fSDavid du Colombier 	int type;
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier 	for(; pat; pat=pat->next){
5289a747e4fSDavid du Colombier 		type = pat->type;
5292ebbfa15SDavid du Colombier 		if(ignoreattr(pat->name))
5309a747e4fSDavid du Colombier 			type = AttrDefault;
5319a747e4fSDavid du Colombier 		switch(type){
5329a747e4fSDavid du Colombier 		case AttrQuery:		/* name=something be present */
5332ebbfa15SDavid du Colombier 			if(!hasname(a0, a1, pat->name))
5349a747e4fSDavid du Colombier 				return 0;
5359a747e4fSDavid du Colombier 			break;
5369a747e4fSDavid du Colombier 		case AttrNameval:	/* name=val must be present */
5372ebbfa15SDavid du Colombier 			if(!hasnameval(a0, a1, pat->name, pat->val))
5389a747e4fSDavid du Colombier 				return 0;
5399a747e4fSDavid du Colombier 			break;
5409a747e4fSDavid du Colombier 		case AttrDefault:	/* name=val must be present if name=anything is present */
5412ebbfa15SDavid du Colombier 			if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
5429a747e4fSDavid du Colombier 				return 0;
5439a747e4fSDavid du Colombier 			break;
5449a747e4fSDavid du Colombier 		}
5459a747e4fSDavid du Colombier 	}
5469a747e4fSDavid du Colombier 	return 1;
5479a747e4fSDavid du Colombier }
5489a747e4fSDavid du Colombier 
5499a747e4fSDavid du Colombier void
5509a747e4fSDavid du Colombier memrandom(void *p, int n)
5519a747e4fSDavid du Colombier {
5529a747e4fSDavid du Colombier 	uchar *cp;
5539a747e4fSDavid du Colombier 
5549a747e4fSDavid du Colombier 	for(cp = (uchar*)p; n > 0; n--)
5559a747e4fSDavid du Colombier 		*cp++ = fastrand();
5569a747e4fSDavid du Colombier }
5579a747e4fSDavid du Colombier 
5589a747e4fSDavid du Colombier /*
5593ff48bf5SDavid du Colombier  *  keep caphash fd open since opens of it could be disabled
5603ff48bf5SDavid du Colombier  */
5613ff48bf5SDavid du Colombier static int caphashfd;
5623ff48bf5SDavid du Colombier 
5633ff48bf5SDavid du Colombier void
5643ff48bf5SDavid du Colombier initcap(void)
5653ff48bf5SDavid du Colombier {
5663ff48bf5SDavid du Colombier 	caphashfd = open("#¤/caphash", OWRITE);
567d9306527SDavid du Colombier //	if(caphashfd < 0)
568d9306527SDavid du Colombier //		fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
5693ff48bf5SDavid du Colombier }
5703ff48bf5SDavid du Colombier 
5713ff48bf5SDavid du Colombier /*
5729a747e4fSDavid du Colombier  *  create a change uid capability
5739a747e4fSDavid du Colombier  */
5749a747e4fSDavid du Colombier char*
5753ff48bf5SDavid du Colombier mkcap(char *from, char *to)
5769a747e4fSDavid du Colombier {
5779a747e4fSDavid du Colombier 	uchar rand[20];
5789a747e4fSDavid du Colombier 	char *cap;
5799a747e4fSDavid du Colombier 	char *key;
5803ff48bf5SDavid du Colombier 	int nfrom, nto;
5819a747e4fSDavid du Colombier 	uchar hash[SHA1dlen];
5829a747e4fSDavid du Colombier 
5833ff48bf5SDavid du Colombier 	if(caphashfd < 0)
5849a747e4fSDavid du Colombier 		return nil;
5859a747e4fSDavid du Colombier 
5869a747e4fSDavid du Colombier 	/* create the capability */
5873ff48bf5SDavid du Colombier 	nto = strlen(to);
5883ff48bf5SDavid du Colombier 	nfrom = strlen(from);
5893ff48bf5SDavid du Colombier 	cap = emalloc(nfrom+1+nto+1+sizeof(rand)*3+1);
5903ff48bf5SDavid du Colombier 	sprint(cap, "%s@%s", from, to);
5919a747e4fSDavid du Colombier 	memrandom(rand, sizeof(rand));
5923ff48bf5SDavid du Colombier 	key = cap+nfrom+1+nto+1;
5939a747e4fSDavid du Colombier 	enc64(key, sizeof(rand)*3, rand, sizeof(rand));
5949a747e4fSDavid du Colombier 
5959a747e4fSDavid du Colombier 	/* hash the capability */
5963ff48bf5SDavid du Colombier 	hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
5979a747e4fSDavid du Colombier 
5989a747e4fSDavid du Colombier 	/* give the kernel the hash */
5993ff48bf5SDavid du Colombier 	key[-1] = '@';
6003ff48bf5SDavid du Colombier 	if(write(caphashfd, hash, SHA1dlen) < 0){
6019a747e4fSDavid du Colombier 		free(cap);
6029a747e4fSDavid du Colombier 		return nil;
6039a747e4fSDavid du Colombier 	}
6049a747e4fSDavid du Colombier 
6059a747e4fSDavid du Colombier 	return cap;
6069a747e4fSDavid du Colombier }
6079a747e4fSDavid du Colombier 
6089a747e4fSDavid du Colombier int
6099a747e4fSDavid du Colombier phaseerror(Fsstate *s, char *op)
6109a747e4fSDavid du Colombier {
6119a747e4fSDavid du Colombier 	char tmp[32];
6129a747e4fSDavid du Colombier 
6139a747e4fSDavid du Colombier 	werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));
6149a747e4fSDavid du Colombier 	return RpcPhase;
6159a747e4fSDavid du Colombier }
6169a747e4fSDavid du Colombier 
6179a747e4fSDavid du Colombier char*
6189a747e4fSDavid du Colombier phasename(Fsstate *fss, int phase, char *tmp)
6199a747e4fSDavid du Colombier {
6209a747e4fSDavid du Colombier 	char *name;
6219a747e4fSDavid du Colombier 
6229a747e4fSDavid du Colombier 	if(fss->phase == Broken)
6239a747e4fSDavid du Colombier 		name = "Broken";
6249a747e4fSDavid du Colombier 	else if(phase == Established)
6259a747e4fSDavid du Colombier 		name = "Established";
6269a747e4fSDavid du Colombier 	else if(phase == Notstarted)
6279a747e4fSDavid du Colombier 		name = "Notstarted";
6289a747e4fSDavid du Colombier 	else if(phase < 0 || phase >= fss->maxphase
6299a747e4fSDavid du Colombier 	|| (name = fss->phasename[phase]) == nil){
6309a747e4fSDavid du Colombier 		sprint(tmp, "%d", phase);
6319a747e4fSDavid du Colombier 		name = tmp;
6329a747e4fSDavid du Colombier 	}
6339a747e4fSDavid du Colombier 	return name;
6349a747e4fSDavid du Colombier }
6359a747e4fSDavid du Colombier 
6369a747e4fSDavid du Colombier static int
6379a747e4fSDavid du Colombier outin(char *prompt, char *def, int len)
6389a747e4fSDavid du Colombier {
6392ebbfa15SDavid du Colombier 	char *s;
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier 	s = readcons(prompt, def, 0);
6429a747e4fSDavid du Colombier 	if(s == nil)
6439a747e4fSDavid du Colombier 		return -1;
6442ebbfa15SDavid du Colombier 	if(s == nil)
6452ebbfa15SDavid du Colombier 		sysfatal("s==nil???");
6462ebbfa15SDavid du Colombier 	strncpy(def, s, len);
6479a747e4fSDavid du Colombier 	def[len-1] = 0;
6482ebbfa15SDavid du Colombier 	free(s);
6499a747e4fSDavid du Colombier 	return strlen(def);
6509a747e4fSDavid du Colombier }
6519a747e4fSDavid du Colombier 
6529a747e4fSDavid du Colombier /*
6539a747e4fSDavid du Colombier  *  get host owner and set it
6549a747e4fSDavid du Colombier  */
6559a747e4fSDavid du Colombier void
6569a747e4fSDavid du Colombier promptforhostowner(void)
6579a747e4fSDavid du Colombier {
6589a747e4fSDavid du Colombier 	char owner[64], *p;
6599a747e4fSDavid du Colombier 
6609a747e4fSDavid du Colombier 	/* hack for bitsy; can't prompt during boot */
6619a747e4fSDavid du Colombier 	if(p = getenv("user")){
6629a747e4fSDavid du Colombier 		writehostowner(p);
663d9306527SDavid du Colombier 		free(p);
6649a747e4fSDavid du Colombier 		return;
6659a747e4fSDavid du Colombier 	}
666d9306527SDavid du Colombier 	free(p);
6679a747e4fSDavid du Colombier 
6689a747e4fSDavid du Colombier 	strcpy(owner, "none");
6699a747e4fSDavid du Colombier 	do{
6709a747e4fSDavid du Colombier 		outin("user", owner, sizeof(owner));
6719a747e4fSDavid du Colombier 	} while(*owner == 0);
6729a747e4fSDavid du Colombier 	writehostowner(owner);
6739a747e4fSDavid du Colombier }
6749a747e4fSDavid du Colombier 
6752ebbfa15SDavid du Colombier char*
6762ebbfa15SDavid du Colombier estrappend(char *s, char *fmt, ...)
6772ebbfa15SDavid du Colombier {
6782ebbfa15SDavid du Colombier 	char *t;
6792ebbfa15SDavid du Colombier 	va_list arg;
6802ebbfa15SDavid du Colombier 
6812ebbfa15SDavid du Colombier 	va_start(arg, fmt);
6822ebbfa15SDavid du Colombier 	t = vsmprint(fmt, arg);
6832ebbfa15SDavid du Colombier 	if(t == nil)
6842ebbfa15SDavid du Colombier 		sysfatal("out of memory");
6852ebbfa15SDavid du Colombier 	va_end(arg);
6862ebbfa15SDavid du Colombier 	s = erealloc(s, strlen(s)+strlen(t)+1);
6872ebbfa15SDavid du Colombier 	strcat(s, t);
6882ebbfa15SDavid du Colombier 	free(t);
6892ebbfa15SDavid du Colombier 	return s;
6902ebbfa15SDavid du Colombier }
6912ebbfa15SDavid du Colombier 
6922ebbfa15SDavid du Colombier 
6939a747e4fSDavid du Colombier /*
6949a747e4fSDavid du Colombier  *  prompt for a string with a possible default response
6959a747e4fSDavid du Colombier  */
6962ebbfa15SDavid du Colombier char*
6979a747e4fSDavid du Colombier readcons(char *prompt, char *def, int raw)
6989a747e4fSDavid du Colombier {
6999a747e4fSDavid du Colombier 	int fdin, fdout, ctl, n;
7009a747e4fSDavid du Colombier 	char line[10];
7012ebbfa15SDavid du Colombier 	char *s;
7029a747e4fSDavid du Colombier 
7039a747e4fSDavid du Colombier 	fdin = open("/dev/cons", OREAD);
7049a747e4fSDavid du Colombier 	if(fdin < 0)
7059a747e4fSDavid du Colombier 		fdin = 0;
7069a747e4fSDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
7079a747e4fSDavid du Colombier 	if(fdout < 0)
7089a747e4fSDavid du Colombier 		fdout = 1;
7099a747e4fSDavid du Colombier 	if(def != nil)
7109a747e4fSDavid du Colombier 		fprint(fdout, "%s[%s]: ", prompt, def);
7119a747e4fSDavid du Colombier 	else
7129a747e4fSDavid du Colombier 		fprint(fdout, "%s: ", prompt);
7139a747e4fSDavid du Colombier 	if(raw){
7149a747e4fSDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
7159a747e4fSDavid du Colombier 		if(ctl >= 0)
7169a747e4fSDavid du Colombier 			write(ctl, "rawon", 5);
7179a747e4fSDavid du Colombier 	} else
7189a747e4fSDavid du Colombier 		ctl = -1;
7192ebbfa15SDavid du Colombier 	s = estrdup("");
7209a747e4fSDavid du Colombier 	for(;;){
7219a747e4fSDavid du Colombier 		n = read(fdin, line, 1);
7229a747e4fSDavid du Colombier 		if(n == 0){
7239a747e4fSDavid du Colombier 		Error:
7249a747e4fSDavid du Colombier 			close(fdin);
7259a747e4fSDavid du Colombier 			close(fdout);
7269a747e4fSDavid du Colombier 			if(ctl >= 0)
7279a747e4fSDavid du Colombier 				close(ctl);
7282ebbfa15SDavid du Colombier 			free(s);
7299a747e4fSDavid du Colombier 			return nil;
7309a747e4fSDavid du Colombier 		}
7319a747e4fSDavid du Colombier 		if(n < 0)
7329a747e4fSDavid du Colombier 			goto Error;
7339a747e4fSDavid du Colombier 		if(line[0] == 0x7f)
7349a747e4fSDavid du Colombier 			goto Error;
7359a747e4fSDavid du Colombier 		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
7369a747e4fSDavid du Colombier 			if(raw){
7379a747e4fSDavid du Colombier 				write(ctl, "rawoff", 6);
7389a747e4fSDavid du Colombier 				write(fdout, "\n", 1);
7399a747e4fSDavid du Colombier 			}
7409a747e4fSDavid du Colombier 			close(ctl);
7419a747e4fSDavid du Colombier 			close(fdin);
7429a747e4fSDavid du Colombier 			close(fdout);
7432ebbfa15SDavid du Colombier 			if(*s == 0 && def != nil)
7442ebbfa15SDavid du Colombier 				s = estrappend(s, "%s", def);
7459a747e4fSDavid du Colombier 			return s;
7469a747e4fSDavid du Colombier 		}
7479a747e4fSDavid du Colombier 		if(line[0] == '\b'){
7482ebbfa15SDavid du Colombier 			if(strlen(s) > 0)
7492ebbfa15SDavid du Colombier 				s[strlen(s)-1] = 0;
7509a747e4fSDavid du Colombier 		} else if(line[0] == 0x15) {	/* ^U: line kill */
7512ebbfa15SDavid du Colombier 			if(def != nil)
7522ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s[%s]: ", prompt, def);
7532ebbfa15SDavid du Colombier 			else
7542ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s: ", prompt);
7552ebbfa15SDavid du Colombier 
7562ebbfa15SDavid du Colombier 			s[0] = 0;
7579a747e4fSDavid du Colombier 		} else {
7582ebbfa15SDavid du Colombier 			s = estrappend(s, "%c", line[0]);
7599a747e4fSDavid du Colombier 		}
7609a747e4fSDavid du Colombier 	}
7612ebbfa15SDavid du Colombier 	return nil; /* not reached */
7629a747e4fSDavid du Colombier }
7639a747e4fSDavid du Colombier 
7649a747e4fSDavid du Colombier /*
7659a747e4fSDavid du Colombier  * Insert a key into the keyring.
7669a747e4fSDavid du Colombier  * If the public attributes are identical to some other key, replace that one.
7679a747e4fSDavid du Colombier  */
7689a747e4fSDavid du Colombier int
76970b8e010SDavid du Colombier replacekey(Key *kn, int before)
7709a747e4fSDavid du Colombier {
7719a747e4fSDavid du Colombier 	int i;
7729a747e4fSDavid du Colombier 	Key *k;
7739a747e4fSDavid du Colombier 
7749a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
7759a747e4fSDavid du Colombier 		k = ring->key[i];
7769a747e4fSDavid du Colombier 		if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
7779a747e4fSDavid du Colombier 			closekey(k);
7789a747e4fSDavid du Colombier 			kn->ref++;
7799a747e4fSDavid du Colombier 			ring->key[i] = kn;
7809a747e4fSDavid du Colombier 			return 0;
7819a747e4fSDavid du Colombier 		}
7829a747e4fSDavid du Colombier 	}
7839a747e4fSDavid du Colombier 	if(ring->nkey%16 == 0)
7849a747e4fSDavid du Colombier 		ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
7859a747e4fSDavid du Colombier 	kn->ref++;
78670b8e010SDavid du Colombier 	if(before){
78770b8e010SDavid du Colombier 		memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
78870b8e010SDavid du Colombier 		ring->key[0] = kn;
78970b8e010SDavid du Colombier 		ring->nkey++;
79070b8e010SDavid du Colombier 	}else
7919a747e4fSDavid du Colombier 		ring->key[ring->nkey++] = kn;
7929a747e4fSDavid du Colombier 	return 0;
7939a747e4fSDavid du Colombier }
7949a747e4fSDavid du Colombier 
7959a747e4fSDavid du Colombier char*
7969a747e4fSDavid du Colombier safecpy(char *to, char *from, int n)
7979a747e4fSDavid du Colombier {
7989a747e4fSDavid du Colombier 	memset(to, 0, n);
7999a747e4fSDavid du Colombier 	if(n == 1)
8009a747e4fSDavid du Colombier 		return to;
8019a747e4fSDavid du Colombier 	if(from==nil)
8029a747e4fSDavid du Colombier 		sysfatal("safecpy called with from==nil, pc=%lux\n",
8039a747e4fSDavid du Colombier 			getcallerpc(&to));
8049a747e4fSDavid du Colombier 	strncpy(to, from, n-1);
8059a747e4fSDavid du Colombier 	return to;
8069a747e4fSDavid du Colombier }
8079a747e4fSDavid du Colombier 
8089a747e4fSDavid du Colombier Attr*
8099a747e4fSDavid du Colombier setattr(Attr *a, char *fmt, ...)
8109a747e4fSDavid du Colombier {
8119a747e4fSDavid du Colombier 	char buf[1024];
8129a747e4fSDavid du Colombier 	va_list arg;
8139a747e4fSDavid du Colombier 	Attr *b;
8149a747e4fSDavid du Colombier 
8159a747e4fSDavid du Colombier 	va_start(arg, fmt);
8169a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof buf, fmt, arg);
8179a747e4fSDavid du Colombier 	va_end(arg);
8189a747e4fSDavid du Colombier 	b = _parseattr(buf);
8199a747e4fSDavid du Colombier 	a = setattrs(a, b);
8209a747e4fSDavid du Colombier 	setmalloctag(a, getcallerpc(&a));
8219a747e4fSDavid du Colombier 	_freeattr(b);
8229a747e4fSDavid du Colombier 	return a;
8239a747e4fSDavid du Colombier }
8249a747e4fSDavid du Colombier 
8259a747e4fSDavid du Colombier /*
8269a747e4fSDavid du Colombier  *  add attributes in list b to list a.  If any attributes are in
8279a747e4fSDavid du Colombier  *  both lists, replace those in a by those in b.
8289a747e4fSDavid du Colombier  */
8299a747e4fSDavid du Colombier Attr*
8309a747e4fSDavid du Colombier setattrs(Attr *a, Attr *b)
8319a747e4fSDavid du Colombier {
8329a747e4fSDavid du Colombier 	int found;
8339a747e4fSDavid du Colombier 	Attr **l, *freea;
8349a747e4fSDavid du Colombier 
8359a747e4fSDavid du Colombier 	for(; b; b=b->next){
8369a747e4fSDavid du Colombier 		found = 0;
8379a747e4fSDavid du Colombier 		for(l=&a; *l; ){
8382ebbfa15SDavid du Colombier 			if(strcmp(b->name, (*l)->name) == 0){
8399a747e4fSDavid du Colombier 				switch(b->type){
8409a747e4fSDavid du Colombier 				case AttrNameval:
8419a747e4fSDavid du Colombier 					if(!found){
8429a747e4fSDavid du Colombier 						found = 1;
8432ebbfa15SDavid du Colombier 						free((*l)->val);
8442ebbfa15SDavid du Colombier 						(*l)->val = estrdup(b->val);
8459a747e4fSDavid du Colombier 						(*l)->type = AttrNameval;
8469a747e4fSDavid du Colombier 						l = &(*l)->next;
8479a747e4fSDavid du Colombier 					}else{
8489a747e4fSDavid du Colombier 						freea = *l;
8499a747e4fSDavid du Colombier 						*l = (*l)->next;
8509a747e4fSDavid du Colombier 						freea->next = nil;
8519a747e4fSDavid du Colombier 						_freeattr(freea);
8529a747e4fSDavid du Colombier 					}
8539a747e4fSDavid du Colombier 					break;
8549a747e4fSDavid du Colombier 				case AttrQuery:
8559a747e4fSDavid du Colombier 					found++;
8569a747e4fSDavid du Colombier 					break;
8579a747e4fSDavid du Colombier 				}
8589a747e4fSDavid du Colombier 			}else
8599a747e4fSDavid du Colombier 				l = &(*l)->next;
8609a747e4fSDavid du Colombier 		}
8619a747e4fSDavid du Colombier 		if(found == 0){
8622ebbfa15SDavid du Colombier 			*l = _mkattr(b->type, b->name, b->val, nil);
8639a747e4fSDavid du Colombier 			setmalloctag(*l, getcallerpc(&a));
8649a747e4fSDavid du Colombier 		}
8659a747e4fSDavid du Colombier 	}
8669a747e4fSDavid du Colombier 	return a;
8679a747e4fSDavid du Colombier }
8689a747e4fSDavid du Colombier 
8699a747e4fSDavid du Colombier void
8709a747e4fSDavid du Colombier setmalloctaghere(void *v)
8719a747e4fSDavid du Colombier {
8729a747e4fSDavid du Colombier 	setmalloctag(v, getcallerpc(&v));
8739a747e4fSDavid du Colombier }
8749a747e4fSDavid du Colombier 
8759a747e4fSDavid du Colombier Attr*
8769a747e4fSDavid du Colombier sortattr(Attr *a)
8779a747e4fSDavid du Colombier {
8789a747e4fSDavid du Colombier 	int i;
8799a747e4fSDavid du Colombier 	Attr *anext, *a0, *a1, **l;
8809a747e4fSDavid du Colombier 
8819a747e4fSDavid du Colombier 	if(a == nil || a->next == nil)
8829a747e4fSDavid du Colombier 		return a;
8839a747e4fSDavid du Colombier 
8849a747e4fSDavid du Colombier 	/* cut list in halves */
8859a747e4fSDavid du Colombier 	a0 = nil;
8869a747e4fSDavid du Colombier 	a1 = nil;
8879a747e4fSDavid du Colombier 	i = 0;
8889a747e4fSDavid du Colombier 	for(; a; a=anext){
8899a747e4fSDavid du Colombier 		anext = a->next;
8909a747e4fSDavid du Colombier 		if(i++%2){
8919a747e4fSDavid du Colombier 			a->next = a0;
8929a747e4fSDavid du Colombier 			a0 = a;
8939a747e4fSDavid du Colombier 		}else{
8949a747e4fSDavid du Colombier 			a->next = a1;
8959a747e4fSDavid du Colombier 			a1 = a;
8969a747e4fSDavid du Colombier 		}
8979a747e4fSDavid du Colombier 	}
8989a747e4fSDavid du Colombier 
8999a747e4fSDavid du Colombier 	/* sort */
9009a747e4fSDavid du Colombier 	a0 = sortattr(a0);
9019a747e4fSDavid du Colombier 	a1 = sortattr(a1);
9029a747e4fSDavid du Colombier 
9039a747e4fSDavid du Colombier 	/* merge */
9049a747e4fSDavid du Colombier 	l = &a;
9059a747e4fSDavid du Colombier 	while(a0 || a1){
9069a747e4fSDavid du Colombier 		if(a1==nil){
9079a747e4fSDavid du Colombier 			anext = a0;
9089a747e4fSDavid du Colombier 			a0 = a0->next;
9099a747e4fSDavid du Colombier 		}else if(a0==nil){
9109a747e4fSDavid du Colombier 			anext = a1;
9119a747e4fSDavid du Colombier 			a1 = a1->next;
9122ebbfa15SDavid du Colombier 		}else if(strcmp(a0->name, a1->name) < 0){
9139a747e4fSDavid du Colombier 			anext = a0;
9149a747e4fSDavid du Colombier 			a0 = a0->next;
9159a747e4fSDavid du Colombier 		}else{
9169a747e4fSDavid du Colombier 			anext = a1;
9179a747e4fSDavid du Colombier 			a1 = a1->next;
9189a747e4fSDavid du Colombier 		}
9199a747e4fSDavid du Colombier 		*l = anext;
9209a747e4fSDavid du Colombier 		l = &(*l)->next;
9219a747e4fSDavid du Colombier 	}
9229a747e4fSDavid du Colombier 	*l = nil;
9239a747e4fSDavid du Colombier 	return a;
9249a747e4fSDavid du Colombier }
9259a747e4fSDavid du Colombier 
9269a747e4fSDavid du Colombier int
9279a747e4fSDavid du Colombier toosmall(Fsstate *fss, uint n)
9289a747e4fSDavid du Colombier {
9299a747e4fSDavid du Colombier 	fss->rpc.nwant = n;
9309a747e4fSDavid du Colombier 	return RpcToosmall;
9319a747e4fSDavid du Colombier }
9329a747e4fSDavid du Colombier 
9339a747e4fSDavid du Colombier void
9349a747e4fSDavid du Colombier writehostowner(char *owner)
9359a747e4fSDavid du Colombier {
9369a747e4fSDavid du Colombier 	int fd;
9379a747e4fSDavid du Colombier 	char *s;
9389a747e4fSDavid du Colombier 
9399a747e4fSDavid du Colombier 	if((s = strchr(owner,'@')) != nil){
9409a747e4fSDavid du Colombier 		*s++ = 0;
9419a747e4fSDavid du Colombier 		strncpy(secstore, s, (sizeof secstore)-1);
9429a747e4fSDavid du Colombier 	}
9439a747e4fSDavid du Colombier 	fd = open("#c/hostowner", OWRITE);
9449a747e4fSDavid du Colombier 	if(fd >= 0){
9459a747e4fSDavid du Colombier 		if(fprint(fd, "%s", owner) < 0)
9469a747e4fSDavid du Colombier 			fprint(2, "setting #c/hostowner to %q: %r\n", owner);
9479a747e4fSDavid du Colombier 		close(fd);
9489a747e4fSDavid du Colombier 	}
9499a747e4fSDavid du Colombier }
9509a747e4fSDavid du Colombier 
9515d459b5aSDavid du Colombier int
9525d459b5aSDavid du Colombier attrnamefmt(Fmt *fmt)
9535d459b5aSDavid du Colombier {
9545d459b5aSDavid du Colombier 	char *b, buf[1024], *ebuf;
9555d459b5aSDavid du Colombier 	Attr *a;
9565d459b5aSDavid du Colombier 
9575d459b5aSDavid du Colombier 	ebuf = buf+sizeof buf;
9585d459b5aSDavid du Colombier 	b = buf;
9595d459b5aSDavid du Colombier 	strcpy(buf, " ");
9605d459b5aSDavid du Colombier 	for(a=va_arg(fmt->args, Attr*); a; a=a->next){
9615d459b5aSDavid du Colombier 		if(a->name == nil)
9625d459b5aSDavid du Colombier 			continue;
9632ebbfa15SDavid du Colombier 		b = seprint(b, ebuf, " %q?", a->name);
9645d459b5aSDavid du Colombier 	}
9655d459b5aSDavid du Colombier 	return fmtstrcpy(fmt, buf+1);
9665d459b5aSDavid du Colombier }
967260f7b65SDavid du Colombier 
968260f7b65SDavid du Colombier void
969260f7b65SDavid du Colombier disablekey(Key *k)
970260f7b65SDavid du Colombier {
971260f7b65SDavid du Colombier 	Attr *a;
972260f7b65SDavid du Colombier 
973260f7b65SDavid du Colombier 	for(a=k->attr; a; a=a->next){
974260f7b65SDavid du Colombier 		if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
975260f7b65SDavid du Colombier 			return;
976260f7b65SDavid du Colombier 		if(a->next == nil)
977260f7b65SDavid du Colombier 			break;
978260f7b65SDavid du Colombier 	}
979260f7b65SDavid du Colombier 	if(a)
980260f7b65SDavid du Colombier 		a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
981260f7b65SDavid du Colombier 	else
982260f7b65SDavid du Colombier 		k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil);	/* not reached: always a proto attribute */
983260f7b65SDavid du Colombier }
984