GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/pppd/chap.c Lines: 0 284 0.0 %
Date: 2017-11-07 Branches: 0 142 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: chap.c,v 1.18 2015/01/15 23:19:48 tedu 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
115
ChapInit(unit)
116
    int unit;
117
{
118
    chap_state *cstate = &chap[unit];
119
120
    BZERO(cstate, sizeof(*cstate));
121
    cstate->unit = unit;
122
    cstate->clientstate = CHAPCS_INITIAL;
123
    cstate->serverstate = CHAPSS_INITIAL;
124
    cstate->timeouttime = CHAP_DEFTIMEOUT;
125
    cstate->max_transmits = CHAP_DEFTRANSMITS;
126
    /* random number generator is initialized in magic_init */
127
}
128
129
130
/*
131
 * ChapAuthWithPeer - Authenticate us with our peer (start client).
132
 *
133
 */
134
void
135
ChapAuthWithPeer(unit, our_name, digest)
136
    int unit;
137
    char *our_name;
138
    int digest;
139
{
140
    chap_state *cstate = &chap[unit];
141
142
    cstate->resp_name = our_name;
143
    cstate->resp_type = digest;
144
145
    if (cstate->clientstate == CHAPCS_INITIAL ||
146
	cstate->clientstate == CHAPCS_PENDING) {
147
	/* lower layer isn't up - wait until later */
148
	cstate->clientstate = CHAPCS_PENDING;
149
	return;
150
    }
151
152
    /*
153
     * We get here as a result of LCP coming up.
154
     * So even if CHAP was open before, we will
155
     * have to re-authenticate ourselves.
156
     */
157
    cstate->clientstate = CHAPCS_LISTEN;
158
}
159
160
161
/*
162
 * ChapAuthPeer - Authenticate our peer (start server).
163
 */
164
void
165
ChapAuthPeer(unit, our_name, digest)
166
    int unit;
167
    char *our_name;
168
    int digest;
169
{
170
    chap_state *cstate = &chap[unit];
171
172
    cstate->chal_name = our_name;
173
    cstate->chal_type = digest;
174
175
    if (cstate->serverstate == CHAPSS_INITIAL ||
176
	cstate->serverstate == CHAPSS_PENDING) {
177
	/* lower layer isn't up - wait until later */
178
	cstate->serverstate = CHAPSS_PENDING;
179
	return;
180
    }
181
182
    ChapGenChallenge(cstate);
183
    ChapSendChallenge(cstate);		/* crank it up dude! */
184
    cstate->serverstate = CHAPSS_INITIAL_CHAL;
185
}
186
187
188
/*
189
 * ChapChallengeTimeout - Timeout expired on sending challenge.
190
 */
191
static void
192
ChapChallengeTimeout(arg)
193
    void *arg;
194
{
195
    chap_state *cstate = (chap_state *) arg;
196
197
    /* if we aren't sending challenges, don't worry.  then again we */
198
    /* probably shouldn't be here either */
199
    if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
200
	cstate->serverstate != CHAPSS_RECHALLENGE)
201
	return;
202
203
    if (cstate->chal_transmits >= cstate->max_transmits) {
204
	/* give up on peer */
205
	syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
206
	cstate->serverstate = CHAPSS_BADAUTH;
207
	auth_peer_fail(cstate->unit, PPP_CHAP);
208
	return;
209
    }
210
211
    ChapSendChallenge(cstate);		/* Re-send challenge */
212
}
213
214
215
/*
216
 * ChapResponseTimeout - Timeout expired on sending response.
217
 */
218
static void
219
ChapResponseTimeout(arg)
220
    void *arg;
221
{
222
    chap_state *cstate = (chap_state *) arg;
223
224
    /* if we aren't sending a response, don't worry. */
225
    if (cstate->clientstate != CHAPCS_RESPONSE)
226
	return;
227
228
    ChapSendResponse(cstate);		/* re-send response */
229
}
230
231
232
/*
233
 * ChapRechallenge - Time to challenge the peer again.
234
 */
