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

Line Branch Exec Source
1
/*	$OpenBSD: chap.c,v 1.15 2016/03/22 04:11:27 yasuoka Exp $ */
2
3
/*-
4
 * Copyright (c) 2009 Internet Initiative Japan Inc.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
/**@file
29
 * This file provides CHAP (PPP Challenge Handshake Authentication Protocol,
30
 * RFC 1994) handlers.  Currently this contains authenticator side
31
 * implementation only.
32
 *<p>
33
 * Supported authentication types:
34
 *  <li>MD5-CHAP</li>
35
 *  <li>MS-CHAP Version 2 (RFC 2759)</li>
36
 * </ul></p>
37
 */
38
/* RFC 1994, 2433 */
39
/* $Id: chap.c,v 1.15 2016/03/22 04:11:27 yasuoka Exp $ */
40
#include <sys/types.h>
41
#include <sys/socket.h>
42
#include <sys/time.h>
43
#include <netinet/in.h>
44
#include <net/if_dl.h>
45
#include <stdlib.h>
46
#include <stdio.h>
47
#include <syslog.h>
48
#include <string.h>
49
#include <unistd.h>
50
#include <stdarg.h>
51
#include <errno.h>
52
#include <time.h>
53
#include <event.h>
54
#include <md5.h>
55
#include <vis.h>
56
57
#include "slist.h"
58
#include "npppd.h"
59
#include "ppp.h"
60
61
#ifdef USE_NPPPD_RADIUS
62
#include "radius_chap_const.h"
63
#include "npppd_radius.h"
64
#endif
65
#include "npppd_defs.h"
66
67
#include "debugutil.h"
68
#include "chap_ms.h"
69
70
#define	HEADERLEN	4
71
72
#define	CHAP_STATE_INITIAL		1
73
#define	CHAP_STATE_SENT_CHALLENGE	2
74
#define	CHAP_STATE_AUTHENTICATING	3
75
#define	CHAP_STATE_SENT_RESPONSE	4
76
#define	CHAP_STATE_STOPPED		5
77
#define	CHAP_STATE_PROXY_AUTHENTICATION	6
78
79
/* retry intervals */
80
#define	CHAP_TIMEOUT	3
81
#define	CHAP_RETRY	10
82
83
#define	CHAP_CHALLENGE	1
84
#define	CHAP_RESPONSE	2
85
#define	CHAP_SUCCESS	3
86
#define	CHAP_FAILURE	4
87
88
/* from RFC 2433 */
89
#define	ERROR_RESTRICTED_LOGIN_HOURS		646
90
#define	ERROR_ACCT_DISABLED			647
91
#define	ERROR_PASSWD_EXPIRED			648
92
#define	ERROR_NO_DIALIN_PERMISSION		649
93
#define	ERROR_AUTHENTICATION_FAILURE		691
94
#define	ERROR_CHANGING_PASSWORD			709
95
96
/*  MprError.h */
97
#define	ERROR_AUTH_SERVER_TIMEOUT		930
98
99
#ifdef	CHAP_DEBUG
100
#define	CHAP_DBG(x)	chap_log x
101
#define	CHAP_ASSERT(cond)					\
102
	if (!(cond)) {						\
103
	    fprintf(stderr,					\
104
		"\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
105
		, __func__, __FILE__, __LINE__);		\
106
	    abort(); 						\
107
	}
