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