235
static void
236
ChapRechallenge(arg)
237
    void *arg;
238
{
239
    chap_state *cstate = (chap_state *) arg;
240
241
    /* if we aren't sending a response, don't worry. */
242
    if (cstate->serverstate != CHAPSS_OPEN)
243
	return;
244
245
    ChapGenChallenge(cstate);
246
    ChapSendChallenge(cstate);
247
    cstate->serverstate = CHAPSS_RECHALLENGE;
248
}
249
250
251
/*
252
 * ChapLowerUp - The lower layer is up.
253
 *
254
 * Start up if we have pending requests.
255
 */
256
static void
257
ChapLowerUp(unit)
258
    int unit;
259
{
260
    chap_state *cstate = &chap[unit];
261
262
    if (cstate->clientstate == CHAPCS_INITIAL)
263
	cstate->clientstate = CHAPCS_CLOSED;
264
    else if (cstate->clientstate == CHAPCS_PENDING)
265
	cstate->clientstate = CHAPCS_LISTEN;
266
267
    if (cstate->serverstate == CHAPSS_INITIAL)
268
	cstate->serverstate = CHAPSS_CLOSED;
269
    else if (cstate->serverstate == CHAPSS_PENDING) {
270
	ChapGenChallenge(cstate);
271
	ChapSendChallenge(cstate);
272
	cstate->serverstate = CHAPSS_INITIAL_CHAL;
273
    }
274
}
275
276
277
/*
278
 * ChapLowerDown - The lower layer is down.
279
 *
280
 * Cancel all timeouts.
281
 */
282
static void
283
ChapLowerDown(unit)
284
    int unit;
285
{
286
    chap_state *cstate = &chap[unit];
287
288
    /* Timeout(s) pending?  Cancel if so. */
289
    if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
290
	cstate->serverstate == CHAPSS_RECHALLENGE)
291
	UNTIMEOUT(ChapChallengeTimeout, cstate);
292
    else if (cstate->serverstate == CHAPSS_OPEN
293
	     && cstate->chal_interval != 0)
294
	UNTIMEOUT(ChapRechallenge, cstate);
295
    if (cstate->clientstate == CHAPCS_RESPONSE)
296
	UNTIMEOUT(ChapResponseTimeout, cstate);
297
298
    cstate->clientstate = CHAPCS_INITIAL;
299
    cstate->serverstate = CHAPSS_INITIAL;
300
}
301
302
303
/*
304
 * ChapProtocolReject - Peer doesn't grok CHAP.
305
 */
306
static void
307
ChapProtocolReject(unit)
308
    int unit;
309
{
310
    chap_state *cstate = &chap[unit];
311
312
    if (cstate->serverstate != CHAPSS_INITIAL &&
313
	cstate->serverstate != CHAPSS_CLOSED)
314
	auth_peer_fail(unit, PPP_CHAP);
315
    if (cstate->clientstate != CHAPCS_INITIAL &&
316
	cstate->clientstate != CHAPCS_CLOSED)
317
	auth_withpeer_fail(unit, PPP_CHAP);
318
    ChapLowerDown(unit);		/* shutdown chap */
319
}
320
321
322
/*
323
 * ChapInput - Input CHAP packet.
324
 */
325
static void
326
ChapInput(unit, inpacket, packet_len)
327
    int unit;
328
    u_char *inpacket;
329
    int packet_len;