108
#else
109
#define	CHAP_ASSERT(cond)
110
#define	CHAP_DBG(x)
111
#endif
112
113
static void        chap_authenticate(chap *_this, u_char *, int);
114
static void        chap_failure(chap *, const char *, int);
115
static void        chap_response (chap *, int, u_char *, int);
116
static void        chap_create_challenge (chap *);
117
static void        chap_send_error (chap *, const char *);
118
static void        md5chap_authenticate (chap *, int, char *, u_char *, int, u_char *);
119
static void        mschapv2_send_error (chap *, int, int);
120
static void        mschapv2_authenticate (chap *, int, char *, u_char *, int, u_char *);
121
#ifdef USE_NPPPD_RADIUS
122
static void        chap_radius_authenticate (chap *, int, char *, u_char *, int, u_char *);
123
static void        chap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
124
#endif
125
static char       *strip_nt_domain (char *);
126
static void        chap_log (chap *, uint32_t, const char *, ...) __printflike(3,4);
127
128
/** Initialize the CHAP */
129
void
130
chap_init(chap *_this, npppd_ppp *ppp)
131
{
132
	struct tunnconf *conf;
133
134
	CHAP_ASSERT(ppp != NULL);
135
	CHAP_ASSERT(_this != NULL);
136
137
	memset(_this, 0, sizeof(chap));
138
	_this->ppp = ppp;
139
140
	conf = ppp_get_tunnconf(ppp);
141
142
	if (conf->chap_name == NULL)
143
		gethostname(_this->myname, sizeof(_this->myname));
144
	else
145
		strlcpy(_this->myname, conf->chap_name, sizeof(_this->myname));
146
147
	_this->timerctx.ctx = _this;
148
	_this->state = CHAP_STATE_INITIAL;
149
150
	_this->ntry = CHAP_RETRY;
151
}
152
153
/** Start CHAP as a authenticator.  Send a challenge */
154
void
155
chap_start(chap *_this)
156
{
157
	u_char *challp, *challp0;
158
	int lmyname;
159
160
	CHAP_ASSERT(_this != NULL);
161
	CHAP_ASSERT(_this->ppp != NULL);
162
163
	if (_this->state == CHAP_STATE_PROXY_AUTHENTICATION) {
164
		_this->type = PPP_AUTH_CHAP_MD5;
165
		_this->state = CHAP_STATE_AUTHENTICATING;
166
		chap_authenticate(_this, _this->ppp->proxy_authen_resp,
167
		    _this->ppp->lproxy_authen_resp);
168
		return;
169
	}
170
171
	if (_this->state == CHAP_STATE_INITIAL ||
172
	    _this->state == CHAP_STATE_SENT_CHALLENGE) {
173
		if (_this->ntry > 0) {
174
			_this->ntry--;
175
			_this->type = _this->ppp->peer_auth;
176
177
			/* The type is supported? */
178
			if (_this->type != PPP_AUTH_CHAP_MS_V2 &&
179
			    _this->type != PPP_AUTH_CHAP_MD5) {
180
				chap_log(_this, LOG_ALERT,
181
				    "Requested authentication type(0x%x) "
182
				    "is not supported.", _this->type);
183
				ppp_set_disconnect_cause(_this->ppp,
184
				    PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE,
185
				    PPP_PROTO_CHAP, 2 /* local */, NULL);
186
				ppp_stop(_this->ppp, "Authentication Required");
187
				return;
188
			}
189
190
191
#ifdef USE_NPPPD_MPPE
192
			/* The peer must use MS-CHAP-V2 as the type */
193
			if (MPPE_IS_REQUIRED(_this->ppp) &&
194
			    _this->type != PPP_AUTH_CHAP_MS_V2) {
195
				chap_log(_this, LOG_ALERT,
196
				    "mppe is required but try to start chap "
197
				    "type=0x%02x", _this->type);
198
				ppp_set_disconnect_cause(_this->ppp,
199
				    PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE,
200
				    PPP_PROTO_CHAP, 2 /* local */, NULL);
201
				ppp_stop(_this->ppp, "Authentication Required");
202
				return;
203
			}
204
#endif
205
			/* Generate a challenge packet and send it */
206
			challp = ppp_packetbuf(_this->ppp, PPP_AUTH_CHAP);
207
			challp += HEADERLEN;
208
			challp0 = challp;
209
210
			chap_create_challenge(_this);
211
212
			PUTCHAR(_this->lchall, challp);
213
			memcpy(challp, &_this->chall, _this->lchall);
214
			challp += _this->lchall;
215
216
			lmyname = strlen(_this->myname);
217
218
			memcpy(challp, _this->myname, lmyname);
219
			challp += lmyname;
220
221
			_this->challid = ++_this->pktid;
222
223
			ppp_output(_this->ppp, PPP_PROTO_CHAP, CHAP_CHALLENGE,
224
			    _this->challid, challp0, challp - challp0);
225
226
			_this->state = CHAP_STATE_SENT_CHALLENGE;
227
228
			TIMEOUT((void (*)(void *))chap_start, _this,
229
			    CHAP_TIMEOUT);
230
		} else {
231
			chap_log(_this, LOG_INFO,
232
			    "Client did't respond our challenage.");
233
			ppp_set_disconnect_cause(_this->ppp,
234
			    PPP_DISCON_AUTH_FSM_TIMEOUT,
235
			    PPP_PROTO_CHAP, 0, NULL);
236
			ppp_stop(_this->ppp, "Authentication Required");
237
		}
238
	}
239
}
240
241
/** Stop the CHAP */
242
void
243
chap_stop(chap *_this)
244
{
245
	_this->state = CHAP_STATE_STOPPED;
246
	UNTIMEOUT(chap_start, _this);
247
#ifdef USE_NPPPD_RADIUS
248
	if (_this->radctx != NULL) {
249
		radius_cancel_request(_this->radctx);
250
		_this->radctx = NULL;
251
	}
252
#endif
253
}
254
255
/** Called when a CHAP packet is received. */
256
void
257
chap_input(chap *_this, u_char *pktp, int len)
258
{
259
	int code, id, length, lval, lname, authok;
260
	u_char *pktp1, *val, namebuf[MAX_USERNAME_LENGTH];
261
	char *name;
262
263
	if (_this->state == CHAP_STATE_STOPPED ||
264
	    _this->state == CHAP_STATE_INITIAL) {
265
		chap_log(_this, LOG_INFO, "Received chap packet.  But chap is "
266
		    "not started");
267
		return;
268
	}
269
270
	CHAP_ASSERT(_this != NULL);
271
	if (len < 4) {
272
		chap_log(_this, LOG_ERR, "%s: Received broken packet.",
273
		    __func__);
274
		return;
275
	}
276
277
	pktp1 = pktp;
278
279
	GETCHAR(code, pktp1);
280
	GETCHAR(id, pktp1);
281
	GETSHORT(length, pktp1);
282
	if (len < length || len < 5) {
283
		chap_log(_this, LOG_ERR, "%s: Received broken packet.",
284
		    __func__);
285
		return;
286
	}
287
288
	if (code != CHAP_RESPONSE) {
289
		chap_log(_this, LOG_ERR, "Received unknown code=%d", code);
290
		return;
291
	}
292
293
	/* Create a chap response */
294
295
	if (id != _this->challid) {
296
		chap_log(_this, LOG_ERR,
297
		    "Received challenge response has unknown id.");
298
		return;
299
	}
300
	if (_this->state == CHAP_STATE_AUTHENTICATING)
301
		return;
302
303
	authok = 0;
304
	UNTIMEOUT(chap_start, _this);
305
306
	/* pick the username */
307
	GETCHAR(lval, pktp1);
308
	val = pktp1;
309
	pktp1 += lval;
310
311
	if (lval > length) {
312
		chap_log(_this, LOG_ERR,
313
		    "Received challenge response has invalid Value-Size "
314
		    "field. %d", lval);
315
		return;
316
	}
317
	name = pktp1;
318
	lname = len - (pktp1 - pktp);
319
	if (lname <= 0 || sizeof(namebuf) <= lname + 1) {
320
		chap_log(_this, LOG_ERR,
321
		    "Received challenge response has invalid Name "
322
		    "field.");
323
		return;
324
	}
325
	memcpy(namebuf, name, lname);
326
	namebuf[lname] = '\0';
327
	name = namebuf;
328
	if (_this->state == CHAP_STATE_SENT_RESPONSE) {
329
		if (strcmp(_this->name, name) != 0) {
330
			/*
331
			 * The peer requests us to resend, but the username
332
			 * has been changed.
333
			 */
334
			chap_log(_this, LOG_ERR,
335
			    "Received AuthReq is not same as before.  "
336
			    "%s != %s", name, _this->name);
337
			return;
338
		}
339
	} else if (_this->state != CHAP_STATE_SENT_CHALLENGE) {
340
		chap_log(_this, LOG_ERR,
341
		    "Received AuthReq in illegal state.  username=%s", name);
342
		return;
343
	}
344
	_this->state = CHAP_STATE_AUTHENTICATING;
345
	strlcpy(_this->name, name, sizeof(_this->name));
346
347
	chap_authenticate(_this, val, lval);
348
}
349
350
static void
351
chap_failure(chap *_this, const char *msg, int mschapv2err)
352
{
353
354
	switch(_this->type) {
355
	case PPP_AUTH_CHAP_MD5:
356
		chap_send_error(_this, "FAILED");
357
		break;
358
	case PPP_AUTH_CHAP_MS_V2:
359
		mschapv2_send_error(_this, mschapv2err, 0);
360
		break;
361
	}
362
}
363
364
static void
365
chap_authenticate(chap *_this, u_char *response, int lresponse)
366
{
367
368
	switch(_this->type) {
369
	case PPP_AUTH_CHAP_MD5:
370
		/* check the length */
371
		if (lresponse != 16) {
372
			chap_log(_this, LOG_ERR,
373
			    "Invalid response length %d != 16", lresponse);
374
			chap_failure(_this, "FAILED",
375
			    ERROR_AUTHENTICATION_FAILURE);
376
			return;
377
		}
378
		break;
379
	case PPP_AUTH_CHAP_MS_V2:
380
		/* check the length */
381
		if (lresponse < 49) {
382
			chap_log(_this, LOG_ERR, "Packet too short.");
383
			chap_failure(_this, "FAILED",
384
			    ERROR_AUTHENTICATION_FAILURE);
385
			return;
386
		}
387
		break;
388
	}
389
	if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 0)
