123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- /*
- * 4th Edition p9any/p9sk1 authentication based on auth9p1.c
- * Nigel Roles (nigel@9fs.org) 2003
- */
- #include <plan9.h>
- #include <fcall.h>
- #include <u9fs.h>
- #include <stdlib.h> /* for random stuff */
- typedef struct Ticket Ticket;
- typedef struct Ticketreq Ticketreq;
- typedef struct Authenticator Authenticator;
- enum
- {
- DOMLEN= 48, /* length of an authentication domain name */
- CHALLEN= 8 /* length of a challenge */
- };
- enum {
- HaveProtos,
- NeedProto,
- NeedChal,
- HaveTreq,
- NeedTicket,
- HaveAuth,
- Established,
- };
- /* encryption numberings (anti-replay) */
- enum
- {
- AuthTreq=1, /* ticket request */
- AuthChal=2, /* challenge box request */
- AuthPass=3, /* change password */
- AuthOK=4, /* fixed length reply follows */
- AuthErr=5, /* error follows */
- AuthMod=6, /* modify user */
- AuthApop=7, /* apop authentication for pop3 */
- AuthOKvar=9, /* variable length reply follows */
- AuthChap=10, /* chap authentication for ppp */
- AuthMSchap=11, /* MS chap authentication for ppp */
- AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
- AuthHttp=13, /* http domain login */
- AuthVNC=14, /* http domain login */
- AuthTs=64, /* ticket encrypted with server's key */
- AuthTc, /* ticket encrypted with client's key */
- AuthAs, /* server generated authenticator */
- AuthAc, /* client generated authenticator */
- AuthTp, /* ticket encrypted with client's key for password change */
- AuthHr /* http reply */
- };
- struct Ticketreq
- {
- char type;
- char authid[NAMELEN]; /* server's encryption id */
- char authdom[DOMLEN]; /* server's authentication domain */
- char chal[CHALLEN]; /* challenge from server */
- char hostid[NAMELEN]; /* host's encryption id */
- char uid[NAMELEN]; /* uid of requesting user on host */
- };
- #define TICKREQLEN (3*NAMELEN+CHALLEN+DOMLEN+1)
- struct Ticket
- {
- char num; /* replay protection */
- char chal[CHALLEN]; /* server challenge */
- char cuid[NAMELEN]; /* uid on client */
- char suid[NAMELEN]; /* uid on server */
- char key[DESKEYLEN]; /* nonce DES key */
- };
- #define TICKETLEN (CHALLEN+2*NAMELEN+DESKEYLEN+1)
- struct Authenticator
- {
- char num; /* replay protection */
- char chal[CHALLEN];
- ulong id; /* authenticator id, ++'d with each auth */
- };
- #define AUTHENTLEN (CHALLEN+4+1)
- extern int chatty9p;
- static int convT2M(Ticket*, char*, char*);
- static void convM2T(char*, Ticket*, char*);
- static void convM2Tnoenc(char*, Ticket*);
- static int convA2M(Authenticator*, char*, char*);
- static void convM2A(char*, Authenticator*, char*);
- static int convTR2M(Ticketreq*, char*);
- static void convM2TR(char*, Ticketreq*);
- static int passtokey(char*, char*);
- /*
- * destructively encrypt the buffer, which
- * must be at least 8 characters long.
- */
- static int
- encrypt9p(void *key, void *vbuf, int n)
- {
- char ekey[128], *buf;
- int i, r;
- if(n < 8)
- return 0;
- key_setup(key, ekey);
- buf = vbuf;
- n--;
- r = n % 7;
- n /= 7;
- for(i = 0; i < n; i++){
- block_cipher(ekey, buf, 0);
- buf += 7;
- }
- if(r)
- block_cipher(ekey, buf - 7 + r, 0);
- return 1;
- }
- /*
- * destructively decrypt the buffer, which
- * must be at least 8 characters long.
- */
- static int
- decrypt9p(void *key, void *vbuf, int n)
- {
- char ekey[128], *buf;
- int i, r;
- if(n < 8)
- return 0;
- key_setup(key, ekey);
- buf = vbuf;
- n--;
- r = n % 7;
- n /= 7;
- buf += n * 7;
- if(r)
- block_cipher(ekey, buf - 7 + r, 1);
- for(i = 0; i < n; i++){
- buf -= 7;
- block_cipher(ekey, buf, 1);
- }
- return 1;
- }
- #define CHAR(x) *p++ = f->x
- #define SHORT(x) p[0] = f->x; p[1] = f->x>>8; p += 2
- #define VLONG(q) p[0] = (q); p[1] = (q)>>8; p[2] = (q)>>16; p[3] = (q)>>24; p += 4
- #define LONG(x) VLONG(f->x)
- #define STRING(x,n) memmove(p, f->x, n); p += n
- static int
- convTR2M(Ticketreq *f, char *ap)
- {
- int n;
- uchar *p;
- p = (uchar*)ap;
- CHAR(type);
- STRING(authid, NAMELEN);
- STRING(authdom, DOMLEN);
- STRING(chal, CHALLEN);
- STRING(hostid, NAMELEN);
- STRING(uid, NAMELEN);
- n = p - (uchar*)ap;
- return n;
- }
- static int
- convT2M(Ticket *f, char *ap, char *key)
- {
- int n;
- uchar *p;
- p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- STRING(cuid, NAMELEN);
- STRING(suid, NAMELEN);
- STRING(key, DESKEYLEN);
- n = p - (uchar*)ap;
- if(key)
- encrypt9p(key, ap, n);
- return n;
- }
- int
- convA2M(Authenticator *f, char *ap, char *key)
- {
- int n;
- uchar *p;
- p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- LONG(id);
- n = p - (uchar*)ap;
- if(key)
- encrypt9p(key, ap, n);
- return n;
- }
- #undef CHAR
- #undef SHORT
- #undef VLONG
- #undef LONG
- #undef STRING
- #define CHAR(x) f->x = *p++
- #define SHORT(x) f->x = (p[0] | (p[1]<<8)); p += 2
- #define VLONG(q) q = (p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24)); p += 4
- #define LONG(x) VLONG(f->x)
- #define STRING(x,n) memmove(f->x, p, n); p += n
- void
- convM2A(char *ap, Authenticator *f, char *key)
- {
- uchar *p;
- if(key)
- decrypt9p(key, ap, AUTHENTLEN);
- p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- LONG(id);
- USED(p);
- }
- void
- convM2T(char *ap, Ticket *f, char *key)
- {
- uchar *p;
- if(key)
- decrypt9p(key, ap, TICKETLEN);
- p = (uchar*)ap;
- CHAR(num);
- STRING(chal, CHALLEN);
- STRING(cuid, NAMELEN);
- f->cuid[NAMELEN-1] = 0;
- STRING(suid, NAMELEN);
- f->suid[NAMELEN-1] = 0;
- STRING(key, DESKEYLEN);
- USED(p);
- }
- #undef CHAR
- #undef SHORT
- #undef LONG
- #undef VLONG
- #undef STRING
- static int
- passtokey(char *key, char *p)
- {
- uchar buf[NAMELEN], *t;
- int i, n;
- n = strlen(p);
- if(n >= NAMELEN)
- n = NAMELEN-1;
- memset(buf, ' ', 8);
- t = buf;
- strncpy((char*)t, p, n);
- t[n] = 0;
- memset(key, 0, DESKEYLEN);
- for(;;){
- for(i = 0; i < DESKEYLEN; i++)
- key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1)));
- if(n <= 8)
- return 1;
- n -= 8;
- t += 8;
- if(n < 8){
- t -= 8 - n;
- n = 8;
- }
- encrypt9p(key, t, 8);
- }
- return 1; /* not reached */
- }
- static char authkey[DESKEYLEN];
- static char *authid;
- static char *authdom;
- static char *haveprotosmsg;
- static char *needprotomsg;
- static void
- p9anyinit(void)
- {
- int n, fd;
- char abuf[200];
- char *af, *f[4];
- af = autharg;
- if(af == nil)
- af = "/etc/u9fs.key";
- if((fd = open(af, OREAD)) < 0)
- sysfatal("can't open key file '%s'", af);
- if((n = readn(fd, abuf, sizeof(abuf)-1)) < 0)
- sysfatal("can't read key file '%s'", af);
- if (n > 0 && abuf[n - 1] == '\n')
- n--;
- abuf[n] = '\0';
- if(getfields(abuf, f, nelem(f), 0, "\n") != 3)
- sysfatal("key file '%s' not exactly 3 lines", af);
- passtokey(authkey, f[0]);
- authid = strdup(f[1]);
- authdom = strdup(f[2]);
- haveprotosmsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
- sprint(haveprotosmsg, "p9sk1@%s", authdom);
- needprotomsg = malloc(strlen("p9sk1") + 1 + strlen(authdom) + 1);
- sprint(needprotomsg, "p9sk1 %s", authdom);
- }
- typedef struct AuthSession {
- int state;
- char *uname;
- char *aname;
- char cchal[CHALLEN];
- Ticketreq tr;
- Ticket t;
- } AuthSession;
- static char*
- p9anyauth(Fcall *rx, Fcall *tx)
- {
- AuthSession *sp;
- Fid *f;
- char *ep;
- sp = malloc(sizeof(AuthSession));
- f = newauthfid(rx->afid, sp, &ep);
- if (f == nil) {
- free(sp);
- return ep;
- }
- if (chatty9p)
- fprint(2, "p9anyauth: afid %d\n", rx->afid);
- sp->state = HaveProtos;
- sp->uname = strdup(rx->uname);
- sp->aname = strdup(rx->aname);
- tx->aqid.type = QTAUTH;
- tx->aqid.path = 1;
- tx->aqid.vers = 0;
- return nil;
- }
- static char *
- p9anyattach(Fcall *rx, Fcall *tx)
- {
- AuthSession *sp;
- Fid *f;
- char *ep;
- f = oldauthfid(rx->afid, (void **)&sp, &ep);
- if (f == nil)
- return ep;
- if (chatty9p)
- fprint(2, "p9anyattach: afid %d state %d\n", rx->afid, sp->state);
- if (sp->state == Established && strcmp(rx->uname, sp->uname) == 0
- && strcmp(rx->aname, sp->aname) == 0)
- return nil;
- return "authentication failed";
- }
- static int
- readstr(Fcall *rx, Fcall *tx, char *s, int len)
- {
- if (rx->offset >= len)
- return 0;
- tx->count = len - rx->offset;
- if (tx->count > rx->count)
- tx->count = rx->count;
- memcpy(tx->data, s + rx->offset, tx->count);
- return tx->count;
- }
- static char *
- p9anyread(Fcall *rx, Fcall *tx)
- {
- AuthSession *sp;
- char *ep;
- Fid *f;
- f = oldauthfid(rx->afid, (void **)&sp, &ep);
- if (f == nil)
- return ep;
- if (chatty9p)
- fprint(2, "p9anyread: afid %d state %d\n", rx->fid, sp->state);
- switch (sp->state) {
- case HaveProtos:
- readstr(rx, tx, haveprotosmsg, strlen(haveprotosmsg) + 1);
- if (rx->offset + tx->count == strlen(haveprotosmsg) + 1)
- sp->state = NeedProto;
- return nil;
- case HaveTreq:
- if (rx->count != TICKREQLEN)
- goto botch;
- convTR2M(&sp->tr, tx->data);
- tx->count = TICKREQLEN;
- sp->state = NeedTicket;
- return nil;
- case HaveAuth: {
- Authenticator a;
- if (rx->count != AUTHENTLEN)
- goto botch;
- a.num = AuthAs;
- memmove(a.chal, sp->cchal, CHALLEN);
- a.id = 0;
- convA2M(&a, (char*)tx->data, sp->t.key);
- memset(sp->t.key, 0, sizeof(sp->t.key));
- tx->count = rx->count;
- sp->state = Established;
- return nil;
- }
- default:
- botch:
- return "protocol botch";
- }
- }
- static char *
- p9anywrite(Fcall *rx, Fcall *tx)
- {
- AuthSession *sp;
- char *ep;
- Fid *f;
- f = oldauthfid(rx->afid, (void **)&sp, &ep);
- if (f == nil)
- return ep;
- if (chatty9p)
- fprint(2, "p9anywrite: afid %d state %d\n", rx->fid, sp->state);
- switch (sp->state) {
- case NeedProto:
- if (rx->count != strlen(needprotomsg) + 1)
- return "protocol response wrong length";
- if (memcmp(rx->data, needprotomsg, rx->count) != 0)
- return "unacceptable protocol";
- sp->state = NeedChal;
- tx->count = rx->count;
- return nil;
- case NeedChal:
- if (rx->count != CHALLEN)
- goto botch;
- memmove(sp->cchal, rx->data, CHALLEN);
- sp->tr.type = AuthTreq;
- safecpy(sp->tr.authid, authid, sizeof(sp->tr.authid));
- safecpy(sp->tr.authdom, authdom, sizeof(sp->tr.authdom));
- randombytes((uchar *)sp->tr.chal, CHALLEN);
- safecpy(sp->tr.hostid, "", sizeof(sp->tr.hostid));
- safecpy(sp->tr.uid, "", sizeof(sp->tr.uid));
- tx->count = rx->count;
- sp->state = HaveTreq;
- return nil;
- case NeedTicket: {
- Authenticator a;
- if (rx->count != TICKETLEN + AUTHENTLEN) {
- fprint(2, "bad length in attach");
- goto botch;
- }
- convM2T((char*)rx->data, &sp->t, authkey);
- if (sp->t.num != AuthTs) {
- fprint(2, "bad AuthTs in attach\n");
- goto botch;
- }
- if (memcmp(sp->t.chal, sp->tr.chal, CHALLEN) != 0) {
- fprint(2, "bad challenge in attach\n");
- goto botch;
- }
- convM2A((char*)rx->data + TICKETLEN, &a, sp->t.key);
- if (a.num != AuthAc) {
- fprint(2, "bad AuthAs in attach\n");
- goto botch;
- }
- if(memcmp(a.chal, sp->tr.chal, CHALLEN) != 0) {
- fprint(2, "bad challenge in attach 2\n");
- goto botch;
- }
- sp->state = HaveAuth;
- tx->count = rx->count;
- return nil;
- }
- default:
- botch:
- return "protocol botch";
- }
- }
- static void
- safefree(char *p)
- {
- if (p) {
- memset(p, 0, strlen(p));
- free(p);
- }
- }
- static char *
- p9anyclunk(Fcall *rx, Fcall *tx)
- {
- Fid *f;
- AuthSession *sp;
- char *ep;
- f = oldauthfid(rx->afid, (void **)&sp, &ep);
- if (f == nil)
- return ep;
- if (chatty9p)
- fprint(2, "p9anyclunk: afid %d\n", rx->fid);
- safefree(sp->uname);
- safefree(sp->aname);
- memset(sp, 0, sizeof(sp));
- free(sp);
- return nil;
- }
- Auth authp9any = {
- "p9any",
- p9anyauth,
- p9anyattach,
- p9anyinit,
- p9anyread,
- p9anywrite,
- p9anyclunk,
- };
|