chap.c revision 13379
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.
198857Srgrimes *
2013379Sphk * $Id: chap.c,v 1.3 1995/05/30 03:50:28 rgrimes Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai */
2413379Sphk#include <sys/types.h>
2513379Sphk#include <time.h>
266059Samurai#include "fsm.h"
276059Samurai#include "chap.h"
286059Samurai#include "lcpproto.h"
296059Samurai#include "lcp.h"
306059Samurai#include "hdlc.h"
316059Samurai#include "phase.h"
326059Samurai#include "vars.h"
336735Samurai#include "auth.h"
346059Samurai
356059Samuraistatic char *chapcodes[] = {
366059Samurai  "???", "CHALLENGE", "RESPONCE", "SUCCESS", "FAILURE"
376059Samurai};
386059Samurai
396735Samuraistruct authinfo AuthChapInfo  = {
406735Samurai  SendChapChallenge,
416735Samurai};
426735Samurai
436059Samuraiextern char *AuthGetSecret();
446059Samurai
456059Samuraivoid
466059SamuraiChapOutput(code, id, ptr, count)
476059Samuraiu_int code, id;
486059Samuraiu_char *ptr;
496059Samuraiint count;
506059Samurai{
516059Samurai  int plen;
526059Samurai  struct fsmheader lh;
536059Samurai  struct mbuf *bp;
546059Samurai
556059Samurai  plen =  sizeof(struct fsmheader) + count;
566059Samurai  lh.code = code;
576059Samurai  lh.id = id;
586059Samurai  lh.length = htons(plen);
596059Samurai  bp = mballoc(plen, MB_FSM);
606059Samurai  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
616059Samurai  if (count)
626059Samurai    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
636059Samurai#ifdef DEBUG
646059Samurai  DumpBp(bp);
656059Samurai#endif
666059Samurai  LogPrintf(LOG_LCP, "ChapOutput: %s\n", chapcodes[code]);
676059Samurai  HdlcOutput(PRI_NORMAL, PROTO_CHAP, bp);
686059Samurai}
696059Samurai
706059Samurai
716059Samuraistatic char challenge_data[80];
726059Samuraistatic int  challenge_len;
736059Samurai
746059Samuraivoid
756735SamuraiSendChapChallenge(chapid)
766735Samuraiint chapid;
776059Samurai{
7813379Sphk  int len, i;
796059Samurai  char *cp;
806059Samurai
816059Samurai  srandom(time(NULL));
826059Samurai
836059Samurai  cp = challenge_data;
846059Samurai  *cp++ = challenge_len = random() % 32 + 16;
856059Samurai  for (i = 0; i < challenge_len; i++)
866059Samurai    *cp++ = random() & 0xff;
876059Samurai  len = strlen(VarAuthName);
886059Samurai  bcopy(VarAuthName, cp, len);
896059Samurai  cp += len;
906059Samurai  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
916059Samurai}
926059Samurai
936059Samurai#ifdef DEBUG
946059Samuraivoid
956059SamuraiDumpDigest(mes, cp, len)
966059Samuraichar *mes;
976059Samuraichar *cp;
986735Samuraiint len;
996059Samurai{
1006059Samurai  int i;
1016059Samurai
1026059Samurai  logprintf("%s: ", mes);
1036059Samurai  for (i = 0; i < len; i++) {
1046059Samurai    logprintf(" %02x", *cp++ & 0xff);
1056059Samurai  }
1066059Samurai  logprintf("\n");
1076059Samurai}
1086059Samurai#endif
1096059Samurai
1106059Samuraivoid
1116059SamuraiRecvChapTalk(chp, bp)
1126059Samuraistruct fsmheader *chp;
1136059Samuraistruct mbuf *bp;
1146059Samurai{
1156059Samurai  int valsize, len;
1166059Samurai  int arglen, keylen, namelen;
1176059Samurai  char *cp, *argp, *ap, *name, *digest;
1186059Samurai  char *keyp;
1196059Samurai  MD5_CTX context;                            /* context */
1206059Samurai  char answer[100];
1216059Samurai  char cdigest[16];
1226059Samurai
1236059Samurai  len = ntohs(chp->length);
1246059Samurai#ifdef DEBUG
1256059Samurai  logprintf("length: %d\n", len);
1266059Samurai#endif
1276059Samurai  arglen = len - sizeof(struct fsmheader);
1286059Samurai  cp = (char *)MBUF_CTOP(bp);
1296059Samurai  valsize = *cp++ & 255;
1306059Samurai  name = cp + valsize;
1316059Samurai  namelen = arglen - valsize - 1;
1326059Samurai  name[namelen] = 0;
1336059Samurai  LogPrintf(LOG_PHASE, " Valsize = %d, Name = %s\n", valsize, name);
1346059Samurai
1356059Samurai  /*
1366059Samurai   * Get a secret key corresponds to the peer
1376059Samurai   */
1386059Samurai  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
1396059Samurai
1406059Samurai  switch (chp->code) {
1416059Samurai  case CHAP_CHALLENGE:
1426059Samurai    if (keyp) {
1436059Samurai      keylen = strlen(keyp);
1446059Samurai    } else {
1456059Samurai      keylen = strlen(VarAuthKey);
1466059Samurai      keyp = VarAuthKey;
1476059Samurai    }
1486059Samurai    name = VarAuthName;
1496059Samurai    namelen = strlen(VarAuthName);
1506059Samurai    argp = malloc(1 + valsize + namelen);
1516059Samurai    digest = argp;
1526059Samurai    *digest++ = 16;		/* value size */
1536059Samurai    ap = answer;
1546059Samurai    *ap++ = chp->id;
1556059Samurai    bcopy(keyp, ap, keylen);
1566059Samurai    ap += keylen;
1576059Samurai    bcopy(cp, ap, valsize);
1586059Samurai#ifdef DEBUG
1596059Samurai    DumpDigest("recv", ap, valsize);
1606059Samurai#endif
1616059Samurai    ap += valsize;
1626059Samurai    MD5Init(&context);
1636059Samurai    MD5Update(&context, answer, ap - answer);
1646059Samurai    MD5Final(digest, &context);
1656059Samurai#ifdef DEBUG
1666059Samurai    DumpDigest("answer", digest, 16);
1676059Samurai#endif
1686059Samurai    bcopy(name, digest + 16, namelen);
1696059Samurai    ap += namelen;
1706059Samurai    /* Send answer to the peer */
1716059Samurai    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
1726059Samurai    break;
1736059Samurai  case CHAP_RESPONSE:
1746059Samurai    if (keyp) {
1756059Samurai      /*
1766059Samurai       * Compute correct digest value
1776059Samurai       */
1786059Samurai      keylen = strlen(keyp);
1796059Samurai      ap = answer;
1806059Samurai      *ap++ = chp->id;
1816059Samurai      bcopy(keyp, ap, keylen);
1826059Samurai      ap += keylen;
1836059Samurai      MD5Init(&context);
1846059Samurai      MD5Update(&context, answer, ap - answer);
1856059Samurai      MD5Update(&context, challenge_data+1, challenge_len);
1866059Samurai      MD5Final(cdigest, &context);
1876059Samurai#ifdef DEBUG
1886059Samurai      DumpDigest("got", cp, 16);
1896059Samurai      DumpDigest("expect", cdigest, 16);
1906059Samurai#endif
1916059Samurai      /*
1926059Samurai       * Compare with the response
1936059Samurai       */
1946059Samurai      if (bcmp(cp, cdigest, 16) == 0) {
1956059Samurai	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
1966059Samurai	NewPhase(PHASE_NETWORK);
1976059Samurai	break;
1986059Samurai      }
1996059Samurai    }
2006059Samurai    /*
2016059Samurai     * Peer is not registerd, or response digest is wrong.
2026059Samurai     */
2036059Samurai    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
2046059Samurai    LcpClose();
2056059Samurai    break;
2066059Samurai  }
2076059Samurai}
2086059Samurai
2096059Samuraivoid
2106059SamuraiRecvChapResult(chp, bp)
2116059Samuraistruct fsmheader *chp;
2126059Samuraistruct mbuf *bp;
2136059Samurai{
2146059Samurai  int len;
2156059Samurai  struct lcpstate *lcp = &LcpInfo;
2166059Samurai
2176059Samurai  len = ntohs(chp->length);
2186059Samurai#ifdef DEBUG
2196059Samurai  logprintf("length: %d\n", len);
2206059Samurai#endif
2216059Samurai  if (chp->code == CHAP_SUCCESS) {
2226059Samurai    if (lcp->auth_iwait == PROTO_CHAP) {
2236059Samurai      lcp->auth_iwait = 0;
2246059Samurai      if (lcp->auth_ineed == 0)
2256059Samurai	NewPhase(PHASE_NETWORK);
2266059Samurai    }
2276059Samurai  } else {
2286059Samurai    /*
2296059Samurai     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2306059Samurai     */
2316059Samurai    ;
2326059Samurai  }
2336059Samurai}
2346059Samurai
2356059Samuraivoid
2366059SamuraiChapInput(struct mbuf *bp)
2376059Samurai{
2386059Samurai  int len = plength(bp);
2396059Samurai  struct fsmheader *chp;
2406059Samurai
2416059Samurai  if (len >= sizeof(struct fsmheader)) {
2426059Samurai    chp = (struct fsmheader *)MBUF_CTOP(bp);
2436059Samurai    if (len >= ntohs(chp->length)) {
2446059Samurai      if (chp->code < 1 || chp->code > 4)
2456059Samurai	chp->code = 0;
2466059Samurai      LogPrintf(LOG_LCP, "ChapInput: %s\n", chapcodes[chp->code]);
2476059Samurai
2486059Samurai      bp->offset += sizeof(struct fsmheader);
2496059Samurai      bp->cnt -= sizeof(struct fsmheader);
2506059Samurai
2516059Samurai      switch (chp->code) {
2526735Samurai      case CHAP_RESPONSE:
2536735Samurai	StopAuthTimer(&AuthChapInfo);
2546735Samurai	/* Fall into.. */
2556059Samurai      case CHAP_CHALLENGE:
2566059Samurai	RecvChapTalk(chp, bp);
2576059Samurai	break;
2586059Samurai      case CHAP_SUCCESS:
2596059Samurai      case CHAP_FAILURE:
2606059Samurai	RecvChapResult(chp, bp);
2616059Samurai	break;
2626059Samurai      }
2636059Samurai    }
2646059Samurai  }
2656059Samurai  pfree(bp);
2666059Samurai}
267