chap.c revision 28679
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 *
2028679Sbrian * $Id: chap.c,v 1.19 1997/06/14 00:21:23 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"
3226142Sbrian#include "loadalias.h"
336059Samurai#include "vars.h"
346735Samurai#include "auth.h"
356059Samurai
366059Samuraistatic char *chapcodes[] = {
3719866Sphk  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
386059Samurai};
396059Samurai
4028679Sbrianstruct authinfo AuthChapInfo = {
416735Samurai  SendChapChallenge,
426735Samurai};
436735Samurai
446059Samuraiextern char *AuthGetSecret();
4523603Sacheextern int randinit;
466059Samurai
476059Samuraivoid
4828679SbrianChapOutput(u_int code, u_int id, u_char * ptr, int count)
496059Samurai{
506059Samurai  int plen;
516059Samurai  struct fsmheader lh;
526059Samurai  struct mbuf *bp;
536059Samurai
5428679Sbrian  plen = sizeof(struct fsmheader) + count;
556059Samurai  lh.code = code;
566059Samurai  lh.id = id;
576059Samurai  lh.length = htons(plen);
586059Samurai  bp = mballoc(plen, MB_FSM);
596059Samurai  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
606059Samurai  if (count)
616059Samurai    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
6226516Sbrian  LogDumpBp(LogDEBUG, "ChapOutput", bp);
6326516Sbrian  LogPrintf(LogLCP, "ChapOutput: %s\n", chapcodes[code]);
6413733Sdfr  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
656059Samurai}
666059Samurai
676059Samurai
686059Samuraistatic char challenge_data[80];
6928679Sbrianstatic int challenge_len;
706059Samurai
716059Samuraivoid
7228679SbrianSendChapChallenge(int chapid)
736059Samurai{
7413379Sphk  int len, i;
756059Samurai  char *cp;
766059Samurai
7723603Sache  if (!randinit) {
7823603Sache    randinit = 1;
7926626Sache    srandomdev();
8023603Sache  }
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
916059Samuraivoid
9228679SbrianRecvChapTalk(struct fsmheader * chp, struct mbuf * bp)
936059Samurai{
946059Samurai  int valsize, len;
956059Samurai  int arglen, keylen, namelen;
966059Samurai  char *cp, *argp, *ap, *name, *digest;
976059Samurai  char *keyp;
9828679Sbrian  MD5_CTX context;		/* context */
996059Samurai  char answer[100];
1006059Samurai  char cdigest[16];
1016059Samurai
1026059Samurai  len = ntohs(chp->length);
10326516Sbrian  LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len);
1046059Samurai  arglen = len - sizeof(struct fsmheader);
10528679Sbrian  cp = (char *) MBUF_CTOP(bp);
1066059Samurai  valsize = *cp++ & 255;
1076059Samurai  name = cp + valsize;
1086059Samurai  namelen = arglen - valsize - 1;
1096059Samurai  name[namelen] = 0;
11026516Sbrian  LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name);
1116059Samurai
1126059Samurai  /*
1136059Samurai   * Get a secret key corresponds to the peer
1146059Samurai   */
1156059Samurai  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
1166059Samurai
1176059Samurai  switch (chp->code) {
1186059Samurai  case CHAP_CHALLENGE:
1196059Samurai    if (keyp) {
1206059Samurai      keylen = strlen(keyp);
1216059Samurai    } else {
1226059Samurai      keylen = strlen(VarAuthKey);
1236059Samurai      keyp = VarAuthKey;
1246059Samurai    }
1256059Samurai    name = VarAuthName;
1266059Samurai    namelen = strlen(VarAuthName);
12718885Sjkh    argp = malloc(1 + valsize + namelen + 16);
12825630Sbrian    if (argp == NULL) {
12925630Sbrian      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
13025630Sbrian      return;
13125630Sbrian    }
1326059Samurai    digest = argp;
1336059Samurai    *digest++ = 16;		/* value size */
1346059Samurai    ap = answer;
1356059Samurai    *ap++ = chp->id;
1366059Samurai    bcopy(keyp, ap, keylen);
1376059Samurai    ap += keylen;
1386059Samurai    bcopy(cp, ap, valsize);
13926516Sbrian    LogDumpBuff(LogDEBUG, "recv", ap, valsize);
1406059Samurai    ap += valsize;
1416059Samurai    MD5Init(&context);
1426059Samurai    MD5Update(&context, answer, ap - answer);
1436059Samurai    MD5Final(digest, &context);
14426516Sbrian    LogDumpBuff(LogDEBUG, "answer", digest, 16);
1456059Samurai    bcopy(name, digest + 16, namelen);
1466059Samurai    ap += namelen;
1476059Samurai    /* Send answer to the peer */
1486059Samurai    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
14918885Sjkh    free(argp);
1506059Samurai    break;
1516059Samurai  case CHAP_RESPONSE:
1526059Samurai    if (keyp) {
15328679Sbrian
1546059Samurai      /*
1556059Samurai       * Compute correct digest value
1566059Samurai       */
1576059Samurai      keylen = strlen(keyp);
1586059Samurai      ap = answer;
1596059Samurai      *ap++ = chp->id;
1606059Samurai      bcopy(keyp, ap, keylen);
1616059Samurai      ap += keylen;
1626059Samurai      MD5Init(&context);
1636059Samurai      MD5Update(&context, answer, ap - answer);
16428679Sbrian      MD5Update(&context, challenge_data + 1, challenge_len);
1656059Samurai      MD5Final(cdigest, &context);
16626516Sbrian      LogDumpBuff(LogDEBUG, "got", cp, 16);
16726516Sbrian      LogDumpBuff(LogDEBUG, "expect", cdigest, 16);
16828679Sbrian
1696059Samurai      /*
1706059Samurai       * Compare with the response
1716059Samurai       */
1726059Samurai      if (bcmp(cp, cdigest, 16) == 0) {
1736059Samurai	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
1746059Samurai	NewPhase(PHASE_NETWORK);
1756059Samurai	break;
1766059Samurai      }
1776059Samurai    }
17828679Sbrian
1796059Samurai    /*
1806059Samurai     * Peer is not registerd, or response digest is wrong.
1816059Samurai     */
1826059Samurai    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
18326098Sbrian    reconnect(RECON_FALSE);
1846059Samurai    LcpClose();
1856059Samurai    break;
1866059Samurai  }
1876059Samurai}
1886059Samurai
1896059Samuraivoid
19028679SbrianRecvChapResult(struct fsmheader * chp, struct mbuf * bp)
1916059Samurai{
1926059Samurai  int len;
1936059Samurai  struct lcpstate *lcp = &LcpInfo;
1946059Samurai
1956059Samurai  len = ntohs(chp->length);
19626516Sbrian  LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len);
1976059Samurai  if (chp->code == CHAP_SUCCESS) {
1986059Samurai    if (lcp->auth_iwait == PROTO_CHAP) {
1996059Samurai      lcp->auth_iwait = 0;
2006059Samurai      if (lcp->auth_ineed == 0)
2016059Samurai	NewPhase(PHASE_NETWORK);
2026059Samurai    }
2036059Samurai  } else {
20428679Sbrian
2056059Samurai    /*
2066059Samurai     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
2076059Samurai     */
2086059Samurai    ;
2096059Samurai  }
2106059Samurai}
2116059Samurai
2126059Samuraivoid
21328679SbrianChapInput(struct mbuf * bp)
2146059Samurai{
2156059Samurai  int len = plength(bp);
2166059Samurai  struct fsmheader *chp;
2176059Samurai
2186059Samurai  if (len >= sizeof(struct fsmheader)) {
21928679Sbrian    chp = (struct fsmheader *) MBUF_CTOP(bp);
2206059Samurai    if (len >= ntohs(chp->length)) {
2216059Samurai      if (chp->code < 1 || chp->code > 4)
2226059Samurai	chp->code = 0;
22326516Sbrian      LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]);
2246059Samurai
2256059Samurai      bp->offset += sizeof(struct fsmheader);
2266059Samurai      bp->cnt -= sizeof(struct fsmheader);
2276059Samurai
2286059Samurai      switch (chp->code) {
2296735Samurai      case CHAP_RESPONSE:
2306735Samurai	StopAuthTimer(&AuthChapInfo);
2316735Samurai	/* Fall into.. */
2326059Samurai      case CHAP_CHALLENGE:
2336059Samurai	RecvChapTalk(chp, bp);
2346059Samurai	break;
2356059Samurai      case CHAP_SUCCESS:
2366059Samurai      case CHAP_FAILURE:
2376059Samurai	RecvChapResult(chp, bp);
2386059Samurai	break;
2396059Samurai      }
2406059Samurai    }
2416059Samurai  }
2426059Samurai  pfree(bp);
2436059Samurai}
244