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.
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 $"
48 #include <sys/types.h>
54 #if defined(CHAPMS) || defined(CHAPMSV2)
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 },
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
*));
124 chap_cstate(int clientstate
)
126 static const char *cstate
[] = { CHAPCS__LIST
};
129 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
130 (void) slprintf(buf
, sizeof(buf
), "#%d", clientstate
);
133 return cstate
[clientstate
];
137 chap_sstate(int serverstate
)
139 static const char *sstate
[] = { CHAPSS__LIST
};
142 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
143 (void) slprintf(buf
, sizeof(buf
), "#%d", serverstate
);
146 return sstate
[serverstate
];
150 * ChapInit - Initialize a CHAP unit.
156 chap_state
*cstate
= &chap
[unit
];
158 BZERO(cstate
, sizeof(*cstate
));
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).
175 ChapAuthWithPeer(unit
, our_name
, 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
;
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).
205 ChapAuthPeer(unit
, our_name
, 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
;
222 ChapGenChallenge(cstate
);
223 ChapSendChallenge(cstate
); /* crank it up dude! */
224 cstate
->serverstate
= CHAPSS_INITIAL_CHAL
;
229 * ChapChallengeTimeout - Timeout expired on sending challenge.
232 ChapChallengeTimeout(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
)
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
);
251 ChapSendChallenge(cstate
); /* Re-send challenge */
256 * ChapResponseTimeout - Timeout expired on sending response.
259 ChapResponseTimeout(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
)
268 ChapSendResponse(cstate
); /* re-send response */
273 * ChapRechallenge - Time to challenge the peer again.
279 chap_state
*cstate
= (chap_state
*) arg
;
281 /* if we aren't sending a response, don't worry. */
282 if (cstate
->serverstate
!= CHAPSS_OPEN
)
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.
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.
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.
347 ChapProtocolReject(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.
366 ChapInput(unit
, inpacket
, packet_len
)
371 chap_state
*cstate
= &chap
[unit
];
377 * Parse header (code, id and length).
378 * If packet too short, drop it.
381 if (packet_len
< CHAP_HEADERLEN
) {
382 error("CHAP: packet is too small (%d < %d)", packet_len
,
389 if (len
< CHAP_HEADERLEN
|| len
> packet_len
) {
390 error("CHAP: packet has illegal length %d (%d..%d)",
391 len
, CHAP_HEADERLEN
, packet_len
);
394 len
-= CHAP_HEADERLEN
;
397 * Action depends on code (as in fact it usually does :-).
401 ChapReceiveChallenge(cstate
, inp
, id
, len
);
405 ChapReceiveResponse(cstate
, inp
, id
, len
);
409 ChapReceiveFailure(cstate
, inp
, id
, len
);
413 ChapReceiveSuccess(cstate
, inp
, id
, len
);
417 /* CHAP does not define a code reject. */
418 warn("Unknown CHAP code (%d) received.", code
);
425 * ChapReceiveChallenge - Receive Challenge and send Response.
428 ChapReceiveChallenge(cstate
, inp
, id
, len
)
437 char rhostname
[MAXNAMELEN
];
438 char secret
[MAXSECRETLEN
];
440 u_char hash
[MD5_SIGNATURE_SIZE
];
441 int fake_response
= 0;
443 if (cstate
->clientstate
== CHAPCS_CLOSED
||
444 cstate
->clientstate
== CHAPCS_PENDING
) {
446 dbglog("CHAP Challenge unexpectedly received in state %s",
447 chap_cstate(cstate
->clientstate
));
452 error("CHAP: Challenge message length %d", len
);
456 GETCHAR(rchallenge_len
, inp
);
457 len
-= sizeof (u_char
) + rchallenge_len
; /* now name field length */
459 error("CHAP: Challenge truncated");
463 INCPTR(rchallenge_len
, inp
);
465 if (len
>= sizeof(rhostname
))
466 len
= sizeof(rhostname
) - 1;
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
);
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
));
487 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
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
));
502 if (cstate
->rename_count
== 2)
503 warn("CHAP: peer challenge name changed again to '%q'",
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
:
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
);
533 for (len
= 0; len
< MD5_SIGNATURE_SIZE
; len
++)
534 cstate
->response
[len
] = (char) (drand48() * 0xff);
536 BCOPY(hash
, cstate
->response
, MD5_SIGNATURE_SIZE
);
538 cstate
->resp_length
= MD5_SIGNATURE_SIZE
;
543 ChapMS(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
548 case CHAP_MICROSOFT_V2
:
549 ChapMSv2(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
554 error("CHAP: unknown digest type %d", cstate
->resp_type
);
558 BZERO(secret
, sizeof(secret
));
559 ChapSendResponse(cstate
);
564 * ChapReceiveResponse - Receive and process response.
567 ChapReceiveResponse(cstate
, inp
, id
, len
)
573 u_char
*remmd
, remmd_len
;
574 int secret_len
, old_state
;
576 char rhostname
[MAXNAMELEN
], *rhn
;
578 char secret
[MAXSECRETLEN
];
579 u_char hash
[MD5_SIGNATURE_SIZE
];
581 if (cstate
->serverstate
== CHAPSS_CLOSED
||
582 cstate
->serverstate
== CHAPSS_PENDING
) {
584 dbglog("CHAP Response unexpectedly received in state %s",
585 chap_sstate(cstate
->serverstate
));
589 if (id
!= cstate
->chal_id
) {
591 dbglog("CHAP: discard response %d; expecting %d", 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
) {
603 dbglog("CHAP ignoring response and resending success message");
604 ChapSendStatus(cstate
, CHAP_SUCCESS
);
607 if (cstate
->serverstate
== CHAPSS_BADAUTH
) {
609 dbglog("CHAP ignoring response and resending failure message");
610 ChapSendStatus(cstate
, CHAP_FAILURE
);
615 error("CHAP: Response message length %d", len
);
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
;
624 error("CHAP: Response truncated");
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.
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
,
647 warn("No CHAP secret found for authenticating %q to us (%q)",
648 rhn
, cstate
->chal_name
);
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 */
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! */
670 if (ChapMSValidate(cstate
, remmd
, remmd_len
, secret
,
677 case CHAP_MICROSOFT_V2
:
678 if (ChapMSv2Validate(cstate
, rhostname
, remmd
, remmd_len
,
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
);
703 dbglog("CHAP peer reauthentication succeeded for %q", rhostname
);
705 error("CHAP peer %sauthentication failed for remote host %q",
706 (cstate
->serverstate
== CHAPSS_INITIAL_CHAL
? "" : "re"),
708 cstate
->serverstate
= CHAPSS_BADAUTH
;
709 auth_peer_fail(cstate
->unit
, PPP_CHAP
);
714 * ChapReceiveSuccess - Receive Success
718 ChapReceiveSuccess(cstate
, inp
, id
, len
)
725 if (cstate
->clientstate
== CHAPCS_OPEN
) {
726 /* presumably an answer to a duplicate response */
728 dbglog("CHAP duplicate Success message ignored");
732 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
733 /* don't know what this is */
735 dbglog("CHAP Success unexpectedly received in state %s",
736 chap_cstate(cstate
->clientstate
));
740 UNTIMEOUT(ChapResponseTimeout
, cstate
);
748 cstate
->clientstate
= CHAPCS_OPEN
;
750 auth_withpeer_success(cstate
->unit
, PPP_CHAP
);
755 * ChapReceiveFailure - Receive failure.
759 ChapReceiveFailure(cstate
, inp
, id
, len
)
765 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
766 /* don't know what this is */
768 dbglog("CHAP Failure unexpectedly received in state %s",
769 chap_cstate(cstate
->clientstate
));
773 UNTIMEOUT(ChapResponseTimeout
, cstate
);
781 error("CHAP authentication failed");
782 auth_withpeer_fail(cstate
->unit
, PPP_CHAP
);
787 * ChapSendChallenge - Send an Authenticate challenge.
790 ChapSendChallenge(cstate
)
794 int chal_len
, name_len
;
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).
825 ChapSendStatus(cstate
, code
)
831 char msg
[256], *msgp
;
833 if ((msgp
= cstate
->stat_message
) != NULL
) {
834 msglen
= cstate
->stat_length
;
836 if (code
== CHAP_SUCCESS
)
837 (void) slprintf(msg
, sizeof(msg
), "Welcome to %s.", hostname
);
839 (void) slprintf(msg
, sizeof(msg
), "I don't like you. Go 'way.");
840 msglen
= strlen(msg
);
844 outlen
= CHAP_HEADERLEN
+ msglen
;
845 outp
= outpacket_buf
;
847 MAKEHEADER(outp
, PPP_CHAP
); /* paste in a header */
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.
864 ChapGenChallenge(cstate
)
868 u_char
*ptr
= cstate
->challenge
;
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
893 ChapSendResponse(cstate
)
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"
932 ChapPrintPkt(p
, plen
, printer
, arg
)
935 void (*printer
) __P((void *, const char *, ...));
942 if (plen
< CHAP_HEADERLEN
)
947 if (len
< CHAP_HEADERLEN
|| len
> plen
)
950 if (code
>= 1 && code
<= sizeof(ChapCodenames
) / sizeof(char *))
951 printer(arg
, " %s", ChapCodenames
[code
-1]);
953 printer(arg
, " code=0x%x", code
);
954 printer(arg
, " id=0x%x", id
);
955 len
-= CHAP_HEADERLEN
;
965 nlen
= len
- clen
- 1;
967 for (; clen
> 0; --clen
) {
969 printer(arg
, "%.2x", x
);
971 printer(arg
, ">, name = ");
972 print_string((char *)p
, nlen
, printer
, arg
);
977 print_string((char *)p
, len
, printer
, arg
);
980 for (clen
= len
; clen
> 0; --clen
) {
982 printer(arg
, " %.2x", x
);
986 return len
+ CHAP_HEADERLEN
;