Updates to help it compile with glibc 2
[mpls-ppp.git] / pppd / chap.c
blob189eb20ecc2de6ebbf5a22359c39fd3365e037fe
1 /*
2 * chap.c - Challenge Handshake Authentication Protocol.
4 * Copyright (c) 1993 The Australian National University.
5 * All rights reserved.
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.
19 * Copyright (c) 1991 Gregory M. Christy.
20 * All rights reserved.
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.
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.
36 #ifndef lint
37 static char rcsid[] = "$Id: chap.c,v 1.15 1997/11/27 06:07:48 paulus Exp $";
38 #endif
41 * TODO:
44 #include <stdio.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <syslog.h>
50 #include "pppd.h"
51 #include "chap.h"
52 #include "md5.h"
53 #ifdef CHAPMS
54 #include "chap_ms.h"
55 #endif
58 * Protocol entry points.
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 *));
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,
80 "CHAP",
81 NULL,
82 NULL,
83 NULL
86 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
88 static void ChapChallengeTimeout __P((void *));
89 static void ChapResponseTimeout __P((void *));
90 static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
91 static void ChapRechallenge __P((void *));
92 static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
93 static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
94 static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
95 static void ChapSendStatus __P((chap_state *, int));
96 static void ChapSendChallenge __P((chap_state *));
97 static void ChapSendResponse __P((chap_state *));
98 static void ChapGenChallenge __P((chap_state *));
100 extern double drand48 __P((void));
101 extern void srand48 __P((long));
104 * ChapInit - Initialize a CHAP unit.
106 static void
107 ChapInit(unit)
108 int unit;
110 chap_state *cstate = &chap[unit];
112 BZERO(cstate, sizeof(*cstate));
113 cstate->unit = unit;
114 cstate->clientstate = CHAPCS_INITIAL;
115 cstate->serverstate = CHAPSS_INITIAL;
116 cstate->timeouttime = CHAP_DEFTIMEOUT;
117 cstate->max_transmits = CHAP_DEFTRANSMITS;
118 /* random number generator is initialized in magic_init */
123 * ChapAuthWithPeer - Authenticate us with our peer (start client).
126 void
127 ChapAuthWithPeer(unit, our_name, digest)
128 int unit;
129 char *our_name;
130 int digest;
132 chap_state *cstate = &chap[unit];
134 cstate->resp_name = our_name;
135 cstate->resp_type = digest;
137 if (cstate->clientstate == CHAPCS_INITIAL ||
138 cstate->clientstate == CHAPCS_PENDING) {
139 /* lower layer isn't up - wait until later */
140 cstate->clientstate = CHAPCS_PENDING;
141 return;
145 * We get here as a result of LCP coming up.
146 * So even if CHAP was open before, we will
147 * have to re-authenticate ourselves.
149 cstate->clientstate = CHAPCS_LISTEN;
154 * ChapAuthPeer - Authenticate our peer (start server).
156 void
157 ChapAuthPeer(unit, our_name, digest)
158 int unit;
159 char *our_name;
160 int digest;
162 chap_state *cstate = &chap[unit];
164 cstate->chal_name = our_name;
165 cstate->chal_type = digest;
167 if (cstate->serverstate == CHAPSS_INITIAL ||
168 cstate->serverstate == CHAPSS_PENDING) {
169 /* lower layer isn't up - wait until later */
170 cstate->serverstate = CHAPSS_PENDING;
171 return;
174 ChapGenChallenge(cstate);
175 ChapSendChallenge(cstate); /* crank it up dude! */
176 cstate->serverstate = CHAPSS_INITIAL_CHAL;
181 * ChapChallengeTimeout - Timeout expired on sending challenge.
183 static void
184 ChapChallengeTimeout(arg)
185 void *arg;
187 chap_state *cstate = (chap_state *) arg;
189 /* if we aren't sending challenges, don't worry. then again we */
190 /* probably shouldn't be here either */
191 if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
192 cstate->serverstate != CHAPSS_RECHALLENGE)
193 return;
195 if (cstate->chal_transmits >= cstate->max_transmits) {
196 /* give up on peer */
197 syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
198 cstate->serverstate = CHAPSS_BADAUTH;
199 auth_peer_fail(cstate->unit, PPP_CHAP);
200 return;
203 ChapSendChallenge(cstate); /* Re-send challenge */
208 * ChapResponseTimeout - Timeout expired on sending response.
210 static void
211 ChapResponseTimeout(arg)
212 void *arg;
214 chap_state *cstate = (chap_state *) arg;
216 /* if we aren't sending a response, don't worry. */
217 if (cstate->clientstate != CHAPCS_RESPONSE)
218 return;
220 ChapSendResponse(cstate); /* re-send response */
225 * ChapRechallenge - Time to challenge the peer again.
227 static void
228 ChapRechallenge(arg)
229 void *arg;
231 chap_state *cstate = (chap_state *) arg;
233 /* if we aren't sending a response, don't worry. */
234 if (cstate->serverstate != CHAPSS_OPEN)
235 return;
237 ChapGenChallenge(cstate);
238 ChapSendChallenge(cstate);
239 cstate->serverstate = CHAPSS_RECHALLENGE;
244 * ChapLowerUp - The lower layer is up.
246 * Start up if we have pending requests.
248 static void
249 ChapLowerUp(unit)
250 int unit;
252 chap_state *cstate = &chap[unit];
254 if (cstate->clientstate == CHAPCS_INITIAL)
255 cstate->clientstate = CHAPCS_CLOSED;
256 else if (cstate->clientstate == CHAPCS_PENDING)
257 cstate->clientstate = CHAPCS_LISTEN;
259 if (cstate->serverstate == CHAPSS_INITIAL)
260 cstate->serverstate = CHAPSS_CLOSED;
261 else if (cstate->serverstate == CHAPSS_PENDING) {
262 ChapGenChallenge(cstate);
263 ChapSendChallenge(cstate);
264 cstate->serverstate = CHAPSS_INITIAL_CHAL;
270 * ChapLowerDown - The lower layer is down.
272 * Cancel all timeouts.
274 static void
275 ChapLowerDown(unit)
276 int unit;
278 chap_state *cstate = &chap[unit];
280 /* Timeout(s) pending? Cancel if so. */
281 if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
282 cstate->serverstate == CHAPSS_RECHALLENGE)
283 UNTIMEOUT(ChapChallengeTimeout, cstate);
284 else if (cstate->serverstate == CHAPSS_OPEN
285 && cstate->chal_interval != 0)
286 UNTIMEOUT(ChapRechallenge, cstate);
287 if (cstate->clientstate == CHAPCS_RESPONSE)
288 UNTIMEOUT(ChapResponseTimeout, cstate);
290 cstate->clientstate = CHAPCS_INITIAL;
291 cstate->serverstate = CHAPSS_INITIAL;
296 * ChapProtocolReject - Peer doesn't grok CHAP.
298 static void
299 ChapProtocolReject(unit)
300 int unit;
302 chap_state *cstate = &chap[unit];
304 if (cstate->serverstate != CHAPSS_INITIAL &&
305 cstate->serverstate != CHAPSS_CLOSED)
306 auth_peer_fail(unit, PPP_CHAP);
307 if (cstate->clientstate != CHAPCS_INITIAL &&
308 cstate->clientstate != CHAPCS_CLOSED)
309 auth_withpeer_fail(unit, PPP_CHAP);
310 ChapLowerDown(unit); /* shutdown chap */
315 * ChapInput - Input CHAP packet.
317 static void
318 ChapInput(unit, inpacket, packet_len)
319 int unit;
320 u_char *inpacket;
321 int packet_len;
323 chap_state *cstate = &chap[unit];
324 u_char *inp;
325 u_char code, id;
326 int len;
329 * Parse header (code, id and length).
330 * If packet too short, drop it.
332 inp = inpacket;
333 if (packet_len < CHAP_HEADERLEN) {
334 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
335 return;
337 GETCHAR(code, inp);
338 GETCHAR(id, inp);
339 GETSHORT(len, inp);
340 if (len < CHAP_HEADERLEN) {
341 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
342 return;
344 if (len > packet_len) {
345 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
346 return;
348 len -= CHAP_HEADERLEN;
351 * Action depends on code (as in fact it usually does :-).
353 switch (code) {
354 case CHAP_CHALLENGE:
355 ChapReceiveChallenge(cstate, inp, id, len);
356 break;
358 case CHAP_RESPONSE:
359 ChapReceiveResponse(cstate, inp, id, len);
360 break;
362 case CHAP_FAILURE:
363 ChapReceiveFailure(cstate, inp, id, len);
364 break;
366 case CHAP_SUCCESS:
367 ChapReceiveSuccess(cstate, inp, id, len);
368 break;
370 default: /* Need code reject? */
371 syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
372 break;
378 * ChapReceiveChallenge - Receive Challenge and send Response.
380 static void
381 ChapReceiveChallenge(cstate, inp, id, len)
382 chap_state *cstate;
383 u_char *inp;
384 int id;
385 int len;
387 int rchallenge_len;
388 u_char *rchallenge;
389 int secret_len;
390 char secret[MAXSECRETLEN];
391 char rhostname[256];
392 MD5_CTX mdContext;
393 u_char hash[MD5_SIGNATURE_SIZE];
395 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
396 if (cstate->clientstate == CHAPCS_CLOSED ||
397 cstate->clientstate == CHAPCS_PENDING) {
398 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
399 cstate->clientstate));
400 return;
403 if (len < 2) {
404 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
405 return;
408 GETCHAR(rchallenge_len, inp);
409 len -= sizeof (u_char) + rchallenge_len; /* now name field length */
410 if (len < 0) {
411 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
412 return;
414 rchallenge = inp;
415 INCPTR(rchallenge_len, inp);
417 if (len >= sizeof(rhostname))
418 len = sizeof(rhostname) - 1;
419 BCOPY(inp, rhostname, len);
420 rhostname[len] = '\000';
422 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'",
423 rhostname));
425 /* Microsoft doesn't send their name back in the PPP packet */
426 if (remote_name[0] != 0 && (explicit_remote || rhostname[0] == 0)) {
427 strncpy(rhostname, remote_name, sizeof(rhostname));
428 rhostname[sizeof(rhostname) - 1] = 0;
429 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name",
430 rhostname));
433 /* get secret for authenticating ourselves with the specified host */
434 if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
435 secret, &secret_len, 0)) {
436 secret_len = 0; /* assume null secret if can't find one */
437 syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
438 rhostname);
441 /* cancel response send timeout if necessary */
442 if (cstate->clientstate == CHAPCS_RESPONSE)
443 UNTIMEOUT(ChapResponseTimeout, cstate);
445 cstate->resp_id = id;
446 cstate->resp_transmits = 0;
448 /* generate MD based on negotiated type */
449 switch (cstate->resp_type) {
451 case CHAP_DIGEST_MD5:
452 MD5Init(&mdContext);
453 MD5Update(&mdContext, &cstate->resp_id, 1);
454 MD5Update(&mdContext, secret, secret_len);
455 MD5Update(&mdContext, rchallenge, rchallenge_len);
456 MD5Final(hash, &mdContext);
457 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
458 cstate->resp_length = MD5_SIGNATURE_SIZE;
459 break;
461 #ifdef CHAPMS
462 case CHAP_MICROSOFT:
463 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
464 break;
465 #endif
467 default:
468 CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
469 return;
472 BZERO(secret, sizeof(secret));
473 ChapSendResponse(cstate);
478 * ChapReceiveResponse - Receive and process response.
480 static void
481 ChapReceiveResponse(cstate, inp, id, len)
482 chap_state *cstate;
483 u_char *inp;
484 int id;
485 int len;
487 u_char *remmd, remmd_len;
488 int secret_len, old_state;
489 int code;
490 char rhostname[256];
491 MD5_CTX mdContext;
492 char secret[MAXSECRETLEN];
493 u_char hash[MD5_SIGNATURE_SIZE];
495 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
497 if (cstate->serverstate == CHAPSS_CLOSED ||
498 cstate->serverstate == CHAPSS_PENDING) {
499 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
500 cstate->serverstate));
501 return;
504 if (id != cstate->chal_id)
505 return; /* doesn't match ID of last challenge */
508 * If we have received a duplicate or bogus Response,
509 * we have to send the same answer (Success/Failure)
510 * as we did for the first Response we saw.
512 if (cstate->serverstate == CHAPSS_OPEN) {
513 ChapSendStatus(cstate, CHAP_SUCCESS);
514 return;
516 if (cstate->serverstate == CHAPSS_BADAUTH) {
517 ChapSendStatus(cstate, CHAP_FAILURE);
518 return;
521 if (len < 2) {
522 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
523 return;
525 GETCHAR(remmd_len, inp); /* get length of MD */
526 remmd = inp; /* get pointer to MD */
527 INCPTR(remmd_len, inp);
529 len -= sizeof (u_char) + remmd_len;
530 if (len < 0) {
531 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
532 return;
535 UNTIMEOUT(ChapChallengeTimeout, cstate);
537 if (len >= sizeof(rhostname))
538 len = sizeof(rhostname) - 1;
539 BCOPY(inp, rhostname, len);
540 rhostname[len] = '\000';
542 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
543 rhostname));
546 * Get secret for authenticating them with us,
547 * do the hash ourselves, and compare the result.
549 code = CHAP_FAILURE;
550 if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
551 secret, &secret_len, 1)) {
552 syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
553 rhostname);
554 } else {
556 /* generate MD based on negotiated type */
557 switch (cstate->chal_type) {
559 case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
560 if (remmd_len != MD5_SIGNATURE_SIZE)
561 break; /* it's not even the right length */
562 MD5Init(&mdContext);
563 MD5Update(&mdContext, &cstate->chal_id, 1);
564 MD5Update(&mdContext, secret, secret_len);
565 MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
566 MD5Final(hash, &mdContext);
568 /* compare local and remote MDs and send the appropriate status */
569 if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
570 code = CHAP_SUCCESS; /* they are the same! */
571 break;
573 default:
574 CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
578 BZERO(secret, sizeof(secret));
579 ChapSendStatus(cstate, code);
581 if (code == CHAP_SUCCESS) {
582 old_state = cstate->serverstate;
583 cstate->serverstate = CHAPSS_OPEN;
584 if (old_state == CHAPSS_INITIAL_CHAL) {
585 auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
587 if (cstate->chal_interval != 0)
588 TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
589 syslog(LOG_NOTICE, "CHAP peer authentication succeeded for %s",
590 rhostname);
592 } else {
593 syslog(LOG_ERR, "CHAP peer authentication failed for remote host %s",
594 rhostname);
595 cstate->serverstate = CHAPSS_BADAUTH;
596 auth_peer_fail(cstate->unit, PPP_CHAP);
601 * ChapReceiveSuccess - Receive Success
603 static void
604 ChapReceiveSuccess(cstate, inp, id, len)
605 chap_state *cstate;
606 u_char *inp;
607 u_char id;
608 int len;
611 CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
613 if (cstate->clientstate == CHAPCS_OPEN)
614 /* presumably an answer to a duplicate response */
615 return;
617 if (cstate->clientstate != CHAPCS_RESPONSE) {
618 /* don't know what this is */
619 CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
620 cstate->clientstate));
621 return;
624 UNTIMEOUT(ChapResponseTimeout, cstate);
627 * Print message.
629 if (len > 0)
630 PRINTMSG(inp, len);
632 cstate->clientstate = CHAPCS_OPEN;
634 auth_withpeer_success(cstate->unit, PPP_CHAP);
639 * ChapReceiveFailure - Receive failure.
641 static void
642 ChapReceiveFailure(cstate, inp, id, len)
643 chap_state *cstate;
644 u_char *inp;
645 u_char id;
646 int len;
648 CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
650 if (cstate->clientstate != CHAPCS_RESPONSE) {
651 /* don't know what this is */
652 CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
653 cstate->clientstate));
654 return;
657 UNTIMEOUT(ChapResponseTimeout, cstate);
660 * Print message.
662 if (len > 0)
663 PRINTMSG(inp, len);
665 syslog(LOG_ERR, "CHAP authentication failed");
666 auth_withpeer_fail(cstate->unit, PPP_CHAP);
671 * ChapSendChallenge - Send an Authenticate challenge.
673 static void
674 ChapSendChallenge(cstate)
675 chap_state *cstate;
677 u_char *outp;
678 int chal_len, name_len;
679 int outlen;
681 chal_len = cstate->chal_len;
682 name_len = strlen(cstate->chal_name);
683 outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
684 outp = outpacket_buf;
686 MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
688 PUTCHAR(CHAP_CHALLENGE, outp);
689 PUTCHAR(cstate->chal_id, outp);
690 PUTSHORT(outlen, outp);
692 PUTCHAR(chal_len, outp); /* put length of challenge */
693 BCOPY(cstate->challenge, outp, chal_len);
694 INCPTR(chal_len, outp);
696 BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
698 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
700 CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
702 TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
703 ++cstate->chal_transmits;
708 * ChapSendStatus - Send a status response (ack or nak).
710 static void
711 ChapSendStatus(cstate, code)
712 chap_state *cstate;
713 int code;
715 u_char *outp;
716 int outlen, msglen;
717 char msg[256];
719 if (code == CHAP_SUCCESS)
720 sprintf(msg, "Welcome to %s.", hostname);
721 else
722 sprintf(msg, "I don't like you. Go 'way.");
723 msglen = strlen(msg);
725 outlen = CHAP_HEADERLEN + msglen;
726 outp = outpacket_buf;
728 MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
730 PUTCHAR(code, outp);
731 PUTCHAR(cstate->chal_id, outp);
732 PUTSHORT(outlen, outp);
733 BCOPY(msg, outp, msglen);
734 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
736 CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
737 cstate->chal_id));
741 * ChapGenChallenge is used to generate a pseudo-random challenge string of
742 * a pseudo-random length between min_len and max_len. The challenge
743 * string and its length are stored in *cstate, and various other fields of
744 * *cstate are initialized.
747 static void
748 ChapGenChallenge(cstate)
749 chap_state *cstate;
751 int chal_len;
752 u_char *ptr = cstate->challenge;
753 unsigned int i;
755 /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
756 MAX_CHALLENGE_LENGTH */
757 chal_len = (unsigned) ((drand48() *
758 (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
759 MIN_CHALLENGE_LENGTH);
760 cstate->chal_len = chal_len;
761 cstate->chal_id = ++cstate->id;
762 cstate->chal_transmits = 0;
764 /* generate a random string */
765 for (i = 0; i < chal_len; i++ )
766 *ptr++ = (char) (drand48() * 0xff);
770 * ChapSendResponse - send a response packet with values as specified
771 * in *cstate.
773 /* ARGSUSED */
774 static void
775 ChapSendResponse(cstate)
776 chap_state *cstate;
778 u_char *outp;
779 int outlen, md_len, name_len;
781 md_len = cstate->resp_length;
782 name_len = strlen(cstate->resp_name);
783 outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
784 outp = outpacket_buf;
786 MAKEHEADER(outp, PPP_CHAP);
788 PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
789 PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
790 PUTSHORT(outlen, outp); /* packet length */
792 PUTCHAR(md_len, outp); /* length of MD */
793 BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
794 INCPTR(md_len, outp);
796 BCOPY(cstate->resp_name, outp, name_len); /* append our name */
798 /* send the packet */
799 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
801 cstate->clientstate = CHAPCS_RESPONSE;
802 TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
803 ++cstate->resp_transmits;
807 * ChapPrintPkt - print the contents of a CHAP packet.
809 static char *ChapCodenames[] = {
810 "Challenge", "Response", "Success", "Failure"
813 static int
814 ChapPrintPkt(p, plen, printer, arg)
815 u_char *p;
816 int plen;
817 void (*printer) __P((void *, char *, ...));
818 void *arg;
820 int code, id, len;
821 int clen, nlen;
822 u_char x;
824 if (plen < CHAP_HEADERLEN)
825 return 0;
826 GETCHAR(code, p);
827 GETCHAR(id, p);
828 GETSHORT(len, p);
829 if (len < CHAP_HEADERLEN || len > plen)
830 return 0;
832 if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
833 printer(arg, " %s", ChapCodenames[code-1]);
834 else
835 printer(arg, " code=0x%x", code);
836 printer(arg, " id=0x%x", id);
837 len -= CHAP_HEADERLEN;
838 switch (code) {
839 case CHAP_CHALLENGE:
840 case CHAP_RESPONSE:
841 if (len < 1)
842 break;
843 clen = p[0];
844 if (len < clen + 1)
845 break;
846 ++p;
847 nlen = len - clen - 1;
848 printer(arg, " <");
849 for (; clen > 0; --clen) {
850 GETCHAR(x, p);
851 printer(arg, "%.2x", x);
853 printer(arg, ">, name = ");
854 print_string((char *)p, nlen, printer, arg);
855 break;
856 case CHAP_FAILURE:
857 case CHAP_SUCCESS:
858 printer(arg, " ");
859 print_string((char *)p, len, printer, arg);
860 break;
861 default:
862 for (clen = len; clen > 0; --clen) {
863 GETCHAR(x, p);
864 printer(arg, " %.2x", x);
868 return len + CHAP_HEADERLEN;