xref: /plan9/sys/src/9/port/auth.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include	"u.h"
2*219b2ee8SDavid du Colombier #include	"../port/lib.h"
3*219b2ee8SDavid du Colombier #include	"mem.h"
4*219b2ee8SDavid du Colombier #include	"dat.h"
5*219b2ee8SDavid du Colombier #include	"fns.h"
6*219b2ee8SDavid du Colombier #include	"io.h"
7*219b2ee8SDavid du Colombier #include	"../port/error.h"
8*219b2ee8SDavid du Colombier 
9*219b2ee8SDavid du Colombier typedef struct Crypt	Crypt;
10*219b2ee8SDavid du Colombier struct Crypt
11*219b2ee8SDavid du Colombier {
12*219b2ee8SDavid du Colombier 	Crypt		*next;
13*219b2ee8SDavid du Colombier 	Ticket		t;
14*219b2ee8SDavid du Colombier 	Authenticator	a;
15*219b2ee8SDavid du Colombier 	char		tbuf[TICKETLEN];	/* remote ticket */
16*219b2ee8SDavid du Colombier };
17*219b2ee8SDavid du Colombier 
18*219b2ee8SDavid du Colombier typedef struct Session	Session;
19*219b2ee8SDavid du Colombier struct Session
20*219b2ee8SDavid du Colombier {
21*219b2ee8SDavid du Colombier 	Lock;
22*219b2ee8SDavid du Colombier 	QLock	send;
23*219b2ee8SDavid du Colombier 	Crypt	*cache;			/* cache of tickets */
24*219b2ee8SDavid du Colombier 	char	cchal[CHALLEN];		/* client challenge */
25*219b2ee8SDavid du Colombier 	char	schal[CHALLEN];		/* server challenge */
26*219b2ee8SDavid du Colombier 	char	authid[NAMELEN];	/* server encryption uid */
27*219b2ee8SDavid du Colombier 	char	authdom[DOMLEN];	/* server encryption domain */
28*219b2ee8SDavid du Colombier 	ulong	cid;			/* challenge id */
29*219b2ee8SDavid du Colombier 	int	valid;
30*219b2ee8SDavid du Colombier };
31*219b2ee8SDavid du Colombier 
32*219b2ee8SDavid du Colombier struct
33*219b2ee8SDavid du Colombier {
34*219b2ee8SDavid du Colombier 	Lock;
35*219b2ee8SDavid du Colombier 	Crypt		*free;
36*219b2ee8SDavid du Colombier } cryptalloc;
37*219b2ee8SDavid du Colombier 
38*219b2ee8SDavid du Colombier char	eve[NAMELEN] = "bootes";
39*219b2ee8SDavid du Colombier char	evekey[DESKEYLEN];
40*219b2ee8SDavid du Colombier char	hostdomain[DOMLEN];
41*219b2ee8SDavid du Colombier 
42*219b2ee8SDavid du Colombier /*
43*219b2ee8SDavid du Colombier  *  return true if current user is eve
44*219b2ee8SDavid du Colombier  */
45*219b2ee8SDavid du Colombier int
46*219b2ee8SDavid du Colombier iseve(void)
47*219b2ee8SDavid du Colombier {
48*219b2ee8SDavid du Colombier 	return strcmp(eve, u->p->user) == 0;
49*219b2ee8SDavid du Colombier }
50*219b2ee8SDavid du Colombier 
51*219b2ee8SDavid du Colombier /*
52*219b2ee8SDavid du Colombier  * crypt entries are allocated from a pool rather than allocated using malloc so
53*219b2ee8SDavid du Colombier  * the memory can be protected from reading by devproc. The base and top of the
54*219b2ee8SDavid du Colombier  * crypt arena is stored in palloc for devproc.
55*219b2ee8SDavid du Colombier  */
56*219b2ee8SDavid du Colombier Crypt*
57*219b2ee8SDavid du Colombier newcrypt(void)
58*219b2ee8SDavid du Colombier {
59*219b2ee8SDavid du Colombier 	Crypt *c;
60*219b2ee8SDavid du Colombier 
61*219b2ee8SDavid du Colombier 	lock(&cryptalloc);
62*219b2ee8SDavid du Colombier 	if(cryptalloc.free) {
63*219b2ee8SDavid du Colombier 		c = cryptalloc.free;
64*219b2ee8SDavid du Colombier 		cryptalloc.free = c->next;
65*219b2ee8SDavid du Colombier 		unlock(&cryptalloc);
66*219b2ee8SDavid du Colombier 		memset(c, 0, sizeof(Crypt));
67*219b2ee8SDavid du Colombier 		return c;
68*219b2ee8SDavid du Colombier 	}
69*219b2ee8SDavid du Colombier 
70*219b2ee8SDavid du Colombier 	cryptalloc.free = xalloc(sizeof(Crypt)*conf.nproc);
71*219b2ee8SDavid du Colombier 	if(cryptalloc.free == 0)
72*219b2ee8SDavid du Colombier 		panic("newcrypt");
73*219b2ee8SDavid du Colombier 
74*219b2ee8SDavid du Colombier 	for(c = cryptalloc.free; c < cryptalloc.free+conf.nproc-1; c++)
75*219b2ee8SDavid du Colombier 		c->next = c+1;
76*219b2ee8SDavid du Colombier 
77*219b2ee8SDavid du Colombier 	palloc.cmembase = (ulong)cryptalloc.free;
78*219b2ee8SDavid du Colombier 	palloc.cmemtop = palloc.cmembase+(sizeof(Crypt)*conf.nproc);
79*219b2ee8SDavid du Colombier 	unlock(&cryptalloc);
80*219b2ee8SDavid du Colombier 	return newcrypt();
81*219b2ee8SDavid du Colombier }
82*219b2ee8SDavid du Colombier 
83*219b2ee8SDavid du Colombier void
84*219b2ee8SDavid du Colombier freecrypt(Crypt *c)
85*219b2ee8SDavid du Colombier {
86*219b2ee8SDavid du Colombier 	lock(&cryptalloc);
87*219b2ee8SDavid du Colombier 	c->next = cryptalloc.free;
88*219b2ee8SDavid du Colombier 	cryptalloc.free = c;
89*219b2ee8SDavid du Colombier 	unlock(&cryptalloc);
90*219b2ee8SDavid du Colombier }
91*219b2ee8SDavid du Colombier 
92*219b2ee8SDavid du Colombier /*
93*219b2ee8SDavid du Colombier  *  return the info received in the session message on this channel.
94*219b2ee8SDavid du Colombier  *  if no session message has been exchanged, do it.
95*219b2ee8SDavid du Colombier  */
96*219b2ee8SDavid du Colombier long
97*219b2ee8SDavid du Colombier sysfsession(ulong *arg)
98*219b2ee8SDavid du Colombier {
99*219b2ee8SDavid du Colombier 	int i, n;
100*219b2ee8SDavid du Colombier 	Chan *c;
101*219b2ee8SDavid du Colombier 	Crypt *cp;
102*219b2ee8SDavid du Colombier 	Session *s;
103*219b2ee8SDavid du Colombier 	Ticketreq tr;
104*219b2ee8SDavid du Colombier 	Fcall f;
105*219b2ee8SDavid du Colombier 	char buf[MAXMSG];
106*219b2ee8SDavid du Colombier 
107*219b2ee8SDavid du Colombier 	validaddr(arg[1], TICKREQLEN, 1);
108*219b2ee8SDavid du Colombier 	c = fdtochan(arg[0], OWRITE, 0, 1);
109*219b2ee8SDavid du Colombier 	if(waserror()){
110*219b2ee8SDavid du Colombier 		close(c);
111*219b2ee8SDavid du Colombier 		nexterror();
112*219b2ee8SDavid du Colombier 	}
113*219b2ee8SDavid du Colombier 
114*219b2ee8SDavid du Colombier 	/* add a session structure to the channel if it has none */
115*219b2ee8SDavid du Colombier 	lock(c);
116*219b2ee8SDavid du Colombier 	s = c->session;
117*219b2ee8SDavid du Colombier 	if(s == 0){
118*219b2ee8SDavid du Colombier 		s = malloc(sizeof(Session));
119*219b2ee8SDavid du Colombier 		if(s == 0){
120*219b2ee8SDavid du Colombier 			unlock(c);
121*219b2ee8SDavid du Colombier 			error(Enomem);
122*219b2ee8SDavid du Colombier 		}
123*219b2ee8SDavid du Colombier 		c->session = s;
124*219b2ee8SDavid du Colombier 	}
125*219b2ee8SDavid du Colombier 	unlock(c);
126*219b2ee8SDavid du Colombier 
127*219b2ee8SDavid du Colombier 	qlock(&s->send);
128*219b2ee8SDavid du Colombier 	if(s->valid == 0){
129*219b2ee8SDavid du Colombier 		/*
130*219b2ee8SDavid du Colombier 		 *  Exchange a session message with the server.
131*219b2ee8SDavid du Colombier 		 */
132*219b2ee8SDavid du Colombier 		for(i = 0; i < CHALLEN; i++)
133*219b2ee8SDavid du Colombier 			s->cchal[i] = nrand(256);
134*219b2ee8SDavid du Colombier 
135*219b2ee8SDavid du Colombier 		f.tag = NOTAG;
136*219b2ee8SDavid du Colombier 		f.type = Tsession;
137*219b2ee8SDavid du Colombier 		memmove(f.chal, s->cchal, CHALLEN);
138*219b2ee8SDavid du Colombier 		n = convS2M(&f, buf);
139*219b2ee8SDavid du Colombier 
140*219b2ee8SDavid du Colombier 		/*
141*219b2ee8SDavid du Colombier 		 *  If an error occurs reading or writing,
142*219b2ee8SDavid du Colombier 		 *  this probably is a mount of a mount so turn off
143*219b2ee8SDavid du Colombier 		 *  authentication.
144*219b2ee8SDavid du Colombier 		 */
145*219b2ee8SDavid du Colombier 		if(waserror())
146*219b2ee8SDavid du Colombier 			goto noauth;
147*219b2ee8SDavid du Colombier 
148*219b2ee8SDavid du Colombier 		if((*devtab[c->type].write)(c, buf, n, 0) != n)
149*219b2ee8SDavid du Colombier 			error(Esession);
150*219b2ee8SDavid du Colombier 		n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
151*219b2ee8SDavid du Colombier 		/* OK is sometimes sent as a Datakit sign-on */
152*219b2ee8SDavid du Colombier 		if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
153*219b2ee8SDavid du Colombier 			n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
154*219b2ee8SDavid du Colombier 
155*219b2ee8SDavid du Colombier 		poperror();
156*219b2ee8SDavid du Colombier 
157*219b2ee8SDavid du Colombier 		if(convM2S(buf, &f, n) == 0){
158*219b2ee8SDavid du Colombier 			qunlock(&s->send);
159*219b2ee8SDavid du Colombier 			error(Esession);
160*219b2ee8SDavid du Colombier 		}
161*219b2ee8SDavid du Colombier 		switch(f.type){
162*219b2ee8SDavid du Colombier 		case Rsession:
163*219b2ee8SDavid du Colombier 			memmove(s->schal, f.chal, CHALLEN);
164*219b2ee8SDavid du Colombier 			memmove(s->authid, f.authid, NAMELEN);
165*219b2ee8SDavid du Colombier 			memmove(s->authdom, f.authdom, DOMLEN);
166*219b2ee8SDavid du Colombier 			break;
167*219b2ee8SDavid du Colombier 		case Rerror:
168*219b2ee8SDavid du Colombier 			qunlock(&s->send);
169*219b2ee8SDavid du Colombier 			error(f.ename);
170*219b2ee8SDavid du Colombier 		default:
171*219b2ee8SDavid du Colombier 			qunlock(&s->send);
172*219b2ee8SDavid du Colombier 			error(Esession);
173*219b2ee8SDavid du Colombier 		}
174*219b2ee8SDavid du Colombier noauth:
175*219b2ee8SDavid du Colombier 		s->valid = 1;
176*219b2ee8SDavid du Colombier 	}
177*219b2ee8SDavid du Colombier 	qunlock(&s->send);
178*219b2ee8SDavid du Colombier 
179*219b2ee8SDavid du Colombier 	/*
180*219b2ee8SDavid du Colombier 	 *  If server requires no ticket, or user is "none", or a ticket
181*219b2ee8SDavid du Colombier 	 *  is already cached, zero the request type
182*219b2ee8SDavid du Colombier 	 */
183*219b2ee8SDavid du Colombier 	tr.type = AuthTreq;
184*219b2ee8SDavid du Colombier 	if(strcmp(u->p->user, "none") == 0 || s->authid[0] == 0)
185*219b2ee8SDavid du Colombier 		tr.type = 0;
186*219b2ee8SDavid du Colombier 	else{
187*219b2ee8SDavid du Colombier 		lock(s);
188*219b2ee8SDavid du Colombier 		for(cp = s->cache; cp; cp = cp->next)
189*219b2ee8SDavid du Colombier 			if(strcmp(cp->t.cuid, u->p->user) == 0){
190*219b2ee8SDavid du Colombier 				tr.type = 0;
191*219b2ee8SDavid du Colombier 				break;
192*219b2ee8SDavid du Colombier 			}
193*219b2ee8SDavid du Colombier 		unlock(s);
194*219b2ee8SDavid du Colombier 	}
195*219b2ee8SDavid du Colombier 
196*219b2ee8SDavid du Colombier 	/*  create ticket request */
197*219b2ee8SDavid du Colombier 	memmove(tr.chal, s->schal, CHALLEN);
198*219b2ee8SDavid du Colombier 	memmove(tr.authid, s->authid, NAMELEN);
199*219b2ee8SDavid du Colombier 	memmove(tr.authdom, s->authdom, DOMLEN);
200*219b2ee8SDavid du Colombier 	memmove(tr.uid, u->p->user, NAMELEN);
201*219b2ee8SDavid du Colombier 	memmove(tr.hostid, eve, NAMELEN);
202*219b2ee8SDavid du Colombier 	convTR2M(&tr, (char*)arg[1]);
203*219b2ee8SDavid du Colombier 
204*219b2ee8SDavid du Colombier 	close(c);
205*219b2ee8SDavid du Colombier 	poperror();
206*219b2ee8SDavid du Colombier 	return 0;
207*219b2ee8SDavid du Colombier }
208*219b2ee8SDavid du Colombier 
209*219b2ee8SDavid du Colombier /*
210*219b2ee8SDavid du Colombier  *  attach tickets to a session
211*219b2ee8SDavid du Colombier  */
212*219b2ee8SDavid du Colombier long
213*219b2ee8SDavid du Colombier sysfauth(ulong *arg)
214*219b2ee8SDavid du Colombier {
215*219b2ee8SDavid du Colombier 	Chan *c;
216*219b2ee8SDavid du Colombier 	char *ta;
217*219b2ee8SDavid du Colombier 	Session *s;
218*219b2ee8SDavid du Colombier 	Crypt *cp, *ncp, **l;
219*219b2ee8SDavid du Colombier 	char tbuf[2*TICKETLEN];
220*219b2ee8SDavid du Colombier 
221*219b2ee8SDavid du Colombier 	validaddr(arg[1], 2*TICKETLEN, 0);
222*219b2ee8SDavid du Colombier 	c = fdtochan(arg[0], OWRITE, 0, 1);
223*219b2ee8SDavid du Colombier 	s = c->session;
224*219b2ee8SDavid du Colombier 	if(s == 0)
225*219b2ee8SDavid du Colombier 		error("fauth must follow fsession");
226*219b2ee8SDavid du Colombier 	cp = newcrypt();
227*219b2ee8SDavid du Colombier 	if(waserror()){
228*219b2ee8SDavid du Colombier 		freecrypt(cp);
229*219b2ee8SDavid du Colombier 		nexterror();
230*219b2ee8SDavid du Colombier 	}
231*219b2ee8SDavid du Colombier 
232*219b2ee8SDavid du Colombier 	/*  ticket supplied, use it */
233*219b2ee8SDavid du Colombier 	ta = (char*)arg[1];
234*219b2ee8SDavid du Colombier 	memmove(tbuf, ta, 2*TICKETLEN);
235*219b2ee8SDavid du Colombier 	convM2T(tbuf, &cp->t, evekey);
236*219b2ee8SDavid du Colombier 	if(cp->t.num != AuthTc)
237*219b2ee8SDavid du Colombier 		error("bad AuthTc in ticket");
238*219b2ee8SDavid du Colombier 	if(strncmp(u->p->user, cp->t.cuid, NAMELEN) != 0)
239*219b2ee8SDavid du Colombier 		error("bad uid in ticket");
240*219b2ee8SDavid du Colombier 	if(memcmp(cp->t.chal, s->schal, CHALLEN) != 0)
241*219b2ee8SDavid du Colombier 		error("bad chal in ticket");
242*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, tbuf+TICKETLEN, TICKETLEN);
243*219b2ee8SDavid du Colombier 
244*219b2ee8SDavid du Colombier 	/* string onto local list, replace old version */
245*219b2ee8SDavid du Colombier 	lock(s);
246*219b2ee8SDavid du Colombier 	l = &s->cache;
247*219b2ee8SDavid du Colombier 	for(ncp = s->cache; ncp; ncp = *l){
248*219b2ee8SDavid du Colombier 		if(strcmp(ncp->t.cuid, u->p->user) == 0){
249*219b2ee8SDavid du Colombier 			*l = ncp->next;
250*219b2ee8SDavid du Colombier 			freecrypt(ncp);
251*219b2ee8SDavid du Colombier 			break;
252*219b2ee8SDavid du Colombier 		}
253*219b2ee8SDavid du Colombier 		l = &ncp->next;
254*219b2ee8SDavid du Colombier 	}
255*219b2ee8SDavid du Colombier 	cp->next = s->cache;
256*219b2ee8SDavid du Colombier 	s->cache = cp;
257*219b2ee8SDavid du Colombier 	unlock(s);
258*219b2ee8SDavid du Colombier 	poperror();
259*219b2ee8SDavid du Colombier 	return 0;
260*219b2ee8SDavid du Colombier }
261*219b2ee8SDavid du Colombier 
262*219b2ee8SDavid du Colombier /*
263*219b2ee8SDavid du Colombier  *  free a session created by fsession
264*219b2ee8SDavid du Colombier  */
265*219b2ee8SDavid du Colombier void
266*219b2ee8SDavid du Colombier freesession(Session *s)
267*219b2ee8SDavid du Colombier {
268*219b2ee8SDavid du Colombier 	Crypt *cp, *next;
269*219b2ee8SDavid du Colombier 
270*219b2ee8SDavid du Colombier 	for(cp = s->cache; cp; cp = next) {
271*219b2ee8SDavid du Colombier 		next = cp->next;
272*219b2ee8SDavid du Colombier 		freecrypt(cp);
273*219b2ee8SDavid du Colombier 	}
274*219b2ee8SDavid du Colombier 	free(s);
275*219b2ee8SDavid du Colombier }
276*219b2ee8SDavid du Colombier 
277*219b2ee8SDavid du Colombier /*
278*219b2ee8SDavid du Colombier  *  called by mattach() to fill in the Tattach message
279*219b2ee8SDavid du Colombier  */
280*219b2ee8SDavid du Colombier ulong
281*219b2ee8SDavid du Colombier authrequest(Session *s, Fcall *f)
282*219b2ee8SDavid du Colombier {
283*219b2ee8SDavid du Colombier 	Crypt *cp;
284*219b2ee8SDavid du Colombier 	ulong id, dofree;
285*219b2ee8SDavid du Colombier 
286*219b2ee8SDavid du Colombier 	/* no authentication if user is "none" or if no ticket required by remote */
287*219b2ee8SDavid du Colombier 	if(s == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0){
288*219b2ee8SDavid du Colombier 		memset(f->ticket, 0, TICKETLEN);
289*219b2ee8SDavid du Colombier 		memset(f->auth, 0, AUTHENTLEN);
290*219b2ee8SDavid du Colombier 		return 0;
291*219b2ee8SDavid du Colombier 	}
292*219b2ee8SDavid du Colombier 
293*219b2ee8SDavid du Colombier 	/* look for ticket in cache */
294*219b2ee8SDavid du Colombier 	dofree = 0;
295*219b2ee8SDavid du Colombier 	lock(s);
296*219b2ee8SDavid du Colombier 	for(cp = s->cache; cp; cp = cp->next)
297*219b2ee8SDavid du Colombier 		if(strcmp(cp->t.cuid, u->p->user) == 0)
298*219b2ee8SDavid du Colombier 			break;
299*219b2ee8SDavid du Colombier 
300*219b2ee8SDavid du Colombier 	id = s->cid++;
301*219b2ee8SDavid du Colombier 	unlock(s);
302*219b2ee8SDavid du Colombier 
303*219b2ee8SDavid du Colombier 	if(cp == 0){
304*219b2ee8SDavid du Colombier 		/*
305*219b2ee8SDavid du Colombier 		 *  create a ticket using hostkey, this solves the
306*219b2ee8SDavid du Colombier 		 *  chicken and egg problem
307*219b2ee8SDavid du Colombier 		 */
308*219b2ee8SDavid du Colombier 		cp = newcrypt();
309*219b2ee8SDavid du Colombier 		cp->t.num = AuthTs;
310*219b2ee8SDavid du Colombier 		memmove(cp->t.chal, s->schal, CHALLEN);
311*219b2ee8SDavid du Colombier 		memmove(cp->t.cuid, u->p->user, NAMELEN);
312*219b2ee8SDavid du Colombier 		memmove(cp->t.suid, u->p->user, NAMELEN);
313*219b2ee8SDavid du Colombier 		memmove(cp->t.key, evekey, DESKEYLEN);
314*219b2ee8SDavid du Colombier 		convT2M(&cp->t, f->ticket, evekey);
315*219b2ee8SDavid du Colombier 		dofree = 1;
316*219b2ee8SDavid du Colombier 	} else
317*219b2ee8SDavid du Colombier 		memmove(f->ticket, cp->tbuf, TICKETLEN);
318*219b2ee8SDavid du Colombier 
319*219b2ee8SDavid du Colombier 	/* create an authenticator */
320*219b2ee8SDavid du Colombier 	memmove(cp->a.chal, s->schal, CHALLEN);
321*219b2ee8SDavid du Colombier 	cp->a.num = AuthAc;
322*219b2ee8SDavid du Colombier 	cp->a.id = id;
323*219b2ee8SDavid du Colombier 	convA2M(&cp->a, f->auth, cp->t.key);
324*219b2ee8SDavid du Colombier 	if(dofree)
325*219b2ee8SDavid du Colombier 		freecrypt(cp);
326*219b2ee8SDavid du Colombier 	return id;
327*219b2ee8SDavid du Colombier }
328*219b2ee8SDavid du Colombier 
329*219b2ee8SDavid du Colombier /*
330*219b2ee8SDavid du Colombier  *  called by mattach() to check the Rattach message
331*219b2ee8SDavid du Colombier  */
332*219b2ee8SDavid du Colombier void
333*219b2ee8SDavid du Colombier authreply(Session *s, ulong id, Fcall *f)
334*219b2ee8SDavid du Colombier {
335*219b2ee8SDavid du Colombier 	Crypt *cp;
336*219b2ee8SDavid du Colombier 
337*219b2ee8SDavid du Colombier 	if(s == 0)
338*219b2ee8SDavid du Colombier 		return;
339*219b2ee8SDavid du Colombier 
340*219b2ee8SDavid du Colombier 	lock(s);
341*219b2ee8SDavid du Colombier 	for(cp = s->cache; cp; cp = cp->next)
342*219b2ee8SDavid du Colombier 		if(strcmp(cp->t.cuid, u->p->user) == 0)
343*219b2ee8SDavid du Colombier 			break;
344*219b2ee8SDavid du Colombier 	unlock(s);
345*219b2ee8SDavid du Colombier 
346*219b2ee8SDavid du Colombier 	/* we're getting around authentication */
347*219b2ee8SDavid du Colombier 	if(s == 0 || cp == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0)
348*219b2ee8SDavid du Colombier 		return;
349*219b2ee8SDavid du Colombier 
350*219b2ee8SDavid du Colombier 	convM2A(f->rauth, &cp->a, cp->t.key);
351*219b2ee8SDavid du Colombier 	if(cp->a.num != AuthAs){
352*219b2ee8SDavid du Colombier 		print("bad encryption type\n");
353*219b2ee8SDavid du Colombier 		error("server lies");
354*219b2ee8SDavid du Colombier 	}
355*219b2ee8SDavid du Colombier 	if(memcmp(cp->a.chal, s->cchal, sizeof(cp->a.chal))){
356*219b2ee8SDavid du Colombier 		print("bad returned challenge\n");
357*219b2ee8SDavid du Colombier 		error("server lies");
358*219b2ee8SDavid du Colombier 	}
359*219b2ee8SDavid du Colombier 	if(cp->a.id != id){
360*219b2ee8SDavid du Colombier 		print("bad returned id\n");
361*219b2ee8SDavid du Colombier 		error("server lies");
362*219b2ee8SDavid du Colombier 	}
363*219b2ee8SDavid du Colombier }
364*219b2ee8SDavid du Colombier 
365*219b2ee8SDavid du Colombier /*
366*219b2ee8SDavid du Colombier  *  called by devcons() for #c/authenticate
367*219b2ee8SDavid du Colombier  *
368*219b2ee8SDavid du Colombier  *  The protocol is
369*219b2ee8SDavid du Colombier  *	1) read ticket request from #c/authenticate
370*219b2ee8SDavid du Colombier  *	2) write ticket+authenticator to #c/authenticate. if it matches
371*219b2ee8SDavid du Colombier  *	  the challenge the user is changed to the suid field of the ticket
372*219b2ee8SDavid du Colombier  *	3) read authenticator (to confirm this is the server advertised)
373*219b2ee8SDavid du Colombier  */
374*219b2ee8SDavid du Colombier long
375*219b2ee8SDavid du Colombier authread(Chan *c, char *a, int n)
376*219b2ee8SDavid du Colombier {
377*219b2ee8SDavid du Colombier 	Crypt *cp;
378*219b2ee8SDavid du Colombier 	int i;
379*219b2ee8SDavid du Colombier 	Ticketreq tr;
380*219b2ee8SDavid du Colombier 
381*219b2ee8SDavid du Colombier 	if(c->aux == 0){
382*219b2ee8SDavid du Colombier 		/*
383*219b2ee8SDavid du Colombier 		 *  first read returns a ticket request
384*219b2ee8SDavid du Colombier 		 */
385*219b2ee8SDavid du Colombier 		if(n != TICKREQLEN)
386*219b2ee8SDavid du Colombier 			error(Ebadarg);
387*219b2ee8SDavid du Colombier 		c->aux = newcrypt();
388*219b2ee8SDavid du Colombier 		cp = c->aux;
389*219b2ee8SDavid du Colombier 
390*219b2ee8SDavid du Colombier 		memset(&tr, 0, sizeof(tr));
391*219b2ee8SDavid du Colombier 		tr.type = AuthTreq;
392*219b2ee8SDavid du Colombier 		strcpy(tr.hostid, eve);
393*219b2ee8SDavid du Colombier 		strcpy(tr.authid, eve);
394*219b2ee8SDavid du Colombier 		strcpy(tr.authdom, hostdomain);
395*219b2ee8SDavid du Colombier 		strcpy(tr.uid, u->p->user);
396*219b2ee8SDavid du Colombier 		for(i = 0; i < CHALLEN; i++)
397*219b2ee8SDavid du Colombier 			tr.chal[i] = nrand(256);
398*219b2ee8SDavid du Colombier 		memmove(cp->a.chal, tr.chal, CHALLEN);
399*219b2ee8SDavid du Colombier 		convTR2M(&tr, a);
400*219b2ee8SDavid du Colombier 	} else {
401*219b2ee8SDavid du Colombier 		/*
402*219b2ee8SDavid du Colombier 		 *  subsequent read returns an authenticator
403*219b2ee8SDavid du Colombier 		 */
404*219b2ee8SDavid du Colombier 		if(n != AUTHENTLEN)
405*219b2ee8SDavid du Colombier 			error(Ebadarg);
406*219b2ee8SDavid du Colombier 		cp = c->aux;
407*219b2ee8SDavid du Colombier 
408*219b2ee8SDavid du Colombier 		cp->a.num = AuthAs;
409*219b2ee8SDavid du Colombier 		memmove(cp->a.chal, cp->t.chal, CHALLEN);
410*219b2ee8SDavid du Colombier 		cp->a.id = 0;
411*219b2ee8SDavid du Colombier 		convA2M(&cp->a, cp->tbuf, cp->t.key);
412*219b2ee8SDavid du Colombier 		memmove(a, cp->tbuf, AUTHENTLEN);
413*219b2ee8SDavid du Colombier 
414*219b2ee8SDavid du Colombier 		freecrypt(cp);
415*219b2ee8SDavid du Colombier 		c->aux = 0;
416*219b2ee8SDavid du Colombier 	}
417*219b2ee8SDavid du Colombier 	return n;
418*219b2ee8SDavid du Colombier }
419*219b2ee8SDavid du Colombier 
420*219b2ee8SDavid du Colombier long
421*219b2ee8SDavid du Colombier authwrite(Chan *c, char *a, int n)
422*219b2ee8SDavid du Colombier {
423*219b2ee8SDavid du Colombier 	Crypt *cp;
424*219b2ee8SDavid du Colombier 
425*219b2ee8SDavid du Colombier 	if(n != TICKETLEN+AUTHENTLEN)
426*219b2ee8SDavid du Colombier 		error(Ebadarg);
427*219b2ee8SDavid du Colombier 	if(c->aux == 0)
428*219b2ee8SDavid du Colombier 		error(Ebadarg);
429*219b2ee8SDavid du Colombier 	cp = c->aux;
430*219b2ee8SDavid du Colombier 
431*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, a, TICKETLEN);
432*219b2ee8SDavid du Colombier 	convM2T(cp->tbuf, &cp->t, evekey);
433*219b2ee8SDavid du Colombier 	if(cp->t.num != AuthTs || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
434*219b2ee8SDavid du Colombier 		error(Eperm);
435*219b2ee8SDavid du Colombier 
436*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
437*219b2ee8SDavid du Colombier 	convM2A(cp->tbuf, &cp->a, cp->t.key);
438*219b2ee8SDavid du Colombier 	if(cp->a.num != AuthAc || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
439*219b2ee8SDavid du Colombier 		error(Eperm);
440*219b2ee8SDavid du Colombier 
441*219b2ee8SDavid du Colombier 	memmove(u->p->user, cp->t.suid, NAMELEN);
442*219b2ee8SDavid du Colombier 	return n;
443*219b2ee8SDavid du Colombier }
444*219b2ee8SDavid du Colombier 
445*219b2ee8SDavid du Colombier /*
446*219b2ee8SDavid du Colombier  *  called by devcons() for #c/authcheck
447*219b2ee8SDavid du Colombier  *
448*219b2ee8SDavid du Colombier  *  a write of a ticket+authenticator [+challenge+id] succeeds if they match
449*219b2ee8SDavid du Colombier  */
450*219b2ee8SDavid du Colombier long
451*219b2ee8SDavid du Colombier authcheck(Chan *c, char *a, int n)
452*219b2ee8SDavid du Colombier {
453*219b2ee8SDavid du Colombier 	Crypt *cp;
454*219b2ee8SDavid du Colombier 	char *chal;
455*219b2ee8SDavid du Colombier 	ulong id;
456*219b2ee8SDavid du Colombier 
457*219b2ee8SDavid du Colombier 	if(n != TICKETLEN+AUTHENTLEN && n != TICKETLEN+AUTHENTLEN+CHALLEN+4)
458*219b2ee8SDavid du Colombier 		error(Ebadarg);
459*219b2ee8SDavid du Colombier 	if(c->aux == 0)
460*219b2ee8SDavid du Colombier 		c->aux = newcrypt();
461*219b2ee8SDavid du Colombier 	cp = c->aux;
462*219b2ee8SDavid du Colombier 
463*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, a, TICKETLEN);
464*219b2ee8SDavid du Colombier 	convM2T(cp->tbuf, &cp->t, evekey);
465*219b2ee8SDavid du Colombier 	if(cp->t.num != AuthTc)
466*219b2ee8SDavid du Colombier 		error(Ebadarg);
467*219b2ee8SDavid du Colombier 	if(strcmp(u->p->user, cp->t.cuid))
468*219b2ee8SDavid du Colombier 		error(cp->t.cuid);
469*219b2ee8SDavid du Colombier 
470*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
471*219b2ee8SDavid du Colombier 	convM2A(cp->tbuf, &cp->a, cp->t.key);
472*219b2ee8SDavid du Colombier 	if(n == TICKETLEN+AUTHENTLEN+CHALLEN+4){
473*219b2ee8SDavid du Colombier 		uchar *p = (uchar *)&a[TICKETLEN+AUTHENTLEN+CHALLEN];
474*219b2ee8SDavid du Colombier 		id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
475*219b2ee8SDavid du Colombier 		chal = &a[TICKETLEN+AUTHENTLEN];
476*219b2ee8SDavid du Colombier 	}else{
477*219b2ee8SDavid du Colombier 		id = 0;
478*219b2ee8SDavid du Colombier 		chal = cp->t.chal;
479*219b2ee8SDavid du Colombier 	}
480*219b2ee8SDavid du Colombier 	if(cp->a.num != AuthAs || memcmp(chal, cp->a.chal, CHALLEN) || cp->a.id != id)
481*219b2ee8SDavid du Colombier 		error(Eperm);
482*219b2ee8SDavid du Colombier 
483*219b2ee8SDavid du Colombier 	return n;
484*219b2ee8SDavid du Colombier }
485*219b2ee8SDavid du Colombier 
486*219b2ee8SDavid du Colombier /*
487*219b2ee8SDavid du Colombier  *  called by devcons() for #c/authenticator
488*219b2ee8SDavid du Colombier  *
489*219b2ee8SDavid du Colombier  *  a read after a write of a ticket (or ticket+id) returns an authenticator
490*219b2ee8SDavid du Colombier  *  for that ticket.
491*219b2ee8SDavid du Colombier  */
492*219b2ee8SDavid du Colombier long
493*219b2ee8SDavid du Colombier authentwrite(Chan *c, char *a, int n)
494*219b2ee8SDavid du Colombier {
495*219b2ee8SDavid du Colombier 	Crypt *cp;
496*219b2ee8SDavid du Colombier 
497*219b2ee8SDavid du Colombier 	if(n != TICKETLEN && n != TICKETLEN+4)
498*219b2ee8SDavid du Colombier 		error(Ebadarg);
499*219b2ee8SDavid du Colombier 	if(c->aux == 0)
500*219b2ee8SDavid du Colombier 		c->aux = newcrypt();
501*219b2ee8SDavid du Colombier 	cp = c->aux;
502*219b2ee8SDavid du Colombier 
503*219b2ee8SDavid du Colombier 	memmove(cp->tbuf, a, TICKETLEN);
504*219b2ee8SDavid du Colombier 	convM2T(cp->tbuf, &cp->t, evekey);
505*219b2ee8SDavid du Colombier 	if(cp->t.num != AuthTc || strcmp(cp->t.cuid, u->p->user)){
506*219b2ee8SDavid du Colombier 		freecrypt(cp);
507*219b2ee8SDavid du Colombier 		c->aux = 0;
508*219b2ee8SDavid du Colombier 		error(Ebadarg);
509*219b2ee8SDavid du Colombier 	}
510*219b2ee8SDavid du Colombier 	if(n == TICKETLEN+4){
511*219b2ee8SDavid du Colombier 		uchar *p = (uchar *)&a[TICKETLEN];
512*219b2ee8SDavid du Colombier 		cp->a.id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
513*219b2ee8SDavid du Colombier 	}else
514*219b2ee8SDavid du Colombier 		cp->a.id = 0;
515*219b2ee8SDavid du Colombier 
516*219b2ee8SDavid du Colombier 	return n;
517*219b2ee8SDavid du Colombier }
518*219b2ee8SDavid du Colombier long
519*219b2ee8SDavid du Colombier authentread(Chan *c, char *a, int n)
520*219b2ee8SDavid du Colombier {
521*219b2ee8SDavid du Colombier 	Crypt *cp;
522*219b2ee8SDavid du Colombier 
523*219b2ee8SDavid du Colombier 	cp = c->aux;
524*219b2ee8SDavid du Colombier 	if(cp == 0)
525*219b2ee8SDavid du Colombier 		error("authenticator read must follow a write");
526*219b2ee8SDavid du Colombier 
527*219b2ee8SDavid du Colombier 	cp->a.num = AuthAc;
528*219b2ee8SDavid du Colombier 	memmove(cp->a.chal, cp->t.chal, CHALLEN);
529*219b2ee8SDavid du Colombier 	convA2M(&cp->a, cp->tbuf, cp->t.key);
530*219b2ee8SDavid du Colombier 	memmove(a, cp->tbuf, AUTHENTLEN);
531*219b2ee8SDavid du Colombier 
532*219b2ee8SDavid du Colombier 	return n;
533*219b2ee8SDavid du Colombier }
534*219b2ee8SDavid du Colombier 
535*219b2ee8SDavid du Colombier void
536*219b2ee8SDavid du Colombier authclose(Chan *c)
537*219b2ee8SDavid du Colombier {
538*219b2ee8SDavid du Colombier 	if(c->aux)
539*219b2ee8SDavid du Colombier 		freecrypt(c->aux);
540*219b2ee8SDavid du Colombier 	c->aux = 0;
541*219b2ee8SDavid du Colombier }
542*219b2ee8SDavid du Colombier 
543*219b2ee8SDavid du Colombier /*
544*219b2ee8SDavid du Colombier  *  called by devcons() for key device
545*219b2ee8SDavid du Colombier  */
546*219b2ee8SDavid du Colombier long
547*219b2ee8SDavid du Colombier keyread(char *a, int n, long offset)
548*219b2ee8SDavid du Colombier {
549*219b2ee8SDavid du Colombier 	if(n<DESKEYLEN || offset != 0)
550*219b2ee8SDavid du Colombier 		error(Ebadarg);
551*219b2ee8SDavid du Colombier 	if(!cpuserver || !iseve())
552*219b2ee8SDavid du Colombier 		error(Eperm);
553*219b2ee8SDavid du Colombier 	memmove(a, evekey, DESKEYLEN);
554*219b2ee8SDavid du Colombier 	return DESKEYLEN;
555*219b2ee8SDavid du Colombier }
556*219b2ee8SDavid du Colombier 
557*219b2ee8SDavid du Colombier long
558*219b2ee8SDavid du Colombier keywrite(char *a, int n)
559*219b2ee8SDavid du Colombier {
560*219b2ee8SDavid du Colombier 	if(n != DESKEYLEN)
561*219b2ee8SDavid du Colombier 		error(Ebadarg);
562*219b2ee8SDavid du Colombier 	if(!iseve())
563*219b2ee8SDavid du Colombier 		error(Eperm);
564*219b2ee8SDavid du Colombier 	memmove(evekey, a, DESKEYLEN);
565*219b2ee8SDavid du Colombier 	return DESKEYLEN;
566*219b2ee8SDavid du Colombier }
567*219b2ee8SDavid du Colombier 
568*219b2ee8SDavid du Colombier /*
569*219b2ee8SDavid du Colombier  *  called by devcons() for user device
570*219b2ee8SDavid du Colombier  *
571*219b2ee8SDavid du Colombier  *  anyone can become none
572*219b2ee8SDavid du Colombier  */
573*219b2ee8SDavid du Colombier long
574*219b2ee8SDavid du Colombier userwrite(char *a, int n)
575*219b2ee8SDavid du Colombier {
576*219b2ee8SDavid du Colombier 	if(n >= NAMELEN)
577*219b2ee8SDavid du Colombier 		error(Ebadarg);
578*219b2ee8SDavid du Colombier 	if(strcmp(a, "none") != 0)
579*219b2ee8SDavid du Colombier 		error(Eperm);
580*219b2ee8SDavid du Colombier 	memset(u->p->user, 0, NAMELEN);
581*219b2ee8SDavid du Colombier 	strcpy(u->p->user, "none");
582*219b2ee8SDavid du Colombier 	return n;
583*219b2ee8SDavid du Colombier }
584*219b2ee8SDavid du Colombier 
585*219b2ee8SDavid du Colombier /*
586*219b2ee8SDavid du Colombier  *  called by devcons() for host owner/domain
587*219b2ee8SDavid du Colombier  *
588*219b2ee8SDavid du Colombier  *  writing hostowner also sets user
589*219b2ee8SDavid du Colombier  */
590*219b2ee8SDavid du Colombier long
591*219b2ee8SDavid du Colombier hostownerwrite(char *a, int n)
592*219b2ee8SDavid du Colombier {
593*219b2ee8SDavid du Colombier 	char buf[NAMELEN];
594*219b2ee8SDavid du Colombier 
595*219b2ee8SDavid du Colombier 	if(!iseve())
596*219b2ee8SDavid du Colombier 		error(Eperm);
597*219b2ee8SDavid du Colombier 	if(n >= NAMELEN)
598*219b2ee8SDavid du Colombier 		error(Ebadarg);
599*219b2ee8SDavid du Colombier 	memset(buf, 0, NAMELEN);
600*219b2ee8SDavid du Colombier 	strncpy(buf, a, n);
601*219b2ee8SDavid du Colombier 	if(buf[0] == 0)
602*219b2ee8SDavid du Colombier 		error(Ebadarg);
603*219b2ee8SDavid du Colombier 	memmove(eve, buf, NAMELEN);
604*219b2ee8SDavid du Colombier 	memmove(u->p->user, buf, NAMELEN);
605*219b2ee8SDavid du Colombier 	return n;
606*219b2ee8SDavid du Colombier }
607*219b2ee8SDavid du Colombier 
608*219b2ee8SDavid du Colombier long
609*219b2ee8SDavid du Colombier hostdomainwrite(char *a, int n)
610*219b2ee8SDavid du Colombier {
611*219b2ee8SDavid du Colombier 	char buf[DOMLEN];
612*219b2ee8SDavid du Colombier 
613*219b2ee8SDavid du Colombier 	if(!iseve())
614*219b2ee8SDavid du Colombier 		error(Eperm);
615*219b2ee8SDavid du Colombier 	if(n >= DOMLEN)
616*219b2ee8SDavid du Colombier 		error(Ebadarg);
617*219b2ee8SDavid du Colombier 	memset(buf, 0, DOMLEN);
618*219b2ee8SDavid du Colombier 	strncpy(buf, a, n);
619*219b2ee8SDavid du Colombier 	if(buf[0] == 0)
620*219b2ee8SDavid du Colombier 		error(Ebadarg);
621*219b2ee8SDavid du Colombier 	memmove(hostdomain, buf, DOMLEN);
622*219b2ee8SDavid du Colombier 	return n;
623*219b2ee8SDavid du Colombier }
624*219b2ee8SDavid du Colombier 
625*219b2ee8SDavid du Colombier void
626*219b2ee8SDavid du Colombier wipekeys(void)
627*219b2ee8SDavid du Colombier {
628*219b2ee8SDavid du Colombier 	memset(evekey, 0, sizeof(evekey));
629*219b2ee8SDavid du Colombier 	memset((void*)palloc.cmembase, 0, palloc.cmemtop - palloc.cmembase);
630*219b2ee8SDavid du Colombier }
631