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