aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/factotum/chap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/factotum/chap.c')
-rw-r--r--src/cmd/factotum/chap.c424
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?",
-};
-