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