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