19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * CHAP, MSCHAP
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier * The client does not authenticate the server, hence no CAI
59a747e4fSDavid du Colombier *
69a747e4fSDavid du Colombier * Client protocol:
749eeb88aSDavid du Colombier * write Chapchal
849eeb88aSDavid du Colombier * read response Chapreply or MSchaprely structure
99a747e4fSDavid du Colombier *
109a747e4fSDavid du Colombier * Server protocol:
119a747e4fSDavid du Colombier * read challenge: 8 bytes binary
129a747e4fSDavid du Colombier * write user: utf8
139a747e4fSDavid du Colombier * write response: Chapreply or MSchapreply structure
149a747e4fSDavid du Colombier */
159a747e4fSDavid du Colombier
1649eeb88aSDavid du Colombier #include <ctype.h>
179a747e4fSDavid du Colombier #include "dat.h"
189a747e4fSDavid du Colombier
199a747e4fSDavid du Colombier enum {
209a747e4fSDavid du Colombier ChapChallen = 8,
2149eeb88aSDavid du Colombier ChapResplen = 16,
2249eeb88aSDavid du Colombier MSchapResplen = 24,
239a747e4fSDavid du Colombier };
249a747e4fSDavid du Colombier
259a747e4fSDavid du Colombier static int dochal(State*);
269a747e4fSDavid du Colombier static int doreply(State*, void*, int);
2749eeb88aSDavid du Colombier static void doLMchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);
2849eeb88aSDavid du Colombier static void doNTchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);
2949eeb88aSDavid du Colombier static void dochap(char *, int, char [ChapChallen], uchar [ChapResplen]);
3049eeb88aSDavid du Colombier
319a747e4fSDavid du Colombier
329a747e4fSDavid du Colombier struct State
339a747e4fSDavid du Colombier {
349a747e4fSDavid du Colombier char *protoname;
359a747e4fSDavid du Colombier int astype;
369a747e4fSDavid du Colombier int asfd;
379a747e4fSDavid du Colombier Key *key;
389a747e4fSDavid du Colombier Ticket t;
399a747e4fSDavid du Colombier Ticketreq tr;
409a747e4fSDavid du Colombier char chal[ChapChallen];
4149eeb88aSDavid du Colombier MSchapreply mcr;
4249eeb88aSDavid du Colombier char cr[ChapResplen];
439a747e4fSDavid du Colombier char err[ERRMAX];
449a747e4fSDavid du Colombier char user[64];
459a747e4fSDavid du Colombier uchar secret[16]; /* for mschap */
469a747e4fSDavid du Colombier int nsecret;
479a747e4fSDavid du Colombier };
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier enum
509a747e4fSDavid du Colombier {
5149eeb88aSDavid du Colombier CNeedChal,
5249eeb88aSDavid du Colombier CHaveResp,
5349eeb88aSDavid du Colombier
549a747e4fSDavid du Colombier SHaveChal,
559a747e4fSDavid du Colombier SNeedUser,
569a747e4fSDavid du Colombier SNeedResp,
579a747e4fSDavid du Colombier SHaveZero,
589a747e4fSDavid du Colombier SHaveCAI,
599a747e4fSDavid du Colombier
609a747e4fSDavid du Colombier Maxphase
619a747e4fSDavid du Colombier };
629a747e4fSDavid du Colombier
639a747e4fSDavid du Colombier static char *phasenames[Maxphase] =
649a747e4fSDavid du Colombier {
6549eeb88aSDavid du Colombier [CNeedChal] "CNeedChal",
6649eeb88aSDavid du Colombier [CHaveResp] "CHaveResp",
6749eeb88aSDavid du Colombier
689a747e4fSDavid du Colombier [SHaveChal] "SHaveChal",
699a747e4fSDavid du Colombier [SNeedUser] "SNeedUser",
709a747e4fSDavid du Colombier [SNeedResp] "SNeedResp",
719a747e4fSDavid du Colombier [SHaveZero] "SHaveZero",
729a747e4fSDavid du Colombier [SHaveCAI] "SHaveCAI",
739a747e4fSDavid du Colombier };
749a747e4fSDavid du Colombier
759a747e4fSDavid du Colombier static int
chapinit(Proto * p,Fsstate * fss)769a747e4fSDavid du Colombier chapinit(Proto *p, Fsstate *fss)
779a747e4fSDavid du Colombier {
789a747e4fSDavid du Colombier int iscli, ret;
799a747e4fSDavid du Colombier State *s;
809a747e4fSDavid du Colombier
812ebbfa15SDavid du Colombier if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
829a747e4fSDavid du Colombier return failure(fss, nil);
839a747e4fSDavid du Colombier
849a747e4fSDavid du Colombier s = emalloc(sizeof *s);
859a747e4fSDavid du Colombier fss->phasename = phasenames;
869a747e4fSDavid du Colombier fss->maxphase = Maxphase;
879a747e4fSDavid du Colombier s->asfd = -1;
889a747e4fSDavid du Colombier if(p == &chap){
899a747e4fSDavid du Colombier s->astype = AuthChap;
909a747e4fSDavid du Colombier s->protoname = "chap";
919a747e4fSDavid du Colombier }else{
929a747e4fSDavid du Colombier s->astype = AuthMSchap;
939a747e4fSDavid du Colombier s->protoname = "mschap";
949a747e4fSDavid du Colombier }
9549eeb88aSDavid du Colombier
9649eeb88aSDavid du Colombier if(iscli)
9749eeb88aSDavid du Colombier fss->phase = CNeedChal;
9849eeb88aSDavid du Colombier else{
999a747e4fSDavid du Colombier if((ret = findp9authkey(&s->key, fss)) != RpcOk){
1009a747e4fSDavid du Colombier free(s);
1019a747e4fSDavid du Colombier return ret;
1029a747e4fSDavid du Colombier }
1039a747e4fSDavid du Colombier if(dochal(s) < 0){
1049a747e4fSDavid du Colombier free(s);
1059a747e4fSDavid du Colombier return failure(fss, nil);
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier fss->phase = SHaveChal;
10849eeb88aSDavid du Colombier }
10949eeb88aSDavid du Colombier
1109a747e4fSDavid du Colombier fss->ps = s;
1119a747e4fSDavid du Colombier return RpcOk;
1129a747e4fSDavid du Colombier }
1139a747e4fSDavid du Colombier
1149a747e4fSDavid du Colombier static void
chapclose(Fsstate * fss)1159a747e4fSDavid du Colombier chapclose(Fsstate *fss)
1169a747e4fSDavid du Colombier {
1179a747e4fSDavid du Colombier State *s;
1189a747e4fSDavid du Colombier
1199a747e4fSDavid du Colombier s = fss->ps;
1209a747e4fSDavid du Colombier if(s->asfd >= 0){
1219a747e4fSDavid du Colombier close(s->asfd);
1229a747e4fSDavid du Colombier s->asfd = -1;
1239a747e4fSDavid du Colombier }
1249a747e4fSDavid du Colombier free(s);
1259a747e4fSDavid du Colombier }
1269a747e4fSDavid du Colombier
12749eeb88aSDavid du Colombier
1289a747e4fSDavid du Colombier static int
chapwrite(Fsstate * fss,void * va,uint n)1299a747e4fSDavid du Colombier chapwrite(Fsstate *fss, void *va, uint n)
1309a747e4fSDavid du Colombier {
13149eeb88aSDavid du Colombier int ret, nreply;
13249eeb88aSDavid du Colombier char *a, *v;
1339a747e4fSDavid du Colombier void *reply;
13449eeb88aSDavid du Colombier Key *k;
135260f7b65SDavid du Colombier Keyinfo ki;
1369a747e4fSDavid du Colombier State *s;
1379a747e4fSDavid du Colombier Chapreply cr;
1389a747e4fSDavid du Colombier MSchapreply mcr;
1399a747e4fSDavid du Colombier OChapreply ocr;
1409a747e4fSDavid du Colombier OMSchapreply omcr;
1419a747e4fSDavid du Colombier
1429a747e4fSDavid du Colombier s = fss->ps;
14349eeb88aSDavid du Colombier a = va;
1449a747e4fSDavid du Colombier switch(fss->phase){
1459a747e4fSDavid du Colombier default:
1469a747e4fSDavid du Colombier return phaseerror(fss, "write");
1479a747e4fSDavid du Colombier
14849eeb88aSDavid du Colombier case CNeedChal:
149260f7b65SDavid du Colombier ret = findkey(&k, mkkeyinfo(&ki, fss, nil), "%s", fss->proto->keyprompt);
15049eeb88aSDavid du Colombier if(ret != RpcOk)
15149eeb88aSDavid du Colombier return ret;
15249eeb88aSDavid du Colombier v = _strfindattr(k->privattr, "!password");
15349eeb88aSDavid du Colombier if(v == nil)
15449eeb88aSDavid du Colombier return failure(fss, "key has no password");
15549eeb88aSDavid du Colombier setattrs(fss->attr, k->attr);
15649eeb88aSDavid du Colombier switch(s->astype){
15749eeb88aSDavid du Colombier default:
15849eeb88aSDavid du Colombier abort();
15949eeb88aSDavid du Colombier case AuthMSchap:
16049eeb88aSDavid du Colombier doLMchap(v, (uchar *)a, (uchar *)s->mcr.LMresp);
16149eeb88aSDavid du Colombier doNTchap(v, (uchar *)a, (uchar *)s->mcr.NTresp);
16249eeb88aSDavid du Colombier break;
16349eeb88aSDavid du Colombier case AuthChap:
16449eeb88aSDavid du Colombier dochap(v, *a, a+1, (uchar *)s->cr);
16549eeb88aSDavid du Colombier break;
16649eeb88aSDavid du Colombier }
16749eeb88aSDavid du Colombier closekey(k);
16849eeb88aSDavid du Colombier fss->phase = CHaveResp;
16949eeb88aSDavid du Colombier return RpcOk;
17049eeb88aSDavid du Colombier
1719a747e4fSDavid du Colombier case SNeedUser:
1729a747e4fSDavid du Colombier if(n >= sizeof s->user)
1739a747e4fSDavid du Colombier return failure(fss, "user name too long");
1749a747e4fSDavid du Colombier memmove(s->user, va, n);
1759a747e4fSDavid du Colombier s->user[n] = '\0';
1769a747e4fSDavid du Colombier fss->phase = SNeedResp;
1779a747e4fSDavid du Colombier return RpcOk;
1789a747e4fSDavid du Colombier
1799a747e4fSDavid du Colombier case SNeedResp:
1809a747e4fSDavid du Colombier switch(s->astype){
1819a747e4fSDavid du Colombier default:
1829a747e4fSDavid du Colombier return failure(fss, "chap internal botch");
1839a747e4fSDavid du Colombier case AuthChap:
1849a747e4fSDavid du Colombier if(n != sizeof(Chapreply))
1859a747e4fSDavid du Colombier return failure(fss, "did not get Chapreply");
1869a747e4fSDavid du Colombier memmove(&cr, va, sizeof cr);
1879a747e4fSDavid du Colombier ocr.id = cr.id;
1889a747e4fSDavid du Colombier memmove(ocr.resp, cr.resp, sizeof ocr.resp);
189f4eafd00SDavid du Colombier memset(omcr.uid, 0, sizeof(omcr.uid));
1909a747e4fSDavid du Colombier strecpy(ocr.uid, ocr.uid+sizeof ocr.uid, s->user);
1919a747e4fSDavid du Colombier reply = &ocr;
1929a747e4fSDavid du Colombier nreply = sizeof ocr;
1939a747e4fSDavid du Colombier break;
1949a747e4fSDavid du Colombier case AuthMSchap:
1959a747e4fSDavid du Colombier if(n != sizeof(MSchapreply))
1969a747e4fSDavid du Colombier return failure(fss, "did not get MSchapreply");
1979a747e4fSDavid du Colombier memmove(&mcr, va, sizeof mcr);
1989a747e4fSDavid du Colombier memmove(omcr.LMresp, mcr.LMresp, sizeof omcr.LMresp);
1999a747e4fSDavid du Colombier memmove(omcr.NTresp, mcr.NTresp, sizeof omcr.NTresp);
200f4eafd00SDavid du Colombier memset(omcr.uid, 0, sizeof(omcr.uid));
2019a747e4fSDavid du Colombier strecpy(omcr.uid, omcr.uid+sizeof omcr.uid, s->user);
2029a747e4fSDavid du Colombier reply = &omcr;
2039a747e4fSDavid du Colombier nreply = sizeof omcr;
2049a747e4fSDavid du Colombier break;
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier if(doreply(s, reply, nreply) < 0)
2079a747e4fSDavid du Colombier return failure(fss, nil);
2089a747e4fSDavid du Colombier fss->phase = Established;
2099a747e4fSDavid du Colombier fss->ai.cuid = s->t.cuid;
2109a747e4fSDavid du Colombier fss->ai.suid = s->t.suid;
2119a747e4fSDavid du Colombier fss->ai.secret = s->secret;
2129a747e4fSDavid du Colombier fss->ai.nsecret = s->nsecret;
2139a747e4fSDavid du Colombier fss->haveai = 1;
2149a747e4fSDavid du Colombier return RpcOk;
2159a747e4fSDavid du Colombier }
2169a747e4fSDavid du Colombier }
2179a747e4fSDavid du Colombier
2189a747e4fSDavid du Colombier static int
chapread(Fsstate * fss,void * va,uint * n)2199a747e4fSDavid du Colombier chapread(Fsstate *fss, void *va, uint *n)
2209a747e4fSDavid du Colombier {
2219a747e4fSDavid du Colombier State *s;
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier s = fss->ps;
2249a747e4fSDavid du Colombier switch(fss->phase){
2259a747e4fSDavid du Colombier default:
2269a747e4fSDavid du Colombier return phaseerror(fss, "read");
2279a747e4fSDavid du Colombier
22849eeb88aSDavid du Colombier case CHaveResp:
22949eeb88aSDavid du Colombier switch(s->astype){
23049eeb88aSDavid du Colombier default:
231f4eafd00SDavid du Colombier phaseerror(fss, "write");
232f4eafd00SDavid du Colombier break;
23349eeb88aSDavid du Colombier case AuthMSchap:
23449eeb88aSDavid du Colombier if(*n > sizeof(MSchapreply))
23549eeb88aSDavid du Colombier *n = sizeof(MSchapreply);
23649eeb88aSDavid du Colombier memmove(va, &s->mcr, *n);
23749eeb88aSDavid du Colombier break;
23849eeb88aSDavid du Colombier case AuthChap:
23949eeb88aSDavid du Colombier if(*n > ChapResplen)
24049eeb88aSDavid du Colombier *n = ChapResplen;
24149eeb88aSDavid du Colombier memmove(va, s->cr, ChapResplen);
24249eeb88aSDavid du Colombier break;
24349eeb88aSDavid du Colombier }
24449eeb88aSDavid du Colombier fss->phase = Established;
24549eeb88aSDavid du Colombier fss->haveai = 0;
24649eeb88aSDavid du Colombier return RpcOk;
24749eeb88aSDavid du Colombier
2489a747e4fSDavid du Colombier case SHaveChal:
2499a747e4fSDavid du Colombier if(*n > sizeof s->chal)
2509a747e4fSDavid du Colombier *n = sizeof s->chal;
2519a747e4fSDavid du Colombier memmove(va, s->chal, *n);
2529a747e4fSDavid du Colombier fss->phase = SNeedUser;
2539a747e4fSDavid du Colombier return RpcOk;
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier }
2569a747e4fSDavid du Colombier
2579a747e4fSDavid du Colombier static int
dochal(State * s)2589a747e4fSDavid du Colombier dochal(State *s)
2599a747e4fSDavid du Colombier {
2609a747e4fSDavid du Colombier char *dom, *user;
2619a747e4fSDavid du Colombier char trbuf[TICKREQLEN];
2629a747e4fSDavid du Colombier
2639a747e4fSDavid du Colombier s->asfd = -1;
2649a747e4fSDavid du Colombier
2659a747e4fSDavid du Colombier /* send request to authentication server and get challenge */
2662ebbfa15SDavid du Colombier if((dom = _strfindattr(s->key->attr, "dom")) == nil
2672ebbfa15SDavid du Colombier || (user = _strfindattr(s->key->attr, "user")) == nil){
2689a747e4fSDavid du Colombier werrstr("chap/dochal cannot happen");
2699a747e4fSDavid du Colombier goto err;
2709a747e4fSDavid du Colombier }
2719a747e4fSDavid du Colombier s->asfd = _authdial(nil, dom);
2729a747e4fSDavid du Colombier if(s->asfd < 0)
2739a747e4fSDavid du Colombier goto err;
2749a747e4fSDavid du Colombier
2759a747e4fSDavid du Colombier memset(&s->tr, 0, sizeof(s->tr));
2769a747e4fSDavid du Colombier s->tr.type = s->astype;
2779a747e4fSDavid du Colombier safecpy(s->tr.authdom, dom, sizeof s->tr.authdom);
2789a747e4fSDavid du Colombier safecpy(s->tr.hostid, user, sizeof(s->tr.hostid));
2799a747e4fSDavid du Colombier convTR2M(&s->tr, trbuf);
2809a747e4fSDavid du Colombier
2819a747e4fSDavid du Colombier if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
2829a747e4fSDavid du Colombier goto err;
2839a747e4fSDavid du Colombier
2849a747e4fSDavid du Colombier /* readn, not _asrdresp. needs to match auth.srv.c. */
2859a747e4fSDavid du Colombier if(readn(s->asfd, s->chal, sizeof s->chal) != sizeof s->chal)
2869a747e4fSDavid du Colombier goto err;
2879a747e4fSDavid du Colombier return 0;
2889a747e4fSDavid du Colombier
2899a747e4fSDavid du Colombier err:
2909a747e4fSDavid du Colombier if(s->asfd >= 0)
2919a747e4fSDavid du Colombier close(s->asfd);
2929a747e4fSDavid du Colombier s->asfd = -1;
2939a747e4fSDavid du Colombier return -1;
2949a747e4fSDavid du Colombier }
2959a747e4fSDavid du Colombier
2969a747e4fSDavid du Colombier static int
doreply(State * s,void * reply,int nreply)2979a747e4fSDavid du Colombier doreply(State *s, void *reply, int nreply)
2989a747e4fSDavid du Colombier {
2999a747e4fSDavid du Colombier char ticket[TICKETLEN+AUTHENTLEN];
3009a747e4fSDavid du Colombier int n;
3019a747e4fSDavid du Colombier Authenticator a;
3029a747e4fSDavid du Colombier
3039a747e4fSDavid du Colombier if((n=write(s->asfd, reply, nreply)) != nreply){
3049a747e4fSDavid du Colombier if(n >= 0)
3059a747e4fSDavid du Colombier werrstr("short write to auth server");
3069a747e4fSDavid du Colombier goto err;
3079a747e4fSDavid du Colombier }
3089a747e4fSDavid du Colombier
3099a747e4fSDavid du Colombier if(_asrdresp(s->asfd, ticket, TICKETLEN+AUTHENTLEN) < 0){
3109a747e4fSDavid du Colombier /* leave connection open so we can try again */
3119a747e4fSDavid du Colombier return -1;
3129a747e4fSDavid du Colombier }
3139a747e4fSDavid du Colombier s->nsecret = readn(s->asfd, s->secret, sizeof s->secret);
3149a747e4fSDavid du Colombier if(s->nsecret < 0)
3159a747e4fSDavid du Colombier s->nsecret = 0;
3169a747e4fSDavid du Colombier close(s->asfd);
3179a747e4fSDavid du Colombier s->asfd = -1;
3189a747e4fSDavid du Colombier convM2T(ticket, &s->t, s->key->priv);
3199a747e4fSDavid du Colombier if(s->t.num != AuthTs
3209a747e4fSDavid du Colombier || memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){
321*6822557bSDavid du Colombier if(s->key->successes == 0)
322260f7b65SDavid du Colombier disablekey(s->key);
3239a747e4fSDavid du Colombier werrstr(Easproto);
3249a747e4fSDavid du Colombier return -1;
3259a747e4fSDavid du Colombier }
326*6822557bSDavid du Colombier s->key->successes++;
3279a747e4fSDavid du Colombier convM2A(ticket+TICKETLEN, &a, s->t.key);
3289a747e4fSDavid du Colombier if(a.num != AuthAc
3299a747e4fSDavid du Colombier || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
3309a747e4fSDavid du Colombier || a.id != 0){
3319a747e4fSDavid du Colombier werrstr(Easproto);
3329a747e4fSDavid du Colombier return -1;
3339a747e4fSDavid du Colombier }
3349a747e4fSDavid du Colombier
3359a747e4fSDavid du Colombier return 0;
3369a747e4fSDavid du Colombier err:
3379a747e4fSDavid du Colombier if(s->asfd >= 0)
3389a747e4fSDavid du Colombier close(s->asfd);
3399a747e4fSDavid du Colombier s->asfd = -1;
3409a747e4fSDavid du Colombier return -1;
3419a747e4fSDavid du Colombier }
3429a747e4fSDavid du Colombier
3439a747e4fSDavid du Colombier Proto chap = {
3449a747e4fSDavid du Colombier .name= "chap",
3459a747e4fSDavid du Colombier .init= chapinit,
3469a747e4fSDavid du Colombier .write= chapwrite,
3479a747e4fSDavid du Colombier .read= chapread,
3489a747e4fSDavid du Colombier .close= chapclose,
34949eeb88aSDavid du Colombier .addkey= replacekey,
35049eeb88aSDavid du Colombier .keyprompt= "!password?"
3519a747e4fSDavid du Colombier };
3529a747e4fSDavid du Colombier
3539a747e4fSDavid du Colombier Proto mschap = {
3549a747e4fSDavid du Colombier .name= "mschap",
3559a747e4fSDavid du Colombier .init= chapinit,
3569a747e4fSDavid du Colombier .write= chapwrite,
3579a747e4fSDavid du Colombier .read= chapread,
3589a747e4fSDavid du Colombier .close= chapclose,
35949eeb88aSDavid du Colombier .addkey= replacekey,
36049eeb88aSDavid du Colombier .keyprompt= "!password?"
3619a747e4fSDavid du Colombier };
3629a747e4fSDavid du Colombier
36349eeb88aSDavid du Colombier static void
hash(uchar pass[16],uchar c8[ChapChallen],uchar p24[MSchapResplen])36449eeb88aSDavid du Colombier hash(uchar pass[16], uchar c8[ChapChallen], uchar p24[MSchapResplen])
36549eeb88aSDavid du Colombier {
36649eeb88aSDavid du Colombier int i;
36749eeb88aSDavid du Colombier uchar p21[21];
36849eeb88aSDavid du Colombier ulong schedule[32];
36949eeb88aSDavid du Colombier
37049eeb88aSDavid du Colombier memset(p21, 0, sizeof p21 );
37149eeb88aSDavid du Colombier memmove(p21, pass, 16);
37249eeb88aSDavid du Colombier
37349eeb88aSDavid du Colombier for(i=0; i<3; i++) {
37449eeb88aSDavid du Colombier key_setup(p21+i*7, schedule);
37549eeb88aSDavid du Colombier memmove(p24+i*8, c8, 8);
37649eeb88aSDavid du Colombier block_cipher(schedule, p24+i*8, 0);
37749eeb88aSDavid du Colombier }
37849eeb88aSDavid du Colombier }
37949eeb88aSDavid du Colombier
38049eeb88aSDavid du Colombier static void
doNTchap(char * pass,uchar chal[ChapChallen],uchar reply[MSchapResplen])38149eeb88aSDavid du Colombier doNTchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen])
38249eeb88aSDavid du Colombier {
38349eeb88aSDavid du Colombier Rune r;
384f4eafd00SDavid du Colombier int i, n;
385f4eafd00SDavid du Colombier uchar digest[MD4dlen];
386f4eafd00SDavid du Colombier uchar *w, unipass[256];
38749eeb88aSDavid du Colombier
38849eeb88aSDavid du Colombier // Standard says unlimited length, experience says 128 max
38949eeb88aSDavid du Colombier if ((n = strlen(pass)) > 128)
39049eeb88aSDavid du Colombier n = 128;
39149eeb88aSDavid du Colombier
39249eeb88aSDavid du Colombier for(i=0, w=unipass; i < n; i++) {
39349eeb88aSDavid du Colombier pass += chartorune(&r, pass);
39449eeb88aSDavid du Colombier *w++ = r & 0xff;
39549eeb88aSDavid du Colombier *w++ = r >> 8;
39649eeb88aSDavid du Colombier }
39749eeb88aSDavid du Colombier
39849eeb88aSDavid du Colombier memset(digest, 0, sizeof digest);
39949eeb88aSDavid du Colombier md4(unipass, w-unipass, digest, nil);
400f4eafd00SDavid du Colombier memset(unipass, 0, sizeof unipass);
40149eeb88aSDavid du Colombier hash(digest, chal, reply);
40249eeb88aSDavid du Colombier }
40349eeb88aSDavid du Colombier
40449eeb88aSDavid du Colombier static void
doLMchap(char * pass,uchar chal[ChapChallen],uchar reply[MSchapResplen])40549eeb88aSDavid du Colombier doLMchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen])
40649eeb88aSDavid du Colombier {
40749eeb88aSDavid du Colombier int i;
40849eeb88aSDavid du Colombier ulong schedule[32];
40949eeb88aSDavid du Colombier uchar p14[15], p16[16];
41049eeb88aSDavid du Colombier uchar s8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
41157ea2923SDavid du Colombier int n = strlen(pass);
41257ea2923SDavid du Colombier
41357ea2923SDavid du Colombier if(n > 14){
41457ea2923SDavid du Colombier // let prudent people avoid the LM vulnerability
41557ea2923SDavid du Colombier // and protect the loop below from buffer overflow
41657ea2923SDavid du Colombier memset(reply, 0, MSchapResplen);
41757ea2923SDavid du Colombier return;
41857ea2923SDavid du Colombier }
41949eeb88aSDavid du Colombier
42049eeb88aSDavid du Colombier // Spec says space padded, experience says otherwise
42149eeb88aSDavid du Colombier memset(p14, 0, sizeof p14 -1);
42249eeb88aSDavid du Colombier p14[sizeof p14 - 1] = '\0';
42349eeb88aSDavid du Colombier
42449eeb88aSDavid du Colombier // NT4 requires uppercase, Win XP doesn't care
42549eeb88aSDavid du Colombier for (i = 0; pass[i]; i++)
42649eeb88aSDavid du Colombier p14[i] = islower(pass[i])? toupper(pass[i]): pass[i];
42749eeb88aSDavid du Colombier
42849eeb88aSDavid du Colombier for(i=0; i<2; i++) {
42949eeb88aSDavid du Colombier key_setup(p14+i*7, schedule);
43049eeb88aSDavid du Colombier memmove(p16+i*8, s8, 8);
43149eeb88aSDavid du Colombier block_cipher(schedule, p16+i*8, 0);
43249eeb88aSDavid du Colombier }
43349eeb88aSDavid du Colombier
434f4eafd00SDavid du Colombier memset(p14, 0, sizeof p14);
43549eeb88aSDavid du Colombier hash(p16, chal, reply);
43649eeb88aSDavid du Colombier }
43749eeb88aSDavid du Colombier
43849eeb88aSDavid du Colombier static void
dochap(char * pass,int id,char chal[ChapChallen],uchar resp[ChapResplen])43949eeb88aSDavid du Colombier dochap(char *pass, int id, char chal[ChapChallen], uchar resp[ChapResplen])
44049eeb88aSDavid du Colombier {
44149eeb88aSDavid du Colombier char buf[1+ChapChallen+MAXNAMELEN+1];
44249eeb88aSDavid du Colombier int n = strlen(pass);
44349eeb88aSDavid du Colombier
44449eeb88aSDavid du Colombier *buf = id;
445f4eafd00SDavid du Colombier if (n > MAXNAMELEN)
446f4eafd00SDavid du Colombier n = MAXNAMELEN-1;
447f4eafd00SDavid du Colombier memset(buf, 0, sizeof buf);
448f4eafd00SDavid du Colombier strncpy(buf+1, pass, n);
44949eeb88aSDavid du Colombier memmove(buf+1+n, chal, ChapChallen);
45049eeb88aSDavid du Colombier md5((uchar*)buf, 1+n+ChapChallen, resp, nil);
45149eeb88aSDavid du Colombier }
45249eeb88aSDavid du Colombier
453