1 /*
2 * chap.c - Challenge Handshake Authentication Protocol.
3 *
4 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
6 *
7 * Copyright (c) 1993 The Australian National University.
8 * All rights reserved.
9 *
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.
21 *
22 * Copyright (c) 1991 Gregory M. Christy.
23 * All rights reserved.
24 *
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.
33 *
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.
37 */
38
39 #define RCSID "$Id: chap.c,v 1.24 1999/11/15 01:51:50 paulus Exp $"
40
41 /*
42 * TODO:
43 */
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <sys/types.h>
49 #include <sys/time.h>
50
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
57
58 #if !defined(lint) && !defined(_lint)
59 static const char rcsid[] = RCSID;
60 #endif
61
62 /*
63 * Command-line options.
64 */
65 static option_t chap_option_list[] = {
66 { "chap-restart", o_int, &chap[0].timeouttime,
67 "Set CHAP Challenge retry interval" },
68 { "chap-max-challenge", o_int, &chap[0].max_transmits,
69 "Max number of Challenges sent without a valid response" },
70 { "chap-interval", o_int, &chap[0].chal_interval,
71 "Set interval for rechallenge" },
72 #if defined(CHAPMS) && defined(MSLANMAN)
73 { "ms-lanman", o_bool, &ms_lanman,
74 "Use obsolete LAN Manager password when using MS-CHAP", 1 },
75 #endif
76 { NULL }
77 };
78
79 /*
80 * Protocol entry points.
81 */
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 *));
89
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 */
108 };
109
110 /* Not static'd for plug-ins */
111 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
112
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 *));
124
125 static const char *
chap_cstate(int clientstate)126 chap_cstate(int clientstate)
127 {
128 static const char *cstate[] = { CHAPCS__LIST };
129 static char buf[32];
130
131 if (clientstate < 0 || clientstate >= Dim(cstate)) {
132 (void) slprintf(buf, sizeof(buf), "#%d", clientstate);
133 return (buf);
134 }
135 return cstate[clientstate];
136 }
137
138 static const char *
chap_sstate(int serverstate)139 chap_sstate(int serverstate)
140 {
141 static const char *sstate[] = { CHAPSS__LIST };
142 static char buf[32];
143
144 if (serverstate < 0 || serverstate >= Dim(sstate)) {
145 (void) slprintf(buf, sizeof(buf), "#%d", serverstate);
146 return (buf);
147 }
148 return sstate[serverstate];
149 }
150
151 /*
152 * ChapInit - Initialize a CHAP unit.
153 */
154 static void
ChapInit(unit)155 ChapInit(unit)
156 int unit;
157 {
158 chap_state *cstate = &chap[unit];
159
160 BZERO(cstate, sizeof(*cstate));
161 cstate->unit = unit;
162 cstate->clientstate = CHAPCS_INITIAL;
163 cstate->serverstate = CHAPSS_INITIAL;
164 cstate->timeouttime = CHAP_DEFTIMEOUT;
165 cstate->max_transmits = CHAP_DEFTRANSMITS;
166
167 /* XXX save get_first_hwaddr() here. */
168 /* random number generator is initialized in magic_init */
169 }
170
171
172 /*
173 * ChapAuthWithPeer - Authenticate us with our peer (start client).
174 *
175 */
176 void
ChapAuthWithPeer(unit,our_name,digest)177 ChapAuthWithPeer(unit, our_name, digest)
178 int unit;
179 char *our_name;
180 int digest;
181 {
182 chap_state *cstate = &chap[unit];
183
184 cstate->resp_name = our_name;
185 cstate->resp_type = digest;
186
187 if (cstate->clientstate == CHAPCS_INITIAL ||
188 cstate->clientstate == CHAPCS_PENDING) {
189 /* lower layer isn't up - wait until later */
190 cstate->clientstate = CHAPCS_PENDING;
191 return;
192 }
193
194 /*
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.
198 */
199 cstate->clientstate = CHAPCS_LISTEN;
200 }
201
202
203 /*
204 * ChapAuthPeer - Authenticate our peer (start server).
205 */
206 void
ChapAuthPeer(unit,our_name,digest)207 ChapAuthPeer(unit, our_name, digest)
208 int unit;
209 char *our_name;
210 int digest;
211 {
212 chap_state *cstate = &chap[unit];
213
214 cstate->chal_name = our_name;
215 cstate->chal_type = digest;
216
217 if (cstate->serverstate == CHAPSS_INITIAL ||
218 cstate->serverstate == CHAPSS_PENDING) {
219 /* lower layer isn't up - wait until later */
220 cstate->serverstate = CHAPSS_PENDING;
221 return;
222 }
223
224 ChapGenChallenge(cstate);
225 ChapSendChallenge(cstate); /* crank it up dude! */
226 cstate->serverstate = CHAPSS_INITIAL_CHAL;
227 }
228
229
230 /*
231 * ChapChallengeTimeout - Timeout expired on sending challenge.
232 */
233 static void
ChapChallengeTimeout(arg)234 ChapChallengeTimeout(arg)
235 void *arg;
236 {
237 chap_state *cstate = (chap_state *) arg;
238
239 /* if we aren't sending challenges, don't worry. then again we */
240 /* probably shouldn't be here either */
241 if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
242 cstate->serverstate != CHAPSS_RECHALLENGE)
243 return;
244
245 if (cstate->chal_transmits >= cstate->max_transmits) {
246 /* give up on peer */
247 error("Peer failed to respond to CHAP challenge");
248 cstate->serverstate = CHAPSS_BADAUTH;
249 auth_peer_fail(cstate->unit, PPP_CHAP);
250 return;
251 }
252
253 ChapSendChallenge(cstate); /* Re-send challenge */
254 }
255
256
257 /*
258 * ChapResponseTimeout - Timeout expired on sending response.
259 */
260 static void
ChapResponseTimeout(arg)261 ChapResponseTimeout(arg)
262 void *arg;
263 {
264 chap_state *cstate = (chap_state *) arg;
265
266 /* if we aren't sending a response, don't worry. */
267 if (cstate->clientstate != CHAPCS_RESPONSE)
268 return;
269
270 ChapSendResponse(cstate); /* re-send response */
271 }
272
273
274 /*
275 * ChapRechallenge - Time to challenge the peer again.
276 */
277 static void
ChapRechallenge(arg)278 ChapRechallenge(arg)
279 void *arg;
280 {
281 chap_state *cstate = (chap_state *) arg;
282
283 /* if we aren't sending a response, don't worry. */
284 if (cstate->serverstate != CHAPSS_OPEN)
285 return;
286
287 ChapGenChallenge(cstate);
288 ChapSendChallenge(cstate);
289 cstate->serverstate = CHAPSS_RECHALLENGE;
290 }
291
292
293 /*
294 * ChapLowerUp - The lower layer is up.
295 *
296 * Start up if we have pending requests.
297 */
298 static void
ChapLowerUp(unit)299 ChapLowerUp(unit)
300 int unit;
301 {
302 chap_state *cstate = &chap[unit];
303
304 if (cstate->clientstate == CHAPCS_INITIAL)
305 cstate->clientstate = CHAPCS_CLOSED;
306 else if (cstate->clientstate == CHAPCS_PENDING)
307 cstate->clientstate = CHAPCS_LISTEN;
308
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;
315 }
316 }
317
318
319 /*
320 * ChapLowerDown - The lower layer is down.
321 *
322 * Cancel all timeouts.
323 */
324 static void
ChapLowerDown(unit)325 ChapLowerDown(unit)
326 int unit;
327 {
328 chap_state *cstate = &chap[unit];
329
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);
339
340 cstate->clientstate = CHAPCS_INITIAL;
341 cstate->serverstate = CHAPSS_INITIAL;
342 }
343
344
345 /*
346 * ChapProtocolReject - Peer doesn't grok CHAP.
347 */
348 static void
ChapProtocolReject(unit)349 ChapProtocolReject(unit)
350 int unit;
351 {
352 chap_state *cstate = &chap[unit];
353
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 */
361 }
362
363
364 /*
365 * ChapInput - Input CHAP packet.
366 */
367 static void
ChapInput(unit,inpacket,packet_len)368 ChapInput(unit, inpacket, packet_len)
369 int unit;
370 u_char *inpacket;
371 int packet_len;
372 {
373 chap_state *cstate = &chap[unit];
374 u_char *inp;
375 u_char code, id;
376 int len;
377
378 /*
379 * Parse header (code, id and length).
380 * If packet too short, drop it.
381 */
382 inp = inpacket;
383 if (packet_len < CHAP_HEADERLEN) {
384 error("CHAP: packet is too small (%d < %d)", packet_len,
385 CHAP_HEADERLEN);
386 return;
387 }
388 GETCHAR(code, inp);
389 GETCHAR(id, inp);
390 GETSHORT(len, inp);
391 if (len < CHAP_HEADERLEN || len > packet_len) {
392 error("CHAP: packet has illegal length %d (%d..%d)",
393 len, CHAP_HEADERLEN, packet_len);
394 return;
395 }
396 len -= CHAP_HEADERLEN;
397
398 /*
399 * Action depends on code (as in fact it usually does :-).
400 */
401 switch (code) {
402 case CHAP_CHALLENGE:
403 ChapReceiveChallenge(cstate, inp, id, len);
404 break;
405
406 case CHAP_RESPONSE:
407 ChapReceiveResponse(cstate, inp, id, len);
408 break;
409
410 case CHAP_FAILURE:
411 ChapReceiveFailure(cstate, inp, id, len);
412 break;
413
414 case CHAP_SUCCESS:
415 ChapReceiveSuccess(cstate, inp, id, len);
416 break;
417
418 default:
419 /* CHAP does not define a code reject. */
420 warn("Unknown CHAP code (%d) received.", code);
421 break;
422 }
423 }
424
425
426 /*
427 * ChapReceiveChallenge - Receive Challenge and send Response.
428 */
429 static void
ChapReceiveChallenge(cstate,inp,id,len)430 ChapReceiveChallenge(cstate, inp, id, len)
431 chap_state *cstate;
432 u_char *inp;
433 int id;
434 int len;
435 {
436 int rchallenge_len;
437 u_char *rchallenge;
438 int secret_len;
439 char rhostname[MAXNAMELEN];
440 char secret[MAXSECRETLEN];
441 MD5_CTX mdContext;
442 u_char hash[MD5_SIGNATURE_SIZE];
443 int fake_response = 0;
444
445 if (cstate->clientstate == CHAPCS_CLOSED ||
446 cstate->clientstate == CHAPCS_PENDING) {
447 if (debug)
448 dbglog("CHAP Challenge unexpectedly received in state %s",
449 chap_cstate(cstate->clientstate));
450 return;
451 }
452
453 if (len < 2) {
454 error("CHAP: Challenge message length %d", len);
455 return;
456 }
457
458 GETCHAR(rchallenge_len, inp);
459 len -= sizeof (u_char) + rchallenge_len; /* now name field length */
460 if (len < 0) {
461 error("CHAP: Challenge truncated");
462 return;
463 }
464 rchallenge = inp;
465 INCPTR(rchallenge_len, inp);
466
467 if (len >= sizeof(rhostname))
468 len = sizeof(rhostname) - 1;
469 if (len > 0) {
470 BCOPY(inp, rhostname, len);
471 }
472 rhostname[len] = '\0';
473
474 #ifdef CHECK_CHALLENGE_LENGTH
475 if (rchallenge_len < CHECK_CHALLENGE_LENGTH) {
476 warn("CHAP: Challenge from %s unreasonably short (%d octets)",
477 rhostname, rchallenge_len);
478 fake_response = 1;
479 }
480 #endif
481
482 /* XXX compare against saved get_first_hwaddr() here. */
483
484 /* Microsoft NT doesn't send a name in the CHAP Challenge message */
485 if (explicit_remote ||
486 (remote_name[0] != '\0' && rhostname[0] == '\0')) {
487 (void) strlcpy(rhostname, remote_name, sizeof(rhostname));
488 if (debug)
489 dbglog("CHAP: Peer gave no name; using '%q' as remote name",
490 rhostname);
491 }
492
493 if (cstate->peercname[0] == '\0') {
494 (void) strlcpy(cstate->peercname, rhostname,
495 sizeof (cstate->peercname));
496 } else if (strcmp(rhostname, cstate->peercname) != 0) {
497 if (++cstate->rename_count == 1) {
498 info("CHAP: peer challenge name changed from '%q' to '%q'",
499 cstate->peercname, rhostname);
500 (void) strlcpy(cstate->peercname, rhostname,
501 sizeof (cstate->peercname));
502 } else {
503 fake_response = 1;
504 if (cstate->rename_count == 2)
505 warn("CHAP: peer challenge name changed again to '%q'",
506 rhostname);
507 }
508 }
509
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);
516 }
517
518 /* cancel response send timeout if necessary */
519 if (cstate->clientstate == CHAPCS_RESPONSE)
520 UNTIMEOUT(ChapResponseTimeout, cstate);
521
522 cstate->resp_id = id;
523 cstate->resp_transmits = 0;
524
525 /* generate MD based on negotiated type */
526 switch (cstate->resp_type) {
527
528 case CHAP_DIGEST_MD5:
529 MD5Init(&mdContext);
530 MD5Update(&mdContext, &cstate->resp_id, 1);
531 MD5Update(&mdContext, (u_char *)secret, (unsigned)secret_len);
532 MD5Update(&mdContext, rchallenge, rchallenge_len);
533 MD5Final(hash, &mdContext);
534 if (fake_response) {
535 for (len = 0; len < MD5_SIGNATURE_SIZE; len++)
536 cstate->response[len] = (char) (drand48() * 0xff);
537 } else {
538 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
539 }
540 cstate->resp_length = MD5_SIGNATURE_SIZE;
541 break;
542
543 #ifdef CHAPMS
544 case CHAP_MICROSOFT:
545 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
546 break;
547 #endif
548
549 #ifdef CHAPMSV2
550 case CHAP_MICROSOFT_V2:
551 ChapMSv2(cstate, rchallenge, rchallenge_len, secret, secret_len);
552 break;
553 #endif
554
555 default:
556 error("CHAP: unknown digest type %d", cstate->resp_type);
557 return;
558 }
559
560 BZERO(secret, sizeof(secret));
561 ChapSendResponse(cstate);
562 }
563
564
565 /*
566 * ChapReceiveResponse - Receive and process response.
567 */
568 static void
ChapReceiveResponse(cstate,inp,id,len)569 ChapReceiveResponse(cstate, inp, id, len)
570 chap_state *cstate;
571 u_char *inp;
572 int id;
573 int len;
574 {
575 u_char *remmd, remmd_len;
576 int secret_len, old_state;
577 int code;
578 char rhostname[MAXNAMELEN], *rhn;
579 MD5_CTX mdContext;
580 char secret[MAXSECRETLEN];
581 u_char hash[MD5_SIGNATURE_SIZE];
582
583 if (cstate->serverstate == CHAPSS_CLOSED ||
584 cstate->serverstate == CHAPSS_PENDING) {
585 if (debug)
586 dbglog("CHAP Response unexpectedly received in state %s",
587 chap_sstate(cstate->serverstate));
588 return;
589 }
590
591 if (id != cstate->chal_id) {
592 if (debug)
593 dbglog("CHAP: discard response %d; expecting %d", id,
594 cstate->chal_id);
595 return; /* doesn't match ID of last challenge */
596 }
597
598 /*
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.
602 */
603 if (cstate->serverstate == CHAPSS_OPEN) {
604 if (debug)
605 dbglog("CHAP ignoring response and resending success message");
606 ChapSendStatus(cstate, CHAP_SUCCESS);
607 return;
608 }
609 if (cstate->serverstate == CHAPSS_BADAUTH) {
610 if (debug)
611 dbglog("CHAP ignoring response and resending failure message");
612 ChapSendStatus(cstate, CHAP_FAILURE);
613 return;
614 }
615
616 if (len < 2) {
617 error("CHAP: Response message length %d", len);
618 return;
619 }
620 GETCHAR(remmd_len, inp); /* get length of MD */
621 remmd = inp; /* get pointer to MD */
622 INCPTR(remmd_len, inp);
623
624 len -= sizeof (u_char) + remmd_len;
625 if (len < 0) {
626 error("CHAP: Response truncated");
627 return;
628 }
629
630 UNTIMEOUT(ChapChallengeTimeout, cstate);
631
632 if (len >= sizeof(rhostname))
633 len = sizeof(rhostname) - 1;
634 BCOPY(inp, rhostname, len);
635 rhostname[len] = '\0';
636
637 /*
638 * Get secret for authenticating them with us,
639 * do the hash ourselves, and compare the result.
640 */
641 code = CHAP_FAILURE;
642 rhn = (explicit_remote? remote_name: rhostname);
643 if (cstate->serverstate == CHAPSS_RECHALLENGE &&
644 strcmp(rhostname, peer_authname) != 0) {
645 warn("Peer changed his name from '%q' to '%q' on rechallenge",
646 peer_authname, rhostname);
647 } else if (!get_secret(cstate->unit, rhn, cstate->chal_name, secret,
648 &secret_len, 1)) {
649 warn("No CHAP secret found for authenticating %q to us (%q)",
650 rhn, cstate->chal_name);
651 } else {
652
653 /* generate MD based on negotiated type */
654 switch (cstate->chal_type) {
655
656 case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
657 if (remmd_len != MD5_SIGNATURE_SIZE)
658 break; /* it's not even the right length */
659 MD5Init(&mdContext);
660 MD5Update(&mdContext, &cstate->chal_id, 1);
661 MD5Update(&mdContext, (u_char *)secret, secret_len);
662 MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
663 MD5Final(hash, &mdContext);
664
665 /* compare local and remote MDs and send the appropriate status */
666 if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
667 code = CHAP_SUCCESS; /* they are the same! */
668 break;
669
670 #ifdef CHAPMS
671 case CHAP_MICROSOFT:
672 if (ChapMSValidate(cstate, remmd, remmd_len, secret,
673 secret_len))
674 code = CHAP_SUCCESS;
675 break;
676 #endif
677
678 #ifdef CHAPMSV2
679 case CHAP_MICROSOFT_V2:
680 if (ChapMSv2Validate(cstate, rhostname, remmd, remmd_len,
681 secret, secret_len))
682 code = CHAP_SUCCESS;
683 break;
684 #endif
685
686 default:
687 error("CHAP: unknown digest type %d", cstate->chal_type);
688 }
689 }
690
691 BZERO(secret, sizeof(secret));
692 ChapSendStatus(cstate, code);
693
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);
699 }
700 if (cstate->chal_interval != 0)
701 TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
702 if (old_state == CHAPSS_INITIAL_CHAL)
703 notice("CHAP peer authentication succeeded for %q", rhostname);
704 else if (debug)
705 dbglog("CHAP peer reauthentication succeeded for %q", rhostname);
706 } else {
707 error("CHAP peer %sauthentication failed for remote host %q",
708 (cstate->serverstate == CHAPSS_INITIAL_CHAL ? "" : "re"),
709 rhostname);
710 cstate->serverstate = CHAPSS_BADAUTH;
711 auth_peer_fail(cstate->unit, PPP_CHAP);
712 }
713 }
714
715 /*
716 * ChapReceiveSuccess - Receive Success
717 */
718 /*ARGSUSED*/
719 static void
ChapReceiveSuccess(cstate,inp,id,len)720 ChapReceiveSuccess(cstate, inp, id, len)
721 chap_state *cstate;
722 u_char *inp;
723 u_char id;
724 int len;
725 {
726
727 if (cstate->clientstate == CHAPCS_OPEN) {
728 /* presumably an answer to a duplicate response */
729 if (debug)
730 dbglog("CHAP duplicate Success message ignored");
731 return;
732 }
733
734 if (cstate->clientstate != CHAPCS_RESPONSE) {
735 /* don't know what this is */
736 if (debug)
737 dbglog("CHAP Success unexpectedly received in state %s",
738 chap_cstate(cstate->clientstate));
739 return;
740 }
741
742 UNTIMEOUT(ChapResponseTimeout, cstate);
743
744 /*
745 * Print message.
746 */
747 if (len > 0)
748 PRINTMSG(inp, len);
749
750 cstate->clientstate = CHAPCS_OPEN;
751
752 auth_withpeer_success(cstate->unit, PPP_CHAP);
753 }
754
755
756 /*
757 * ChapReceiveFailure - Receive failure.
758 */
759 /*ARGSUSED*/
760 static void
ChapReceiveFailure(cstate,inp,id,len)761 ChapReceiveFailure(cstate, inp, id, len)
762 chap_state *cstate;
763 u_char *inp;
764 u_char id;
765 int len;
766 {
767 if (cstate->clientstate != CHAPCS_RESPONSE) {
768 /* don't know what this is */
769 if (debug)
770 dbglog("CHAP Failure unexpectedly received in state %s",
771 chap_cstate(cstate->clientstate));
772 return;
773 }
774
775 UNTIMEOUT(ChapResponseTimeout, cstate);
776
777 /*
778 * Print message.
779 */
780 if (len > 0)
781 PRINTMSG(inp, len);
782
783 error("CHAP authentication failed");
784 auth_withpeer_fail(cstate->unit, PPP_CHAP);
785 }
786
787
788 /*
789 * ChapSendChallenge - Send an Authenticate challenge.
790 */
791 static void
ChapSendChallenge(cstate)792 ChapSendChallenge(cstate)
793 chap_state *cstate;
794 {
795 u_char *outp;
796 int chal_len, name_len;
797 int outlen;
798
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;
803
804 MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
805
806 PUTCHAR(CHAP_CHALLENGE, outp);
807 PUTCHAR(cstate->chal_id, outp);
808 PUTSHORT(outlen, outp);
809
810 PUTCHAR(chal_len, outp); /* put length of challenge */
811 BCOPY(cstate->challenge, outp, chal_len);
812 INCPTR(chal_len, outp);
813
814 BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
815
816 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
817
818 TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
819 ++cstate->chal_transmits;
820 }
821
822
823 /*
824 * ChapSendStatus - Send a status response (ack or nak).
825 */
826 static void
ChapSendStatus(cstate,code)827 ChapSendStatus(cstate, code)
828 chap_state *cstate;
829 int code;
830 {
831 u_char *outp;
832 int outlen, msglen;
833 char msg[256], *msgp;
834
835 if ((msgp = cstate->stat_message) != NULL) {
836 msglen = cstate->stat_length;
837 } else {
838 if (code == CHAP_SUCCESS)
839 (void) slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
840 else
841 (void) slprintf(msg, sizeof(msg), "I don't like you. Go 'way.");
842 msglen = strlen(msg);
843 msgp = msg;
844 }
845
846 outlen = CHAP_HEADERLEN + msglen;
847 outp = outpacket_buf;
848
849 MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
850
851 PUTCHAR(code, outp);
852 PUTCHAR(cstate->chal_id, outp);
853 PUTSHORT(outlen, outp);
854 BCOPY(msgp, outp, msglen);
855 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
856 }
857
858 /*
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.
863 */
864
865 static void
ChapGenChallenge(cstate)866 ChapGenChallenge(cstate)
867 chap_state *cstate;
868 {
869 int chal_len;
870 u_char *ptr = cstate->challenge;
871 int i;
872
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;
881
882 /* XXX tack on saved get_first_hwaddr() here. */
883
884 /* generate a random string */
885 for (i = 0; i < chal_len; i++)
886 *ptr++ = (char) (drand48() * 0xff);
887 }
888
889 /*
890 * ChapSendResponse - send a response packet with values as specified
891 * in *cstate.
892 */
893 /* ARGSUSED */
894 static void
ChapSendResponse(cstate)895 ChapSendResponse(cstate)
896 chap_state *cstate;
897 {
898 u_char *outp;
899 int outlen, md_len, name_len;
900
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;
905
906 MAKEHEADER(outp, PPP_CHAP);
907
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 */
911
912 PUTCHAR(md_len, outp); /* length of MD */
913 BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
914 INCPTR(md_len, outp);
915
916 BCOPY(cstate->resp_name, outp, name_len); /* append our name */
917
918 /* send the packet */
919 output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
920
921 cstate->clientstate = CHAPCS_RESPONSE;
922 TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
923 ++cstate->resp_transmits;
924 }
925
926 /*
927 * ChapPrintPkt - print the contents of a CHAP packet.
928 */
929 static char *ChapCodenames[] = {
930 "Challenge", "Response", "Success", "Failure"
931 };
932
933 static int
ChapPrintPkt(p,plen,printer,arg)934 ChapPrintPkt(p, plen, printer, arg)
935 u_char *p;
936 int plen;
937 void (*printer) __P((void *, const char *, ...));
938 void *arg;
939 {
940 int code, id, len;
941 int clen, nlen;
942 u_char x;
943
944 if (plen < CHAP_HEADERLEN)
945 return 0;
946 GETCHAR(code, p);
947 GETCHAR(id, p);
948 GETSHORT(len, p);
949 if (len < CHAP_HEADERLEN || len > plen)
950 return 0;
951
952 if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
953 printer(arg, " %s", ChapCodenames[code-1]);
954 else
955 printer(arg, " code=0x%x", code);
956 printer(arg, " id=0x%x", id);
957 len -= CHAP_HEADERLEN;
958 switch (code) {
959 case CHAP_CHALLENGE:
960 case CHAP_RESPONSE:
961 if (len < 1)
962 break;
963 clen = p[0];
964 if (len < clen + 1)
965 break;
966 ++p;
967 nlen = len - clen - 1;
968 printer(arg, " <");
969 for (; clen > 0; --clen) {
970 GETCHAR(x, p);
971 printer(arg, "%.2x", x);
972 }
973 printer(arg, ">, name = ");
974 print_string((char *)p, nlen, printer, arg);
975 break;
976 case CHAP_FAILURE:
977 case CHAP_SUCCESS:
978 printer(arg, " ");
979 print_string((char *)p, len, printer, arg);
980 break;
981 default:
982 for (clen = len; clen > 0; --clen) {
983 GETCHAR(x, p);
984 printer(arg, " %.2x", x);
985 }
986 }
987
988 return len + CHAP_HEADERLEN;
989 }
990