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