chap.c revision 26098
1/*
2 *			PPP CHAP Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id: chap.c,v 1.15 1997/05/19 01:59:57 brian Exp $
21 *
22 *	TODO:
23 */
24#include <sys/types.h>
25#include <time.h>
26#include "fsm.h"
27#include "chap.h"
28#include "lcpproto.h"
29#include "lcp.h"
30#include "hdlc.h"
31#include "phase.h"
32#include "vars.h"
33#include "auth.h"
34
35static char *chapcodes[] = {
36  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
37};
38
39struct authinfo AuthChapInfo  = {
40  SendChapChallenge,
41};
42
43extern char *AuthGetSecret();
44extern int randinit;
45
46void
47ChapOutput(code, id, ptr, count)
48u_int code, id;
49u_char *ptr;
50int count;
51{
52  int plen;
53  struct fsmheader lh;
54  struct mbuf *bp;
55
56  plen =  sizeof(struct fsmheader) + count;
57  lh.code = code;
58  lh.id = id;
59  lh.length = htons(plen);
60  bp = mballoc(plen, MB_FSM);
61  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
62  if (count)
63    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
64#ifdef DEBUG
65  DumpBp(bp);
66#endif
67  LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
68  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
69}
70
71
72static char challenge_data[80];
73static int  challenge_len;
74
75void
76SendChapChallenge(chapid)
77int chapid;
78{
79  int len, i;
80  char *cp;
81
82  if (!randinit) {
83    randinit = 1;
84    if (srandomdev() < 0)
85      srandom((unsigned long)(time(NULL) ^ getpid()));
86  }
87
88  cp = challenge_data;
89  *cp++ = challenge_len = random() % 32 + 16;
90  for (i = 0; i < challenge_len; i++)
91    *cp++ = random() & 0xff;
92  len = strlen(VarAuthName);
93  bcopy(VarAuthName, cp, len);
94  cp += len;
95  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
96}
97
98#ifdef DEBUG
99void
100DumpDigest(mes, cp, len)
101char *mes;
102char *cp;
103int len;
104{
105  int i;
106
107  logprintf("%s: ", mes);
108  for (i = 0; i < len; i++) {
109    logprintf(" %02x", *cp++ & 0xff);
110  }
111  logprintf("\n");
112}
113#endif
114
115void
116RecvChapTalk(chp, bp)
117struct fsmheader *chp;
118struct mbuf *bp;
119{
120  int valsize, len;
121  int arglen, keylen, namelen;
122  char *cp, *argp, *ap, *name, *digest;
123  char *keyp;
124  MD5_CTX context;                            /* context */
125  char answer[100];
126  char cdigest[16];
127
128  len = ntohs(chp->length);
129#ifdef DEBUG
130  logprintf("length: %d\n", len);
131#endif
132  arglen = len - sizeof(struct fsmheader);
133  cp = (char *)MBUF_CTOP(bp);
134  valsize = *cp++ & 255;
135  name = cp + valsize;
136  namelen = arglen - valsize - 1;
137  name[namelen] = 0;
138  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
139
140  /*
141   * Get a secret key corresponds to the peer
142   */
143  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
144
145  switch (chp->code) {
146  case CHAP_CHALLENGE:
147    if (keyp) {
148      keylen = strlen(keyp);
149    } else {
150      keylen = strlen(VarAuthKey);
151      keyp = VarAuthKey;
152    }
153    name = VarAuthName;
154    namelen = strlen(VarAuthName);
155    argp = malloc(1 + valsize + namelen + 16);
156    if (argp == NULL) {
157      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
158      return;
159    }
160    digest = argp;
161    *digest++ = 16;		/* value size */
162    ap = answer;
163    *ap++ = chp->id;
164    bcopy(keyp, ap, keylen);
165    ap += keylen;
166    bcopy(cp, ap, valsize);
167#ifdef DEBUG
168    DumpDigest("recv", ap, valsize);
169#endif
170    ap += valsize;
171    MD5Init(&context);
172    MD5Update(&context, answer, ap - answer);
173    MD5Final(digest, &context);
174#ifdef DEBUG
175    DumpDigest("answer", digest, 16);
176#endif
177    bcopy(name, digest + 16, namelen);
178    ap += namelen;
179    /* Send answer to the peer */
180    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
181    free(argp);
182    break;
183  case CHAP_RESPONSE:
184    if (keyp) {
185      /*
186       * Compute correct digest value
187       */
188      keylen = strlen(keyp);
189      ap = answer;
190      *ap++ = chp->id;
191      bcopy(keyp, ap, keylen);
192      ap += keylen;
193      MD5Init(&context);
194      MD5Update(&context, answer, ap - answer);
195      MD5Update(&context, challenge_data+1, challenge_len);
196      MD5Final(cdigest, &context);
197#ifdef DEBUG
198      DumpDigest("got", cp, 16);
199      DumpDigest("expect", cdigest, 16);
200#endif
201      /*
202       * Compare with the response
203       */
204      if (bcmp(cp, cdigest, 16) == 0) {
205	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
206	NewPhase(PHASE_NETWORK);
207	break;
208      }
209    }
210    /*
211     * Peer is not registerd, or response digest is wrong.
212     */
213    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
214    reconnect(RECON_FALSE);
215    LcpClose();
216    break;
217  }
218}
219
220void
221RecvChapResult(chp, bp)
222struct fsmheader *chp;
223struct mbuf *bp;
224{
225  int len;
226  struct lcpstate *lcp = &LcpInfo;
227
228  len = ntohs(chp->length);
229#ifdef DEBUG
230  logprintf("length: %d\n", len);
231#endif
232  if (chp->code == CHAP_SUCCESS) {
233    if (lcp->auth_iwait == PROTO_CHAP) {
234      lcp->auth_iwait = 0;
235      if (lcp->auth_ineed == 0)
236	NewPhase(PHASE_NETWORK);
237    }
238  } else {
239    /*
240     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
241     */
242    ;
243  }
244}
245
246void
247ChapInput(struct mbuf *bp)
248{
249  int len = plength(bp);
250  struct fsmheader *chp;
251
252  if (len >= sizeof(struct fsmheader)) {
253    chp = (struct fsmheader *)MBUF_CTOP(bp);
254    if (len >= ntohs(chp->length)) {
255      if (chp->code < 1 || chp->code > 4)
256	chp->code = 0;
257      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
258
259      bp->offset += sizeof(struct fsmheader);
260      bp->cnt -= sizeof(struct fsmheader);
261
262      switch (chp->code) {
263      case CHAP_RESPONSE:
264	StopAuthTimer(&AuthChapInfo);
265	/* Fall into.. */
266      case CHAP_CHALLENGE:
267	RecvChapTalk(chp, bp);
268	break;
269      case CHAP_SUCCESS:
270      case CHAP_FAILURE:
271	RecvChapResult(chp, bp);
272	break;
273      }
274    }
275  }
276  pfree(bp);
277}
278