xref: /plan9/sys/src/cmd/auth/factotum/util.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
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
bindnetcs(void)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
_authdial(char * net,char * authdom)269a747e4fSDavid du Colombier _authdial(char *net, char *authdom)
279a747e4fSDavid du Colombier {
28b05f4f54SDavid du Colombier 	int fd, vanilla;
299a747e4fSDavid du Colombier 
30b05f4f54SDavid du Colombier 	vanilla = net==nil || strcmp(net, "/net")==0;
31b05f4f54SDavid du Colombier 
32b05f4f54SDavid du Colombier 	if(!vanilla || bindnetcs()>=0)
33b05f4f54SDavid du Colombier 		return authdial(net, authdom);
34b05f4f54SDavid du Colombier 
35b05f4f54SDavid du Colombier 	/*
36b05f4f54SDavid du Colombier 	 * If we failed to mount /srv/cs, assume that
37b05f4f54SDavid du Colombier 	 * we're still bootstrapping the system and dial
38b05f4f54SDavid du Colombier 	 * the one auth server passed to us on the command line.
39b05f4f54SDavid du Colombier 	 * In normal operation, it is important *not* to do this,
40b05f4f54SDavid du Colombier 	 * because the bootstrap auth server is only good for
41b05f4f54SDavid du Colombier 	 * a single auth domain.
42b05f4f54SDavid du Colombier 	 *
43b05f4f54SDavid du Colombier 	 * The ticket request code should really check the
44b05f4f54SDavid du Colombier 	 * remote authentication domain too.
45b05f4f54SDavid du Colombier 	 */
469a747e4fSDavid du Colombier 
478c41de82SDavid du Colombier 	/* use the auth server passed to us as an arg */
489a747e4fSDavid du Colombier 	if(authaddr == nil)
499a747e4fSDavid du Colombier 		return -1;
508c41de82SDavid du Colombier 	fd = dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
519a747e4fSDavid du Colombier 	if(fd >= 0)
529a747e4fSDavid du Colombier 		return fd;
538c41de82SDavid du Colombier 	return dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
549a747e4fSDavid du Colombier }
559a747e4fSDavid du Colombier 
569a747e4fSDavid du Colombier int
secdial(void)579a747e4fSDavid du Colombier secdial(void)
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier 	char *p, buf[80], *f[3];
609a747e4fSDavid du Colombier 	int fd, nf;
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier 	p = secstore; /* take it from writehostowner, if set there */
639a747e4fSDavid du Colombier 	if(*p == 0)	  /* else use the authserver */
649a747e4fSDavid du Colombier 		p = "$auth";
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier 	if(bindnetcs() >= 0)
679a747e4fSDavid du Colombier 		return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
689a747e4fSDavid du Colombier 
699a747e4fSDavid du Colombier 	/* translate $auth ourselves.
709a747e4fSDavid du Colombier 	 * authaddr is something like il!host!566 or tcp!host!567.
719a747e4fSDavid du Colombier 	 * extract host, accounting for a change of format to something
729a747e4fSDavid du Colombier 	 * like il!host or tcp!host or host.
739a747e4fSDavid du Colombier 	 */
749a747e4fSDavid du Colombier 	if(strcmp(p, "$auth")==0){
759a747e4fSDavid du Colombier 		if(authaddr == nil)
769a747e4fSDavid du Colombier 			return -1;
779a747e4fSDavid du Colombier 		safecpy(buf, authaddr, sizeof buf);
789a747e4fSDavid du Colombier 		nf = getfields(buf, f, nelem(f), 0, "!");
799a747e4fSDavid du Colombier 		switch(nf){
809a747e4fSDavid du Colombier 		default:
819a747e4fSDavid du Colombier 			return -1;
829a747e4fSDavid du Colombier 		case 1:
839a747e4fSDavid du Colombier 			p = f[0];
849a747e4fSDavid du Colombier 			break;
859a747e4fSDavid du Colombier 		case 2:
869a747e4fSDavid du Colombier 		case 3:
879a747e4fSDavid du Colombier 			p = f[1];
889a747e4fSDavid du Colombier 			break;
899a747e4fSDavid du Colombier 		}
909a747e4fSDavid du Colombier 	}
919a747e4fSDavid du Colombier 	fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
929a747e4fSDavid du Colombier 	if(fd >= 0)
939a747e4fSDavid du Colombier 		return fd;
949a747e4fSDavid du Colombier 	return -1;
959a747e4fSDavid du Colombier }
969a747e4fSDavid du Colombier /*
979a747e4fSDavid du Colombier  *  prompt user for a key.  don't care about memory leaks, runs standalone
989a747e4fSDavid du Colombier  */
999a747e4fSDavid du Colombier static Attr*
promptforkey(char * params)1009a747e4fSDavid du Colombier promptforkey(char *params)
1019a747e4fSDavid du Colombier {
1029a747e4fSDavid du Colombier 	char *v;
1039a747e4fSDavid du Colombier 	int fd;
1049a747e4fSDavid du Colombier 	Attr *a, *attr;
1059a747e4fSDavid du Colombier 	char *def;
1069a747e4fSDavid du Colombier 
1079a747e4fSDavid du Colombier 	fd = open("/dev/cons", ORDWR);
1089a747e4fSDavid du Colombier 	if(fd < 0)
1099a747e4fSDavid du Colombier 		sysfatal("opening /dev/cons: %r");
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier 	attr = _parseattr(params);
1129a747e4fSDavid du Colombier 	fprint(fd, "\n!Adding key:");
1139a747e4fSDavid du Colombier 	for(a=attr; a; a=a->next)
1142ebbfa15SDavid du Colombier 		if(a->type != AttrQuery && a->name[0] != '!')
1152ebbfa15SDavid du Colombier 			fprint(fd, " %q=%q", a->name, a->val);
1169a747e4fSDavid du Colombier 	fprint(fd, "\n");
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, "user") == 0)
1249a747e4fSDavid du Colombier 			def = getuser();
1259a747e4fSDavid du Colombier 		a->val = readcons(v, def, 0);
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 	for(a=attr; a; a=a->next){
1312ebbfa15SDavid du Colombier 		v = a->name;
1329a747e4fSDavid du Colombier 		if(a->type != AttrQuery || v[0]!='!')
1339a747e4fSDavid du Colombier 			continue;
1349a747e4fSDavid du Colombier 		def = nil;
1359a747e4fSDavid du Colombier 		if(strcmp(v+1, "user") == 0)
1369a747e4fSDavid du Colombier 			def = getuser();
1379a747e4fSDavid du Colombier 		a->val = readcons(v+1, def, 1);
1389a747e4fSDavid du Colombier 		if(a->val == nil)
1399a747e4fSDavid du Colombier 			sysfatal("user terminated key input");
1409a747e4fSDavid du Colombier 		a->type = AttrNameval;
1419a747e4fSDavid du Colombier 	}
1429a747e4fSDavid du Colombier 	fprint(fd, "!\n");
1439a747e4fSDavid du Colombier 	close(fd);
1449a747e4fSDavid du Colombier 	return attr;
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier 
1479a747e4fSDavid du Colombier /*
1489a747e4fSDavid du Colombier  *  send a key to the mounted factotum
1499a747e4fSDavid du Colombier  */
1509a747e4fSDavid du Colombier static int
sendkey(Attr * attr)1519a747e4fSDavid du Colombier sendkey(Attr *attr)
1529a747e4fSDavid du Colombier {
1539a747e4fSDavid du Colombier 	int fd, rv;
1549a747e4fSDavid du Colombier 	char buf[1024];
1559a747e4fSDavid du Colombier 
1569a747e4fSDavid du Colombier 	fd = open("/mnt/factotum/ctl", ORDWR);
1579a747e4fSDavid du Colombier 	if(fd < 0)
1589a747e4fSDavid du Colombier 		sysfatal("opening /mnt/factotum/ctl: %r");
1599a747e4fSDavid du Colombier 	rv = fprint(fd, "key %A\n", attr);
1609a747e4fSDavid du Colombier 	read(fd, buf, sizeof buf);
1619a747e4fSDavid du Colombier 	close(fd);
1629a747e4fSDavid du Colombier 	return rv;
1639a747e4fSDavid du Colombier }
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier /* askuser */
1669a747e4fSDavid du Colombier void
askuser(char * params)1679a747e4fSDavid du Colombier askuser(char *params)
1689a747e4fSDavid du Colombier {
1699a747e4fSDavid du Colombier 	Attr *attr;
1709a747e4fSDavid du Colombier 
1719a747e4fSDavid du Colombier 	attr = promptforkey(params);
1729a747e4fSDavid du Colombier 	if(attr == nil)
1739a747e4fSDavid du Colombier 		sysfatal("no key supplied");
1749a747e4fSDavid du Colombier 	if(sendkey(attr) < 0)
1759a747e4fSDavid du Colombier 		sysfatal("sending key to factotum: %r");
1769a747e4fSDavid du Colombier }
1779a747e4fSDavid du Colombier 
1789a747e4fSDavid du Colombier ulong conftaggen;
1799a747e4fSDavid du Colombier int
canusekey(Fsstate * fss,Key * k)1809a747e4fSDavid du Colombier canusekey(Fsstate *fss, Key *k)
1819a747e4fSDavid du Colombier {
1829a747e4fSDavid du Colombier 	int i;
1839a747e4fSDavid du Colombier 
1842ebbfa15SDavid du Colombier 	if(_strfindattr(k->attr, "confirm")){
1859a747e4fSDavid du Colombier 		for(i=0; i<fss->nconf; i++)
1869a747e4fSDavid du Colombier 			if(fss->conf[i].key == k)
1879a747e4fSDavid du Colombier 				return fss->conf[i].canuse;
1889a747e4fSDavid du Colombier 		if(fss->nconf%16 == 0)
1899a747e4fSDavid du Colombier 			fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
1909a747e4fSDavid du Colombier 		fss->conf[fss->nconf].key = k;
1919a747e4fSDavid du Colombier 		k->ref++;
1929a747e4fSDavid du Colombier 		fss->conf[fss->nconf].canuse = -1;
1939a747e4fSDavid du Colombier 		fss->conf[fss->nconf].tag = conftaggen++;
1949a747e4fSDavid du Colombier 		fss->nconf++;
1959a747e4fSDavid du Colombier 		return -1;
1969a747e4fSDavid du Colombier 	}
1979a747e4fSDavid du Colombier 	return 1;
1989a747e4fSDavid du Colombier }
1999a747e4fSDavid du Colombier 
2009a747e4fSDavid du Colombier /* closekey */
2019a747e4fSDavid du Colombier void
closekey(Key * k)2029a747e4fSDavid du Colombier closekey(Key *k)
2039a747e4fSDavid du Colombier {
2049a747e4fSDavid du Colombier 	if(k == nil)
2059a747e4fSDavid du Colombier 		return;
2069a747e4fSDavid du Colombier 	if(--k->ref != 0)
2079a747e4fSDavid du Colombier 		return;
208d9306527SDavid du Colombier 	if(k->proto && k->proto->closekey)
209d9306527SDavid du Colombier 		(*k->proto->closekey)(k);
2109a747e4fSDavid du Colombier 	_freeattr(k->attr);
2119a747e4fSDavid du Colombier 	_freeattr(k->privattr);
2129a747e4fSDavid du Colombier 	k->attr = (void*)~1;
2139a747e4fSDavid du Colombier 	k->privattr = (void*)~1;
2149a747e4fSDavid du Colombier 	k->proto = nil;
2159a747e4fSDavid du Colombier 	free(k);
2169a747e4fSDavid du Colombier }
2179a747e4fSDavid du Colombier 
2189a747e4fSDavid du Colombier static uchar*
pstring(uchar * p,uchar * e,char * s)2199a747e4fSDavid du Colombier pstring(uchar *p, uchar *e, char *s)
2209a747e4fSDavid du Colombier {
2219a747e4fSDavid du Colombier 	uint n;
2229a747e4fSDavid du Colombier 
2239a747e4fSDavid du Colombier 	if(p == nil)
2249a747e4fSDavid du Colombier 		return nil;
2259a747e4fSDavid du Colombier 	if(s == nil)
2269a747e4fSDavid du Colombier 		s = "";
2279a747e4fSDavid du Colombier 	n = strlen(s);
2289a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2299a747e4fSDavid du Colombier 		return nil;
2309a747e4fSDavid du Colombier 	PBIT16(p, n);
2319a747e4fSDavid du Colombier 	p += BIT16SZ;
2329a747e4fSDavid du Colombier 	memmove(p, s, n);
2339a747e4fSDavid du Colombier 	p += n;
2349a747e4fSDavid du Colombier 	return p;
2359a747e4fSDavid du Colombier }
2369a747e4fSDavid du Colombier 
2379a747e4fSDavid du Colombier static uchar*
pcarray(uchar * p,uchar * e,uchar * s,uint n)2389a747e4fSDavid du Colombier pcarray(uchar *p, uchar *e, uchar *s, uint n)
2399a747e4fSDavid du Colombier {
2409a747e4fSDavid du Colombier 	if(p == nil)
2419a747e4fSDavid du Colombier 		return nil;
2429a747e4fSDavid du Colombier 	if(s == nil){
2439a747e4fSDavid du Colombier 		if(n > 0)
2449a747e4fSDavid du Colombier 			sysfatal("pcarray");
2459a747e4fSDavid du Colombier 		s = (uchar*)"";
2469a747e4fSDavid du Colombier 	}
2479a747e4fSDavid du Colombier 	if(p+n+BIT16SZ >= e)
2489a747e4fSDavid du Colombier 		return nil;
2499a747e4fSDavid du Colombier 	PBIT16(p, n);
2509a747e4fSDavid du Colombier 	p += BIT16SZ;
2519a747e4fSDavid du Colombier 	memmove(p, s, n);
2529a747e4fSDavid du Colombier 	p += n;
2539a747e4fSDavid du Colombier 	return p;
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier 
2569a747e4fSDavid du Colombier uchar*
convAI2M(AuthInfo * ai,uchar * p,int n)2579a747e4fSDavid du Colombier convAI2M(AuthInfo *ai, uchar *p, int n)
2589a747e4fSDavid du Colombier {
2599a747e4fSDavid du Colombier 	uchar *e = p+n;
2609a747e4fSDavid du Colombier 
2619a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cuid);
2629a747e4fSDavid du Colombier 	p = pstring(p, e, ai->suid);
2639a747e4fSDavid du Colombier 	p = pstring(p, e, ai->cap);
2649a747e4fSDavid du Colombier 	p = pcarray(p, e, ai->secret, ai->nsecret);
2659a747e4fSDavid du Colombier 	return p;
2669a747e4fSDavid du Colombier }
2679a747e4fSDavid du Colombier 
2689a747e4fSDavid du Colombier int
failure(Fsstate * s,char * fmt,...)2699a747e4fSDavid du Colombier failure(Fsstate *s, char *fmt, ...)
2709a747e4fSDavid du Colombier {
2719a747e4fSDavid du Colombier 	char e[ERRMAX];
2729a747e4fSDavid du Colombier 	va_list arg;
2739a747e4fSDavid du Colombier 
2749a747e4fSDavid du Colombier 	if(fmt == nil)
2759a747e4fSDavid du Colombier 		rerrstr(s->err, sizeof(s->err));
2769a747e4fSDavid du Colombier 	else {
2779a747e4fSDavid du Colombier 		va_start(arg, fmt);
27823e56024SDavid du Colombier 		vsnprint(e, sizeof e, fmt, arg);
2799a747e4fSDavid du Colombier 		va_end(arg);
2809a747e4fSDavid du Colombier 		strecpy(s->err, s->err+sizeof(s->err), e);
28187dfdc75SDavid du Colombier 		werrstr(e);
2829a747e4fSDavid du Colombier 	}
2839a747e4fSDavid du Colombier 	flog("%d: failure %s", s->seqnum, s->err);
2849a747e4fSDavid du Colombier 	return RpcFailure;
2859a747e4fSDavid du Colombier }
2869a747e4fSDavid du Colombier 
2879a747e4fSDavid du Colombier static int
hasqueries(Attr * a)2889a747e4fSDavid du Colombier hasqueries(Attr *a)
2899a747e4fSDavid du Colombier {
2909a747e4fSDavid du Colombier 	for(; a; a=a->next)
2919a747e4fSDavid du Colombier 		if(a->type == AttrQuery)
2929a747e4fSDavid du Colombier 			return 1;
2939a747e4fSDavid du Colombier 	return 0;
2949a747e4fSDavid du Colombier }
2959a747e4fSDavid du Colombier 
2969a747e4fSDavid du Colombier char *ignored[] = {
2979a747e4fSDavid du Colombier 	"role",
298260f7b65SDavid du Colombier 	"disabled",
2999a747e4fSDavid du Colombier };
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier static int
ignoreattr(char * s)3029a747e4fSDavid du Colombier ignoreattr(char *s)
3039a747e4fSDavid du Colombier {
3049a747e4fSDavid du Colombier 	int i;
3059a747e4fSDavid du Colombier 
3069a747e4fSDavid du Colombier 	for(i=0; i<nelem(ignored); i++)
3079a747e4fSDavid du Colombier 		if(strcmp(ignored[i], s)==0)
3089a747e4fSDavid du Colombier 			return 1;
3099a747e4fSDavid du Colombier 	return 0;
3109a747e4fSDavid du Colombier }
3119a747e4fSDavid du Colombier 
312260f7b65SDavid du Colombier Keyinfo*
mkkeyinfo(Keyinfo * k,Fsstate * fss,Attr * attr)313260f7b65SDavid du Colombier mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
314260f7b65SDavid du Colombier {
315260f7b65SDavid du Colombier 	memset(k, 0, sizeof *k);
316260f7b65SDavid du Colombier 	k->fss = fss;
317260f7b65SDavid du Colombier 	k->user = fss->sysuser;
3186b8bc682SDavid du Colombier 	if(attr)
319260f7b65SDavid du Colombier 		k->attr = attr;
3206b8bc682SDavid du Colombier 	else
3216b8bc682SDavid du Colombier 		k->attr = fss->attr;
322260f7b65SDavid du Colombier 	return k;
323260f7b65SDavid du Colombier }
324260f7b65SDavid du Colombier 
3259a747e4fSDavid du Colombier int
findkey(Key ** ret,Keyinfo * ki,char * fmt,...)326260f7b65SDavid du Colombier findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
3279a747e4fSDavid du Colombier {
3289a747e4fSDavid du Colombier 	int i, s, nmatch;
329260f7b65SDavid du Colombier 	char buf[1024], *p, *who;
3309a747e4fSDavid du Colombier 	va_list arg;
331260f7b65SDavid du Colombier 	Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
3329a747e4fSDavid du Colombier 	Key *k;
3339a747e4fSDavid du Colombier 
3349a747e4fSDavid du Colombier 	*ret = nil;
3359a747e4fSDavid du Colombier 
336260f7b65SDavid du Colombier 	who = ki->user;
337260f7b65SDavid du Colombier 	attr0 = ki->attr;
3389a747e4fSDavid du Colombier 	if(fmt){
3399a747e4fSDavid du Colombier 		va_start(arg, fmt);
3409a747e4fSDavid du Colombier 		vseprint(buf, buf+sizeof buf, fmt, arg);
3419a747e4fSDavid du Colombier 		va_end(arg);
3429a747e4fSDavid du Colombier 		attr1 = _parseattr(buf);
3439a747e4fSDavid du Colombier 	}else
3449a747e4fSDavid du Colombier 		attr1 = nil;
3459a747e4fSDavid du Colombier 
346fb7f0c93SDavid du Colombier 	if(who && strcmp(who, owner) == 0)
347fb7f0c93SDavid du Colombier 		who = nil;
348fb7f0c93SDavid du Colombier 
349fb7f0c93SDavid du Colombier 	if(who){
350fb7f0c93SDavid du Colombier 		snprint(buf, sizeof buf, "owner=%q", who);
351fb7f0c93SDavid du Colombier 		attr2 = _parseattr(buf);
352fb7f0c93SDavid du Colombier 		attr3 = _parseattr("owner=*");
353fb7f0c93SDavid du Colombier 	}else
354fb7f0c93SDavid du Colombier 		attr2 = attr3 = nil;
355fb7f0c93SDavid du Colombier 
3562ebbfa15SDavid du Colombier 	p = _strfindattr(attr0, "proto");
3579a747e4fSDavid du Colombier 	if(p == nil)
3582ebbfa15SDavid du Colombier 		p = _strfindattr(attr1, "proto");
3599a747e4fSDavid du Colombier 	if(p && findproto(p) == nil){
3609a747e4fSDavid du Colombier 		werrstr("unknown protocol %s", p);
3619a747e4fSDavid du Colombier 		_freeattr(attr1);
3624de34a7eSDavid du Colombier 		_freeattr(attr2);
3634de34a7eSDavid du Colombier 		_freeattr(attr3);
364260f7b65SDavid du Colombier 		return failure(ki->fss, nil);
3659a747e4fSDavid du Colombier 	}
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier 	nmatch = 0;
3689a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
3699a747e4fSDavid du Colombier 		k = ring->key[i];
370260f7b65SDavid du Colombier 		if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
371260f7b65SDavid du Colombier 			continue;
3729a747e4fSDavid du Colombier 		if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
373fb7f0c93SDavid du Colombier 			/* check ownership */
374fb7f0c93SDavid du Colombier 			if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
375fb7f0c93SDavid du Colombier 				continue;
376260f7b65SDavid du Colombier 			if(nmatch++ < ki->skip)
3779a747e4fSDavid du Colombier 				continue;
378260f7b65SDavid du Colombier 			if(!ki->noconf){
379260f7b65SDavid du Colombier 				switch(canusekey(ki->fss, k)){
3809a747e4fSDavid du Colombier 				case -1:
3819a747e4fSDavid du Colombier 					_freeattr(attr1);
3829a747e4fSDavid du Colombier 					return RpcConfirm;
3839a747e4fSDavid du Colombier 				case 0:
3849a747e4fSDavid du Colombier 					continue;
3859a747e4fSDavid du Colombier 				case 1:
3869a747e4fSDavid du Colombier 					break;
3879a747e4fSDavid du Colombier 				}
3889a747e4fSDavid du Colombier 			}
3899a747e4fSDavid du Colombier 			_freeattr(attr1);
3904de34a7eSDavid du Colombier 			_freeattr(attr2);
3914de34a7eSDavid du Colombier 			_freeattr(attr3);
3929a747e4fSDavid du Colombier 			k->ref++;
3939a747e4fSDavid du Colombier 			*ret = k;
3949a747e4fSDavid du Colombier 			return RpcOk;
3959a747e4fSDavid du Colombier 		}
3969a747e4fSDavid du Colombier 	}
397260f7b65SDavid du Colombier 	flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
3989a747e4fSDavid du Colombier 	werrstr("no key matches %A %A", attr0, attr1);
3994de34a7eSDavid du Colombier 	_freeattr(attr2);
4004de34a7eSDavid du Colombier 	_freeattr(attr3);
4019a747e4fSDavid du Colombier 	s = RpcFailure;
402fb7f0c93SDavid du Colombier 	if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
4039a747e4fSDavid du Colombier 		if(nmatch == 0){
4049a747e4fSDavid du Colombier 			attr0 = _copyattr(attr0);
4059a747e4fSDavid du Colombier 			for(l=&attr0; *l; l=&(*l)->next)
4069a747e4fSDavid du Colombier 				;
4079a747e4fSDavid du Colombier 			*l = attr1;
4089a747e4fSDavid du Colombier 			for(l=&attr0; *l; ){
4092ebbfa15SDavid du Colombier 				if(ignoreattr((*l)->name)){
4109a747e4fSDavid du Colombier 					a = *l;
4119a747e4fSDavid du Colombier 					*l = (*l)->next;
4129a747e4fSDavid du Colombier 					a->next = nil;
4139a747e4fSDavid du Colombier 					_freeattr(a);
4149a747e4fSDavid du Colombier 				}else
4159a747e4fSDavid du Colombier 					l = &(*l)->next;
4169a747e4fSDavid du Colombier 			}
4179a747e4fSDavid du Colombier 			attr0 = sortattr(attr0);
418260f7b65SDavid du Colombier 			snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
4199a747e4fSDavid du Colombier 			_freeattr(attr0);
4209a747e4fSDavid du Colombier 			attr1 = nil;	/* attr1 was linked to attr0 */
4219a747e4fSDavid du Colombier 		}else
422260f7b65SDavid du Colombier 			ki->fss->keyinfo[0] = '\0';
4239a747e4fSDavid du Colombier 		s = RpcNeedkey;
4249a747e4fSDavid du Colombier 	}
4259a747e4fSDavid du Colombier 	_freeattr(attr1);
4269a747e4fSDavid du Colombier 	if(s == RpcFailure)
427260f7b65SDavid du Colombier 		return failure(ki->fss, nil);	/* loads error string */
4289a747e4fSDavid du Colombier 	return s;
4299a747e4fSDavid du Colombier }
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier int
findp9authkey(Key ** k,Fsstate * fss)4329a747e4fSDavid du Colombier findp9authkey(Key **k, Fsstate *fss)
4339a747e4fSDavid du Colombier {
4349a747e4fSDavid du Colombier 	char *dom;
435260f7b65SDavid du Colombier 	Keyinfo ki;
4369a747e4fSDavid du Colombier 
4379a747e4fSDavid du Colombier 	/*
4389a747e4fSDavid du Colombier 	 * We don't use fss->attr here because we don't
4399a747e4fSDavid du Colombier 	 * care about what the user name is set to, for instance.
4409a747e4fSDavid du Colombier 	 */
441260f7b65SDavid du Colombier 	mkkeyinfo(&ki, fss, nil);
442260f7b65SDavid du Colombier 	ki.attr = nil;
443260f7b65SDavid du Colombier 	ki.user = nil;
4442ebbfa15SDavid du Colombier 	if(dom = _strfindattr(fss->attr, "dom"))
445260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
4469a747e4fSDavid du Colombier 	else
447260f7b65SDavid du Colombier 		return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
4489a747e4fSDavid du Colombier }
4499a747e4fSDavid du Colombier 
4509a747e4fSDavid du Colombier Proto*
findproto(char * name)4519a747e4fSDavid du Colombier findproto(char *name)
4529a747e4fSDavid du Colombier {
4539a747e4fSDavid du Colombier 	int i;
4549a747e4fSDavid du Colombier 
4559a747e4fSDavid du Colombier 	for(i=0; prototab[i]; i++)
4569a747e4fSDavid du Colombier 		if(strcmp(name, prototab[i]->name) == 0)
4579a747e4fSDavid du Colombier 			return prototab[i];
4589a747e4fSDavid du Colombier 	return nil;
4599a747e4fSDavid du Colombier }
4609a747e4fSDavid du Colombier 
4619a747e4fSDavid du Colombier char*
getnvramkey(int flag,char ** secstorepw)4629a747e4fSDavid du Colombier getnvramkey(int flag, char **secstorepw)
4639a747e4fSDavid du Colombier {
4649a747e4fSDavid du Colombier 	char *s;
4659a747e4fSDavid du Colombier 	Nvrsafe safe;
4669a747e4fSDavid du Colombier 	char spw[CONFIGLEN+1];
4679a747e4fSDavid du Colombier 	int i;
4689a747e4fSDavid du Colombier 
4699a747e4fSDavid du Colombier 	memset(&safe, 0, sizeof safe);
4709a747e4fSDavid du Colombier 	/*
4719a747e4fSDavid du Colombier 	 * readnvram can return -1 meaning nvram wasn't written,
4729a747e4fSDavid du Colombier 	 * but safe still holds good data.
4739a747e4fSDavid du Colombier 	 */
4745fe11e25SDavid du Colombier 	if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
4759a747e4fSDavid du Colombier 		return nil;
4769a747e4fSDavid du Colombier 
4779a747e4fSDavid du Colombier 	/*
4789a747e4fSDavid du Colombier 	 *  we're using the config area to hold the secstore
4799a747e4fSDavid du Colombier 	 *  password.  if there's anything there, return it.
4809a747e4fSDavid du Colombier 	 */
4819a747e4fSDavid du Colombier 	memmove(spw, safe.config, CONFIGLEN);
4829a747e4fSDavid du Colombier 	spw[CONFIGLEN] = 0;
4839a747e4fSDavid du Colombier 	if(spw[0] != 0)
4849a747e4fSDavid du Colombier 		*secstorepw = estrdup(spw);
4859a747e4fSDavid du Colombier 
4869a747e4fSDavid du Colombier 	/*
4879a747e4fSDavid du Colombier 	 *  only use nvram key if it is non-zero
4889a747e4fSDavid du Colombier 	 */
4899a747e4fSDavid du Colombier 	for(i = 0; i < DESKEYLEN; i++)
4909a747e4fSDavid du Colombier 		if(safe.machkey[i] != 0)
4919a747e4fSDavid du Colombier 			break;
4929a747e4fSDavid du Colombier 	if(i == DESKEYLEN)
4939a747e4fSDavid du Colombier 		return nil;
4949a747e4fSDavid du Colombier 
4959a747e4fSDavid du Colombier 	s = emalloc(512);
4969a747e4fSDavid du Colombier 	fmtinstall('H', encodefmt);
497*f54edc78SDavid du Colombier 	snprint(s, 512, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
4989a747e4fSDavid du Colombier 		safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
4999a747e4fSDavid du Colombier 	writehostowner(safe.authid);
5009a747e4fSDavid du Colombier 
5019a747e4fSDavid du Colombier 	return s;
5029a747e4fSDavid du Colombier }
5039a747e4fSDavid du Colombier 
5049a747e4fSDavid du Colombier int
isclient(char * role)5059a747e4fSDavid du Colombier isclient(char *role)
5069a747e4fSDavid du Colombier {
5079a747e4fSDavid du Colombier 	if(role == nil){
5089a747e4fSDavid du Colombier 		werrstr("role not specified");
5099a747e4fSDavid du Colombier 		return -1;
5109a747e4fSDavid du Colombier 	}
5119a747e4fSDavid du Colombier 	if(strcmp(role, "server") == 0)
5129a747e4fSDavid du Colombier 		return 0;
5139a747e4fSDavid du Colombier 	if(strcmp(role, "client") == 0)
5149a747e4fSDavid du Colombier 		return 1;
5159a747e4fSDavid du Colombier 	werrstr("unknown role %q", role);
5169a747e4fSDavid du Colombier 	return -1;
5179a747e4fSDavid du Colombier }
5189a747e4fSDavid du Colombier 
5199a747e4fSDavid du Colombier static int
hasname(Attr * a0,Attr * a1,char * name)5209a747e4fSDavid du Colombier hasname(Attr *a0, Attr *a1, char *name)
5219a747e4fSDavid du Colombier {
5229a747e4fSDavid du Colombier 	return _findattr(a0, name) || _findattr(a1, name);
5239a747e4fSDavid du Colombier }
5249a747e4fSDavid du Colombier 
5259a747e4fSDavid du Colombier static int
hasnameval(Attr * a0,Attr * a1,char * name,char * val)5269a747e4fSDavid du Colombier hasnameval(Attr *a0, Attr *a1, char *name, char *val)
5279a747e4fSDavid du Colombier {
5289a747e4fSDavid du Colombier 	Attr *a;
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier 	for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
5312ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5329a747e4fSDavid du Colombier 			return 1;
5339a747e4fSDavid du Colombier 	for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
5342ebbfa15SDavid du Colombier 		if(strcmp(a->val, val) == 0)
5359a747e4fSDavid du Colombier 			return 1;
5369a747e4fSDavid du Colombier 	return 0;
5379a747e4fSDavid du Colombier }
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier int
matchattr(Attr * pat,Attr * a0,Attr * a1)5409a747e4fSDavid du Colombier matchattr(Attr *pat, Attr *a0, Attr *a1)
5419a747e4fSDavid du Colombier {
5429a747e4fSDavid du Colombier 	int type;
5439a747e4fSDavid du Colombier 
5449a747e4fSDavid du Colombier 	for(; pat; pat=pat->next){
5459a747e4fSDavid du Colombier 		type = pat->type;
5462ebbfa15SDavid du Colombier 		if(ignoreattr(pat->name))
5479a747e4fSDavid du Colombier 			type = AttrDefault;
5489a747e4fSDavid du Colombier 		switch(type){
5499a747e4fSDavid du Colombier 		case AttrQuery:		/* name=something be present */
5502ebbfa15SDavid du Colombier 			if(!hasname(a0, a1, pat->name))
5519a747e4fSDavid du Colombier 				return 0;
5529a747e4fSDavid du Colombier 			break;
5539a747e4fSDavid du Colombier 		case AttrNameval:	/* name=val must be present */
5542ebbfa15SDavid du Colombier 			if(!hasnameval(a0, a1, pat->name, pat->val))
5559a747e4fSDavid du Colombier 				return 0;
5569a747e4fSDavid du Colombier 			break;
5579a747e4fSDavid du Colombier 		case AttrDefault:	/* name=val must be present if name=anything is present */
5582ebbfa15SDavid du Colombier 			if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
5599a747e4fSDavid du Colombier 				return 0;
5609a747e4fSDavid du Colombier 			break;
5619a747e4fSDavid du Colombier 		}
5629a747e4fSDavid du Colombier 	}
5639a747e4fSDavid du Colombier 	return 1;
5649a747e4fSDavid du Colombier }
5659a747e4fSDavid du Colombier 
5669a747e4fSDavid du Colombier void
memrandom(void * p,int n)5679a747e4fSDavid du Colombier memrandom(void *p, int n)
5689a747e4fSDavid du Colombier {
5699a747e4fSDavid du Colombier 	uchar *cp;
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier 	for(cp = (uchar*)p; n > 0; n--)
5729a747e4fSDavid du Colombier 		*cp++ = fastrand();
5739a747e4fSDavid du Colombier }
5749a747e4fSDavid du Colombier 
5759a747e4fSDavid du Colombier /*
5763ff48bf5SDavid du Colombier  *  keep caphash fd open since opens of it could be disabled
5773ff48bf5SDavid du Colombier  */
5783ff48bf5SDavid du Colombier static int caphashfd;
5793ff48bf5SDavid du Colombier 
5803ff48bf5SDavid du Colombier void
initcap(void)5813ff48bf5SDavid du Colombier initcap(void)
5823ff48bf5SDavid du Colombier {
5833ff48bf5SDavid du Colombier 	caphashfd = open("#¤/caphash", OWRITE);
584d9306527SDavid du Colombier //	if(caphashfd < 0)
585d9306527SDavid du Colombier //		fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
5863ff48bf5SDavid du Colombier }
5873ff48bf5SDavid du Colombier 
5883ff48bf5SDavid du Colombier /*
5899a747e4fSDavid du Colombier  *  create a change uid capability
5909a747e4fSDavid du Colombier  */
5919a747e4fSDavid du Colombier char*
mkcap(char * from,char * to)5923ff48bf5SDavid du Colombier mkcap(char *from, char *to)
5939a747e4fSDavid du Colombier {
5949a747e4fSDavid du Colombier 	uchar rand[20];
5959a747e4fSDavid du Colombier 	char *cap;
5969a747e4fSDavid du Colombier 	char *key;
597*f54edc78SDavid du Colombier 	int nfrom, nto, ncap;
5989a747e4fSDavid du Colombier 	uchar hash[SHA1dlen];
5999a747e4fSDavid du Colombier 
6003ff48bf5SDavid du Colombier 	if(caphashfd < 0)
6019a747e4fSDavid du Colombier 		return nil;
6029a747e4fSDavid du Colombier 
6039a747e4fSDavid du Colombier 	/* create the capability */
6043ff48bf5SDavid du Colombier 	nto = strlen(to);
6053ff48bf5SDavid du Colombier 	nfrom = strlen(from);
606*f54edc78SDavid du Colombier 	ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1;
607*f54edc78SDavid du Colombier 	cap = emalloc(ncap);
608*f54edc78SDavid du Colombier 	snprint(cap, ncap, "%s@%s", from, to);
6099a747e4fSDavid du Colombier 	memrandom(rand, sizeof(rand));
6103ff48bf5SDavid du Colombier 	key = cap+nfrom+1+nto+1;
6119a747e4fSDavid du Colombier 	enc64(key, sizeof(rand)*3, rand, sizeof(rand));
6129a747e4fSDavid du Colombier 
6139a747e4fSDavid du Colombier 	/* hash the capability */
6143ff48bf5SDavid du Colombier 	hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
6159a747e4fSDavid du Colombier 
6169a747e4fSDavid du Colombier 	/* give the kernel the hash */
6173ff48bf5SDavid du Colombier 	key[-1] = '@';
6183ff48bf5SDavid du Colombier 	if(write(caphashfd, hash, SHA1dlen) < 0){
6199a747e4fSDavid du Colombier 		free(cap);
6209a747e4fSDavid du Colombier 		return nil;
6219a747e4fSDavid du Colombier 	}
6229a747e4fSDavid du Colombier 
6239a747e4fSDavid du Colombier 	return cap;
6249a747e4fSDavid du Colombier }
6259a747e4fSDavid du Colombier 
6269a747e4fSDavid du Colombier int
phaseerror(Fsstate * s,char * op)6279a747e4fSDavid du Colombier phaseerror(Fsstate *s, char *op)
6289a747e4fSDavid du Colombier {
6299a747e4fSDavid du Colombier 	char tmp[32];
6309a747e4fSDavid du Colombier 
6319a747e4fSDavid du Colombier 	werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));
6329a747e4fSDavid du Colombier 	return RpcPhase;
6339a747e4fSDavid du Colombier }
6349a747e4fSDavid du Colombier 
6359a747e4fSDavid du Colombier char*
phasename(Fsstate * fss,int phase,char * tmp)6369a747e4fSDavid du Colombier phasename(Fsstate *fss, int phase, char *tmp)
6379a747e4fSDavid du Colombier {
6389a747e4fSDavid du Colombier 	char *name;
6399a747e4fSDavid du Colombier 
6409a747e4fSDavid du Colombier 	if(fss->phase == Broken)
6419a747e4fSDavid du Colombier 		name = "Broken";
6429a747e4fSDavid du Colombier 	else if(phase == Established)
6439a747e4fSDavid du Colombier 		name = "Established";
6449a747e4fSDavid du Colombier 	else if(phase == Notstarted)
6459a747e4fSDavid du Colombier 		name = "Notstarted";
6469a747e4fSDavid du Colombier 	else if(phase < 0 || phase >= fss->maxphase
6479a747e4fSDavid du Colombier 	|| (name = fss->phasename[phase]) == nil){
6489a747e4fSDavid du Colombier 		sprint(tmp, "%d", phase);
6499a747e4fSDavid du Colombier 		name = tmp;
6509a747e4fSDavid du Colombier 	}
6519a747e4fSDavid du Colombier 	return name;
6529a747e4fSDavid du Colombier }
6539a747e4fSDavid du Colombier 
6549a747e4fSDavid du Colombier static int
outin(char * prompt,char * def,int len)6559a747e4fSDavid du Colombier outin(char *prompt, char *def, int len)
6569a747e4fSDavid du Colombier {
6572ebbfa15SDavid du Colombier 	char *s;
6589a747e4fSDavid du Colombier 
6599a747e4fSDavid du Colombier 	s = readcons(prompt, def, 0);
6609a747e4fSDavid du Colombier 	if(s == nil)
6619a747e4fSDavid du Colombier 		return -1;
6622ebbfa15SDavid du Colombier 	if(s == nil)
6632ebbfa15SDavid du Colombier 		sysfatal("s==nil???");
6642ebbfa15SDavid du Colombier 	strncpy(def, s, len);
6659a747e4fSDavid du Colombier 	def[len-1] = 0;
6662ebbfa15SDavid du Colombier 	free(s);
6679a747e4fSDavid du Colombier 	return strlen(def);
6689a747e4fSDavid du Colombier }
6699a747e4fSDavid du Colombier 
6709a747e4fSDavid du Colombier /*
6719a747e4fSDavid du Colombier  *  get host owner and set it
6729a747e4fSDavid du Colombier  */
6739a747e4fSDavid du Colombier void
promptforhostowner(void)6749a747e4fSDavid du Colombier promptforhostowner(void)
6759a747e4fSDavid du Colombier {
6769a747e4fSDavid du Colombier 	char owner[64], *p;
6779a747e4fSDavid du Colombier 
6789a747e4fSDavid du Colombier 	/* hack for bitsy; can't prompt during boot */
6799a747e4fSDavid du Colombier 	if(p = getenv("user")){
6809a747e4fSDavid du Colombier 		writehostowner(p);
681d9306527SDavid du Colombier 		free(p);
6829a747e4fSDavid du Colombier 		return;
6839a747e4fSDavid du Colombier 	}
684d9306527SDavid du Colombier 	free(p);
6859a747e4fSDavid du Colombier 
6869a747e4fSDavid du Colombier 	strcpy(owner, "none");
6879a747e4fSDavid du Colombier 	do{
6889a747e4fSDavid du Colombier 		outin("user", owner, sizeof(owner));
6899a747e4fSDavid du Colombier 	} while(*owner == 0);
6909a747e4fSDavid du Colombier 	writehostowner(owner);
6919a747e4fSDavid du Colombier }
6929a747e4fSDavid du Colombier 
6932ebbfa15SDavid du Colombier char*
estrappend(char * s,char * fmt,...)6942ebbfa15SDavid du Colombier estrappend(char *s, char *fmt, ...)
6952ebbfa15SDavid du Colombier {
6962ebbfa15SDavid du Colombier 	char *t;
6972ebbfa15SDavid du Colombier 	va_list arg;
6982ebbfa15SDavid du Colombier 
6992ebbfa15SDavid du Colombier 	va_start(arg, fmt);
7002ebbfa15SDavid du Colombier 	t = vsmprint(fmt, arg);
7012ebbfa15SDavid du Colombier 	if(t == nil)
7022ebbfa15SDavid du Colombier 		sysfatal("out of memory");
7032ebbfa15SDavid du Colombier 	va_end(arg);
7042ebbfa15SDavid du Colombier 	s = erealloc(s, strlen(s)+strlen(t)+1);
7052ebbfa15SDavid du Colombier 	strcat(s, t);
7062ebbfa15SDavid du Colombier 	free(t);
7072ebbfa15SDavid du Colombier 	return s;
7082ebbfa15SDavid du Colombier }
7092ebbfa15SDavid du Colombier 
7102ebbfa15SDavid du Colombier 
7119a747e4fSDavid du Colombier /*
7129a747e4fSDavid du Colombier  *  prompt for a string with a possible default response
7139a747e4fSDavid du Colombier  */
7142ebbfa15SDavid du Colombier char*
readcons(char * prompt,char * def,int raw)7159a747e4fSDavid du Colombier readcons(char *prompt, char *def, int raw)
7169a747e4fSDavid du Colombier {
7179a747e4fSDavid du Colombier 	int fdin, fdout, ctl, n;
7189a747e4fSDavid du Colombier 	char line[10];
7192ebbfa15SDavid du Colombier 	char *s;
7209a747e4fSDavid du Colombier 
7219a747e4fSDavid du Colombier 	fdin = open("/dev/cons", OREAD);
7229a747e4fSDavid du Colombier 	if(fdin < 0)
7239a747e4fSDavid du Colombier 		fdin = 0;
7249a747e4fSDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
7259a747e4fSDavid du Colombier 	if(fdout < 0)
7269a747e4fSDavid du Colombier 		fdout = 1;
7279a747e4fSDavid du Colombier 	if(def != nil)
7289a747e4fSDavid du Colombier 		fprint(fdout, "%s[%s]: ", prompt, def);
7299a747e4fSDavid du Colombier 	else
7309a747e4fSDavid du Colombier 		fprint(fdout, "%s: ", prompt);
7319a747e4fSDavid du Colombier 	if(raw){
7329a747e4fSDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
7339a747e4fSDavid du Colombier 		if(ctl >= 0)
7349a747e4fSDavid du Colombier 			write(ctl, "rawon", 5);
7359a747e4fSDavid du Colombier 	} else
7369a747e4fSDavid du Colombier 		ctl = -1;
7372ebbfa15SDavid du Colombier 	s = estrdup("");
7389a747e4fSDavid du Colombier 	for(;;){
7399a747e4fSDavid du Colombier 		n = read(fdin, line, 1);
7409a747e4fSDavid du Colombier 		if(n == 0){
7419a747e4fSDavid du Colombier 		Error:
7429a747e4fSDavid du Colombier 			close(fdin);
7439a747e4fSDavid du Colombier 			close(fdout);
7449a747e4fSDavid du Colombier 			if(ctl >= 0)
7459a747e4fSDavid du Colombier 				close(ctl);
7462ebbfa15SDavid du Colombier 			free(s);
7479a747e4fSDavid du Colombier 			return nil;
7489a747e4fSDavid du Colombier 		}
7499a747e4fSDavid du Colombier 		if(n < 0)
7509a747e4fSDavid du Colombier 			goto Error;
7519a747e4fSDavid du Colombier 		if(line[0] == 0x7f)
7529a747e4fSDavid du Colombier 			goto Error;
7539a747e4fSDavid du Colombier 		if(n == 0 || line[0] == '\n' || line[0] == '\r'){
7549a747e4fSDavid du Colombier 			if(raw){
7559a747e4fSDavid du Colombier 				write(ctl, "rawoff", 6);
7569a747e4fSDavid du Colombier 				write(fdout, "\n", 1);
7579a747e4fSDavid du Colombier 			}
7589a747e4fSDavid du Colombier 			close(ctl);
7599a747e4fSDavid du Colombier 			close(fdin);
7609a747e4fSDavid du Colombier 			close(fdout);
7612ebbfa15SDavid du Colombier 			if(*s == 0 && def != nil)
7622ebbfa15SDavid du Colombier 				s = estrappend(s, "%s", def);
7639a747e4fSDavid du Colombier 			return s;
7649a747e4fSDavid du Colombier 		}
7659a747e4fSDavid du Colombier 		if(line[0] == '\b'){
7662ebbfa15SDavid du Colombier 			if(strlen(s) > 0)
7672ebbfa15SDavid du Colombier 				s[strlen(s)-1] = 0;
7689a747e4fSDavid du Colombier 		} else if(line[0] == 0x15) {	/* ^U: line kill */
7692ebbfa15SDavid du Colombier 			if(def != nil)
7702ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s[%s]: ", prompt, def);
7712ebbfa15SDavid du Colombier 			else
7722ebbfa15SDavid du Colombier 				fprint(fdout, "\n%s: ", prompt);
7732ebbfa15SDavid du Colombier 
7742ebbfa15SDavid du Colombier 			s[0] = 0;
7759a747e4fSDavid du Colombier 		} else {
7762ebbfa15SDavid du Colombier 			s = estrappend(s, "%c", line[0]);
7779a747e4fSDavid du Colombier 		}
7789a747e4fSDavid du Colombier 	}
7799a747e4fSDavid du Colombier }
7809a747e4fSDavid du Colombier 
7819a747e4fSDavid du Colombier /*
7829a747e4fSDavid du Colombier  * Insert a key into the keyring.
7839a747e4fSDavid du Colombier  * If the public attributes are identical to some other key, replace that one.
7849a747e4fSDavid du Colombier  */
7859a747e4fSDavid du Colombier int
replacekey(Key * kn,int before)78670b8e010SDavid du Colombier replacekey(Key *kn, int before)
7879a747e4fSDavid du Colombier {
7889a747e4fSDavid du Colombier 	int i;
7899a747e4fSDavid du Colombier 	Key *k;
7909a747e4fSDavid du Colombier 
7919a747e4fSDavid du Colombier 	for(i=0; i<ring->nkey; i++){
7929a747e4fSDavid du Colombier 		k = ring->key[i];
7939a747e4fSDavid du Colombier 		if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
7949a747e4fSDavid du Colombier 			closekey(k);
7959a747e4fSDavid du Colombier 			kn->ref++;
7969a747e4fSDavid du Colombier 			ring->key[i] = kn;
7979a747e4fSDavid du Colombier 			return 0;
7989a747e4fSDavid du Colombier 		}
7999a747e4fSDavid du Colombier 	}
8009a747e4fSDavid du Colombier 	if(ring->nkey%16 == 0)
8019a747e4fSDavid du Colombier 		ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
8029a747e4fSDavid du Colombier 	kn->ref++;
80370b8e010SDavid du Colombier 	if(before){
80470b8e010SDavid du Colombier 		memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
80570b8e010SDavid du Colombier 		ring->key[0] = kn;
80670b8e010SDavid du Colombier 		ring->nkey++;
80770b8e010SDavid du Colombier 	}else
8089a747e4fSDavid du Colombier 		ring->key[ring->nkey++] = kn;
8099a747e4fSDavid du Colombier 	return 0;
8109a747e4fSDavid du Colombier }
8119a747e4fSDavid du Colombier 
8129a747e4fSDavid du Colombier char*
safecpy(char * to,char * from,int n)8139a747e4fSDavid du Colombier safecpy(char *to, char *from, int n)
8149a747e4fSDavid du Colombier {
8159a747e4fSDavid du Colombier 	memset(to, 0, n);
8169a747e4fSDavid du Colombier 	if(n == 1)
8179a747e4fSDavid du Colombier 		return to;
8189a747e4fSDavid du Colombier 	if(from==nil)
81914cc0f53SDavid du Colombier 		sysfatal("safecpy called with from==nil, pc=%#p",
8209a747e4fSDavid du Colombier 			getcallerpc(&to));
8219a747e4fSDavid du Colombier 	strncpy(to, from, n-1);
8229a747e4fSDavid du Colombier 	return to;
8239a747e4fSDavid du Colombier }
8249a747e4fSDavid du Colombier 
8259a747e4fSDavid du Colombier Attr*
setattr(Attr * a,char * fmt,...)8269a747e4fSDavid du Colombier setattr(Attr *a, char *fmt, ...)
8279a747e4fSDavid du Colombier {
8289a747e4fSDavid du Colombier 	char buf[1024];
8299a747e4fSDavid du Colombier 	va_list arg;
8309a747e4fSDavid du Colombier 	Attr *b;
8319a747e4fSDavid du Colombier 
8329a747e4fSDavid du Colombier 	va_start(arg, fmt);
8339a747e4fSDavid du Colombier 	vseprint(buf, buf+sizeof buf, fmt, arg);
8349a747e4fSDavid du Colombier 	va_end(arg);
8359a747e4fSDavid du Colombier 	b = _parseattr(buf);
8369a747e4fSDavid du Colombier 	a = setattrs(a, b);
8379a747e4fSDavid du Colombier 	setmalloctag(a, getcallerpc(&a));
8389a747e4fSDavid du Colombier 	_freeattr(b);
8399a747e4fSDavid du Colombier 	return a;
8409a747e4fSDavid du Colombier }
8419a747e4fSDavid du Colombier 
8429a747e4fSDavid du Colombier /*
8439a747e4fSDavid du Colombier  *  add attributes in list b to list a.  If any attributes are in
8449a747e4fSDavid du Colombier  *  both lists, replace those in a by those in b.
8459a747e4fSDavid du Colombier  */
8469a747e4fSDavid du Colombier Attr*
setattrs(Attr * a,Attr * b)8479a747e4fSDavid du Colombier setattrs(Attr *a, Attr *b)
8489a747e4fSDavid du Colombier {
8499a747e4fSDavid du Colombier 	int found;
8509a747e4fSDavid du Colombier 	Attr **l, *freea;
8519a747e4fSDavid du Colombier 
8529a747e4fSDavid du Colombier 	for(; b; b=b->next){
8539a747e4fSDavid du Colombier 		found = 0;
8549a747e4fSDavid du Colombier 		for(l=&a; *l; ){
8552ebbfa15SDavid du Colombier 			if(strcmp(b->name, (*l)->name) == 0){
8569a747e4fSDavid du Colombier 				switch(b->type){
8579a747e4fSDavid du Colombier 				case AttrNameval:
8589a747e4fSDavid du Colombier 					if(!found){
8599a747e4fSDavid du Colombier 						found = 1;
8602ebbfa15SDavid du Colombier 						free((*l)->val);
8612ebbfa15SDavid du Colombier 						(*l)->val = estrdup(b->val);
8629a747e4fSDavid du Colombier 						(*l)->type = AttrNameval;
8639a747e4fSDavid du Colombier 						l = &(*l)->next;
8649a747e4fSDavid du Colombier 					}else{
8659a747e4fSDavid du Colombier 						freea = *l;
8669a747e4fSDavid du Colombier 						*l = (*l)->next;
8679a747e4fSDavid du Colombier 						freea->next = nil;
8689a747e4fSDavid du Colombier 						_freeattr(freea);
8699a747e4fSDavid du Colombier 					}
8709a747e4fSDavid du Colombier 					break;
8719a747e4fSDavid du Colombier 				case AttrQuery:
872f0ed0fb6SDavid du Colombier 					goto continue2;
8739a747e4fSDavid du Colombier 				}
8749a747e4fSDavid du Colombier 			}else
8759a747e4fSDavid du Colombier 				l = &(*l)->next;
8769a747e4fSDavid du Colombier 		}
8779a747e4fSDavid du Colombier 		if(found == 0){
8782ebbfa15SDavid du Colombier 			*l = _mkattr(b->type, b->name, b->val, nil);
8799a747e4fSDavid du Colombier 			setmalloctag(*l, getcallerpc(&a));
8809a747e4fSDavid du Colombier 		}
881f0ed0fb6SDavid du Colombier continue2:;
8829a747e4fSDavid du Colombier 	}
8839a747e4fSDavid du Colombier 	return a;
8849a747e4fSDavid du Colombier }
8859a747e4fSDavid du Colombier 
8869a747e4fSDavid du Colombier void
setmalloctaghere(void * v)8879a747e4fSDavid du Colombier setmalloctaghere(void *v)
8889a747e4fSDavid du Colombier {
8899a747e4fSDavid du Colombier 	setmalloctag(v, getcallerpc(&v));
8909a747e4fSDavid du Colombier }
8919a747e4fSDavid du Colombier 
8929a747e4fSDavid du Colombier Attr*
sortattr(Attr * a)8939a747e4fSDavid du Colombier sortattr(Attr *a)
8949a747e4fSDavid du Colombier {
8959a747e4fSDavid du Colombier 	int i;
8969a747e4fSDavid du Colombier 	Attr *anext, *a0, *a1, **l;
8979a747e4fSDavid du Colombier 
8989a747e4fSDavid du Colombier 	if(a == nil || a->next == nil)
8999a747e4fSDavid du Colombier 		return a;
9009a747e4fSDavid du Colombier 
9019a747e4fSDavid du Colombier 	/* cut list in halves */
9029a747e4fSDavid du Colombier 	a0 = nil;
9039a747e4fSDavid du Colombier 	a1 = nil;
9049a747e4fSDavid du Colombier 	i = 0;
9059a747e4fSDavid du Colombier 	for(; a; a=anext){
9069a747e4fSDavid du Colombier 		anext = a->next;
9079a747e4fSDavid du Colombier 		if(i++%2){
9089a747e4fSDavid du Colombier 			a->next = a0;
9099a747e4fSDavid du Colombier 			a0 = a;
9109a747e4fSDavid du Colombier 		}else{
9119a747e4fSDavid du Colombier 			a->next = a1;
9129a747e4fSDavid du Colombier 			a1 = a;
9139a747e4fSDavid du Colombier 		}
9149a747e4fSDavid du Colombier 	}
9159a747e4fSDavid du Colombier 
9169a747e4fSDavid du Colombier 	/* sort */
9179a747e4fSDavid du Colombier 	a0 = sortattr(a0);
9189a747e4fSDavid du Colombier 	a1 = sortattr(a1);
9199a747e4fSDavid du Colombier 
9209a747e4fSDavid du Colombier 	/* merge */
9219a747e4fSDavid du Colombier 	l = &a;
9229a747e4fSDavid du Colombier 	while(a0 || a1){
9239a747e4fSDavid du Colombier 		if(a1==nil){
9249a747e4fSDavid du Colombier 			anext = a0;
9259a747e4fSDavid du Colombier 			a0 = a0->next;
9269a747e4fSDavid du Colombier 		}else if(a0==nil){
9279a747e4fSDavid du Colombier 			anext = a1;
9289a747e4fSDavid du Colombier 			a1 = a1->next;
9292ebbfa15SDavid du Colombier 		}else if(strcmp(a0->name, a1->name) < 0){
9309a747e4fSDavid du Colombier 			anext = a0;
9319a747e4fSDavid du Colombier 			a0 = a0->next;
9329a747e4fSDavid du Colombier 		}else{
9339a747e4fSDavid du Colombier 			anext = a1;
9349a747e4fSDavid du Colombier 			a1 = a1->next;
9359a747e4fSDavid du Colombier 		}
9369a747e4fSDavid du Colombier 		*l = anext;
9379a747e4fSDavid du Colombier 		l = &(*l)->next;
9389a747e4fSDavid du Colombier 	}
9399a747e4fSDavid du Colombier 	*l = nil;
9409a747e4fSDavid du Colombier 	return a;
9419a747e4fSDavid du Colombier }
9429a747e4fSDavid du Colombier 
9439a747e4fSDavid du Colombier int
toosmall(Fsstate * fss,uint n)9449a747e4fSDavid du Colombier toosmall(Fsstate *fss, uint n)
9459a747e4fSDavid du Colombier {
9469a747e4fSDavid du Colombier 	fss->rpc.nwant = n;
9479a747e4fSDavid du Colombier 	return RpcToosmall;
9489a747e4fSDavid du Colombier }
9499a747e4fSDavid du Colombier 
9509a747e4fSDavid du Colombier void
writehostowner(char * owner)9519a747e4fSDavid du Colombier writehostowner(char *owner)
9529a747e4fSDavid du Colombier {
9539a747e4fSDavid du Colombier 	int fd;
9549a747e4fSDavid du Colombier 	char *s;
9559a747e4fSDavid du Colombier 
9569a747e4fSDavid du Colombier 	if((s = strchr(owner,'@')) != nil){
9579a747e4fSDavid du Colombier 		*s++ = 0;
9589a747e4fSDavid du Colombier 		strncpy(secstore, s, (sizeof secstore)-1);
9599a747e4fSDavid du Colombier 	}
9609a747e4fSDavid du Colombier 	fd = open("#c/hostowner", OWRITE);
9619a747e4fSDavid du Colombier 	if(fd >= 0){
9629a747e4fSDavid du Colombier 		if(fprint(fd, "%s", owner) < 0)
963d854de59SDavid du Colombier 			fprint(2, "factotum: setting #c/hostowner to %q: %r\n",
964d854de59SDavid du Colombier 				owner);
9659a747e4fSDavid du Colombier 		close(fd);
9669a747e4fSDavid du Colombier 	}
9679a747e4fSDavid du Colombier }
9689a747e4fSDavid du Colombier 
9695d459b5aSDavid du Colombier int
attrnamefmt(Fmt * fmt)9705d459b5aSDavid du Colombier attrnamefmt(Fmt *fmt)
9715d459b5aSDavid du Colombier {
9725d459b5aSDavid du Colombier 	char *b, buf[1024], *ebuf;
9735d459b5aSDavid du Colombier 	Attr *a;
9745d459b5aSDavid du Colombier 
9755d459b5aSDavid du Colombier 	ebuf = buf+sizeof buf;
9765d459b5aSDavid du Colombier 	b = buf;
9775d459b5aSDavid du Colombier 	strcpy(buf, " ");
9785d459b5aSDavid du Colombier 	for(a=va_arg(fmt->args, Attr*); a; a=a->next){
9795d459b5aSDavid du Colombier 		if(a->name == nil)
9805d459b5aSDavid du Colombier 			continue;
9812ebbfa15SDavid du Colombier 		b = seprint(b, ebuf, " %q?", a->name);
9825d459b5aSDavid du Colombier 	}
9835d459b5aSDavid du Colombier 	return fmtstrcpy(fmt, buf+1);
9845d459b5aSDavid du Colombier }
985260f7b65SDavid du Colombier 
986260f7b65SDavid du Colombier void
disablekey(Key * k)987260f7b65SDavid du Colombier disablekey(Key *k)
988260f7b65SDavid du Colombier {
989260f7b65SDavid du Colombier 	Attr *a;
990260f7b65SDavid du Colombier 
991b05f4f54SDavid du Colombier 	if(sflag)	/* not on servers */
992b05f4f54SDavid du Colombier 		return;
993260f7b65SDavid du Colombier 	for(a=k->attr; a; a=a->next){
994260f7b65SDavid du Colombier 		if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
995260f7b65SDavid du Colombier 			return;
996260f7b65SDavid du Colombier 		if(a->next == nil)
997260f7b65SDavid du Colombier 			break;
998260f7b65SDavid du Colombier 	}
999260f7b65SDavid du Colombier 	if(a)
1000260f7b65SDavid du Colombier 		a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
1001260f7b65SDavid du Colombier 	else
1002260f7b65SDavid du Colombier 		k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil);	/* not reached: always a proto attribute */
1003260f7b65SDavid du Colombier }
1004