chap.c revision 23603
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 *
2023603Sache * $Id: chap.c,v 1.10 1997/02/22 16:10:05 peter 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[] = {
3619866Sphk  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
376059Samurai};
386059Samurai
396735Samuraistruct authinfo AuthChapInfo  = {
406735Samurai  SendChapChallenge,
416735Samurai};
426735Samurai
436059Samuraiextern char *AuthGetSecret();
4423603Sacheextern int randinit;
456059Samurai
466059Samuraivoid
476059SamuraiChapOutput(code, id, ptr, count)
486059Samuraiu_int code, id;
496059Samuraiu_char *ptr;
506059Samuraiint count;
516059Samurai{
526059Samurai  int plen;
536059Samurai  struct fsmheader lh;
546059Samurai  struct mbuf *bp;
556059Samurai
566059Samurai  plen =  sizeof(struct fsmheader) + count;
576059Samurai  lh.code = code;
586059Samurai  lh.id = id;
596059Samurai  lh.length = htons(plen);
606059Samurai  bp = mballoc(plen, MB_FSM);
616059Samurai  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
626059Samurai  if (count)
636059Samurai    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
646059Samurai#ifdef DEBUG
656059Samurai  DumpBp(bp);
666059Samurai#endif
6715738Sphk  LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
6813733Sdfr  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
696059Samurai}
706059Samurai
716059Samurai
726059Samuraistatic char challenge_data[80];
736059Samuraistatic int  challenge_len;
746059Samurai
756059Samuraivoid
766735SamuraiSendChapChallenge(chapid)
776735Samuraiint chapid;
786059Samurai{
7913379Sphk  int len, i;
806059Samurai  char *cp;
816059Samurai
8223603Sache  if (!randinit) {
8323603Sache    srandom((unsigned)(time(NULL) ^ getpid()));
8423603Sache    randinit = 1;
8523603Sache  }
866059Samurai
876059Samurai  cp = challenge_data;
886059Samurai  *cp++ = challenge_len = random() % 32 + 16;
896059Samurai  for (i = 0; i < challenge_len; i++)
906059Samurai    *cp++ = random() & 0xff;
916059Samurai  len = strlen(VarAuthName);
926059Samurai  bcopy(VarAuthName, cp, len);
936059Samurai  cp += len;
946059Samurai  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
956059Samurai}
966059Samurai
976059Samurai#ifdef DEBUG
986059Samuraivoid
996059SamuraiDumpDigest(mes, cp, len)
1006059Samuraichar *mes;
1016059Samuraichar *cp;
1026735Samuraiint len;
1036059Samurai{
1046059Samurai  int i;
1056059Samurai
1066059Samurai  logprintf("%s: ", mes);
1076059Samurai  for (i = 0; i < len; i++) {
1086059Samurai    logprintf(" %02x", *cp++ & 0xff);
1096059Samurai  }
1106059Samurai  logprintf("\n");
1116059Samurai}
1126059Samurai#endif
1136059Samurai
1146059Samuraivoid
1156059SamuraiRecvChapTalk(chp, bp)
1166059Samuraistruct fsmheader *chp;
1176059Samuraistruct mbuf *bp;
1186059Samurai{
1196059Samurai  int valsize, len;
1206059Samurai  int arglen, keylen, namelen;
1216059Samurai  char *cp, *argp, *ap, *name, *digest;
1226059Samurai  char *keyp;
1236059Samurai  MD5_CTX context;                            /* context */
1246059Samurai  char answer[100];
1256059Samurai  char cdigest[16];
1266059Samurai
1276059Samurai  len = ntohs(chp->length);
1286059Samurai#ifdef DEBUG
1296059Samurai  logprintf("length: %d\n", len);
1306059Samurai#endif
1316059Samurai  arglen = len - sizeof(struct fsmheader);
1326059Samurai  cp = (char *)MBUF_CTOP(bp);
1336059Samurai  valsize = *cp++ & 255;
1346059Samurai  name = cp + valsize;
1356059Samurai  namelen = arglen - valsize - 1;
1366059Samurai  name[namelen] = 0;
13715738Sphk  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
1386059Samurai
1396059Samurai  /*
1406059Samurai   * Get a secret key corresponds to the peer
1416059Samurai   */
1426059Samurai  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
1436059Samurai
1446059Samurai  switch (chp->code) {
1456059Samurai  case CHAP_CHALLENGE:
1466059Samurai    if (keyp) {
1476059Samurai      keylen = strlen(keyp);
1486059Samurai    } else {
1496059Samurai      keylen = strlen(VarAuthKey);
1506059Samurai      keyp = VarAuthKey;
1516059Samurai    }
1526059Samurai    name = VarAuthName;
1536059Samurai    namelen = strlen(VarAuthName);
15418885Sjkh    argp = malloc(1 + valsize + namelen + 16);
1556059Samurai    digest = argp;
1566059Samurai    *digest++ = 16;		/* value size */
1576059Samurai    ap = answer;
1586059Samurai    *ap++ = chp->id;
1596059Samurai    bcopy(keyp, ap, keylen);
1606059Samurai    ap += keylen;
1616059Samurai    bcopy(cp, ap, valsize);
1626059Samurai#ifdef DEBUG
1636059Samurai    DumpDigest("recv", ap, valsize);
1646059Samurai#endif
1656059Samurai    ap += valsize;
1666059Samurai    MD5Init(&context);
1676059Samurai    MD5Update(&context, answer, ap - answer);
1686059Samurai    MD5Final(digest, &context);
1696059Samurai#ifdef DEBUG
1706059Samurai    DumpDigest("answer", digest, 16);
1716059Samurai#endif
1726059Samurai    bcopy(name, digest + 16, namelen);
1736059Samurai    ap += namelen;
1746059Samurai    /* Send answer to the peer */
1756059Samurai    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
17618885Sjkh    free(argp);
1776059Samurai    break;
1786059Samurai  case CHAP_RESPONSE:
1796059Samurai    if (keyp) {
1806059Samurai      /*
1816059Samurai       * Compute correct digest value
1826059Samurai       */
1836059Samurai      keylen = strlen(keyp);
1846059Samurai      ap = answer;
1856059Samurai      *ap++ = chp->id;
1866059Samurai      bcopy(keyp, ap, keylen);
1876059Samurai      ap += keylen;
1886059Samurai      MD5Init(&context);
1896059Samurai      MD5Update(&context, answer, ap - answer);
1906059Samurai      MD5Update(&context, challenge_data+1, challenge_len);
1916059Samurai      MD5Final(cdigest, &context);
1926059Samurai#ifdef DEBUG
1936059Samurai      DumpDigest("got", cp, 16);
1946059Samurai      DumpDigest("expect", cdigest, 16);
1956059Samurai#endif
1966059Samurai      /*
1976059Samurai       * Compare with the response
1986059Samurai       */
1996059Samurai      if (bcmp(cp, cdigest, 16) == 0) {
2006059Samurai	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
2016059Samurai	NewPhase(PHASE_NETWORK);
2026059Samurai	break;
2036059Samurai      }
2046059Samurai    }
2056059Samurai    /*
2066059Samurai     * Peer is not registerd, or response digest is wrong.
2076059Samurai     */
2086059Samurai    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
2096059Samurai    LcpClose();
2106059Samurai    break;
2116059Samurai  }
2126059Samurai}
2136059Samurai
2146059Samuraivoid
2156059SamuraiRecvChapResult(chp, bp)
2166059Samuraistruct fsmheader *chp;
2176059Samuraistruct mbuf *bp;
2186059Samurai{
2196059Samurai  int len;
2206059Samurai  struct lcpstate *lcp = &LcpInfo;
2216059Samurai
2226059Samurai  len = ntohs(chp->length);
2236059Samurai#ifdef DEBUG
2246059Samurai  logprintf("length: %d\n", len);
2256059Samurai#endif
2266059Samurai  if (chp->code == CHAP_SUCCESS) {
2276059Samurai    if (lcp->auth_iwait == PROTO_CHAP) {
2286059Samurai      lcp->auth_iwait = 0;
2296059Samurai      if (lcp->auth_ineed == 0)
2306059Samurai	NewPhase(PHASE_NETWORK);
2316059Samurai    }
2326059Samurai  } else {
2336059Samurai    /*
2346059Samurai     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2356059Samurai     */
2366059Samurai    ;
2376059Samurai  }
2386059Samurai}
2396059Samurai
2406059Samuraivoid
2416059SamuraiChapInput(struct mbuf *bp)
2426059Samurai{
2436059Samurai  int len = plength(bp);
2446059Samurai  struct fsmheader *chp;
2456059Samurai
2466059Samurai  if (len >= sizeof(struct fsmheader)) {
2476059Samurai    chp = (struct fsmheader *)MBUF_CTOP(bp);
2486059Samurai    if (len >= ntohs(chp->length)) {
2496059Samurai      if (chp->code < 1 || chp->code > 4)
2506059Samurai	chp->code = 0;
25115738Sphk      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
2526059Samurai
2536059Samurai      bp->offset += sizeof(struct fsmheader);
2546059Samurai      bp->cnt -= sizeof(struct fsmheader);
2556059Samurai
2566059Samurai      switch (chp->code) {
2576735Samurai      case CHAP_RESPONSE:
2586735Samurai	StopAuthTimer(&AuthChapInfo);
2596735Samurai	/* Fall into.. */
2606059Samurai      case CHAP_CHALLENGE:
2616059Samurai	RecvChapTalk(chp, bp);
2626059Samurai	break;
2636059Samurai      case CHAP_SUCCESS:
2646059Samurai      case CHAP_FAILURE:
2656059Samurai	RecvChapResult(chp, bp);
2666059Samurai	break;
2676059Samurai      }
2686059Samurai    }
2696059Samurai  }
2706059Samurai  pfree(bp);
2716059Samurai}
272