chap.c revision 23968
18097Sjkh/*
28097Sjkh *			PPP CHAP Module
38097Sjkh *
48097Sjkh *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
58097Sjkh *
68097Sjkh *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
729628Sjkh *
88097Sjkh * Redistribution and use in source and binary forms are permitted
98097Sjkh * provided that the above copyright notice and this paragraph are
108097Sjkh * duplicated in all such forms and that any documentation,
118097Sjkh * advertising materials, and other materials related to such
128097Sjkh * distribution and use acknowledge that the software was developed
138097Sjkh * by the Internet Initiative Japan, Inc.  The name of the
148097Sjkh * IIJ may not be used to endorse or promote products derived
158097Sjkh * from this software without specific prior written permission.
168881Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
178881Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
188097Sjkh * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198097Sjkh *
208097Sjkh * $Id: chap.c,v 1.11 1997/03/10 08:04:13 ache Exp $
218097Sjkh *
228097Sjkh *	TODO:
238097Sjkh */
248097Sjkh#include <sys/types.h>
258097Sjkh#include <time.h>
268097Sjkh#include "fsm.h"
278097Sjkh#include "chap.h"
288097Sjkh#include "lcpproto.h"
298097Sjkh#include "lcp.h"
308097Sjkh#include "hdlc.h"
318097Sjkh#include "phase.h"
328097Sjkh#include "vars.h"
338097Sjkh#include "auth.h"
348097Sjkh
358097Sjkhstatic char *chapcodes[] = {
368097Sjkh  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
378097Sjkh};
388097Sjkh
398825Sjkhstruct authinfo AuthChapInfo  = {
408825Sjkh  SendChapChallenge,
418097Sjkh};
428837Sjkh
438837Sjkhextern char *AuthGetSecret();
448837Sjkhextern int randinit;
4512661Speter
4612661Spetervoid
4712661SpeterChapOutput(code, id, ptr, count)
488837Sjkhu_int code, id;
498837Sjkhu_char *ptr;
508262Sjkhint count;
518262Sjkh{
528262Sjkh  int plen;
538262Sjkh  struct fsmheader lh;
548262Sjkh  struct mbuf *bp;
558262Sjkh
568262Sjkh  plen =  sizeof(struct fsmheader) + count;
578262Sjkh  lh.code = code;
5815416Sjkh  lh.id = id;
598262Sjkh  lh.length = htons(plen);
608347Sjkh  bp = mballoc(plen, MB_FSM);
618262Sjkh  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
628262Sjkh  if (count)
638314Sjkh    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
6417375Sjkh#ifdef DEBUG
658262Sjkh  DumpBp(bp);
668262Sjkh#endif
678262Sjkh  LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
688262Sjkh  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
698097Sjkh}
708097Sjkh
718097Sjkh
728097Sjkhstatic char challenge_data[80];
738097Sjkhstatic int  challenge_len;
748097Sjkh
758705Sjkhvoid
768705SjkhSendChapChallenge(chapid)
778097Sjkhint chapid;
788705Sjkh{
798641Sjkh  int len, i;
808641Sjkh  char *cp;
8117375Sjkh
828641Sjkh  if (!randinit) {
838641Sjkh    srandom((unsigned long)(time(NULL) ^ getpid()));
848641Sjkh    randinit = 1;
8515416Sjkh  }
868097Sjkh
878347Sjkh  cp = challenge_data;
888097Sjkh  *cp++ = challenge_len = random() % 32 + 16;
898705Sjkh  for (i = 0; i < challenge_len; i++)
908705Sjkh    *cp++ = random() & 0xff;
918705Sjkh  len = strlen(VarAuthName);
928705Sjkh  bcopy(VarAuthName, cp, len);
938705Sjkh  cp += len;
948705Sjkh  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
958705Sjkh}
968705Sjkh
9716366Sjkh#ifdef DEBUG
9817375Sjkhvoid
998262SjkhDumpDigest(mes, cp, len)
10017375Sjkhchar *mes;
1018262Sjkhchar *cp;
1028097Sjkhint len;
1038097Sjkh{
1048097Sjkh  int i;
1058097Sjkh
1068097Sjkh  logprintf("%s: ", mes);
1078097Sjkh  for (i = 0; i < len; i++) {
1088097Sjkh    logprintf(" %02x", *cp++ & 0xff);
1098097Sjkh  }
1108262Sjkh  logprintf("\n");
1118097Sjkh}
11215416Sjkh#endif
1138097Sjkh
1148097Sjkhvoid
1158097SjkhRecvChapTalk(chp, bp)
1168097Sjkhstruct fsmheader *chp;
1178262Sjkhstruct mbuf *bp;
1188097Sjkh{
11916366Sjkh  int valsize, len;
12017375Sjkh  int arglen, keylen, namelen;
1218262Sjkh  char *cp, *argp, *ap, *name, *digest;
1228262Sjkh  char *keyp;
1238837Sjkh  MD5_CTX context;                            /* context */
1248628Sjkh  char answer[100];
1258097Sjkh  char cdigest[16];
1268097Sjkh
1278097Sjkh  len = ntohs(chp->length);
1288097Sjkh#ifdef DEBUG
1298097Sjkh  logprintf("length: %d\n", len);
1308097Sjkh#endif
1318097Sjkh  arglen = len - sizeof(struct fsmheader);
1328097Sjkh  cp = (char *)MBUF_CTOP(bp);
1338262Sjkh  valsize = *cp++ & 255;
1348097Sjkh  name = cp + valsize;
13515416Sjkh  namelen = arglen - valsize - 1;
1368097Sjkh  name[namelen] = 0;
1378097Sjkh  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
1388097Sjkh
1398097Sjkh  /*
1408097Sjkh   * Get a secret key corresponds to the peer
1418262Sjkh   */
14216366Sjkh  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
14317375Sjkh
1448262Sjkh  switch (chp->code) {
1458262Sjkh  case CHAP_CHALLENGE:
1468837Sjkh    if (keyp) {
1478628Sjkh      keylen = strlen(keyp);
1488097Sjkh    } else {
1498097Sjkh      keylen = strlen(VarAuthKey);
1508097Sjkh      keyp = VarAuthKey;
1518097Sjkh    }
1528097Sjkh    name = VarAuthName;
1538097Sjkh    namelen = strlen(VarAuthName);
1548097Sjkh    argp = malloc(1 + valsize + namelen + 16);
1558097Sjkh    digest = argp;
1568262Sjkh    *digest++ = 16;		/* value size */
1578097Sjkh    ap = answer;
15815416Sjkh    *ap++ = chp->id;
1598097Sjkh    bcopy(keyp, ap, keylen);
1608097Sjkh    ap += keylen;
1618097Sjkh    bcopy(cp, ap, valsize);
1628097Sjkh#ifdef DEBUG
1638097Sjkh    DumpDigest("recv", ap, valsize);
1648262Sjkh#endif
16516366Sjkh    ap += valsize;
16617375Sjkh    MD5Init(&context);
1678097Sjkh    MD5Update(&context, answer, ap - answer);
1688097Sjkh    MD5Final(digest, &context);
1698097Sjkh#ifdef DEBUG
1708097Sjkh    DumpDigest("answer", digest, 16);
1718097Sjkh#endif
1728097Sjkh    bcopy(name, digest + 16, namelen);
1738262Sjkh    ap += namelen;
1748262Sjkh    /* Send answer to the peer */
1758628Sjkh    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
1768628Sjkh    free(argp);
1778097Sjkh    break;
17815788Sjkh  case CHAP_RESPONSE:
1798097Sjkh    if (keyp) {
1808097Sjkh      /*
1818208Sjkh       * Compute correct digest value
1828208Sjkh       */
1838208Sjkh      keylen = strlen(keyp);
1848208Sjkh      ap = answer;
1858208Sjkh      *ap++ = chp->id;
1868208Sjkh      bcopy(keyp, ap, keylen);
1878208Sjkh      ap += keylen;
18815416Sjkh      MD5Init(&context);
1898208Sjkh      MD5Update(&context, answer, ap - answer);
1908208Sjkh      MD5Update(&context, challenge_data+1, challenge_len);
1918208Sjkh      MD5Final(cdigest, &context);
1928208Sjkh#ifdef DEBUG
1938208Sjkh      DumpDigest("got", cp, 16);
1948640Sjkh      DumpDigest("expect", cdigest, 16);
1959202Srgrimes#endif
1968641Sjkh      /*
1978640Sjkh       * Compare with the response
1988556Sjkh       */
1998208Sjkh      if (bcmp(cp, cdigest, 16) == 0) {
2008208Sjkh	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
2018302Sjkh	NewPhase(PHASE_NETWORK);
2028302Sjkh	break;
2038302Sjkh      }
2048302Sjkh    }
2058302Sjkh    /*
2068302Sjkh     * Peer is not registerd, or response digest is wrong.
2078302Sjkh     */
20815416Sjkh    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
2098302Sjkh    LcpClose();
2108302Sjkh    break;
2118302Sjkh  }
2128302Sjkh}
2138302Sjkh
2148837Sjkhvoid
2158837SjkhRecvChapResult(chp, bp)
21617404Sjkhstruct fsmheader *chp;
21729628Sjkhstruct mbuf *bp;
2188302Sjkh{
2198302Sjkh  int len;
2208208Sjkh  struct lcpstate *lcp = &LcpInfo;
2218208Sjkh
2228208Sjkh  len = ntohs(chp->length);
2238208Sjkh#ifdef DEBUG
2248208Sjkh  logprintf("length: %d\n", len);
2258208Sjkh#endif
2268208Sjkh  if (chp->code == CHAP_SUCCESS) {
2278208Sjkh    if (lcp->auth_iwait == PROTO_CHAP) {
22815416Sjkh      lcp->auth_iwait = 0;
2298208Sjkh      if (lcp->auth_ineed == 0)
2308208Sjkh	NewPhase(PHASE_NETWORK);
2318208Sjkh    }
2328208Sjkh  } else {
2338208Sjkh    /*
2348640Sjkh     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2359202Srgrimes     */
2368641Sjkh    ;
2378640Sjkh  }
2388281Sjkh}
2398208Sjkh
2408208Sjkhvoid
2418262SjkhChapInput(struct mbuf *bp)
2428262Sjkh{
2438262Sjkh  int len = plength(bp);
2448262Sjkh  struct fsmheader *chp;
2458262Sjkh
2468262Sjkh  if (len >= sizeof(struct fsmheader)) {
2478262Sjkh    chp = (struct fsmheader *)MBUF_CTOP(bp);
2488278Sjkh    if (len >= ntohs(chp->length)) {
2498262Sjkh      if (chp->code < 1 || chp->code > 4)
2508262Sjkh	chp->code = 0;
25115416Sjkh      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
2528262Sjkh
2538262Sjkh      bp->offset += sizeof(struct fsmheader);
2548262Sjkh      bp->cnt -= sizeof(struct fsmheader);
2558262Sjkh
2568262Sjkh      switch (chp->code) {
2578302Sjkh      case CHAP_RESPONSE:
25820247Sjkh	StopAuthTimer(&AuthChapInfo);
2598302Sjkh	/* Fall into.. */
2608302Sjkh      case CHAP_CHALLENGE:
2618640Sjkh	RecvChapTalk(chp, bp);
2629202Srgrimes	break;
2638641Sjkh      case CHAP_SUCCESS:
2648640Sjkh      case CHAP_FAILURE:
2658262Sjkh	RecvChapResult(chp, bp);
2668262Sjkh	break;
2678262Sjkh      }
2688262Sjkh    }
2698262Sjkh  }
2708262Sjkh  pfree(bp);
2718262Sjkh}
2728347Sjkh