xref: /freebsd/usr.sbin/ppp/chap.c (revision b5b2a90624d3d900a42e99758eb95293d04f37fa)
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$
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 
35 static char *chapcodes[] = {
36   "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
37 };
38 
39 struct authinfo AuthChapInfo  = {
40   SendChapChallenge,
41 };
42 
43 extern char *AuthGetSecret();
44 
45 void
46 ChapOutput(code, id, ptr, count)
47 u_int code, id;
48 u_char *ptr;
49 int 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 
71 static char challenge_data[80];
72 static int  challenge_len;
73 
74 void
75 SendChapChallenge(chapid)
76 int 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
94 void
95 DumpDigest(mes, cp, len)
96 char *mes;
97 char *cp;
98 int 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 
110 void
111 RecvChapTalk(chp, bp)
112 struct fsmheader *chp;
113 struct 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 
210 void
211 RecvChapResult(chp, bp)
212 struct fsmheader *chp;
213 struct 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 
236 void
237 ChapInput(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