xref: /plan9/sys/src/cmd/unix/u9fs/authp9any.c (revision 031ba9d16a307751d9a4418aa220a672cebb5430)
150a9bdd4SDavid du Colombier /*
250a9bdd4SDavid du Colombier  * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
350a9bdd4SDavid du Colombier  * Nigel Roles (nigel@9fs.org) 2003
450a9bdd4SDavid du Colombier  */
550a9bdd4SDavid du Colombier 
650a9bdd4SDavid du Colombier #include <plan9.h>
750a9bdd4SDavid du Colombier #include <fcall.h>
850a9bdd4SDavid du Colombier #include <u9fs.h>
950a9bdd4SDavid du Colombier #include <stdlib.h>	/* for random stuff */
1050a9bdd4SDavid du Colombier 
1150a9bdd4SDavid du Colombier typedef struct	Ticket		Ticket;
1250a9bdd4SDavid du Colombier typedef struct	Ticketreq	Ticketreq;
1350a9bdd4SDavid du Colombier typedef struct	Authenticator	Authenticator;
1450a9bdd4SDavid du Colombier 
1550a9bdd4SDavid du Colombier enum
1650a9bdd4SDavid du Colombier {
1750a9bdd4SDavid du Colombier 	DOMLEN=		48,		/* length of an authentication domain name */
1850a9bdd4SDavid du Colombier 	CHALLEN=	8		/* length of a challenge */
1950a9bdd4SDavid du Colombier };
2050a9bdd4SDavid du Colombier 
2150a9bdd4SDavid du Colombier enum {
2250a9bdd4SDavid du Colombier 	HaveProtos,
2350a9bdd4SDavid du Colombier 	NeedProto,
2450a9bdd4SDavid du Colombier 	NeedChal,
2550a9bdd4SDavid du Colombier 	HaveTreq,
2650a9bdd4SDavid du Colombier 	NeedTicket,
2750a9bdd4SDavid du Colombier 	HaveAuth,
2850a9bdd4SDavid du Colombier 	Established,
2950a9bdd4SDavid du Colombier };
3050a9bdd4SDavid du Colombier 
3150a9bdd4SDavid du Colombier /* encryption numberings (anti-replay) */
3250a9bdd4SDavid du Colombier enum
3350a9bdd4SDavid du Colombier {
3450a9bdd4SDavid du Colombier 	AuthTreq=1,	/* ticket request */
3550a9bdd4SDavid du Colombier 	AuthChal=2,	/* challenge box request */
3650a9bdd4SDavid du Colombier 	AuthPass=3,	/* change password */
3750a9bdd4SDavid du Colombier 	AuthOK=4,	/* fixed length reply follows */
3850a9bdd4SDavid du Colombier 	AuthErr=5,	/* error follows */
3950a9bdd4SDavid du Colombier 	AuthMod=6,	/* modify user */
4050a9bdd4SDavid du Colombier 	AuthApop=7,	/* apop authentication for pop3 */
4150a9bdd4SDavid du Colombier 	AuthOKvar=9,	/* variable length reply follows */
4250a9bdd4SDavid du Colombier 	AuthChap=10,	/* chap authentication for ppp */
4350a9bdd4SDavid du Colombier 	AuthMSchap=11,	/* MS chap authentication for ppp */
4450a9bdd4SDavid du Colombier 	AuthCram=12,	/* CRAM verification for IMAP (RFC2195 & rfc2104) */
4550a9bdd4SDavid du Colombier 	AuthHttp=13,	/* http domain login */
4650a9bdd4SDavid du Colombier 	AuthVNC=14,	/* http domain login */
4750a9bdd4SDavid du Colombier 
4850a9bdd4SDavid du Colombier 
4950a9bdd4SDavid du Colombier 	AuthTs=64,	/* ticket encrypted with server's key */
5050a9bdd4SDavid du Colombier 	AuthTc,		/* ticket encrypted with client's key */
5150a9bdd4SDavid du Colombier 	AuthAs,		/* server generated authenticator */
5250a9bdd4SDavid du Colombier 	AuthAc,		/* client generated authenticator */
5350a9bdd4SDavid du Colombier 	AuthTp,		/* ticket encrypted with client's key for password change */
5450a9bdd4SDavid du Colombier 	AuthHr		/* http reply */
5550a9bdd4SDavid du Colombier };
5650a9bdd4SDavid du Colombier 
5750a9bdd4SDavid du Colombier struct Ticketreq
5850a9bdd4SDavid du Colombier {
5950a9bdd4SDavid du Colombier 	char	type;
6050a9bdd4SDavid du Colombier 	char	authid[NAMELEN];	/* server's encryption id */
6150a9bdd4SDavid du Colombier 	char	authdom[DOMLEN];	/* server's authentication domain */
6250a9bdd4SDavid du Colombier 	char	chal[CHALLEN];		/* challenge from server */
6350a9bdd4SDavid du Colombier 	char	hostid[NAMELEN];	/* host's encryption id */
6450a9bdd4SDavid du Colombier 	char	uid[NAMELEN];		/* uid of requesting user on host */
6550a9bdd4SDavid du Colombier };
6650a9bdd4SDavid du Colombier #define	TICKREQLEN	(3*NAMELEN+CHALLEN+DOMLEN+1)
6750a9bdd4SDavid du Colombier 
6850a9bdd4SDavid du Colombier struct Ticket
6950a9bdd4SDavid du Colombier {
7050a9bdd4SDavid du Colombier 	char	num;			/* replay protection */
7150a9bdd4SDavid du Colombier 	char	chal[CHALLEN];		/* server challenge */
7250a9bdd4SDavid du Colombier 	char	cuid[NAMELEN];		/* uid on client */
7350a9bdd4SDavid du Colombier 	char	suid[NAMELEN];		/* uid on server */
7450a9bdd4SDavid du Colombier 	char	key[DESKEYLEN];		/* nonce DES key */
7550a9bdd4SDavid du Colombier };
7650a9bdd4SDavid du Colombier #define	TICKETLEN	(CHALLEN+2*NAMELEN+DESKEYLEN+1)
7750a9bdd4SDavid du Colombier 
7850a9bdd4SDavid du Colombier struct Authenticator
7950a9bdd4SDavid du Colombier {
8050a9bdd4SDavid du Colombier 	char	num;			/* replay protection */
8150a9bdd4SDavid du Colombier 	char	chal[CHALLEN];
8250a9bdd4SDavid du Colombier 	ulong	id;			/* authenticator id, ++'d with each auth */
8350a9bdd4SDavid du Colombier };
8450a9bdd4SDavid du Colombier #define	AUTHENTLEN	(CHALLEN+4+1)
8550a9bdd4SDavid du Colombier 
86*63dc73a9SDavid du Colombier extern int chatty9p;
87*63dc73a9SDavid du Colombier 
8850a9bdd4SDavid du Colombier static	int	convT2M(Ticket*, char*, char*);
8950a9bdd4SDavid du Colombier static	void	convM2T(char*, Ticket*, char*);
9050a9bdd4SDavid du Colombier static	void	convM2Tnoenc(char*, Ticket*);
9150a9bdd4SDavid du Colombier static	int	convA2M(Authenticator*, char*, char*);
9250a9bdd4SDavid du Colombier static	void	convM2A(char*, Authenticator*, char*);
9350a9bdd4SDavid du Colombier static	int	convTR2M(Ticketreq*, char*);
9450a9bdd4SDavid du Colombier static	void	convM2TR(char*, Ticketreq*);
9550a9bdd4SDavid du Colombier static	int	passtokey(char*, char*);
9650a9bdd4SDavid du Colombier 
9750a9bdd4SDavid du Colombier /*
9850a9bdd4SDavid du Colombier  * destructively encrypt the buffer, which
9950a9bdd4SDavid du Colombier  * must be at least 8 characters long.
10050a9bdd4SDavid du Colombier  */
10150a9bdd4SDavid du Colombier static int
encrypt9p(void * key,void * vbuf,int n)10250a9bdd4SDavid du Colombier encrypt9p(void *key, void *vbuf, int n)
10350a9bdd4SDavid du Colombier {
10450a9bdd4SDavid du Colombier 	char ekey[128], *buf;
10550a9bdd4SDavid du Colombier 	int i, r;
10650a9bdd4SDavid du Colombier 
10750a9bdd4SDavid du Colombier 	if(n < 8)
10850a9bdd4SDavid du Colombier 		return 0;
10950a9bdd4SDavid du Colombier 	key_setup(key, ekey);
11050a9bdd4SDavid du Colombier 	buf = vbuf;
11150a9bdd4SDavid du Colombier 	n--;
11250a9bdd4SDavid du Colombier 	r = n % 7;
11350a9bdd4SDavid du Colombier 	n /= 7;
11450a9bdd4SDavid du Colombier 	for(i = 0; i < n; i++){
11550a9bdd4SDavid du Colombier 		block_cipher(ekey, buf, 0);
11650a9bdd4SDavid du Colombier 		buf += 7;
11750a9bdd4SDavid du Colombier 	}
11850a9bdd4SDavid du Colombier 	if(r)
11950a9bdd4SDavid du Colombier 		block_cipher(ekey, buf - 7 + r, 0);
12050a9bdd4SDavid du Colombier 	return 1;
12150a9bdd4SDavid du Colombier }
12250a9bdd4SDavid du Colombier 
12350a9bdd4SDavid du Colombier /*
12450a9bdd4SDavid du Colombier  * destructively decrypt the buffer, which
12550a9bdd4SDavid du Colombier  * must be at least 8 characters long.
12650a9bdd4SDavid du Colombier  */
12750a9bdd4SDavid du Colombier static int
decrypt9p(void * key,void * vbuf,int n)12850a9bdd4SDavid du Colombier decrypt9p(void *key, void *vbuf, int n)
12950a9bdd4SDavid du Colombier {
13050a9bdd4SDavid du Colombier 	char ekey[128], *buf;
13150a9bdd4SDavid du Colombier 	int i, r;
13250a9bdd4SDavid du Colombier 
13350a9bdd4SDavid du Colombier 	if(n < 8)
13450a9bdd4SDavid du Colombier 		return 0;
13550a9bdd4SDavid du Colombier 	key_setup(key, ekey);
13650a9bdd4SDavid du Colombier 	buf = vbuf;
13750a9bdd4SDavid du Colombier 	n--;
13850a9bdd4SDavid du Colombier 	r = n % 7;
13950a9bdd4SDavid du Colombier 	n /= 7;
14050a9bdd4SDavid du Colombier 	buf += n * 7;
14150a9bdd4SDavid du Colombier 	if(r)
14250a9bdd4SDavid du Colombier 		block_cipher(ekey, buf - 7 + r, 1);
14350a9bdd4SDavid du Colombier 	for(i = 0; i < n; i++){
14450a9bdd4SDavid du Colombier 		buf -= 7;
14550a9bdd4SDavid du Colombier 		block_cipher(ekey, buf, 1);
14650a9bdd4SDavid du Colombier 	}
14750a9bdd4SDavid du Colombier 	return 1;
14850a9bdd4SDavid du Colombier }
14950a9bdd4SDavid du Colombier 
15050a9bdd4SDavid du Colombier #define	CHAR(x)		*p++ = f->x
15150a9bdd4SDavid du Colombier #define	SHORT(x)	p[0] = f->x; p[1] = f->x>>8; p += 2
15250a9bdd4SDavid du Colombier #define	VLONG(q)	p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
15350a9bdd4SDavid du Colombier #define	LONG(x)		VLONG(f->x)
15450a9bdd4SDavid du Colombier #define	STRING(x,n)	memmove(p, f->x, n); p += n
15550a9bdd4SDavid du Colombier 
15650a9bdd4SDavid du Colombier static int
convTR2M(Ticketreq * f,char * ap)15750a9bdd4SDavid du Colombier convTR2M(Ticketreq *f, char *ap)
15850a9bdd4SDavid du Colombier {
15950a9bdd4SDavid du Colombier 	int n;
16050a9bdd4SDavid du Colombier 	uchar *p;
16150a9bdd4SDavid du Colombier 
16250a9bdd4SDavid du Colombier 	p = (uchar*)ap;
16350a9bdd4SDavid du Colombier 	CHAR(type);
16450a9bdd4SDavid du Colombier 	STRING(authid, NAMELEN);
16550a9bdd4SDavid du Colombier 	STRING(authdom, DOMLEN);
16650a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
16750a9bdd4SDavid du Colombier 	STRING(hostid, NAMELEN);
16850a9bdd4SDavid du Colombier 	STRING(uid, NAMELEN);
16950a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
17050a9bdd4SDavid du Colombier 	return n;
17150a9bdd4SDavid du Colombier }
17250a9bdd4SDavid du Colombier 
17350a9bdd4SDavid du Colombier static int
convT2M(Ticket * f,char * ap,char * key)17450a9bdd4SDavid du Colombier convT2M(Ticket *f, char *ap, char *key)
17550a9bdd4SDavid du Colombier {
17650a9bdd4SDavid du Colombier 	int n;
17750a9bdd4SDavid du Colombier 	uchar *p;
17850a9bdd4SDavid du Colombier 
17950a9bdd4SDavid du Colombier 	p = (uchar*)ap;
18050a9bdd4SDavid du Colombier 	CHAR(num);
18150a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
18250a9bdd4SDavid du Colombier 	STRING(cuid, NAMELEN);
18350a9bdd4SDavid du Colombier 	STRING(suid, NAMELEN);
18450a9bdd4SDavid du Colombier 	STRING(key, DESKEYLEN);
18550a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
18650a9bdd4SDavid du Colombier 	if(key)
18750a9bdd4SDavid du Colombier 		encrypt9p(key, ap, n);
18850a9bdd4SDavid du Colombier 	return n;
18950a9bdd4SDavid du Colombier }
19050a9bdd4SDavid du Colombier 
19150a9bdd4SDavid du Colombier int
convA2M(Authenticator * f,char * ap,char * key)19250a9bdd4SDavid du Colombier convA2M(Authenticator *f, char *ap, char *key)
19350a9bdd4SDavid du Colombier {
19450a9bdd4SDavid du Colombier 	int n;
19550a9bdd4SDavid du Colombier 	uchar *p;
19650a9bdd4SDavid du Colombier 
19750a9bdd4SDavid du Colombier 	p = (uchar*)ap;
19850a9bdd4SDavid du Colombier 	CHAR(num);
19950a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
20050a9bdd4SDavid du Colombier 	LONG(id);
20150a9bdd4SDavid du Colombier 	n = p - (uchar*)ap;
20250a9bdd4SDavid du Colombier 	if(key)
20350a9bdd4SDavid du Colombier 		encrypt9p(key, ap, n);
20450a9bdd4SDavid du Colombier 	return n;
20550a9bdd4SDavid du Colombier }
20650a9bdd4SDavid du Colombier 
20750a9bdd4SDavid du Colombier #undef CHAR
20850a9bdd4SDavid du Colombier #undef SHORT
20950a9bdd4SDavid du Colombier #undef VLONG
21050a9bdd4SDavid du Colombier #undef LONG
21150a9bdd4SDavid du Colombier #undef STRING
21250a9bdd4SDavid du Colombier 
21350a9bdd4SDavid du Colombier #define	CHAR(x)		f->x = *p++
21450a9bdd4SDavid du Colombier #define	SHORT(x)	f->x = (p[0] | (p[1]<<8)); p += 2
21550a9bdd4SDavid du Colombier #define	VLONG(q)	q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
21650a9bdd4SDavid du Colombier #define	LONG(x)		VLONG(f->x)
21750a9bdd4SDavid du Colombier #define	STRING(x,n)	memmove(f->x, p, n); p += n
21850a9bdd4SDavid du Colombier 
21950a9bdd4SDavid du Colombier void
convM2A(char * ap,Authenticator * f,char * key)22050a9bdd4SDavid du Colombier convM2A(char *ap, Authenticator *f, char *key)
22150a9bdd4SDavid du Colombier {
22250a9bdd4SDavid du Colombier 	uchar *p;
22350a9bdd4SDavid du Colombier 
22450a9bdd4SDavid du Colombier 	if(key)
22550a9bdd4SDavid du Colombier 		decrypt9p(key, ap, AUTHENTLEN);
22650a9bdd4SDavid du Colombier 	p = (uchar*)ap;
22750a9bdd4SDavid du Colombier 	CHAR(num);
22850a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
22950a9bdd4SDavid du Colombier 	LONG(id);
23050a9bdd4SDavid du Colombier 	USED(p);
23150a9bdd4SDavid du Colombier }
23250a9bdd4SDavid du Colombier 
23350a9bdd4SDavid du Colombier void
convM2T(char * ap,Ticket * f,char * key)23450a9bdd4SDavid du Colombier convM2T(char *ap, Ticket *f, char *key)
23550a9bdd4SDavid du Colombier {
23650a9bdd4SDavid du Colombier 	uchar *p;
23750a9bdd4SDavid du Colombier 
23850a9bdd4SDavid du Colombier 	if(key)
23950a9bdd4SDavid du Colombier 		decrypt9p(key, ap, TICKETLEN);
24050a9bdd4SDavid du Colombier 	p = (uchar*)ap;
24150a9bdd4SDavid du Colombier 	CHAR(num);
24250a9bdd4SDavid du Colombier 	STRING(chal, CHALLEN);
24350a9bdd4SDavid du Colombier 	STRING(cuid, NAMELEN);
24450a9bdd4SDavid du Colombier 	f->cuid[NAMELEN-1] = 0;
24550a9bdd4SDavid du Colombier 	STRING(suid, NAMELEN);
24650a9bdd4SDavid du Colombier 	f->suid[NAMELEN-1] = 0;
24750a9bdd4SDavid du Colombier 	STRING(key, DESKEYLEN);
24850a9bdd4SDavid du Colombier 	USED(p);
24950a9bdd4SDavid du Colombier }
25050a9bdd4SDavid du Colombier 
25150a9bdd4SDavid du Colombier #undef CHAR
25250a9bdd4SDavid du Colombier #undef SHORT
25350a9bdd4SDavid du Colombier #undef LONG
25450a9bdd4SDavid du Colombier #undef VLONG
25550a9bdd4SDavid du Colombier #undef STRING
25650a9bdd4SDavid du Colombier 
25750a9bdd4SDavid du Colombier static int
passtokey(char * key,char * p)25850a9bdd4SDavid du Colombier passtokey(char *key, char *p)
25950a9bdd4SDavid du Colombier {
26050a9bdd4SDavid du Colombier 	uchar buf[NAMELEN], *t;
26150a9bdd4SDavid du Colombier 	int i, n;
26250a9bdd4SDavid du Colombier 
26350a9bdd4SDavid du Colombier 	n = strlen(p);
26450a9bdd4SDavid du Colombier 	if(n >= NAMELEN)
26550a9bdd4SDavid du Colombier 		n = NAMELEN-1;
26650a9bdd4SDavid du Colombier 	memset(buf, ' ', 8);
26750a9bdd4SDavid du Colombier 	t = buf;
26850a9bdd4SDavid du Colombier 	strncpy((char*)t, p, n);
26950a9bdd4SDavid du Colombier 	t[n] = 0;
27050a9bdd4SDavid du Colombier 	memset(key, 0, DESKEYLEN);
27150a9bdd4SDavid du Colombier 	for(;;){
27250a9bdd4SDavid du Colombier 		for(i = 0; i < DESKEYLEN; i++)
27350a9bdd4SDavid du Colombier 			key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
27450a9bdd4SDavid du Colombier 		if(n <= 8)
27550a9bdd4SDavid du Colombier 			return 1;
27650a9bdd4SDavid du Colombier 		n -= 8;
27750a9bdd4SDavid du Colombier 		t += 8;
27850a9bdd4SDavid du Colombier 		if(n < 8){
27950a9bdd4SDavid du Colombier 			t -= 8 - n;
28050a9bdd4SDavid du Colombier 			n = 8;
28150a9bdd4SDavid du Colombier 		}
28250a9bdd4SDavid du Colombier 		encrypt9p(key, t, 8);
28350a9bdd4SDavid du Colombier 	}
28450a9bdd4SDavid du Colombier 	return 1;	/* not reached */
28550a9bdd4SDavid du Colombier }
28650a9bdd4SDavid du Colombier 
28750a9bdd4SDavid du Colombier static char authkey[DESKEYLEN];
28850a9bdd4SDavid du Colombier static char *authid;
28950a9bdd4SDavid du Colombier static char *authdom;
29050a9bdd4SDavid du Colombier static char *haveprotosmsg;
29150a9bdd4SDavid du Colombier static char *needprotomsg;
29250a9bdd4SDavid du Colombier 
29350a9bdd4SDavid du Colombier static void
p9anyinit(void)29450a9bdd4SDavid du Colombier p9anyinit(void)
29550a9bdd4SDavid du Colombier {
29650a9bdd4SDavid du Colombier 	int n, fd;
29750a9bdd4SDavid du Colombier 	char abuf[200];
29850a9bdd4SDavid du Colombier 	char *af, *f[4];
29950a9bdd4SDavid du Colombier 
30050a9bdd4SDavid du Colombier 	af = autharg;
30150a9bdd4SDavid du Colombier 	if(af == nil)
30250a9bdd4SDavid du Colombier 		af = "/etc/u9fs.key";
30350a9bdd4SDavid du Colombier 
30450a9bdd4SDavid du Colombier 	if((fd = open(af, OREAD)) < 0)
30550a9bdd4SDavid du Colombier 		sysfatal("can't open key file '%s'", af);
30650a9bdd4SDavid du Colombier 
30750a9bdd4SDavid du Colombier 	if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
30850a9bdd4SDavid du Colombier 		sysfatal("can't read key file '%s'", af);
30950a9bdd4SDavid du Colombier 	if (n > 0 && abuf[n - 1] == '\n')
31050a9bdd4SDavid du Colombier 		n--;
31150a9bdd4SDavid du Colombier 	abuf[n] = '\0';
31250a9bdd4SDavid du Colombier 
31350a9bdd4SDavid du Colombier 	if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
31450a9bdd4SDavid du Colombier 		sysfatal("key file '%s' not exactly 3 lines", af);
31550a9bdd4SDavid du Colombier 
31650a9bdd4SDavid du Colombier 	passtokey(authkey, f[0]);
31750a9bdd4SDavid du Colombier 	authid = strdup(f[1]);
31850a9bdd4SDavid du Colombier 	authdom = strdup(f[2]);
31950a9bdd4SDavid du Colombier 	haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
32050a9bdd4SDavid du Colombier 	sprint(haveprotosmsg, "p9sk1@%s", authdom);
32150a9bdd4SDavid du Colombier 	needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
32250a9bdd4SDavid du Colombier 	sprint(needprotomsg, "p9sk1 %s", authdom);
32350a9bdd4SDavid du Colombier }
32450a9bdd4SDavid du Colombier 
32550a9bdd4SDavid du Colombier typedef struct AuthSession {
32650a9bdd4SDavid du Colombier 	int state;
32750a9bdd4SDavid du Colombier 	char *uname;
32850a9bdd4SDavid du Colombier 	char *aname;
32950a9bdd4SDavid du Colombier 	char cchal[CHALLEN];
33050a9bdd4SDavid du Colombier 	Ticketreq tr;
33150a9bdd4SDavid du Colombier 	Ticket t;
33250a9bdd4SDavid du Colombier } AuthSession;
33350a9bdd4SDavid du Colombier 
33450a9bdd4SDavid du Colombier static char*
p9anyauth(Fcall * rx,Fcall * tx)33550a9bdd4SDavid du Colombier p9anyauth(Fcall *rx, Fcall *tx)
33650a9bdd4SDavid du Colombier {
33750a9bdd4SDavid du Colombier 	AuthSession *sp;
33850a9bdd4SDavid du Colombier 	Fid *f;
33950a9bdd4SDavid du Colombier 	char *ep;
34050a9bdd4SDavid du Colombier 
34150a9bdd4SDavid du Colombier 	sp = malloc(sizeof(AuthSession));
34250a9bdd4SDavid du Colombier 	f = newauthfid(rx->afid, sp, &ep);
34350a9bdd4SDavid du Colombier 	if (f == nil) {
34450a9bdd4SDavid du Colombier 		free(sp);
34550a9bdd4SDavid du Colombier 		return ep;
34650a9bdd4SDavid du Colombier 	}
34750a9bdd4SDavid du Colombier 	if (chatty9p)
34850a9bdd4SDavid du Colombier 		fprint(2, "p9anyauth: afid %d\n", rx->afid);
34950a9bdd4SDavid du Colombier 	sp->state = HaveProtos;
35050a9bdd4SDavid du Colombier 	sp->uname = strdup(rx->uname);
35150a9bdd4SDavid du Colombier 	sp->aname = strdup(rx->aname);
35250a9bdd4SDavid du Colombier 	tx->aqid.type = QTAUTH;
35350a9bdd4SDavid du Colombier 	tx->aqid.path = 1;
35450a9bdd4SDavid du Colombier 	tx->aqid.vers = 0;
35550a9bdd4SDavid du Colombier 	return nil;
35650a9bdd4SDavid du Colombier }
35750a9bdd4SDavid du Colombier 
35850a9bdd4SDavid du Colombier static char *
p9anyattach(Fcall * rx,Fcall * tx)35950a9bdd4SDavid du Colombier p9anyattach(Fcall *rx, Fcall *tx)
36050a9bdd4SDavid du Colombier {
36150a9bdd4SDavid du Colombier 	AuthSession *sp;
36250a9bdd4SDavid du Colombier 	Fid *f;
36350a9bdd4SDavid du Colombier 	char *ep;
36450a9bdd4SDavid du Colombier 
36550a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
36650a9bdd4SDavid du Colombier 	if (f == nil)
36750a9bdd4SDavid du Colombier 		return ep;
36850a9bdd4SDavid du Colombier 	if (chatty9p)
36950a9bdd4SDavid du Colombier 		fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
37050a9bdd4SDavid du Colombier 	if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
37150a9bdd4SDavid du Colombier 		&& strcmp(rx->aname, sp->aname) == 0)
37250a9bdd4SDavid du Colombier 		return nil;
37350a9bdd4SDavid du Colombier 	return "authentication failed";
37450a9bdd4SDavid du Colombier }
37550a9bdd4SDavid du Colombier 
37650a9bdd4SDavid du Colombier static int
readstr(Fcall * rx,Fcall * tx,char * s,int len)37750a9bdd4SDavid du Colombier readstr(Fcall *rx, Fcall *tx, char *s, int len)
37850a9bdd4SDavid du Colombier {
37950a9bdd4SDavid du Colombier 	if (rx->offset >= len)
38050a9bdd4SDavid du Colombier 		return 0;
38150a9bdd4SDavid du Colombier 	tx->count = len - rx->offset;
38250a9bdd4SDavid du Colombier 	if (tx->count > rx->count)
38350a9bdd4SDavid du Colombier 		tx->count = rx->count;
38450a9bdd4SDavid du Colombier 	memcpy(tx->data, s + rx->offset, tx->count);
38550a9bdd4SDavid du Colombier 	return tx->count;
38650a9bdd4SDavid du Colombier }
38750a9bdd4SDavid du Colombier 
38850a9bdd4SDavid du Colombier static char *
p9anyread(Fcall * rx,Fcall * tx)38950a9bdd4SDavid du Colombier p9anyread(Fcall *rx, Fcall *tx)
39050a9bdd4SDavid du Colombier {
39150a9bdd4SDavid du Colombier 	AuthSession *sp;
39250a9bdd4SDavid du Colombier 	char *ep;
39350a9bdd4SDavid du Colombier 
39450a9bdd4SDavid du Colombier 	Fid *f;
39550a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
39650a9bdd4SDavid du Colombier 	if (f == nil)
39750a9bdd4SDavid du Colombier 		return ep;
39850a9bdd4SDavid du Colombier 	if (chatty9p)
39950a9bdd4SDavid du Colombier 		fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
40050a9bdd4SDavid du Colombier 	switch (sp->state) {
40150a9bdd4SDavid du Colombier 	case HaveProtos:
40250a9bdd4SDavid du Colombier 		readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
40350a9bdd4SDavid du Colombier 		if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
40450a9bdd4SDavid du Colombier 			sp->state = NeedProto;
40550a9bdd4SDavid du Colombier 		return nil;
40650a9bdd4SDavid du Colombier 	case HaveTreq:
40750a9bdd4SDavid du Colombier 		if (rx->count != TICKREQLEN)
40850a9bdd4SDavid du Colombier 			goto botch;
40950a9bdd4SDavid du Colombier 		convTR2M(&sp->tr, tx->data);
41050a9bdd4SDavid du Colombier 		tx->count = TICKREQLEN;
41150a9bdd4SDavid du Colombier 		sp->state = NeedTicket;
41250a9bdd4SDavid du Colombier 		return nil;
41350a9bdd4SDavid du Colombier 	case HaveAuth: {
41450a9bdd4SDavid du Colombier 		Authenticator a;
41550a9bdd4SDavid du Colombier 		if (rx->count != AUTHENTLEN)
41650a9bdd4SDavid du Colombier 			goto botch;
41750a9bdd4SDavid du Colombier 		a.num = AuthAs;
41850a9bdd4SDavid du Colombier 		memmove(a.chal, sp->cchal, CHALLEN);
41950a9bdd4SDavid du Colombier 		a.id = 0;
42050a9bdd4SDavid du Colombier 		convA2M(&a, (char*)tx->data, sp->t.key);
42150a9bdd4SDavid du Colombier 		memset(sp->t.key, 0, sizeof(sp->t.key));
42250a9bdd4SDavid du Colombier 		tx->count = rx->count;
42350a9bdd4SDavid du Colombier 		sp->state = Established;
42450a9bdd4SDavid du Colombier 		return nil;
42550a9bdd4SDavid du Colombier 	}
42650a9bdd4SDavid du Colombier 	default:
42750a9bdd4SDavid du Colombier 	botch:
42850a9bdd4SDavid du Colombier 		return "protocol botch";
42950a9bdd4SDavid du Colombier 	}
43050a9bdd4SDavid du Colombier }
43150a9bdd4SDavid du Colombier 
43250a9bdd4SDavid du Colombier static char *
p9anywrite(Fcall * rx,Fcall * tx)43350a9bdd4SDavid du Colombier p9anywrite(Fcall *rx, Fcall *tx)
43450a9bdd4SDavid du Colombier {
43550a9bdd4SDavid du Colombier 	AuthSession *sp;
43650a9bdd4SDavid du Colombier 	char *ep;
43750a9bdd4SDavid du Colombier 
43850a9bdd4SDavid du Colombier 	Fid *f;
43950a9bdd4SDavid du Colombier 
44050a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
44150a9bdd4SDavid du Colombier 	if (f == nil)
44250a9bdd4SDavid du Colombier 		return ep;
44350a9bdd4SDavid du Colombier 	if (chatty9p)
44450a9bdd4SDavid du Colombier 		fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
44550a9bdd4SDavid du Colombier 	switch (sp->state) {
44650a9bdd4SDavid du Colombier 	case NeedProto:
44750a9bdd4SDavid du Colombier 		if (rx->count != strlen(needprotomsg) + 1)
44850a9bdd4SDavid du Colombier 			return "protocol response wrong length";
44950a9bdd4SDavid du Colombier 		if (memcmp(rx->data, needprotomsg, rx->count) != 0)
45050a9bdd4SDavid du Colombier 			return "unacceptable protocol";
45150a9bdd4SDavid du Colombier 		sp->state = NeedChal;
45250a9bdd4SDavid du Colombier 		tx->count = rx->count;
45350a9bdd4SDavid du Colombier 		return nil;
45450a9bdd4SDavid du Colombier 	case NeedChal:
45550a9bdd4SDavid du Colombier 		if (rx->count != CHALLEN)
45650a9bdd4SDavid du Colombier 			goto botch;
45750a9bdd4SDavid du Colombier 		memmove(sp->cchal, rx->data, CHALLEN);
45850a9bdd4SDavid du Colombier 		sp->tr.type = AuthTreq;
45950a9bdd4SDavid du Colombier 		safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
46050a9bdd4SDavid du Colombier 		safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
46150a9bdd4SDavid du Colombier 		randombytes((uchar *)sp->tr.chal, CHALLEN);
46250a9bdd4SDavid du Colombier 		safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
46350a9bdd4SDavid du Colombier 		safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
46450a9bdd4SDavid du Colombier 		tx->count = rx->count;
46550a9bdd4SDavid du Colombier 		sp->state = HaveTreq;
46650a9bdd4SDavid du Colombier 		return nil;
46750a9bdd4SDavid du Colombier 	case NeedTicket: {
46850a9bdd4SDavid du Colombier 		Authenticator a;
46950a9bdd4SDavid du Colombier 
47050a9bdd4SDavid du Colombier 		if (rx->count != TICKETLEN + AUTHENTLEN) {
47150a9bdd4SDavid du Colombier 			fprint(2, "bad length in attach");
47250a9bdd4SDavid du Colombier 			goto botch;
47350a9bdd4SDavid du Colombier 		}
47450a9bdd4SDavid du Colombier 		convM2T((char*)rx->data, &sp->t, authkey);
47550a9bdd4SDavid du Colombier 		if (sp->t.num != AuthTs) {
47650a9bdd4SDavid du Colombier 			fprint(2, "bad AuthTs in attach\n");
47750a9bdd4SDavid du Colombier 			goto botch;
47850a9bdd4SDavid du Colombier 		}
47950a9bdd4SDavid du Colombier 		if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
48050a9bdd4SDavid du Colombier 			fprint(2, "bad challenge in attach\n");
48150a9bdd4SDavid du Colombier 			goto botch;
48250a9bdd4SDavid du Colombier 		}
48350a9bdd4SDavid du Colombier 		convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
48450a9bdd4SDavid du Colombier 		if (a.num != AuthAc) {
48550a9bdd4SDavid du Colombier 			fprint(2, "bad AuthAs in attach\n");
48650a9bdd4SDavid du Colombier 			goto botch;
48750a9bdd4SDavid du Colombier 		}
48850a9bdd4SDavid du Colombier 		if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
48950a9bdd4SDavid du Colombier 			fprint(2, "bad challenge in attach 2\n");
49050a9bdd4SDavid du Colombier 			goto botch;
49150a9bdd4SDavid du Colombier 		}
49250a9bdd4SDavid du Colombier 		sp->state = HaveAuth;
49350a9bdd4SDavid du Colombier 		tx->count = rx->count;
49450a9bdd4SDavid du Colombier 		return nil;
49550a9bdd4SDavid du Colombier 	}
49650a9bdd4SDavid du Colombier 	default:
49750a9bdd4SDavid du Colombier 	botch:
49850a9bdd4SDavid du Colombier 		return "protocol botch";
49950a9bdd4SDavid du Colombier 	}
50050a9bdd4SDavid du Colombier }
50150a9bdd4SDavid du Colombier 
50250a9bdd4SDavid du Colombier static void
safefree(char * p)50350a9bdd4SDavid du Colombier safefree(char *p)
50450a9bdd4SDavid du Colombier {
50550a9bdd4SDavid du Colombier 	if (p) {
50650a9bdd4SDavid du Colombier 		memset(p, 0, strlen(p));
50750a9bdd4SDavid du Colombier 		free(p);
50850a9bdd4SDavid du Colombier 	}
50950a9bdd4SDavid du Colombier }
51050a9bdd4SDavid du Colombier 
51150a9bdd4SDavid du Colombier static char *
p9anyclunk(Fcall * rx,Fcall * tx)51250a9bdd4SDavid du Colombier p9anyclunk(Fcall *rx, Fcall *tx)
51350a9bdd4SDavid du Colombier {
51450a9bdd4SDavid du Colombier 	Fid *f;
51550a9bdd4SDavid du Colombier 	AuthSession *sp;
51650a9bdd4SDavid du Colombier 	char *ep;
51750a9bdd4SDavid du Colombier 
51850a9bdd4SDavid du Colombier 	f = oldauthfid(rx->afid, (void **)&sp, &ep);
51950a9bdd4SDavid du Colombier 	if (f == nil)
52050a9bdd4SDavid du Colombier 		return ep;
52150a9bdd4SDavid du Colombier 	if (chatty9p)
52250a9bdd4SDavid du Colombier 		fprint(2, "p9anyclunk: afid %d\n", rx->fid);
52350a9bdd4SDavid du Colombier 	safefree(sp->uname);
52450a9bdd4SDavid du Colombier 	safefree(sp->aname);
52550a9bdd4SDavid du Colombier 	memset(sp, 0, sizeof(sp));
52650a9bdd4SDavid du Colombier 	free(sp);
52750a9bdd4SDavid du Colombier 	return nil;
52850a9bdd4SDavid du Colombier }
52950a9bdd4SDavid du Colombier 
53050a9bdd4SDavid du Colombier Auth authp9any = {
53150a9bdd4SDavid du Colombier 	"p9any",
53250a9bdd4SDavid du Colombier 	p9anyauth,
53350a9bdd4SDavid du Colombier 	p9anyattach,
53450a9bdd4SDavid du Colombier 	p9anyinit,
53550a9bdd4SDavid du Colombier 	p9anyread,
53650a9bdd4SDavid du Colombier 	p9anywrite,
53750a9bdd4SDavid du Colombier 	p9anyclunk,
53850a9bdd4SDavid du Colombier };
539