]> git.ozlabs.org Git - ppp.git/blob - pppd/chap.c
update to 2.3.1
[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.14 1997/04/30 05:51:08 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
590     } else {
591         syslog(LOG_ERR, "CHAP peer authentication failed");
592         cstate->serverstate = CHAPSS_BADAUTH;
593         auth_peer_fail(cstate->unit, PPP_CHAP);
594     }
595 }
596
597 /*
598  * ChapReceiveSuccess - Receive Success
599  */
600 static void
601 ChapReceiveSuccess(cstate, inp, id, len)
602     chap_state *cstate;
603     u_char *inp;
604     u_char id;
605     int len;
606 {
607
608     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
609
610     if (cstate->clientstate == CHAPCS_OPEN)
611         /* presumably an answer to a duplicate response */
612         return;
613
614     if (cstate->clientstate != CHAPCS_RESPONSE) {
615         /* don't know what this is */
616         CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
617                    cstate->clientstate));
618         return;
619     }
620
621     UNTIMEOUT(ChapResponseTimeout, cstate);
622
623     /*
624      * Print message.
625      */
626     if (len > 0)
627         PRINTMSG(inp, len);
628
629     cstate->clientstate = CHAPCS_OPEN;
630
631     auth_withpeer_success(cstate->unit, PPP_CHAP);
632 }
633
634
635 /*
636  * ChapReceiveFailure - Receive failure.
637  */
638 static void
639 ChapReceiveFailure(cstate, inp, id, len)
640     chap_state *cstate;
641     u_char *inp;
642     u_char id;
643     int len;
644 {
645     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
646
647     if (cstate->clientstate != CHAPCS_RESPONSE) {
648         /* don't know what this is */
649         CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
650                    cstate->clientstate));
651         return;
652     }
653
654     UNTIMEOUT(ChapResponseTimeout, cstate);
655
656     /*
657      * Print message.
658      */
659     if (len > 0)
660         PRINTMSG(inp, len);
661
662     syslog(LOG_ERR, "CHAP authentication failed");
663     auth_withpeer_fail(cstate->unit, PPP_CHAP);
664 }
665
666
667 /*
668  * ChapSendChallenge - Send an Authenticate challenge.
669  */
670 static void
671 ChapSendChallenge(cstate)
672     chap_state *cstate;
673 {
674     u_char *outp;
675     int chal_len, name_len;
676     int outlen;
677
678     chal_len = cstate->chal_len;
679     name_len = strlen(cstate->chal_name);
680     outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
681     outp = outpacket_buf;
682
683     MAKEHEADER(outp, PPP_CHAP);         /* paste in a CHAP header */
684
685     PUTCHAR(CHAP_CHALLENGE, outp);
686     PUTCHAR(cstate->chal_id, outp);
687     PUTSHORT(outlen, outp);
688
689     PUTCHAR(chal_len, outp);            /* put length of challenge */
690     BCOPY(cstate->challenge, outp, chal_len);
691     INCPTR(chal_len, outp);
692
693     BCOPY(cstate->chal_name, outp, name_len);   /* append hostname */
694
695     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
696   
697     CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
698
699     TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
700     ++cstate->chal_transmits;
701 }
702
703
704 /*
705  * ChapSendStatus - Send a status response (ack or nak).
706  */
707 static void
708 ChapSendStatus(cstate, code)
709     chap_state *cstate;
710     int code;
711 {
712     u_char *outp;
713     int outlen, msglen;
714     char msg[256];
715
716     if (code == CHAP_SUCCESS)
717         sprintf(msg, "Welcome to %s.", hostname);
718     else
719         sprintf(msg, "I don't like you.  Go 'way.");
720     msglen = strlen(msg);
721
722     outlen = CHAP_HEADERLEN + msglen;
723     outp = outpacket_buf;
724
725     MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
726   
727     PUTCHAR(code, outp);
728     PUTCHAR(cstate->chal_id, outp);
729     PUTSHORT(outlen, outp);
730     BCOPY(msg, outp, msglen);
731     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
732   
733     CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
734                cstate->chal_id));
735 }
736
737 /*
738  * ChapGenChallenge is used to generate a pseudo-random challenge string of
739  * a pseudo-random length between min_len and max_len.  The challenge
740  * string and its length are stored in *cstate, and various other fields of
741  * *cstate are initialized.
742  */
743
744 static void
745 ChapGenChallenge(cstate)
746     chap_state *cstate;
747 {
748     int chal_len;
749     u_char *ptr = cstate->challenge;
750     unsigned int i;
751
752     /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
753        MAX_CHALLENGE_LENGTH */  
754     chal_len =  (unsigned) ((drand48() *
755                              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
756                             MIN_CHALLENGE_LENGTH);
757     cstate->chal_len = chal_len;
758     cstate->chal_id = ++cstate->id;
759     cstate->chal_transmits = 0;
760
761     /* generate a random string */
762     for (i = 0; i < chal_len; i++ )
763         *ptr++ = (char) (drand48() * 0xff);
764 }
765
766 /*
767  * ChapSendResponse - send a response packet with values as specified
768  * in *cstate.
769  */
770 /* ARGSUSED */
771 static void
772 ChapSendResponse(cstate)
773     chap_state *cstate;
774 {
775     u_char *outp;
776     int outlen, md_len, name_len;
777
778     md_len = cstate->resp_length;
779     name_len = strlen(cstate->resp_name);
780     outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
781     outp = outpacket_buf;
782
783     MAKEHEADER(outp, PPP_CHAP);
784
785     PUTCHAR(CHAP_RESPONSE, outp);       /* we are a response */
786     PUTCHAR(cstate->resp_id, outp);     /* copy id from challenge packet */
787     PUTSHORT(outlen, outp);             /* packet length */
788
789     PUTCHAR(md_len, outp);              /* length of MD */
790     BCOPY(cstate->response, outp, md_len);      /* copy MD to buffer */
791     INCPTR(md_len, outp);
792
793     BCOPY(cstate->resp_name, outp, name_len); /* append our name */
794
795     /* send the packet */
796     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
797
798     cstate->clientstate = CHAPCS_RESPONSE;
799     TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
800     ++cstate->resp_transmits;
801 }
802
803 /*
804  * ChapPrintPkt - print the contents of a CHAP packet.
805  */
806 static char *ChapCodenames[] = {
807     "Challenge", "Response", "Success", "Failure"
808 };
809
810 static int
811 ChapPrintPkt(p, plen, printer, arg)
812     u_char *p;
813     int plen;
814     void (*printer) __P((void *, char *, ...));
815     void *arg;
816 {
817     int code, id, len;
818     int clen, nlen;
819     u_char x;
820
821     if (plen < CHAP_HEADERLEN)
822         return 0;
823     GETCHAR(code, p);
824     GETCHAR(id, p);
825     GETSHORT(len, p);
826     if (len < CHAP_HEADERLEN || len > plen)
827         return 0;
828
829     if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
830         printer(arg, " %s", ChapCodenames[code-1]);
831     else
832         printer(arg, " code=0x%x", code);
833     printer(arg, " id=0x%x", id);
834     len -= CHAP_HEADERLEN;
835     switch (code) {
836     case CHAP_CHALLENGE:
837     case CHAP_RESPONSE:
838         if (len < 1)
839             break;
840         clen = p[0];
841         if (len < clen + 1)
842             break;
843         ++p;
844         nlen = len - clen - 1;
845         printer(arg, " <");
846         for (; clen > 0; --clen) {
847             GETCHAR(x, p);
848             printer(arg, "%.2x", x);
849         }
850         printer(arg, ">, name = ");
851         print_string((char *)p, nlen, printer, arg);
852         break;
853     case CHAP_FAILURE:
854     case CHAP_SUCCESS:
855         printer(arg, " ");
856         print_string((char *)p, len, printer, arg);
857         break;
858     default:
859         for (clen = len; clen > 0; --clen) {
860             GETCHAR(x, p);
861             printer(arg, " %.2x", x);
862         }
863     }
864
865     return len + CHAP_HEADERLEN;
866 }