330
{
331
    chap_state *cstate = &chap[unit];
332
    u_char *inp;
333
    u_char code, id;
334
    int len;
335
336
    /*
337
     * Parse header (code, id and length).
338
     * If packet too short, drop it.
339
     */
340
    inp = inpacket;
341
    if (packet_len < CHAP_HEADERLEN) {
342
	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
343
	return;
344
    }
345
    GETCHAR(code, inp);
346
    GETCHAR(id, inp);
347
    GETSHORT(len, inp);
348
    if (len < CHAP_HEADERLEN) {
349
	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
350
	return;
351
    }
352
    if (len > packet_len) {
353
	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
354
	return;
355
    }
356
    len -= CHAP_HEADERLEN;
357
358
    /*
359
     * Action depends on code (as in fact it usually does :-).
360
     */
361
    switch (code) {
362
    case CHAP_CHALLENGE:
363
	ChapReceiveChallenge(cstate, inp, id, len);
364
	break;
365
366
    case CHAP_RESPONSE:
367
	ChapReceiveResponse(cstate, inp, id, len);
368
	break;
369
370
    case CHAP_FAILURE:
371
	ChapReceiveFailure(cstate, inp, id, len);
372
	break;
373
374
    case CHAP_SUCCESS:
375
	ChapReceiveSuccess(cstate, inp, id, len);
376
	break;
377
378
    default:				/* Need code reject? */
379
	syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
380
	break;
381
    }
382
}
383
384
385
/*
386
 * ChapReceiveChallenge - Receive Challenge and send Response.
387
 */
388
static void
389
ChapReceiveChallenge(cstate, inp, id, len)
390
    chap_state *cstate;
391
    u_char *inp;
392
    int id;
393
    int len;
394
{
395
    int rchallenge_len;
396
    u_char *rchallenge;
397
    int secret_len;
398
    char secret[MAXSECRETLEN];
399
    char rhostname[256];
400
    MD5_CTX mdContext;
401
    u_char hash[MD5_SIGNATURE_SIZE];
402
403
    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
404
    if (cstate->clientstate == CHAPCS_CLOSED ||
405
	cstate->clientstate == CHAPCS_PENDING) {
406
	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
407
		   cstate->clientstate));
408
	return;
409
    }
410
411
    if (len < 2) {
412
	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
413
	return;
414
    }
415
416
    GETCHAR(rchallenge_len, inp);
417
    len -= sizeof (u_char) + rchallenge_len;	/* now name field length */
418
    if (len < 0) {
419
	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
420
	return;
421
    }
422
    rchallenge = inp;
423
    INCPTR(rchallenge_len, inp);
424
425
    if (len >= sizeof(rhostname))
426
	len = sizeof(rhostname) - 1;
427
    BCOPY(inp, rhostname, len);
428
    rhostname[len] = '\000';
429
430
    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'",
431
	rhostname));
432
433
    /* Microsoft doesn't send their name back in the PPP packet */
434
    if (remote_name[0] != 0 && (explicit_remote || rhostname[0] == 0)) {
435
	strlcpy(rhostname, remote_name, sizeof(rhostname));
436
	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name",
437
		  rhostname));
438
    }
439
440
    /* get secret for authenticating ourselves with the specified host */
441
    if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
442
		    secret, &secret_len, 0)) {
443
	secret_len = 0;		/* assume null secret if can't find one */
444
	syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
445
	       rhostname);
446
    }
447
448
    /* cancel response send timeout if necessary */
449
    if (cstate->clientstate == CHAPCS_RESPONSE)
450
	UNTIMEOUT(ChapResponseTimeout, cstate);
451
452
    cstate->resp_id = id;
453
    cstate->resp_transmits = 0;
454
455
    /*  generate MD based on negotiated type */
456
    switch (cstate->resp_type) {
457
458
    case CHAP_DIGEST_MD5:
459
	MD5Init(&mdContext);
460
	MD5Update(&mdContext, &cstate->resp_id, 1);
461
	MD5Update(&mdContext, secret, secret_len);
462
	MD5Update(&mdContext, rchallenge, rchallenge_len);
463
	MD5Final(hash, &mdContext);
464
	BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
465
	cstate->resp_length = MD5_SIGNATURE_SIZE;
466
	break;
467
468
    default:
469
	CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
470
	return;
471
    }
472
473
    BZERO(secret, sizeof(secret));
474
    ChapSendResponse(cstate);
475
}
476
477
478
/*
479
 * ChapReceiveResponse - Receive and process response.
480
 */
481
static void
482
ChapReceiveResponse(cstate, inp, id, len)
483
    chap_state *cstate;
484
    u_char *inp;
485
    int id;