390
	    == 0) {
391
		if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) {
392
			chap_log(_this, LOG_INFO,
393
			    "username=\"%s\" realm is not ready.", _this->name);
394
			chap_failure(_this, "FAILED",
395
			    ERROR_AUTH_SERVER_TIMEOUT);
396
			return;
397
		}
398
#ifdef USE_NPPPD_RADIUS
399
		if (npppd_ppp_is_realm_radius(_this->ppp->pppd, _this->ppp)) {
400
			chap_radius_authenticate(_this, _this->challid,
401
			    _this->name, _this->chall, _this->lchall, response);
402
			return;
403
			/* NOTREACHED */
404
		} else
405
#endif
406
		if (npppd_ppp_is_realm_local(_this->ppp->pppd, _this->ppp)) {
407
			switch(_this->type) {
408
			case PPP_AUTH_CHAP_MD5:
409
				md5chap_authenticate(_this, _this->challid,
410
				    _this->name, _this->chall, _this->lchall,
411
				    response);
412
				return;
413
				/* NOTREACHED */
414
			case PPP_AUTH_CHAP_MS_V2:
415
				mschapv2_authenticate(_this, _this->challid,
416
				    strip_nt_domain(_this->name),
417
				    _this->chall, _this->lchall, response);
418
				return;
419
				/* NOTREACHED */
420
			}
421
		}
