chap.c revision 25908
1229997Sken/*
2229997Sken *			PPP CHAP Module
3229997Sken *
4232604Strasz *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5229997Sken *
6229997Sken *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7232604Strasz *
8232604Strasz * Redistribution and use in source and binary forms are permitted
9232604Strasz * provided that the above copyright notice and this paragraph are
10229997Sken * duplicated in all such forms and that any documentation,
11229997Sken * advertising materials, and other materials related to such
12229997Sken * distribution and use acknowledge that the software was developed
13229997Sken * by the Internet Initiative Japan, Inc.  The name of the
14229997Sken * IIJ may not be used to endorse or promote products derived
15229997Sken * from this software without specific prior written permission.
16229997Sken * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17229997Sken * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18229997Sken * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19229997Sken *
20229997Sken * $Id: chap.c,v 1.14 1997/05/10 01:22:06 brian Exp $
21229997Sken *
22229997Sken *	TODO:
23229997Sken */
24229997Sken#include <sys/types.h>
25229997Sken#include <time.h>
26229997Sken#include "fsm.h"
27229997Sken#include "chap.h"
28229997Sken#include "lcpproto.h"
29229997Sken#include "lcp.h"
30229997Sken#include "hdlc.h"
31229997Sken#include "phase.h"
32229997Sken#include "vars.h"
33229997Sken#include "auth.h"
34229997Sken
35229997Skenstatic char *chapcodes[] = {
36229997Sken  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
37229997Sken};
38229997Sken
39229997Skenstruct authinfo AuthChapInfo  = {
40229997Sken  SendChapChallenge,
41229997Sken};
42229997Sken
43229997Skenextern char *AuthGetSecret();
44229997Skenextern int randinit;
45229997Sken
46229997Skenvoid
47229997SkenChapOutput(code, id, ptr, count)
48229997Skenu_int code, id;
49229997Skenu_char *ptr;
50229997Skenint count;
51229997Sken{
52229997Sken  int plen;
53229997Sken  struct fsmheader lh;
54229997Sken  struct mbuf *bp;
55229997Sken
56229997Sken  plen =  sizeof(struct fsmheader) + count;
57229997Sken  lh.code = code;
58229997Sken  lh.id = id;
59229997Sken  lh.length = htons(plen);
60229997Sken  bp = mballoc(plen, MB_FSM);
61229997Sken  bcopy(&lh, MBUF_CTOP(bp), sizeof(struct fsmheader));
62229997Sken  if (count)
63229997Sken    bcopy(ptr, MBUF_CTOP(bp) + sizeof(struct fsmheader), count);
64229997Sken#ifdef DEBUG
65229997Sken  DumpBp(bp);
66229997Sken#endif
67229997Sken  LogPrintf(LOG_LCP_BIT, "ChapOutput: %s\n", chapcodes[code]);
68229997Sken  HdlcOutput(PRI_LINK, PROTO_CHAP, bp);
69229997Sken}
70229997Sken
71229997Sken
72229997Skenstatic char challenge_data[80];
73229997Skenstatic int  challenge_len;
74229997Sken
75229997Skenvoid
76229997SkenSendChapChallenge(chapid)
77229997Skenint chapid;
78229997Sken{
79229997Sken  int len, i;
80229997Sken  char *cp;
81229997Sken
82229997Sken  if (!randinit) {
83229997Sken    randinit = 1;
84229997Sken    if (srandomdev() < 0)
85229997Sken      srandom((unsigned long)(time(NULL) ^ getpid()));
86229997Sken  }
87229997Sken
88229997Sken  cp = challenge_data;
89229997Sken  *cp++ = challenge_len = random() % 32 + 16;
90229997Sken  for (i = 0; i < challenge_len; i++)
91229997Sken    *cp++ = random() & 0xff;
92229997Sken  len = strlen(VarAuthName);
93229997Sken  bcopy(VarAuthName, cp, len);
94229997Sken  cp += len;
95229997Sken  ChapOutput(CHAP_CHALLENGE, chapid, challenge_data, cp - challenge_data);
96229997Sken}
97229997Sken
98229997Sken#ifdef DEBUG
99229997Skenvoid
100229997SkenDumpDigest(mes, cp, len)
101229997Skenchar *mes;
102229997Skenchar *cp;
103229997Skenint len;
104229997Sken{
105229997Sken  int i;
106229997Sken
107229997Sken  logprintf("%s: ", mes);
108229997Sken  for (i = 0; i < len; i++) {
109229997Sken    logprintf(" %02x", *cp++ & 0xff);
110229997Sken  }
111229997Sken  logprintf("\n");
112229997Sken}
113229997Sken#endif
114229997Sken
115229997Skenvoid
116229997SkenRecvChapTalk(chp, bp)
117229997Skenstruct fsmheader *chp;
118229997Skenstruct mbuf *bp;
119229997Sken{
120229997Sken  int valsize, len;
121229997Sken  int arglen, keylen, namelen;
122229997Sken  char *cp, *argp, *ap, *name, *digest;
123229997Sken  char *keyp;
124229997Sken  MD5_CTX context;                            /* context */
125229997Sken  char answer[100];
126229997Sken  char cdigest[16];
127229997Sken
128229997Sken  len = ntohs(chp->length);
129229997Sken#ifdef DEBUG
130229997Sken  logprintf("length: %d\n", len);
131229997Sken#endif
132229997Sken  arglen = len - sizeof(struct fsmheader);
133229997Sken  cp = (char *)MBUF_CTOP(bp);
134229997Sken  valsize = *cp++ & 255;
135229997Sken  name = cp + valsize;
136229997Sken  namelen = arglen - valsize - 1;
137229997Sken  name[namelen] = 0;
138229997Sken  LogPrintf(LOG_PHASE_BIT, " Valsize = %d, Name = %s\n", valsize, name);
139229997Sken
140229997Sken  /*
141229997Sken   * Get a secret key corresponds to the peer
142229997Sken   */
143229997Sken  keyp = AuthGetSecret(SECRETFILE, name, namelen, chp->code == CHAP_RESPONSE);
144229997Sken
145229997Sken  switch (chp->code) {
146229997Sken  case CHAP_CHALLENGE:
147229997Sken    if (keyp) {
148229997Sken      keylen = strlen(keyp);
149229997Sken    } else {
150229997Sken      keylen = strlen(VarAuthKey);
151229997Sken      keyp = VarAuthKey;
152229997Sken    }
153229997Sken    name = VarAuthName;
154229997Sken    namelen = strlen(VarAuthName);
155229997Sken    argp = malloc(1 + valsize + namelen + 16);
156229997Sken    if (argp == NULL) {
157229997Sken      ChapOutput(CHAP_FAILURE, chp->id, "Out of memory!", 14);
158229997Sken      return;
159264191Smav    }
160264191Smav    digest = argp;
161229997Sken    *digest++ = 16;		/* value size */
162229997Sken    ap = answer;
163229997Sken    *ap++ = chp->id;
164229997Sken    bcopy(keyp, ap, keylen);
165229997Sken    ap += keylen;
166229997Sken    bcopy(cp, ap, valsize);
167229997Sken#ifdef DEBUG
168229997Sken    DumpDigest("recv", ap, valsize);
169229997Sken#endif
170229997Sken    ap += valsize;
171229997Sken    MD5Init(&context);
172229997Sken    MD5Update(&context, answer, ap - answer);
173229997Sken    MD5Final(digest, &context);
174229997Sken#ifdef DEBUG
175229997Sken    DumpDigest("answer", digest, 16);
176229997Sken#endif
177229997Sken    bcopy(name, digest + 16, namelen);
178229997Sken    ap += namelen;
179229997Sken    /* Send answer to the peer */
180229997Sken    ChapOutput(CHAP_RESPONSE, chp->id, argp, namelen + 17);
181229997Sken    free(argp);
182229997Sken    break;
183229997Sken  case CHAP_RESPONSE:
184229997Sken    if (keyp) {
185229997Sken      /*
186229997Sken       * Compute correct digest value
187229997Sken       */
188229997Sken      keylen = strlen(keyp);
189229997Sken      ap = answer;
190229997Sken      *ap++ = chp->id;
191229997Sken      bcopy(keyp, ap, keylen);
192229997Sken      ap += keylen;
193229997Sken      MD5Init(&context);
194229997Sken      MD5Update(&context, answer, ap - answer);
195229997Sken      MD5Update(&context, challenge_data+1, challenge_len);
196229997Sken      MD5Final(cdigest, &context);
197229997Sken#ifdef DEBUG
198229997Sken      DumpDigest("got", cp, 16);
199229997Sken      DumpDigest("expect", cdigest, 16);
200229997Sken#endif
201229997Sken      /*
202229997Sken       * Compare with the response
203229997Sken       */
204229997Sken      if (bcmp(cp, cdigest, 16) == 0) {
205229997Sken	ChapOutput(CHAP_SUCCESS, chp->id, "Wellcome!!", 10);
206229997Sken	NewPhase(PHASE_NETWORK);
207229997Sken	break;
208229997Sken      }
209229997Sken    }
210229997Sken    /*
211229997Sken     * Peer is not registerd, or response digest is wrong.
212229997Sken     */
213229997Sken    ChapOutput(CHAP_FAILURE, chp->id, "Invalid!!", 9);
214229997Sken    LcpClose();
215229997Sken    reconnectCount = 0;
216229997Sken    break;
217229997Sken  }
218229997Sken}
219229997Sken
220229997Skenvoid
221229997SkenRecvChapResult(chp, bp)
222229997Skenstruct fsmheader *chp;
223229997Skenstruct mbuf *bp;
224229997Sken{
225229997Sken  int len;
226229997Sken  struct lcpstate *lcp = &LcpInfo;
227229997Sken
228229997Sken  len = ntohs(chp->length);
229229997Sken#ifdef DEBUG
230229997Sken  logprintf("length: %d\n", len);
231229997Sken#endif
232229997Sken  if (chp->code == CHAP_SUCCESS) {
233229997Sken    if (lcp->auth_iwait == PROTO_CHAP) {
234229997Sken      lcp->auth_iwait = 0;
235229997Sken      if (lcp->auth_ineed == 0)
236229997Sken	NewPhase(PHASE_NETWORK);
237229997Sken    }
238229997Sken  } else {
239229997Sken    /*
240229997Sken     * Maybe, we shoud close LCP. Of cause, peer may take close action, too.
241229997Sken     */
242229997Sken    ;
243229997Sken  }
244229997Sken}
245229997Sken
246229997Skenvoid
247229997SkenChapInput(struct mbuf *bp)
248229997Sken{
249229997Sken  int len = plength(bp);
250232604Strasz  struct fsmheader *chp;
251232604Strasz
252232604Strasz  if (len >= sizeof(struct fsmheader)) {
253232604Strasz    chp = (struct fsmheader *)MBUF_CTOP(bp);
254232604Strasz    if (len >= ntohs(chp->length)) {
255232604Strasz      if (chp->code < 1 || chp->code > 4)
256229997Sken	chp->code = 0;
257229997Sken      LogPrintf(LOG_LCP_BIT, "ChapInput: %s\n", chapcodes[chp->code]);
258229997Sken
259229997Sken      bp->offset += sizeof(struct fsmheader);
260229997Sken      bp->cnt -= sizeof(struct fsmheader);
261229997Sken
262229997Sken      switch (chp->code) {
263229997Sken      case CHAP_RESPONSE:
264229997Sken	StopAuthTimer(&AuthChapInfo);
265229997Sken	/* Fall into.. */
266230334Sken      case CHAP_CHALLENGE:
267230334Sken	RecvChapTalk(chp, bp);
268230334Sken	break;
269230334Sken      case CHAP_SUCCESS:
270230334Sken      case CHAP_FAILURE:
271230334Sken	RecvChapResult(chp, bp);
272230334Sken	break;
273230334Sken      }
274230334Sken    }
275229997Sken  }
276229997Sken  pfree(bp);
277229997Sken}
278229997Sken