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