diff options
Diffstat (limited to 'src/cmd/factotum/chap.c')
-rw-r--r-- | src/cmd/factotum/chap.c | 424 |
1 files changed, 0 insertions, 424 deletions
diff --git a/src/cmd/factotum/chap.c b/src/cmd/factotum/chap.c deleted file mode 100644 index debf8d0e..00000000 --- a/src/cmd/factotum/chap.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * CHAP, MSCHAP - * - * The client does not authenticate the server, hence no CAI - * - * Protocol: - * - * S -> C: random 8-byte challenge - * C -> S: user in UTF-8 - * C -> S: Chapreply or MSchapreply structure - * S -> C: ok or 'bad why' - * - * The chap protocol requires the client to give it id=%d, the id of - * the PPP message containing the challenge, which is used - * as part of the response. Because the client protocol is message-id - * specific, there is no point in looping to try multiple keys. - * - * The MS chap protocol actually uses two different hashes, an - * older insecure one called the LM (Lan Manager) hash, and a newer - * more secure one called the NT hash. By default we send back only - * the NT hash, because the LM hash can help an eavesdropper run - * a brute force attack. If the key has an lm attribute, then we send only the - * LM hash. - */ - -#include "std.h" -#include "dat.h" - -enum { - ChapChallen = 8, - - MShashlen = 16, - MSchallen = 8, - MSresplen = 24, -}; - -static int -chapcheck(Key *k) -{ - if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){ - werrstr("need user and !password attributes"); - return -1; - } - return 0; -} - -static void -nthash(uchar hash[MShashlen], char *passwd) -{ - uchar buf[512]; - int i; - - for(i=0; *passwd && i<sizeof(buf); passwd++) { - buf[i++] = *passwd; - buf[i++] = 0; - } - - memset(hash, 0, 16); - - md4(buf, i, hash, 0); -} - -static void -desencrypt(uchar data[8], uchar key[7]) -{ - ulong ekey[32]; - - key_setup(key, ekey); - block_cipher(ekey, data, 0); -} - -static void -lmhash(uchar hash[MShashlen], char *passwd) -{ - uchar buf[14]; - char *stdtext = "KGS!@#$%"; - int i; - - strncpy((char*)buf, passwd, sizeof(buf)); - for(i=0; i<sizeof(buf); i++) - if(buf[i] >= 'a' && buf[i] <= 'z') - buf[i] += 'A' - 'a'; - - memset(hash, 0, 16); - memcpy(hash, stdtext, 8); - memcpy(hash+8, stdtext, 8); - - desencrypt(hash, buf); - desencrypt(hash+8, buf+7); -} - -static void -mschalresp(uchar resp[MSresplen], uchar hash[MShashlen], uchar chal[MSchallen]) -{ - int i; - uchar buf[21]; - - memset(buf, 0, sizeof(buf)); - memcpy(buf, hash, MShashlen); - - for(i=0; i<3; i++) { - memmove(resp+i*MSchallen, chal, MSchallen); - desencrypt(resp+i*MSchallen, buf+i*7); - } -} - -static int -chapclient(Conv *c) -{ - int id, astype, nchal, npw, ret; - uchar *chal; - char *s, *pw, *user, *res; - Attr *attr; - Key *k; - Chapreply cr; - MSchapreply mscr; - DigestState *ds; - - ret = -1; - chal = nil; - k = nil; - attr = c->attr; - - if(c->proto == &chap){ - astype = AuthChap; - s = strfindattr(attr, "id"); - if(s == nil || *s == 0){ - werrstr("need id=n attr in start message"); - goto out; - } - id = strtol(s, &s, 10); - if(*s != 0 || id < 0 || id >= 256){ - werrstr("bad id=n attr in start message"); - goto out; - } - cr.id = id; - }else if(c->proto == &mschap) - astype = AuthMSchap; - else{ - werrstr("bad proto"); - goto out; - } - - c->state = "find key"; - k = keyfetch(c, "%A %s", attr, c->proto->keyprompt); - if(k == nil) - goto out; - - c->attr = addattrs(copyattr(attr), k->attr); - - c->state = "read challenge"; - if((nchal = convreadm(c, (char**)(void*)&chal)) < 0) - goto out; - if(astype == AuthMSchap && nchal != MSchallen) - c->state = "write user"; - if((user = strfindattr(k->attr, "user")) == nil){ - werrstr("key has no user (cannot happen?)"); - goto out; - } - if(convprint(c, "%s", user) < 0) - goto out; - - c->state = "write response"; - if((pw = strfindattr(k->privattr, "!password")) == nil){ - werrstr("key has no password (cannot happen?)"); - goto out; - } - npw = strlen(pw); - - if(astype == AuthChap){ - ds = md5(&cr.id, 1, 0, 0); - md5((uchar*)pw, npw, 0, ds); - md5(chal, nchal, (uchar*)cr.resp, ds); - if(convwrite(c, &cr, sizeof cr) < 0) - goto out; - }else{ - uchar hash[MShashlen]; - - memset(&mscr, 0, sizeof mscr); - if(strfindattr(k->attr, "lm")){ - lmhash(hash, pw); - mschalresp((uchar*)mscr.LMresp, hash, chal); - }else{ - nthash(hash, pw); - mschalresp((uchar*)mscr.NTresp, hash, chal); - } - if(convwrite(c, &mscr, sizeof mscr) < 0) - goto out; - } - - c->state = "read result"; - if(convreadm(c, &res) < 0) - goto out; - if(strcmp(res, "ok") == 0){ - ret = 0; - werrstr("succeeded"); - goto out; - } - if(strncmp(res, "bad ", 4) != 0){ - werrstr("bad result: %s", res); - goto out; - } - - c->state = "replace key"; - keyevict(c, k, "%s", res+4); - werrstr("%s", res+4); - -out: - free(res); - keyclose(k); - free(chal); - if(c->attr != attr) - freeattr(attr); - return ret; -} - -/* shared with auth dialing routines */ -typedef struct ServerState ServerState; -struct ServerState -{ - int asfd; - Key *k; - Ticketreq tr; - Ticket t; - char *dom; - char *hostid; -}; - -static int chapchal(ServerState*, int, char[ChapChallen]); -static int chapresp(ServerState*, char*, char*); - -static int -chapserver(Conv *c) -{ - char chal[ChapChallen], *user, *resp; - ServerState s; - int astype, ret; - Attr *a; - - ret = -1; - user = nil; - resp = nil; - memset(&s, 0, sizeof s); - s.asfd = -1; - - if(c->proto == &chap) - astype = AuthChap; - else if(c->proto == &mschap) - astype = AuthMSchap; - else{ - werrstr("bad proto"); - goto out; - } - - c->state = "find key"; - if((s.k = plan9authkey(c->attr)) == nil) - goto out; - - a = copyattr(s.k->attr); - a = delattr(a, "proto"); - c->attr = addattrs(c->attr, a); - freeattr(a); - - c->state = "authdial"; - s.hostid = strfindattr(s.k->attr, "user"); - s.dom = strfindattr(s.k->attr, "dom"); - if((s.asfd = xioauthdial(nil, s.dom)) < 0){ - werrstr("authdial %s: %r", s.dom); - goto out; - } - - c->state = "authchal"; - if(chapchal(&s, astype, chal) < 0) - goto out; - - c->state = "write challenge"; - if(convprint(c, "%s", chal) < 0) - goto out; - - c->state = "read user"; - if(convreadm(c, &user) < 0) - goto out; - - c->state = "read response"; - if(convreadm(c, &resp) < 0) - goto out; - - c->state = "authwrite"; - switch(chapresp(&s, user, resp)){ - default: - fprint(2, "factotum: bad result from chapresp\n"); - goto out; - case -1: - goto out; - case 0: - c->state = "write status"; - if(convprint(c, "bad authentication failed") < 0) - goto out; - goto out; - - case 1: - c->state = "write status"; - if(convprint(c, "ok") < 0) - goto out; - goto ok; - } - -ok: - ret = 0; - c->attr = addcap(c->attr, c->sysuser, &s.t); - -out: - keyclose(s.k); - free(user); - free(resp); -// xioclose(s.asfd); - return ret; -} - -static int -chapchal(ServerState *s, int astype, char chal[ChapChallen]) -{ - char trbuf[TICKREQLEN]; - Ticketreq tr; - - memset(&tr, 0, sizeof tr); - - tr.type = astype; - - if(strlen(s->hostid) >= sizeof tr.hostid){ - werrstr("hostid too long"); - return -1; - } - strcpy(tr.hostid, s->hostid); - - if(strlen(s->dom) >= sizeof tr.authdom){ - werrstr("domain too long"); - return -1; - } - strcpy(tr.authdom, s->dom); - - convTR2M(&tr, trbuf); - if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN) - return -1; - - if(xioasrdresp(s->asfd, chal, ChapChallen) <= 5) - return -1; - - s->tr = tr; - return 0; -} - -static int -chapresp(ServerState *s, char *user, char *resp) -{ - char tabuf[TICKETLEN+AUTHENTLEN]; - char trbuf[TICKREQLEN]; - int len; - Authenticator a; - Ticket t; - Ticketreq tr; - - tr = s->tr; - if(memrandom(tr.chal, CHALLEN) < 0) - return -1; - - if(strlen(user) >= sizeof tr.uid){ - werrstr("uid too long"); - return -1; - } - strcpy(tr.uid, user); - - convTR2M(&tr, trbuf); - if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN) - return -1; - - len = strlen(resp); - if(xiowrite(s->asfd, resp, len) != len) - return -1; - - if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN) - return 0; - - convM2T(tabuf, &t, s->k->priv); - if(t.num != AuthTs - || memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){ - werrstr("key mismatch with auth server"); - return -1; - } - - convM2A(tabuf+TICKETLEN, &a, t.key); - if(a.num != AuthAc - || memcmp(a.chal, tr.chal, sizeof a.chal) != 0 - || a.id != 0){ - werrstr("key2 mismatch with auth server"); - return -1; - } - - s->t = t; - return 1; -} - -static Role -chaproles[] = -{ - "client", chapclient, - "server", chapserver, - 0 -}; - -Proto chap = { -.name= "chap", -.roles= chaproles, -.checkkey= chapcheck, -.keyprompt= "user? !password?", -}; - -Proto mschap = { -.name= "mschap", -.roles= chaproles, -.checkkey= chapcheck, -.keyprompt= "user? !password?", -}; - |