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