486
    int len;
487
{
488
    u_char *remmd, remmd_len;
489
    int secret_len, old_state;
490
    int code;
491
    char rhostname[256];
492
    MD5_CTX mdContext;
493
    char secret[MAXSECRETLEN];
494
    u_char hash[MD5_SIGNATURE_SIZE];
495
496
    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
497
498
    if (cstate->serverstate == CHAPSS_CLOSED ||
499
	cstate->serverstate == CHAPSS_PENDING) {
500
	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
501
		   cstate->serverstate));
502
	return;
503
    }
504
505
    if (id != cstate->chal_id)
506
	return;			/* doesn't match ID of last challenge */
507
508
    /*
509
     * If we have received a duplicate or bogus Response,
510
     * we have to send the same answer (Success/Failure)
511
     * as we did for the first Response we saw.
512
     */
513
    if (cstate->serverstate == CHAPSS_OPEN) {
514
	ChapSendStatus(cstate, CHAP_SUCCESS);
515
	return;
516
    }
517
    if (cstate->serverstate == CHAPSS_BADAUTH) {
518
	ChapSendStatus(cstate, CHAP_FAILURE);
519
	return;
520
    }
521
522
    if (len < 2) {
523
	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
524
	return;
525
    }
526
    GETCHAR(remmd_len, inp);		/* get length of MD */
527
    remmd = inp;			/* get pointer to MD */
528
    INCPTR(remmd_len, inp);
529
530
    len -= sizeof (u_char) + remmd_len;
531
    if (len < 0) {
532
	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
533
	return;
534
    }
535
536
    UNTIMEOUT(ChapChallengeTimeout, cstate);
537
538
    if (len >= sizeof(rhostname))
539
	len = sizeof(rhostname) - 1;
540
    BCOPY(inp, rhostname, len);
541
    rhostname[len] = '\000';
542
543
    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
544
	       rhostname));
545
546
    /*
547
     * Get secret for authenticating them with us,
548
     * do the hash ourselves, and compare the result.
549
     */
550
    code = CHAP_FAILURE;
551
    if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
552
		   secret, &secret_len, 1)) {
553
	syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
554
	       rhostname);
555
    } else {
556
557
	/*  generate MD based on negotiated type */
558
	switch (cstate->chal_type) {
559
560
	case CHAP_DIGEST_MD5:		/* only MD5 is defined for now */
561
	    if (remmd_len != MD5_SIGNATURE_SIZE)
562
		break;			/* it's not even the right length */
563
	    MD5Init(&mdContext);
564
	    MD5Update(&mdContext, &cstate->chal_id, 1);
565
	    MD5Update(&mdContext, secret, secret_len);
566
	    MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
567
	    MD5Final(hash, &mdContext);
568
569
	    /* compare local and remote MDs and send the appropriate status */
570
	    if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
571
		code = CHAP_SUCCESS;	/* they are the same! */
572
	    break;
573
574
	default:
575
	    CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
576
	}
577
    }
578
579
    BZERO(secret, sizeof(secret));
580
    ChapSendStatus(cstate, code);
581
582
    if (code == CHAP_SUCCESS) {
583
	old_state = cstate->serverstate;
584
	cstate->serverstate = CHAPSS_OPEN;
585
	if (old_state == CHAPSS_INITIAL_CHAL) {
586
            auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
587
	}
588
	if (cstate->chal_interval != 0)
589
	    TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
590
	syslog(LOG_NOTICE, "CHAP peer authentication succeeded for %s",
591
		rhostname);
592
593
    } else {
594
	syslog(LOG_ERR, "CHAP peer authentication failed for remote host %s",
595
		rhostname);
596
	cstate->serverstate = CHAPSS_BADAUTH;
597
	auth_peer_fail(cstate->unit, PPP_CHAP);
598
    }
599
}
600
601
/*
602
 * ChapReceiveSuccess - Receive Success
603
 */
604
static void
605
ChapReceiveSuccess(cstate, inp, id, len)
606
    chap_state *cstate;
607
    u_char *inp;
