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