chap.c revision 26142
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.16 1997/05/24 17:32:32 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 "loadalias.h"
33#include "vars.h"
34#include "auth.h"
35
36static char *chapcodes[] = {
37  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
38};
39
40struct authinfo AuthChapInfo  = {
41  SendChapChallenge,
42};
43
44extern char *AuthGetSecret();
45extern int randinit;
46
47void
48ChapOutput(code, id, ptr, count)
49u_int code, id;
50u_char *ptr;
51int count;
52{
53  int plen;
54  struct fsmheader lh;
55  struct mbuf *bp;
56
57  plen =  sizeof(struct fsmheader) + count;
58  lh.code = code;
59  lh.id = id;
60  lh.length = htons(plen);
61  bp = mballoc(plen, MB_FSM);
62  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
63  if (count)
64    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
65#ifdef DEBUG
66  DumpBp(bp);
67#endif
68  LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
69  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
70}
71
72
73static char challenge_data[80];
74static int  challenge_len;
75
76void
77SendChapChallenge(chapid)
78int chapid;
79{
80  int len, i;
81  char *cp;
82
83  if (!randinit) {
84    randinit = 1;
85    if (srandomdev() < 0)
86      srandom((unsigned long)(time(NULL) ^ getpid()));
87  }
88
89  cp = challenge_data;
90  *cp++ = challenge_len = random() % 32 + 16;
91  for (i = 0; i < challenge_len; i++)
92    *cp++ = random() & 0xff;
93  len = strlen(VarAuthName);
94  bcopy(VarAuthName, cp, len);
95  cp += len;
96  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
97}
98
99#ifdef DEBUG
100void
101DumpDigest(mes, cp, len)
102char *mes;
103char *cp;
104int len;
105{
106  int i;
107
108  logprintf("%s: ", mes);
109  for (i = 0; i < len; i++) {
110    logprintf(" %02x", *cp++ & 0xff);
111  }
112  logprintf("\n");
113}
114#endif
115
116void
117RecvChapTalk(chp, bp)
118struct fsmheader *chp;
119struct mbuf *bp;
120{
121  int valsize, len;
122  int arglen, keylen, namelen;
123  char *cp, *argp, *ap, *name, *digest;
124  char *keyp;
125  MD5_CTX context;                            /* context */
126  char answer[100];
127  char cdigest[16];
128
129  len = ntohs(chp->length);
130#ifdef DEBUG
131  logprintf("length: %d\n", len);
132#endif
133  arglen = len - sizeof(struct fsmheader);
134  cp = (char *)MBUF_CTOP(bp);
135  valsize = *cp++ & 255;
136  name = cp + valsize;
137  namelen = arglen - valsize - 1;
138  name[namelen] = 0;
139  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
140
141  /*
142   * Get a secret key corresponds to the peer
143   */
144  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
145
146  switch (chp->code) {
147  case CHAP_CHALLENGE:
148    if (keyp) {
149      keylen = strlen(keyp);
150    } else {
151      keylen = strlen(VarAuthKey);
152      keyp = VarAuthKey;
153    }
154    name = VarAuthName;
155    namelen = strlen(VarAuthName);
156    argp = malloc(1 + valsize + namelen + 16);
157    if (argp == NULL) {
158      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
159      return;
160    }
161    digest = argp;
162    *digest++ = 16;		/* value size */
163    ap = answer;
164    *ap++ = chp->id;
165    bcopy(keyp, ap, keylen);
166    ap += keylen;
167    bcopy(cp, ap, valsize);
168#ifdef DEBUG
169    DumpDigest("recv", ap, valsize);
170#endif
171    ap += valsize;
172    MD5Init(&context);
173    MD5Update(&context, answer, ap - answer);
174    MD5Final(digest, &context);
175#ifdef DEBUG
176    DumpDigest("answer", digest, 16);
177#endif
178    bcopy(name, digest + 16, namelen);
179    ap += namelen;
180    /* Send answer to the peer */
181    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
182    free(argp);
183    break;
184  case CHAP_RESPONSE:
185    if (keyp) {
186      /*
187       * Compute correct digest value
188       */
189      keylen = strlen(keyp);
190      ap = answer;
191      *ap++ = chp->id;
192      bcopy(keyp, ap, keylen);
193      ap += keylen;
194      MD5Init(&context);
195      MD5Update(&context, answer, ap - answer);
196      MD5Update(&context, challenge_data+1, challenge_len);
197      MD5Final(cdigest, &context);
198#ifdef DEBUG
199      DumpDigest("got", cp, 16);
200      DumpDigest("expect", cdigest, 16);
201#endif
202      /*
203       * Compare with the response
204       */
205      if (bcmp(cp, cdigest, 16) == 0) {
206	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
207	NewPhase(PHASE_NETWORK);
208	break;
209      }
210    }
211    /*
212     * Peer is not registerd, or response digest is wrong.
213     */
214    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
215    reconnect(RECON_FALSE);
216    LcpClose();
217    break;
218  }
219}
220
221void
222RecvChapResult(chp, bp)
223struct fsmheader *chp;
224struct mbuf *bp;
225{
226  int len;
227  struct lcpstate *lcp = &LcpInfo;
228
229  len = ntohs(chp->length);
230#ifdef DEBUG
231  logprintf("length: %d\n", len);
232#endif
233  if (chp->code == CHAP_SUCCESS) {
234    if (lcp->auth_iwait == PROTO_CHAP) {
235      lcp->auth_iwait = 0;
236      if (lcp->auth_ineed == 0)
237	NewPhase(PHASE_NETWORK);
238    }
239  } else {
240    /*
241     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
242     */
243    ;
244  }
245}
246
247void
248ChapInput(struct mbuf *bp)
249{
250  int len = plength(bp);
251  struct fsmheader *chp;
252
253  if (len >= sizeof(struct fsmheader)) {
254    chp = (struct fsmheader *)MBUF_CTOP(bp);
255    if (len >= ntohs(chp->length)) {
256      if (chp->code < 1 || chp->code > 4)
257	chp->code = 0;
258      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
259
260      bp->offset += sizeof(struct fsmheader);
261      bp->cnt -= sizeof(struct fsmheader);
262
263      switch (chp->code) {
264      case CHAP_RESPONSE:
265	StopAuthTimer(&AuthChapInfo);
266	/* Fall into.. */
267      case CHAP_CHALLENGE:
268	RecvChapTalk(chp, bp);
269	break;
270      case CHAP_SUCCESS:
271      case CHAP_FAILURE:
272	RecvChapResult(chp, bp);
273	break;
274      }
275    }
276  }
277  pfree(bp);
278}
279