422
	}
423
	chap_failure(_this, "FAILED", ERROR_AUTHENTICATION_FAILURE);
424
425
	return;
426
}
427
428
static void
429
chap_response(chap *_this, int authok, u_char *pktp, int lpktp)
430
{
431
	const char *realm_name;
432
433
	CHAP_ASSERT(_this != NULL);
434
	CHAP_ASSERT(pktp != NULL);
435
	CHAP_ASSERT(_this->type == PPP_AUTH_CHAP_MD5 ||
436
	    _this->type == PPP_AUTH_CHAP_MS_V2);
437
438
	ppp_output(_this->ppp, PPP_PROTO_CHAP, (authok)? 3 : 4, _this->challid,
439
	    pktp, lpktp);
440
441
	realm_name = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp);
442
	if (!authok) {
443
		chap_log(_this, LOG_ALERT,
444
		    "logtype=Failure username=\"%s\" realm=%s", _this->name,
445
		    realm_name);
446
		chap_stop(_this);
447
		/* Stop the PPP if the authentication is failed. */
448
		ppp_set_disconnect_cause(_this->ppp,
449
		    PPP_DISCON_AUTH_FAILED, PPP_PROTO_CHAP, 1 /* peer */, NULL);
450
		ppp_stop(_this->ppp, "Authentication Required");
451
	} else {
452
		strlcpy(_this->ppp->username, _this->name,
453
		    sizeof(_this->ppp->username));
454
		chap_log(_this, LOG_INFO,
455
		    "logtype=Success username=\"%s\" "
456
		    "realm=%s", _this->name, realm_name);
457
		chap_stop(_this);
458
		/* We change our state to prepare to resend requests. */
459
		_this->state = CHAP_STATE_SENT_RESPONSE;
460
		ppp_auth_ok(_this->ppp);
461
	}
462
}
463
464
/** Generate a challenge */
465
static void
466
chap_create_challenge(chap *_this)
467
{
468
	CHAP_ASSERT(_this->ppp->peer_auth == PPP_AUTH_CHAP_MS_V2 ||
469
	    _this->ppp->peer_auth == PPP_AUTH_CHAP_MD5);
470
471
	_this->lchall = 16;
472
	arc4random_buf(_this->chall, _this->lchall);
473
}
474
475
/***********************************************************************
476
 * Proxy Authentication
477
 ***********************************************************************/
