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