xref: /plan9-contrib/sys/src/cmd/auth/factotum/p9sk1.c (revision decede3daff5663ad9461ecbdee99636df315e35)
19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier  * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
39a747e4fSDavid du Colombier  * p9sk2 is an incomplete flawed variant of p9sk1.
49a747e4fSDavid du Colombier  *
59a747e4fSDavid du Colombier  * Client protocol:
69a747e4fSDavid du Colombier  *	write challenge[challen]	(p9sk1 only)
79a747e4fSDavid du Colombier  *	read tickreq[tickreqlen]
89a747e4fSDavid du Colombier  *	write ticket[ticketlen]
99a747e4fSDavid du Colombier  *	read authenticator[authentlen]
109a747e4fSDavid du Colombier  *
119a747e4fSDavid du Colombier  * Server protocol:
129a747e4fSDavid du Colombier  * 	read challenge[challen]	(p9sk1 only)
139a747e4fSDavid du Colombier  *	write tickreq[tickreqlen]
149a747e4fSDavid du Colombier  *	read ticket[ticketlen]
159a747e4fSDavid du Colombier  *	write authenticator[authentlen]
169a747e4fSDavid du Colombier  */
179a747e4fSDavid du Colombier 
189a747e4fSDavid du Colombier #include "dat.h"
199a747e4fSDavid du Colombier 
209a747e4fSDavid du Colombier struct State
219a747e4fSDavid du Colombier {
229a747e4fSDavid du Colombier 	int vers;
239a747e4fSDavid du Colombier 	Key *key;
249a747e4fSDavid du Colombier 	Ticket t;
259a747e4fSDavid du Colombier 	Ticketreq tr;
269a747e4fSDavid du Colombier 	char cchal[CHALLEN];
279a747e4fSDavid du Colombier 	char tbuf[TICKETLEN+AUTHENTLEN];
289a747e4fSDavid du Colombier 	char authkey[DESKEYLEN];
299a747e4fSDavid du Colombier 	uchar *secret;
309a747e4fSDavid du Colombier 	int speakfor;
319a747e4fSDavid du Colombier };
329a747e4fSDavid du Colombier 
339a747e4fSDavid du Colombier enum
349a747e4fSDavid du Colombier {
359a747e4fSDavid du Colombier 	/* client phases */
369a747e4fSDavid du Colombier 	CHaveChal,
379a747e4fSDavid du Colombier 	CNeedTreq,
389a747e4fSDavid du Colombier 	CHaveTicket,
399a747e4fSDavid du Colombier 	CNeedAuth,
409a747e4fSDavid du Colombier 
419a747e4fSDavid du Colombier 	/* server phases */
429a747e4fSDavid du Colombier 	SNeedChal,
439a747e4fSDavid du Colombier 	SHaveTreq,
449a747e4fSDavid du Colombier 	SNeedTicket,
459a747e4fSDavid du Colombier 	SHaveAuth,
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier 	Maxphase,
489a747e4fSDavid du Colombier };
499a747e4fSDavid du Colombier 
509a747e4fSDavid du Colombier static char *phasenames[Maxphase] =
519a747e4fSDavid du Colombier {
529a747e4fSDavid du Colombier [CHaveChal]		"CHaveChal",
539a747e4fSDavid du Colombier [CNeedTreq]		"CNeedTreq",
549a747e4fSDavid du Colombier [CHaveTicket]		"CHaveTicket",
559a747e4fSDavid du Colombier [CNeedAuth]		"CNeedAuth",
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier [SNeedChal]		"SNeedChal",
589a747e4fSDavid du Colombier [SHaveTreq]		"SHaveTreq",
599a747e4fSDavid du Colombier [SNeedTicket]		"SNeedTicket",
609a747e4fSDavid du Colombier [SHaveAuth]		"SHaveAuth",
619a747e4fSDavid du Colombier };
629a747e4fSDavid du Colombier 
639a747e4fSDavid du Colombier static int gettickets(State*, char*, char*);
649a747e4fSDavid du Colombier 
659a747e4fSDavid du Colombier static int
p9skinit(Proto * p,Fsstate * fss)669a747e4fSDavid du Colombier p9skinit(Proto *p, Fsstate *fss)
679a747e4fSDavid du Colombier {
689a747e4fSDavid du Colombier 	State *s;
699a747e4fSDavid du Colombier 	int iscli, ret;
709a747e4fSDavid du Colombier 	Key *k;
71260f7b65SDavid du Colombier 	Keyinfo ki;
729a747e4fSDavid du Colombier 	Attr *attr;
739a747e4fSDavid du Colombier 
742ebbfa15SDavid du Colombier 	if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
759a747e4fSDavid du Colombier 		return failure(fss, nil);
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier 	s = emalloc(sizeof *s);
789a747e4fSDavid du Colombier 	fss = fss;
799a747e4fSDavid du Colombier 	fss->phasename = phasenames;
809a747e4fSDavid du Colombier 	fss->maxphase = Maxphase;
819a747e4fSDavid du Colombier 	if(p == &p9sk1)
829a747e4fSDavid du Colombier 		s->vers = 1;
839a747e4fSDavid du Colombier 	else if(p == &p9sk2)
849a747e4fSDavid du Colombier 		s->vers = 2;
859a747e4fSDavid du Colombier 	else
869a747e4fSDavid du Colombier 		abort();
879a747e4fSDavid du Colombier 	if(iscli){
889a747e4fSDavid du Colombier 		switch(s->vers){
899a747e4fSDavid du Colombier 		case 1:
909a747e4fSDavid du Colombier 			fss->phase = CHaveChal;
919a747e4fSDavid du Colombier 			memrandom(s->cchal, CHALLEN);
929a747e4fSDavid du Colombier 			break;
939a747e4fSDavid du Colombier 		case 2:
949a747e4fSDavid du Colombier 			fss->phase = CNeedTreq;
959a747e4fSDavid du Colombier 			break;
969a747e4fSDavid du Colombier 		}
979a747e4fSDavid du Colombier 	}else{
989a747e4fSDavid du Colombier 		s->tr.type = AuthTreq;
999a747e4fSDavid du Colombier 		attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
100260f7b65SDavid du Colombier 		mkkeyinfo(&ki, fss, attr);
101260f7b65SDavid du Colombier 		ki.user = nil;
102260f7b65SDavid du Colombier 		ret = findkey(&k, &ki, "user? dom?");
1039a747e4fSDavid du Colombier 		_freeattr(attr);
1049a747e4fSDavid du Colombier 		if(ret != RpcOk){
1059a747e4fSDavid du Colombier 			free(s);
1069a747e4fSDavid du Colombier 			return ret;
1079a747e4fSDavid du Colombier 		}
1082ebbfa15SDavid du Colombier 		safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid));
1092ebbfa15SDavid du Colombier 		safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom));
1109a747e4fSDavid du Colombier 		s->key = k;
1119a747e4fSDavid du Colombier 		memrandom(s->tr.chal, sizeof s->tr.chal);
1129a747e4fSDavid du Colombier 		switch(s->vers){
1139a747e4fSDavid du Colombier 		case 1:
1149a747e4fSDavid du Colombier 			fss->phase = SNeedChal;
1159a747e4fSDavid du Colombier 			break;
1169a747e4fSDavid du Colombier 		case 2:
1179a747e4fSDavid du Colombier 			fss->phase = SHaveTreq;
1189a747e4fSDavid du Colombier 			memmove(s->cchal, s->tr.chal, CHALLEN);
1199a747e4fSDavid du Colombier 			break;
1209a747e4fSDavid du Colombier 		}
1219a747e4fSDavid du Colombier 	}
1229a747e4fSDavid du Colombier 	fss->ps = s;
1239a747e4fSDavid du Colombier 	return RpcOk;
1249a747e4fSDavid du Colombier }
1259a747e4fSDavid du Colombier 
1269a747e4fSDavid du Colombier static int
p9skread(Fsstate * fss,void * a,uint * n)1279a747e4fSDavid du Colombier p9skread(Fsstate *fss, void *a, uint *n)
1289a747e4fSDavid du Colombier {
1299a747e4fSDavid du Colombier 	int m;
1309a747e4fSDavid du Colombier 	State *s;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	s = fss->ps;
1339a747e4fSDavid du Colombier 	switch(fss->phase){
1349a747e4fSDavid du Colombier 	default:
1359a747e4fSDavid du Colombier 		return phaseerror(fss, "read");
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier 	case CHaveChal:
1389a747e4fSDavid du Colombier 		m = CHALLEN;
1399a747e4fSDavid du Colombier 		if(*n < m)
1409a747e4fSDavid du Colombier 			return toosmall(fss, m);
1419a747e4fSDavid du Colombier 		*n = m;
1429a747e4fSDavid du Colombier 		memmove(a, s->cchal, m);
1439a747e4fSDavid du Colombier 		fss->phase = CNeedTreq;
1449a747e4fSDavid du Colombier 		return RpcOk;
1459a747e4fSDavid du Colombier 
1469a747e4fSDavid du Colombier 	case SHaveTreq:
1479a747e4fSDavid du Colombier 		m = TICKREQLEN;
1489a747e4fSDavid du Colombier 		if(*n < m)
1499a747e4fSDavid du Colombier 			return toosmall(fss, m);
1509a747e4fSDavid du Colombier 		*n = m;
1519a747e4fSDavid du Colombier 		convTR2M(&s->tr, a);
1529a747e4fSDavid du Colombier 		fss->phase = SNeedTicket;
1539a747e4fSDavid du Colombier 		return RpcOk;
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier 	case CHaveTicket:
1569a747e4fSDavid du Colombier 		m = TICKETLEN+AUTHENTLEN;
1579a747e4fSDavid du Colombier 		if(*n < m)
1589a747e4fSDavid du Colombier 			return toosmall(fss, m);
1599a747e4fSDavid du Colombier 		*n = m;
1609a747e4fSDavid du Colombier 		memmove(a, s->tbuf, m);
1619a747e4fSDavid du Colombier 		fss->phase = CNeedAuth;
1629a747e4fSDavid du Colombier 		return RpcOk;
1639a747e4fSDavid du Colombier 
1649a747e4fSDavid du Colombier 	case SHaveAuth:
1659a747e4fSDavid du Colombier 		m = AUTHENTLEN;
1669a747e4fSDavid du Colombier 		if(*n < m)
1679a747e4fSDavid du Colombier 			return toosmall(fss, m);
1689a747e4fSDavid du Colombier 		*n = m;
1699a747e4fSDavid du Colombier 		memmove(a, s->tbuf+TICKETLEN, m);
1709a747e4fSDavid du Colombier 		fss->ai.cuid = s->t.cuid;
1719a747e4fSDavid du Colombier 		fss->ai.suid = s->t.suid;
1729a747e4fSDavid du Colombier 		s->secret = emalloc(8);
1739a747e4fSDavid du Colombier 		des56to64((uchar*)s->t.key, s->secret);
1749a747e4fSDavid du Colombier 		fss->ai.secret = s->secret;
1759a747e4fSDavid du Colombier 		fss->ai.nsecret = 8;
1769a747e4fSDavid du Colombier 		fss->haveai = 1;
1779a747e4fSDavid du Colombier 		fss->phase = Established;
1789a747e4fSDavid du Colombier 		return RpcOk;
1799a747e4fSDavid du Colombier 	}
1809a747e4fSDavid du Colombier }
1819a747e4fSDavid du Colombier 
1829a747e4fSDavid du Colombier static int
p9skwrite(Fsstate * fss,void * a,uint n)1839a747e4fSDavid du Colombier p9skwrite(Fsstate *fss, void *a, uint n)
1849a747e4fSDavid du Colombier {
1859a747e4fSDavid du Colombier 	int m, ret, sret;
1869a747e4fSDavid du Colombier 	char tbuf[2*TICKETLEN], trbuf[TICKREQLEN], *user;
187260f7b65SDavid du Colombier 	Attr *attr;
1889a747e4fSDavid du Colombier 	Authenticator auth;
1899a747e4fSDavid du Colombier 	State *s;
1909a747e4fSDavid du Colombier 	Key *srvkey;
191260f7b65SDavid du Colombier 	Keyinfo ki;
1929a747e4fSDavid du Colombier 
1939a747e4fSDavid du Colombier 	s = fss->ps;
1949a747e4fSDavid du Colombier 	switch(fss->phase){
1959a747e4fSDavid du Colombier 	default:
1969a747e4fSDavid du Colombier 		return phaseerror(fss, "write");
1979a747e4fSDavid du Colombier 
1989a747e4fSDavid du Colombier 	case SNeedChal:
1999a747e4fSDavid du Colombier 		m = CHALLEN;
2009a747e4fSDavid du Colombier 		if(n < m)
2019a747e4fSDavid du Colombier 			return toosmall(fss, m);
2029a747e4fSDavid du Colombier 		memmove(s->cchal, a, m);
2039a747e4fSDavid du Colombier 		fss->phase = SHaveTreq;
2049a747e4fSDavid du Colombier 		return RpcOk;
2059a747e4fSDavid du Colombier 
2069a747e4fSDavid du Colombier 	case CNeedTreq:
2079a747e4fSDavid du Colombier 		m = TICKREQLEN;
2089a747e4fSDavid du Colombier 		if(n < m)
2099a747e4fSDavid du Colombier 			return toosmall(fss, m);
2109a747e4fSDavid du Colombier 
2119a747e4fSDavid du Colombier 		/* remember server's chal */
2129a747e4fSDavid du Colombier 		convM2TR(a, &s->tr);
2139a747e4fSDavid du Colombier 		if(s->vers == 2)
2149a747e4fSDavid du Colombier 			memmove(s->cchal, s->tr.chal, CHALLEN);
2159a747e4fSDavid du Colombier 
2169a747e4fSDavid du Colombier 		if(s->key != nil)
2179a747e4fSDavid du Colombier 			closekey(s->key);
2189a747e4fSDavid du Colombier 
2199a747e4fSDavid du Colombier 		attr = _delattr(_delattr(_copyattr(fss->attr), "role"), "user");
2209a747e4fSDavid du Colombier 		attr = setattr(attr, "proto=p9sk1");
2212ebbfa15SDavid du Colombier 		user = _strfindattr(fss->attr, "user");
2229a747e4fSDavid du Colombier 		/*
2239a747e4fSDavid du Colombier 		 * If our client is the user who started factotum (client==owner), then
2249a747e4fSDavid du Colombier 		 * he can use whatever keys we have to speak as whoever he pleases.
2259a747e4fSDavid du Colombier 		 * If, on the other hand, we're speaking on behalf of someone else,
2269a747e4fSDavid du Colombier 		 * we will only vouch for their name on the local system.
2279a747e4fSDavid du Colombier 		 *
228fb7f0c93SDavid du Colombier 		 * We do the sysuser findkey second so that if we return RpcNeedkey,
2299a747e4fSDavid du Colombier 		 * the correct key information gets asked for.
2309a747e4fSDavid du Colombier 		 */
2319a747e4fSDavid du Colombier 		srvkey = nil;
2329a747e4fSDavid du Colombier 		s->speakfor = 0;
2339a747e4fSDavid du Colombier 		sret = RpcFailure;
234260f7b65SDavid du Colombier 		if(user==nil || strcmp(user, fss->sysuser) == 0){
235260f7b65SDavid du Colombier 			mkkeyinfo(&ki, fss, attr);
236260f7b65SDavid du Colombier 			ki.user = nil;
237260f7b65SDavid du Colombier 			sret = findkey(&srvkey, &ki,
2389a747e4fSDavid du Colombier 				"role=speakfor dom=%q user?", s->tr.authdom);
239260f7b65SDavid du Colombier 		}
2409a747e4fSDavid du Colombier 		if(user != nil)
2419a747e4fSDavid du Colombier 			attr = setattr(attr, "user=%q", user);
242260f7b65SDavid du Colombier 		mkkeyinfo(&ki, fss, attr);
243260f7b65SDavid du Colombier 		ret = findkey(&s->key, &ki,
2449a747e4fSDavid du Colombier 			"role=client dom=%q %s", s->tr.authdom, p9sk1.keyprompt);
2459a747e4fSDavid du Colombier 		if(ret == RpcOk)
2469a747e4fSDavid du Colombier 			closekey(srvkey);
2479a747e4fSDavid du Colombier 		else if(sret == RpcOk){
2489a747e4fSDavid du Colombier 			s->key = srvkey;
2499a747e4fSDavid du Colombier 			s->speakfor = 1;
2509a747e4fSDavid du Colombier 		}else if(ret == RpcConfirm || sret == RpcConfirm){
2519a747e4fSDavid du Colombier 			_freeattr(attr);
2529a747e4fSDavid du Colombier 			return RpcConfirm;
2539a747e4fSDavid du Colombier 		}else{
2549a747e4fSDavid du Colombier 			_freeattr(attr);
2559a747e4fSDavid du Colombier 			return ret;
2569a747e4fSDavid du Colombier 		}
2579a747e4fSDavid du Colombier 
2589a747e4fSDavid du Colombier 		/* fill in the rest of the request */
2599a747e4fSDavid du Colombier 		s->tr.type = AuthTreq;
2602ebbfa15SDavid du Colombier 		safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid);
2619a747e4fSDavid du Colombier 		if(s->speakfor)
2629a747e4fSDavid du Colombier 			safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid);
2639a747e4fSDavid du Colombier 		else
2649a747e4fSDavid du Colombier 			safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
2659a747e4fSDavid du Colombier 
2669a747e4fSDavid du Colombier 		convTR2M(&s->tr, trbuf);
2679a747e4fSDavid du Colombier 
2689a747e4fSDavid du Colombier 		/* get tickets, from auth server or invent if we can */
2699a747e4fSDavid du Colombier 		if(gettickets(s, trbuf, tbuf) < 0){
2709a747e4fSDavid du Colombier 			_freeattr(attr);
2719a747e4fSDavid du Colombier 			return failure(fss, nil);
2729a747e4fSDavid du Colombier 		}
2739a747e4fSDavid du Colombier 
2749a747e4fSDavid du Colombier 		convM2T(tbuf, &s->t, (char*)s->key->priv);
2759a747e4fSDavid du Colombier 		if(s->t.num != AuthTc){
276*decede3dSDavid du Colombier 			if(s->key->successes == 0 && !s->speakfor)
277260f7b65SDavid du Colombier 				disablekey(s->key);
278*decede3dSDavid du Colombier 			if(askforkeys && !s->speakfor){
2796822557bSDavid du Colombier 				snprint(fss->keyinfo, sizeof fss->keyinfo,
2806822557bSDavid du Colombier 					"%A %s", attr, p9sk1.keyprompt);
2819a747e4fSDavid du Colombier 				_freeattr(attr);
2829a747e4fSDavid du Colombier 				return RpcNeedkey;
2839a747e4fSDavid du Colombier 			}else{
2849a747e4fSDavid du Colombier 				_freeattr(attr);
2859a747e4fSDavid du Colombier 				return failure(fss, Ebadkey);
2869a747e4fSDavid du Colombier 			}
2879a747e4fSDavid du Colombier 		}
2886822557bSDavid du Colombier 		s->key->successes++;
2899a747e4fSDavid du Colombier 		_freeattr(attr);
2909a747e4fSDavid du Colombier 		memmove(s->tbuf, tbuf+TICKETLEN, TICKETLEN);
2919a747e4fSDavid du Colombier 
2929a747e4fSDavid du Colombier 		auth.num = AuthAc;
2939a747e4fSDavid du Colombier 		memmove(auth.chal, s->tr.chal, CHALLEN);
2949a747e4fSDavid du Colombier 		auth.id = 0;
2959a747e4fSDavid du Colombier 		convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
2969a747e4fSDavid du Colombier 		fss->phase = CHaveTicket;
2979a747e4fSDavid du Colombier 		return RpcOk;
2989a747e4fSDavid du Colombier 
2999a747e4fSDavid du Colombier 	case SNeedTicket:
3009a747e4fSDavid du Colombier 		m = TICKETLEN+AUTHENTLEN;
3019a747e4fSDavid du Colombier 		if(n < m)
3029a747e4fSDavid du Colombier 			return toosmall(fss, m);
3039a747e4fSDavid du Colombier 		convM2T(a, &s->t, (char*)s->key->priv);
3049a747e4fSDavid du Colombier 		if(s->t.num != AuthTs
3059a747e4fSDavid du Colombier 		|| memcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
3069a747e4fSDavid du Colombier 			return failure(fss, Easproto);
3079a747e4fSDavid du Colombier 		convM2A((char*)a+TICKETLEN, &auth, s->t.key);
3089a747e4fSDavid du Colombier 		if(auth.num != AuthAc
3099a747e4fSDavid du Colombier 		|| memcmp(auth.chal, s->tr.chal, CHALLEN) != 0
310a5d97709SDavid du Colombier 		|| auth.id != 0)
3119a747e4fSDavid du Colombier 			return failure(fss, Easproto);
3129a747e4fSDavid du Colombier 		auth.num = AuthAs;
3139a747e4fSDavid du Colombier 		memmove(auth.chal, s->cchal, CHALLEN);
3149a747e4fSDavid du Colombier 		auth.id = 0;
3159a747e4fSDavid du Colombier 		convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
3169a747e4fSDavid du Colombier 		fss->phase = SHaveAuth;
3179a747e4fSDavid du Colombier 		return RpcOk;
3189a747e4fSDavid du Colombier 
3199a747e4fSDavid du Colombier 	case CNeedAuth:
3209a747e4fSDavid du Colombier 		m = AUTHENTLEN;
3219a747e4fSDavid du Colombier 		if(n < m)
3229a747e4fSDavid du Colombier 			return toosmall(fss, m);
3239a747e4fSDavid du Colombier 		convM2A(a, &auth, s->t.key);
3249a747e4fSDavid du Colombier 		if(auth.num != AuthAs
3259a747e4fSDavid du Colombier 		|| memcmp(auth.chal, s->cchal, CHALLEN) != 0
3269a747e4fSDavid du Colombier 		|| auth.id != 0)
3279a747e4fSDavid du Colombier 			return failure(fss, Easproto);
3289a747e4fSDavid du Colombier 		fss->ai.cuid = s->t.cuid;
3299a747e4fSDavid du Colombier 		fss->ai.suid = s->t.suid;
3309a747e4fSDavid du Colombier 		s->secret = emalloc(8);
3319a747e4fSDavid du Colombier 		des56to64((uchar*)s->t.key, s->secret);
3329a747e4fSDavid du Colombier 		fss->ai.secret = s->secret;
3339a747e4fSDavid du Colombier 		fss->ai.nsecret = 8;
3349a747e4fSDavid du Colombier 		fss->haveai = 1;
3359a747e4fSDavid du Colombier 		fss->phase = Established;
3369a747e4fSDavid du Colombier 		return RpcOk;
3379a747e4fSDavid du Colombier 	}
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier static void
p9skclose(Fsstate * fss)3419a747e4fSDavid du Colombier p9skclose(Fsstate *fss)
3429a747e4fSDavid du Colombier {
3439a747e4fSDavid du Colombier 	State *s;
3449a747e4fSDavid du Colombier 
3459a747e4fSDavid du Colombier 	s = fss->ps;
3469a747e4fSDavid du Colombier 	if(s->secret != nil){
3479a747e4fSDavid du Colombier 		free(s->secret);
3489a747e4fSDavid du Colombier 		s->secret = nil;
3499a747e4fSDavid du Colombier 	}
3509a747e4fSDavid du Colombier 	if(s->key != nil){
3519a747e4fSDavid du Colombier 		closekey(s->key);
3529a747e4fSDavid du Colombier 		s->key = nil;
3539a747e4fSDavid du Colombier 	}
3549a747e4fSDavid du Colombier 	free(s);
3559a747e4fSDavid du Colombier }
3569a747e4fSDavid du Colombier 
3579a747e4fSDavid du Colombier static int
unhex(char c)3589a747e4fSDavid du Colombier unhex(char c)
3599a747e4fSDavid du Colombier {
3609a747e4fSDavid du Colombier 	if('0' <= c && c <= '9')
3619a747e4fSDavid du Colombier 		return c-'0';
3629a747e4fSDavid du Colombier 	if('a' <= c && c <= 'f')
3639a747e4fSDavid du Colombier 		return c-'a'+10;
3649a747e4fSDavid du Colombier 	if('A' <= c && c <= 'F')
3659a747e4fSDavid du Colombier 		return c-'A'+10;
3669a747e4fSDavid du Colombier 	abort();
3679a747e4fSDavid du Colombier 	return -1;
3689a747e4fSDavid du Colombier }
3699a747e4fSDavid du Colombier 
3709a747e4fSDavid du Colombier static int
hexparse(char * hex,uchar * dat,int ndat)3719a747e4fSDavid du Colombier hexparse(char *hex, uchar *dat, int ndat)
3729a747e4fSDavid du Colombier {
3739a747e4fSDavid du Colombier 	int i;
3749a747e4fSDavid du Colombier 
3759a747e4fSDavid du Colombier 	if(strlen(hex) != 2*ndat)
3769a747e4fSDavid du Colombier 		return -1;
3779a747e4fSDavid du Colombier 	if(hex[strspn(hex, "0123456789abcdefABCDEF")] != '\0')
3789a747e4fSDavid du Colombier 		return -1;
3799a747e4fSDavid du Colombier 	for(i=0; i<ndat; i++)
3809a747e4fSDavid du Colombier 		dat[i] = (unhex(hex[2*i])<<4)|unhex(hex[2*i+1]);
3819a747e4fSDavid du Colombier 	return 0;
3829a747e4fSDavid du Colombier }
3839a747e4fSDavid du Colombier 
3849a747e4fSDavid du Colombier static int
p9skaddkey(Key * k,int before)38570b8e010SDavid du Colombier p9skaddkey(Key *k, int before)
3869a747e4fSDavid du Colombier {
3879a747e4fSDavid du Colombier 	char *s;
3889a747e4fSDavid du Colombier 
3899a747e4fSDavid du Colombier 	k->priv = emalloc(DESKEYLEN);
3902ebbfa15SDavid du Colombier 	if(s = _strfindattr(k->privattr, "!hex")){
3919a747e4fSDavid du Colombier 		if(hexparse(s, k->priv, 7) < 0){
392d9306527SDavid du Colombier 			free(k->priv);
393d9306527SDavid du Colombier 			k->priv = nil;
3949a747e4fSDavid du Colombier 			werrstr("malformed key data");
3959a747e4fSDavid du Colombier 			return -1;
3969a747e4fSDavid du Colombier 		}
3972ebbfa15SDavid du Colombier 	}else if(s = _strfindattr(k->privattr, "!password")){
3989a747e4fSDavid du Colombier 		passtokey((char*)k->priv, s);
3999a747e4fSDavid du Colombier 	}else{
4009a747e4fSDavid du Colombier 		werrstr("no key data");
401d9306527SDavid du Colombier 		free(k->priv);
402d9306527SDavid du Colombier 		k->priv = nil;
4039a747e4fSDavid du Colombier 		return -1;
4049a747e4fSDavid du Colombier 	}
40570b8e010SDavid du Colombier 	return replacekey(k, before);
4069a747e4fSDavid du Colombier }
4079a747e4fSDavid du Colombier 
4089a747e4fSDavid du Colombier static void
p9skclosekey(Key * k)4099a747e4fSDavid du Colombier p9skclosekey(Key *k)
4109a747e4fSDavid du Colombier {
4119a747e4fSDavid du Colombier 	free(k->priv);
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier 
4149a747e4fSDavid du Colombier static int
getastickets(State * s,char * trbuf,char * tbuf)4159a747e4fSDavid du Colombier getastickets(State *s, char *trbuf, char *tbuf)
4169a747e4fSDavid du Colombier {
4179a747e4fSDavid du Colombier 	int asfd, rv;
4189a747e4fSDavid du Colombier 	char *dom;
4199a747e4fSDavid du Colombier 
4202ebbfa15SDavid du Colombier 	if((dom = _strfindattr(s->key->attr, "dom")) == nil){
4219a747e4fSDavid du Colombier 		werrstr("auth key has no domain");
4229a747e4fSDavid du Colombier 		return -1;
4239a747e4fSDavid du Colombier 	}
4249a747e4fSDavid du Colombier 	asfd = _authdial(nil, dom);
4259a747e4fSDavid du Colombier 	if(asfd < 0)
4269a747e4fSDavid du Colombier 		return -1;
4279a747e4fSDavid du Colombier 	rv = _asgetticket(asfd, trbuf, tbuf);
4289a747e4fSDavid du Colombier 	close(asfd);
4299a747e4fSDavid du Colombier 	return rv;
4309a747e4fSDavid du Colombier }
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier static int
mkserverticket(State * s,char * tbuf)433b7b24591SDavid du Colombier mkserverticket(State *s, char *tbuf)
434b7b24591SDavid du Colombier {
435b7b24591SDavid du Colombier 	Ticketreq *tr = &s->tr;
436b7b24591SDavid du Colombier 	Ticket t;
437b7b24591SDavid du Colombier 
4385d459b5aSDavid du Colombier 	if(strcmp(tr->authid, tr->hostid) != 0)
439b7b24591SDavid du Colombier 		return -1;
440fb7f0c93SDavid du Colombier /* this keeps creating accounts on martha from working.  -- presotto
441fb7f0c93SDavid du Colombier 	if(strcmp(tr->uid, "none") == 0)
442fb7f0c93SDavid du Colombier 		return -1;
443fb7f0c93SDavid du Colombier */
444b7b24591SDavid du Colombier 	memset(&t, 0, sizeof(t));
445b7b24591SDavid du Colombier 	memmove(t.chal, tr->chal, CHALLEN);
446b7b24591SDavid du Colombier 	strcpy(t.cuid, tr->uid);
447b7b24591SDavid du Colombier 	strcpy(t.suid, tr->uid);
448b7b24591SDavid du Colombier 	memrandom(t.key, DESKEYLEN);
449b7b24591SDavid du Colombier 	t.num = AuthTc;
450b7b24591SDavid du Colombier 	convT2M(&t, tbuf, s->key->priv);
451b7b24591SDavid du Colombier 	t.num = AuthTs;
452b7b24591SDavid du Colombier 	convT2M(&t, tbuf+TICKETLEN, s->key->priv);
453b7b24591SDavid du Colombier 	return 0;
454b7b24591SDavid du Colombier }
455b7b24591SDavid du Colombier 
456b7b24591SDavid du Colombier static int
gettickets(State * s,char * trbuf,char * tbuf)4579a747e4fSDavid du Colombier gettickets(State *s, char *trbuf, char *tbuf)
4589a747e4fSDavid du Colombier {
4599a747e4fSDavid du Colombier /*
4609a747e4fSDavid du Colombier 	if(mktickets(s, trbuf, tbuf) >= 0)
4619a747e4fSDavid du Colombier 		return 0;
4629a747e4fSDavid du Colombier */
4639a747e4fSDavid du Colombier 	if(getastickets(s, trbuf, tbuf) >= 0)
4649a747e4fSDavid du Colombier 		return 0;
465b7b24591SDavid du Colombier 	return mkserverticket(s, tbuf);
4669a747e4fSDavid du Colombier }
4679a747e4fSDavid du Colombier 
4689a747e4fSDavid du Colombier Proto p9sk1 = {
4699a747e4fSDavid du Colombier .name=	"p9sk1",
4709a747e4fSDavid du Colombier .init=		p9skinit,
4719a747e4fSDavid du Colombier .write=	p9skwrite,
4729a747e4fSDavid du Colombier .read=	p9skread,
4739a747e4fSDavid du Colombier .close=	p9skclose,
4749a747e4fSDavid du Colombier .addkey=	p9skaddkey,
4759a747e4fSDavid du Colombier .closekey=	p9skclosekey,
4769a747e4fSDavid du Colombier .keyprompt=	"user? !password?"
4779a747e4fSDavid du Colombier };
4789a747e4fSDavid du Colombier 
4799a747e4fSDavid du Colombier Proto p9sk2 = {
4809a747e4fSDavid du Colombier .name=	"p9sk2",
4819a747e4fSDavid du Colombier .init=		p9skinit,
4829a747e4fSDavid du Colombier .write=	p9skwrite,
4839a747e4fSDavid du Colombier .read=	p9skread,
4849a747e4fSDavid du Colombier .close=	p9skclose,
4859a747e4fSDavid du Colombier };
4869a747e4fSDavid du Colombier 
487