blob: 4d1dc0d245b3d8203062baa358fe95cf5ca9d8f7 [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
2/*****************************************************************************
3* chap.c - Network Challenge Handshake Authentication Protocol program file.
4*
5* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
6* portions Copyright (c) 1997 by Global Election Systems Inc.
7*
8* The authors hereby grant permission to use, copy, modify, distribute,
9* and license this software and its documentation for any purpose, provided
10* that existing copyright notices are retained in all copies and that this
11* notice and the following disclaimer are included verbatim in any
12* distributions. No written agreement, license, or royalty fee is required
13* for any of the authorized uses.
14*
15* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
16* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*
26******************************************************************************
27* REVISION HISTORY
28*
29* 03-01-01 Marc Boucher <marc@mbsi.ca>
30* Ported to lwIP.
31* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32* Original based on BSD chap.c.
33*****************************************************************************/
34/*
35 * chap.c - Challenge Handshake Authentication Protocol.
36 *
37 * Copyright (c) 1993 The Australian National University.
38 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms are permitted
41 * provided that the above copyright notice and this paragraph are
42 * duplicated in all such forms and that any documentation,
43 * advertising materials, and other materials related to such
44 * distribution and use acknowledge that the software was developed
45 * by the Australian National University. The name of the University
46 * may not be used to endorse or promote products derived from this
47 * software without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
50 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51 *
52 * Copyright (c) 1991 Gregory M. Christy.
53 * All rights reserved.
54 *
55 * Redistribution and use in source and binary forms are permitted
56 * provided that the above copyright notice and this paragraph are
57 * duplicated in all such forms and that any documentation,
58 * advertising materials, and other materials related to such
59 * distribution and use acknowledge that the software was developed
60 * by Gregory M. Christy. The name of the author may not be used to
61 * endorse or promote products derived from this software without
62 * specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
67 */
68
69#include "ppp.h"
70#if PPP_SUPPORT > 0
71#include "magic.h"
72
73#if CHAP_SUPPORT > 0
74
75#include "randm.h"
76#include "auth.h"
77#include "md5.h"
78#include "chap.h"
79#include "chpms.h"
80#include "pppdebug.h"
81
82
83/*************************/
84/*** LOCAL DEFINITIONS ***/
85/*************************/
86
87
88/************************/
89/*** LOCAL DATA TYPES ***/
90/************************/
91
92
93/***********************************/
94/*** LOCAL FUNCTION DECLARATIONS ***/
95/***********************************/
96/*
97 * Protocol entry points.
98 */
99static void ChapInit (int);
100static void ChapLowerUp (int);
101static void ChapLowerDown (int);
102static void ChapInput (int, u_char *, int);
103static void ChapProtocolReject (int);
104static int ChapPrintPkt (u_char *, int,
105 void (*) (void *, char *, ...), void *);
106
107static void ChapChallengeTimeout (void *);
108static void ChapResponseTimeout (void *);
109static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
110static void ChapRechallenge (void *);
111static void ChapReceiveResponse (chap_state *, u_char *, int, int);
112static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
113static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
114static void ChapSendStatus (chap_state *, int);
115static void ChapSendChallenge (chap_state *);
116static void ChapSendResponse (chap_state *);
117static void ChapGenChallenge (chap_state *);
118
119
120/******************************/
121/*** PUBLIC DATA STRUCTURES ***/
122/******************************/
123chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
124
125struct protent chap_protent = {
126 PPP_CHAP,
127 ChapInit,
128 ChapInput,
129 ChapProtocolReject,
130 ChapLowerUp,
131 ChapLowerDown,
132 NULL,
133 NULL,
134#if 0
135 ChapPrintPkt,
136 NULL,
137#endif
138 1,
139 "CHAP",
140#if 0
141 NULL,
142 NULL,
143 NULL
144#endif
145};
146
147
148
149/*****************************/
150/*** LOCAL DATA STRUCTURES ***/
151/*****************************/
152static char *ChapCodenames[] = {
153 "Challenge", "Response", "Success", "Failure"
154};
155
156
157
158/***********************************/
159/*** PUBLIC FUNCTION DEFINITIONS ***/
160/***********************************/
161/*
162 * ChapAuthWithPeer - Authenticate us with our peer (start client).
163 *
164 */
165void ChapAuthWithPeer(int unit, char *our_name, int digest)
166{
167 chap_state *cstate = &chap[unit];
168
169 cstate->resp_name = our_name;
170 cstate->resp_type = digest;
171
172 if (cstate->clientstate == CHAPCS_INITIAL ||
173 cstate->clientstate == CHAPCS_PENDING) {
174 /* lower layer isn't up - wait until later */
175 cstate->clientstate = CHAPCS_PENDING;
176 return;
177 }
178
179 /*
180 * We get here as a result of LCP coming up.
181 * So even if CHAP was open before, we will
182 * have to re-authenticate ourselves.
183 */
184 cstate->clientstate = CHAPCS_LISTEN;
185}
186
187
188/*
189 * ChapAuthPeer - Authenticate our peer (start server).
190 */
191void ChapAuthPeer(int unit, char *our_name, int digest)
192{
193 chap_state *cstate = &chap[unit];
194
195 cstate->chal_name = our_name;
196 cstate->chal_type = digest;
197
198 if (cstate->serverstate == CHAPSS_INITIAL ||
199 cstate->serverstate == CHAPSS_PENDING) {
200 /* lower layer isn't up - wait until later */
201 cstate->serverstate = CHAPSS_PENDING;
202 return;
203 }
204
205 ChapGenChallenge(cstate);
206 ChapSendChallenge(cstate); /* crank it up dude! */
207 cstate->serverstate = CHAPSS_INITIAL_CHAL;
208}
209
210
211
212
213/**********************************/
214/*** LOCAL FUNCTION DEFINITIONS ***/
215/**********************************/
216/*
217 * ChapInit - Initialize a CHAP unit.
218 */
219static void ChapInit(int unit)
220{
221 chap_state *cstate = &chap[unit];
222
223 BZERO(cstate, sizeof(*cstate));
224 cstate->unit = unit;
225 cstate->clientstate = CHAPCS_INITIAL;
226 cstate->serverstate = CHAPSS_INITIAL;
227 cstate->timeouttime = CHAP_DEFTIMEOUT;
228 cstate->max_transmits = CHAP_DEFTRANSMITS;
229 /* random number generator is initialized in magic_init */
230}
231
232
233/*
234 * ChapChallengeTimeout - Timeout expired on sending challenge.
235 */
236static void ChapChallengeTimeout(void *arg)
237{
238 chap_state *cstate = (chap_state *) arg;
239
240 /* if we aren't sending challenges, don't worry. then again we */
241 /* probably shouldn't be here either */
242 if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
243 cstate->serverstate != CHAPSS_RECHALLENGE)
244 return;
245
246 if (cstate->chal_transmits >= cstate->max_transmits) {
247 /* give up on peer */
248 CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
249 cstate->serverstate = CHAPSS_BADAUTH;
250 auth_peer_fail(cstate->unit, PPP_CHAP);
251 return;
252 }
253
254 ChapSendChallenge(cstate); /* Re-send challenge */
255}
256
257
258/*
259 * ChapResponseTimeout - Timeout expired on sending response.
260 */
261static void ChapResponseTimeout(void *arg)
262{
263 chap_state *cstate = (chap_state *) arg;
264
265 /* if we aren't sending a response, don't worry. */
266 if (cstate->clientstate != CHAPCS_RESPONSE)
267 return;
268
269 ChapSendResponse(cstate); /* re-send response */
270}
271
272
273/*
274 * ChapRechallenge - Time to challenge the peer again.
275 */
276static void ChapRechallenge(void *arg)
277{
278 chap_state *cstate = (chap_state *) arg;
279
280 /* if we aren't sending a response, don't worry. */
281 if (cstate->serverstate != CHAPSS_OPEN)
282 return;
283
284 ChapGenChallenge(cstate);
285 ChapSendChallenge(cstate);
286 cstate->serverstate = CHAPSS_RECHALLENGE;
287}
288
289
290/*
291 * ChapLowerUp - The lower layer is up.
292 *
293 * Start up if we have pending requests.
294 */
295static void ChapLowerUp(int unit)
296{
297 chap_state *cstate = &chap[unit];
298
299 if (cstate->clientstate == CHAPCS_INITIAL)
300 cstate->clientstate = CHAPCS_CLOSED;
301 else if (cstate->clientstate == CHAPCS_PENDING)
302 cstate->clientstate = CHAPCS_LISTEN;
303
304 if (cstate->serverstate == CHAPSS_INITIAL)
305 cstate->serverstate = CHAPSS_CLOSED;
306 else if (cstate->serverstate == CHAPSS_PENDING) {
307 ChapGenChallenge(cstate);
308 ChapSendChallenge(cstate);
309 cstate->serverstate = CHAPSS_INITIAL_CHAL;
310 }
311}
312
313
314/*
315 * ChapLowerDown - The lower layer is down.
316 *
317 * Cancel all timeouts.
318 */
319static void ChapLowerDown(int unit)
320{
321 chap_state *cstate = &chap[unit];
322
323 /* Timeout(s) pending? Cancel if so. */
324 if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
325 cstate->serverstate == CHAPSS_RECHALLENGE)
326 UNTIMEOUT(ChapChallengeTimeout, cstate);
327 else if (cstate->serverstate == CHAPSS_OPEN
328 && cstate->chal_interval != 0)
329 UNTIMEOUT(ChapRechallenge, cstate);
330 if (cstate->clientstate == CHAPCS_RESPONSE)
331 UNTIMEOUT(ChapResponseTimeout, cstate);
332
333 cstate->clientstate = CHAPCS_INITIAL;
334 cstate->serverstate = CHAPSS_INITIAL;
335}
336
337
338/*
339 * ChapProtocolReject - Peer doesn't grok CHAP.
340 */
341static void ChapProtocolReject(int unit)
342{
343 chap_state *cstate = &chap[unit];
344
345 if (cstate->serverstate != CHAPSS_INITIAL &&
346 cstate->serverstate != CHAPSS_CLOSED)
347 auth_peer_fail(unit, PPP_CHAP);
348 if (cstate->clientstate != CHAPCS_INITIAL &&
349 cstate->clientstate != CHAPCS_CLOSED)
350 auth_withpeer_fail(unit, PPP_CHAP);
351 ChapLowerDown(unit); /* shutdown chap */
352}
353
354
355/*
356 * ChapInput - Input CHAP packet.
357 */
358static void ChapInput(int unit, u_char *inpacket, int packet_len)
359{
360 chap_state *cstate = &chap[unit];
361 u_char *inp;
362 u_char code, id;
363 int len;
364
365 /*
366 * Parse header (code, id and length).
367 * If packet too short, drop it.
368 */
369 inp = inpacket;
370 if (packet_len < CHAP_HEADERLEN) {
371 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
372 return;
373 }
374 GETCHAR(code, inp);
375 GETCHAR(id, inp);
376 GETSHORT(len, inp);
377 if (len < CHAP_HEADERLEN) {
378 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
379 return;
380 }
381 if (len > packet_len) {
382 CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
383 return;
384 }
385 len -= CHAP_HEADERLEN;
386
387 /*
388 * Action depends on code (as in fact it usually does :-).
389 */
390 switch (code) {
391 case CHAP_CHALLENGE:
392 ChapReceiveChallenge(cstate, inp, id, len);
393 break;
394
395 case CHAP_RESPONSE:
396 ChapReceiveResponse(cstate, inp, id, len);
397 break;
398
399 case CHAP_FAILURE:
400 ChapReceiveFailure(cstate, inp, id, len);
401 break;
402
403 case CHAP_SUCCESS:
404 ChapReceiveSuccess(cstate, inp, id, len);
405 break;
406
407 default: /* Need code reject? */
408 CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
409 break;
410 }
411}
412
413
414/*
415 * ChapReceiveChallenge - Receive Challenge and send Response.
416 */
417static void ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
418{
419 int rchallenge_len;
420 u_char *rchallenge;
421 int secret_len;
422 char secret[MAXSECRETLEN];
423 char rhostname[256];
424 MD5_CTX mdContext;
425 u_char hash[MD5_SIGNATURE_SIZE];
426
427 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
428 if (cstate->clientstate == CHAPCS_CLOSED ||
429 cstate->clientstate == CHAPCS_PENDING) {
430 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
431 cstate->clientstate));
432 return;
433 }
434
435 if (len < 2) {
436 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
437 return;
438 }
439
440 GETCHAR(rchallenge_len, inp);
441 len -= sizeof (u_char) + rchallenge_len; /* now name field length */
442 if (len < 0) {
443 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
444 return;
445 }
446 rchallenge = inp;
447 INCPTR(rchallenge_len, inp);
448
449 if (len >= sizeof(rhostname))
450 len = sizeof(rhostname) - 1;
451 BCOPY(inp, rhostname, len);
452 rhostname[len] = '\000';
453
454 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n",
455 rhostname));
456
457 /* Microsoft doesn't send their name back in the PPP packet */
458 if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
459 strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
460 rhostname[sizeof(rhostname) - 1] = 0;
461 CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n",
462 rhostname));
463 }
464
465 /* get secret for authenticating ourselves with the specified host */
466 if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
467 secret, &secret_len, 0)) {
468 secret_len = 0; /* assume null secret if can't find one */
469 CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
470 }
471
472 /* cancel response send timeout if necessary */
473 if (cstate->clientstate == CHAPCS_RESPONSE)
474 UNTIMEOUT(ChapResponseTimeout, cstate);
475
476 cstate->resp_id = id;
477 cstate->resp_transmits = 0;
478
479 /* generate MD based on negotiated type */
480 switch (cstate->resp_type) {
481
482 case CHAP_DIGEST_MD5:
483 MD5Init(&mdContext);
484 MD5Update(&mdContext, &cstate->resp_id, 1);
485 MD5Update(&mdContext, (u_char*)secret, secret_len);
486 MD5Update(&mdContext, rchallenge, rchallenge_len);
487 MD5Final(hash, &mdContext);
488 BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
489 cstate->resp_length = MD5_SIGNATURE_SIZE;
490 break;
491
492#ifdef CHAPMS
493 case CHAP_MICROSOFT:
494 ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
495 break;
496#endif
497
498 default:
499 CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
500 return;
501 }
502
503 BZERO(secret, sizeof(secret));
504 ChapSendResponse(cstate);
505}
506
507
508/*
509 * ChapReceiveResponse - Receive and process response.
510 */
511static void ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
512{
513 u_char *remmd, remmd_len;
514 int secret_len, old_state;
515 int code;
516 char rhostname[256];
517 MD5_CTX mdContext;
518 char secret[MAXSECRETLEN];
519 u_char hash[MD5_SIGNATURE_SIZE];
520
521 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
522
523 if (cstate->serverstate == CHAPSS_CLOSED ||
524 cstate->serverstate == CHAPSS_PENDING) {
525 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
526 cstate->serverstate));
527 return;
528 }
529
530 if (id != cstate->chal_id)
531 return; /* doesn't match ID of last challenge */
532
533 /*
534 * If we have received a duplicate or bogus Response,
535 * we have to send the same answer (Success/Failure)
536 * as we did for the first Response we saw.
537 */
538 if (cstate->serverstate == CHAPSS_OPEN) {
539 ChapSendStatus(cstate, CHAP_SUCCESS);
540 return;
541 }
542 if (cstate->serverstate == CHAPSS_BADAUTH) {
543 ChapSendStatus(cstate, CHAP_FAILURE);
544 return;
545 }
546
547 if (len < 2) {
548 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
549 return;
550 }
551 GETCHAR(remmd_len, inp); /* get length of MD */
552 remmd = inp; /* get pointer to MD */
553 INCPTR(remmd_len, inp);
554
555 len -= sizeof (u_char) + remmd_len;
556 if (len < 0) {
557 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
558 return;
559 }
560
561 UNTIMEOUT(ChapChallengeTimeout, cstate);
562
563 if (len >= sizeof(rhostname))
564 len = sizeof(rhostname) - 1;
565 BCOPY(inp, rhostname, len);
566 rhostname[len] = '\000';
567
568 CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n",
569 rhostname));
570
571 /*
572 * Get secret for authenticating them with us,
573 * do the hash ourselves, and compare the result.
574 */
575 code = CHAP_FAILURE;
576 if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
577 secret, &secret_len, 1)) {
578/* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
579 CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
580 rhostname));
581 } else {
582
583 /* generate MD based on negotiated type */
584 switch (cstate->chal_type) {
585
586 case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
587 if (remmd_len != MD5_SIGNATURE_SIZE)
588 break; /* it's not even the right length */
589 MD5Init(&mdContext);
590 MD5Update(&mdContext, &cstate->chal_id, 1);
591 MD5Update(&mdContext, (u_char*)secret, secret_len);
592 MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
593 MD5Final(hash, &mdContext);
594
595 /* compare local and remote MDs and send the appropriate status */
596 if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
597 code = CHAP_SUCCESS; /* they are the same! */
598 break;
599
600 default:
601 CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
602 }
603 }
604
605 BZERO(secret, sizeof(secret));
606 ChapSendStatus(cstate, code);
607
608 if (code == CHAP_SUCCESS) {
609 old_state = cstate->serverstate;
610 cstate->serverstate = CHAPSS_OPEN;
611 if (old_state == CHAPSS_INITIAL_CHAL) {
612 auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
613 }
614 if (cstate->chal_interval != 0)
615 TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
616 } else {
617 CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
618 cstate->serverstate = CHAPSS_BADAUTH;
619 auth_peer_fail(cstate->unit, PPP_CHAP);
620 }
621}
622
623/*
624 * ChapReceiveSuccess - Receive Success
625 */
626static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
627{
628
629 CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
630
631 if (cstate->clientstate == CHAPCS_OPEN)
632 /* presumably an answer to a duplicate response */
633 return;
634
635 if (cstate->clientstate != CHAPCS_RESPONSE) {
636 /* don't know what this is */
637 CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
638 cstate->clientstate));
639 return;
640 }
641
642 UNTIMEOUT(ChapResponseTimeout, cstate);
643
644 /*
645 * Print message.
646 */
647 if (len > 0)
648 PRINTMSG(inp, len);
649
650 cstate->clientstate = CHAPCS_OPEN;
651
652 auth_withpeer_success(cstate->unit, PPP_CHAP);
653}
654
655
656/*
657 * ChapReceiveFailure - Receive failure.
658 */
659static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
660{
661 CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
662
663 if (cstate->clientstate != CHAPCS_RESPONSE) {
664 /* don't know what this is */
665 CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
666 cstate->clientstate));
667 return;
668 }
669
670 UNTIMEOUT(ChapResponseTimeout, cstate);
671
672 /*
673 * Print message.
674 */
675 if (len > 0)
676 PRINTMSG(inp, len);
677
678 CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
679 auth_withpeer_fail(cstate->unit, PPP_CHAP);
680}
681
682
683/*
684 * ChapSendChallenge - Send an Authenticate challenge.
685 */
686static void ChapSendChallenge(chap_state *cstate)
687{
688 u_char *outp;
689 int chal_len, name_len;
690 int outlen;
691
692 chal_len = cstate->chal_len;
693 name_len = strlen(cstate->chal_name);
694 outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
695 outp = outpacket_buf[cstate->unit];
696
697 MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */
698
699 PUTCHAR(CHAP_CHALLENGE, outp);
700 PUTCHAR(cstate->chal_id, outp);
701 PUTSHORT(outlen, outp);
702
703 PUTCHAR(chal_len, outp); /* put length of challenge */
704 BCOPY(cstate->challenge, outp, chal_len);
705 INCPTR(chal_len, outp);
706
707 BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
708
709 pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
710
711 CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
712
713 TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
714 ++cstate->chal_transmits;
715}
716
717
718/*
719 * ChapSendStatus - Send a status response (ack or nak).
720 */
721static void ChapSendStatus(chap_state *cstate, int code)
722{
723 u_char *outp;
724 int outlen, msglen;
725 char msg[256];
726
727 if (code == CHAP_SUCCESS)
728 strcpy(msg, "Welcome!");
729 else
730 strcpy(msg, "I don't like you. Go 'way.");
731 msglen = strlen(msg);
732
733 outlen = CHAP_HEADERLEN + msglen;
734 outp = outpacket_buf[cstate->unit];
735
736 MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
737
738 PUTCHAR(code, outp);
739 PUTCHAR(cstate->chal_id, outp);
740 PUTSHORT(outlen, outp);
741 BCOPY(msg, outp, msglen);
742 pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
743
744 CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code,
745 cstate->chal_id));
746}
747
748/*
749 * ChapGenChallenge is used to generate a pseudo-random challenge string of
750 * a pseudo-random length between min_len and max_len. The challenge
751 * string and its length are stored in *cstate, and various other fields of
752 * *cstate are initialized.
753 */
754
755static void ChapGenChallenge(chap_state *cstate)
756{
757 int chal_len;
758 u_char *ptr = cstate->challenge;
759 int i;
760
761 /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
762 MAX_CHALLENGE_LENGTH */
763 chal_len = (unsigned)
764 ((((magic() >> 16) *
765 (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
766 + MIN_CHALLENGE_LENGTH);
767 cstate->chal_len = chal_len;
768 cstate->chal_id = ++cstate->id;
769 cstate->chal_transmits = 0;
770
771 /* generate a random string */
772 for (i = 0; i < chal_len; i++ )
773 *ptr++ = (char) (magic() & 0xff);
774}
775
776/*
777 * ChapSendResponse - send a response packet with values as specified
778 * in *cstate.
779 */
780/* ARGSUSED */
781static void ChapSendResponse(chap_state *cstate)
782{
783 u_char *outp;
784 int outlen, md_len, name_len;
785
786 md_len = cstate->resp_length;
787 name_len = strlen(cstate->resp_name);
788 outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
789 outp = outpacket_buf[cstate->unit];
790
791 MAKEHEADER(outp, PPP_CHAP);
792
793 PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
794 PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
795 PUTSHORT(outlen, outp); /* packet length */
796
797 PUTCHAR(md_len, outp); /* length of MD */
798 BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
799 INCPTR(md_len, outp);
800
801 BCOPY(cstate->resp_name, outp, name_len); /* append our name */
802
803 /* send the packet */
804 pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
805
806 cstate->clientstate = CHAPCS_RESPONSE;
807 TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
808 ++cstate->resp_transmits;
809}
810
811/*
812 * ChapPrintPkt - print the contents of a CHAP packet.
813 */
814static int ChapPrintPkt(
815 u_char *p,
816 int plen,
817 void (*printer) (void *, char *, ...),
818 void *arg
819)
820{
821 int code, id, len;
822 int clen, nlen;
823 u_char x;
824
825 if (plen < CHAP_HEADERLEN)
826 return 0;
827 GETCHAR(code, p);
828 GETCHAR(id, p);
829 GETSHORT(len, p);
830 if (len < CHAP_HEADERLEN || len > plen)
831 return 0;
832
833 if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
834 printer(arg, " %s", ChapCodenames[code-1]);
835 else
836 printer(arg, " code=0x%x", code);
837 printer(arg, " id=0x%x", id);
838 len -= CHAP_HEADERLEN;
839 switch (code) {
840 case CHAP_CHALLENGE:
841 case CHAP_RESPONSE:
842 if (len < 1)
843 break;
844 clen = p[0];
845 if (len < clen + 1)
846 break;
847 ++p;
848 nlen = len - clen - 1;
849 printer(arg, " <");
850 for (; clen > 0; --clen) {
851 GETCHAR(x, p);
852 printer(arg, "%.2x", x);
853 }
854 printer(arg, ">, name = %.*Z", nlen, p);
855 break;
856 case CHAP_FAILURE:
857 case CHAP_SUCCESS:
858 printer(arg, " %.*Z", len, p);
859 break;
860 default:
861 for (clen = len; clen > 0; --clen) {
862 GETCHAR(x, p);
863 printer(arg, " %.2x", x);
864 }
865 }
866
867 return len + CHAP_HEADERLEN;
868}
869
870#endif
871
872#endif /* PPP_SUPPORT */