478
int
479
chap_proxy_authen_prepare(chap *_this, dialin_proxy_info *dpi)
480
{
481
482
	CHAP_ASSERT(dpi->auth_type == PPP_AUTH_CHAP_MD5);
483
	CHAP_ASSERT(_this->state == CHAP_STATE_INITIAL);
484
485
	_this->pktid = dpi->auth_id;
486
487
#ifdef USE_NPPPD_MPPE
488
	if (MPPE_IS_REQUIRED(_this->ppp) &&
489
	    _this->type != PPP_AUTH_CHAP_MS_V2) {
490
		chap_log(_this, LOG_ALERT,
491
		    "mppe is required but try to start chap "
492
		    "type=0x%02x", dpi->auth_type);
493
		return -1;
494
	}
495
#endif
496
	/* authentication */
497
	if (strlen(dpi->username) >= sizeof(_this->name)) {
498
		chap_log(_this, LOG_NOTICE,
499
		    "\"Proxy Authen Name\" is too long.");
500
		return -1;
501
	}
502
	if (dpi->lauth_chall >= sizeof(_this->chall)) {
503
		chap_log(_this, LOG_NOTICE,
504
		    "\"Proxy Authen Challenge\" is too long.");
505
		return -1;
506
	}
507
508
	/* copy the authenticaiton properties */
509
	CHAP_ASSERT(_this->ppp->proxy_authen_resp == NULL);
510
	if ((_this->ppp->proxy_authen_resp = malloc(dpi->lauth_resp)) ==
511
	    NULL) {
512
		chap_log(_this, LOG_ERR, "malloc() failed in %s(): %m",
513
		    __func__);
514
		return -1;
515
	}
516
	memcpy(_this->ppp->proxy_authen_resp, dpi->auth_resp,
517
	    dpi->lauth_resp);
518
	_this->ppp->lproxy_authen_resp = dpi->lauth_resp;
519
520
	_this->challid = dpi->auth_id;
521
	strlcpy(_this->name, dpi->username, sizeof(_this->name));
522
523
	memcpy(_this->chall, dpi->auth_chall, dpi->lauth_chall);
524
	_this->lchall = dpi->lauth_chall;
525
526
	_this->state = CHAP_STATE_PROXY_AUTHENTICATION;
527
528
	return 0;
529
}
530
531
/************************************************************************
532
 * Functions for MD5-CHAP(RFC1994)
533
 ************************************************************************/
534
static void
535
md5chap_authenticate(chap *_this, int id, char *username, u_char *challenge,
536
    int lchallenge, u_char *response)
537
{
538
	MD5_CTX md5ctx;
539
	int rval, passlen;
540
	u_char digest[16];
541
	char *password, buf[MAX_PASSWORD_LENGTH + 1];
542
543
	buf[0] = id;
544
	passlen = sizeof(buf) - 1;
545
	password = &buf[1];
546
547
	rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
548
	    password, &passlen);
549
550
	if (rval != 0) {
551
		switch (rval) {
552
		case 1:
553
			chap_log(_this, LOG_INFO,
554
			    "username=\"%s\" user unknown", username);
555
			break;
556
		default:
557
			chap_log(_this, LOG_ERR,
558
			    "username=\"%s\" generic error", username);
559
			break;
560
		}
561
		goto auth_failed;
562
	}
563
	passlen = strlen(password);
564
	MD5Init(&md5ctx);
565
	MD5Update(&md5ctx, buf, passlen + 1);
566
	MD5Update(&md5ctx, challenge, lchallenge);
567
	MD5Final(digest, &md5ctx);
568
569
	if (memcmp(response, digest, 16) == 0) {
570
		chap_response(_this, 1, "OK", 2);
571
		return;
572
	}
573
	/* FALLTHROUGH.  The password are not matched */
574
auth_failed:
575
	/* No extra information, just "FAILED" */
576
	chap_send_error(_this, "FAILED");
577
578
	return;
579
}
580
581
static void
582
chap_send_error(chap *_this, const char *msg)
583
{
584
	u_char *pkt, *challenge;
585
	int lpkt;
586
587
	challenge = _this->chall;
588
589
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
590
	lpkt = _this->ppp->mru - HEADERLEN;
591
592
	strlcpy(pkt, msg, lpkt);
593
	lpkt = strlen(msg);
594
595
	chap_response(_this, 0, pkt, lpkt);
596
}
597
598
/************************************************************************
599
 * Functions for MS-CHAP-V2(RFC 2759)
600
 ************************************************************************/
