xref: /openbsd/usr.sbin/npppd/npppd/pap.c (revision a168fdd3)
1 /*	$OpenBSD: pap.c,v 1.14 2024/07/01 07:09:07 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 /* $Id: pap.c,v 1.14 2024/07/01 07:09:07 yasuoka Exp $ */
29 /**@file
30  * This file provides Password Authentication Protocol (PAP) handlers.
31  * @author Yasuoka Masahiko
32  */
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <net/if_dl.h>
37 #include <netinet/in.h>
38 
39 #include <event.h>
40 #include <md5.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <errno.h>
47 #include <vis.h>
48 
49 #include "npppd.h"
50 #include "ppp.h"
51 
52 #ifdef USE_NPPPD_RADIUS
53 #include <radius.h>
54 #include "radius_chap_const.h"
55 #include "npppd_radius.h"
56 #endif
57 
58 #include "debugutil.h"
59 
60 #define	AUTHREQ				0x01
61 #define	AUTHACK				0x02
62 #define	AUTHNAK				0x03
63 
64 #define	PAP_STATE_INITIAL		0
65 #define	PAP_STATE_STARTING		1
66 #define	PAP_STATE_AUTHENTICATING	2
67 #define	PAP_STATE_SENT_RESPONSE		3
68 #define	PAP_STATE_STOPPED		4
69 #define	PAP_STATE_PROXY_AUTHENTICATION	5
70 
71 #define	DEFAULT_SUCCESS_MESSAGE		"OK"
72 #define	DEFAULT_FAILURE_MESSAGE		"Unknown username or password"
73 #define	DEFAULT_ERROR_MESSAGE		"Unknown failure"
74 
75 #ifdef	PAP_DEBUG
76 #define	PAP_DBG(x)	pap_log x
77 #define	PAP_ASSERT(cond)					\
78 	if (!(cond)) {						\
79 	    fprintf(stderr,					\
80 		"\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
81 		, __func__, __FILE__, __LINE__);		\
82 	    abort(); 						\
83 	}
84 #else
85 #define	PAP_ASSERT(cond)
86 #define	PAP_DBG(x)
87 #endif
88 
89 static void  pap_log (pap *, uint32_t, const char *, ...) __printflike(3,4);
90 static void  pap_response (pap *, int, const char *);
91 static void  pap_authenticate(pap *, const char *);
92 static void  pap_local_authenticate (pap *, const char *, const char *);
93 #ifdef USE_NPPPD_RADIUS
94 static void  pap_radius_authenticate (pap *, const char *, const char *);
95 static void  pap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
96 #endif
97 
98 #ifdef __cplusplus
99 extern "C" {
100 #endif
101 
102 void  pap_init (pap *, npppd_ppp *);
103 int   pap_start (pap *);
104 int   pap_stop (pap *);
105 int   pap_input (pap *, u_char *, int);
106 
107 #ifdef __cplusplus
108 }
109 #endif
110 
111 void
pap_init(pap * _this,npppd_ppp * ppp)112 pap_init(pap *_this, npppd_ppp *ppp)
113 {
114 	_this->ppp = ppp;
115 	_this->state = PAP_STATE_INITIAL;
116 	_this->auth_id = -1;
117 }
118 
119 int
pap_start(pap * _this)120 pap_start(pap *_this)
121 {
122 	pap_log(_this, LOG_DEBUG, "%s", __func__);
123 
124 	if (_this->state == PAP_STATE_PROXY_AUTHENTICATION) {
125 		_this->state = PAP_STATE_AUTHENTICATING;
126 		pap_authenticate(_this, _this->ppp->proxy_authen_resp);
127 		return 0;
128 	}
129 
130 	_this->state = PAP_STATE_STARTING;
131 	return 0;
132 }
133 
134 int
pap_stop(pap * _this)135 pap_stop(pap *_this)
136 {
137 	_this->state = PAP_STATE_STOPPED;
138 	_this->auth_id = -1;
139 
140 #ifdef USE_NPPPD_RADIUS
141 	if (_this->radctx != NULL) {
142 		radius_cancel_request(_this->radctx);
143 		_this->radctx = NULL;
144 	}
145 #endif
146 	return 0;
147 }
148 
149 /** Receiving PAP packet */
150 int
pap_input(pap * _this,u_char * pktp,int lpktp)151 pap_input(pap *_this, u_char *pktp, int lpktp)
152 {
153 	int code, id, length, len;
154 	u_char *pktp1;
155 	char name[MAX_USERNAME_LENGTH], password[MAX_PASSWORD_LENGTH];
156 
157 	if (_this->state == PAP_STATE_STOPPED ||
158 	    _this->state == PAP_STATE_INITIAL) {
159 		pap_log(_this, LOG_ERR, "Received pap packet.  But pap is "
160 		    "not started.");
161 		return -1;
162 	}
163 	pktp1 = pktp;
164 
165 	GETCHAR(code, pktp1);
166 	GETCHAR(id, pktp1);
167 	GETSHORT(length, pktp1);
168 
169 	if (code != AUTHREQ) {
170 		pap_log(_this, LOG_ERR, "%s: Received unknown code=%d",
171 		    __func__, code);
172 		return -1;
173 	}
174 	if (lpktp < length) {
175 		pap_log(_this, LOG_ERR, "%s: Received broken packet.",
176 		    __func__);
177 		return -1;
178 	}
179 
180 	/* retribute the username */
181 #define	remlen		(lpktp - (pktp1 - pktp))
182 	if (remlen < 1)
183 		goto fail;
184 	GETCHAR(len, pktp1);
185 	if (len <= 0)
186 		goto fail;
187 	if (remlen < len)
188 		goto fail;
189 	if (len > 0)
190 		memcpy(name, pktp1, len);
191 	name[len] = '\0';
192 	pktp1 += len;
193 
194 	if (_this->state != PAP_STATE_STARTING) {
195 		/*
196 		 * Receiving identical message again, it must be the message
197 		 * retransmit by the peer.  Continue if the username is same.
198 		 */
199 		if ((_this->state == PAP_STATE_AUTHENTICATING ||
200 		    _this->state == PAP_STATE_SENT_RESPONSE) &&
201 		    strcmp(_this->name, name) == 0) {
202 			/* continue */
203 		} else {
204 			pap_log(_this, LOG_ERR,
205 			    "Received AuthReq is not same as before.  "
206 			    "(%d,%s) != (%d,%s)", id, name, _this->auth_id,
207 			    _this->name);
208 			_this->auth_id = id;
209 			goto fail;
210 		}
211 	}
212 	if (_this->state == PAP_STATE_AUTHENTICATING)
213 		return 0;
214 	_this->auth_id = id;
215 	strlcpy(_this->name, name, sizeof(_this->name));
216 
217 	_this->state = PAP_STATE_AUTHENTICATING;
218 
219 	/* retribute the password */
220 	if (remlen < 1)
221 		goto fail;
222 	GETCHAR(len, pktp1);
223 	if (remlen < len)
224 		goto fail;
225 	if (len > 0)
226 		memcpy(password, pktp1, len);
227 
228 	password[len] = '\0';
229 	pap_authenticate(_this, password);
230 
231 	return 0;
232 fail:
233 	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
234 	return -1;
235 }
236 
237 static void
pap_authenticate(pap * _this,const char * password)238 pap_authenticate(pap *_this, const char *password)
239 {
240 	if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 0)
241 	    == 0) {
242 		if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) {
243 			pap_log(_this, LOG_INFO,
244 			    "username=\"%s\" realm is not ready.", _this->name);
245 			goto fail;
246 			/* NOTREACHED */
247 		}
248 #if USE_NPPPD_RADIUS
249 		if (npppd_ppp_is_realm_radius(_this->ppp->pppd, _this->ppp)) {
250 			pap_radius_authenticate(_this, _this->name, password);
251 			return;
252 			/* NOTREACHED */
253 		} else
254 #endif
255 		if (npppd_ppp_is_realm_local(_this->ppp->pppd, _this->ppp)) {
256 			pap_local_authenticate(_this, _this->name, password);
257 			return;
258 			/* NOTREACHED */
259 		}
260 	}
261 fail:
262 	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
263 }
264 
265 static void
pap_log(pap * _this,uint32_t prio,const char * fmt,...)266 pap_log(pap *_this, uint32_t prio, const char *fmt, ...)
267 {
268 	char logbuf[BUFSIZ];
269 	va_list ap;
270 
271 	va_start(ap, fmt);
272 	snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=pap %s",
273 	    _this->ppp->id, fmt);
274 	vlog_printf(prio, logbuf, ap);
275 	va_end(ap);
276 }
277 
278 static void
pap_response(pap * _this,int authok,const char * mes)279 pap_response(pap *_this, int authok, const char *mes)
280 {
281 	int lpktp, lmes;
282 	u_char *pktp, *pktp1;
283 	const char *realm;
284 
285 	pktp = ppp_packetbuf(_this->ppp, PPP_PROTO_PAP) + HEADERLEN;
286 	lpktp = _this->ppp->mru - HEADERLEN;
287 	realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp);
288 
289 	pktp1 = pktp;
290 	if (mes == NULL)
291 		lmes = 0;
292 	else
293 		lmes = strlen(mes);
294 	lmes = MINIMUM(lmes, lpktp - 1);
295 
296 	PUTCHAR(lmes, pktp1);
297 	if (lmes > 0)
298 		memcpy(pktp1, mes, lmes);
299 	lpktp = lmes + 1;
300 
301 	if (authok)
302 		ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHACK, _this->auth_id,
303 		    pktp, lpktp);
304 	else
305 		ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHNAK, _this->auth_id,
306 		    pktp, lpktp);
307 
308 	if (!authok) {
309 		pap_log(_this, LOG_ALERT,
310 		    "logtype=Failure username=\"%s\" realm=%s", _this->name,
311 		    realm);
312 		pap_stop(_this);
313 		ppp_set_disconnect_cause(_this->ppp,
314 		    PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL);
315 		ppp_stop(_this->ppp, "Authentication Required");
316 	} else {
317 		strlcpy(_this->ppp->username, _this->name,
318 		    sizeof(_this->ppp->username));
319 		pap_log(_this, LOG_INFO,
320 		    "logtype=Success username=\"%s\" realm=%s", _this->name,
321 		    realm);
322 		pap_stop(_this);
323 		ppp_auth_ok(_this->ppp);
324 		/* reset the state to response request of retransmision. */
325 		_this->state = PAP_STATE_SENT_RESPONSE;
326 	}
327 }
328 
329 static void
pap_local_authenticate(pap * _this,const char * username,const char * password)330 pap_local_authenticate(pap *_this, const char *username, const char *password)
331 {
332 	int lpassword0;
333 	char password0[MAX_PASSWORD_LENGTH];
334 
335 	lpassword0 = sizeof(password0);
336 
337 	if (npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
338 	    password0, &lpassword0) == 0) {
339 		if (!strcmp(password0, password)) {
340 			pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE);
341 			return;
342 		}
343 	}
344 	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
345 }
346 
347 /***********************************************************************
348  * Proxy Authentication
349  ***********************************************************************/
350 int
pap_proxy_authen_prepare(pap * _this,dialin_proxy_info * dpi)351 pap_proxy_authen_prepare(pap *_this, dialin_proxy_info *dpi)
352 {
353 
354 	PAP_ASSERT(dpi->auth_type == PPP_AUTH_PAP);
355 	PAP_ASSERT(_this->state == PAP_STATE_INITIAL);
356 
357 	_this->auth_id = dpi->auth_id;
358 	if (strlen(dpi->username) >= sizeof(_this->name)) {
359 		pap_log(_this, LOG_NOTICE,
360 		    "\"Proxy Authen Name\" is too long.");
361 		return -1;
362 	}
363 
364 	/* copy the authentication properties */
365 	PAP_ASSERT(_this->ppp->proxy_authen_resp == NULL);
366 	if ((_this->ppp->proxy_authen_resp = malloc(dpi->lauth_resp + 1)) ==
367 	    NULL) {
368 		pap_log(_this, LOG_ERR, "malloc() failed in %s(): %m",
369 		    __func__);
370 		return -1;
371 	}
372 	memcpy(_this->ppp->proxy_authen_resp, dpi->auth_resp,
373 	    dpi->lauth_resp);
374 	_this->ppp->proxy_authen_resp[dpi->lauth_resp] = '\0';
375 	strlcpy(_this->name, dpi->username, sizeof(_this->name));
376 
377 	_this->state = PAP_STATE_PROXY_AUTHENTICATION;
378 
379 	return 0;
380 }
381 
382 #ifdef USE_NPPPD_RADIUS
383 static void
pap_radius_authenticate(pap * _this,const char * username,const char * password)384 pap_radius_authenticate(pap *_this, const char *username, const char *password)
385 {
386 	void *radctx;
387 	RADIUS_PACKET *radpkt;
388 	MD5_CTX md5ctx;
389 	int i, j, s_len, passlen;
390 	u_char ra[16], digest[16], pass[128];
391 	const char *s;
392 	radius_req_setting *rad_setting = NULL;
393 	char buf0[MAX_USERNAME_LENGTH];
394 
395 	if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd,
396 	    _this->ppp)) == NULL)
397 		goto fail;
398 
399 	if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
400 	    == NULL)
401 		goto fail;
402 
403 	if (radius_prepare(rad_setting, _this, &radctx, pap_radius_response)
404 	    != 0) {
405 		radius_delete_packet(radpkt);
406 		goto fail;
407 	}
408 
409 	if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt)
410 	    != 0)
411 		goto fail;
412 
413 	if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
414 	    npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp,
415 	    username, buf0)) != 0)
416 		goto fail;
417 
418 	if (_this->radctx != NULL)
419 		radius_cancel_request(_this->radctx);
420 
421 	_this->radctx = radctx;
422 
423 	/* Create RADIUS User-Password Attribute (RFC 2865, 5.2.) */
424 	s = radius_get_server_secret(_this->radctx);
425 	s_len = strlen(s);
426 
427 	memset(pass, 0, sizeof(pass)); /* null padding */
428 	passlen = MINIMUM(strlen(password), sizeof(pass));
429 	memcpy(pass, password, passlen);
430 	if ((passlen % 16) != 0)
431 		passlen += 16 - (passlen % 16);
432 
433 	radius_get_authenticator(radpkt, ra);
434 
435 	MD5Init(&md5ctx);
436 	MD5Update(&md5ctx, s, s_len);
437 	MD5Update(&md5ctx, ra, 16);
438 	MD5Final(digest, &md5ctx);
439 
440 	for (i = 0; i < 16; i++)
441 		pass[i] ^= digest[i];
442 
443 	while (i < passlen) {
444 		MD5Init(&md5ctx);
445 		MD5Update(&md5ctx, s, s_len);
446 		MD5Update(&md5ctx, &pass[i - 16], 16);
447 		MD5Final(digest, &md5ctx);
448 
449 		for (j = 0; j < 16; j++, i++)
450 			pass[i] ^= digest[j];
451 	}
452 
453 	if (radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD, pass,
454 	    passlen) != 0)
455 		goto fail;
456 
457 	radius_request(_this->radctx, radpkt);
458 
459 	return;
460 fail:
461 	if (_this->radctx != NULL)
462 		radius_cancel_request(_this->radctx);
463 	pap_log(_this, LOG_ERR, "%s() failed: %m", __func__);
464 	pap_response(_this, 0, DEFAULT_ERROR_MESSAGE);
465 
466 	return;
467 }
468 
469 static void
pap_radius_response(void * context,RADIUS_PACKET * pkt,int flags,RADIUS_REQUEST_CTX reqctx)470 pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags,
471     RADIUS_REQUEST_CTX reqctx)
472 {
473 	int code = -1;
474 	const char *reason = NULL;
475 	RADIUS_REQUEST_CTX radctx;
476 	pap *_this;
477 
478 	_this = context;
479 	radctx = _this->radctx;
480 	_this->radctx = NULL;	/* important */
481 
482 	if (pkt == NULL) {
483 		if (flags & RADIUS_REQUEST_TIMEOUT)
484 			reason = "timeout";
485 		else if (flags & RADIUS_REQUEST_ERROR)
486 			reason = strerror(errno);
487 		else
488 			reason = "error";
489 		goto auth_failed;
490 	}
491 	code = radius_get_code(pkt);
492 	if (code == RADIUS_CODE_ACCESS_REJECT) {
493 		reason="reject";
494 		goto auth_failed;
495 	} else if (code != RADIUS_CODE_ACCESS_ACCEPT) {
496 		reason="error";
497 		goto auth_failed;
498 	}
499 	if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 &&
500 	    (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) {
501 		reason="bad_authenticator";
502 		goto auth_failed;
503 	}
504 	if ((flags & RADIUS_REQUEST_CHECK_MSG_AUTHENTICATOR_OK) == 0 &&
505 	    (flags & RADIUS_REQUEST_CHECK_NO_MSG_AUTHENTICATOR) == 0) {
506 		reason="bad_authenticator";
507 		goto auth_failed;
508 	}
509 	/* Authentication succeeded */
510 	pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE);
511 	ppp_process_radius_attrs(_this->ppp, pkt);
512 
513 	return;
514 auth_failed:
515 	/* Authentication failure */
516 	pap_log(_this, LOG_WARNING, "Radius authentication request failed: %s",
517 	    reason);
518 	/* log reply messages from radius server */
519 	if (pkt != NULL) {
520 		char radmsg[255], vissed[1024];
521 		size_t rmlen = 0;
522 		if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE,
523 		    radmsg, &rmlen)) == 0) {
524 			if (rmlen != 0) {
525 				strvisx(vissed, radmsg, rmlen, VIS_WHITE);
526 				pap_log(_this, LOG_WARNING,
527 				    "Radius reply message: %s", vissed);
528 			}
529 		}
530 	}
531 
532 	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
533 }
534 #endif
535