8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / chap.c
blob707b9f7a71661a7f06117e752dbc1c9e013d2f22
1 /*
2 * chap.c - Challenge Handshake Authentication Protocol.
4 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 1993 The Australian National University.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the Australian National University. The name of the University
16 * may not be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 * Copyright (c) 1991 Gregory M. Christy.
23 * All rights reserved.
25 * Redistribution and use in source and binary forms are permitted
26 * provided that the above copyright notice and this paragraph are
27 * duplicated in all such forms and that any documentation,
28 * advertising materials, and other materials related to such
29 * distribution and use acknowledge that the software was developed
30 * by Gregory M. Christy. The name of the author may not be used to
31 * endorse or promote products derived from this software without
32 * specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
35 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
36 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
39 #define RCSID "$Id: chap.c,v 1.24 1999/11/15 01:51:50 paulus Exp $"
42 * TODO:
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <sys/types.h>
49 #include <sys/time.h>
51 #include "pppd.h"
52 #include "chap.h"
53 #include "md5.h"
54 #if defined(CHAPMS) || defined(CHAPMSV2)
55 #include "chap_ms.h"
56 #endif
58 #if !defined(lint) && !defined(_lint)
59 static const char rcsid[] = RCSID;
60 #endif
63 * Command-line options.
65 static option_t chap_option_list[] = {
66 { "chap-restart", o_int, &chap[0].timeouttime,
67 "Set CHAP Challenge retry interval" },
68 { "chap-max-challenge", o_int, &chap[0].max_transmits,
69 "Max number of Challenges sent without a valid response" },
70 { "chap-interval", o_int, &chap[0].chal_interval,
71 "Set interval for rechallenge" },
72 #if defined(CHAPMS) && defined(MSLANMAN)
73 { "ms-lanman", o_bool, &ms_lanman,
74 "Use obsolete LAN Manager password when using MS-CHAP", 1 },
75 #endif
76 { NULL }
80 * Protocol entry points.
82 static void ChapInit __P((int));
83 static void ChapLowerUp __P((int));
84 static void ChapLowerDown __P((int));
85 static void ChapInput __P((int, u_char *, int));
86 static void ChapProtocolReject __P((int));
87 static int ChapPrintPkt __P((u_char *, int,
88 void (*) __P((void *, const char *, ...)), void *));
90 struct protent chap_protent = {
91 PPP_CHAP, /* PPP protocol number */
92 ChapInit, /* Initialization procedure */
93 ChapInput, /* Process a received packet */
94 ChapProtocolReject, /* Process a received protocol-reject */
95 ChapLowerUp, /* Lower layer has come up */
96 ChapLowerDown, /* Lower layer has gone down */
97 NULL, /* Open the protocol */
98 NULL, /* Close the protocol */
99 ChapPrintPkt, /* Print a packet in readable form */
100 NULL, /* Process a received data packet */
101 1, /* 0 iff protocol is disabled */
102 "CHAP", /* Text name of protocol */
103 NULL, /* Text name of corresponding data protocol */
104 chap_option_list, /* List of command-line options */
105 NULL, /* Check requested options, assign defaults */
106 NULL, /* Configure interface for demand-dial */
107 NULL /* Say whether to bring up link for this pkt */
110 /* Not static'd for plug-ins */
111 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
113 static void ChapChallengeTimeout __P((void *));
114 static void ChapResponseTimeout __P((void *));
115 static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
116 static void ChapRechallenge __P((void *));
117 static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
118 static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
119 static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
120 static void ChapSendStatus __P((chap_state *, int));
121 static void ChapSendChallenge __P((chap_state *));
122 static void ChapSendResponse __P((chap_state *));
123 static void ChapGenChallenge __P((chap_state *));
125 static const char *
126 chap_cstate(int clientstate)
128 static const char *cstate[] = { CHAPCS__LIST };
129 static char buf[32];
131 if (clientstate < 0 || clientstate >= Dim(cstate)) {
132 (void) slprintf(buf, sizeof(buf), "#%d", clientstate);
133 return (buf);
135 return cstate[clientstate];
138 static const char *
139 chap_sstate(int serverstate)
141 static const char *sstate[] = { CHAPSS__LIST };
142 static char buf[32];
144 if (serverstate < 0 || serverstate >= Dim(sstate)) {
145 (void) slprintf(buf, sizeof(buf), "#%d", serverstate);
146 return (buf);
148 return sstate[serverstate];
152 * ChapInit - Initialize a CHAP unit.
154 static void
155 ChapInit(unit)
156 int unit;
158 chap_state *cstate = &chap[unit];
160 BZERO(cstate, sizeof(*cstate));
161 cstate->unit = unit;
162 cstate->clientstate = CHAPCS_INITIAL;
163 cstate->serverstate = CHAPSS_INITIAL;
164 cstate->timeouttime = CHAP_DEFTIMEOUT;
165 cstate->max_transmits = CHAP_DEFTRANSMITS;
167 /* XXX save get_first_hwaddr() here. */
168 /* random number generator is initialized in magic_init */
173 * ChapAuthWithPeer - Authenticate us with our peer (start client).
176 void
177 ChapAuthWithPeer(unit, our_name, digest)
178 int unit;
179 char *our_name;
180 int digest;
182 chap_state *cstate = &chap[unit];
184 cstate->resp_name = our_name;
185 cstate->resp_type = digest;
187 if (cstate->clientstate == CHAPCS_INITIAL ||
188 cstate->clientstate == CHAPCS_PENDING) {
189 /* lower layer isn't up - wait until later */
190 cstate->clientstate = CHAPCS_PENDING;
191 return;
195 * We get here as a result of LCP coming up.
196 * So even if CHAP was open before, we will
197 * have to re-authenticate ourselves.
199 cstate->clientstate = CHAPCS_LISTEN;
204 * ChapAuthPeer - Authenticate our peer (start server).
206 void
207 ChapAuthPeer(unit, our_name, digest)
208 int unit;
209 char *our_name;
210 int digest;
212 chap_state *cstate = &chap[unit];
214 cstate->chal_name = our_name;
215 cstate->chal_type = digest;
217 if (cstate->serverstate == CHAPSS_INITIAL ||
218 cstate->serverstate == CHAPSS_PENDING) {
219 /* lower layer isn't up - wait until later */
220 cstate->serverstate = CHAPSS_PENDING;
221 return;
224 ChapGenChallenge(cstate);
225 ChapSendChallenge(cstate); /* crank it up dude! */
226 cstate->serverstate = CHAPSS_INITIAL_CHAL;
231 * ChapChallengeTimeout - Timeout expired on sending challenge.
233 static void
234 ChapChallengeTimeout(arg)
235 void *arg;
237 chap_state *cstate = (chap_state *) arg;
239 /* if we aren't sending challenges, don't worry. then again we */
240 /* probably shouldn't be here either */
241 if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
242 cstate->serverstate != CHAPSS_RECHALLENGE)
243 return;
245 if (cstate->chal_transmits >= cstate->max_transmits) {
246 /* give up on peer */
247 error("Peer failed to respond to CHAP challenge");
248 cstate->serverstate = CHAPSS_BADAUTH;
249 auth_peer_fail(cstate->unit, PPP_CHAP);
250 return;
253 ChapSendChallenge(cstate); /* Re-send challenge */
258 * ChapResponseTimeout - Timeout expired on sending response.
260 static void
261 ChapResponseTimeout(arg)
262 void *arg;
264 chap_state *cstate = (chap_state *) arg;
266 /* if we aren't sending a response, don't worry. */
267 if (cstate->clientstate != CHAPCS_RESPONSE)
268 return;
270 ChapSendResponse(cstate); /* re-send response */
275 * ChapRechallenge - Time to challenge the peer again.
277 static void
278 ChapRechallenge(arg)
279 void *arg;
281 chap_state *cstate = (chap_state *) arg;
283 /* if we aren't sending a response, don't worry. */
284 if (cstate->serverstate != CHAPSS_OPEN)
285 return;
287 ChapGenChallenge(cstate);
288 ChapSendChallenge(cstate);
289 cstate->serverstate = CHAPSS_RECHALLENGE;
294 * ChapLowerUp - The lower layer is up.
296 * Start up if we have pending requests.
298 static void
299 ChapLowerUp(unit)
300 int unit;
302 chap_state *cstate = &chap[unit];
304 if (cstate->clientstate == CHAPCS_INITIAL)
305 cstate->clientstate = CHAPCS_CLOSED;
306 else if (cstate->clientstate == CHAPCS_PENDING)
307 cstate->clientstate = CHAPCS_LISTEN;
309 if (cstate->serverstate == CHAPSS_INITIAL)
310 cstate->serverstate = CHAPSS_CLOSED;
311 else if (cstate->serverstate == CHAPSS_PENDING) {
312 ChapGenChallenge(cstate);
313 ChapSendChallenge(cstate);
314 cstate->serverstate = CHAPSS_INITIAL_CHAL;
320 * ChapLowerDown - The lower layer is down.
322 * Cancel all timeouts.
324 static void
325 ChapLowerDown(unit)
326 int unit;
328 chap_state *cstate = &chap[unit];
330 /* Timeout(s) pending? Cancel if so. */
331 if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
332 cstate->serverstate == CHAPSS_RECHALLENGE)
333 UNTIMEOUT(ChapChallengeTimeout, cstate);
334 else if (cstate->serverstate == CHAPSS_OPEN
335 && cstate->chal_interval != 0)
336 UNTIMEOUT(ChapRechallenge, cstate);
337 if (cstate->clientstate == CHAPCS_RESPONSE)
338 UNTIMEOUT(ChapResponseTimeout, cstate);
340 cstate->clientstate = CHAPCS_INITIAL;
341 cstate->serverstate = CHAPSS_INITIAL;
346 * ChapProtocolReject - Peer doesn't grok CHAP.
348 static void
349 ChapProtocolReject(unit)
350 int unit;
352 chap_state *cstate = &chap[unit];
354 if (cstate->serverstate != CHAPSS_INITIAL &&
355 cstate->serverstate != CHAPSS_CLOSED)
356 auth_peer_fail(unit, PPP_CHAP);
357 if (cstate->clientstate != CHAPCS_INITIAL &&
358 cstate->clientstate != CHAPCS_CLOSED)
359 auth_withpeer_fail(unit, PPP_CHAP);
360 ChapLowerDown(unit); /* shutdown chap */
365 * ChapInput - Input CHAP packet.
367 static void
368 ChapInput(unit, inpacket, packet_len)
369 int unit;
370 u_char *inpacket;
371 int packet_len;
373 chap_state *cstate = &chap[unit];
374 u_char *inp;
375 u_char code, id;
376 int len;
379 * Parse header (code, id and length).
380 * If packet too short, drop it.
382 inp = inpacket;
383 if (packet_len < CHAP_HEADERLEN) {
384 error("CHAP: packet is too small (%d < %d)", packet_len,
385 CHAP_HEADERLEN);
386 return;
388 GETCHAR(code, inp);
389 GETCHAR(id, inp);
390 GETSHORT(len, inp);
391 if (len < CHAP_HEADERLEN || len > packet_len) {
392 error("CHAP: packet has illegal length %d (%d..%d)",
393 len, CHAP_HEADERLEN, packet_len);
394 return;
396 len -= CHAP_HEADERLEN;
399 * Action depends on code (as in fact it usually does :-).
401 switch (code) {
402 case CHAP_CHALLENGE:
403 ChapReceiveChallenge(cstate, inp, id, len);
404 break;
406 case CHAP_RESPONSE:
407 ChapReceiveResponse(cstate, inp, id, len);
408 break;
410 case CHAP_FAILURE:
411 ChapReceiveFailure(cstate, inp, id, len);
412 break;
414 case CHAP_SUCCESS:
415 ChapReceiveSuccess(cstate, inp, id, len);
416 break;
418 default:
419 /* CHAP does not define a code reject. */
420 warn("Unknown CHAP code (%d) received.", code);
421 break;
427 * ChapReceiveChallenge - Receive Challenge and send Response.
429 static void
430 ChapReceiveChallenge(cstate, inp, id, len)
431 chap_state *cstate;
432 u_char *inp;
433 int id;
434 int len;
436 int rchallenge_len;
437 u_char *rchallenge;
438 int secret_len;
439 char rhostname[MAXNAMELEN];
440 char secret[MAXSECRETLEN];
441 MD5_CTX mdContext;
442 u_char hash[MD5_SIGNATURE_SIZE];
443 int fake_response = 0;
445 if (cstate->clientstate == CHAPCS_CLOSED ||
446 cstate->clientstate == CHAPCS_PENDING) {
447 if (debug)
448 dbglog("CHAP Challenge unexpectedly received in state %s",
449 chap_cstate(cstate->clientstate));
450 return;
453 if (len < 2) {
454 error("CHAP: Challenge message length %d", len);
455 return;
458 GETCHAR(rchallenge_len, inp);
459 len -= sizeof (u_char) + rchallenge_len; /* now name field length */
460 if (len < 0) {
461 error("CHAP: Challenge truncated");
462 return;
464 rchallenge = inp;
465 INCPTR(rchallenge_len, inp);
467 if (len >= sizeof(rhostname))
468 len = sizeof(rhostname) - 1;
469 if (len > 0) {
470 BCOPY(inp, rhostname, len);
472 rhostname[len] = '\0';
474 #ifdef CHECK_CHALLENGE_LENGTH
475 if (rchallenge_len < CHECK_CHALLENGE_LENGTH) {
476 warn("CHAP: Challenge from %s unreasonably short (%d octets)",
477 rhostname, rchallenge_len);
478 fake_response = 1;
480 #endif
482 /* XXX compare against saved get_first_hwaddr() here. */
484 /* Microsoft NT doesn't send a name in the CHAP Challenge message */
485 if (explicit_remote ||
486 (remote_name[0] != '\0' && rhostname[0] == '\0')) {
487 (void) strlcpy(rhostname, remote_name, sizeof(rhostname));
488 if (debug)
489 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
490 rhostname);
493 if (cstate->peercname[0] == '\0') {
494 (void) strlcpy(cstate->peercname, rhostname,
495 sizeof (cstate->peercname));
496 } else if (strcmp(rhostname, cstate->peercname) != 0) {
497 if (++cstate->rename_count == 1) {
498 info("CHAP: peer challenge name changed from '%q' to '%q'",
499 cstate->peercname, rhostname);
500 (void) strlcpy(cstate->peercname, rhostname,
501 sizeof (cstate->peercname));
502 } else {
503 fake_response = 1;
504 if (cstate->rename_count == 2)
505 warn("CHAP: peer challenge name changed again to '%q'",
506 rhostname);
510 /* get secret for authenticating ourselves with the specified host */
511 if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
512 secret, &secret_len, 0)) {
513 secret_len = 0; /* assume null secret if can't find one */
514 warn("No CHAP secret found for authenticating us (%q) to %q",
515 cstate->resp_name, rhostname);
518 /* cancel response send timeout if necessary */
519 if (cstate->clientstate == CHAPCS_RESPONSE)
520 UNTIMEOUT(ChapResponseTimeout, cstate);
522 cstate->resp_id = id;
523 cstate->resp_transmits = 0;
525 /* generate MD based on negotiated type */
526 switch (cstate->resp_type) {
528 case CHAP_DIGEST_MD5:
529 MD5Init(&mdContext);
530 MD5Update(&mdContext, &cstate->resp_id, 1);
531 MD5Update(&mdContext, (u_char *)secret, (unsigned)secret_len);
532 MD5Update(&mdContext, rchallenge, rchallenge_len);
533 MD5Final(hash, &mdContext);
534 if (fake_response) {
535 for (len = 0; len < MD5_SIGNATURE_SIZE; len++)
536 cstate->response[len] = (char) (drand48() * 0xff);
537 } else {
538 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
540 cstate->resp_length = MD5_SIGNATURE_SIZE;
541 break;
543 #ifdef CHAPMS
544 case CHAP_MICROSOFT:
545 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
546 break;
547 #endif
549 #ifdef CHAPMSV2
550 case CHAP_MICROSOFT_V2:
551 ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len);
552 break;
553 #endif
555 default:
556 error("CHAP: unknown digest type %d", cstate->resp_type);
557 return;
560 BZERO(secret, sizeof(secret));
561 ChapSendResponse(cstate);
566 * ChapReceiveResponse - Receive and process response.
568 static void
569 ChapReceiveResponse(cstate, inp, id, len)
570 chap_state *cstate;
571 u_char *inp;
572 int id;
573 int len;
575 u_char *remmd, remmd_len;
576 int secret_len, old_state;
577 int code;
578 char rhostname[MAXNAMELEN], *rhn;
579 MD5_CTX mdContext;
580 char secret[MAXSECRETLEN];
581 u_char hash[MD5_SIGNATURE_SIZE];
583 if (cstate->serverstate == CHAPSS_CLOSED ||
584 cstate->serverstate == CHAPSS_PENDING) {
585 if (debug)
586 dbglog("CHAP Response unexpectedly received in state %s",
587 chap_sstate(cstate->serverstate));
588 return;
591 if (id != cstate->chal_id) {
592 if (debug)
593 dbglog("CHAP: discard response %d; expecting %d", id,
594 cstate->chal_id);
595 return; /* doesn't match ID of last challenge */
599 * If we have received a duplicate or bogus Response,
600 * we have to send the same answer (Success/Failure)
601 * as we did for the first Response we saw.
603 if (cstate->serverstate == CHAPSS_OPEN) {
604 if (debug)
605 dbglog("CHAP ignoring response and resending success message");
606 ChapSendStatus(cstate, CHAP_SUCCESS);
607 return;
609 if (cstate->serverstate == CHAPSS_BADAUTH) {
610 if (debug)
611 dbglog("CHAP ignoring response and resending failure message");
612 ChapSendStatus(cstate, CHAP_FAILURE);
613 return;
616 if (len < 2) {
617 error("CHAP: Response message length %d", len);
618 return;
620 GETCHAR(remmd_len, inp); /* get length of MD */
621 remmd = inp; /* get pointer to MD */
622 INCPTR(remmd_len, inp);
624 len -= sizeof (u_char) + remmd_len;
625 if (len < 0) {
626 error("CHAP: Response truncated");
627 return;
630 UNTIMEOUT(ChapChallengeTimeout, cstate);
632 if (len >= sizeof(rhostname))
633 len = sizeof(rhostname) - 1;
634 BCOPY(inp, rhostname, len);
635 rhostname[len] = '\0';
638 * Get secret for authenticating them with us,
639 * do the hash ourselves, and compare the result.
641 code = CHAP_FAILURE;
642 rhn = (explicit_remote? remote_name: rhostname);
643 if (cstate->serverstate == CHAPSS_RECHALLENGE &&
644 strcmp(rhostname, peer_authname) != 0) {
645 warn("Peer changed his name from '%q' to '%q' on rechallenge",
646 peer_authname, rhostname);
647 } else if (!get_secret(cstate->unit, rhn, cstate->chal_name, secret,
648 &secret_len, 1)) {
649 warn("No CHAP secret found for authenticating %q to us (%q)",
650 rhn, cstate->chal_name);
651 } else {
653 /* generate MD based on negotiated type */
654 switch (cstate->chal_type) {
656 case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
657 if (remmd_len != MD5_SIGNATURE_SIZE)
658 break; /* it's not even the right length */
659 MD5Init(&mdContext);
660 MD5Update(&mdContext, &cstate->chal_id, 1);
661 MD5Update(&mdContext, (u_char *)secret, secret_len);
662 MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
663 MD5Final(hash, &mdContext);
665 /* compare local and remote MDs and send the appropriate status */
666 if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
667 code = CHAP_SUCCESS; /* they are the same! */
668 break;
670 #ifdef CHAPMS
671 case CHAP_MICROSOFT:
672 if (ChapMSValidate(cstate, remmd, remmd_len, secret,
673 secret_len))
674 code = CHAP_SUCCESS;
675 break;
676 #endif
678 #ifdef CHAPMSV2
679 case CHAP_MICROSOFT_V2:
680 if (ChapMSv2Validate(cstate, rhostname, remmd, remmd_len,
681 secret, secret_len))
682 code = CHAP_SUCCESS;
683 break;
684 #endif
686 default:
687 error("CHAP: unknown digest type %d", cstate->chal_type);
691 BZERO(secret, sizeof(secret));
692 ChapSendStatus(cstate, code);
694 if (code == CHAP_SUCCESS) {
695 old_state = cstate->serverstate;
696 cstate->serverstate = CHAPSS_OPEN;
697 if (old_state == CHAPSS_INITIAL_CHAL) {
698 auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
700 if (cstate->chal_interval != 0)
701 TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
702 if (old_state == CHAPSS_INITIAL_CHAL)
703 notice("CHAP peer authentication succeeded for %q", rhostname);
704 else if (debug)
705 dbglog("CHAP peer reauthentication succeeded for %q", rhostname);
706 } else {
707 error("CHAP peer %sauthentication failed for remote host %q",
708 (cstate->serverstate == CHAPSS_INITIAL_CHAL ? "" : "re"),
709 rhostname);
710 cstate->serverstate = CHAPSS_BADAUTH;
711 auth_peer_fail(cstate->unit, PPP_CHAP);
716 * ChapReceiveSuccess - Receive Success
718 /*ARGSUSED*/
719 static void
720 ChapReceiveSuccess(cstate, inp, id, len)
721 chap_state *cstate;
722 u_char *inp;
723 u_char id;
724 int len;
727 if (cstate->clientstate == CHAPCS_OPEN) {
728 /* presumably an answer to a duplicate response */
729 if (debug)
730 dbglog("CHAP duplicate Success message ignored");
731 return;
734 if (cstate->clientstate != CHAPCS_RESPONSE) {
735 /* don't know what this is */
736 if (debug)
737 dbglog("CHAP Success unexpectedly received in state %s",
738 chap_cstate(cstate->clientstate));
739 return;
742 UNTIMEOUT(ChapResponseTimeout, cstate);
745 * Print message.
747 if (len > 0)
748 PRINTMSG(inp, len);
750 cstate->clientstate = CHAPCS_OPEN;
752 auth_withpeer_success(cstate->unit, PPP_CHAP);
757 * ChapReceiveFailure - Receive failure.
759 /*ARGSUSED*/
760 static void
761 ChapReceiveFailure(cstate, inp, id, len)
762 chap_state *cstate;
763 u_char *inp;
764 u_char id;
765 int len;
767 if (cstate->clientstate != CHAPCS_RESPONSE) {
768 /* don't know what this is */
769 if (debug)
770 dbglog("CHAP Failure unexpectedly received in state %s",
771 chap_cstate(cstate->clientstate));
772 return;
775 UNTIMEOUT(ChapResponseTimeout, cstate);
778 * Print message.
780 if (len > 0)
781 PRINTMSG(inp, len);
783 error("CHAP authentication failed");
784 auth_withpeer_fail(cstate->unit, PPP_CHAP);
789 * ChapSendChallenge - Send an Authenticate challenge.
791 static void
792 ChapSendChallenge(cstate)
793 chap_state *cstate;
795 u_char *outp;
796 int chal_len, name_len;
797 int outlen;
799 chal_len = cstate->chal_len;
800 name_len = strlen(cstate->chal_name);
801 outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
802 outp = outpacket_buf;
804 MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
806 PUTCHAR(CHAP_CHALLENGE, outp);
807 PUTCHAR(cstate->chal_id, outp);
808 PUTSHORT(outlen, outp);
810 PUTCHAR(chal_len, outp); /* put length of challenge */
811 BCOPY(cstate->challenge, outp, chal_len);
812 INCPTR(chal_len, outp);
814 BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
816 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
818 TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
819 ++cstate->chal_transmits;
824 * ChapSendStatus - Send a status response (ack or nak).
826 static void
827 ChapSendStatus(cstate, code)
828 chap_state *cstate;
829 int code;
831 u_char *outp;
832 int outlen, msglen;
833 char msg[256], *msgp;
835 if ((msgp = cstate->stat_message) != NULL) {
836 msglen = cstate->stat_length;
837 } else {
838 if (code == CHAP_SUCCESS)
839 (void) slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
840 else
841 (void) slprintf(msg, sizeof(msg), "I don't like you. Go 'way.");
842 msglen = strlen(msg);
843 msgp = msg;
846 outlen = CHAP_HEADERLEN + msglen;
847 outp = outpacket_buf;
849 MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
851 PUTCHAR(code, outp);
852 PUTCHAR(cstate->chal_id, outp);
853 PUTSHORT(outlen, outp);
854 BCOPY(msgp, outp, msglen);
855 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
859 * ChapGenChallenge is used to generate a pseudo-random challenge string of
860 * a pseudo-random length between min_len and max_len. The challenge
861 * string and its length are stored in *cstate, and various other fields of
862 * *cstate are initialized.
865 static void
866 ChapGenChallenge(cstate)
867 chap_state *cstate;
869 int chal_len;
870 u_char *ptr = cstate->challenge;
871 int i;
873 /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
874 MAX_CHALLENGE_LENGTH */
875 chal_len = (unsigned) ((drand48() *
876 (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
877 MIN_CHALLENGE_LENGTH);
878 cstate->chal_len = chal_len;
879 cstate->chal_id = ++cstate->id;
880 cstate->chal_transmits = 0;
882 /* XXX tack on saved get_first_hwaddr() here. */
884 /* generate a random string */
885 for (i = 0; i < chal_len; i++)
886 *ptr++ = (char) (drand48() * 0xff);
890 * ChapSendResponse - send a response packet with values as specified
891 * in *cstate.
893 /* ARGSUSED */
894 static void
895 ChapSendResponse(cstate)
896 chap_state *cstate;
898 u_char *outp;
899 int outlen, md_len, name_len;
901 md_len = cstate->resp_length;
902 name_len = strlen(cstate->resp_name);
903 outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
904 outp = outpacket_buf;
906 MAKEHEADER(outp, PPP_CHAP);
908 PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
909 PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
910 PUTSHORT(outlen, outp); /* packet length */
912 PUTCHAR(md_len, outp); /* length of MD */
913 BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
914 INCPTR(md_len, outp);
916 BCOPY(cstate->resp_name, outp, name_len); /* append our name */
918 /* send the packet */
919 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
921 cstate->clientstate = CHAPCS_RESPONSE;
922 TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
923 ++cstate->resp_transmits;
927 * ChapPrintPkt - print the contents of a CHAP packet.
929 static char *ChapCodenames[] = {
930 "Challenge", "Response", "Success", "Failure"
933 static int
934 ChapPrintPkt(p, plen, printer, arg)
935 u_char *p;
936 int plen;
937 void (*printer) __P((void *, const char *, ...));
938 void *arg;
940 int code, id, len;
941 int clen, nlen;
942 u_char x;
944 if (plen < CHAP_HEADERLEN)
945 return 0;
946 GETCHAR(code, p);
947 GETCHAR(id, p);
948 GETSHORT(len, p);
949 if (len < CHAP_HEADERLEN || len > plen)
950 return 0;
952 if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
953 printer(arg, " %s", ChapCodenames[code-1]);
954 else
955 printer(arg, " code=0x%x", code);
956 printer(arg, " id=0x%x", id);
957 len -= CHAP_HEADERLEN;
958 switch (code) {
959 case CHAP_CHALLENGE:
960 case CHAP_RESPONSE:
961 if (len < 1)
962 break;
963 clen = p[0];
964 if (len < clen + 1)
965 break;
966 ++p;
967 nlen = len - clen - 1;
968 printer(arg, " <");
969 for (; clen > 0; --clen) {
970 GETCHAR(x, p);
971 printer(arg, "%.2x", x);
973 printer(arg, ">, name = ");
974 print_string((char *)p, nlen, printer, arg);
975 break;
976 case CHAP_FAILURE:
977 case CHAP_SUCCESS:
978 printer(arg, " ");
979 print_string((char *)p, len, printer, arg);
980 break;
981 default:
982 for (clen = len; clen > 0; --clen) {
983 GETCHAR(x, p);
984 printer(arg, " %.2x", x);
988 return len + CHAP_HEADERLEN;