chap.c revision 6735
16059Samurai/*
26059Samurai *			PPP CHAP Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196735Samurai *
206059Samurai * $Id:$
216735Samurai *
226059Samurai *	TODO:
236059Samurai */
246059Samurai#include "fsm.h"
256059Samurai#include "chap.h"
266059Samurai#include "lcpproto.h"
276059Samurai#include "lcp.h"
286059Samurai#include "hdlc.h"
296059Samurai#include "phase.h"
306059Samurai#include "vars.h"
316735Samurai#include "auth.h"
326059Samurai
336059Samuraistatic char *chapcodes[] = {
346059Samurai  "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
356059Samurai};
366059Samurai
376735Samuraistruct authinfo AuthChapInfo  = {
386735Samurai  SendChapChallenge,
396735Samurai};
406735Samurai
416059Samuraiextern char *AuthGetSecret();
426059Samurai
436059Samuraivoid
446059SamuraiChapOutput(code, id, ptr, count)
456059Samuraiu_int code, id;
466059Samuraiu_char *ptr;
476059Samuraiint count;
486059Samurai{
496059Samurai  int plen;
506059Samurai  struct fsmheader lh;
516059Samurai  struct mbuf *bp;
526059Samurai
536059Samurai  plen =  sizeof(struct fsmheader) + count;
546059Samurai  lh.code = code;
556059Samurai  lh.id = id;
566059Samurai  lh.length = htons(plen);
576059Samurai  bp = mballoc(plen, MB_FSM);
586059Samurai  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
596059Samurai  if (count)
606059Samurai    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
616059Samurai#ifdef DEBUG
626059Samurai  DumpBp(bp);
636059Samurai#endif
646059Samurai  LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
656059Samurai  HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
666059Samurai}
676059Samurai
686059Samurai
696059Samuraistatic char challenge_data[80];
706059Samuraistatic int  challenge_len;
716059Samurai
726059Samuraivoid
736735SamuraiSendChapChallenge(chapid)
746735Samuraiint chapid;
756059Samurai{
766059Samurai  int keylen, len, i;
776059Samurai  char *cp;
786059Samurai
796059Samurai  srandom(time(NULL));
806059Samurai
816059Samurai  cp = challenge_data;
826059Samurai  *cp++ = challenge_len = random() % 32 + 16;
836059Samurai  for (i = 0; i < challenge_len; i++)
846059Samurai    *cp++ = random() & 0xff;
856059Samurai  len = strlen(VarAuthName);
866059Samurai  bcopy(VarAuthName, cp, len);
876059Samurai  cp += len;
886059Samurai  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
896059Samurai}
906059Samurai
916059Samurai#ifdef DEBUG
926059Samuraivoid
936059SamuraiDumpDigest(mes, cp, len)
946059Samuraichar *mes;
956059Samuraichar *cp;
966735Samuraiint len;
976059Samurai{
986059Samurai  int i;
996059Samurai
1006059Samurai  logprintf("%s: ", mes);
1016059Samurai  for (i = 0; i < len; i++) {
1026059Samurai    logprintf(" %02x", *cp++ & 0xff);
1036059Samurai  }
1046059Samurai  logprintf("\n");
1056059Samurai}
1066059Samurai#endif
1076059Samurai
1086059Samuraivoid
1096059SamuraiRecvChapTalk(chp, bp)
1106059Samuraistruct fsmheader *chp;
1116059Samuraistruct mbuf *bp;
1126059Samurai{
1136059Samurai  int valsize, len;
1146059Samurai  int arglen, keylen, namelen;
1156059Samurai  char *cp, *argp, *ap, *name, *digest;
1166059Samurai  char *keyp;
1176059Samurai  MD5_CTX context;                            /* context */
1186059Samurai  char answer[100];
1196059Samurai  char cdigest[16];
1206059Samurai
1216059Samurai  len = ntohs(chp->length);
1226059Samurai#ifdef DEBUG
1236059Samurai  logprintf("length: %d\n", len);
1246059Samurai#endif
1256059Samurai  arglen = len - sizeof(struct fsmheader);
1266059Samurai  cp = (char *)MBUF_CTOP(bp);
1276059Samurai  valsize = *cp++ & 255;
1286059Samurai  name = cp + valsize;
1296059Samurai  namelen = arglen - valsize - 1;
1306059Samurai  name[namelen] = 0;
1316059Samurai  LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
1326059Samurai
1336059Samurai  /*
1346059Samurai   * Get a secret key corresponds to the peer
1356059Samurai   */
1366059Samurai  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
1376059Samurai
1386059Samurai  switch (chp->code) {
1396059Samurai  case CHAP_CHALLENGE:
1406059Samurai    if (keyp) {
1416059Samurai      keylen = strlen(keyp);
1426059Samurai    } else {
1436059Samurai      keylen = strlen(VarAuthKey);
1446059Samurai      keyp = VarAuthKey;
1456059Samurai    }
1466059Samurai    name = VarAuthName;
1476059Samurai    namelen = strlen(VarAuthName);
1486059Samurai    argp = malloc(1 + valsize + namelen);
1496059Samurai    digest = argp;
1506059Samurai    *digest++ = 16;		/* value size */
1516059Samurai    ap = answer;
1526059Samurai    *ap++ = chp->id;
1536059Samurai    bcopy(keyp, ap, keylen);
1546059Samurai    ap += keylen;
1556059Samurai    bcopy(cp, ap, valsize);
1566059Samurai#ifdef DEBUG
1576059Samurai    DumpDigest("recv", ap, valsize);
1586059Samurai#endif
1596059Samurai    ap += valsize;
1606059Samurai    MD5Init(&context);
1616059Samurai    MD5Update(&context, answer, ap - answer);
1626059Samurai    MD5Final(digest, &context);
1636059Samurai#ifdef DEBUG
1646059Samurai    DumpDigest("answer", digest, 16);
1656059Samurai#endif
1666059Samurai    bcopy(name, digest + 16, namelen);
1676059Samurai    ap += namelen;
1686059Samurai    /* Send answer to the peer */
1696059Samurai    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
1706059Samurai    break;
1716059Samurai  case CHAP_RESPONSE:
1726059Samurai    if (keyp) {
1736059Samurai      /*
1746059Samurai       * Compute correct digest value
1756059Samurai       */
1766059Samurai      keylen = strlen(keyp);
1776059Samurai      ap = answer;
1786059Samurai      *ap++ = chp->id;
1796059Samurai      bcopy(keyp, ap, keylen);
1806059Samurai      ap += keylen;
1816059Samurai      MD5Init(&context);
1826059Samurai      MD5Update(&context, answer, ap - answer);
1836059Samurai      MD5Update(&context, challenge_data+1, challenge_len);
1846059Samurai      MD5Final(cdigest, &context);
1856059Samurai#ifdef DEBUG
1866059Samurai      DumpDigest("got", cp, 16);
1876059Samurai      DumpDigest("expect", cdigest, 16);
1886059Samurai#endif
1896059Samurai      /*
1906059Samurai       * Compare with the response
1916059Samurai       */
1926059Samurai      if (bcmp(cp, cdigest, 16) == 0) {
1936059Samurai	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
1946059Samurai	NewPhase(PHASE_NETWORK);
1956059Samurai	break;
1966059Samurai      }
1976059Samurai    }
1986059Samurai    /*
1996059Samurai     * Peer is not registerd, or response digest is wrong.
2006059Samurai     */
2016059Samurai    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
2026059Samurai    LcpClose();
2036059Samurai    break;
2046059Samurai  }
2056059Samurai}
2066059Samurai
2076059Samuraivoid
2086059SamuraiRecvChapResult(chp, bp)
2096059Samuraistruct fsmheader *chp;
2106059Samuraistruct mbuf *bp;
2116059Samurai{
2126059Samurai  int len;
2136059Samurai  struct lcpstate *lcp = &LcpInfo;
2146059Samurai
2156059Samurai  len = ntohs(chp->length);
2166059Samurai#ifdef DEBUG
2176059Samurai  logprintf("length: %d\n", len);
2186059Samurai#endif
2196059Samurai  if (chp->code == CHAP_SUCCESS) {
2206059Samurai    if (lcp->auth_iwait == PROTO_CHAP) {
2216059Samurai      lcp->auth_iwait = 0;
2226059Samurai      if (lcp->auth_ineed == 0)
2236059Samurai	NewPhase(PHASE_NETWORK);
2246059Samurai    }
2256059Samurai  } else {
2266059Samurai    /*
2276059Samurai     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2286059Samurai     */
2296059Samurai    ;
2306059Samurai  }
2316059Samurai}
2326059Samurai
2336059Samuraivoid
2346059SamuraiChapInput(struct mbuf *bp)
2356059Samurai{
2366059Samurai  int len = plength(bp);
2376059Samurai  struct fsmheader *chp;
2386059Samurai
2396059Samurai  if (len >= sizeof(struct fsmheader)) {
2406059Samurai    chp = (struct fsmheader *)MBUF_CTOP(bp);
2416059Samurai    if (len >= ntohs(chp->length)) {
2426059Samurai      if (chp->code < 1 || chp->code > 4)
2436059Samurai	chp->code = 0;
2446059Samurai      LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
2456059Samurai
2466059Samurai      bp->offset += sizeof(struct fsmheader);
2476059Samurai      bp->cnt -= sizeof(struct fsmheader);
2486059Samurai
2496059Samurai      switch (chp->code) {
2506735Samurai      case CHAP_RESPONSE:
2516735Samurai	StopAuthTimer(&AuthChapInfo);
2526735Samurai	/* Fall into.. */
2536059Samurai      case CHAP_CHALLENGE:
2546059Samurai	RecvChapTalk(chp, bp);
2556059Samurai	break;
2566059Samurai      case CHAP_SUCCESS:
2576059Samurai      case CHAP_FAILURE:
2586059Samurai	RecvChapResult(chp, bp);
2596059Samurai	break;
2606059Samurai      }
2616059Samurai    }
2626059Samurai  }
2636059Samurai  pfree(bp);
2646059Samurai}
265