chap.c revision 26516
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.17 1997/05/26 00:43:56 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  LogDumpBp(LogDEBUG, "ChapOutput", bp);
66  LogPrintf(LogLCP, "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  if (!randinit) {
82    randinit = 1;
83    if (srandomdev() < 0)
84      srandom((unsigned long)(time(NULL) ^ getpid()));
85  }
86
87  cp = challenge_data;
88  *cp++ = challenge_len = random() % 32 + 16;
89  for (i = 0; i < challenge_len; i++)
90    *cp++ = random() & 0xff;
91  len = strlen(VarAuthName);
92  bcopy(VarAuthName, cp, len);
93  cp += len;
94  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
95}
96
97void
98RecvChapTalk(chp, bp)
99struct fsmheader *chp;
100struct mbuf *bp;
101{
102  int valsize, len;
103  int arglen, keylen, namelen;
104  char *cp, *argp, *ap, *name, *digest;
105  char *keyp;
106  MD5_CTX context;                            /* context */
107  char answer[100];
108  char cdigest[16];
109
110  len = ntohs(chp->length);
111  LogPrintf(LogDEBUG, "RecvChapTalk: length: %d\n", len);
112  arglen = len - sizeof(struct fsmheader);
113  cp = (char *)MBUF_CTOP(bp);
114  valsize = *cp++ & 255;
115  name = cp + valsize;
116  namelen = arglen - valsize - 1;
117  name[namelen] = 0;
118  LogPrintf(LogPHASE, " Valsize = %d, Name = %s\n", valsize, name);
119
120  /*
121   * Get a secret key corresponds to the peer
122   */
123  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
124
125  switch (chp->code) {
126  case CHAP_CHALLENGE:
127    if (keyp) {
128      keylen = strlen(keyp);
129    } else {
130      keylen = strlen(VarAuthKey);
131      keyp = VarAuthKey;
132    }
133    name = VarAuthName;
134    namelen = strlen(VarAuthName);
135    argp = malloc(1 + valsize + namelen + 16);
136    if (argp == NULL) {
137      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
138      return;
139    }
140    digest = argp;
141    *digest++ = 16;		/* value size */
142    ap = answer;
143    *ap++ = chp->id;
144    bcopy(keyp, ap, keylen);
145    ap += keylen;
146    bcopy(cp, ap, valsize);
147    LogDumpBuff(LogDEBUG, "recv", ap, valsize);
148    ap += valsize;
149    MD5Init(&context);
150    MD5Update(&context, answer, ap - answer);
151    MD5Final(digest, &context);
152    LogDumpBuff(LogDEBUG, "answer", digest, 16);
153    bcopy(name, digest + 16, namelen);
154    ap += namelen;
155    /* Send answer to the peer */
156    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
157    free(argp);
158    break;
159  case CHAP_RESPONSE:
160    if (keyp) {
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      MD5Init(&context);
170      MD5Update(&context, answer, ap - answer);
171      MD5Update(&context, challenge_data+1, challenge_len);
172      MD5Final(cdigest, &context);
173      LogDumpBuff(LogDEBUG, "got", cp, 16);
174      LogDumpBuff(LogDEBUG, "expect", cdigest, 16);
175      /*
176       * Compare with the response
177       */
178      if (bcmp(cp, cdigest, 16) == 0) {
179	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
180	NewPhase(PHASE_NETWORK);
181	break;
182      }
183    }
184    /*
185     * Peer is not registerd, or response digest is wrong.
186     */
187    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
188    reconnect(RECON_FALSE);
189    LcpClose();
190    break;
191  }
192}
193
194void
195RecvChapResult(chp, bp)
196struct fsmheader *chp;
197struct mbuf *bp;
198{
199  int len;
200  struct lcpstate *lcp = &LcpInfo;
201
202  len = ntohs(chp->length);
203  LogPrintf(LogDEBUG, "RecvChapResult: length: %d\n", len);
204  if (chp->code == CHAP_SUCCESS) {
205    if (lcp->auth_iwait == PROTO_CHAP) {
206      lcp->auth_iwait = 0;
207      if (lcp->auth_ineed == 0)
208	NewPhase(PHASE_NETWORK);
209    }
210  } else {
211    /*
212     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
213     */
214    ;
215  }
216}
217
218void
219ChapInput(struct mbuf *bp)
220{
221  int len = plength(bp);
222  struct fsmheader *chp;
223
224  if (len >= sizeof(struct fsmheader)) {
225    chp = (struct fsmheader *)MBUF_CTOP(bp);
226    if (len >= ntohs(chp->length)) {
227      if (chp->code < 1 || chp->code > 4)
228	chp->code = 0;
229      LogPrintf(LogLCP, "ChapInput: %s\n", chapcodes[chp->code]);
230
231      bp->offset += sizeof(struct fsmheader);
232      bp->cnt -= sizeof(struct fsmheader);
233
234      switch (chp->code) {
235      case CHAP_RESPONSE:
236	StopAuthTimer(&AuthChapInfo);
237	/* Fall into.. */
238      case CHAP_CHALLENGE:
239	RecvChapTalk(chp, bp);
240	break;
241      case CHAP_SUCCESS:
242      case CHAP_FAILURE:
243	RecvChapResult(chp, bp);
244	break;
245      }
246    }
247  }
248  pfree(bp);
249}
250