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.
42 #include <sys/types.h>
48 #if defined(CHAPMS) || defined(CHAPMSV2)
53 * Command-line options.
55 static option_t chap_option_list
[] = {
56 { "chap-restart", o_int
, &chap
[0].timeouttime
,
57 "Set CHAP Challenge retry interval" },
58 { "chap-max-challenge", o_int
, &chap
[0].max_transmits
,
59 "Max number of Challenges sent without a valid response" },
60 { "chap-interval", o_int
, &chap
[0].chal_interval
,
61 "Set interval for rechallenge" },
62 #if defined(CHAPMS) && defined(MSLANMAN)
63 { "ms-lanman", o_bool
, &ms_lanman
,
64 "Use obsolete LAN Manager password when using MS-CHAP", 1 },
70 * Protocol entry points.
72 static void ChapInit
__P((int));
73 static void ChapLowerUp
__P((int));
74 static void ChapLowerDown
__P((int));
75 static void ChapInput
__P((int, u_char
*, int));
76 static void ChapProtocolReject
__P((int));
77 static int ChapPrintPkt
__P((u_char
*, int,
78 void (*) __P((void *, const char *, ...)), void *));
80 struct protent chap_protent
= {
81 PPP_CHAP
, /* PPP protocol number */
82 ChapInit
, /* Initialization procedure */
83 ChapInput
, /* Process a received packet */
84 ChapProtocolReject
, /* Process a received protocol-reject */
85 ChapLowerUp
, /* Lower layer has come up */
86 ChapLowerDown
, /* Lower layer has gone down */
87 NULL
, /* Open the protocol */
88 NULL
, /* Close the protocol */
89 ChapPrintPkt
, /* Print a packet in readable form */
90 NULL
, /* Process a received data packet */
91 1, /* 0 iff protocol is disabled */
92 "CHAP", /* Text name of protocol */
93 NULL
, /* Text name of corresponding data protocol */
94 chap_option_list
, /* List of command-line options */
95 NULL
, /* Check requested options, assign defaults */
96 NULL
, /* Configure interface for demand-dial */
97 NULL
/* Say whether to bring up link for this pkt */
100 /* Not static'd for plug-ins */
101 chap_state chap
[NUM_PPP
]; /* CHAP state; one for each unit */
103 static void ChapChallengeTimeout
__P((void *));
104 static void ChapResponseTimeout
__P((void *));
105 static void ChapReceiveChallenge
__P((chap_state
*, u_char
*, int, int));
106 static void ChapRechallenge
__P((void *));
107 static void ChapReceiveResponse
__P((chap_state
*, u_char
*, int, int));
108 static void ChapReceiveSuccess
__P((chap_state
*, u_char
*, int, int));
109 static void ChapReceiveFailure
__P((chap_state
*, u_char
*, int, int));
110 static void ChapSendStatus
__P((chap_state
*, int));
111 static void ChapSendChallenge
__P((chap_state
*));
112 static void ChapSendResponse
__P((chap_state
*));
113 static void ChapGenChallenge
__P((chap_state
*));
116 chap_cstate(int clientstate
)
118 static const char *cstate
[] = { CHAPCS__LIST
};
121 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
122 (void) slprintf(buf
, sizeof(buf
), "#%d", clientstate
);
125 return cstate
[clientstate
];
129 chap_sstate(int serverstate
)
131 static const char *sstate
[] = { CHAPSS__LIST
};
134 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
135 (void) slprintf(buf
, sizeof(buf
), "#%d", serverstate
);
138 return sstate
[serverstate
];
142 * ChapInit - Initialize a CHAP unit.
148 chap_state
*cstate
= &chap
[unit
];
150 BZERO(cstate
, sizeof(*cstate
));
152 cstate
->clientstate
= CHAPCS_INITIAL
;
153 cstate
->serverstate
= CHAPSS_INITIAL
;
154 cstate
->timeouttime
= CHAP_DEFTIMEOUT
;
155 cstate
->max_transmits
= CHAP_DEFTRANSMITS
;
157 /* XXX save get_first_hwaddr() here. */
158 /* random number generator is initialized in magic_init */
163 * ChapAuthWithPeer - Authenticate us with our peer (start client).
167 ChapAuthWithPeer(unit
, our_name
, digest
)
172 chap_state
*cstate
= &chap
[unit
];
174 cstate
->resp_name
= our_name
;
175 cstate
->resp_type
= digest
;
177 if (cstate
->clientstate
== CHAPCS_INITIAL
||
178 cstate
->clientstate
== CHAPCS_PENDING
) {
179 /* lower layer isn't up - wait until later */
180 cstate
->clientstate
= CHAPCS_PENDING
;
185 * We get here as a result of LCP coming up.
186 * So even if CHAP was open before, we will
187 * have to re-authenticate ourselves.
189 cstate
->clientstate
= CHAPCS_LISTEN
;
194 * ChapAuthPeer - Authenticate our peer (start server).
197 ChapAuthPeer(unit
, our_name
, digest
)
202 chap_state
*cstate
= &chap
[unit
];
204 cstate
->chal_name
= our_name
;
205 cstate
->chal_type
= digest
;
207 if (cstate
->serverstate
== CHAPSS_INITIAL
||
208 cstate
->serverstate
== CHAPSS_PENDING
) {
209 /* lower layer isn't up - wait until later */
210 cstate
->serverstate
= CHAPSS_PENDING
;
214 ChapGenChallenge(cstate
);
215 ChapSendChallenge(cstate
); /* crank it up dude! */
216 cstate
->serverstate
= CHAPSS_INITIAL_CHAL
;
221 * ChapChallengeTimeout - Timeout expired on sending challenge.
224 ChapChallengeTimeout(arg
)
227 chap_state
*cstate
= (chap_state
*) arg
;
229 /* if we aren't sending challenges, don't worry. then again we */
230 /* probably shouldn't be here either */
231 if (cstate
->serverstate
!= CHAPSS_INITIAL_CHAL
&&
232 cstate
->serverstate
!= CHAPSS_RECHALLENGE
)
235 if (cstate
->chal_transmits
>= cstate
->max_transmits
) {
236 /* give up on peer */
237 error("Peer failed to respond to CHAP challenge");
238 cstate
->serverstate
= CHAPSS_BADAUTH
;
239 auth_peer_fail(cstate
->unit
, PPP_CHAP
);
243 ChapSendChallenge(cstate
); /* Re-send challenge */
248 * ChapResponseTimeout - Timeout expired on sending response.
251 ChapResponseTimeout(arg
)
254 chap_state
*cstate
= (chap_state
*) arg
;
256 /* if we aren't sending a response, don't worry. */
257 if (cstate
->clientstate
!= CHAPCS_RESPONSE
)
260 ChapSendResponse(cstate
); /* re-send response */
265 * ChapRechallenge - Time to challenge the peer again.
271 chap_state
*cstate
= (chap_state
*) arg
;
273 /* if we aren't sending a response, don't worry. */
274 if (cstate
->serverstate
!= CHAPSS_OPEN
)
277 ChapGenChallenge(cstate
);
278 ChapSendChallenge(cstate
);
279 cstate
->serverstate
= CHAPSS_RECHALLENGE
;
284 * ChapLowerUp - The lower layer is up.
286 * Start up if we have pending requests.
292 chap_state
*cstate
= &chap
[unit
];
294 if (cstate
->clientstate
== CHAPCS_INITIAL
)
295 cstate
->clientstate
= CHAPCS_CLOSED
;
296 else if (cstate
->clientstate
== CHAPCS_PENDING
)
297 cstate
->clientstate
= CHAPCS_LISTEN
;
299 if (cstate
->serverstate
== CHAPSS_INITIAL
)
300 cstate
->serverstate
= CHAPSS_CLOSED
;
301 else if (cstate
->serverstate
== CHAPSS_PENDING
) {
302 ChapGenChallenge(cstate
);
303 ChapSendChallenge(cstate
);
304 cstate
->serverstate
= CHAPSS_INITIAL_CHAL
;
310 * ChapLowerDown - The lower layer is down.
312 * Cancel all timeouts.
318 chap_state
*cstate
= &chap
[unit
];
320 /* Timeout(s) pending? Cancel if so. */
321 if (cstate
->serverstate
== CHAPSS_INITIAL_CHAL
||
322 cstate
->serverstate
== CHAPSS_RECHALLENGE
)
323 UNTIMEOUT(ChapChallengeTimeout
, cstate
);
324 else if (cstate
->serverstate
== CHAPSS_OPEN
325 && cstate
->chal_interval
!= 0)
326 UNTIMEOUT(ChapRechallenge
, cstate
);
327 if (cstate
->clientstate
== CHAPCS_RESPONSE
)
328 UNTIMEOUT(ChapResponseTimeout
, cstate
);
330 cstate
->clientstate
= CHAPCS_INITIAL
;
331 cstate
->serverstate
= CHAPSS_INITIAL
;
336 * ChapProtocolReject - Peer doesn't grok CHAP.
339 ChapProtocolReject(unit
)
342 chap_state
*cstate
= &chap
[unit
];
344 if (cstate
->serverstate
!= CHAPSS_INITIAL
&&
345 cstate
->serverstate
!= CHAPSS_CLOSED
)
346 auth_peer_fail(unit
, PPP_CHAP
);
347 if (cstate
->clientstate
!= CHAPCS_INITIAL
&&
348 cstate
->clientstate
!= CHAPCS_CLOSED
)
349 auth_withpeer_fail(unit
, PPP_CHAP
);
350 ChapLowerDown(unit
); /* shutdown chap */
355 * ChapInput - Input CHAP packet.
358 ChapInput(unit
, inpacket
, packet_len
)
363 chap_state
*cstate
= &chap
[unit
];
369 * Parse header (code, id and length).
370 * If packet too short, drop it.
373 if (packet_len
< CHAP_HEADERLEN
) {
374 error("CHAP: packet is too small (%d < %d)", packet_len
,
381 if (len
< CHAP_HEADERLEN
|| len
> packet_len
) {
382 error("CHAP: packet has illegal length %d (%d..%d)",
383 len
, CHAP_HEADERLEN
, packet_len
);
386 len
-= CHAP_HEADERLEN
;
389 * Action depends on code (as in fact it usually does :-).
393 ChapReceiveChallenge(cstate
, inp
, id
, len
);
397 ChapReceiveResponse(cstate
, inp
, id
, len
);
401 ChapReceiveFailure(cstate
, inp
, id
, len
);
405 ChapReceiveSuccess(cstate
, inp
, id
, len
);
409 /* CHAP does not define a code reject. */
410 warn("Unknown CHAP code (%d) received.", code
);
417 * ChapReceiveChallenge - Receive Challenge and send Response.
420 ChapReceiveChallenge(cstate
, inp
, id
, len
)
429 char rhostname
[MAXNAMELEN
];
430 char secret
[MAXSECRETLEN
];
432 u_char hash
[MD5_SIGNATURE_SIZE
];
433 int fake_response
= 0;
435 if (cstate
->clientstate
== CHAPCS_CLOSED
||
436 cstate
->clientstate
== CHAPCS_PENDING
) {
438 dbglog("CHAP Challenge unexpectedly received in state %s",
439 chap_cstate(cstate
->clientstate
));
444 error("CHAP: Challenge message length %d", len
);
448 GETCHAR(rchallenge_len
, inp
);
449 len
-= sizeof (u_char
) + rchallenge_len
; /* now name field length */
451 error("CHAP: Challenge truncated");
455 INCPTR(rchallenge_len
, inp
);
457 if (len
>= sizeof(rhostname
))
458 len
= sizeof(rhostname
) - 1;
460 BCOPY(inp
, rhostname
, len
);
462 rhostname
[len
] = '\0';
464 #ifdef CHECK_CHALLENGE_LENGTH
465 if (rchallenge_len
< CHECK_CHALLENGE_LENGTH
) {
466 warn("CHAP: Challenge from %s unreasonably short (%d octets)",
467 rhostname
, rchallenge_len
);
472 /* XXX compare against saved get_first_hwaddr() here. */
474 /* Microsoft NT doesn't send a name in the CHAP Challenge message */
475 if (explicit_remote
||
476 (remote_name
[0] != '\0' && rhostname
[0] == '\0')) {
477 (void) strlcpy(rhostname
, remote_name
, sizeof(rhostname
));
479 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
483 if (cstate
->peercname
[0] == '\0') {
484 (void) strlcpy(cstate
->peercname
, rhostname
,
485 sizeof (cstate
->peercname
));
486 } else if (strcmp(rhostname
, cstate
->peercname
) != 0) {
487 if (++cstate
->rename_count
== 1) {
488 info("CHAP: peer challenge name changed from '%q' to '%q'",
489 cstate
->peercname
, rhostname
);
490 (void) strlcpy(cstate
->peercname
, rhostname
,
491 sizeof (cstate
->peercname
));
494 if (cstate
->rename_count
== 2)
495 warn("CHAP: peer challenge name changed again to '%q'",
500 /* get secret for authenticating ourselves with the specified host */
501 if (!get_secret(cstate
->unit
, cstate
->resp_name
, rhostname
,
502 secret
, &secret_len
, 0)) {
503 secret_len
= 0; /* assume null secret if can't find one */
504 warn("No CHAP secret found for authenticating us (%q) to %q",
505 cstate
->resp_name
, rhostname
);
508 /* cancel response send timeout if necessary */
509 if (cstate
->clientstate
== CHAPCS_RESPONSE
)
510 UNTIMEOUT(ChapResponseTimeout
, cstate
);
512 cstate
->resp_id
= id
;
513 cstate
->resp_transmits
= 0;
515 /* generate MD based on negotiated type */
516 switch (cstate
->resp_type
) {
518 case CHAP_DIGEST_MD5
:
520 MD5Update(&mdContext
, &cstate
->resp_id
, 1);
521 MD5Update(&mdContext
, (u_char
*)secret
, (unsigned)secret_len
);
522 MD5Update(&mdContext
, rchallenge
, rchallenge_len
);
523 MD5Final(hash
, &mdContext
);
525 for (len
= 0; len
< MD5_SIGNATURE_SIZE
; len
++)
526 cstate
->response
[len
] = (char) (drand48() * 0xff);
528 BCOPY(hash
, cstate
->response
, MD5_SIGNATURE_SIZE
);
530 cstate
->resp_length
= MD5_SIGNATURE_SIZE
;
535 ChapMS(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
540 case CHAP_MICROSOFT_V2
:
541 ChapMSv2(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
546 error("CHAP: unknown digest type %d", cstate
->resp_type
);
550 BZERO(secret
, sizeof(secret
));
551 ChapSendResponse(cstate
);
556 * ChapReceiveResponse - Receive and process response.
559 ChapReceiveResponse(cstate
, inp
, id
, len
)
565 u_char
*remmd
, remmd_len
;
566 int secret_len
, old_state
;
568 char rhostname
[MAXNAMELEN
], *rhn
;
570 char secret
[MAXSECRETLEN
];
571 u_char hash
[MD5_SIGNATURE_SIZE
];
573 if (cstate
->serverstate
== CHAPSS_CLOSED
||
574 cstate
->serverstate
== CHAPSS_PENDING
) {
576 dbglog("CHAP Response unexpectedly received in state %s",
577 chap_sstate(cstate
->serverstate
));
581 if (id
!= cstate
->chal_id
) {
583 dbglog("CHAP: discard response %d; expecting %d", id
,
585 return; /* doesn't match ID of last challenge */
589 * If we have received a duplicate or bogus Response,
590 * we have to send the same answer (Success/Failure)
591 * as we did for the first Response we saw.
593 if (cstate
->serverstate
== CHAPSS_OPEN
) {
595 dbglog("CHAP ignoring response and resending success message");
596 ChapSendStatus(cstate
, CHAP_SUCCESS
);
599 if (cstate
->serverstate
== CHAPSS_BADAUTH
) {
601 dbglog("CHAP ignoring response and resending failure message");
602 ChapSendStatus(cstate
, CHAP_FAILURE
);
607 error("CHAP: Response message length %d", len
);
610 GETCHAR(remmd_len
, inp
); /* get length of MD */
611 remmd
= inp
; /* get pointer to MD */
612 INCPTR(remmd_len
, inp
);
614 len
-= sizeof (u_char
) + remmd_len
;
616 error("CHAP: Response truncated");
620 UNTIMEOUT(ChapChallengeTimeout
, cstate
);
622 if (len
>= sizeof(rhostname
))
623 len
= sizeof(rhostname
) - 1;
624 BCOPY(inp
, rhostname
, len
);
625 rhostname
[len
] = '\0';
628 * Get secret for authenticating them with us,
629 * do the hash ourselves, and compare the result.
632 rhn
= (explicit_remote
? remote_name
: rhostname
);
633 if (cstate
->serverstate
== CHAPSS_RECHALLENGE
&&
634 strcmp(rhostname
, peer_authname
) != 0) {
635 warn("Peer changed his name from '%q' to '%q' on rechallenge",
636 peer_authname
, rhostname
);
637 } else if (!get_secret(cstate
->unit
, rhn
, cstate
->chal_name
, secret
,
639 warn("No CHAP secret found for authenticating %q to us (%q)",
640 rhn
, cstate
->chal_name
);
643 /* generate MD based on negotiated type */
644 switch (cstate
->chal_type
) {
646 case CHAP_DIGEST_MD5
: /* only MD5 is defined for now */
647 if (remmd_len
!= MD5_SIGNATURE_SIZE
)
648 break; /* it's not even the right length */
650 MD5Update(&mdContext
, &cstate
->chal_id
, 1);
651 MD5Update(&mdContext
, (u_char
*)secret
, secret_len
);
652 MD5Update(&mdContext
, cstate
->challenge
, cstate
->chal_len
);
653 MD5Final(hash
, &mdContext
);
655 /* compare local and remote MDs and send the appropriate status */
656 if (memcmp (hash
, remmd
, MD5_SIGNATURE_SIZE
) == 0)
657 code
= CHAP_SUCCESS
; /* they are the same! */
662 if (ChapMSValidate(cstate
, remmd
, remmd_len
, secret
,
669 case CHAP_MICROSOFT_V2
:
670 if (ChapMSv2Validate(cstate
, rhostname
, remmd
, remmd_len
,
677 error("CHAP: unknown digest type %d", cstate
->chal_type
);
681 BZERO(secret
, sizeof(secret
));
682 ChapSendStatus(cstate
, code
);
684 if (code
== CHAP_SUCCESS
) {
685 old_state
= cstate
->serverstate
;
686 cstate
->serverstate
= CHAPSS_OPEN
;
687 if (old_state
== CHAPSS_INITIAL_CHAL
) {
688 auth_peer_success(cstate
->unit
, PPP_CHAP
, rhostname
, len
);
690 if (cstate
->chal_interval
!= 0)
691 TIMEOUT(ChapRechallenge
, cstate
, cstate
->chal_interval
);
692 if (old_state
== CHAPSS_INITIAL_CHAL
)
693 notice("CHAP peer authentication succeeded for %q", rhostname
);
695 dbglog("CHAP peer reauthentication succeeded for %q", rhostname
);
697 error("CHAP peer %sauthentication failed for remote host %q",
698 (cstate
->serverstate
== CHAPSS_INITIAL_CHAL
? "" : "re"),
700 cstate
->serverstate
= CHAPSS_BADAUTH
;
701 auth_peer_fail(cstate
->unit
, PPP_CHAP
);
706 * ChapReceiveSuccess - Receive Success
710 ChapReceiveSuccess(cstate
, inp
, id
, len
)
717 if (cstate
->clientstate
== CHAPCS_OPEN
) {
718 /* presumably an answer to a duplicate response */
720 dbglog("CHAP duplicate Success message ignored");
724 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
725 /* don't know what this is */
727 dbglog("CHAP Success unexpectedly received in state %s",
728 chap_cstate(cstate
->clientstate
));
732 UNTIMEOUT(ChapResponseTimeout
, cstate
);
740 cstate
->clientstate
= CHAPCS_OPEN
;
742 auth_withpeer_success(cstate
->unit
, PPP_CHAP
);
747 * ChapReceiveFailure - Receive failure.
751 ChapReceiveFailure(cstate
, inp
, id
, len
)
757 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
758 /* don't know what this is */
760 dbglog("CHAP Failure unexpectedly received in state %s",
761 chap_cstate(cstate
->clientstate
));
765 UNTIMEOUT(ChapResponseTimeout
, cstate
);
773 error("CHAP authentication failed");
774 auth_withpeer_fail(cstate
->unit
, PPP_CHAP
);
779 * ChapSendChallenge - Send an Authenticate challenge.
782 ChapSendChallenge(cstate
)
786 int chal_len
, name_len
;
789 chal_len
= cstate
->chal_len
;
790 name_len
= strlen(cstate
->chal_name
);
791 outlen
= CHAP_HEADERLEN
+ sizeof (u_char
) + chal_len
+ name_len
;
792 outp
= outpacket_buf
;
794 MAKEHEADER(outp
, PPP_CHAP
); /* paste in a CHAP header */
796 PUTCHAR(CHAP_CHALLENGE
, outp
);
797 PUTCHAR(cstate
->chal_id
, outp
);
798 PUTSHORT(outlen
, outp
);
800 PUTCHAR(chal_len
, outp
); /* put length of challenge */
801 BCOPY(cstate
->challenge
, outp
, chal_len
);
802 INCPTR(chal_len
, outp
);
804 BCOPY(cstate
->chal_name
, outp
, name_len
); /* append hostname */
806 output(cstate
->unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
808 TIMEOUT(ChapChallengeTimeout
, cstate
, cstate
->timeouttime
);
809 ++cstate
->chal_transmits
;
814 * ChapSendStatus - Send a status response (ack or nak).
817 ChapSendStatus(cstate
, code
)
823 char msg
[256], *msgp
;
825 if ((msgp
= cstate
->stat_message
) != NULL
) {
826 msglen
= cstate
->stat_length
;
828 if (code
== CHAP_SUCCESS
)
829 (void) slprintf(msg
, sizeof(msg
), "Welcome to %s.", hostname
);
831 (void) slprintf(msg
, sizeof(msg
), "I don't like you. Go 'way.");
832 msglen
= strlen(msg
);
836 outlen
= CHAP_HEADERLEN
+ msglen
;
837 outp
= outpacket_buf
;
839 MAKEHEADER(outp
, PPP_CHAP
); /* paste in a header */
842 PUTCHAR(cstate
->chal_id
, outp
);
843 PUTSHORT(outlen
, outp
);
844 BCOPY(msgp
, outp
, msglen
);
845 output(cstate
->unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
849 * ChapGenChallenge is used to generate a pseudo-random challenge string of
850 * a pseudo-random length between min_len and max_len. The challenge
851 * string and its length are stored in *cstate, and various other fields of
852 * *cstate are initialized.
856 ChapGenChallenge(cstate
)
860 u_char
*ptr
= cstate
->challenge
;
863 /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
864 MAX_CHALLENGE_LENGTH */
865 chal_len
= (unsigned) ((drand48() *
866 (MAX_CHALLENGE_LENGTH
- MIN_CHALLENGE_LENGTH
)) +
867 MIN_CHALLENGE_LENGTH
);
868 cstate
->chal_len
= chal_len
;
869 cstate
->chal_id
= ++cstate
->id
;
870 cstate
->chal_transmits
= 0;
872 /* XXX tack on saved get_first_hwaddr() here. */
874 /* generate a random string */
875 for (i
= 0; i
< chal_len
; i
++)
876 *ptr
++ = (char) (drand48() * 0xff);
880 * ChapSendResponse - send a response packet with values as specified
885 ChapSendResponse(cstate
)
889 int outlen
, md_len
, name_len
;
891 md_len
= cstate
->resp_length
;
892 name_len
= strlen(cstate
->resp_name
);
893 outlen
= CHAP_HEADERLEN
+ sizeof (u_char
) + md_len
+ name_len
;
894 outp
= outpacket_buf
;
896 MAKEHEADER(outp
, PPP_CHAP
);
898 PUTCHAR(CHAP_RESPONSE
, outp
); /* we are a response */
899 PUTCHAR(cstate
->resp_id
, outp
); /* copy id from challenge packet */
900 PUTSHORT(outlen
, outp
); /* packet length */
902 PUTCHAR(md_len
, outp
); /* length of MD */
903 BCOPY(cstate
->response
, outp
, md_len
); /* copy MD to buffer */
904 INCPTR(md_len
, outp
);
906 BCOPY(cstate
->resp_name
, outp
, name_len
); /* append our name */
908 /* send the packet */
909 output(cstate
->unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
911 cstate
->clientstate
= CHAPCS_RESPONSE
;
912 TIMEOUT(ChapResponseTimeout
, cstate
, cstate
->timeouttime
);
913 ++cstate
->resp_transmits
;
917 * ChapPrintPkt - print the contents of a CHAP packet.
919 static char *ChapCodenames
[] = {
920 "Challenge", "Response", "Success", "Failure"
924 ChapPrintPkt(p
, plen
, printer
, arg
)
927 void (*printer
) __P((void *, const char *, ...));
934 if (plen
< CHAP_HEADERLEN
)
939 if (len
< CHAP_HEADERLEN
|| len
> plen
)
942 if (code
>= 1 && code
<= sizeof(ChapCodenames
) / sizeof(char *))
943 printer(arg
, " %s", ChapCodenames
[code
-1]);
945 printer(arg
, " code=0x%x", code
);
946 printer(arg
, " id=0x%x", id
);
947 len
-= CHAP_HEADERLEN
;
957 nlen
= len
- clen
- 1;
959 for (; clen
> 0; --clen
) {
961 printer(arg
, "%.2x", x
);
963 printer(arg
, ">, name = ");
964 print_string((char *)p
, nlen
, printer
, arg
);
969 print_string((char *)p
, len
, printer
, arg
);
972 for (clen
= len
; clen
> 0; --clen
) {
974 printer(arg
, " %.2x", x
);
978 return len
+ CHAP_HEADERLEN
;