608
    u_char id;
609
    int len;
610
{
611
612
    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
613
614
    if (cstate->clientstate == CHAPCS_OPEN)
615
	/* presumably an answer to a duplicate response */
616
	return;
617
618
    if (cstate->clientstate != CHAPCS_RESPONSE) {
619
	/* don't know what this is */
620
	CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
621
		   cstate->clientstate));
622
	return;
623
    }
624
625
    UNTIMEOUT(ChapResponseTimeout, cstate);
626
627
    /*
628
     * Print message.
629
     */
630
    if (len > 0)
631
	PRINTMSG(inp, len);
632
633
    cstate->clientstate = CHAPCS_OPEN;
634
635
    auth_withpeer_success(cstate->unit, PPP_CHAP);
636
}
637
638
639
/*
640
 * ChapReceiveFailure - Receive failure.
641
 */
642
static void
643
ChapReceiveFailure(cstate, inp, id, len)
644
    chap_state *cstate;
645
    u_char *inp;
646
    u_char id;
647
    int len;
648
{
649
    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
650
651
    if (cstate->clientstate != CHAPCS_RESPONSE) {
652
	/* don't know what this is */
653
	CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
654
		   cstate->clientstate));
655
	return;
656
    }
657
658
    UNTIMEOUT(ChapResponseTimeout, cstate);
659
660
    /*
661
     * Print message.
662
     */
663
    if (len > 0)
664
	PRINTMSG(inp, len);
665
666
    syslog(LOG_ERR, "CHAP authentication failed");
667
    auth_withpeer_fail(cstate->unit, PPP_CHAP);
668
}
669
670
671
/*
672
 * ChapSendChallenge - Send an Authenticate challenge.
673
 */
674
static void
675
ChapSendChallenge(cstate)
676
    chap_state *cstate;
677
{
678
    u_char *outp;
679
    int chal_len, name_len;
680
    int outlen;
681
682
    chal_len = cstate->chal_len;
683
    name_len = strlen(cstate->chal_name);
684
    outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
685
    outp = outpacket_buf;
686
687
    MAKEHEADER(outp, PPP_CHAP);		/* paste in a CHAP header */
688
689
    PUTCHAR(CHAP_CHALLENGE, outp);
690
    PUTCHAR(cstate->chal_id, outp);
691
    PUTSHORT(outlen, outp);
692
693
    PUTCHAR(chal_len, outp);		/* put length of challenge */
694
    BCOPY(cstate->challenge, outp, chal_len);
695
    INCPTR(chal_len, outp);
696
697
    BCOPY(cstate->chal_name, outp, name_len);	/* append hostname */
698
699
    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
700
701
    CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
702
703
    TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
704
    ++cstate->chal_transmits;
705
}
706
707
708
/*
709
 * ChapSendStatus - Send a status response (ack or nak).
710
 */
711
static void
712
ChapSendStatus(cstate, code)
713
    chap_state *cstate;
714
    int code;
715
{
716
    u_char *outp;
717
    int outlen, msglen;
718
    char msg[256];
719
720
    if (code == CHAP_SUCCESS)
721
	snprintf(msg, sizeof msg, "Welcome to %s.", hostname);
722
    else
723
	snprintf(msg, sizeof msg, "I don't like you.  Go 'way.");
724
    msglen = strlen(msg);
725
726
    outlen = CHAP_HEADERLEN + msglen;
727
    outp = outpacket_buf;
728
729
    MAKEHEADER(outp, PPP_CHAP);	/* paste in a header */
730
731
    PUTCHAR(code, outp);
732
    PUTCHAR(cstate->chal_id, outp);
733
    PUTSHORT(outlen, outp);
734
    BCOPY(msg, outp, msglen);
735
    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
736
737
    CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
738
	       cstate->chal_id));
739
}
740
741
/*
742
 * ChapGenChallenge is used to generate a pseudo-random challenge string of
743
 * a pseudo-random length between min_len and max_len.  The challenge
744
 * string and its length are stored in *cstate, and various other fields of
745
 * *cstate are initialized.
746
 */