601
static void
602
mschapv2_send_error(chap *_this, int error, int can_retry)
603
{
604
	u_char *pkt, *challenge;
605
	int lpkt;
606
607
	challenge = _this->chall;
608
609
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
610
	lpkt = _this->ppp->mru - HEADERLEN;
611
612
	/*
613
	 * We don't use "M=<msg>"
614
	 *  - pppd on Mac OS 10.4 hungs up if it received a failure packet
615
	 *    with "M=<msg>".
616
	 *  - RRAS on windows server 2003 never uses "M=".
617
	 */
618
	snprintf(pkt, lpkt, "E=%d R=%d C=%02x%02x%02x%02x%02x%02x%02x%02x"
619
	    "%02x%02x%02x%02x%02x%02x%02x%02x V=3", error, can_retry,
620
	    challenge[0], challenge[1], challenge[2], challenge[3],
621
	    challenge[4], challenge[5], challenge[6], challenge[7],
622
	    challenge[8], challenge[9], challenge[10], challenge[11],
623
	    challenge[12], challenge[13], challenge[14], challenge[15]
624
	);
625
	lpkt = strlen(pkt);
626
627
	chap_response(_this, 0, pkt, lpkt);
628
}
629
630
static void
631
mschapv2_authenticate(chap *_this, int id, char *username, u_char *challenge,
632
    int lchallenge, u_char *response)
633
{
634
	int i, rval, passlen, lpkt;
635
	u_char *pkt;
636
	char password[MAX_PASSWORD_LENGTH * 2], ntresponse[24];
637
#ifdef	USE_NPPPD_MPPE
638
	char pwdhash[16], pwdhashhash[16];
639
#endif
640
641
	CHAP_DBG((_this, LOG_DEBUG, "%s()", __func__));
642
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
643
	lpkt = _this->ppp->mru - HEADERLEN;
644
645
	passlen = sizeof(password) / 2;
646
	rval = npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
647
	    password, &passlen);
648
649
	if (rval != 0) {
650
		switch (rval) {
651
		case 1:
652
			chap_log(_this, LOG_INFO,
653
			    "username=\"%s\" user unknown", username);
654
			break;
655
		default:
656
			chap_log(_this, LOG_ERR,
657
			    "username=\"%s\" generic error", username);
658
			break;
659
		}
660
		goto auth_failed;
661
	}
662
663
	/* Convert the string charset from ASCII to UTF16-LE */
664
	passlen = strlen(password);
665
	for (i = passlen - 1; i >= 0; i--) {
666
		password[i*2] = password[i];
667
		password[i*2+1] = 0;
668
	}
669
670
	mschap_nt_response(challenge, response, username, strlen(username),
671
		    password, passlen * 2, ntresponse);
672
673
	if (memcmp(ntresponse, response + 24, 24) != 0) {
674
		chap_log(_this, LOG_INFO,
675
		    "username=\"%s\" password mismatch.", username);
676
		goto auth_failed;
677
	}
678
679
    /*
680
     * Authentication succeed
681
     */
682
	CHAP_DBG((_this, LOG_DEBUG, "%s() OK", __func__));
683
684
	mschap_auth_response(password, passlen * 2, ntresponse,
685
	    challenge, response, username, strlen(username), pkt);
686
	lpkt = 42;
687
#ifdef	USE_NPPPD_MPPE
688
	if (_this->ppp->mppe.enabled != 0) {
689
		mschap_ntpassword_hash(password, passlen * 2, pwdhash);
690
		mschap_ntpassword_hash(pwdhash, sizeof(pwdhash), pwdhashhash);
691
692
		mschap_masterkey(pwdhashhash, ntresponse,
693
		    _this->ppp->mppe.master_key);
694
		mschap_asymetric_startkey(_this->ppp->mppe.master_key,
695
		    _this->ppp->mppe.recv.master_key, MPPE_KEYLEN, 0, 1);
696
		mschap_asymetric_startkey(_this->ppp->mppe.master_key,
697
		    _this->ppp->mppe.send.master_key, MPPE_KEYLEN, 1, 1);
698
	}
699
#endif
700
	chap_response(_this, 1, pkt, lpkt);
701
702
	return;
703
auth_failed:
704
	/* No extra information */
705
	mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);
706
707
	return;
708
}
709
710
#ifdef USE_NPPPD_RADIUS
711
/************************************************************************
712
 * Functions for RADIUS
713
 * RFC 2058: RADIUS
714
 * RFC 2548: Microsoft Vendor-specific RADIUS Attributes
715
 ************************************************************************/
716
static void
717
chap_radius_authenticate(chap *_this, int id, char *username,
718
    u_char *challenge, int lchallenge, u_char *response)
