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