dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / chap.c
blobd517c596add99e235e674f78cddac856fcc57be3
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 static const char rcsid[] = RCSID;
61 * Command-line options.
63 static option_t chap_option_list[] = {
64 { "chap-restart", o_int, &chap[0].timeouttime,
65 "Set CHAP Challenge retry interval" },
66 { "chap-max-challenge", o_int, &chap[0].max_transmits,
67 "Max number of Challenges sent without a valid response" },
68 { "chap-interval", o_int, &chap[0].chal_interval,
69 "Set interval for rechallenge" },
70 #if defined(CHAPMS) && defined(MSLANMAN)
71 { "ms-lanman", o_bool, &ms_lanman,
72 "Use obsolete LAN Manager password when using MS-CHAP", 1 },
73 #endif
74 { NULL }
78 * Protocol entry points.
80 static void ChapInit __P((int));
81 static void ChapLowerUp __P((int));
82 static void ChapLowerDown __P((int));
83 static void ChapInput __P((int, u_char *, int));
84 static void ChapProtocolReject __P((int));
85 static int ChapPrintPkt __P((u_char *, int,
86 void (*) __P((void *, const char *, ...)), void *));
88 struct protent chap_protent = {
89 PPP_CHAP, /* PPP protocol number */
90 ChapInit, /* Initialization procedure */
91 ChapInput, /* Process a received packet */
92 ChapProtocolReject, /* Process a received protocol-reject */
93 ChapLowerUp, /* Lower layer has come up */
94 ChapLowerDown, /* Lower layer has gone down */
95 NULL, /* Open the protocol */
96 NULL, /* Close the protocol */
97 ChapPrintPkt, /* Print a packet in readable form */
98 NULL, /* Process a received data packet */
99 1, /* 0 iff protocol is disabled */
100 "CHAP", /* Text name of protocol */
101 NULL, /* Text name of corresponding data protocol */
102 chap_option_list, /* List of command-line options */
103 NULL, /* Check requested options, assign defaults */
104 NULL, /* Configure interface for demand-dial */
105 NULL /* Say whether to bring up link for this pkt */
108 /* Not static'd for plug-ins */
109 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
111 static void ChapChallengeTimeout __P((void *));
112 static void ChapResponseTimeout __P((void *));
113 static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
114 static void ChapRechallenge __P((void *));
115 static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
116 static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
117 static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
118 static void ChapSendStatus __P((chap_state *, int));
119 static void ChapSendChallenge __P((chap_state *));
120 static void ChapSendResponse __P((chap_state *));
121 static void ChapGenChallenge __P((chap_state *));
123 static const char *
124 chap_cstate(int clientstate)
126 static const char *cstate[] = { CHAPCS__LIST };
127 static char buf[32];
129 if (clientstate < 0 || clientstate >= Dim(cstate)) {
130 (void) slprintf(buf, sizeof(buf), "#%d", clientstate);
131 return (buf);
133 return cstate[clientstate];
136 static const char *
137 chap_sstate(int serverstate)
139 static const char *sstate[] = { CHAPSS__LIST };
140 static char buf[32];
142 if (serverstate < 0 || serverstate >= Dim(sstate)) {
143 (void) slprintf(buf, sizeof(buf), "#%d", serverstate);
144 return (buf);
146 return sstate[serverstate];
150 * ChapInit - Initialize a CHAP unit.
152 static void
153 ChapInit(unit)
154 int unit;
156 chap_state *cstate = &chap[unit];
158 BZERO(cstate, sizeof(*cstate));
159 cstate->unit = unit;
160 cstate->clientstate = CHAPCS_INITIAL;
161 cstate->serverstate = CHAPSS_INITIAL;
162 cstate->timeouttime = CHAP_DEFTIMEOUT;
163 cstate->max_transmits = CHAP_DEFTRANSMITS;
165 /* XXX save get_first_hwaddr() here. */
166 /* random number generator is initialized in magic_init */
171 * ChapAuthWithPeer - Authenticate us with our peer (start client).
174 void
175 ChapAuthWithPeer(unit, our_name, digest)
176 int unit;
177 char *our_name;
178 int digest;
180 chap_state *cstate = &chap[unit];
182 cstate->resp_name = our_name;
183 cstate->resp_type = digest;
185 if (cstate->clientstate == CHAPCS_INITIAL ||
186 cstate->clientstate == CHAPCS_PENDING) {
187 /* lower layer isn't up - wait until later */
188 cstate->clientstate = CHAPCS_PENDING;
189 return;
193 * We get here as a result of LCP coming up.
194 * So even if CHAP was open before, we will
195 * have to re-authenticate ourselves.
197 cstate->clientstate = CHAPCS_LISTEN;
202 * ChapAuthPeer - Authenticate our peer (start server).
204 void
205 ChapAuthPeer(unit, our_name, digest)
206 int unit;
207 char *our_name;
208 int digest;
210 chap_state *cstate = &chap[unit];
212 cstate->chal_name = our_name;
213 cstate->chal_type = digest;
215 if (cstate->serverstate == CHAPSS_INITIAL ||
216 cstate->serverstate == CHAPSS_PENDING) {
217 /* lower layer isn't up - wait until later */
218 cstate->serverstate = CHAPSS_PENDING;
219 return;
222 ChapGenChallenge(cstate);
223 ChapSendChallenge(cstate); /* crank it up dude! */
224 cstate->serverstate = CHAPSS_INITIAL_CHAL;
229 * ChapChallengeTimeout - Timeout expired on sending challenge.
231 static void
232 ChapChallengeTimeout(arg)
233 void *arg;
235 chap_state *cstate = (chap_state *) arg;
237 /* if we aren't sending challenges, don't worry. then again we */
238 /* probably shouldn't be here either */
239 if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
240 cstate->serverstate != CHAPSS_RECHALLENGE)
241 return;
243 if (cstate->chal_transmits >= cstate->max_transmits) {
244 /* give up on peer */
245 error("Peer failed to respond to CHAP challenge");
246 cstate->serverstate = CHAPSS_BADAUTH;
247 auth_peer_fail(cstate->unit, PPP_CHAP);
248 return;
251 ChapSendChallenge(cstate); /* Re-send challenge */
256 * ChapResponseTimeout - Timeout expired on sending response.
258 static void
259 ChapResponseTimeout(arg)
260 void *arg;
262 chap_state *cstate = (chap_state *) arg;
264 /* if we aren't sending a response, don't worry. */
265 if (cstate->clientstate != CHAPCS_RESPONSE)
266 return;
268 ChapSendResponse(cstate); /* re-send response */
273 * ChapRechallenge - Time to challenge the peer again.
275 static void
276 ChapRechallenge(arg)
277 void *arg;
279 chap_state *cstate = (chap_state *) arg;
281 /* if we aren't sending a response, don't worry. */
282 if (cstate->serverstate != CHAPSS_OPEN)
283 return;
285 ChapGenChallenge(cstate);
286 ChapSendChallenge(cstate);
287 cstate->serverstate = CHAPSS_RECHALLENGE;
292 * ChapLowerUp - The lower layer is up.
294 * Start up if we have pending requests.
296 static void
297 ChapLowerUp(unit)
298 int unit;
300 chap_state *cstate = &chap[unit];
302 if (cstate->clientstate == CHAPCS_INITIAL)
303 cstate->clientstate = CHAPCS_CLOSED;
304 else if (cstate->clientstate == CHAPCS_PENDING)
305 cstate->clientstate = CHAPCS_LISTEN;
307 if (cstate->serverstate == CHAPSS_INITIAL)
308 cstate->serverstate = CHAPSS_CLOSED;
309 else if (cstate->serverstate == CHAPSS_PENDING) {
310 ChapGenChallenge(cstate);
311 ChapSendChallenge(cstate);
312 cstate->serverstate = CHAPSS_INITIAL_CHAL;
318 * ChapLowerDown - The lower layer is down.
320 * Cancel all timeouts.
322 static void
323 ChapLowerDown(unit)
324 int unit;
326 chap_state *cstate = &chap[unit];
328 /* Timeout(s) pending? Cancel if so. */
329 if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
330 cstate->serverstate == CHAPSS_RECHALLENGE)
331 UNTIMEOUT(ChapChallengeTimeout, cstate);
332 else if (cstate->serverstate == CHAPSS_OPEN
333 && cstate->chal_interval != 0)
334 UNTIMEOUT(ChapRechallenge, cstate);
335 if (cstate->clientstate == CHAPCS_RESPONSE)
336 UNTIMEOUT(ChapResponseTimeout, cstate);
338 cstate->clientstate = CHAPCS_INITIAL;
339 cstate->serverstate = CHAPSS_INITIAL;
344 * ChapProtocolReject - Peer doesn't grok CHAP.
346 static void
347 ChapProtocolReject(unit)
348 int unit;
350 chap_state *cstate = &chap[unit];
352 if (cstate->serverstate != CHAPSS_INITIAL &&
353 cstate->serverstate != CHAPSS_CLOSED)
354 auth_peer_fail(unit, PPP_CHAP);
355 if (cstate->clientstate != CHAPCS_INITIAL &&
356 cstate->clientstate != CHAPCS_CLOSED)
357 auth_withpeer_fail(unit, PPP_CHAP);
358 ChapLowerDown(unit); /* shutdown chap */
363 * ChapInput - Input CHAP packet.
365 static void
366 ChapInput(unit, inpacket, packet_len)
367 int unit;
368 u_char *inpacket;
369 int packet_len;
371 chap_state *cstate = &chap[unit];
372 u_char *inp;
373 u_char code, id;
374 int len;
377 * Parse header (code, id and length).
378 * If packet too short, drop it.
380 inp = inpacket;
381 if (packet_len < CHAP_HEADERLEN) {
382 error("CHAP: packet is too small (%d < %d)", packet_len,
383 CHAP_HEADERLEN);
384 return;
386 GETCHAR(code, inp);
387 GETCHAR(id, inp);
388 GETSHORT(len, inp);
389 if (len < CHAP_HEADERLEN || len > packet_len) {
390 error("CHAP: packet has illegal length %d (%d..%d)",
391 len, CHAP_HEADERLEN, packet_len);
392 return;
394 len -= CHAP_HEADERLEN;
397 * Action depends on code (as in fact it usually does :-).
399 switch (code) {
400 case CHAP_CHALLENGE:
401 ChapReceiveChallenge(cstate, inp, id, len);
402 break;
404 case CHAP_RESPONSE:
405 ChapReceiveResponse(cstate, inp, id, len);
406 break;
408 case CHAP_FAILURE:
409 ChapReceiveFailure(cstate, inp, id, len);
410 break;
412 case CHAP_SUCCESS:
413 ChapReceiveSuccess(cstate, inp, id, len);
414 break;
416 default:
417 /* CHAP does not define a code reject. */
418 warn("Unknown CHAP code (%d) received.", code);
419 break;
425 * ChapReceiveChallenge - Receive Challenge and send Response.
427 static void
428 ChapReceiveChallenge(cstate, inp, id, len)
429 chap_state *cstate;
430 u_char *inp;
431 int id;
432 int len;
434 int rchallenge_len;
435 u_char *rchallenge;
436 int secret_len;
437 char rhostname[MAXNAMELEN];
438 char secret[MAXSECRETLEN];
439 MD5_CTX mdContext;
440 u_char hash[MD5_SIGNATURE_SIZE];
441 int fake_response = 0;
443 if (cstate->clientstate == CHAPCS_CLOSED ||
444 cstate->clientstate == CHAPCS_PENDING) {
445 if (debug)
446 dbglog("CHAP Challenge unexpectedly received in state %s",
447 chap_cstate(cstate->clientstate));
448 return;
451 if (len < 2) {
452 error("CHAP: Challenge message length %d", len);
453 return;
456 GETCHAR(rchallenge_len, inp);
457 len -= sizeof (u_char) + rchallenge_len; /* now name field length */
458 if (len < 0) {
459 error("CHAP: Challenge truncated");
460 return;
462 rchallenge = inp;
463 INCPTR(rchallenge_len, inp);
465 if (len >= sizeof(rhostname))
466 len = sizeof(rhostname) - 1;
467 if (len > 0) {
468 BCOPY(inp, rhostname, len);
470 rhostname[len] = '\0';
472 #ifdef CHECK_CHALLENGE_LENGTH
473 if (rchallenge_len < CHECK_CHALLENGE_LENGTH) {
474 warn("CHAP: Challenge from %s unreasonably short (%d octets)",
475 rhostname, rchallenge_len);
476 fake_response = 1;
478 #endif
480 /* XXX compare against saved get_first_hwaddr() here. */
482 /* Microsoft NT doesn't send a name in the CHAP Challenge message */
483 if (explicit_remote ||
484 (remote_name[0] != '\0' && rhostname[0] == '\0')) {
485 (void) strlcpy(rhostname, remote_name, sizeof(rhostname));
486 if (debug)
487 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
488 rhostname);
491 if (cstate->peercname[0] == '\0') {
492 (void) strlcpy(cstate->peercname, rhostname,
493 sizeof (cstate->peercname));
494 } else if (strcmp(rhostname, cstate->peercname) != 0) {
495 if (++cstate->rename_count == 1) {
496 info("CHAP: peer challenge name changed from '%q' to '%q'",
497 cstate->peercname, rhostname);
498 (void) strlcpy(cstate->peercname, rhostname,
499 sizeof (cstate->peercname));
500 } else {
501 fake_response = 1;
502 if (cstate->rename_count == 2)
503 warn("CHAP: peer challenge name changed again to '%q'",
504 rhostname);
508 /* get secret for authenticating ourselves with the specified host */
509 if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
510 secret, &secret_len, 0)) {
511 secret_len = 0; /* assume null secret if can't find one */
512 warn("No CHAP secret found for authenticating us (%q) to %q",
513 cstate->resp_name, rhostname);
516 /* cancel response send timeout if necessary */
517 if (cstate->clientstate == CHAPCS_RESPONSE)
518 UNTIMEOUT(ChapResponseTimeout, cstate);
520 cstate->resp_id = id;
521 cstate->resp_transmits = 0;
523 /* generate MD based on negotiated type */
524 switch (cstate->resp_type) {
526 case CHAP_DIGEST_MD5:
527 MD5Init(&mdContext);
528 MD5Update(&mdContext, &cstate->resp_id, 1);
529 MD5Update(&mdContext, (u_char *)secret, (unsigned)secret_len);
530 MD5Update(&mdContext, rchallenge, rchallenge_len);
531 MD5Final(hash, &mdContext);
532 if (fake_response) {
533 for (len = 0; len < MD5_SIGNATURE_SIZE; len++)
534 cstate->response[len] = (char) (drand48() * 0xff);
535 } else {
536 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
538 cstate->resp_length = MD5_SIGNATURE_SIZE;
539 break;
541 #ifdef CHAPMS
542 case CHAP_MICROSOFT:
543 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
544 break;
545 #endif
547 #ifdef CHAPMSV2
548 case CHAP_MICROSOFT_V2:
549 ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len);
550 break;
551 #endif
553 default:
554 error("CHAP: unknown digest type %d", cstate->resp_type);
555 return;
558 BZERO(secret, sizeof(secret));
559 ChapSendResponse(cstate);
564 * ChapReceiveResponse - Receive and process response.
566 static void
567 ChapReceiveResponse(cstate, inp, id, len)
568 chap_state *cstate;
569 u_char *inp;
570 int id;
571 int len;
573 u_char *remmd, remmd_len;
574 int secret_len, old_state;
575 int code;
576 char rhostname[MAXNAMELEN], *rhn;
577 MD5_CTX mdContext;
578 char secret[MAXSECRETLEN];
579 u_char hash[MD5_SIGNATURE_SIZE];
581 if (cstate->serverstate == CHAPSS_CLOSED ||
582 cstate->serverstate == CHAPSS_PENDING) {
583 if (debug)
584 dbglog("CHAP Response unexpectedly received in state %s",
585 chap_sstate(cstate->serverstate));
586 return;
589 if (id != cstate->chal_id) {
590 if (debug)
591 dbglog("CHAP: discard response %d; expecting %d", id,
592 cstate->chal_id);
593 return; /* doesn't match ID of last challenge */
597 * If we have received a duplicate or bogus Response,
598 * we have to send the same answer (Success/Failure)
599 * as we did for the first Response we saw.
601 if (cstate->serverstate == CHAPSS_OPEN) {
602 if (debug)
603 dbglog("CHAP ignoring response and resending success message");
604 ChapSendStatus(cstate, CHAP_SUCCESS);
605 return;
607 if (cstate->serverstate == CHAPSS_BADAUTH) {
608 if (debug)
609 dbglog("CHAP ignoring response and resending failure message");
610 ChapSendStatus(cstate, CHAP_FAILURE);
611 return;
614 if (len < 2) {
615 error("CHAP: Response message length %d", len);
616 return;
618 GETCHAR(remmd_len, inp); /* get length of MD */
619 remmd = inp; /* get pointer to MD */
620 INCPTR(remmd_len, inp);
622 len -= sizeof (u_char) + remmd_len;
623 if (len < 0) {
624 error("CHAP: Response truncated");
625 return;
628 UNTIMEOUT(ChapChallengeTimeout, cstate);
630 if (len >= sizeof(rhostname))
631 len = sizeof(rhostname) - 1;
632 BCOPY(inp, rhostname, len);
633 rhostname[len] = '\0';
636 * Get secret for authenticating them with us,
637 * do the hash ourselves, and compare the result.
639 code = CHAP_FAILURE;
640 rhn = (explicit_remote? remote_name: rhostname);
641 if (cstate->serverstate == CHAPSS_RECHALLENGE &&
642 strcmp(rhostname, peer_authname) != 0) {
643 warn("Peer changed his name from '%q' to '%q' on rechallenge",
644 peer_authname, rhostname);
645 } else if (!get_secret(cstate->unit, rhn, cstate->chal_name, secret,
646 &secret_len, 1)) {
647 warn("No CHAP secret found for authenticating %q to us (%q)",
648 rhn, cstate->chal_name);
649 } else {
651 /* generate MD based on negotiated type */
652 switch (cstate->chal_type) {
654 case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
655 if (remmd_len != MD5_SIGNATURE_SIZE)
656 break; /* it's not even the right length */
657 MD5Init(&mdContext);
658 MD5Update(&mdContext, &cstate->chal_id, 1);
659 MD5Update(&mdContext, (u_char *)secret, secret_len);
660 MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
661 MD5Final(hash, &mdContext);
663 /* compare local and remote MDs and send the appropriate status */
664 if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
665 code = CHAP_SUCCESS; /* they are the same! */
666 break;
668 #ifdef CHAPMS
669 case CHAP_MICROSOFT:
670 if (ChapMSValidate(cstate, remmd, remmd_len, secret,
671 secret_len))
672 code = CHAP_SUCCESS;
673 break;
674 #endif
676 #ifdef CHAPMSV2
677 case CHAP_MICROSOFT_V2:
678 if (ChapMSv2Validate(cstate, rhostname, remmd, remmd_len,
679 secret, secret_len))
680 code = CHAP_SUCCESS;
681 break;
682 #endif
684 default:
685 error("CHAP: unknown digest type %d", cstate->chal_type);
689 BZERO(secret, sizeof(secret));
690 ChapSendStatus(cstate, code);
692 if (code == CHAP_SUCCESS) {
693 old_state = cstate->serverstate;
694 cstate->serverstate = CHAPSS_OPEN;
695 if (old_state == CHAPSS_INITIAL_CHAL) {
696 auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
698 if (cstate->chal_interval != 0)
699 TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
700 if (old_state == CHAPSS_INITIAL_CHAL)
701 notice("CHAP peer authentication succeeded for %q", rhostname);
702 else if (debug)
703 dbglog("CHAP peer reauthentication succeeded for %q", rhostname);
704 } else {
705 error("CHAP peer %sauthentication failed for remote host %q",
706 (cstate->serverstate == CHAPSS_INITIAL_CHAL ? "" : "re"),
707 rhostname);
708 cstate->serverstate = CHAPSS_BADAUTH;
709 auth_peer_fail(cstate->unit, PPP_CHAP);
714 * ChapReceiveSuccess - Receive Success
716 /*ARGSUSED*/
717 static void
718 ChapReceiveSuccess(cstate, inp, id, len)
719 chap_state *cstate;
720 u_char *inp;
721 u_char id;
722 int len;
725 if (cstate->clientstate == CHAPCS_OPEN) {
726 /* presumably an answer to a duplicate response */
727 if (debug)
728 dbglog("CHAP duplicate Success message ignored");
729 return;
732 if (cstate->clientstate != CHAPCS_RESPONSE) {
733 /* don't know what this is */
734 if (debug)
735 dbglog("CHAP Success unexpectedly received in state %s",
736 chap_cstate(cstate->clientstate));
737 return;
740 UNTIMEOUT(ChapResponseTimeout, cstate);
743 * Print message.
745 if (len > 0)
746 PRINTMSG(inp, len);
748 cstate->clientstate = CHAPCS_OPEN;
750 auth_withpeer_success(cstate->unit, PPP_CHAP);
755 * ChapReceiveFailure - Receive failure.
757 /*ARGSUSED*/
758 static void
759 ChapReceiveFailure(cstate, inp, id, len)
760 chap_state *cstate;
761 u_char *inp;
762 u_char id;
763 int len;
765 if (cstate->clientstate != CHAPCS_RESPONSE) {
766 /* don't know what this is */
767 if (debug)
768 dbglog("CHAP Failure unexpectedly received in state %s",
769 chap_cstate(cstate->clientstate));
770 return;
773 UNTIMEOUT(ChapResponseTimeout, cstate);
776 * Print message.
778 if (len > 0)
779 PRINTMSG(inp, len);
781 error("CHAP authentication failed");
782 auth_withpeer_fail(cstate->unit, PPP_CHAP);
787 * ChapSendChallenge - Send an Authenticate challenge.
789 static void
790 ChapSendChallenge(cstate)
791 chap_state *cstate;
793 u_char *outp;
794 int chal_len, name_len;
795 int outlen;
797 chal_len = cstate->chal_len;
798 name_len = strlen(cstate->chal_name);
799 outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
800 outp = outpacket_buf;
802 MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
804 PUTCHAR(CHAP_CHALLENGE, outp);
805 PUTCHAR(cstate->chal_id, outp);
806 PUTSHORT(outlen, outp);
808 PUTCHAR(chal_len, outp); /* put length of challenge */
809 BCOPY(cstate->challenge, outp, chal_len);
810 INCPTR(chal_len, outp);
812 BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
814 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
816 TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
817 ++cstate->chal_transmits;
822 * ChapSendStatus - Send a status response (ack or nak).
824 static void
825 ChapSendStatus(cstate, code)
826 chap_state *cstate;
827 int code;
829 u_char *outp;
830 int outlen, msglen;
831 char msg[256], *msgp;
833 if ((msgp = cstate->stat_message) != NULL) {
834 msglen = cstate->stat_length;
835 } else {
836 if (code == CHAP_SUCCESS)
837 (void) slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
838 else
839 (void) slprintf(msg, sizeof(msg), "I don't like you. Go 'way.");
840 msglen = strlen(msg);
841 msgp = msg;
844 outlen = CHAP_HEADERLEN + msglen;
845 outp = outpacket_buf;
847 MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
849 PUTCHAR(code, outp);
850 PUTCHAR(cstate->chal_id, outp);
851 PUTSHORT(outlen, outp);
852 BCOPY(msgp, outp, msglen);
853 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
857 * ChapGenChallenge is used to generate a pseudo-random challenge string of
858 * a pseudo-random length between min_len and max_len. The challenge
859 * string and its length are stored in *cstate, and various other fields of
860 * *cstate are initialized.
863 static void
864 ChapGenChallenge(cstate)
865 chap_state *cstate;
867 int chal_len;
868 u_char *ptr = cstate->challenge;
869 int i;
871 /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
872 MAX_CHALLENGE_LENGTH */
873 chal_len = (unsigned) ((drand48() *
874 (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
875 MIN_CHALLENGE_LENGTH);
876 cstate->chal_len = chal_len;
877 cstate->chal_id = ++cstate->id;
878 cstate->chal_transmits = 0;
880 /* XXX tack on saved get_first_hwaddr() here. */
882 /* generate a random string */
883 for (i = 0; i < chal_len; i++)
884 *ptr++ = (char) (drand48() * 0xff);
888 * ChapSendResponse - send a response packet with values as specified
889 * in *cstate.
891 /* ARGSUSED */
892 static void
893 ChapSendResponse(cstate)
894 chap_state *cstate;
896 u_char *outp;
897 int outlen, md_len, name_len;
899 md_len = cstate->resp_length;
900 name_len = strlen(cstate->resp_name);
901 outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
902 outp = outpacket_buf;
904 MAKEHEADER(outp, PPP_CHAP);
906 PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
907 PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
908 PUTSHORT(outlen, outp); /* packet length */
910 PUTCHAR(md_len, outp); /* length of MD */
911 BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
912 INCPTR(md_len, outp);
914 BCOPY(cstate->resp_name, outp, name_len); /* append our name */
916 /* send the packet */
917 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
919 cstate->clientstate = CHAPCS_RESPONSE;
920 TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
921 ++cstate->resp_transmits;
925 * ChapPrintPkt - print the contents of a CHAP packet.
927 static char *ChapCodenames[] = {
928 "Challenge", "Response", "Success", "Failure"
931 static int
932 ChapPrintPkt(p, plen, printer, arg)
933 u_char *p;
934 int plen;
935 void (*printer) __P((void *, const char *, ...));
936 void *arg;
938 int code, id, len;
939 int clen, nlen;
940 u_char x;
942 if (plen < CHAP_HEADERLEN)
943 return 0;
944 GETCHAR(code, p);
945 GETCHAR(id, p);
946 GETSHORT(len, p);
947 if (len < CHAP_HEADERLEN || len > plen)
948 return 0;
950 if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
951 printer(arg, " %s", ChapCodenames[code-1]);
952 else
953 printer(arg, " code=0x%x", code);
954 printer(arg, " id=0x%x", id);
955 len -= CHAP_HEADERLEN;
956 switch (code) {
957 case CHAP_CHALLENGE:
958 case CHAP_RESPONSE:
959 if (len < 1)
960 break;
961 clen = p[0];
962 if (len < clen + 1)
963 break;
964 ++p;
965 nlen = len - clen - 1;
966 printer(arg, " <");
967 for (; clen > 0; --clen) {
968 GETCHAR(x, p);
969 printer(arg, "%.2x", x);
971 printer(arg, ">, name = ");
972 print_string((char *)p, nlen, printer, arg);
973 break;
974 case CHAP_FAILURE:
975 case CHAP_SUCCESS:
976 printer(arg, " ");
977 print_string((char *)p, len, printer, arg);
978 break;
979 default:
980 for (clen = len; clen > 0; --clen) {
981 GETCHAR(x, p);
982 printer(arg, " %.2x", x);
986 return len + CHAP_HEADERLEN;