chap.c revision 25630
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 *
2025630Sbrian * $Id: chap.c,v 1.13 1997/03/24 16:01:42 ache 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    randinit = 1;
8424217Sache    if (srandomdev() < 0)
8524217Sache      srandom((unsigned long)(time(NULL) ^ getpid()));
8623603Sache  }
876059Samurai
886059Samurai  cp = challenge_data;
896059Samurai  *cp++ = challenge_len = random() % 32 + 16;
906059Samurai  for (i = 0; i < challenge_len; i++)
916059Samurai    *cp++ = random() & 0xff;
926059Samurai  len = strlen(VarAuthName);
936059Samurai  bcopy(VarAuthName, cp, len);
946059Samurai  cp += len;
956059Samurai  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
966059Samurai}
976059Samurai
986059Samurai#ifdef DEBUG
996059Samuraivoid
1006059SamuraiDumpDigest(mes, cp, len)
1016059Samuraichar *mes;
1026059Samuraichar *cp;
1036735Samuraiint len;
1046059Samurai{
1056059Samurai  int i;
1066059Samurai
1076059Samurai  logprintf("%s: ", mes);
1086059Samurai  for (i = 0; i < len; i++) {
1096059Samurai    logprintf(" %02x", *cp++ & 0xff);
1106059Samurai  }
1116059Samurai  logprintf("\n");
1126059Samurai}
1136059Samurai#endif
1146059Samurai
1156059Samuraivoid
1166059SamuraiRecvChapTalk(chp, bp)
1176059Samuraistruct fsmheader *chp;
1186059Samuraistruct mbuf *bp;
1196059Samurai{
1206059Samurai  int valsize, len;
1216059Samurai  int arglen, keylen, namelen;
1226059Samurai  char *cp, *argp, *ap, *name, *digest;
1236059Samurai  char *keyp;
1246059Samurai  MD5_CTX context;                            /* context */
1256059Samurai  char answer[100];
1266059Samurai  char cdigest[16];
1276059Samurai
1286059Samurai  len = ntohs(chp->length);
1296059Samurai#ifdef DEBUG
1306059Samurai  logprintf("length: %d\n", len);
1316059Samurai#endif
1326059Samurai  arglen = len - sizeof(struct fsmheader);
1336059Samurai  cp = (char *)MBUF_CTOP(bp);
1346059Samurai  valsize = *cp++ & 255;
1356059Samurai  name = cp + valsize;
1366059Samurai  namelen = arglen - valsize - 1;
1376059Samurai  name[namelen] = 0;
13815738Sphk  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
1396059Samurai
1406059Samurai  /*
1416059Samurai   * Get a secret key corresponds to the peer
1426059Samurai   */
1436059Samurai  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
1446059Samurai
1456059Samurai  switch (chp->code) {
1466059Samurai  case CHAP_CHALLENGE:
1476059Samurai    if (keyp) {
1486059Samurai      keylen = strlen(keyp);
1496059Samurai    } else {
1506059Samurai      keylen = strlen(VarAuthKey);
1516059Samurai      keyp = VarAuthKey;
1526059Samurai    }
1536059Samurai    name = VarAuthName;
1546059Samurai    namelen = strlen(VarAuthName);
15518885Sjkh    argp = malloc(1 + valsize + namelen + 16);
15625630Sbrian    if (argp == NULL) {
15725630Sbrian      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
15825630Sbrian      return;
15925630Sbrian    }
1606059Samurai    digest = argp;
1616059Samurai    *digest++ = 16;		/* value size */
1626059Samurai    ap = answer;
1636059Samurai    *ap++ = chp->id;
1646059Samurai    bcopy(keyp, ap, keylen);
1656059Samurai    ap += keylen;
1666059Samurai    bcopy(cp, ap, valsize);
1676059Samurai#ifdef DEBUG
1686059Samurai    DumpDigest("recv", ap, valsize);
1696059Samurai#endif
1706059Samurai    ap += valsize;
1716059Samurai    MD5Init(&context);
1726059Samurai    MD5Update(&context, answer, ap - answer);
1736059Samurai    MD5Final(digest, &context);
1746059Samurai#ifdef DEBUG
1756059Samurai    DumpDigest("answer", digest, 16);
1766059Samurai#endif
1776059Samurai    bcopy(name, digest + 16, namelen);
1786059Samurai    ap += namelen;
1796059Samurai    /* Send answer to the peer */
1806059Samurai    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
18118885Sjkh    free(argp);
1826059Samurai    break;
1836059Samurai  case CHAP_RESPONSE:
1846059Samurai    if (keyp) {
1856059Samurai      /*
1866059Samurai       * Compute correct digest value
1876059Samurai       */
1886059Samurai      keylen = strlen(keyp);
1896059Samurai      ap = answer;
1906059Samurai      *ap++ = chp->id;
1916059Samurai      bcopy(keyp, ap, keylen);
1926059Samurai      ap += keylen;
1936059Samurai      MD5Init(&context);
1946059Samurai      MD5Update(&context, answer, ap - answer);
1956059Samurai      MD5Update(&context, challenge_data+1, challenge_len);
1966059Samurai      MD5Final(cdigest, &context);
1976059Samurai#ifdef DEBUG
1986059Samurai      DumpDigest("got", cp, 16);
1996059Samurai      DumpDigest("expect", cdigest, 16);
2006059Samurai#endif
2016059Samurai      /*
2026059Samurai       * Compare with the response
2036059Samurai       */
2046059Samurai      if (bcmp(cp, cdigest, 16) == 0) {
2056059Samurai	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
2066059Samurai	NewPhase(PHASE_NETWORK);
2076059Samurai	break;
2086059Samurai      }
2096059Samurai    }
2106059Samurai    /*
2116059Samurai     * Peer is not registerd, or response digest is wrong.
2126059Samurai     */
2136059Samurai    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
2146059Samurai    LcpClose();
2156059Samurai    break;
2166059Samurai  }
2176059Samurai}
2186059Samurai
2196059Samuraivoid
2206059SamuraiRecvChapResult(chp, bp)
2216059Samuraistruct fsmheader *chp;
2226059Samuraistruct mbuf *bp;
2236059Samurai{
2246059Samurai  int len;
2256059Samurai  struct lcpstate *lcp = &LcpInfo;
2266059Samurai
2276059Samurai  len = ntohs(chp->length);
2286059Samurai#ifdef DEBUG
2296059Samurai  logprintf("length: %d\n", len);
2306059Samurai#endif
2316059Samurai  if (chp->code == CHAP_SUCCESS) {
2326059Samurai    if (lcp->auth_iwait == PROTO_CHAP) {
2336059Samurai      lcp->auth_iwait = 0;
2346059Samurai      if (lcp->auth_ineed == 0)
2356059Samurai	NewPhase(PHASE_NETWORK);
2366059Samurai    }
2376059Samurai  } else {
2386059Samurai    /*
2396059Samurai     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2406059Samurai     */
2416059Samurai    ;
2426059Samurai  }
2436059Samurai}
2446059Samurai
2456059Samuraivoid
2466059SamuraiChapInput(struct mbuf *bp)
2476059Samurai{
2486059Samurai  int len = plength(bp);
2496059Samurai  struct fsmheader *chp;
2506059Samurai
2516059Samurai  if (len >= sizeof(struct fsmheader)) {
2526059Samurai    chp = (struct fsmheader *)MBUF_CTOP(bp);
2536059Samurai    if (len >= ntohs(chp->length)) {
2546059Samurai      if (chp->code < 1 || chp->code > 4)
2556059Samurai	chp->code = 0;
25615738Sphk      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
2576059Samurai
2586059Samurai      bp->offset += sizeof(struct fsmheader);
2596059Samurai      bp->cnt -= sizeof(struct fsmheader);
2606059Samurai
2616059Samurai      switch (chp->code) {
2626735Samurai      case CHAP_RESPONSE:
2636735Samurai	StopAuthTimer(&AuthChapInfo);
2646735Samurai	/* Fall into.. */
2656059Samurai      case CHAP_CHALLENGE:
2666059Samurai	RecvChapTalk(chp, bp);
2676059Samurai	break;
2686059Samurai      case CHAP_SUCCESS:
2696059Samurai      case CHAP_FAILURE:
2706059Samurai	RecvChapResult(chp, bp);
2716059Samurai	break;
2726059Samurai      }
2736059Samurai    }
2746059Samurai  }
2756059Samurai  pfree(bp);
2766059Samurai}
277