719
{
720
	void *radctx;
721
	RADIUS_PACKET *radpkt;
722
	radius_req_setting *rad_setting;
723
	int lpkt;
724
	u_char *pkt;
725
	char buf0[MAX_USERNAME_LENGTH];
726
727
	radpkt = NULL;
728
	radctx = NULL;
729
730
	if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd,
731
	    _this->ppp)) == NULL) {
732
		goto fail;	/* no radius server */
733
	}
734
	pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN;
735
	lpkt = _this->ppp->mru - HEADERLEN;
736
737
	if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
738
	    == NULL)
739
		goto fail;
740
	if (radius_prepare(rad_setting, _this, &radctx, chap_radius_response)
741
	    != 0) {
742
		radius_delete_packet(radpkt);
743
		goto fail;
744
	}
745
746
	if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt)
747
	    != 0)
748
		goto fail;
749
750
	if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
751
	    npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp,
752
		username, buf0)) != 0)
753
		goto fail;
754
755
	switch (_this->type) {
756
	case PPP_AUTH_CHAP_MD5:
757
	    {
758
		u_char md5response[17];
759
760
		md5response[0] = _this->challid;
761
		memcpy(&md5response[1], response, 16);
762
		if (radius_put_raw_attr(radpkt,
763
		    RADIUS_TYPE_CHAP_PASSWORD, md5response, 17) != 0)
764
			goto fail;
765
		if (radius_put_raw_attr(radpkt,
766
		    RADIUS_TYPE_CHAP_CHALLENGE, challenge, lchallenge) != 0)
767
			goto fail;
768
		break;
769
	    }
770
	case PPP_AUTH_CHAP_MS_V2:
771
	    {
772
		struct RADIUS_MS_CHAP2_RESPONSE msresponse;
773
774
		/* Preparing RADIUS_MS_CHAP2_RESPONSE  */
775
		memset(&msresponse, 0, sizeof(msresponse));
776
		msresponse.ident = id;
777
		msresponse.flags = response[48];
778
		memcpy(&msresponse.peer_challenge, response, 16);
779
		memcpy(&msresponse.response, response + 24, 24);
780
781
		if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
782
		    RADIUS_VTYPE_MS_CHAP_CHALLENGE, challenge, 16) != 0)
783
			goto fail;
784
		if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT,
785
		    RADIUS_VTYPE_MS_CHAP2_RESPONSE, &msresponse,
786
		    sizeof(msresponse)) != 0)
787
			goto fail;
788
		break;
789
	    }
790
791
	}
792
	radius_get_authenticator(radpkt, _this->authenticator);
793
794
	/* Cancel previous request */
795
	if (_this->radctx != NULL)
796
		radius_cancel_request(_this->radctx);
797
798
	/* Send a request */
799
	_this->radctx = radctx;
800
	radius_request(radctx, radpkt);
801
802
	return;
803
fail:
804
	switch (_this->type) {
805
	case PPP_AUTH_CHAP_MD5:
806
		/* No extra information, just "FAILED" */
807
		chap_send_error(_this, "FAILED");
808
		break;
809
	case PPP_AUTH_CHAP_MS_V2:
810
		/* No extra information */
811
		mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0);
812
		break;
813
	}
814
	if (radctx != NULL)
815
		radius_cancel_request(radctx);
816
}
817
818
static void
819
chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags,
820
    RADIUS_REQUEST_CTX reqctx)
821
{
822
	int code, lrespkt;
823
	const char *secret, *reason = "";
824
	chap *_this;
825
	u_char *respkt, *respkt0;
826
	int errorCode;
827
	RADIUS_REQUEST_CTX radctx;
828
829
	CHAP_ASSERT(context != NULL);
830
831
	reason = "";
832
	errorCode = ERROR_AUTH_SERVER_TIMEOUT;
833
	_this = context;
834
	secret = radius_get_server_secret(_this->radctx);
835
	radctx = _this->radctx;
836
	_this->radctx = NULL;	/* IMPORTANT */
837
838
	respkt = respkt0 = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP)
839
	    + HEADERLEN;
840
	lrespkt = _this->ppp->mru - HEADERLEN;
841
	if (pkt == NULL) {
842
		if (flags & RADIUS_REQUEST_TIMEOUT)
843
			reason = "timeout";
844
		else if (flags & RADIUS_REQUEST_ERROR)
845
			reason = strerror(errno);
846
		else
847
			reason = "error";
848
		goto auth_failed;
849
	}
850
851
	code = radius_get_code(pkt);
