xref: /plan9/sys/src/cmd/auth/factotum/util.c (revision f0ed0fb6ece3d3929965f9aae57d7447f228b5ed)
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 
303b8f1eaaSDavid du Colombier 	if(bindnetcs() >= 0 && (fd=authdial(net, authdom)) >= 0)
313b8f1eaaSDavid du Colombier 		return fd;
323b8f1eaaSDavid du Colombier 	if(net != nil && strcmp(net, "/net") != 0)
333b8f1eaaSDavid du Colombier 		return -1;
349a747e4fSDavid du Colombier 
359a747e4fSDavid du Colombier 	/* use the auth sever passed to us as an arg */
369a747e4fSDavid du Colombier 	if(authaddr == nil)
379a747e4fSDavid du Colombier 		return -1;
389a747e4fSDavid du Colombier 	fd = dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
399a747e4fSDavid du Colombier 	if(fd >= 0)
409a747e4fSDavid du Colombier 		return fd;
419a747e4fSDavid du Colombier 	return dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
429a747e4fSDavid du Colombier }
439a747e4fSDavid du Colombier 
449a747e4fSDavid du Colombier int
459a747e4fSDavid du Colombier secdial(void)
469a747e4fSDavid du Colombier {
479a747e4fSDavid du Colombier 	char *p, buf[80], *f[3];
489a747e4fSDavid du Colombier 	int fd, nf;
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier 	p = secstore; /* take it from writehostowner, if set there */
519a747e4fSDavid du Colombier 	if(*p == 0)	  /* else use the authserver */
529a747e4fSDavid du Colombier 		p = "$auth";
539a747e4fSDavid du Colombier 
549a747e4fSDavid du Colombier 	if(bindnetcs() >= 0)
559a747e4fSDavid du Colombier 		return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier 	/* translate $auth ourselves.
589a747e4fSDavid du Colombier 	 * authaddr is something like il!host!566 or tcp!host!567.
599a747e4fSDavid du Colombier 	 * extract host, accounting for a change of format to something
609a747e4fSDavid du Colombier 	 * like il!host or tcp!host or host.
619a747e4fSDavid du Colombier 	 */
629a747e4fSDavid du Colombier 	if(strcmp(p, "$auth")==0){
639a747e4fSDavid du Colombier 		if(authaddr == nil)
649a747e4fSDavid du Colombier 			return -1;
659a747e4fSDavid du Colombier 		safecpy(buf, authaddr, sizeof buf);
669a747e4fSDavid du Colombier 		nf = getfields(buf, f, nelem(f), 0, "!");
679a747e4fSDavid du Colombier 		switch(nf){
689a747e4fSDavid du Colombier 		default:
699a747e4fSDavid du Colombier 			return -1;
709a747e4fSDavid du Colombier 		case 1:
719a747e4fSDavid du Colombier 			p = f[0];
729a747e4fSDavid du Colombier 			break;
739a747e4fSDavid du Colombier 		case 2:
749a747e4fSDavid du Colombier 		case 3:
759a747e4fSDavid du Colombier 			p = f[1];
769a747e4fSDavid du Colombier 			break;
779a747e4fSDavid du Colombier 		}
789a747e4fSDavid du Colombier 	}
799a747e4fSDavid du Colombier 	fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
809a747e4fSDavid du Colombier 	if(fd >= 0)
819a747e4fSDavid du Colombier 		return fd;
829a747e4fSDavid du Colombier 	return -1;
839a747e4fSDavid du Colombier }
849a747e4fSDavid du Colombier /*
859a747e4fSDavid du Colombier  *  prompt user for a key.  don't care about memory leaks, runs standalone
869a747e4fSDavid du Colombier  */
879a747e4fSDavid du Colombier static Attr*
889a747e4fSDavid du Colombier promptforkey(char *params)
899a747e4fSDavid du Colombier {
909a747e4fSDavid du Colombier 	char *v;
919a747e4fSDavid du Colombier 	int fd;
929a747e4fSDavid du Colombier 	Attr *a, *attr;
939a747e4fSDavid du Colombier 	char *def;
949a747e4fSDavid du Colombier 
959a747e4fSDavid du Colombier 	fd = open("/dev/cons", ORDWR);
969a747e4fSDavid du Colombier 	if(fd < 0)
979a747e4fSDavid du Colombier 		sysfatal("opening /dev/cons: %r");
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier 	attr = _parseattr(params);
1009a747e4fSDavid du Colombier 	fprint(fd, "\n!Adding key:");
1019a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next)
1022ebbfa15SDavid du Colombier 		if(a->type != AttrQuery && a->name[0] != '!')
1032ebbfa15SDavid du Colombier 			fprint(fd, " %q=%q", a->name, a->val);
1049a747e4fSDavid du Colombier 	fprint(fd, "\n");
1059a747e4fSDavid du Colombier 
1069a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next){
1072ebbfa15SDavid du Colombier 		v = a->name;
1089a747e4fSDavid du Colombier 		if(a->type != AttrQuery || v[0]=='!')
1099a747e4fSDavid du Colombier 			continue;
1109a747e4fSDavid du Colombier 		def = nil;
1119a747e4fSDavid du Colombier 		if(strcmp(v, "user") == 0)
1129a747e4fSDavid du Colombier 			def = getuser();
1139a747e4fSDavid du Colombier 		a->val = readcons(v, def, 0);
1149a747e4fSDavid du Colombier 		if(a->val == nil)
1159a747e4fSDavid du Colombier 			sysfatal("user terminated key input");
1169a747e4fSDavid du Colombier 		a->type = AttrNameval;
1179a747e4fSDavid du Colombier 	}
1189a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next){
1192ebbfa15SDavid du Colombier 		v = a->name;
1209a747e4fSDavid du Colombier 		if(a->type != AttrQuery || v[0]!='!')
1219a747e4fSDavid du Colombier 			continue;
1229a747e4fSDavid du Colombier 		def = nil;
1239a747e4fSDavid du Colombier 		if(strcmp(v+1, "user") == 0)
1249a747e4fSDavid du Colombier 			def = getuser();
1259a747e4fSDavid du Colombier 		a->val = readcons(v+1, def, 1);
1269a747e4fSDavid du Colombier 		if(a->val == nil)
1279a747e4fSDavid du Colombier 			sysfatal("user terminated key input");
1289a747e4fSDavid du Colombier 		a->type = AttrNameval;
1299a747e4fSDavid du Colombier 	}
1309a747e4fSDavid du Colombier 	fprint(fd, "!\n");
1319a747e4fSDavid du Colombier 	close(fd);
1329a747e4fSDavid du Colombier 	return attr;
1339a747e4fSDavid du Colombier }
1349a747e4fSDavid du Colombier 
1359a747e4fSDavid du Colombier /*
1369a747e4fSDavid du Colombier  *  send a key to the mounted factotum
1379a747e4fSDavid du Colombier  */
1389a747e4fSDavid du Colombier static int
1399a747e4fSDavid du Colombier sendkey(Attr *attr)
1409a747e4fSDavid du Colombier {
1419a747e4fSDavid du Colombier 	int fd, rv;
1429a747e4fSDavid du Colombier 	char buf[1024];
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier 	fd = open("/mnt/factotum/ctl", ORDWR);
1459a747e4fSDavid du Colombier 	if(fd < 0)
1469a747e4fSDavid du Colombier 		sysfatal("opening /mnt/factotum/ctl: %r");
1479a747e4fSDavid du Colombier 	rv = fprint(fd, "key %A\n", attr);
1489a747e4fSDavid du Colombier 	read(fd, buf, sizeof buf);
1499a747e4fSDavid du Colombier 	close(fd);
1509a747e4fSDavid du Colombier 	return rv;
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier 
1539a747e4fSDavid du Colombier /* askuser */
1549a747e4fSDavid du Colombier void
1559a747e4fSDavid du Colombier askuser(char *params)
1569a747e4fSDavid du Colombier {
1579a747e4fSDavid du Colombier 	Attr *attr;
1589a747e4fSDavid du Colombier 
1599a747e4fSDavid du Colombier 	attr = promptforkey(params);
1609a747e4fSDavid du Colombier 	if(attr == nil)
1619a747e4fSDavid du Colombier 		sysfatal("no key supplied");
1629a747e4fSDavid du Colombier 	if(sendkey(attr) < 0)
1639a747e4fSDavid du Colombier 		sysfatal("sending key to factotum: %r");
1649a747e4fSDavid du Colombier }
1659a747e4fSDavid du Colombier 
1669a747e4fSDavid du Colombier ulong conftaggen;
1679a747e4fSDavid du Colombier int
1689a747e4fSDavid du Colombier canusekey(Fsstate *fss, Key *k)
1699a747e4fSDavid du Colombier {
1709a747e4fSDavid du Colombier 	int i;
1719a747e4fSDavid du Colombier 
1722ebbfa15SDavid du Colombier 	if(_strfindattr(k->attr, "confirm")){
1739a747e4fSDavid du Colombier 		for(i=0; i<fss->nconf; i++)
1749a747e4fSDavid du Colombier 			if(fss->conf[i].key == k)
1759a747e4fSDavid du Colombier 				return fss->conf[i].canuse;
1769a747e4fSDavid du Colombier 		if(fss->nconf%16 == 0)
1779a747e4fSDavid du Colombier 			fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
1789a747e4fSDavid du Colombier 		fss->conf[fss->nconf].key = k;
1799a747e4fSDavid du Colombier 		k->ref++;
1809a747e4fSDavid du Colombier 		fss->conf[fss->nconf].canuse = -1;
1819a747e4fSDavid du Colombier 		fss->conf[fss->nconf].tag = conftaggen++;
1829a747e4fSDavid du Colombier 		fss->nconf++;
1839a747e4fSDavid du Colombier 		return -1;
1849a747e4fSDavid du Colombier 	}
1859a747e4fSDavid du Colombier 	return 1;
1869a747e4fSDavid du Colombier }
1879a747e4fSDavid du Colombier 
1889a747e4fSDavid du Colombier /* closekey */
1899a747e4fSDavid du Colombier void
1909a747e4fSDavid du Colombier closekey(Key *k)
1919a747e4fSDavid du Colombier {
1929a747e4fSDavid du Colombier 	if(k == nil)
1939a747e4fSDavid du Colombier 		return;
1949a747e4fSDavid du Colombier 	if(--k->ref != 0)
1959a747e4fSDavid du Colombier 		return;
196d9306527SDavid du Colombier 	if(k->proto && k->proto->closekey)
197d9306527SDavid du Colombier 		(*k->proto->closekey)(k);
1989a747e4fSDavid du Colombier 	_freeattr(k->attr);
1999a747e4fSDavid du Colombier 	_freeattr(k->privattr);
2009a747e4fSDavid du Colombier 	k->attr = (void*)~1;
2019a747e4fSDavid du Colombier 	k->privattr = (void*)~1;
2029a747e4fSDavid du Colombier 	k->proto = nil;
2039a747e4fSDavid du Colombier 	free(k);
2049a747e4fSDavid du Colombier }
2059a747e4fSDavid du Colombier 
2069a747e4fSDavid du Colombier static uchar*
2079a747e4fSDavid du Colombier pstring(uchar *p, uchar *e, char *s)
2089a747e4fSDavid du Colombier {
2099a747e4fSDavid du Colombier 	uint n;
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier 	if(p == nil)
2129a747e4fSDavid du Colombier 		return nil;
2139a747e4fSDavid du Colombier 	if(s == nil)
2149a747e4fSDavid du Colombier 		s = "";
2159a747e4fSDavid du Colombier 	n = strlen(s);
2169a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2179a747e4fSDavid du Colombier 		return nil;
2189a747e4fSDavid du Colombier 	PBIT16(p, n);
2199a747e4fSDavid du Colombier 	p += BIT16SZ;
2209a747e4fSDavid du Colombier 	memmove(p, s, n);
2219a747e4fSDavid du Colombier 	p += n;
2229a747e4fSDavid du Colombier 	return p;
2239a747e4fSDavid du Colombier }
2249a747e4fSDavid du Colombier 
2259a747e4fSDavid du Colombier static uchar*
2269a747e4fSDavid du Colombier pcarray(uchar *p, uchar *e, uchar *s, uint n)
2279a747e4fSDavid du Colombier {
2289a747e4fSDavid du Colombier 	if(p == nil)
2299a747e4fSDavid du Colombier 		return nil;
2309a747e4fSDavid du Colombier 	if(s == nil){
2319a747e4fSDavid du Colombier 		if(n > 0)
2329a747e4fSDavid du Colombier 			sysfatal("pcarray");
2339a747e4fSDavid du Colombier 		s = (uchar*)"";
2349a747e4fSDavid du Colombier 	}
2359a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2369a747e4fSDavid du Colombier 		return nil;
2379a747e4fSDavid du Colombier 	PBIT16(p, n);
2389a747e4fSDavid du Colombier 	p += BIT16SZ;
2399a747e4fSDavid du Colombier 	memmove(p, s, n);
2409a747e4fSDavid du Colombier 	p += n;
2419a747e4fSDavid du Colombier 	return p;
2429a747e4fSDavid du Colombier }
2439a747e4fSDavid du Colombier 
2449a747e4fSDavid du Colombier uchar*
2459a747e4fSDavid du Colombier convAI2M(AuthInfo *ai, uchar *p, int n)
2469a747e4fSDavid du Colombier {
2479a747e4fSDavid du Colombier 	uchar *e = p+n;
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cuid);
2509a747e4fSDavid du Colombier 	p = pstring(p, e, ai->suid);
2519a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cap);
2529a747e4fSDavid du Colombier 	p = pcarray(p, e, ai->secret, ai->nsecret);
2539a747e4fSDavid du Colombier 	return p;
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier int
2579a747e4fSDavid du Colombier failure(Fsstate *s, char *fmt, ...)
2589a747e4fSDavid du Colombier {
2599a747e4fSDavid du Colombier 	char e[ERRMAX];
2609a747e4fSDavid du Colombier 	va_list arg;
2619a747e4fSDavid du Colombier 
2629a747e4fSDavid du Colombier 	if(fmt == nil)
2639a747e4fSDavid du Colombier 		rerrstr(s->err, sizeof(s->err));
2649a747e4fSDavid du Colombier 	else {
2659a747e4fSDavid du Colombier 		va_start(arg, fmt);
2669a747e4fSDavid du Colombier 		snprint(e, sizeof e, fmt, arg);
2679a747e4fSDavid du Colombier 		va_end(arg);
2689a747e4fSDavid du Colombier 		strecpy(s->err, s->err+sizeof(s->err), e);
2699a747e4fSDavid du Colombier 		errstr(e, sizeof e);
2709a747e4fSDavid du Colombier 	}
2719a747e4fSDavid du Colombier 	flog("%d: failure %s", s->seqnum, s->err);
2729a747e4fSDavid du Colombier 	return RpcFailure;
2739a747e4fSDavid du Colombier }
2749a747e4fSDavid du Colombier 
2759a747e4fSDavid du Colombier static int
2769a747e4fSDavid du Colombier hasqueries(Attr *a)
2779a747e4fSDavid du Colombier {
2789a747e4fSDavid du Colombier 	for(; a; a=a->next)
2799a747e4fSDavid du Colombier 		if(a->type == AttrQuery)
2809a747e4fSDavid du Colombier 			return 1;
2819a747e4fSDavid du Colombier 	return 0;
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier 
2849a747e4fSDavid du Colombier char *ignored[] = {
2859a747e4fSDavid du Colombier 	"role",
286260f7b65SDavid du Colombier 	"disabled",
2879a747e4fSDavid du Colombier };
2889a747e4fSDavid du Colombier 
2899a747e4fSDavid du Colombier static int
2909a747e4fSDavid du Colombier ignoreattr(char *s)
2919a747e4fSDavid du Colombier {
2929a747e4fSDavid du Colombier 	int i;
2939a747e4fSDavid du Colombier 
2949a747e4fSDavid du Colombier 	for(i=0; i<nelem(ignored); i++)
2959a747e4fSDavid du Colombier 		if(strcmp(ignored[i], s)==0)
2969a747e4fSDavid du Colombier 			return 1;
2979a747e4fSDavid du Colombier 	return 0;
2989a747e4fSDavid du Colombier }
2999a747e4fSDavid du Colombier 
300260f7b65SDavid du Colombier Keyinfo*
301260f7b65SDavid du Colombier mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
302260f7b65SDavid du Colombier {
303260f7b65SDavid du Colombier 	memset(k, 0, sizeof *k);
304260f7b65SDavid du Colombier 	k->fss = fss;
305260f7b65SDavid du Colombier 	k->user = fss->sysuser;
3066b8bc682SDavid du Colombier 	if(attr)
307260f7b65SDavid du Colombier 		k->attr = attr;
3086b8bc682SDavid du Colombier 	else
3096b8bc682SDavid du Colombier 		k->attr = fss->attr;
310260f7b65SDavid du Colombier 	return k;
311260f7b65SDavid du Colombier }
312260f7b65SDavid du Colombier 
3139a747e4fSDavid du Colombier int
314260f7b65SDavid du Colombier findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
3159a747e4fSDavid du Colombier {
3169a747e4fSDavid du Colombier 	int i, s, nmatch;
317260f7b65SDavid du Colombier 	char buf[1024], *p, *who;
3189a747e4fSDavid du Colombier 	va_list arg;
319260f7b65SDavid du Colombier 	Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
3209a747e4fSDavid du Colombier 	Key *k;
3219a747e4fSDavid du Colombier 
3229a747e4fSDavid du Colombier 	*ret = nil;
3239a747e4fSDavid du Colombier 
324260f7b65SDavid du Colombier 	who = ki->user;
325260f7b65SDavid du Colombier 	attr0 = ki->attr;
3269a747e4fSDavid du Colombier 	if(fmt){
3279a747e4fSDavid du Colombier 		va_start(arg, fmt);
3289a747e4fSDavid du Colombier 		vseprint(buf, buf+sizeof buf, fmt, arg);
3299a747e4fSDavid du Colombier 		va_end(arg);
3309a747e4fSDavid du Colombier 		attr1 = _parseattr(buf);
3319a747e4fSDavid du Colombier 	}else
3329a747e4fSDavid du Colombier 		attr1 = nil;
3339a747e4fSDavid du Colombier 
334fb7f0c93SDavid du Colombier 	if(who && strcmp(who, owner) == 0)
335fb7f0c93SDavid du Colombier 		who = nil;
336fb7f0c93SDavid du Colombier 
337fb7f0c93SDavid du Colombier 	if(who){
338fb7f0c93SDavid du Colombier 		snprint(buf, sizeof buf, "owner=%q", who);
339fb7f0c93SDavid du Colombier 		attr2 = _parseattr(buf);
340fb7f0c93SDavid du Colombier 		attr3 = _parseattr("owner=*");
341fb7f0c93SDavid du Colombier 	}else
342fb7f0c93SDavid du Colombier 		attr2 = attr3 = nil;
343fb7f0c93SDavid du Colombier 
3442ebbfa15SDavid du Colombier 	p = _strfindattr(attr0, "proto");
3459a747e4fSDavid du Colombier 	if(p == nil)
3462ebbfa15SDavid du Colombier 		p = _strfindattr(attr1, "proto");
3479a747e4fSDavid du Colombier 	if(p && findproto(p) == nil){
3489a747e4fSDavid du Colombier 		werrstr("unknown protocol %s", p);
3499a747e4fSDavid du Colombier 		_freeattr(attr1);
3504de34a7eSDavid du Colombier 		_freeattr(attr2);
3514de34a7eSDavid du Colombier 		_freeattr(attr3);
352260f7b65SDavid du Colombier 		return failure(ki->fss, nil);
3539a747e4fSDavid du Colombier 	}
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier 	nmatch = 0;
3569a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
3579a747e4fSDavid du Colombier 		k = ring->key[i];
358260f7b65SDavid du Colombier 		if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
359260f7b65SDavid du Colombier 			continue;
3609a747e4fSDavid du Colombier 		if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
361fb7f0c93SDavid du Colombier 			/* check ownership */
362fb7f0c93SDavid du Colombier 			if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
363fb7f0c93SDavid du Colombier 				continue;
364260f7b65SDavid du Colombier 			if(nmatch++ < ki->skip)
3659a747e4fSDavid du Colombier 				continue;
366260f7b65SDavid du Colombier 			if(!ki->noconf){
367260f7b65SDavid du Colombier 				switch(canusekey(ki->fss, k)){
3689a747e4fSDavid du Colombier 				case -1:
3699a747e4fSDavid du Colombier 					_freeattr(attr1);
3709a747e4fSDavid du Colombier 					return RpcConfirm;
3719a747e4fSDavid du Colombier 				case 0:
3729a747e4fSDavid du Colombier 					continue;
3739a747e4fSDavid du Colombier 				case 1:
3749a747e4fSDavid du Colombier 					break;
3759a747e4fSDavid du Colombier 				}
3769a747e4fSDavid du Colombier 			}
3779a747e4fSDavid du Colombier 			_freeattr(attr1);
3784de34a7eSDavid du Colombier 			_freeattr(attr2);
3794de34a7eSDavid du Colombier 			_freeattr(attr3);
3809a747e4fSDavid du Colombier 			k->ref++;
3819a747e4fSDavid du Colombier 			*ret = k;
3829a747e4fSDavid du Colombier 			return RpcOk;
3839a747e4fSDavid du Colombier 		}
3849a747e4fSDavid du Colombier 	}
385260f7b65SDavid du Colombier 	flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
3869a747e4fSDavid du Colombier 	werrstr("no key matches %A %A", attr0, attr1);
3874de34a7eSDavid du Colombier 	_freeattr(attr2);
3884de34a7eSDavid du Colombier 	_freeattr(attr3);
3899a747e4fSDavid du Colombier 	s = RpcFailure;
390fb7f0c93SDavid du Colombier 	if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
3919a747e4fSDavid du Colombier 		if(nmatch == 0){
3929a747e4fSDavid du Colombier 			attr0 = _copyattr(attr0);
3939a747e4fSDavid du Colombier 			for(l=&attr0; *l; l=&(*l)->next)
3949a747e4fSDavid du Colombier 				;
3959a747e4fSDavid du Colombier 			*l = attr1;
3969a747e4fSDavid du Colombier 			for(l=&attr0; *l; ){
3972ebbfa15SDavid du Colombier 				if(ignoreattr((*l)->name)){
3989a747e4fSDavid du Colombier 					a = *l;
3999a747e4fSDavid du Colombier 					*l = (*l)->next;
4009a747e4fSDavid du Colombier 					a->next = nil;
4019a747e4fSDavid du Colombier 					_freeattr(a);
4029a747e4fSDavid du Colombier 				}else
4039a747e4fSDavid du Colombier 					l = &(*l)->next;
4049a747e4fSDavid du Colombier 			}
4059a747e4fSDavid du Colombier 			attr0 = sortattr(attr0);
406260f7b65SDavid du Colombier 			snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
4079a747e4fSDavid du Colombier 			_freeattr(attr0);
4089a747e4fSDavid du Colombier 			attr1 = nil;	/* attr1 was linked to attr0 */
4099a747e4fSDavid du Colombier 		}else
410260f7b65SDavid du Colombier 			ki->fss->keyinfo[0] = '\0';
4119a747e4fSDavid du Colombier 		s = RpcNeedkey;
4129a747e4fSDavid du Colombier 	}
4139a747e4fSDavid du Colombier 	_freeattr(attr1);
4149a747e4fSDavid du Colombier 	if(s == RpcFailure)
415260f7b65SDavid du Colombier 		return failure(ki->fss, nil);	/* loads error string */
4169a747e4fSDavid du Colombier 	return s;
4179a747e4fSDavid du Colombier }
4189a747e4fSDavid du Colombier 
4199a747e4fSDavid du Colombier int
4209a747e4fSDavid du Colombier findp9authkey(Key **k, Fsstate *fss)
4219a747e4fSDavid du Colombier {
4229a747e4fSDavid du Colombier 	char *dom;
423260f7b65SDavid du Colombier 	Keyinfo ki;
4249a747e4fSDavid du Colombier 
4259a747e4fSDavid du Colombier 	/*
4269a747e4fSDavid du Colombier 	 * We don't use fss->attr here because we don't
4279a747e4fSDavid du Colombier 	 * care about what the user name is set to, for instance.
4289a747e4fSDavid du Colombier 	 */
429260f7b65SDavid du Colombier 	mkkeyinfo(&ki, fss, nil);
430260f7b65SDavid du Colombier 	ki.attr = nil;
431260f7b65SDavid du Colombier 	ki.user = nil;
4322ebbfa15SDavid du Colombier 	if(dom = _strfindattr(fss->attr, "dom"))
433260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
4349a747e4fSDavid du Colombier 	else
435260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
4369a747e4fSDavid du Colombier }
4379a747e4fSDavid du Colombier 
4389a747e4fSDavid du Colombier Proto*
4399a747e4fSDavid du Colombier findproto(char *name)
4409a747e4fSDavid du Colombier {
4419a747e4fSDavid du Colombier 	int i;
4429a747e4fSDavid du Colombier 
4439a747e4fSDavid du Colombier 	for(i=0; prototab[i]; i++)
4449a747e4fSDavid du Colombier 		if(strcmp(name, prototab[i]->name) == 0)
4459a747e4fSDavid du Colombier 			return prototab[i];
4469a747e4fSDavid du Colombier 	return nil;
4479a747e4fSDavid du Colombier }
4489a747e4fSDavid du Colombier 
4499a747e4fSDavid du Colombier char*
4509a747e4fSDavid du Colombier getnvramkey(int flag, char **secstorepw)
4519a747e4fSDavid du Colombier {
4529a747e4fSDavid du Colombier 	char *s;
4539a747e4fSDavid du Colombier 	Nvrsafe safe;
4549a747e4fSDavid du Colombier 	char spw[CONFIGLEN+1];
4559a747e4fSDavid du Colombier 	int i;
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 	memset(&safe, 0, sizeof safe);
4589a747e4fSDavid du Colombier 	/*
4599a747e4fSDavid du Colombier 	 * readnvram can return -1 meaning nvram wasn't written,
4609a747e4fSDavid du Colombier 	 * but safe still holds good data.
4619a747e4fSDavid du Colombier 	 */
4625fe11e25SDavid du Colombier 	if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
4639a747e4fSDavid du Colombier 		return nil;
4649a747e4fSDavid du Colombier 
4659a747e4fSDavid du Colombier 	/*
4669a747e4fSDavid du Colombier 	 *  we're using the config area to hold the secstore
4679a747e4fSDavid du Colombier 	 *  password.  if there's anything there, return it.
4689a747e4fSDavid du Colombier 	 */
4699a747e4fSDavid du Colombier 	memmove(spw, safe.config, CONFIGLEN);
4709a747e4fSDavid du Colombier 	spw[CONFIGLEN] = 0;
4719a747e4fSDavid du Colombier 	if(spw[0] != 0)
4729a747e4fSDavid du Colombier 		*secstorepw = estrdup(spw);
4739a747e4fSDavid du Colombier 
4749a747e4fSDavid du Colombier 	/*
4759a747e4fSDavid du Colombier 	 *  only use nvram key if it is non-zero
4769a747e4fSDavid du Colombier 	 */
4779a747e4fSDavid du Colombier 	for(i = 0; i < DESKEYLEN; i++)
4789a747e4fSDavid du Colombier 		if(safe.machkey[i] != 0)
4799a747e4fSDavid du Colombier 			break;
4809a747e4fSDavid du Colombier 	if(i == DESKEYLEN)
4819a747e4fSDavid du Colombier 		return nil;
4829a747e4fSDavid du Colombier 
4839a747e4fSDavid du Colombier 	s = emalloc(512);
4849a747e4fSDavid du Colombier 	fmtinstall('H', encodefmt);
4859a747e4fSDavid du Colombier 	sprint(s, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
4869a747e4fSDavid du Colombier 		safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
4879a747e4fSDavid du Colombier 	writehostowner(safe.authid);
4889a747e4fSDavid du Colombier 
4899a747e4fSDavid du Colombier 	return s;
4909a747e4fSDavid du Colombier }
4919a747e4fSDavid du Colombier 
4929a747e4fSDavid du Colombier int
4939a747e4fSDavid du Colombier isclient(char *role)
4949a747e4fSDavid du Colombier {
4959a747e4fSDavid du Colombier 	if(role == nil){
4969a747e4fSDavid du Colombier 		werrstr("role not specified");
4979a747e4fSDavid du Colombier 		return -1;
4989a747e4fSDavid du Colombier 	}
4999a747e4fSDavid du Colombier 	if(strcmp(role, "server") == 0)
5009a747e4fSDavid du Colombier 		return 0;
5019a747e4fSDavid du Colombier 	if(strcmp(role, "client") == 0)
5029a747e4fSDavid du Colombier 		return 1;
5039a747e4fSDavid du Colombier 	werrstr("unknown role %q", role);
5049a747e4fSDavid du Colombier 	return -1;
5059a747e4fSDavid du Colombier }
5069a747e4fSDavid du Colombier 
5079a747e4fSDavid du Colombier static int
5089a747e4fSDavid du Colombier hasname(Attr *a0, Attr *a1, char *name)
5099a747e4fSDavid du Colombier {
5109a747e4fSDavid du Colombier 	return _findattr(a0, name) || _findattr(a1, name);
5119a747e4fSDavid du Colombier }
5129a747e4fSDavid du Colombier 
5139a747e4fSDavid du Colombier static int
5149a747e4fSDavid du Colombier hasnameval(Attr *a0, Attr *a1, char *name, char *val)
5159a747e4fSDavid du Colombier {
5169a747e4fSDavid du Colombier 	Attr *a;
5179a747e4fSDavid du Colombier 
5189a747e4fSDavid du Colombier 	for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
5192ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5209a747e4fSDavid du Colombier 			return 1;
5219a747e4fSDavid du Colombier 	for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
5222ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5239a747e4fSDavid du Colombier 			return 1;
5249a747e4fSDavid du Colombier 	return 0;
5259a747e4fSDavid du Colombier }
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier int
5289a747e4fSDavid du Colombier matchattr(Attr *pat, Attr *a0, Attr *a1)
5299a747e4fSDavid du Colombier {
5309a747e4fSDavid du Colombier 	int type;
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier 	for(; pat; pat=pat->next){
5339a747e4fSDavid du Colombier 		type = pat->type;
5342ebbfa15SDavid du Colombier 		if(ignoreattr(pat->name))
5359a747e4fSDavid du Colombier 			type = AttrDefault;
5369a747e4fSDavid du Colombier 		switch(type){
5379a747e4fSDavid du Colombier 		case AttrQuery:		/* name=something be present */
5382ebbfa15SDavid du Colombier 			if(!hasname(a0, a1, pat->name))
5399a747e4fSDavid du Colombier 				return 0;
5409a747e4fSDavid du Colombier 			break;
5419a747e4fSDavid du Colombier 		case AttrNameval:	/* name=val must be present */
5422ebbfa15SDavid du Colombier 			if(!hasnameval(a0, a1, pat->name, pat->val))
5439a747e4fSDavid du Colombier 				return 0;
5449a747e4fSDavid du Colombier 			break;
5459a747e4fSDavid du Colombier 		case AttrDefault:	/* name=val must be present if name=anything is present */
5462ebbfa15SDavid du Colombier 			if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
5479a747e4fSDavid du Colombier 				return 0;
5489a747e4fSDavid du Colombier 			break;
5499a747e4fSDavid du Colombier 		}
5509a747e4fSDavid du Colombier 	}
5519a747e4fSDavid du Colombier 	return 1;
5529a747e4fSDavid du Colombier }
5539a747e4fSDavid du Colombier 
5549a747e4fSDavid du Colombier void
5559a747e4fSDavid du Colombier memrandom(void *p, int n)
5569a747e4fSDavid du Colombier {
5579a747e4fSDavid du Colombier 	uchar *cp;
5589a747e4fSDavid du Colombier 
5599a747e4fSDavid du Colombier 	for(cp = (uchar*)p; n > 0; n--)
5609a747e4fSDavid du Colombier 		*cp++ = fastrand();
5619a747e4fSDavid du Colombier }
5629a747e4fSDavid du Colombier 
5639a747e4fSDavid du Colombier /*
5643ff48bf5SDavid du Colombier  *  keep caphash fd open since opens of it could be disabled
5653ff48bf5SDavid du Colombier  */
5663ff48bf5SDavid du Colombier static int caphashfd;
5673ff48bf5SDavid du Colombier 
5683ff48bf5SDavid du Colombier void
5693ff48bf5SDavid du Colombier initcap(void)
5703ff48bf5SDavid du Colombier {
5713ff48bf5SDavid du Colombier 	caphashfd = open("#¤/caphash", OWRITE);
572d9306527SDavid du Colombier //	if(caphashfd < 0)
573d9306527SDavid du Colombier //		fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
5743ff48bf5SDavid du Colombier }
5753ff48bf5SDavid du Colombier 
5763ff48bf5SDavid du Colombier /*
5779a747e4fSDavid du Colombier  *  create a change uid capability
5789a747e4fSDavid du Colombier  */
5799a747e4fSDavid du Colombier char*
5803ff48bf5SDavid du Colombier mkcap(char *from, char *to)
5819a747e4fSDavid du Colombier {
5829a747e4fSDavid du Colombier 	uchar rand[20];
5839a747e4fSDavid du Colombier 	char *cap;
5849a747e4fSDavid du Colombier 	char *key;
5853ff48bf5SDavid du Colombier 	int nfrom, nto;
5869a747e4fSDavid du Colombier 	uchar hash[SHA1dlen];
5879a747e4fSDavid du Colombier 
5883ff48bf5SDavid du Colombier 	if(caphashfd < 0)
5899a747e4fSDavid du Colombier 		return nil;
5909a747e4fSDavid du Colombier 
5919a747e4fSDavid du Colombier 	/* create the capability */
5923ff48bf5SDavid du Colombier 	nto = strlen(to);
5933ff48bf5SDavid du Colombier 	nfrom = strlen(from);
5943ff48bf5SDavid du Colombier 	cap = emalloc(nfrom+1+nto+1+sizeof(rand)*3+1);
5953ff48bf5SDavid du Colombier 	sprint(cap, "%s@%s", from, to);
5969a747e4fSDavid du Colombier 	memrandom(rand, sizeof(rand));
5973ff48bf5SDavid du Colombier 	key = cap+nfrom+1+nto+1;
5989a747e4fSDavid du Colombier 	enc64(key, sizeof(rand)*3, rand, sizeof(rand));
5999a747e4fSDavid du Colombier 
6009a747e4fSDavid du Colombier 	/* hash the capability */
6013ff48bf5SDavid du Colombier 	hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
6029a747e4fSDavid du Colombier 
6039a747e4fSDavid du Colombier 	/* give the kernel the hash */
6043ff48bf5SDavid du Colombier 	key[-1] = '@';
6053ff48bf5SDavid du Colombier 	if(write(caphashfd, hash, SHA1dlen) < 0){
6069a747e4fSDavid du Colombier 		free(cap);
6079a747e4fSDavid du Colombier 		return nil;
6089a747e4fSDavid du Colombier 	}
6099a747e4fSDavid du Colombier 
6109a747e4fSDavid du Colombier 	return cap;
6119a747e4fSDavid du Colombier }
6129a747e4fSDavid du Colombier 
6139a747e4fSDavid du Colombier int
6149a747e4fSDavid du Colombier phaseerror(Fsstate *s, char *op)
6159a747e4fSDavid du Colombier {
6169a747e4fSDavid du Colombier 	char tmp[32];
6179a747e4fSDavid du Colombier 
6189a747e4fSDavid du Colombier 	werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));
6199a747e4fSDavid du Colombier 	return RpcPhase;
6209a747e4fSDavid du Colombier }
6219a747e4fSDavid du Colombier 
6229a747e4fSDavid du Colombier char*
6239a747e4fSDavid du Colombier phasename(Fsstate *fss, int phase, char *tmp)
6249a747e4fSDavid du Colombier {
6259a747e4fSDavid du Colombier 	char *name;
6269a747e4fSDavid du Colombier 
6279a747e4fSDavid du Colombier 	if(fss->phase == Broken)
6289a747e4fSDavid du Colombier 		name = "Broken";
6299a747e4fSDavid du Colombier 	else if(phase == Established)
6309a747e4fSDavid du Colombier 		name = "Established";
6319a747e4fSDavid du Colombier 	else if(phase == Notstarted)
6329a747e4fSDavid du Colombier 		name = "Notstarted";
6339a747e4fSDavid du Colombier 	else if(phase < 0 || phase >= fss->maxphase
6349a747e4fSDavid du Colombier 	|| (name = fss->phasename[phase]) == nil){
6359a747e4fSDavid du Colombier 		sprint(tmp, "%d", phase);
6369a747e4fSDavid du Colombier 		name = tmp;
6379a747e4fSDavid du Colombier 	}
6389a747e4fSDavid du Colombier 	return name;
6399a747e4fSDavid du Colombier }
6409a747e4fSDavid du Colombier 
6419a747e4fSDavid du Colombier static int
6429a747e4fSDavid du Colombier outin(char *prompt, char *def, int len)
6439a747e4fSDavid du Colombier {
6442ebbfa15SDavid du Colombier 	char *s;
6459a747e4fSDavid du Colombier 
6469a747e4fSDavid du Colombier 	s = readcons(prompt, def, 0);
6479a747e4fSDavid du Colombier 	if(s == nil)
6489a747e4fSDavid du Colombier 		return -1;
6492ebbfa15SDavid du Colombier 	if(s == nil)
6502ebbfa15SDavid du Colombier 		sysfatal("s==nil???");
6512ebbfa15SDavid du Colombier 	strncpy(def, s, len);
6529a747e4fSDavid du Colombier 	def[len-1] = 0;
6532ebbfa15SDavid du Colombier 	free(s);
6549a747e4fSDavid du Colombier 	return strlen(def);
6559a747e4fSDavid du Colombier }
6569a747e4fSDavid du Colombier 
6579a747e4fSDavid du Colombier /*
6589a747e4fSDavid du Colombier  *  get host owner and set it
6599a747e4fSDavid du Colombier  */
6609a747e4fSDavid du Colombier void
6619a747e4fSDavid du Colombier promptforhostowner(void)
6629a747e4fSDavid du Colombier {
6639a747e4fSDavid du Colombier 	char owner[64], *p;
6649a747e4fSDavid du Colombier 
6659a747e4fSDavid du Colombier 	/* hack for bitsy; can't prompt during boot */
6669a747e4fSDavid du Colombier 	if(p = getenv("user")){
6679a747e4fSDavid du Colombier 		writehostowner(p);
668d9306527SDavid du Colombier 		free(p);
6699a747e4fSDavid du Colombier 		return;
6709a747e4fSDavid du Colombier 	}
671d9306527SDavid du Colombier 	free(p);
6729a747e4fSDavid du Colombier 
6739a747e4fSDavid du Colombier 	strcpy(owner, "none");
6749a747e4fSDavid du Colombier 	do{
6759a747e4fSDavid du Colombier 		outin("user", owner, sizeof(owner));
6769a747e4fSDavid du Colombier 	} while(*owner == 0);
6779a747e4fSDavid du Colombier 	writehostowner(owner);
6789a747e4fSDavid du Colombier }
6799a747e4fSDavid du Colombier 
6802ebbfa15SDavid du Colombier char*
6812ebbfa15SDavid du Colombier estrappend(char *s, char *fmt, ...)
6822ebbfa15SDavid du Colombier {
6832ebbfa15SDavid du Colombier 	char *t;
6842ebbfa15SDavid du Colombier 	va_list arg;
6852ebbfa15SDavid du Colombier 
6862ebbfa15SDavid du Colombier 	va_start(arg, fmt);
6872ebbfa15SDavid du Colombier 	t = vsmprint(fmt, arg);
6882ebbfa15SDavid du Colombier 	if(t == nil)
6892ebbfa15SDavid du Colombier 		sysfatal("out of memory");
6902ebbfa15SDavid du Colombier 	va_end(arg);
6912ebbfa15SDavid du Colombier 	s = erealloc(s, strlen(s)+strlen(t)+1);
6922ebbfa15SDavid du Colombier 	strcat(s, t);
6932ebbfa15SDavid du Colombier 	free(t);
6942ebbfa15SDavid du Colombier 	return s;
6952ebbfa15SDavid du Colombier }
6962ebbfa15SDavid du Colombier 
6972ebbfa15SDavid du Colombier 
6989a747e4fSDavid du Colombier /*
6999a747e4fSDavid du Colombier  *  prompt for a string with a possible default response
7009a747e4fSDavid du Colombier  */
7012ebbfa15SDavid du Colombier char*
7029a747e4fSDavid du Colombier readcons(char *prompt, char *def, int raw)
7039a747e4fSDavid du Colombier {
7049a747e4fSDavid du Colombier 	int fdin, fdout, ctl, n;
7059a747e4fSDavid du Colombier 	char line[10];
7062ebbfa15SDavid du Colombier 	char *s;
7079a747e4fSDavid du Colombier 
7089a747e4fSDavid du Colombier 	fdin = open("/dev/cons", OREAD);
7099a747e4fSDavid du Colombier 	if(fdin < 0)
7109a747e4fSDavid du Colombier 		fdin = 0;
7119a747e4fSDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
7129a747e4fSDavid du Colombier 	if(fdout < 0)
7139a747e4fSDavid du Colombier 		fdout = 1;
7149a747e4fSDavid du Colombier 	if(def != nil)
7159a747e4fSDavid du Colombier 		fprint(fdout, "%s[%s]: ", prompt, def);
7169a747e4fSDavid du Colombier 	else
7179a747e4fSDavid du Colombier 		fprint(fdout, "%s: ", prompt);
7189a747e4fSDavid du Colombier 	if(raw){
7199a747e4fSDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
7209a747e4fSDavid du Colombier 		if(ctl >= 0)
7219a747e4fSDavid du Colombier 			write(ctl, "rawon", 5);
7229a747e4fSDavid du Colombier 	} else
7239a747e4fSDavid du Colombier 		ctl = -1;
7242ebbfa15SDavid du Colombier 	s = estrdup("");
7259a747e4fSDavid du Colombier 	for(;;){
7269a747e4fSDavid du Colombier 		n = read(fdin, line, 1);
7279a747e4fSDavid du Colombier 		if(n == 0){
7289a747e4fSDavid du Colombier 		Error:
7299a747e4fSDavid du Colombier 			close(fdin);
7309a747e4fSDavid du Colombier 			close(fdout);
7319a747e4fSDavid du Colombier 			if(ctl >= 0)
7329a747e4fSDavid du Colombier 				close(ctl);
7332ebbfa15SDavid du Colombier 			free(s);
7349a747e4fSDavid du Colombier 			return nil;
7359a747e4fSDavid du Colombier 		}
7369a747e4fSDavid du Colombier 		if(n < 0)
7379a747e4fSDavid du Colombier 			goto Error;
7389a747e4fSDavid du Colombier 		if(line[0] == 0x7f)
7399a747e4fSDavid du Colombier 			goto Error;
7409a747e4fSDavid du Colombier 		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
7419a747e4fSDavid du Colombier 			if(raw){
7429a747e4fSDavid du Colombier 				write(ctl, "rawoff", 6);
7439a747e4fSDavid du Colombier 				write(fdout, "\n", 1);
7449a747e4fSDavid du Colombier 			}
7459a747e4fSDavid du Colombier 			close(ctl);
7469a747e4fSDavid du Colombier 			close(fdin);
7479a747e4fSDavid du Colombier 			close(fdout);
7482ebbfa15SDavid du Colombier 			if(*s == 0 && def != nil)
7492ebbfa15SDavid du Colombier 				s = estrappend(s, "%s", def);
7509a747e4fSDavid du Colombier 			return s;
7519a747e4fSDavid du Colombier 		}
7529a747e4fSDavid du Colombier 		if(line[0] == '\b'){
7532ebbfa15SDavid du Colombier 			if(strlen(s) > 0)
7542ebbfa15SDavid du Colombier 				s[strlen(s)-1] = 0;
7559a747e4fSDavid du Colombier 		} else if(line[0] == 0x15) {	/* ^U: line kill */
7562ebbfa15SDavid du Colombier 			if(def != nil)
7572ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s[%s]: ", prompt, def);
7582ebbfa15SDavid du Colombier 			else
7592ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s: ", prompt);
7602ebbfa15SDavid du Colombier 
7612ebbfa15SDavid du Colombier 			s[0] = 0;
7629a747e4fSDavid du Colombier 		} else {
7632ebbfa15SDavid du Colombier 			s = estrappend(s, "%c", line[0]);
7649a747e4fSDavid du Colombier 		}
7659a747e4fSDavid du Colombier 	}
7662ebbfa15SDavid du Colombier 	return nil; /* not reached */
7679a747e4fSDavid du Colombier }
7689a747e4fSDavid du Colombier 
7699a747e4fSDavid du Colombier /*
7709a747e4fSDavid du Colombier  * Insert a key into the keyring.
7719a747e4fSDavid du Colombier  * If the public attributes are identical to some other key, replace that one.
7729a747e4fSDavid du Colombier  */
7739a747e4fSDavid du Colombier int
77470b8e010SDavid du Colombier replacekey(Key *kn, int before)
7759a747e4fSDavid du Colombier {
7769a747e4fSDavid du Colombier 	int i;
7779a747e4fSDavid du Colombier 	Key *k;
7789a747e4fSDavid du Colombier 
7799a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
7809a747e4fSDavid du Colombier 		k = ring->key[i];
7819a747e4fSDavid du Colombier 		if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
7829a747e4fSDavid du Colombier 			closekey(k);
7839a747e4fSDavid du Colombier 			kn->ref++;
7849a747e4fSDavid du Colombier 			ring->key[i] = kn;
7859a747e4fSDavid du Colombier 			return 0;
7869a747e4fSDavid du Colombier 		}
7879a747e4fSDavid du Colombier 	}
7889a747e4fSDavid du Colombier 	if(ring->nkey%16 == 0)
7899a747e4fSDavid du Colombier 		ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
7909a747e4fSDavid du Colombier 	kn->ref++;
79170b8e010SDavid du Colombier 	if(before){
79270b8e010SDavid du Colombier 		memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
79370b8e010SDavid du Colombier 		ring->key[0] = kn;
79470b8e010SDavid du Colombier 		ring->nkey++;
79570b8e010SDavid du Colombier 	}else
7969a747e4fSDavid du Colombier 		ring->key[ring->nkey++] = kn;
7979a747e4fSDavid du Colombier 	return 0;
7989a747e4fSDavid du Colombier }
7999a747e4fSDavid du Colombier 
8009a747e4fSDavid du Colombier char*
8019a747e4fSDavid du Colombier safecpy(char *to, char *from, int n)
8029a747e4fSDavid du Colombier {
8039a747e4fSDavid du Colombier 	memset(to, 0, n);
8049a747e4fSDavid du Colombier 	if(n == 1)
8059a747e4fSDavid du Colombier 		return to;
8069a747e4fSDavid du Colombier 	if(from==nil)
8079a747e4fSDavid du Colombier 		sysfatal("safecpy called with from==nil, pc=%lux\n",
8089a747e4fSDavid du Colombier 			getcallerpc(&to));
8099a747e4fSDavid du Colombier 	strncpy(to, from, n-1);
8109a747e4fSDavid du Colombier 	return to;
8119a747e4fSDavid du Colombier }
8129a747e4fSDavid du Colombier 
8139a747e4fSDavid du Colombier Attr*
8149a747e4fSDavid du Colombier setattr(Attr *a, char *fmt, ...)
8159a747e4fSDavid du Colombier {
8169a747e4fSDavid du Colombier 	char buf[1024];
8179a747e4fSDavid du Colombier 	va_list arg;
8189a747e4fSDavid du Colombier 	Attr *b;
8199a747e4fSDavid du Colombier 
8209a747e4fSDavid du Colombier 	va_start(arg, fmt);
8219a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof buf, fmt, arg);
8229a747e4fSDavid du Colombier 	va_end(arg);
8239a747e4fSDavid du Colombier 	b = _parseattr(buf);
8249a747e4fSDavid du Colombier 	a = setattrs(a, b);
8259a747e4fSDavid du Colombier 	setmalloctag(a, getcallerpc(&a));
8269a747e4fSDavid du Colombier 	_freeattr(b);
8279a747e4fSDavid du Colombier 	return a;
8289a747e4fSDavid du Colombier }
8299a747e4fSDavid du Colombier 
8309a747e4fSDavid du Colombier /*
8319a747e4fSDavid du Colombier  *  add attributes in list b to list a.  If any attributes are in
8329a747e4fSDavid du Colombier  *  both lists, replace those in a by those in b.
8339a747e4fSDavid du Colombier  */
8349a747e4fSDavid du Colombier Attr*
8359a747e4fSDavid du Colombier setattrs(Attr *a, Attr *b)
8369a747e4fSDavid du Colombier {
8379a747e4fSDavid du Colombier 	int found;
8389a747e4fSDavid du Colombier 	Attr **l, *freea;
8399a747e4fSDavid du Colombier 
8409a747e4fSDavid du Colombier 	for(; b; b=b->next){
8419a747e4fSDavid du Colombier 		found = 0;
8429a747e4fSDavid du Colombier 		for(l=&a; *l; ){
8432ebbfa15SDavid du Colombier 			if(strcmp(b->name, (*l)->name) == 0){
8449a747e4fSDavid du Colombier 				switch(b->type){
8459a747e4fSDavid du Colombier 				case AttrNameval:
8469a747e4fSDavid du Colombier 					if(!found){
8479a747e4fSDavid du Colombier 						found = 1;
8482ebbfa15SDavid du Colombier 						free((*l)->val);
8492ebbfa15SDavid du Colombier 						(*l)->val = estrdup(b->val);
8509a747e4fSDavid du Colombier 						(*l)->type = AttrNameval;
8519a747e4fSDavid du Colombier 						l = &(*l)->next;
8529a747e4fSDavid du Colombier 					}else{
8539a747e4fSDavid du Colombier 						freea = *l;
8549a747e4fSDavid du Colombier 						*l = (*l)->next;
8559a747e4fSDavid du Colombier 						freea->next = nil;
8569a747e4fSDavid du Colombier 						_freeattr(freea);
8579a747e4fSDavid du Colombier 					}
8589a747e4fSDavid du Colombier 					break;
8599a747e4fSDavid du Colombier 				case AttrQuery:
860*f0ed0fb6SDavid du Colombier 					goto continue2;
8619a747e4fSDavid du Colombier 				}
8629a747e4fSDavid du Colombier 			}else
8639a747e4fSDavid du Colombier 				l = &(*l)->next;
8649a747e4fSDavid du Colombier 		}
8659a747e4fSDavid du Colombier 		if(found == 0){
8662ebbfa15SDavid du Colombier 			*l = _mkattr(b->type, b->name, b->val, nil);
8679a747e4fSDavid du Colombier 			setmalloctag(*l, getcallerpc(&a));
8689a747e4fSDavid du Colombier 		}
869*f0ed0fb6SDavid du Colombier continue2:;
8709a747e4fSDavid du Colombier 	}
8719a747e4fSDavid du Colombier 	return a;
8729a747e4fSDavid du Colombier }
8739a747e4fSDavid du Colombier 
8749a747e4fSDavid du Colombier void
8759a747e4fSDavid du Colombier setmalloctaghere(void *v)
8769a747e4fSDavid du Colombier {
8779a747e4fSDavid du Colombier 	setmalloctag(v, getcallerpc(&v));
8789a747e4fSDavid du Colombier }
8799a747e4fSDavid du Colombier 
8809a747e4fSDavid du Colombier Attr*
8819a747e4fSDavid du Colombier sortattr(Attr *a)
8829a747e4fSDavid du Colombier {
8839a747e4fSDavid du Colombier 	int i;
8849a747e4fSDavid du Colombier 	Attr *anext, *a0, *a1, **l;
8859a747e4fSDavid du Colombier 
8869a747e4fSDavid du Colombier 	if(a == nil || a->next == nil)
8879a747e4fSDavid du Colombier 		return a;
8889a747e4fSDavid du Colombier 
8899a747e4fSDavid du Colombier 	/* cut list in halves */
8909a747e4fSDavid du Colombier 	a0 = nil;
8919a747e4fSDavid du Colombier 	a1 = nil;
8929a747e4fSDavid du Colombier 	i = 0;
8939a747e4fSDavid du Colombier 	for(; a; a=anext){
8949a747e4fSDavid du Colombier 		anext = a->next;
8959a747e4fSDavid du Colombier 		if(i++%2){
8969a747e4fSDavid du Colombier 			a->next = a0;
8979a747e4fSDavid du Colombier 			a0 = a;
8989a747e4fSDavid du Colombier 		}else{
8999a747e4fSDavid du Colombier 			a->next = a1;
9009a747e4fSDavid du Colombier 			a1 = a;
9019a747e4fSDavid du Colombier 		}
9029a747e4fSDavid du Colombier 	}
9039a747e4fSDavid du Colombier 
9049a747e4fSDavid du Colombier 	/* sort */
9059a747e4fSDavid du Colombier 	a0 = sortattr(a0);
9069a747e4fSDavid du Colombier 	a1 = sortattr(a1);
9079a747e4fSDavid du Colombier 
9089a747e4fSDavid du Colombier 	/* merge */
9099a747e4fSDavid du Colombier 	l = &a;
9109a747e4fSDavid du Colombier 	while(a0 || a1){
9119a747e4fSDavid du Colombier 		if(a1==nil){
9129a747e4fSDavid du Colombier 			anext = a0;
9139a747e4fSDavid du Colombier 			a0 = a0->next;
9149a747e4fSDavid du Colombier 		}else if(a0==nil){
9159a747e4fSDavid du Colombier 			anext = a1;
9169a747e4fSDavid du Colombier 			a1 = a1->next;
9172ebbfa15SDavid du Colombier 		}else if(strcmp(a0->name, a1->name) < 0){
9189a747e4fSDavid du Colombier 			anext = a0;
9199a747e4fSDavid du Colombier 			a0 = a0->next;
9209a747e4fSDavid du Colombier 		}else{
9219a747e4fSDavid du Colombier 			anext = a1;
9229a747e4fSDavid du Colombier 			a1 = a1->next;
9239a747e4fSDavid du Colombier 		}
9249a747e4fSDavid du Colombier 		*l = anext;
9259a747e4fSDavid du Colombier 		l = &(*l)->next;
9269a747e4fSDavid du Colombier 	}
9279a747e4fSDavid du Colombier 	*l = nil;
9289a747e4fSDavid du Colombier 	return a;
9299a747e4fSDavid du Colombier }
9309a747e4fSDavid du Colombier 
9319a747e4fSDavid du Colombier int
9329a747e4fSDavid du Colombier toosmall(Fsstate *fss, uint n)
9339a747e4fSDavid du Colombier {
9349a747e4fSDavid du Colombier 	fss->rpc.nwant = n;
9359a747e4fSDavid du Colombier 	return RpcToosmall;
9369a747e4fSDavid du Colombier }
9379a747e4fSDavid du Colombier 
9389a747e4fSDavid du Colombier void
9399a747e4fSDavid du Colombier writehostowner(char *owner)
9409a747e4fSDavid du Colombier {
9419a747e4fSDavid du Colombier 	int fd;
9429a747e4fSDavid du Colombier 	char *s;
9439a747e4fSDavid du Colombier 
9449a747e4fSDavid du Colombier 	if((s = strchr(owner,'@')) != nil){
9459a747e4fSDavid du Colombier 		*s++ = 0;
9469a747e4fSDavid du Colombier 		strncpy(secstore, s, (sizeof secstore)-1);
9479a747e4fSDavid du Colombier 	}
9489a747e4fSDavid du Colombier 	fd = open("#c/hostowner", OWRITE);
9499a747e4fSDavid du Colombier 	if(fd >= 0){
9509a747e4fSDavid du Colombier 		if(fprint(fd, "%s", owner) < 0)
9519a747e4fSDavid du Colombier 			fprint(2, "setting #c/hostowner to %q: %r\n", owner);
9529a747e4fSDavid du Colombier 		close(fd);
9539a747e4fSDavid du Colombier 	}
9549a747e4fSDavid du Colombier }
9559a747e4fSDavid du Colombier 
9565d459b5aSDavid du Colombier int
9575d459b5aSDavid du Colombier attrnamefmt(Fmt *fmt)
9585d459b5aSDavid du Colombier {
9595d459b5aSDavid du Colombier 	char *b, buf[1024], *ebuf;
9605d459b5aSDavid du Colombier 	Attr *a;
9615d459b5aSDavid du Colombier 
9625d459b5aSDavid du Colombier 	ebuf = buf+sizeof buf;
9635d459b5aSDavid du Colombier 	b = buf;
9645d459b5aSDavid du Colombier 	strcpy(buf, " ");
9655d459b5aSDavid du Colombier 	for(a=va_arg(fmt->args, Attr*); a; a=a->next){
9665d459b5aSDavid du Colombier 		if(a->name == nil)
9675d459b5aSDavid du Colombier 			continue;
9682ebbfa15SDavid du Colombier 		b = seprint(b, ebuf, " %q?", a->name);
9695d459b5aSDavid du Colombier 	}
9705d459b5aSDavid du Colombier 	return fmtstrcpy(fmt, buf+1);
9715d459b5aSDavid du Colombier }
972260f7b65SDavid du Colombier 
973260f7b65SDavid du Colombier void
974260f7b65SDavid du Colombier disablekey(Key *k)
975260f7b65SDavid du Colombier {
976260f7b65SDavid du Colombier 	Attr *a;
977260f7b65SDavid du Colombier 
978260f7b65SDavid du Colombier 	for(a=k->attr; a; a=a->next){
979260f7b65SDavid du Colombier 		if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
980260f7b65SDavid du Colombier 			return;
981260f7b65SDavid du Colombier 		if(a->next == nil)
982260f7b65SDavid du Colombier 			break;
983260f7b65SDavid du Colombier 	}
984260f7b65SDavid du Colombier 	if(a)
985260f7b65SDavid du Colombier 		a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
986260f7b65SDavid du Colombier 	else
987260f7b65SDavid du Colombier 		k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil);	/* not reached: always a proto attribute */
988260f7b65SDavid du Colombier }
989