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