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