xref: /plan9/sys/src/cmd/unix/u9fs/authp9any.c (revision 50a9bdd425267f47e4e77489986ba84a0ae9d1f2)
1*50a9bdd4SDavid du Colombier /*
2*50a9bdd4SDavid du Colombier  * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
3*50a9bdd4SDavid du Colombier  * Nigel Roles (nigel@9fs.org) 2003
4*50a9bdd4SDavid du Colombier  */
5*50a9bdd4SDavid du Colombier 
6*50a9bdd4SDavid du Colombier #include <plan9.h>
7*50a9bdd4SDavid du Colombier #include <fcall.h>
8*50a9bdd4SDavid du Colombier #include <u9fs.h>
9*50a9bdd4SDavid du Colombier #include <stdlib.h>	/* for random stuff */
10*50a9bdd4SDavid du Colombier 
11*50a9bdd4SDavid du Colombier typedef struct	Ticket		Ticket;
12*50a9bdd4SDavid du Colombier typedef struct	Ticketreq	Ticketreq;
13*50a9bdd4SDavid du Colombier typedef struct	Authenticator	Authenticator;
14*50a9bdd4SDavid du Colombier 
15*50a9bdd4SDavid du Colombier enum
16*50a9bdd4SDavid du Colombier {
17*50a9bdd4SDavid du Colombier 	DOMLEN=		48,		/* length of an authentication domain name */
18*50a9bdd4SDavid du Colombier 	DESKEYLEN=	7,		/* length of a des key for encrypt/decrypt */
19*50a9bdd4SDavid du Colombier 	CHALLEN=	8		/* length of a challenge */
20*50a9bdd4SDavid du Colombier };
21*50a9bdd4SDavid du Colombier 
22*50a9bdd4SDavid du Colombier enum {
23*50a9bdd4SDavid du Colombier 	HaveProtos,
24*50a9bdd4SDavid du Colombier 	NeedProto,
25*50a9bdd4SDavid du Colombier 	NeedChal,
26*50a9bdd4SDavid du Colombier 	HaveTreq,
27*50a9bdd4SDavid du Colombier 	NeedTicket,
28*50a9bdd4SDavid du Colombier 	HaveAuth,
29*50a9bdd4SDavid du Colombier 	Established,
30*50a9bdd4SDavid du Colombier };
31*50a9bdd4SDavid du Colombier 
32*50a9bdd4SDavid du Colombier /* encryption numberings (anti-replay) */
33*50a9bdd4SDavid du Colombier enum
34*50a9bdd4SDavid du Colombier {
35*50a9bdd4SDavid du Colombier 	AuthTreq=1,	/* ticket request */
36*50a9bdd4SDavid du Colombier 	AuthChal=2,	/* challenge box request */
37*50a9bdd4SDavid du Colombier 	AuthPass=3,	/* change password */
38*50a9bdd4SDavid du Colombier 	AuthOK=4,	/* fixed length reply follows */
39*50a9bdd4SDavid du Colombier 	AuthErr=5,	/* error follows */
40*50a9bdd4SDavid du Colombier 	AuthMod=6,	/* modify user */
41*50a9bdd4SDavid du Colombier 	AuthApop=7,	/* apop authentication for pop3 */
42*50a9bdd4SDavid du Colombier 	AuthOKvar=9,	/* variable length reply follows */
43*50a9bdd4SDavid du Colombier 	AuthChap=10,	/* chap authentication for ppp */
44*50a9bdd4SDavid du Colombier 	AuthMSchap=11,	/* MS chap authentication for ppp */
45*50a9bdd4SDavid du Colombier 	AuthCram=12,	/* CRAM verification for IMAP (RFC2195 & rfc2104) */
46*50a9bdd4SDavid du Colombier 	AuthHttp=13,	/* http domain login */
47*50a9bdd4SDavid du Colombier 	AuthVNC=14,	/* http domain login */
48*50a9bdd4SDavid du Colombier 
49*50a9bdd4SDavid du Colombier 
50*50a9bdd4SDavid du Colombier 	AuthTs=64,	/* ticket encrypted with server's key */
51*50a9bdd4SDavid du Colombier 	AuthTc,		/* ticket encrypted with client's key */
52*50a9bdd4SDavid du Colombier 	AuthAs,		/* server generated authenticator */
53*50a9bdd4SDavid du Colombier 	AuthAc,		/* client generated authenticator */
54*50a9bdd4SDavid du Colombier 	AuthTp,		/* ticket encrypted with client's key for password change */
55*50a9bdd4SDavid du Colombier 	AuthHr		/* http reply */
56*50a9bdd4SDavid du Colombier };
57*50a9bdd4SDavid du Colombier 
58*50a9bdd4SDavid du Colombier struct Ticketreq
59*50a9bdd4SDavid du Colombier {
60*50a9bdd4SDavid du Colombier 	char	type;
61*50a9bdd4SDavid du Colombier 	char	authid[NAMELEN];	/* server's encryption id */
62*50a9bdd4SDavid du Colombier 	char	authdom[DOMLEN];	/* server's authentication domain */
63*50a9bdd4SDavid du Colombier 	char	chal[CHALLEN];		/* challenge from server */
64*50a9bdd4SDavid du Colombier 	char	hostid[NAMELEN];	/* host's encryption id */
65*50a9bdd4SDavid du Colombier 	char	uid[NAMELEN];		/* uid of requesting user on host */
66*50a9bdd4SDavid du Colombier };
67*50a9bdd4SDavid du Colombier #define	TICKREQLEN	(3*NAMELEN+CHALLEN+DOMLEN+1)
68*50a9bdd4SDavid du Colombier 
69*50a9bdd4SDavid du Colombier struct Ticket
70*50a9bdd4SDavid du Colombier {
71*50a9bdd4SDavid du Colombier 	char	num;			/* replay protection */
72*50a9bdd4SDavid du Colombier 	char	chal[CHALLEN];		/* server challenge */
73*50a9bdd4SDavid du Colombier 	char	cuid[NAMELEN];		/* uid on client */
74*50a9bdd4SDavid du Colombier 	char	suid[NAMELEN];		/* uid on server */
75*50a9bdd4SDavid du Colombier 	char	key[DESKEYLEN];		/* nonce DES key */
76*50a9bdd4SDavid du Colombier };
77*50a9bdd4SDavid du Colombier #define	TICKETLEN	(CHALLEN+2*NAMELEN+DESKEYLEN+1)
78*50a9bdd4SDavid du Colombier 
79*50a9bdd4SDavid du Colombier struct Authenticator
80*50a9bdd4SDavid du Colombier {
81*50a9bdd4SDavid du Colombier 	char	num;			/* replay protection */
82*50a9bdd4SDavid du Colombier 	char	chal[CHALLEN];
83*50a9bdd4SDavid du Colombier 	ulong	id;			/* authenticator id, ++'d with each auth */
84*50a9bdd4SDavid du Colombier };
85*50a9bdd4SDavid du Colombier #define	AUTHENTLEN	(CHALLEN+4+1)
86*50a9bdd4SDavid du Colombier 
87*50a9bdd4SDavid du Colombier static	int	convT2M(Ticket*, char*, char*);
88*50a9bdd4SDavid du Colombier static	void	convM2T(char*, Ticket*, char*);
89*50a9bdd4SDavid du Colombier static	void	convM2Tnoenc(char*, Ticket*);
90*50a9bdd4SDavid du Colombier static	int	convA2M(Authenticator*, char*, char*);
91*50a9bdd4SDavid du Colombier static	void	convM2A(char*, Authenticator*, char*);
92*50a9bdd4SDavid du Colombier static	int	convTR2M(Ticketreq*, char*);
93*50a9bdd4SDavid du Colombier static	void	convM2TR(char*, Ticketreq*);
94*50a9bdd4SDavid du Colombier static	int	passtokey(char*, char*);
95*50a9bdd4SDavid du Colombier 
96*50a9bdd4SDavid du Colombier /*
97*50a9bdd4SDavid du Colombier  *	Data Encryption Standard
98*50a9bdd4SDavid du Colombier  *	D.P.Mitchell  83/06/08.
99*50a9bdd4SDavid du Colombier  *
100*50a9bdd4SDavid du Colombier  *	block_cipher(key, block, decrypting)
101*50a9bdd4SDavid du Colombier  */
102*50a9bdd4SDavid du Colombier 
103*50a9bdd4SDavid du Colombier static	long	ip_low(char [8]);
104*50a9bdd4SDavid du Colombier static	long	ip_high(char [8]);
105*50a9bdd4SDavid du Colombier static	void	fp(long, long, char[8]);
106*50a9bdd4SDavid du Colombier static	void	key_setup(char[DESKEYLEN], char[128]);
107*50a9bdd4SDavid du Colombier static	void	block_cipher(char[128], char[8], int);
108*50a9bdd4SDavid du Colombier 
109*50a9bdd4SDavid du Colombier extern int chatty9p;
110*50a9bdd4SDavid du Colombier 
111*50a9bdd4SDavid du Colombier /*
112*50a9bdd4SDavid du Colombier  * destructively encrypt the buffer, which
113*50a9bdd4SDavid du Colombier  * must be at least 8 characters long.
114*50a9bdd4SDavid du Colombier  */
115*50a9bdd4SDavid du Colombier static int
116*50a9bdd4SDavid du Colombier encrypt9p(void *key, void *vbuf, int n)
117*50a9bdd4SDavid du Colombier {
118*50a9bdd4SDavid du Colombier 	char ekey[128], *buf;
119*50a9bdd4SDavid du Colombier 	int i, r;
120*50a9bdd4SDavid du Colombier 
121*50a9bdd4SDavid du Colombier 	if(n < 8)
122*50a9bdd4SDavid du Colombier 		return 0;
123*50a9bdd4SDavid du Colombier 	key_setup(key, ekey);
124*50a9bdd4SDavid du Colombier 	buf = vbuf;
125*50a9bdd4SDavid du Colombier 	n--;
126*50a9bdd4SDavid du Colombier 	r = n % 7;
127*50a9bdd4SDavid du Colombier 	n /= 7;
128*50a9bdd4SDavid du Colombier 	for(i = 0; i < n; i++){
129*50a9bdd4SDavid du Colombier 		block_cipher(ekey, buf, 0);
130*50a9bdd4SDavid du Colombier 		buf += 7;
131*50a9bdd4SDavid du Colombier 	}
132*50a9bdd4SDavid du Colombier 	if(r)
133*50a9bdd4SDavid du Colombier 		block_cipher(ekey, buf - 7 + r, 0);
134*50a9bdd4SDavid du Colombier 	return 1;
135*50a9bdd4SDavid du Colombier }
136*50a9bdd4SDavid du Colombier 
137*50a9bdd4SDavid du Colombier /*
138*50a9bdd4SDavid du Colombier  * destructively decrypt the buffer, which
139*50a9bdd4SDavid du Colombier  * must be at least 8 characters long.
140*50a9bdd4SDavid du Colombier  */
141*50a9bdd4SDavid du Colombier static int
142*50a9bdd4SDavid du Colombier decrypt9p(void *key, void *vbuf, int n)
143*50a9bdd4SDavid du Colombier {
144*50a9bdd4SDavid du Colombier 	char ekey[128], *buf;
145*50a9bdd4SDavid du Colombier 	int i, r;
146*50a9bdd4SDavid du Colombier 
147*50a9bdd4SDavid du Colombier 	if(n < 8)
148*50a9bdd4SDavid du Colombier 		return 0;
149*50a9bdd4SDavid du Colombier 	key_setup(key, ekey);
150*50a9bdd4SDavid du Colombier 	buf = vbuf;
151*50a9bdd4SDavid du Colombier 	n--;
152*50a9bdd4SDavid du Colombier 	r = n % 7;
153*50a9bdd4SDavid du Colombier 	n /= 7;
154*50a9bdd4SDavid du Colombier 	buf += n * 7;
155*50a9bdd4SDavid du Colombier 	if(r)
156*50a9bdd4SDavid du Colombier 		block_cipher(ekey, buf - 7 + r, 1);
157*50a9bdd4SDavid du Colombier 	for(i = 0; i < n; i++){
158*50a9bdd4SDavid du Colombier 		buf -= 7;
159*50a9bdd4SDavid du Colombier 		block_cipher(ekey, buf, 1);
160*50a9bdd4SDavid du Colombier 	}
161*50a9bdd4SDavid du Colombier 	return 1;
162*50a9bdd4SDavid du Colombier }
163*50a9bdd4SDavid du Colombier 
164*50a9bdd4SDavid du Colombier /*
165*50a9bdd4SDavid du Colombier  *	Tables for Combined S and P Boxes
166*50a9bdd4SDavid du Colombier  */
167*50a9bdd4SDavid du Colombier 
168*50a9bdd4SDavid du Colombier static long  s0p[] = {
169*50a9bdd4SDavid du Colombier 0x00410100,0x00010000,0x40400000,0x40410100,0x00400000,0x40010100,0x40010000,0x40400000,
170*50a9bdd4SDavid du Colombier 0x40010100,0x00410100,0x00410000,0x40000100,0x40400100,0x00400000,0x00000000,0x40010000,
171*50a9bdd4SDavid du Colombier 0x00010000,0x40000000,0x00400100,0x00010100,0x40410100,0x00410000,0x40000100,0x00400100,
172*50a9bdd4SDavid du Colombier 0x40000000,0x00000100,0x00010100,0x40410000,0x00000100,0x40400100,0x40410000,0x00000000,
173*50a9bdd4SDavid du Colombier 0x00000000,0x40410100,0x00400100,0x40010000,0x00410100,0x00010000,0x40000100,0x00400100,
174*50a9bdd4SDavid du Colombier 0x40410000,0x00000100,0x00010100,0x40400000,0x40010100,0x40000000,0x40400000,0x00410000,
175*50a9bdd4SDavid du Colombier 0x40410100,0x00010100,0x00410000,0x40400100,0x00400000,0x40000100,0x40010000,0x00000000,
176*50a9bdd4SDavid du Colombier 0x00010000,0x00400000,0x40400100,0x00410100,0x40000000,0x40410000,0x00000100,0x40010100,
177*50a9bdd4SDavid du Colombier };
178*50a9bdd4SDavid du Colombier 
179*50a9bdd4SDavid du Colombier static long  s1p[] = {
180*50a9bdd4SDavid du Colombier 0x08021002,0x00000000,0x00021000,0x08020000,0x08000002,0x00001002,0x08001000,0x00021000,
181*50a9bdd4SDavid du Colombier 0x00001000,0x08020002,0x00000002,0x08001000,0x00020002,0x08021000,0x08020000,0x00000002,
182*50a9bdd4SDavid du Colombier 0x00020000,0x08001002,0x08020002,0x00001000,0x00021002,0x08000000,0x00000000,0x00020002,
183*50a9bdd4SDavid du Colombier 0x08001002,0x00021002,0x08021000,0x08000002,0x08000000,0x00020000,0x00001002,0x08021002,
184*50a9bdd4SDavid du Colombier 0x00020002,0x08021000,0x08001000,0x00021002,0x08021002,0x00020002,0x08000002,0x00000000,
185*50a9bdd4SDavid du Colombier 0x08000000,0x00001002,0x00020000,0x08020002,0x00001000,0x08000000,0x00021002,0x08001002,
186*50a9bdd4SDavid du Colombier 0x08021000,0x00001000,0x00000000,0x08000002,0x00000002,0x08021002,0x00021000,0x08020000,
187*50a9bdd4SDavid du Colombier 0x08020002,0x00020000,0x00001002,0x08001000,0x08001002,0x00000002,0x08020000,0x00021000,
188*50a9bdd4SDavid du Colombier };
189*50a9bdd4SDavid du Colombier 
190*50a9bdd4SDavid du Colombier static long  s2p[] = {
191*50a9bdd4SDavid du Colombier 0x20800000,0x00808020,0x00000020,0x20800020,0x20008000,0x00800000,0x20800020,0x00008020,
192*50a9bdd4SDavid du Colombier 0x00800020,0x00008000,0x00808000,0x20000000,0x20808020,0x20000020,0x20000000,0x20808000,
193*50a9bdd4SDavid du Colombier 0x00000000,0x20008000,0x00808020,0x00000020,0x20000020,0x20808020,0x00008000,0x20800000,
194*50a9bdd4SDavid du Colombier 0x20808000,0x00800020,0x20008020,0x00808000,0x00008020,0x00000000,0x00800000,0x20008020,
195*50a9bdd4SDavid du Colombier 0x00808020,0x00000020,0x20000000,0x00008000,0x20000020,0x20008000,0x00808000,0x20800020,
196*50a9bdd4SDavid du Colombier 0x00000000,0x00808020,0x00008020,0x20808000,0x20008000,0x00800000,0x20808020,0x20000000,
197*50a9bdd4SDavid du Colombier 0x20008020,0x20800000,0x00800000,0x20808020,0x00008000,0x00800020,0x20800020,0x00008020,
198*50a9bdd4SDavid du Colombier 0x00800020,0x00000000,0x20808000,0x20000020,0x20800000,0x20008020,0x00000020,0x00808000,
199*50a9bdd4SDavid du Colombier };
200*50a9bdd4SDavid du Colombier 
201*50a9bdd4SDavid du Colombier static long  s3p[] = {
202*50a9bdd4SDavid du Colombier 0x00080201,0x02000200,0x00000001,0x02080201,0x00000000,0x02080000,0x02000201,0x00080001,
203*50a9bdd4SDavid du Colombier 0x02080200,0x02000001,0x02000000,0x00000201,0x02000001,0x00080201,0x00080000,0x02000000,
204*50a9bdd4SDavid du Colombier 0x02080001,0x00080200,0x00000200,0x00000001,0x00080200,0x02000201,0x02080000,0x00000200,
205*50a9bdd4SDavid du Colombier 0x00000201,0x00000000,0x00080001,0x02080200,0x02000200,0x02080001,0x02080201,0x00080000,
206*50a9bdd4SDavid du Colombier 0x02080001,0x00000201,0x00080000,0x02000001,0x00080200,0x02000200,0x00000001,0x02080000,
207*50a9bdd4SDavid du Colombier 0x02000201,0x00000000,0x00000200,0x00080001,0x00000000,0x02080001,0x02080200,0x00000200,
208*50a9bdd4SDavid du Colombier 0x02000000,0x02080201,0x00080201,0x00080000,0x02080201,0x00000001,0x02000200,0x00080201,
209*50a9bdd4SDavid du Colombier 0x00080001,0x00080200,0x02080000,0x02000201,0x00000201,0x02000000,0x02000001,0x02080200,
210*50a9bdd4SDavid du Colombier };
211*50a9bdd4SDavid du Colombier 
212*50a9bdd4SDavid du Colombier static long  s4p[] = {
213*50a9bdd4SDavid du Colombier 0x01000000,0x00002000,0x00000080,0x01002084,0x01002004,0x01000080,0x00002084,0x01002000,
214*50a9bdd4SDavid du Colombier 0x00002000,0x00000004,0x01000004,0x00002080,0x01000084,0x01002004,0x01002080,0x00000000,
215*50a9bdd4SDavid du Colombier 0x00002080,0x01000000,0x00002004,0x00000084,0x01000080,0x00002084,0x00000000,0x01000004,
216*50a9bdd4SDavid du Colombier 0x00000004,0x01000084,0x01002084,0x00002004,0x01002000,0x00000080,0x00000084,0x01002080,
217*50a9bdd4SDavid du Colombier 0x01002080,0x01000084,0x00002004,0x01002000,0x00002000,0x00000004,0x01000004,0x01000080,
218*50a9bdd4SDavid du Colombier 0x01000000,0x00002080,0x01002084,0x00000000,0x00002084,0x01000000,0x00000080,0x00002004,
219*50a9bdd4SDavid du Colombier 0x01000084,0x00000080,0x00000000,0x01002084,0x01002004,0x01002080,0x00000084,0x00002000,
220*50a9bdd4SDavid du Colombier 0x00002080,0x01002004,0x01000080,0x00000084,0x00000004,0x00002084,0x01002000,0x01000004,
221*50a9bdd4SDavid du Colombier };
222*50a9bdd4SDavid du Colombier 
223*50a9bdd4SDavid du Colombier static long  s5p[] = {
224*50a9bdd4SDavid du Colombier 0x10000008,0x00040008,0x00000000,0x10040400,0x00040008,0x00000400,0x10000408,0x00040000,
225*50a9bdd4SDavid du Colombier 0x00000408,0x10040408,0x00040400,0x10000000,0x10000400,0x10000008,0x10040000,0x00040408,
226*50a9bdd4SDavid du Colombier 0x00040000,0x10000408,0x10040008,0x00000000,0x00000400,0x00000008,0x10040400,0x10040008,
227*50a9bdd4SDavid du Colombier 0x10040408,0x10040000,0x10000000,0x00000408,0x00000008,0x00040400,0x00040408,0x10000400,
228*50a9bdd4SDavid du Colombier 0x00000408,0x10000000,0x10000400,0x00040408,0x10040400,0x00040008,0x00000000,0x10000400,
229*50a9bdd4SDavid du Colombier 0x10000000,0x00000400,0x10040008,0x00040000,0x00040008,0x10040408,0x00040400,0x00000008,
230*50a9bdd4SDavid du Colombier 0x10040408,0x00040400,0x00040000,0x10000408,0x10000008,0x10040000,0x00040408,0x00000000,
231*50a9bdd4SDavid du Colombier 0x00000400,0x10000008,0x10000408,0x10040400,0x10040000,0x00000408,0x00000008,0x10040008,
232*50a9bdd4SDavid du Colombier };
233*50a9bdd4SDavid du Colombier 
234*50a9bdd4SDavid du Colombier static long  s6p[] = {
235*50a9bdd4SDavid du Colombier 0x00000800,0x00000040,0x00200040,0x80200000,0x80200840,0x80000800,0x00000840,0x00000000,
236*50a9bdd4SDavid du Colombier 0x00200000,0x80200040,0x80000040,0x00200800,0x80000000,0x00200840,0x00200800,0x80000040,
237*50a9bdd4SDavid du Colombier 0x80200040,0x00000800,0x80000800,0x80200840,0x00000000,0x00200040,0x80200000,0x00000840,
238*50a9bdd4SDavid du Colombier 0x80200800,0x80000840,0x00200840,0x80000000,0x80000840,0x80200800,0x00000040,0x00200000,
239*50a9bdd4SDavid du Colombier 0x80000840,0x00200800,0x80200800,0x80000040,0x00000800,0x00000040,0x00200000,0x80200800,
240*50a9bdd4SDavid du Colombier 0x80200040,0x80000840,0x00000840,0x00000000,0x00000040,0x80200000,0x80000000,0x00200040,
241*50a9bdd4SDavid du Colombier 0x00000000,0x80200040,0x00200040,0x00000840,0x80000040,0x00000800,0x80200840,0x00200000,
242*50a9bdd4SDavid du Colombier 0x00200840,0x80000000,0x80000800,0x80200840,0x80200000,0x00200840,0x00200800,0x80000800,
243*50a9bdd4SDavid du Colombier };
244*50a9bdd4SDavid du Colombier 
245*50a9bdd4SDavid du Colombier static long  s7p[] = {
246*50a9bdd4SDavid du Colombier 0x04100010,0x04104000,0x00004010,0x00000000,0x04004000,0x00100010,0x04100000,0x04104010,
247*50a9bdd4SDavid du Colombier 0x00000010,0x04000000,0x00104000,0x00004010,0x00104010,0x04004010,0x04000010,0x04100000,
248*50a9bdd4SDavid du Colombier 0x00004000,0x00104010,0x00100010,0x04004000,0x04104010,0x04000010,0x00000000,0x00104000,
249*50a9bdd4SDavid du Colombier 0x04000000,0x00100000,0x04004010,0x04100010,0x00100000,0x00004000,0x04104000,0x00000010,
250*50a9bdd4SDavid du Colombier 0x00100000,0x00004000,0x04000010,0x04104010,0x00004010,0x04000000,0x00000000,0x00104000,
251*50a9bdd4SDavid du Colombier 0x04100010,0x04004010,0x04004000,0x00100010,0x04104000,0x00000010,0x00100010,0x04004000,
252*50a9bdd4SDavid du Colombier 0x04104010,0x00100000,0x04100000,0x04000010,0x00104000,0x00004010,0x04004010,0x04100000,
253*50a9bdd4SDavid du Colombier 0x00000010,0x04104000,0x00104010,0x00000000,0x04000000,0x04100010,0x00004000,0x00104010,
254*50a9bdd4SDavid du Colombier };
255*50a9bdd4SDavid du Colombier 
256*50a9bdd4SDavid du Colombier /*
257*50a9bdd4SDavid du Colombier  *	DES electronic codebook encryption of one block
258*50a9bdd4SDavid du Colombier  */
259*50a9bdd4SDavid du Colombier static void
260*50a9bdd4SDavid du Colombier block_cipher(char expanded_key[128], char text[8], int decrypting)
261*50a9bdd4SDavid du Colombier {
262*50a9bdd4SDavid du Colombier 	char *key;
263*50a9bdd4SDavid du Colombier 	long crypto, temp, right, left;
264*50a9bdd4SDavid du Colombier 	int i, key_offset;
265*50a9bdd4SDavid du Colombier 
266*50a9bdd4SDavid du Colombier 	key = expanded_key;
267*50a9bdd4SDavid du Colombier 	left = ip_low(text);
268*50a9bdd4SDavid du Colombier 	right = ip_high(text);
269*50a9bdd4SDavid du Colombier 	if (decrypting) {
270*50a9bdd4SDavid du Colombier 		key_offset = 16;
271*50a9bdd4SDavid du Colombier 		key = key + 128 - 8;
272*50a9bdd4SDavid du Colombier 	} else
273*50a9bdd4SDavid du Colombier 		key_offset = 0;
274*50a9bdd4SDavid du Colombier 	for (i = 0; i < 16; i++) {
275*50a9bdd4SDavid du Colombier 		temp = (right << 1) | ((right >> 31) & 1);
276*50a9bdd4SDavid du Colombier 		crypto  = s0p[(temp         & 0x3f) ^ *key++];
277*50a9bdd4SDavid du Colombier 		crypto |= s1p[((temp >>  4) & 0x3f) ^ *key++];
278*50a9bdd4SDavid du Colombier 		crypto |= s2p[((temp >>  8) & 0x3f) ^ *key++];
279*50a9bdd4SDavid du Colombier 		crypto |= s3p[((temp >> 12) & 0x3f) ^ *key++];
280*50a9bdd4SDavid du Colombier 		crypto |= s4p[((temp >> 16) & 0x3f) ^ *key++];
281*50a9bdd4SDavid du Colombier 		crypto |= s5p[((temp >> 20) & 0x3f) ^ *key++];
282*50a9bdd4SDavid du Colombier 		crypto |= s6p[((temp >> 24) & 0x3f) ^ *key++];
283*50a9bdd4SDavid du Colombier 		temp = ((right & 1) << 5) | ((right >> 27) & 0x1f);
284*50a9bdd4SDavid du Colombier 		crypto |= s7p[temp ^ *key++];
285*50a9bdd4SDavid du Colombier 		temp = left;
286*50a9bdd4SDavid du Colombier 		left = right;
287*50a9bdd4SDavid du Colombier 		right = temp ^ crypto;
288*50a9bdd4SDavid du Colombier 		key -= key_offset;
289*50a9bdd4SDavid du Colombier 	}
290*50a9bdd4SDavid du Colombier 	/*
291*50a9bdd4SDavid du Colombier 	 *	standard final permutation (IPI)
292*50a9bdd4SDavid du Colombier 	 *	left and right are reversed here
293*50a9bdd4SDavid du Colombier 	 */
294*50a9bdd4SDavid du Colombier 	fp(right, left, text);
295*50a9bdd4SDavid du Colombier }
296*50a9bdd4SDavid du Colombier 
297*50a9bdd4SDavid du Colombier /*
298*50a9bdd4SDavid du Colombier  *	Initial Permutation
299*50a9bdd4SDavid du Colombier  */
300*50a9bdd4SDavid du Colombier static long iptab[] = {
301*50a9bdd4SDavid du Colombier 	0x00000000, 0x00008000, 0x00000000, 0x00008000,
302*50a9bdd4SDavid du Colombier 	0x00000080, 0x00008080, 0x00000080, 0x00008080
303*50a9bdd4SDavid du Colombier };
304*50a9bdd4SDavid du Colombier 
305*50a9bdd4SDavid du Colombier static long
306*50a9bdd4SDavid du Colombier ip_low(char block[8])
307*50a9bdd4SDavid du Colombier {
308*50a9bdd4SDavid du Colombier 	int i;
309*50a9bdd4SDavid du Colombier 	long l;
310*50a9bdd4SDavid du Colombier 
311*50a9bdd4SDavid du Colombier 	l = 0;
312*50a9bdd4SDavid du Colombier 	for(i = 0; i < 8; i++){
313*50a9bdd4SDavid du Colombier 		l |= iptab[(block[i] >> 4) & 7] >> i;
314*50a9bdd4SDavid du Colombier 		l |= iptab[block[i] & 7] << (16 - i);
315*50a9bdd4SDavid du Colombier 	}
316*50a9bdd4SDavid du Colombier 	return l;
317*50a9bdd4SDavid du Colombier }
318*50a9bdd4SDavid du Colombier 
319*50a9bdd4SDavid du Colombier static long
320*50a9bdd4SDavid du Colombier ip_high(char block[8])
321*50a9bdd4SDavid du Colombier {
322*50a9bdd4SDavid du Colombier 	int i;
323*50a9bdd4SDavid du Colombier 	long l;
324*50a9bdd4SDavid du Colombier 
325*50a9bdd4SDavid du Colombier 	l = 0;
326*50a9bdd4SDavid du Colombier 	for(i = 0; i < 8; i++){
327*50a9bdd4SDavid du Colombier 		l |= iptab[(block[i] >> 5) & 7] >> i;
328*50a9bdd4SDavid du Colombier 		l |= iptab[(block[i] >> 1) & 7] << (16 - i);
329*50a9bdd4SDavid du Colombier 	}
330*50a9bdd4SDavid du Colombier 	return l;
331*50a9bdd4SDavid du Colombier }
332*50a9bdd4SDavid du Colombier 
333*50a9bdd4SDavid du Colombier /*
334*50a9bdd4SDavid du Colombier  *	Final Permutation
335*50a9bdd4SDavid du Colombier  */
336*50a9bdd4SDavid du Colombier static unsigned long	fptab[] = {
337*50a9bdd4SDavid du Colombier 0x00000000,0x80000000,0x00800000,0x80800000,0x00008000,0x80008000,0x00808000,0x80808000,
338*50a9bdd4SDavid du Colombier 0x00000080,0x80000080,0x00800080,0x80800080,0x00008080,0x80008080,0x00808080,0x80808080,
339*50a9bdd4SDavid du Colombier };
340*50a9bdd4SDavid du Colombier 
341*50a9bdd4SDavid du Colombier static void
342*50a9bdd4SDavid du Colombier fp(long left, long right, char text[8])
343*50a9bdd4SDavid du Colombier {
344*50a9bdd4SDavid du Colombier 	unsigned long ta[2], t, v[2];
345*50a9bdd4SDavid du Colombier 	int i, j, sh;
346*50a9bdd4SDavid du Colombier 
347*50a9bdd4SDavid du Colombier 	ta[0] = right;
348*50a9bdd4SDavid du Colombier 	ta[1] = left;
349*50a9bdd4SDavid du Colombier 	v[0] = v[1] = 0;
350*50a9bdd4SDavid du Colombier 	for(i = 0; i < 2; i++){
351*50a9bdd4SDavid du Colombier 		t = ta[i];
352*50a9bdd4SDavid du Colombier 		sh = i;
353*50a9bdd4SDavid du Colombier 		for(j = 0; j < 4; j++){
354*50a9bdd4SDavid du Colombier 			v[1] |= fptab[t & 0xf] >> sh;
355*50a9bdd4SDavid du Colombier 			t >>= 4;
356*50a9bdd4SDavid du Colombier 			v[0] |= fptab[t & 0xf] >> sh;
357*50a9bdd4SDavid du Colombier 			t >>= 4;
358*50a9bdd4SDavid du Colombier 			sh += 2;
359*50a9bdd4SDavid du Colombier 		}
360*50a9bdd4SDavid du Colombier 	}
361*50a9bdd4SDavid du Colombier 	for(i = 0; i < 2; i++)
362*50a9bdd4SDavid du Colombier 		for(j = 0; j < 4; j++){
363*50a9bdd4SDavid du Colombier 			*text++ = v[i];
364*50a9bdd4SDavid du Colombier 			v[i] >>= 8;
365*50a9bdd4SDavid du Colombier 		}
366*50a9bdd4SDavid du Colombier }
367*50a9bdd4SDavid du Colombier 
368*50a9bdd4SDavid du Colombier /*
369*50a9bdd4SDavid du Colombier  *	Key set-up
370*50a9bdd4SDavid du Colombier  */
371*50a9bdd4SDavid du Colombier static uchar keyexpand[][15][2] = {
372*50a9bdd4SDavid du Colombier 	{   3,  2,   9,  8,  18,  8,  27, 32,  33,  2,  42, 16,  48,  8,  65, 16,
373*50a9bdd4SDavid du Colombier 	   74,  2,  80,  2,  89,  4,  99, 16, 104,  4, 122, 32,   0,  0, },
374*50a9bdd4SDavid du Colombier 	{   1,  4,   8,  1,  18,  4,  25, 32,  34, 32,  41,  8,  50,  8,  59, 32,
375*50a9bdd4SDavid du Colombier 	   64, 16,  75,  4,  90,  1,  97, 16, 106,  2, 112,  2, 123,  1, },
376*50a9bdd4SDavid du Colombier 	{   2,  1,  19,  8,  35,  1,  40,  1,  50,  4,  57, 32,  75,  2,  80, 32,
377*50a9bdd4SDavid du Colombier 	   89,  1,  96, 16, 107,  4, 120,  8,   0,  0,   0,  0,   0,  0, },
378*50a9bdd4SDavid du Colombier 	{   4, 32,  20,  2,  31,  4,  37, 32,  47,  1,  54,  1,  63,  2,  68,  1,
379*50a9bdd4SDavid du Colombier 	   78,  4,  84,  8, 101, 16, 108,  4, 119, 16, 126,  8,   0,  0, },
380*50a9bdd4SDavid du Colombier 	{   5,  4,  15,  4,  21, 32,  31,  1,  38,  1,  47,  2,  53,  2,  68,  8,
381*50a9bdd4SDavid du Colombier 	   85, 16,  92,  4, 103, 16, 108, 32, 118, 32, 124,  2,   0,  0, },
382*50a9bdd4SDavid du Colombier 	{  15,  2,  21,  2,  39,  8,  46, 16,  55, 32,  61,  1,  71, 16,  76, 32,
383*50a9bdd4SDavid du Colombier 	   86, 32,  93,  4, 102,  2, 108, 16, 117,  8, 126,  1,   0,  0, },
384*50a9bdd4SDavid du Colombier 	{  14, 16,  23, 32,  29,  1,  38,  8,  52,  2,  63,  4,  70,  2,  76, 16,
385*50a9bdd4SDavid du Colombier 	   85,  8, 100,  1, 110,  4, 116,  8, 127,  8,   0,  0,   0,  0, },
386*50a9bdd4SDavid du Colombier 	{   1,  8,   8, 32,  17,  1,  24, 16,  35,  4,  50,  1,  57, 16,  67,  8,
387*50a9bdd4SDavid du Colombier 	   83,  1,  88,  1,  98,  4, 105, 32, 114, 32, 123,  2,   0,  0, },
388*50a9bdd4SDavid du Colombier 	{   0,  1,  11, 16,  16,  4,  35,  2,  40, 32,  49,  1,  56, 16,  65,  2,
389*50a9bdd4SDavid du Colombier 	   74, 16,  80,  8,  99,  8, 115,  1, 121,  4,   0,  0,   0,  0, },
390*50a9bdd4SDavid du Colombier 	{   9, 16,  18,  2,  24,  2,  33,  4,  43, 16,  48,  4,  66, 32,  73,  8,
391*50a9bdd4SDavid du Colombier 	   82,  8,  91, 32,  97,  2, 106, 16, 112,  8, 122,  1,   0,  0, },
392*50a9bdd4SDavid du Colombier 	{  14, 32,  21,  4,  30,  2,  36, 16,  45,  8,  60,  1,  69,  2,  87,  8,
393*50a9bdd4SDavid du Colombier 	   94, 16, 103, 32, 109,  1, 118,  8, 124, 32,   0,  0,   0,  0, },
394*50a9bdd4SDavid du Colombier 	{   7,  4,  14,  2,  20, 16,  29,  8,  44,  1,  54,  4,  60,  8,  71,  8,
395*50a9bdd4SDavid du Colombier 	   78, 16,  87, 32,  93,  1, 102,  8, 116,  2, 125,  4,   0,  0, },
396*50a9bdd4SDavid du Colombier 	{   7,  2,  12,  1,  22,  4,  28,  8,  45, 16,  52,  4,  63, 16,  70,  8,
397*50a9bdd4SDavid du Colombier 	   84,  2,  95,  4, 101, 32, 111,  1, 118,  1,   0,  0,   0,  0, },
398*50a9bdd4SDavid du Colombier 	{   6, 16,  13, 16,  20,  4,  31, 16,  36, 32,  46, 32,  53,  4,  62,  2,
399*50a9bdd4SDavid du Colombier 	   69, 32,  79,  1,  86,  1,  95,  2, 101,  2, 119,  8,   0,  0, },
400*50a9bdd4SDavid du Colombier 	{   0, 32,  10,  8,  19, 32,  25,  2,  34, 16,  40,  8,  59,  8,  66,  2,
401*50a9bdd4SDavid du Colombier 	   72,  2,  81,  4,  91, 16,  96,  4, 115,  2, 121,  8,   0,  0, },
402*50a9bdd4SDavid du Colombier 	{   3, 16,  10,  4,  17, 32,  26, 32,  33,  8,  42,  8,  51, 32,  57,  2,
403*50a9bdd4SDavid du Colombier 	   67,  4,  82,  1,  89, 16,  98,  2, 104,  2, 113,  4, 120,  1, },
404*50a9bdd4SDavid du Colombier 	{   1, 16,  11,  8,  27,  1,  32,  1,  42,  4,  49, 32,  58, 32,  67,  2,
405*50a9bdd4SDavid du Colombier 	   72, 32,  81,  1,  88, 16,  99,  4, 114,  1,   0,  0,   0,  0, },
406*50a9bdd4SDavid du Colombier 	{   6, 32,  12,  2,  23,  4,  29, 32,  39,  1,  46,  1,  55,  2,  61,  2,
407*50a9bdd4SDavid du Colombier 	   70,  4,  76,  8,  93, 16, 100,  4, 111, 16, 116, 32,   0,  0, },
408*50a9bdd4SDavid du Colombier 	{   6,  2,  13, 32,  23,  1,  30,  1,  39,  2,  45,  2,  63,  8,  77, 16,
409*50a9bdd4SDavid du Colombier 	   84,  4,  95, 16, 100, 32, 110, 32, 117,  4, 127,  4,   0,  0, },
410*50a9bdd4SDavid du Colombier 	{   4,  1,  13,  2,  31,  8,  38, 16,  47, 32,  53,  1,  62,  8,  68, 32,
411*50a9bdd4SDavid du Colombier 	   78, 32,  85,  4,  94,  2, 100, 16, 109,  8, 127,  2,   0,  0, },
412*50a9bdd4SDavid du Colombier 	{   5, 16,  15, 32,  21,  1,  30,  8,  44,  2,  55,  4,  61, 32,  68, 16,
413*50a9bdd4SDavid du Colombier 	   77,  8,  92,  1, 102,  4, 108,  8, 126, 16,   0,  0,   0,  0, },
414*50a9bdd4SDavid du Colombier 	{   2,  8,   9,  1,  16, 16,  27,  4,  42,  1,  49, 16,  58,  2,  75,  1,
415*50a9bdd4SDavid du Colombier 	   80,  1,  90,  4,  97, 32, 106, 32, 113,  8, 120, 32,   0,  0, },
416*50a9bdd4SDavid du Colombier 	{   2,  4,   8,  4,  27,  2,  32, 32,  41,  1,  48, 16,  59,  4,  66, 16,
417*50a9bdd4SDavid du Colombier 	   72,  8,  91,  8, 107,  1, 112,  1, 123, 16,   0,  0,   0,  0, },
418*50a9bdd4SDavid du Colombier 	{   3,  8,  10,  2,  16,  2,  25,  4,  35, 16,  40,  4,  59,  2,  65,  8,
419*50a9bdd4SDavid du Colombier 	   74,  8,  83, 32,  89,  2,  98, 16, 104,  8, 121, 16,   0,  0, },
420*50a9bdd4SDavid du Colombier 	{   4,  2,  13,  4,  22,  2,  28, 16,  37,  8,  52,  1,  62,  4,  79,  8,
421*50a9bdd4SDavid du Colombier 	   86, 16,  95, 32, 101,  1, 110,  8, 126, 32,   0,  0,   0,  0, },
422*50a9bdd4SDavid du Colombier 	{   5, 32,  12, 16,  21,  8,  36,  1,  46,  4,  52,  8,  70, 16,  79, 32,
423*50a9bdd4SDavid du Colombier 	   85,  1,  94,  8, 108,  2, 119,  4, 126,  2,   0,  0,   0,  0, },
424*50a9bdd4SDavid du Colombier 	{   5,  2,  14,  4,  20,  8,  37, 16,  44,  4,  55, 16,  60, 32,  76,  2,
425*50a9bdd4SDavid du Colombier 	   87,  4,  93, 32, 103,  1, 110,  1, 119,  2, 124,  1,   0,  0, },
426*50a9bdd4SDavid du Colombier 	{   7, 32,  12,  4,  23, 16,  28, 32,  38, 32,  45,  4,  54,  2,  60, 16,
427*50a9bdd4SDavid du Colombier 	   71,  1,  78,  1,  87,  2,  93,  2, 111,  8, 118, 16, 125, 16, },
428*50a9bdd4SDavid du Colombier 	{   1,  1,  11, 32,  17,  2,  26, 16,  32,  8,  51,  8,  64,  2,  73,  4,
429*50a9bdd4SDavid du Colombier 	   83, 16,  88,  4, 107,  2, 112, 32, 122,  8,   0,  0,   0,  0, },
430*50a9bdd4SDavid du Colombier 	{   0,  4,   9, 32,  18, 32,  25,  8,  34,  8,  43, 32,  49,  2,  58, 16,
431*50a9bdd4SDavid du Colombier 	   74,  1,  81, 16,  90,  2,  96,  2, 105,  4, 115, 16, 122,  4, },
432*50a9bdd4SDavid du Colombier 	{   2,  2,  19,  1,  24,  1,  34,  4,  41, 32,  50, 32,  57,  8,  64, 32,
433*50a9bdd4SDavid du Colombier 	   73,  1,  80, 16,  91,  4, 106,  1, 113, 16, 123,  8,   0,  0, },
434*50a9bdd4SDavid du Colombier 	{   3,  4,  10, 16,  16,  8,  35,  8,  51,  1,  56,  1,  67, 16,  72,  4,
435*50a9bdd4SDavid du Colombier 	   91,  2,  96, 32, 105,  1, 112, 16, 121,  2,   0,  0,   0,  0, },
436*50a9bdd4SDavid du Colombier 	{   4, 16,  15,  1,  22,  1,  31,  2,  37,  2,  55,  8,  62, 16,  69, 16,
437*50a9bdd4SDavid du Colombier 	   76,  4,  87, 16,  92, 32, 102, 32, 109,  4, 118,  2, 125, 32, },
438*50a9bdd4SDavid du Colombier 	{   6,  4,  23,  8,  30, 16,  39, 32,  45,  1,  54,  8,  70, 32,  77,  4,
439*50a9bdd4SDavid du Colombier 	   86,  2,  92, 16, 101,  8, 116,  1, 125,  2,   0,  0,   0,  0, },
440*50a9bdd4SDavid du Colombier 	{   4,  4,  13,  1,  22,  8,  36,  2,  47,  4,  53, 32,  63,  1,  69,  8,
441*50a9bdd4SDavid du Colombier 	   84,  1,  94,  4, 100,  8, 117, 16, 127, 32,   0,  0,   0,  0, },
442*50a9bdd4SDavid du Colombier 	{   3, 32,   8, 16,  19,  4,  34,  1,  41, 16,  50,  2,  56,  2,  67,  1,
443*50a9bdd4SDavid du Colombier 	   72,  1,  82,  4,  89, 32,  98, 32, 105,  8, 114,  8, 121,  1, },
444*50a9bdd4SDavid du Colombier 	{   1, 32,  19,  2,  24, 32,  33,  1,  40, 16,  51,  4,  64,  8,  83,  8,
445*50a9bdd4SDavid du Colombier 	   99,  1, 104,  1, 114,  4, 120,  4,   0,  0,   0,  0,   0,  0, },
446*50a9bdd4SDavid du Colombier 	{   8,  2,  17,  4,  27, 16,  32,  4,  51,  2,  56, 32,  66,  8,  75, 32,
447*50a9bdd4SDavid du Colombier 	   81,  2,  90, 16,  96,  8, 115,  8, 122,  2,   0,  0,   0,  0, },
448*50a9bdd4SDavid du Colombier 	{   2, 16,  18,  1,  25, 16,  34,  2,  40,  2,  49,  4,  59, 16,  66,  4,
449*50a9bdd4SDavid du Colombier 	   73, 32,  82, 32,  89,  8,  98,  8, 107, 32, 113,  2, 123,  4, },
450*50a9bdd4SDavid du Colombier 	{   7,  1,  13,  8,  28,  1,  38,  4,  44,  8,  61, 16,  71, 32,  77,  1,
451*50a9bdd4SDavid du Colombier 	   86,  8, 100,  2, 111,  4, 117, 32, 124, 16,   0,  0,   0,  0, },
452*50a9bdd4SDavid du Colombier 	{  12,  8,  29, 16,  36,  4,  47, 16,  52, 32,  62, 32,  68,  2,  79,  4,
453*50a9bdd4SDavid du Colombier 	   85, 32,  95,  1, 102,  1, 111,  2, 117,  2, 126,  4,   0,  0, },
454*50a9bdd4SDavid du Colombier 	{   5,  1,  15, 16,  20, 32,  30, 32,  37,  4,  46,  2,  52, 16,  61,  8,
455*50a9bdd4SDavid du Colombier 	   70,  1,  79,  2,  85,  2, 103,  8, 110, 16, 119, 32, 124,  4, },
456*50a9bdd4SDavid du Colombier 	{   0, 16,   9,  2,  18, 16,  24,  8,  43,  8,  59,  1,  65,  4,  75, 16,
457*50a9bdd4SDavid du Colombier 	   80,  4,  99,  2, 104, 32, 113,  1, 123, 32,   0,  0,   0,  0, },
458*50a9bdd4SDavid du Colombier 	{  10, 32,  17,  8,  26,  8,  35, 32,  41,  2,  50, 16,  56,  8,  66,  1,
459*50a9bdd4SDavid du Colombier 	   73, 16,  82,  2,  88,  2,  97,  4, 107, 16, 112,  4, 121, 32, },
460*50a9bdd4SDavid du Colombier 	{   0,  2,  11,  1,  16,  1,  26,  4,  33, 32,  42, 32,  49,  8,  58,  8,
461*50a9bdd4SDavid du Colombier 	   65,  1,  72, 16,  83,  4,  98,  1, 105, 16, 114,  2,   0,  0, },
462*50a9bdd4SDavid du Colombier 	{   8,  8,  27,  8,  43,  1,  48,  1,  58,  4,  64,  4,  83,  2,  88, 32,
463*50a9bdd4SDavid du Colombier 	   97,  1, 104, 16, 115,  4, 122, 16,   0,  0,   0,  0,   0,  0, },
464*50a9bdd4SDavid du Colombier 	{   5,  8,  14,  1,  23,  2,  29,  2,  47,  8,  54, 16,  63, 32,  68,  4,
465*50a9bdd4SDavid du Colombier 	   79, 16,  84, 32,  94, 32, 101,  4, 110,  2, 116, 16, 127,  1, },
466*50a9bdd4SDavid du Colombier 	{   4,  8,  15,  8,  22, 16,  31, 32,  37,  1,  46,  8,  60,  2,  69,  4,
467*50a9bdd4SDavid du Colombier 	   78,  2,  84, 16,  93,  8, 108,  1, 118,  4,   0,  0,   0,  0, },
468*50a9bdd4SDavid du Colombier 	{   7, 16,  14,  8,  28,  2,  39,  4,  45, 32,  55,  1,  62,  1,  76,  1,
469*50a9bdd4SDavid du Colombier 	   86,  4,  92,  8, 109, 16, 116,  4, 125,  1,   0,  0,   0,  0, },
470*50a9bdd4SDavid du Colombier 	{   1,  2,  11,  4,  26,  1,  33, 16,  42,  2,  48,  2,  57,  4,  64,  1,
471*50a9bdd4SDavid du Colombier 	   74,  4,  81, 32,  90, 32,  97,  8, 106,  8, 115, 32, 120, 16, },
472*50a9bdd4SDavid du Colombier 	{   2, 32,  11,  2,  16, 32,  25,  1,  32, 16,  43,  4,  58,  1,  75,  8,
473*50a9bdd4SDavid du Colombier 	   91,  1,  96,  1, 106,  4, 113, 32,   0,  0,   0,  0,   0,  0, },
474*50a9bdd4SDavid du Colombier 	{   3,  1,   9,  4,  19, 16,  24,  4,  43,  2,  48, 32,  57,  1,  67, 32,
475*50a9bdd4SDavid du Colombier 	   73,  2,  82, 16,  88,  8, 107,  8, 120,  2,   0,  0,   0,  0, },
476*50a9bdd4SDavid du Colombier 	{   0,  8,  10,  1,  17, 16,  26,  2,  32,  2,  41,  4,  51, 16,  56,  4,
477*50a9bdd4SDavid du Colombier 	   65, 32,  74, 32,  81,  8,  90,  8,  99, 32, 105,  2, 114, 16, },
478*50a9bdd4SDavid du Colombier 	{   6,  1,  20,  1,  30,  4,  36,  8,  53, 16,  60,  4,  69,  1,  78,  8,
479*50a9bdd4SDavid du Colombier 	   92,  2, 103,  4, 109, 32, 119,  1, 125,  8,   0,  0,   0,  0, },
480*50a9bdd4SDavid du Colombier 	{   7,  8,  21, 16,  28,  4,  39, 16,  44, 32,  54, 32,  61,  4,  71,  4,
481*50a9bdd4SDavid du Colombier 	   77, 32,  87,  1,  94,  1, 103,  2, 109,  2, 124,  8,   0,  0, },
482*50a9bdd4SDavid du Colombier 	{   6,  8,  12, 32,  22, 32,  29,  4,  38,  2,  44, 16,  53,  8,  71,  2,
483*50a9bdd4SDavid du Colombier 	   77,  2,  95,  8, 102, 16, 111, 32, 117,  1, 127, 16,   0,  0, }
484*50a9bdd4SDavid du Colombier };
485*50a9bdd4SDavid du Colombier 
486*50a9bdd4SDavid du Colombier static void
487*50a9bdd4SDavid du Colombier key_setup(char key[DESKEYLEN], char *ek)
488*50a9bdd4SDavid du Colombier {
489*50a9bdd4SDavid du Colombier 	int i, j, k, mask;
490*50a9bdd4SDavid du Colombier 	uchar (*x)[2];
491*50a9bdd4SDavid du Colombier 
492*50a9bdd4SDavid du Colombier 	memset(ek, 0, 128);
493*50a9bdd4SDavid du Colombier 	x = keyexpand[0];
494*50a9bdd4SDavid du Colombier 	for(i = 0; i < 7; i++){
495*50a9bdd4SDavid du Colombier 		k = key[i];
496*50a9bdd4SDavid du Colombier 		for(mask = 0x80; mask; mask >>= 1){
497*50a9bdd4SDavid du Colombier 			if(k & mask)
498*50a9bdd4SDavid du Colombier 				for(j = 0; j < 15; j++)
499*50a9bdd4SDavid du Colombier 					ek[x[j][0]] |= x[j][1];
500*50a9bdd4SDavid du Colombier 			x += 15;
501*50a9bdd4SDavid du Colombier 		}
502*50a9bdd4SDavid du Colombier 	}
503*50a9bdd4SDavid du Colombier }
504*50a9bdd4SDavid du Colombier 
505*50a9bdd4SDavid du Colombier #define	CHAR(x)		*p++ = f->x
506*50a9bdd4SDavid du Colombier #define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
507*50a9bdd4SDavid du Colombier #define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
508*50a9bdd4SDavid du Colombier #define	LONG(x)		VLONG(f->x)
509*50a9bdd4SDavid du Colombier #define	STRING(x,n)	memmove(p, f->x, n); p += n
510*50a9bdd4SDavid du Colombier 
511*50a9bdd4SDavid du Colombier static int
512*50a9bdd4SDavid du Colombier convTR2M(Ticketreq *f, char *ap)
513*50a9bdd4SDavid du Colombier {
514*50a9bdd4SDavid du Colombier 	int n;
515*50a9bdd4SDavid du Colombier 	uchar *p;
516*50a9bdd4SDavid du Colombier 
517*50a9bdd4SDavid du Colombier 	p = (uchar*)ap;
518*50a9bdd4SDavid du Colombier 	CHAR(type);
519*50a9bdd4SDavid du Colombier 	STRING(authid, NAMELEN);
520*50a9bdd4SDavid du Colombier 	STRING(authdom, DOMLEN);
521*50a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
522*50a9bdd4SDavid du Colombier 	STRING(hostid, NAMELEN);
523*50a9bdd4SDavid du Colombier 	STRING(uid, NAMELEN);
524*50a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
525*50a9bdd4SDavid du Colombier 	return n;
526*50a9bdd4SDavid du Colombier }
527*50a9bdd4SDavid du Colombier 
528*50a9bdd4SDavid du Colombier static int
529*50a9bdd4SDavid du Colombier convT2M(Ticket *f, char *ap, char *key)
530*50a9bdd4SDavid du Colombier {
531*50a9bdd4SDavid du Colombier 	int n;
532*50a9bdd4SDavid du Colombier 	uchar *p;
533*50a9bdd4SDavid du Colombier 
534*50a9bdd4SDavid du Colombier 	p = (uchar*)ap;
535*50a9bdd4SDavid du Colombier 	CHAR(num);
536*50a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
537*50a9bdd4SDavid du Colombier 	STRING(cuid, NAMELEN);
538*50a9bdd4SDavid du Colombier 	STRING(suid, NAMELEN);
539*50a9bdd4SDavid du Colombier 	STRING(key, DESKEYLEN);
540*50a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
541*50a9bdd4SDavid du Colombier 	if(key)
542*50a9bdd4SDavid du Colombier 		encrypt9p(key, ap, n);
543*50a9bdd4SDavid du Colombier 	return n;
544*50a9bdd4SDavid du Colombier }
545*50a9bdd4SDavid du Colombier 
546*50a9bdd4SDavid du Colombier int
547*50a9bdd4SDavid du Colombier convA2M(Authenticator *f, char *ap, char *key)
548*50a9bdd4SDavid du Colombier {
549*50a9bdd4SDavid du Colombier 	int n;
550*50a9bdd4SDavid du Colombier 	uchar *p;
551*50a9bdd4SDavid du Colombier 
552*50a9bdd4SDavid du Colombier 	p = (uchar*)ap;
553*50a9bdd4SDavid du Colombier 	CHAR(num);
554*50a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
555*50a9bdd4SDavid du Colombier 	LONG(id);
556*50a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
557*50a9bdd4SDavid du Colombier 	if(key)
558*50a9bdd4SDavid du Colombier 		encrypt9p(key, ap, n);
559*50a9bdd4SDavid du Colombier 	return n;
560*50a9bdd4SDavid du Colombier }
561*50a9bdd4SDavid du Colombier 
562*50a9bdd4SDavid du Colombier #undef CHAR
563*50a9bdd4SDavid du Colombier #undef SHORT
564*50a9bdd4SDavid du Colombier #undef VLONG
565*50a9bdd4SDavid du Colombier #undef LONG
566*50a9bdd4SDavid du Colombier #undef STRING
567*50a9bdd4SDavid du Colombier 
568*50a9bdd4SDavid du Colombier #define	CHAR(x)		f->x = *p++
569*50a9bdd4SDavid du Colombier #define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
570*50a9bdd4SDavid du Colombier #define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
571*50a9bdd4SDavid du Colombier #define	LONG(x)		VLONG(f->x)
572*50a9bdd4SDavid du Colombier #define	STRING(x,n)	memmove(f->x, p, n); p += n
573*50a9bdd4SDavid du Colombier 
574*50a9bdd4SDavid du Colombier void
575*50a9bdd4SDavid du Colombier convM2A(char *ap, Authenticator *f, char *key)
576*50a9bdd4SDavid du Colombier {
577*50a9bdd4SDavid du Colombier 	uchar *p;
578*50a9bdd4SDavid du Colombier 
579*50a9bdd4SDavid du Colombier 	if(key)
580*50a9bdd4SDavid du Colombier 		decrypt9p(key, ap, AUTHENTLEN);
581*50a9bdd4SDavid du Colombier 	p = (uchar*)ap;
582*50a9bdd4SDavid du Colombier 	CHAR(num);
583*50a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
584*50a9bdd4SDavid du Colombier 	LONG(id);
585*50a9bdd4SDavid du Colombier 	USED(p);
586*50a9bdd4SDavid du Colombier }
587*50a9bdd4SDavid du Colombier 
588*50a9bdd4SDavid du Colombier void
589*50a9bdd4SDavid du Colombier convM2T(char *ap, Ticket *f, char *key)
590*50a9bdd4SDavid du Colombier {
591*50a9bdd4SDavid du Colombier 	uchar *p;
592*50a9bdd4SDavid du Colombier 
593*50a9bdd4SDavid du Colombier 	if(key)
594*50a9bdd4SDavid du Colombier 		decrypt9p(key, ap, TICKETLEN);
595*50a9bdd4SDavid du Colombier 	p = (uchar*)ap;
596*50a9bdd4SDavid du Colombier 	CHAR(num);
597*50a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
598*50a9bdd4SDavid du Colombier 	STRING(cuid, NAMELEN);
599*50a9bdd4SDavid du Colombier 	f->cuid[NAMELEN-1] = 0;
600*50a9bdd4SDavid du Colombier 	STRING(suid, NAMELEN);
601*50a9bdd4SDavid du Colombier 	f->suid[NAMELEN-1] = 0;
602*50a9bdd4SDavid du Colombier 	STRING(key, DESKEYLEN);
603*50a9bdd4SDavid du Colombier 	USED(p);
604*50a9bdd4SDavid du Colombier }
605*50a9bdd4SDavid du Colombier 
606*50a9bdd4SDavid du Colombier #undef CHAR
607*50a9bdd4SDavid du Colombier #undef SHORT
608*50a9bdd4SDavid du Colombier #undef LONG
609*50a9bdd4SDavid du Colombier #undef VLONG
610*50a9bdd4SDavid du Colombier #undef STRING
611*50a9bdd4SDavid du Colombier 
612*50a9bdd4SDavid du Colombier static int
613*50a9bdd4SDavid du Colombier passtokey(char *key, char *p)
614*50a9bdd4SDavid du Colombier {
615*50a9bdd4SDavid du Colombier 	uchar buf[NAMELEN], *t;
616*50a9bdd4SDavid du Colombier 	int i, n;
617*50a9bdd4SDavid du Colombier 
618*50a9bdd4SDavid du Colombier 	n = strlen(p);
619*50a9bdd4SDavid du Colombier 	if(n >= NAMELEN)
620*50a9bdd4SDavid du Colombier 		n = NAMELEN-1;
621*50a9bdd4SDavid du Colombier 	memset(buf, ' ', 8);
622*50a9bdd4SDavid du Colombier 	t = buf;
623*50a9bdd4SDavid du Colombier 	strncpy((char*)t, p, n);
624*50a9bdd4SDavid du Colombier 	t[n] = 0;
625*50a9bdd4SDavid du Colombier 	memset(key, 0, DESKEYLEN);
626*50a9bdd4SDavid du Colombier 	for(;;){
627*50a9bdd4SDavid du Colombier 		for(i = 0; i < DESKEYLEN; i++)
628*50a9bdd4SDavid du Colombier 			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
629*50a9bdd4SDavid du Colombier 		if(n <= 8)
630*50a9bdd4SDavid du Colombier 			return 1;
631*50a9bdd4SDavid du Colombier 		n -= 8;
632*50a9bdd4SDavid du Colombier 		t += 8;
633*50a9bdd4SDavid du Colombier 		if(n < 8){
634*50a9bdd4SDavid du Colombier 			t -= 8 - n;
635*50a9bdd4SDavid du Colombier 			n = 8;
636*50a9bdd4SDavid du Colombier 		}
637*50a9bdd4SDavid du Colombier 		encrypt9p(key, t, 8);
638*50a9bdd4SDavid du Colombier 	}
639*50a9bdd4SDavid du Colombier 	return 1;	/* not reached */
640*50a9bdd4SDavid du Colombier }
641*50a9bdd4SDavid du Colombier 
642*50a9bdd4SDavid du Colombier static char authkey[DESKEYLEN];
643*50a9bdd4SDavid du Colombier static char *authid;
644*50a9bdd4SDavid du Colombier static char *authdom;
645*50a9bdd4SDavid du Colombier static char *haveprotosmsg;
646*50a9bdd4SDavid du Colombier static char *needprotomsg;
647*50a9bdd4SDavid du Colombier 
648*50a9bdd4SDavid du Colombier static void
649*50a9bdd4SDavid du Colombier p9anyinit(void)
650*50a9bdd4SDavid du Colombier {
651*50a9bdd4SDavid du Colombier 	int n, fd;
652*50a9bdd4SDavid du Colombier 	char abuf[200];
653*50a9bdd4SDavid du Colombier 	char *af, *f[4];
654*50a9bdd4SDavid du Colombier 
655*50a9bdd4SDavid du Colombier 	af = autharg;
656*50a9bdd4SDavid du Colombier 	if(af == nil)
657*50a9bdd4SDavid du Colombier 		af = "/etc/u9fs.key";
658*50a9bdd4SDavid du Colombier 
659*50a9bdd4SDavid du Colombier 	if((fd = open(af, OREAD)) < 0)
660*50a9bdd4SDavid du Colombier 		sysfatal("can't open key file '%s'", af);
661*50a9bdd4SDavid du Colombier 
662*50a9bdd4SDavid du Colombier 	if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
663*50a9bdd4SDavid du Colombier 		sysfatal("can't read key file '%s'", af);
664*50a9bdd4SDavid du Colombier 	if (n > 0 && abuf[n - 1] == '\n')
665*50a9bdd4SDavid du Colombier 		n--;
666*50a9bdd4SDavid du Colombier 	abuf[n] = '\0';
667*50a9bdd4SDavid du Colombier 
668*50a9bdd4SDavid du Colombier 	if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
669*50a9bdd4SDavid du Colombier 		sysfatal("key file '%s' not exactly 3 lines", af);
670*50a9bdd4SDavid du Colombier 
671*50a9bdd4SDavid du Colombier 	passtokey(authkey, f[0]);
672*50a9bdd4SDavid du Colombier 	authid = strdup(f[1]);
673*50a9bdd4SDavid du Colombier 	authdom = strdup(f[2]);
674*50a9bdd4SDavid du Colombier 	haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
675*50a9bdd4SDavid du Colombier 	sprint(haveprotosmsg, "p9sk1@%s", authdom);
676*50a9bdd4SDavid du Colombier 	needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
677*50a9bdd4SDavid du Colombier 	sprint(needprotomsg, "p9sk1 %s", authdom);
678*50a9bdd4SDavid du Colombier }
679*50a9bdd4SDavid du Colombier 
680*50a9bdd4SDavid du Colombier typedef struct AuthSession {
681*50a9bdd4SDavid du Colombier 	int state;
682*50a9bdd4SDavid du Colombier 	char *uname;
683*50a9bdd4SDavid du Colombier 	char *aname;
684*50a9bdd4SDavid du Colombier 	char cchal[CHALLEN];
685*50a9bdd4SDavid du Colombier 	Ticketreq tr;
686*50a9bdd4SDavid du Colombier 	Ticket t;
687*50a9bdd4SDavid du Colombier } AuthSession;
688*50a9bdd4SDavid du Colombier 
689*50a9bdd4SDavid du Colombier static char*
690*50a9bdd4SDavid du Colombier p9anyauth(Fcall *rx, Fcall *tx)
691*50a9bdd4SDavid du Colombier {
692*50a9bdd4SDavid du Colombier 	AuthSession *sp;
693*50a9bdd4SDavid du Colombier 	int result;
694*50a9bdd4SDavid du Colombier 	Fid *f;
695*50a9bdd4SDavid du Colombier 	char *ep;
696*50a9bdd4SDavid du Colombier 
697*50a9bdd4SDavid du Colombier 	sp = malloc(sizeof(AuthSession));
698*50a9bdd4SDavid du Colombier 	f = newauthfid(rx->afid, sp, &ep);
699*50a9bdd4SDavid du Colombier 	if (f == nil) {
700*50a9bdd4SDavid du Colombier 		free(sp);
701*50a9bdd4SDavid du Colombier 		return ep;
702*50a9bdd4SDavid du Colombier 	}
703*50a9bdd4SDavid du Colombier 	if (chatty9p)
704*50a9bdd4SDavid du Colombier 		fprint(2, "p9anyauth: afid %d\n", rx->afid);
705*50a9bdd4SDavid du Colombier 	sp->state = HaveProtos;
706*50a9bdd4SDavid du Colombier 	sp->uname = strdup(rx->uname);
707*50a9bdd4SDavid du Colombier 	sp->aname = strdup(rx->aname);
708*50a9bdd4SDavid du Colombier 	tx->aqid.type = QTAUTH;
709*50a9bdd4SDavid du Colombier 	tx->aqid.path = 1;
710*50a9bdd4SDavid du Colombier 	tx->aqid.vers = 0;
711*50a9bdd4SDavid du Colombier 	return nil;
712*50a9bdd4SDavid du Colombier }
713*50a9bdd4SDavid du Colombier 
714*50a9bdd4SDavid du Colombier static char *
715*50a9bdd4SDavid du Colombier p9anyattach(Fcall *rx, Fcall *tx)
716*50a9bdd4SDavid du Colombier {
717*50a9bdd4SDavid du Colombier 	AuthSession *sp;
718*50a9bdd4SDavid du Colombier 	Fid *f;
719*50a9bdd4SDavid du Colombier 	char *ep;
720*50a9bdd4SDavid du Colombier 
721*50a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
722*50a9bdd4SDavid du Colombier 	if (f == nil)
723*50a9bdd4SDavid du Colombier 		return ep;
724*50a9bdd4SDavid du Colombier 	if (chatty9p)
725*50a9bdd4SDavid du Colombier 		fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
726*50a9bdd4SDavid du Colombier 	if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
727*50a9bdd4SDavid du Colombier 		&& strcmp(rx->aname, sp->aname) == 0)
728*50a9bdd4SDavid du Colombier 		return nil;
729*50a9bdd4SDavid du Colombier 	return "authentication failed";
730*50a9bdd4SDavid du Colombier }
731*50a9bdd4SDavid du Colombier 
732*50a9bdd4SDavid du Colombier static int
733*50a9bdd4SDavid du Colombier readstr(Fcall *rx, Fcall *tx, char *s, int len)
734*50a9bdd4SDavid du Colombier {
735*50a9bdd4SDavid du Colombier 	if (rx->offset >= len)
736*50a9bdd4SDavid du Colombier 		return 0;
737*50a9bdd4SDavid du Colombier 	tx->count = len - rx->offset;
738*50a9bdd4SDavid du Colombier 	if (tx->count > rx->count)
739*50a9bdd4SDavid du Colombier 		tx->count = rx->count;
740*50a9bdd4SDavid du Colombier 	memcpy(tx->data, s + rx->offset, tx->count);
741*50a9bdd4SDavid du Colombier 	return tx->count;
742*50a9bdd4SDavid du Colombier }
743*50a9bdd4SDavid du Colombier 
744*50a9bdd4SDavid du Colombier static char *
745*50a9bdd4SDavid du Colombier p9anyread(Fcall *rx, Fcall *tx)
746*50a9bdd4SDavid du Colombier {
747*50a9bdd4SDavid du Colombier 	AuthSession *sp;
748*50a9bdd4SDavid du Colombier 	char *ep;
749*50a9bdd4SDavid du Colombier 	char buf[100];
750*50a9bdd4SDavid du Colombier 
751*50a9bdd4SDavid du Colombier 	Fid *f;
752*50a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
753*50a9bdd4SDavid du Colombier 	if (f == nil)
754*50a9bdd4SDavid du Colombier 		return ep;
755*50a9bdd4SDavid du Colombier 	if (chatty9p)
756*50a9bdd4SDavid du Colombier 		fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
757*50a9bdd4SDavid du Colombier 	switch (sp->state) {
758*50a9bdd4SDavid du Colombier 	case HaveProtos:
759*50a9bdd4SDavid du Colombier 		readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
760*50a9bdd4SDavid du Colombier 		if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
761*50a9bdd4SDavid du Colombier 			sp->state = NeedProto;
762*50a9bdd4SDavid du Colombier 		return nil;
763*50a9bdd4SDavid du Colombier 	case HaveTreq:
764*50a9bdd4SDavid du Colombier 		if (rx->count != TICKREQLEN)
765*50a9bdd4SDavid du Colombier 			goto botch;
766*50a9bdd4SDavid du Colombier 		convTR2M(&sp->tr, tx->data);
767*50a9bdd4SDavid du Colombier 		tx->count = TICKREQLEN;
768*50a9bdd4SDavid du Colombier 		sp->state = NeedTicket;
769*50a9bdd4SDavid du Colombier 		return nil;
770*50a9bdd4SDavid du Colombier 	case HaveAuth: {
771*50a9bdd4SDavid du Colombier 		Authenticator a;
772*50a9bdd4SDavid du Colombier 		if (rx->count != AUTHENTLEN)
773*50a9bdd4SDavid du Colombier 			goto botch;
774*50a9bdd4SDavid du Colombier 		a.num = AuthAs;
775*50a9bdd4SDavid du Colombier 		memmove(a.chal, sp->cchal, CHALLEN);
776*50a9bdd4SDavid du Colombier 		a.id = 0;
777*50a9bdd4SDavid du Colombier 		convA2M(&a, (char*)tx->data, sp->t.key);
778*50a9bdd4SDavid du Colombier 		memset(sp->t.key, 0, sizeof(sp->t.key));
779*50a9bdd4SDavid du Colombier 		tx->count = rx->count;
780*50a9bdd4SDavid du Colombier 		sp->state = Established;
781*50a9bdd4SDavid du Colombier 		return nil;
782*50a9bdd4SDavid du Colombier 	}
783*50a9bdd4SDavid du Colombier 	default:
784*50a9bdd4SDavid du Colombier 	botch:
785*50a9bdd4SDavid du Colombier 		return "protocol botch";
786*50a9bdd4SDavid du Colombier 	}
787*50a9bdd4SDavid du Colombier }
788*50a9bdd4SDavid du Colombier 
789*50a9bdd4SDavid du Colombier static char *
790*50a9bdd4SDavid du Colombier p9anywrite(Fcall *rx, Fcall *tx)
791*50a9bdd4SDavid du Colombier {
792*50a9bdd4SDavid du Colombier 	AuthSession *sp;
793*50a9bdd4SDavid du Colombier 	char *ep;
794*50a9bdd4SDavid du Colombier 
795*50a9bdd4SDavid du Colombier 	Fid *f;
796*50a9bdd4SDavid du Colombier 
797*50a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
798*50a9bdd4SDavid du Colombier 	if (f == nil)
799*50a9bdd4SDavid du Colombier 		return ep;
800*50a9bdd4SDavid du Colombier 	if (chatty9p)
801*50a9bdd4SDavid du Colombier 		fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
802*50a9bdd4SDavid du Colombier 	switch (sp->state) {
803*50a9bdd4SDavid du Colombier 	case NeedProto:
804*50a9bdd4SDavid du Colombier 		if (rx->count != strlen(needprotomsg) + 1)
805*50a9bdd4SDavid du Colombier 			return "protocol response wrong length";
806*50a9bdd4SDavid du Colombier 		if (memcmp(rx->data, needprotomsg, rx->count) != 0)
807*50a9bdd4SDavid du Colombier 			return "unacceptable protocol";
808*50a9bdd4SDavid du Colombier 		sp->state = NeedChal;
809*50a9bdd4SDavid du Colombier 		tx->count = rx->count;
810*50a9bdd4SDavid du Colombier 		return nil;
811*50a9bdd4SDavid du Colombier 	case NeedChal:
812*50a9bdd4SDavid du Colombier 		if (rx->count != CHALLEN)
813*50a9bdd4SDavid du Colombier 			goto botch;
814*50a9bdd4SDavid du Colombier 		memmove(sp->cchal, rx->data, CHALLEN);
815*50a9bdd4SDavid du Colombier 		sp->tr.type = AuthTreq;
816*50a9bdd4SDavid du Colombier 		safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
817*50a9bdd4SDavid du Colombier 		safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
818*50a9bdd4SDavid du Colombier 		randombytes((uchar *)sp->tr.chal, CHALLEN);
819*50a9bdd4SDavid du Colombier 		safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
820*50a9bdd4SDavid du Colombier 		safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
821*50a9bdd4SDavid du Colombier 		tx->count = rx->count;
822*50a9bdd4SDavid du Colombier 		sp->state = HaveTreq;
823*50a9bdd4SDavid du Colombier 		return nil;
824*50a9bdd4SDavid du Colombier 	case NeedTicket: {
825*50a9bdd4SDavid du Colombier 		Authenticator a;
826*50a9bdd4SDavid du Colombier 
827*50a9bdd4SDavid du Colombier 		if (rx->count != TICKETLEN + AUTHENTLEN) {
828*50a9bdd4SDavid du Colombier 			fprint(2, "bad length in attach");
829*50a9bdd4SDavid du Colombier 			goto botch;
830*50a9bdd4SDavid du Colombier 		}
831*50a9bdd4SDavid du Colombier 		convM2T((char*)rx->data, &sp->t, authkey);
832*50a9bdd4SDavid du Colombier 		if (sp->t.num != AuthTs) {
833*50a9bdd4SDavid du Colombier 			fprint(2, "bad AuthTs in attach\n");
834*50a9bdd4SDavid du Colombier 			goto botch;
835*50a9bdd4SDavid du Colombier 		}
836*50a9bdd4SDavid du Colombier 		if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
837*50a9bdd4SDavid du Colombier 			fprint(2, "bad challenge in attach\n");
838*50a9bdd4SDavid du Colombier 			goto botch;
839*50a9bdd4SDavid du Colombier 		}
840*50a9bdd4SDavid du Colombier 		convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
841*50a9bdd4SDavid du Colombier 		if (a.num != AuthAc) {
842*50a9bdd4SDavid du Colombier 			fprint(2, "bad AuthAs in attach\n");
843*50a9bdd4SDavid du Colombier 			goto botch;
844*50a9bdd4SDavid du Colombier 		}
845*50a9bdd4SDavid du Colombier 		if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
846*50a9bdd4SDavid du Colombier 			fprint(2, "bad challenge in attach 2\n");
847*50a9bdd4SDavid du Colombier 			goto botch;
848*50a9bdd4SDavid du Colombier 		}
849*50a9bdd4SDavid du Colombier 		sp->state = HaveAuth;
850*50a9bdd4SDavid du Colombier 		tx->count = rx->count;
851*50a9bdd4SDavid du Colombier 		return nil;
852*50a9bdd4SDavid du Colombier 	}
853*50a9bdd4SDavid du Colombier 	default:
854*50a9bdd4SDavid du Colombier 	botch:
855*50a9bdd4SDavid du Colombier 		return "protocol botch";
856*50a9bdd4SDavid du Colombier 	}
857*50a9bdd4SDavid du Colombier }
858*50a9bdd4SDavid du Colombier 
859*50a9bdd4SDavid du Colombier static void
860*50a9bdd4SDavid du Colombier safefree(char *p)
861*50a9bdd4SDavid du Colombier {
862*50a9bdd4SDavid du Colombier 	if (p) {
863*50a9bdd4SDavid du Colombier 		memset(p, 0, strlen(p));
864*50a9bdd4SDavid du Colombier 		free(p);
865*50a9bdd4SDavid du Colombier 	}
866*50a9bdd4SDavid du Colombier }
867*50a9bdd4SDavid du Colombier 
868*50a9bdd4SDavid du Colombier static char *
869*50a9bdd4SDavid du Colombier p9anyclunk(Fcall *rx, Fcall *tx)
870*50a9bdd4SDavid du Colombier {
871*50a9bdd4SDavid du Colombier 	Fid *f;
872*50a9bdd4SDavid du Colombier 	AuthSession *sp;
873*50a9bdd4SDavid du Colombier 	char *ep;
874*50a9bdd4SDavid du Colombier 
875*50a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
876*50a9bdd4SDavid du Colombier 	if (f == nil)
877*50a9bdd4SDavid du Colombier 		return ep;
878*50a9bdd4SDavid du Colombier 	if (chatty9p)
879*50a9bdd4SDavid du Colombier 		fprint(2, "p9anyclunk: afid %d\n", rx->fid);
880*50a9bdd4SDavid du Colombier 	safefree(sp->uname);
881*50a9bdd4SDavid du Colombier 	safefree(sp->aname);
882*50a9bdd4SDavid du Colombier 	memset(sp, 0, sizeof(sp));
883*50a9bdd4SDavid du Colombier 	free(sp);
884*50a9bdd4SDavid du Colombier 	return nil;
885*50a9bdd4SDavid du Colombier }
886*50a9bdd4SDavid du Colombier 
887*50a9bdd4SDavid du Colombier Auth authp9any = {
888*50a9bdd4SDavid du Colombier 	"p9any",
889*50a9bdd4SDavid du Colombier 	p9anyauth,
890*50a9bdd4SDavid du Colombier 	p9anyattach,
891*50a9bdd4SDavid du Colombier 	p9anyinit,
892*50a9bdd4SDavid du Colombier 	p9anyread,
893*50a9bdd4SDavid du Colombier 	p9anywrite,
894*50a9bdd4SDavid du Colombier 	p9anyclunk,
895*50a9bdd4SDavid du Colombier };
896