747
748
static void
749
ChapGenChallenge(cstate)
750
    chap_state *cstate;
751
{
752
    int chal_len;
753
754
    /* pick a random challenge length >= MIN_CHALLENGE_LENGTH and
755
       <= MAX_CHALLENGE_LENGTH */
756
    chal_len = MIN_CHALLENGE_LENGTH +
757
	arc4random_uniform(MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH + 1);
758
759
    cstate->chal_len = chal_len;
760
    cstate->chal_id = ++cstate->id;
761
    cstate->chal_transmits = 0;
762
763
    /* generate a random string */
764
    arc4random_buf(cstate->challenge, chal_len);
765
}
766
767
/*
768
 * ChapSendResponse - send a response packet with values as specified
769
 * in *cstate.
770
 */
771
/* ARGSUSED */
772
static void
773
ChapSendResponse(cstate)
774
    chap_state *cstate;
775
{
776
    u_char *outp;
777
    int outlen, md_len, name_len;
778
779
    md_len = cstate->resp_length;
780
    name_len = strlen(cstate->resp_name);
781
    outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
782
    outp = outpacket_buf;
783
784
    MAKEHEADER(outp, PPP_CHAP);
785
786
    PUTCHAR(CHAP_RESPONSE, outp);	/* we are a response */
787
    PUTCHAR(cstate->resp_id, outp);	/* copy id from challenge packet */
788
    PUTSHORT(outlen, outp);		/* packet length */
789
790
    PUTCHAR(md_len, outp);		/* length of MD */
791
    BCOPY(cstate->response, outp, md_len);	/* copy MD to buffer */
792
    INCPTR(md_len, outp);
793
794
    BCOPY(cstate->resp_name, outp, name_len); /* append our name */
795
796
    /* send the packet */
797
    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
798
799
    cstate->clientstate = CHAPCS_RESPONSE;
800
    TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
801
    ++cstate->resp_transmits;
802
}
803
804
/*
805
 * ChapPrintPkt - print the contents of a CHAP packet.
806
 */
807
static char *ChapCodenames[] = {
808
    "Challenge", "Response", "Success", "Failure"
809
};
810
811
static int
812
ChapPrintPkt(p, plen, printer, arg)
813
    u_char *p;
814
    int plen;
815
    void (*printer)(void *, char *, ...);
816
    void *arg;
817
{
818
    int code, id, len;
819
    int clen, nlen;
820
    u_char x;
821
822
    if (plen < CHAP_HEADERLEN)
823
	return 0;
824
    GETCHAR(code, p);
825
    GETCHAR(id, p);
826
    GETSHORT(len, p);
827
    if (len < CHAP_HEADERLEN || len > plen)
828
	return 0;
829
830
    if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
831
	printer(arg, " %s", ChapCodenames[code-1]);
832
    else
833
	printer(arg, " code=0x%x", code);
834
    printer(arg, " id=0x%x", id);
835
    len -= CHAP_HEADERLEN;
836
    switch (code) {
837
    case CHAP_CHALLENGE:
838
    case CHAP_RESPONSE:
839
	if (len < 1)
840
	    break;
841
	clen = p[0];
842
	if (len < clen + 1)
843
	    break;
844
	++p;
845
	nlen = len - clen - 1;
846
	printer(arg, " <");
847
	for (; clen > 0; --clen) {
848
	    GETCHAR(x, p);
849
	    printer(arg, "%.2x", x);
850
	}
851
	printer(arg, ">, name = ");
852
	print_string((char *)p, nlen, printer, arg);
853
	break;
854
    case CHAP_FAILURE:
855
    case CHAP_SUCCESS:
856
	printer(arg, " ");
857
	print_string((char *)p, len, printer, arg);
858
	break;
859
    default:
860
	for (clen = len; clen > 0; --clen) {
861
	    GETCHAR(x, p);
862
	    printer(arg, " %.2x", x);
863
	}
864
    }
865
866
    return len + CHAP_HEADERLEN;
867
}