]> git.sur5r.net Git - freertos/blob - Demo/lwIP_MCF5235_GCC/lwip/src/netif/ppp/chap.c
Add PIC24, dsPIC and Coldfire files.
[freertos] / Demo / lwIP_MCF5235_GCC / lwip / src / netif / ppp / chap.c
1 /*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
2 /*****************************************************************************
3 * chap.c - Network Challenge Handshake Authentication Protocol program file.
4 *
5 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
6 * portions Copyright (c) 1997 by Global Election Systems Inc.
7 *
8 * The authors hereby grant permission to use, copy, modify, distribute,
9 * and license this software and its documentation for any purpose, provided
10 * that existing copyright notices are retained in all copies and that this
11 * notice and the following disclaimer are included verbatim in any 
12 * distributions. No written agreement, license, or royalty fee is required
13 * for any of the authorized uses.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
18 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 ******************************************************************************
27 * REVISION HISTORY
28 *
29 * 03-01-01 Marc Boucher <marc@mbsi.ca>
30 *   Ported to lwIP.
31 * 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32 *       Original based on BSD chap.c.
33 *****************************************************************************/
34 /*
35  * chap.c - Challenge Handshake Authentication Protocol.
36  *
37  * Copyright (c) 1993 The Australian National University.
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms are permitted
41  * provided that the above copyright notice and this paragraph are
42  * duplicated in all such forms and that any documentation,
43  * advertising materials, and other materials related to such
44  * distribution and use acknowledge that the software was developed
45  * by the Australian National University.  The name of the University
46  * may not be used to endorse or promote products derived from this
47  * software without specific prior written permission.
48  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
49  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
50  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51  *
52  * Copyright (c) 1991 Gregory M. Christy.
53  * All rights reserved.
54  *
55  * Redistribution and use in source and binary forms are permitted
56  * provided that the above copyright notice and this paragraph are
57  * duplicated in all such forms and that any documentation,
58  * advertising materials, and other materials related to such
59  * distribution and use acknowledge that the software was developed
60  * by Gregory M. Christy.  The name of the author may not be used to
61  * endorse or promote products derived from this software without
62  * specific prior written permission.
63  *
64  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
65  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
67  */
68
69 #include "ppp.h"
70 #if PPP_SUPPORT > 0
71 #include "magic.h"
72
73 #if CHAP_SUPPORT > 0
74
75 #include "randm.h"
76 #include "auth.h"
77 #include "md5.h"
78 #include "chap.h"
79 #include "chpms.h"
80 #include "pppdebug.h"
81
82
83 /*************************/
84 /*** LOCAL DEFINITIONS ***/
85 /*************************/
86
87
88 /************************/
89 /*** LOCAL DATA TYPES ***/
90 /************************/
91
92
93 /***********************************/
94 /*** LOCAL FUNCTION DECLARATIONS ***/
95 /***********************************/
96 /*
97  * Protocol entry points.
98  */
99 static void ChapInit (int);
100 static void ChapLowerUp (int);
101 static void ChapLowerDown (int);
102 static void ChapInput (int, u_char *, int);
103 static void ChapProtocolReject (int);
104 static int  ChapPrintPkt (u_char *, int,
105                               void (*) (void *, char *, ...), void *);
106
107 static void ChapChallengeTimeout (void *);
108 static void ChapResponseTimeout (void *);
109 static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
110 static void ChapRechallenge (void *);
111 static void ChapReceiveResponse (chap_state *, u_char *, int, int);
112 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
113 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
114 static void ChapSendStatus (chap_state *, int);
115 static void ChapSendChallenge (chap_state *);
116 static void ChapSendResponse (chap_state *);
117 static void ChapGenChallenge (chap_state *);
118
119
120 /******************************/
121 /*** PUBLIC DATA STRUCTURES ***/
122 /******************************/
123 chap_state chap[NUM_PPP];               /* CHAP state; one for each unit */
124
125 struct protent chap_protent = {
126     PPP_CHAP,
127     ChapInit,
128     ChapInput,
129     ChapProtocolReject,
130     ChapLowerUp,
131     ChapLowerDown,
132     NULL,
133     NULL,
134 #if 0
135     ChapPrintPkt,
136     NULL,
137 #endif
138     1,
139     "CHAP",
140 #if 0
141     NULL,
142     NULL,
143     NULL
144 #endif
145 };
146
147
148
149 /*****************************/
150 /*** LOCAL DATA STRUCTURES ***/
151 /*****************************/
152 static char *ChapCodenames[] = {
153         "Challenge", "Response", "Success", "Failure"
154 };
155
156
157
158 /***********************************/
159 /*** PUBLIC FUNCTION DEFINITIONS ***/
160 /***********************************/
161 /*
162  * ChapAuthWithPeer - Authenticate us with our peer (start client).
163  *
164  */
165 void ChapAuthWithPeer(int unit, char *our_name, int digest)
166 {
167         chap_state *cstate = &chap[unit];
168         
169         cstate->resp_name = our_name;
170         cstate->resp_type = digest;
171         
172         if (cstate->clientstate == CHAPCS_INITIAL ||
173                         cstate->clientstate == CHAPCS_PENDING) {
174                 /* lower layer isn't up - wait until later */
175                 cstate->clientstate = CHAPCS_PENDING;
176                 return;
177         }
178         
179         /*
180          * We get here as a result of LCP coming up.
181          * So even if CHAP was open before, we will 
182          * have to re-authenticate ourselves.
183          */
184         cstate->clientstate = CHAPCS_LISTEN;
185 }
186
187
188 /*
189  * ChapAuthPeer - Authenticate our peer (start server).
190  */
191 void ChapAuthPeer(int unit, char *our_name, int digest)
192 {
193         chap_state *cstate = &chap[unit];
194         
195         cstate->chal_name = our_name;
196         cstate->chal_type = digest;
197         
198         if (cstate->serverstate == CHAPSS_INITIAL ||
199                         cstate->serverstate == CHAPSS_PENDING) {
200                 /* lower layer isn't up - wait until later */
201                 cstate->serverstate = CHAPSS_PENDING;
202                 return;
203         }
204         
205         ChapGenChallenge(cstate);
206         ChapSendChallenge(cstate);              /* crank it up dude! */
207         cstate->serverstate = CHAPSS_INITIAL_CHAL;
208 }
209
210
211
212
213 /**********************************/
214 /*** LOCAL FUNCTION DEFINITIONS ***/
215 /**********************************/
216 /*
217  * ChapInit - Initialize a CHAP unit.
218  */
219 static void ChapInit(int unit)
220 {
221         chap_state *cstate = &chap[unit];
222         
223         BZERO(cstate, sizeof(*cstate));
224         cstate->unit = unit;
225         cstate->clientstate = CHAPCS_INITIAL;
226         cstate->serverstate = CHAPSS_INITIAL;
227         cstate->timeouttime = CHAP_DEFTIMEOUT;
228         cstate->max_transmits = CHAP_DEFTRANSMITS;
229         /* random number generator is initialized in magic_init */
230 }
231
232
233 /*
234  * ChapChallengeTimeout - Timeout expired on sending challenge.
235  */
236 static void ChapChallengeTimeout(void *arg)
237 {
238         chap_state *cstate = (chap_state *) arg;
239         
240         /* if we aren't sending challenges, don't worry.  then again we */
241         /* probably shouldn't be here either */
242         if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
243                         cstate->serverstate != CHAPSS_RECHALLENGE)
244                 return;
245         
246         if (cstate->chal_transmits >= cstate->max_transmits) {
247                 /* give up on peer */
248                 CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
249                 cstate->serverstate = CHAPSS_BADAUTH;
250                 auth_peer_fail(cstate->unit, PPP_CHAP);
251                 return;
252         }
253         
254         ChapSendChallenge(cstate);              /* Re-send challenge */
255 }
256
257
258 /*
259  * ChapResponseTimeout - Timeout expired on sending response.
260  */
261 static void ChapResponseTimeout(void *arg)
262 {
263         chap_state *cstate = (chap_state *) arg;
264         
265         /* if we aren't sending a response, don't worry. */
266         if (cstate->clientstate != CHAPCS_RESPONSE)
267                 return;
268         
269         ChapSendResponse(cstate);               /* re-send response */
270 }
271
272
273 /*
274  * ChapRechallenge - Time to challenge the peer again.
275  */
276 static void ChapRechallenge(void *arg)
277 {
278         chap_state *cstate = (chap_state *) arg;
279         
280         /* if we aren't sending a response, don't worry. */
281         if (cstate->serverstate != CHAPSS_OPEN)
282                 return;
283         
284         ChapGenChallenge(cstate);
285         ChapSendChallenge(cstate);
286         cstate->serverstate = CHAPSS_RECHALLENGE;
287 }
288
289
290 /*
291  * ChapLowerUp - The lower layer is up.
292  *
293  * Start up if we have pending requests.
294  */
295 static void ChapLowerUp(int unit)
296 {
297         chap_state *cstate = &chap[unit];
298         
299         if (cstate->clientstate == CHAPCS_INITIAL)
300                 cstate->clientstate = CHAPCS_CLOSED;
301         else if (cstate->clientstate == CHAPCS_PENDING)
302                 cstate->clientstate = CHAPCS_LISTEN;
303         
304         if (cstate->serverstate == CHAPSS_INITIAL)
305                 cstate->serverstate = CHAPSS_CLOSED;
306         else if (cstate->serverstate == CHAPSS_PENDING) {
307                 ChapGenChallenge(cstate);
308                 ChapSendChallenge(cstate);
309                 cstate->serverstate = CHAPSS_INITIAL_CHAL;
310         }
311 }
312
313
314 /*
315  * ChapLowerDown - The lower layer is down.
316  *
317  * Cancel all timeouts.
318  */
319 static void ChapLowerDown(int unit)
320 {
321         chap_state *cstate = &chap[unit];
322         
323         /* Timeout(s) pending?  Cancel if so. */
324         if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
325                         cstate->serverstate == CHAPSS_RECHALLENGE)
326                 UNTIMEOUT(ChapChallengeTimeout, cstate);
327         else if (cstate->serverstate == CHAPSS_OPEN
328                         && cstate->chal_interval != 0)
329                 UNTIMEOUT(ChapRechallenge, cstate);
330         if (cstate->clientstate == CHAPCS_RESPONSE)
331                 UNTIMEOUT(ChapResponseTimeout, cstate);
332         
333         cstate->clientstate = CHAPCS_INITIAL;
334         cstate->serverstate = CHAPSS_INITIAL;
335 }
336
337
338 /*
339  * ChapProtocolReject - Peer doesn't grok CHAP.
340  */
341 static void ChapProtocolReject(int unit)
342 {
343         chap_state *cstate = &chap[unit];
344         
345         if (cstate->serverstate != CHAPSS_INITIAL &&
346                         cstate->serverstate != CHAPSS_CLOSED)
347                 auth_peer_fail(unit, PPP_CHAP);
348         if (cstate->clientstate != CHAPCS_INITIAL &&
349                         cstate->clientstate != CHAPCS_CLOSED)
350                 auth_withpeer_fail(unit, PPP_CHAP);
351         ChapLowerDown(unit);            /* shutdown chap */
352 }
353
354
355 /*
356  * ChapInput - Input CHAP packet.
357  */
358 static void ChapInput(int unit, u_char *inpacket, int packet_len)
359 {
360         chap_state *cstate = &chap[unit];
361         u_char *inp;
362         u_char code, id;
363         int len;
364         
365         /*
366          * Parse header (code, id and length).
367          * If packet too short, drop it.
368          */
369         inp = inpacket;
370         if (packet_len < CHAP_HEADERLEN) {
371                 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
372                 return;
373         }
374         GETCHAR(code, inp);
375         GETCHAR(id, inp);
376         GETSHORT(len, inp);
377         if (len < CHAP_HEADERLEN) {
378                 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
379                 return;
380         }
381         if (len > packet_len) {
382                 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
383                 return;
384         }
385         len -= CHAP_HEADERLEN;
386         
387         /*
388          * Action depends on code (as in fact it usually does :-).
389          */
390         switch (code) {
391         case CHAP_CHALLENGE:
392                 ChapReceiveChallenge(cstate, inp, id, len);
393                 break;
394         
395         case CHAP_RESPONSE:
396                 ChapReceiveResponse(cstate, inp, id, len);
397                 break;
398         
399         case CHAP_FAILURE:
400                 ChapReceiveFailure(cstate, inp, id, len);
401                 break;
402         
403         case CHAP_SUCCESS:
404                 ChapReceiveSuccess(cstate, inp, id, len);
405                 break;
406         
407         default:                                /* Need code reject? */
408                 CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
409                 break;
410         }
411 }
412
413
414 /*
415  * ChapReceiveChallenge - Receive Challenge and send Response.
416  */
417 static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
418 {
419         int rchallenge_len;
420         u_char *rchallenge;
421         int secret_len;
422         char secret[MAXSECRETLEN];
423         char rhostname[256];
424         MD5_CTX mdContext;
425         u_char hash[MD5_SIGNATURE_SIZE];
426         
427         CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
428         if (cstate->clientstate == CHAPCS_CLOSED ||
429                 cstate->clientstate == CHAPCS_PENDING) {
430                 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
431                            cstate->clientstate));
432                 return;
433         }
434         
435         if (len < 2) {
436                 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
437                 return;
438         }
439         
440         GETCHAR(rchallenge_len, inp);
441         len -= sizeof (u_char) + rchallenge_len;        /* now name field length */
442         if (len < 0) {
443                 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
444                 return;
445         }
446         rchallenge = inp;
447         INCPTR(rchallenge_len, inp);
448         
449         if (len >= sizeof(rhostname))
450                 len = sizeof(rhostname) - 1;
451         BCOPY(inp, rhostname, len);
452         rhostname[len] = '\000';
453         
454         CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n",
455                rhostname));
456         
457         /* Microsoft doesn't send their name back in the PPP packet */
458         if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
459                 strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
460                 rhostname[sizeof(rhostname) - 1] = 0;
461                 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n",
462                            rhostname));
463         }
464         
465         /* get secret for authenticating ourselves with the specified host */
466         if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
467                             secret, &secret_len, 0)) {
468                 secret_len = 0;         /* assume null secret if can't find one */
469                 CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
470         }
471         
472         /* cancel response send timeout if necessary */
473         if (cstate->clientstate == CHAPCS_RESPONSE)
474                 UNTIMEOUT(ChapResponseTimeout, cstate);
475         
476         cstate->resp_id = id;
477         cstate->resp_transmits = 0;
478         
479         /*  generate MD based on negotiated type */
480         switch (cstate->resp_type) { 
481         
482         case CHAP_DIGEST_MD5:
483                 MD5Init(&mdContext);
484                 MD5Update(&mdContext, &cstate->resp_id, 1);
485                 MD5Update(&mdContext, (u_char*)secret, secret_len);
486                 MD5Update(&mdContext, rchallenge, rchallenge_len);
487                 MD5Final(hash, &mdContext);
488                 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
489                 cstate->resp_length = MD5_SIGNATURE_SIZE;
490                 break;
491         
492 #ifdef CHAPMS
493         case CHAP_MICROSOFT:
494                 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
495                 break;
496 #endif
497         
498         default:
499                 CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
500                 return;
501         }
502         
503         BZERO(secret, sizeof(secret));
504         ChapSendResponse(cstate);
505 }
506
507
508 /*
509  * ChapReceiveResponse - Receive and process response.
510  */
511 static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
512 {
513         u_char *remmd, remmd_len;
514         int secret_len, old_state;
515         int code;
516         char rhostname[256];
517         MD5_CTX mdContext;
518         char secret[MAXSECRETLEN];
519         u_char hash[MD5_SIGNATURE_SIZE];
520         
521         CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
522         
523         if (cstate->serverstate == CHAPSS_CLOSED ||
524                         cstate->serverstate == CHAPSS_PENDING) {
525                 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
526                 cstate->serverstate));
527                 return;
528         }
529         
530         if (id != cstate->chal_id)
531                 return;                 /* doesn't match ID of last challenge */
532         
533         /*
534         * If we have received a duplicate or bogus Response,
535         * we have to send the same answer (Success/Failure)
536         * as we did for the first Response we saw.
537         */
538         if (cstate->serverstate == CHAPSS_OPEN) {
539                 ChapSendStatus(cstate, CHAP_SUCCESS);
540                 return;
541         }
542         if (cstate->serverstate == CHAPSS_BADAUTH) {
543                 ChapSendStatus(cstate, CHAP_FAILURE);
544                 return;
545         }
546         
547         if (len < 2) {
548                 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
549                 return;
550         }
551         GETCHAR(remmd_len, inp);                /* get length of MD */
552         remmd = inp;                    /* get pointer to MD */
553         INCPTR(remmd_len, inp);
554         
555         len -= sizeof (u_char) + remmd_len;
556         if (len < 0) {
557                 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
558                 return;
559         }
560         
561         UNTIMEOUT(ChapChallengeTimeout, cstate);
562         
563         if (len >= sizeof(rhostname))
564                 len = sizeof(rhostname) - 1;
565         BCOPY(inp, rhostname, len);
566         rhostname[len] = '\000';
567         
568         CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n",
569                                 rhostname));
570         
571         /*
572         * Get secret for authenticating them with us,
573         * do the hash ourselves, and compare the result.
574         */
575         code = CHAP_FAILURE;
576         if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
577         secret, &secret_len, 1)) {
578 /*        CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
579                 CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
580                 rhostname));
581         } else {
582         
583                 /*  generate MD based on negotiated type */
584                 switch (cstate->chal_type) { 
585                 
586                 case CHAP_DIGEST_MD5:           /* only MD5 is defined for now */
587                         if (remmd_len != MD5_SIGNATURE_SIZE)
588                                 break;                  /* it's not even the right length */
589                         MD5Init(&mdContext);
590                         MD5Update(&mdContext, &cstate->chal_id, 1);
591                         MD5Update(&mdContext, (u_char*)secret, secret_len);
592                         MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
593                         MD5Final(hash, &mdContext); 
594                         
595                         /* compare local and remote MDs and send the appropriate status */
596                         if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
597                                 code = CHAP_SUCCESS;    /* they are the same! */
598                         break;
599                 
600                 default:
601                         CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
602                 }
603         }
604         
605         BZERO(secret, sizeof(secret));
606         ChapSendStatus(cstate, code);
607         
608         if (code == CHAP_SUCCESS) {
609                 old_state = cstate->serverstate;
610                 cstate->serverstate = CHAPSS_OPEN;
611                 if (old_state == CHAPSS_INITIAL_CHAL) {
612                         auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
613                 }
614                 if (cstate->chal_interval != 0)
615                         TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
616         } else {
617                 CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
618                 cstate->serverstate = CHAPSS_BADAUTH;
619                 auth_peer_fail(cstate->unit, PPP_CHAP);
620         }
621 }
622
623 /*
624  * ChapReceiveSuccess - Receive Success
625  */
626 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
627 {
628
629         CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
630         
631         if (cstate->clientstate == CHAPCS_OPEN)
632                 /* presumably an answer to a duplicate response */
633                 return;
634         
635         if (cstate->clientstate != CHAPCS_RESPONSE) {
636                 /* don't know what this is */
637                 CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
638                            cstate->clientstate));
639                 return;
640         }
641         
642         UNTIMEOUT(ChapResponseTimeout, cstate);
643         
644         /*
645          * Print message.
646          */
647         if (len > 0)
648                 PRINTMSG(inp, len);
649         
650         cstate->clientstate = CHAPCS_OPEN;
651         
652         auth_withpeer_success(cstate->unit, PPP_CHAP);
653 }
654
655
656 /*
657  * ChapReceiveFailure - Receive failure.
658  */
659 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
660 {
661         CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
662         
663         if (cstate->clientstate != CHAPCS_RESPONSE) {
664                 /* don't know what this is */
665                 CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
666                            cstate->clientstate));
667                 return;
668         }
669         
670         UNTIMEOUT(ChapResponseTimeout, cstate);
671         
672         /*
673          * Print message.
674          */
675         if (len > 0)
676                 PRINTMSG(inp, len);
677         
678         CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
679         auth_withpeer_fail(cstate->unit, PPP_CHAP);
680 }
681
682
683 /*
684  * ChapSendChallenge - Send an Authenticate challenge.
685  */
686 static void ChapSendChallenge(chap_state *cstate)
687 {
688         u_char *outp;
689         int chal_len, name_len;
690         int outlen;
691         
692         chal_len = cstate->chal_len;
693         name_len = strlen(cstate->chal_name);
694         outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
695         outp = outpacket_buf[cstate->unit];
696         
697         MAKEHEADER(outp, PPP_CHAP);             /* paste in a CHAP header */
698         
699         PUTCHAR(CHAP_CHALLENGE, outp);
700         PUTCHAR(cstate->chal_id, outp);
701         PUTSHORT(outlen, outp);
702         
703         PUTCHAR(chal_len, outp);                /* put length of challenge */
704         BCOPY(cstate->challenge, outp, chal_len);
705         INCPTR(chal_len, outp);
706         
707         BCOPY(cstate->chal_name, outp, name_len);       /* append hostname */
708         
709         pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
710         
711         CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
712         
713         TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
714         ++cstate->chal_transmits;
715 }
716
717
718 /*
719  * ChapSendStatus - Send a status response (ack or nak).
720  */
721 static void ChapSendStatus(chap_state *cstate, int code)
722 {
723         u_char *outp;
724         int outlen, msglen;
725         char msg[256];
726         
727         if (code == CHAP_SUCCESS)
728                 strcpy(msg, "Welcome!");
729         else
730                 strcpy(msg, "I don't like you.  Go 'way.");
731         msglen = strlen(msg);
732         
733         outlen = CHAP_HEADERLEN + msglen;
734         outp = outpacket_buf[cstate->unit];
735         
736         MAKEHEADER(outp, PPP_CHAP);             /* paste in a header */
737         
738         PUTCHAR(code, outp);
739         PUTCHAR(cstate->chal_id, outp);
740         PUTSHORT(outlen, outp);
741         BCOPY(msg, outp, msglen);
742         pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
743         
744         CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code,
745                cstate->chal_id));
746 }
747
748 /*
749  * ChapGenChallenge is used to generate a pseudo-random challenge string of
750  * a pseudo-random length between min_len and max_len.  The challenge
751  * string and its length are stored in *cstate, and various other fields of
752  * *cstate are initialized.
753  */
754
755 static void ChapGenChallenge(chap_state *cstate)
756 {
757         int chal_len;
758         u_char *ptr = cstate->challenge;
759         int i;
760         
761         /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
762            MAX_CHALLENGE_LENGTH */  
763         chal_len = (unsigned)
764                                 ((((magic() >> 16) *
765                                 (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
766                              + MIN_CHALLENGE_LENGTH);
767         cstate->chal_len = chal_len;
768         cstate->chal_id = ++cstate->id;
769         cstate->chal_transmits = 0;
770         
771         /* generate a random string */
772         for (i = 0; i < chal_len; i++ )
773                 *ptr++ = (char) (magic() & 0xff);
774 }
775
776 /*
777  * ChapSendResponse - send a response packet with values as specified
778  * in *cstate.
779  */
780 /* ARGSUSED */
781 static void ChapSendResponse(chap_state *cstate)
782 {
783         u_char *outp;
784         int outlen, md_len, name_len;
785         
786         md_len = cstate->resp_length;
787         name_len = strlen(cstate->resp_name);
788         outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
789         outp = outpacket_buf[cstate->unit];
790         
791         MAKEHEADER(outp, PPP_CHAP);
792         
793         PUTCHAR(CHAP_RESPONSE, outp);   /* we are a response */
794         PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
795         PUTSHORT(outlen, outp);                 /* packet length */
796         
797         PUTCHAR(md_len, outp);                  /* length of MD */
798         BCOPY(cstate->response, outp, md_len);          /* copy MD to buffer */
799         INCPTR(md_len, outp);
800         
801         BCOPY(cstate->resp_name, outp, name_len);       /* append our name */
802         
803         /* send the packet */
804         pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
805         
806         cstate->clientstate = CHAPCS_RESPONSE;
807         TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
808         ++cstate->resp_transmits;
809 }
810
811 /*
812  * ChapPrintPkt - print the contents of a CHAP packet.
813  */
814 static int ChapPrintPkt(
815         u_char *p,
816         int plen,
817         void (*printer) (void *, char *, ...),
818         void *arg
819 )
820 {
821         int code, id, len;
822         int clen, nlen;
823         u_char x;
824         
825         if (plen < CHAP_HEADERLEN)
826                 return 0;
827         GETCHAR(code, p);
828         GETCHAR(id, p);
829         GETSHORT(len, p);
830         if (len < CHAP_HEADERLEN || len > plen)
831                 return 0;
832         
833         if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
834                 printer(arg, " %s", ChapCodenames[code-1]);
835         else
836                 printer(arg, " code=0x%x", code);
837         printer(arg, " id=0x%x", id);
838         len -= CHAP_HEADERLEN;
839         switch (code) {
840         case CHAP_CHALLENGE:
841         case CHAP_RESPONSE:
842                 if (len < 1)
843                         break;
844                 clen = p[0];
845                 if (len < clen + 1)
846                         break;
847                 ++p;
848                 nlen = len - clen - 1;
849                 printer(arg, " <");
850                 for (; clen > 0; --clen) {
851                         GETCHAR(x, p);
852                         printer(arg, "%.2x", x);
853                 }
854                 printer(arg, ">, name = %.*Z", nlen, p);
855                 break;
856         case CHAP_FAILURE:
857         case CHAP_SUCCESS:
858                 printer(arg, " %.*Z", len, p);
859                 break;
860         default:
861                 for (clen = len; clen > 0; --clen) {
862                         GETCHAR(x, p);
863                         printer(arg, " %.2x", x);
864                 }
865         }
866         
867         return len + CHAP_HEADERLEN;
868 }
869
870 #endif
871
872 #endif /* PPP_SUPPORT */