📄 chap.c
字号:
/* * CHAP, MSCHAP * * The client does not authenticate the server, hence no CAI * * Client protocol: * write Chapchal * read response Chapreply or MSchaprely structure * * Server protocol: * read challenge: 8 bytes binary * write user: utf8 * write response: Chapreply or MSchapreply structure */#include <ctype.h>#include "dat.h"enum { ChapChallen = 8, ChapResplen = 16, MSchapResplen = 24,};static int dochal(State*);static int doreply(State*, void*, int);static void doLMchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);static void doNTchap(char *, uchar [ChapChallen], uchar [MSchapResplen]);static void dochap(char *, int, char [ChapChallen], uchar [ChapResplen]);struct State{ char *protoname; int astype; int asfd; Key *key; Ticket t; Ticketreq tr; char chal[ChapChallen]; MSchapreply mcr; char cr[ChapResplen]; char err[ERRMAX]; char user[64]; uchar secret[16]; /* for mschap */ int nsecret;};enum{ CNeedChal, CHaveResp, SHaveChal, SNeedUser, SNeedResp, SHaveZero, SHaveCAI, Maxphase};static char *phasenames[Maxphase] ={[CNeedChal] "CNeedChal",[CHaveResp] "CHaveResp",[SHaveChal] "SHaveChal",[SNeedUser] "SNeedUser",[SNeedResp] "SNeedResp",[SHaveZero] "SHaveZero",[SHaveCAI] "SHaveCAI",};static intchapinit(Proto *p, Fsstate *fss){ int iscli, ret; State *s; if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0) return failure(fss, nil); s = emalloc(sizeof *s); fss->phasename = phasenames; fss->maxphase = Maxphase; s->asfd = -1; if(p == &chap){ s->astype = AuthChap; s->protoname = "chap"; }else{ s->astype = AuthMSchap; s->protoname = "mschap"; } if(iscli) fss->phase = CNeedChal; else{ if((ret = findp9authkey(&s->key, fss)) != RpcOk){ free(s); return ret; } if(dochal(s) < 0){ free(s); return failure(fss, nil); } fss->phase = SHaveChal; } fss->ps = s; return RpcOk;}static voidchapclose(Fsstate *fss){ State *s; s = fss->ps; if(s->asfd >= 0){ close(s->asfd); s->asfd = -1; } free(s);}static intchapwrite(Fsstate *fss, void *va, uint n){ int ret, nreply; char *a, *v; void *reply; Key *k; Keyinfo ki; State *s; Chapreply cr; MSchapreply mcr; OChapreply ocr; OMSchapreply omcr; s = fss->ps; a = va; switch(fss->phase){ default: return phaseerror(fss, "write"); case CNeedChal: ret = findkey(&k, mkkeyinfo(&ki, fss, nil), "%s", fss->proto->keyprompt); if(ret != RpcOk) return ret; v = _strfindattr(k->privattr, "!password"); if(v == nil) return failure(fss, "key has no password"); setattrs(fss->attr, k->attr); switch(s->astype){ default: abort(); case AuthMSchap: doLMchap(v, (uchar *)a, (uchar *)s->mcr.LMresp); doNTchap(v, (uchar *)a, (uchar *)s->mcr.NTresp); break; case AuthChap: dochap(v, *a, a+1, (uchar *)s->cr); break; } closekey(k); fss->phase = CHaveResp; return RpcOk; case SNeedUser: if(n >= sizeof s->user) return failure(fss, "user name too long"); memmove(s->user, va, n); s->user[n] = '\0'; fss->phase = SNeedResp; return RpcOk; case SNeedResp: switch(s->astype){ default: return failure(fss, "chap internal botch"); case AuthChap: if(n != sizeof(Chapreply)) return failure(fss, "did not get Chapreply"); memmove(&cr, va, sizeof cr); ocr.id = cr.id; memmove(ocr.resp, cr.resp, sizeof ocr.resp); memset(omcr.uid, 0, sizeof(omcr.uid)); strecpy(ocr.uid, ocr.uid+sizeof ocr.uid, s->user); reply = &ocr; nreply = sizeof ocr; break; case AuthMSchap: if(n != sizeof(MSchapreply)) return failure(fss, "did not get MSchapreply"); memmove(&mcr, va, sizeof mcr); memmove(omcr.LMresp, mcr.LMresp, sizeof omcr.LMresp); memmove(omcr.NTresp, mcr.NTresp, sizeof omcr.NTresp); memset(omcr.uid, 0, sizeof(omcr.uid)); strecpy(omcr.uid, omcr.uid+sizeof omcr.uid, s->user); reply = &omcr; nreply = sizeof omcr; break; } if(doreply(s, reply, nreply) < 0) return failure(fss, nil); fss->phase = Established; fss->ai.cuid = s->t.cuid; fss->ai.suid = s->t.suid; fss->ai.secret = s->secret; fss->ai.nsecret = s->nsecret; fss->haveai = 1; return RpcOk; }}static intchapread(Fsstate *fss, void *va, uint *n){ State *s; s = fss->ps; switch(fss->phase){ default: return phaseerror(fss, "read"); case CHaveResp: switch(s->astype){ default: phaseerror(fss, "write"); break; case AuthMSchap: if(*n > sizeof(MSchapreply)) *n = sizeof(MSchapreply); memmove(va, &s->mcr, *n); break; case AuthChap: if(*n > ChapResplen) *n = ChapResplen; memmove(va, s->cr, ChapResplen); break; } fss->phase = Established; fss->haveai = 0; return RpcOk; case SHaveChal: if(*n > sizeof s->chal) *n = sizeof s->chal; memmove(va, s->chal, *n); fss->phase = SNeedUser; return RpcOk; }}static intdochal(State *s){ char *dom, *user; char trbuf[TICKREQLEN]; s->asfd = -1; /* send request to authentication server and get challenge */ if((dom = _strfindattr(s->key->attr, "dom")) == nil || (user = _strfindattr(s->key->attr, "user")) == nil){ werrstr("chap/dochal cannot happen"); goto err; } s->asfd = _authdial(nil, dom); if(s->asfd < 0) goto err; memset(&s->tr, 0, sizeof(s->tr)); s->tr.type = s->astype; safecpy(s->tr.authdom, dom, sizeof s->tr.authdom); safecpy(s->tr.hostid, user, sizeof(s->tr.hostid)); convTR2M(&s->tr, trbuf); if(write(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN) goto err; /* readn, not _asrdresp. needs to match auth.srv.c. */ if(readn(s->asfd, s->chal, sizeof s->chal) != sizeof s->chal) goto err; return 0;err: if(s->asfd >= 0) close(s->asfd); s->asfd = -1; return -1;}static intdoreply(State *s, void *reply, int nreply){ char ticket[TICKETLEN+AUTHENTLEN]; int n; Authenticator a; if((n=write(s->asfd, reply, nreply)) != nreply){ if(n >= 0) werrstr("short write to auth server"); goto err; } if(_asrdresp(s->asfd, ticket, TICKETLEN+AUTHENTLEN) < 0){ /* leave connection open so we can try again */ return -1; } s->nsecret = readn(s->asfd, s->secret, sizeof s->secret); if(s->nsecret < 0) s->nsecret = 0; close(s->asfd); s->asfd = -1; convM2T(ticket, &s->t, s->key->priv); if(s->t.num != AuthTs || memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0){ disablekey(s->key); werrstr(Easproto); return -1; } convM2A(ticket+TICKETLEN, &a, s->t.key); if(a.num != AuthAc || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0 || a.id != 0){ werrstr(Easproto); return -1; } return 0;err: if(s->asfd >= 0) close(s->asfd); s->asfd = -1; return -1;}Proto chap = {.name= "chap",.init= chapinit,.write= chapwrite,.read= chapread,.close= chapclose,.addkey= replacekey,.keyprompt= "!password?"};Proto mschap = {.name= "mschap",.init= chapinit,.write= chapwrite,.read= chapread,.close= chapclose,.addkey= replacekey,.keyprompt= "!password?"};static voidhash(uchar pass[16], uchar c8[ChapChallen], uchar p24[MSchapResplen]){ int i; uchar p21[21]; ulong schedule[32]; memset(p21, 0, sizeof p21 ); memmove(p21, pass, 16); for(i=0; i<3; i++) { key_setup(p21+i*7, schedule); memmove(p24+i*8, c8, 8); block_cipher(schedule, p24+i*8, 0); }}static voiddoNTchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen]){ Rune r; int i, n; uchar digest[MD4dlen]; uchar *w, unipass[256]; // Standard says unlimited length, experience says 128 max if ((n = strlen(pass)) > 128) n = 128; for(i=0, w=unipass; i < n; i++) { pass += chartorune(&r, pass); *w++ = r & 0xff; *w++ = r >> 8; } memset(digest, 0, sizeof digest); md4(unipass, w-unipass, digest, nil); memset(unipass, 0, sizeof unipass); hash(digest, chal, reply);}static voiddoLMchap(char *pass, uchar chal[ChapChallen], uchar reply[MSchapResplen]){ int i; ulong schedule[32]; uchar p14[15], p16[16]; uchar s8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; int n = strlen(pass); if(n > 14){ // let prudent people avoid the LM vulnerability // and protect the loop below from buffer overflow memset(reply, 0, MSchapResplen); return; } // Spec says space padded, experience says otherwise memset(p14, 0, sizeof p14 -1); p14[sizeof p14 - 1] = '\0'; // NT4 requires uppercase, Win XP doesn't care for (i = 0; pass[i]; i++) p14[i] = islower(pass[i])? toupper(pass[i]): pass[i]; for(i=0; i<2; i++) { key_setup(p14+i*7, schedule); memmove(p16+i*8, s8, 8); block_cipher(schedule, p16+i*8, 0); } memset(p14, 0, sizeof p14); hash(p16, chal, reply);}static voiddochap(char *pass, int id, char chal[ChapChallen], uchar resp[ChapResplen]){ char buf[1+ChapChallen+MAXNAMELEN+1]; int n = strlen(pass); *buf = id; if (n > MAXNAMELEN) n = MAXNAMELEN-1; memset(buf, 0, sizeof buf); strncpy(buf+1, pass, n); memmove(buf+1+n, chal, ChapChallen); md5((uchar*)buf, 1+n+ChapChallen, resp, nil);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -