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