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 #if !defined(lint) && !defined(_lint)
59 static const char rcsid
[] = RCSID
;
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 },
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
*));
126 chap_cstate(int clientstate
)
128 static const char *cstate
[] = { CHAPCS__LIST
};
131 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
132 (void) slprintf(buf
, sizeof(buf
), "#%d", clientstate
);
135 return cstate
[clientstate
];
139 chap_sstate(int serverstate
)
141 static const char *sstate
[] = { CHAPSS__LIST
};
144 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
145 (void) slprintf(buf
, sizeof(buf
), "#%d", serverstate
);
148 return sstate
[serverstate
];
152 * ChapInit - Initialize a CHAP unit.
158 chap_state
*cstate
= &chap
[unit
];
160 BZERO(cstate
, sizeof(*cstate
));
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).
177 ChapAuthWithPeer(unit
, our_name
, 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
;
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).
207 ChapAuthPeer(unit
, our_name
, 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
;
224 ChapGenChallenge(cstate
);
225 ChapSendChallenge(cstate
); /* crank it up dude! */
226 cstate
->serverstate
= CHAPSS_INITIAL_CHAL
;
231 * ChapChallengeTimeout - Timeout expired on sending challenge.
234 ChapChallengeTimeout(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
)
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
);
253 ChapSendChallenge(cstate
); /* Re-send challenge */
258 * ChapResponseTimeout - Timeout expired on sending response.
261 ChapResponseTimeout(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
)
270 ChapSendResponse(cstate
); /* re-send response */
275 * ChapRechallenge - Time to challenge the peer again.
281 chap_state
*cstate
= (chap_state
*) arg
;
283 /* if we aren't sending a response, don't worry. */
284 if (cstate
->serverstate
!= CHAPSS_OPEN
)
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.
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.
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.
349 ChapProtocolReject(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.
368 ChapInput(unit
, inpacket
, packet_len
)
373 chap_state
*cstate
= &chap
[unit
];
379 * Parse header (code, id and length).
380 * If packet too short, drop it.
383 if (packet_len
< CHAP_HEADERLEN
) {
384 error("CHAP: packet is too small (%d < %d)", packet_len
,
391 if (len
< CHAP_HEADERLEN
|| len
> packet_len
) {
392 error("CHAP: packet has illegal length %d (%d..%d)",
393 len
, CHAP_HEADERLEN
, packet_len
);
396 len
-= CHAP_HEADERLEN
;
399 * Action depends on code (as in fact it usually does :-).
403 ChapReceiveChallenge(cstate
, inp
, id
, len
);
407 ChapReceiveResponse(cstate
, inp
, id
, len
);
411 ChapReceiveFailure(cstate
, inp
, id
, len
);
415 ChapReceiveSuccess(cstate
, inp
, id
, len
);
419 /* CHAP does not define a code reject. */
420 warn("Unknown CHAP code (%d) received.", code
);
427 * ChapReceiveChallenge - Receive Challenge and send Response.
430 ChapReceiveChallenge(cstate
, inp
, id
, len
)
439 char rhostname
[MAXNAMELEN
];
440 char secret
[MAXSECRETLEN
];
442 u_char hash
[MD5_SIGNATURE_SIZE
];
443 int fake_response
= 0;
445 if (cstate
->clientstate
== CHAPCS_CLOSED
||
446 cstate
->clientstate
== CHAPCS_PENDING
) {
448 dbglog("CHAP Challenge unexpectedly received in state %s",
449 chap_cstate(cstate
->clientstate
));
454 error("CHAP: Challenge message length %d", len
);
458 GETCHAR(rchallenge_len
, inp
);
459 len
-= sizeof (u_char
) + rchallenge_len
; /* now name field length */
461 error("CHAP: Challenge truncated");
465 INCPTR(rchallenge_len
, inp
);
467 if (len
>= sizeof(rhostname
))
468 len
= sizeof(rhostname
) - 1;
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
);
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
));
489 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
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
));
504 if (cstate
->rename_count
== 2)
505 warn("CHAP: peer challenge name changed again to '%q'",
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
:
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
);
535 for (len
= 0; len
< MD5_SIGNATURE_SIZE
; len
++)
536 cstate
->response
[len
] = (char) (drand48() * 0xff);
538 BCOPY(hash
, cstate
->response
, MD5_SIGNATURE_SIZE
);
540 cstate
->resp_length
= MD5_SIGNATURE_SIZE
;
545 ChapMS(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
550 case CHAP_MICROSOFT_V2
:
551 ChapMSv2(cstate
, rchallenge
, rchallenge_len
, secret
, secret_len
);
556 error("CHAP: unknown digest type %d", cstate
->resp_type
);
560 BZERO(secret
, sizeof(secret
));
561 ChapSendResponse(cstate
);
566 * ChapReceiveResponse - Receive and process response.
569 ChapReceiveResponse(cstate
, inp
, id
, len
)
575 u_char
*remmd
, remmd_len
;
576 int secret_len
, old_state
;
578 char rhostname
[MAXNAMELEN
], *rhn
;
580 char secret
[MAXSECRETLEN
];
581 u_char hash
[MD5_SIGNATURE_SIZE
];
583 if (cstate
->serverstate
== CHAPSS_CLOSED
||
584 cstate
->serverstate
== CHAPSS_PENDING
) {
586 dbglog("CHAP Response unexpectedly received in state %s",
587 chap_sstate(cstate
->serverstate
));
591 if (id
!= cstate
->chal_id
) {
593 dbglog("CHAP: discard response %d; expecting %d", 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
) {
605 dbglog("CHAP ignoring response and resending success message");
606 ChapSendStatus(cstate
, CHAP_SUCCESS
);
609 if (cstate
->serverstate
== CHAPSS_BADAUTH
) {
611 dbglog("CHAP ignoring response and resending failure message");
612 ChapSendStatus(cstate
, CHAP_FAILURE
);
617 error("CHAP: Response message length %d", len
);
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
;
626 error("CHAP: Response truncated");
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.
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
,
649 warn("No CHAP secret found for authenticating %q to us (%q)",
650 rhn
, cstate
->chal_name
);
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 */
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! */
672 if (ChapMSValidate(cstate
, remmd
, remmd_len
, secret
,
679 case CHAP_MICROSOFT_V2
:
680 if (ChapMSv2Validate(cstate
, rhostname
, remmd
, remmd_len
,
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
);
705 dbglog("CHAP peer reauthentication succeeded for %q", rhostname
);
707 error("CHAP peer %sauthentication failed for remote host %q",
708 (cstate
->serverstate
== CHAPSS_INITIAL_CHAL
? "" : "re"),
710 cstate
->serverstate
= CHAPSS_BADAUTH
;
711 auth_peer_fail(cstate
->unit
, PPP_CHAP
);
716 * ChapReceiveSuccess - Receive Success
720 ChapReceiveSuccess(cstate
, inp
, id
, len
)
727 if (cstate
->clientstate
== CHAPCS_OPEN
) {
728 /* presumably an answer to a duplicate response */
730 dbglog("CHAP duplicate Success message ignored");
734 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
735 /* don't know what this is */
737 dbglog("CHAP Success unexpectedly received in state %s",
738 chap_cstate(cstate
->clientstate
));
742 UNTIMEOUT(ChapResponseTimeout
, cstate
);
750 cstate
->clientstate
= CHAPCS_OPEN
;
752 auth_withpeer_success(cstate
->unit
, PPP_CHAP
);
757 * ChapReceiveFailure - Receive failure.
761 ChapReceiveFailure(cstate
, inp
, id
, len
)
767 if (cstate
->clientstate
!= CHAPCS_RESPONSE
) {
768 /* don't know what this is */
770 dbglog("CHAP Failure unexpectedly received in state %s",
771 chap_cstate(cstate
->clientstate
));
775 UNTIMEOUT(ChapResponseTimeout
, cstate
);
783 error("CHAP authentication failed");
784 auth_withpeer_fail(cstate
->unit
, PPP_CHAP
);
789 * ChapSendChallenge - Send an Authenticate challenge.
792 ChapSendChallenge(cstate
)
796 int chal_len
, name_len
;
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).
827 ChapSendStatus(cstate
, code
)
833 char msg
[256], *msgp
;
835 if ((msgp
= cstate
->stat_message
) != NULL
) {
836 msglen
= cstate
->stat_length
;
838 if (code
== CHAP_SUCCESS
)
839 (void) slprintf(msg
, sizeof(msg
), "Welcome to %s.", hostname
);
841 (void) slprintf(msg
, sizeof(msg
), "I don't like you. Go 'way.");
842 msglen
= strlen(msg
);
846 outlen
= CHAP_HEADERLEN
+ msglen
;
847 outp
= outpacket_buf
;
849 MAKEHEADER(outp
, PPP_CHAP
); /* paste in a header */
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.
866 ChapGenChallenge(cstate
)
870 u_char
*ptr
= cstate
->challenge
;
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
895 ChapSendResponse(cstate
)
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"
934 ChapPrintPkt(p
, plen
, printer
, arg
)
937 void (*printer
) __P((void *, const char *, ...));
944 if (plen
< CHAP_HEADERLEN
)
949 if (len
< CHAP_HEADERLEN
|| len
> plen
)
952 if (code
>= 1 && code
<= sizeof(ChapCodenames
) / sizeof(char *))
953 printer(arg
, " %s", ChapCodenames
[code
-1]);
955 printer(arg
, " code=0x%x", code
);
956 printer(arg
, " id=0x%x", id
);
957 len
-= CHAP_HEADERLEN
;
967 nlen
= len
- clen
- 1;
969 for (; clen
> 0; --clen
) {
971 printer(arg
, "%.2x", x
);
973 printer(arg
, ">, name = ");
974 print_string((char *)p
, nlen
, printer
, arg
);
979 print_string((char *)p
, len
, printer
, arg
);
982 for (clen
= len
; clen
> 0; --clen
) {
984 printer(arg
, " %.2x", x
);
988 return len
+ CHAP_HEADERLEN
;