852
	if (code == RADIUS_CODE_ACCESS_REJECT) {
853
		reason="reject";
854
		errorCode = ERROR_AUTHENTICATION_FAILURE;
855
		/* Windows peer will reset the password by this error code */
856
		goto auth_failed;
857
	} else if (code != RADIUS_CODE_ACCESS_ACCEPT) {
858
		reason="error";
859
		goto auth_failed;
860
	}
861
	if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 &&
862
	    (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) {
863
		reason="bad_authenticator";
864
		goto auth_failed;
865
	}
866
	/*
867
	 * Authetication OK
868
	 */
869
	switch (_this->type) {
870
	case PPP_AUTH_CHAP_MD5:
871
	    chap_response(_this, 1, "OK", 2);
872
	    break;
873
	case PPP_AUTH_CHAP_MS_V2:
874
	    {
875
		struct RADIUS_MS_CHAP2_SUCCESS success;
876
#ifdef USE_NPPPD_MPPE
877
		struct RADIUS_MPPE_KEY sendkey, recvkey;
878
#endif
879
		size_t len;
880
881
		len = sizeof(success);
882
		if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
883
		    RADIUS_VTYPE_MS_CHAP2_SUCCESS, &success, &len) != 0) {
884
			chap_log(_this, LOG_ERR, "no ms_chap2_success");
885
			goto auth_failed;
886
		}
887
#ifdef	USE_NPPPD_MPPE
888
		if (_this->ppp->mppe.enabled != 0) {
889
			len = sizeof(sendkey);
890
			if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
891
			    RADIUS_VTYPE_MPPE_SEND_KEY, &sendkey, &len) != 0) {
892
				chap_log(_this, LOG_ERR, "no mppe_send_key");
893
				goto auth_failed;
894
			}
895
			len = sizeof(recvkey);
896
			if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT,
897
			    RADIUS_VTYPE_MPPE_RECV_KEY, &recvkey, &len) != 0) {
898
				chap_log(_this, LOG_ERR, "no mppe_recv_key");
899
				goto auth_failed;
900
			}
901
902
			mschap_radiuskey(_this->ppp->mppe.send.master_key,
903
			    sendkey.salt, _this->authenticator, secret);
904
905
			mschap_radiuskey(_this->ppp->mppe.recv.master_key,
906
			    recvkey.salt, _this->authenticator, secret);
907
		}
908
#endif
909
		chap_response(_this, 1, success.str, sizeof(success.str));
910
		break;
911
	    }
912
	}
913
	ppp_process_radius_framed_ip(_this->ppp, pkt);
914
915
	return;
916
auth_failed:
917
	chap_log(_this, LOG_WARNING, "Radius authentication request failed: %s",
918
	    reason);
919
	/* log reply messages from radius server */
920
	if (pkt != NULL) {
921
		char radmsg[255], vissed[1024];
922
		size_t rmlen = 0;
923
		if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE,
924
		    radmsg, &rmlen)) == 0) {
925
			if (rmlen != 0) {
926
				strvisx(vissed, radmsg, rmlen, VIS_WHITE);
927
				chap_log(_this, LOG_WARNING,
928
				    "Radius reply message: %s", vissed);
929
			}
930
		}
931
	}
932
933
	/* No extra information */
934
	chap_failure(_this, "FAILED", errorCode);
935
}
936
937
#endif
938
939
/************************************************************************
940
 * Miscellaneous functions
941
 ************************************************************************/
942
static char *
943
strip_nt_domain(char *username)
944
{
945
	char *lastbackslash;
946
947
	if ((lastbackslash = strrchr(username, '\\')) != NULL)
948
		return lastbackslash + 1;
949
950
	return username;
951
}
952
953
static void
954
chap_log(chap *_this, uint32_t prio, const char *fmt, ...)
955
{
956
	const char *protostr;
957
	char logbuf[BUFSIZ];
958
	va_list ap;
959
960
	CHAP_ASSERT(_this != NULL);
961
	CHAP_ASSERT(_this->ppp != NULL);
962
963
	switch (_this->type) {
964
	case PPP_AUTH_CHAP_MD5:
965
		protostr = "chap";
966
		break;
967
	case PPP_AUTH_CHAP_MS_V2:
968
		protostr = "mschap_v2";
969
		break;
970
	default:
971
		protostr = "unknown";
972
		break;
973
	}
974
975
	va_start(ap, fmt);
976
	snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=chap proto=%s %s",
977
	    _this->ppp->id, protostr, fmt);
978
	vlog_printf(prio, logbuf, ap);
979
	va_end(ap);
980
}