1/*	$OpenBSD: pap.c,v 1.13 2024/02/26 08:47:28 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.13 2024/02/26 08:47:28 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
89static void  pap_log (pap *, uint32_t, const char *, ...) __printflike(3,4);
90static void  pap_response (pap *, int, const char *);
91static void  pap_authenticate(pap *, const char *);
92static void  pap_local_authenticate (pap *, const char *, const char *);
93#ifdef USE_NPPPD_RADIUS
94static void  pap_radius_authenticate (pap *, const char *, const char *);
95static void  pap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
96#endif
97
98#ifdef __cplusplus
99extern "C" {
100#endif
101
102void  pap_init (pap *, npppd_ppp *);
103int   pap_start (pap *);
104int   pap_stop (pap *);
105int   pap_input (pap *, u_char *, int);
106
107#ifdef __cplusplus
108}
109#endif
110
111void
112pap_init(pap *_this, npppd_ppp *ppp)
113{
114	_this->ppp = ppp;
115	_this->state = PAP_STATE_INITIAL;
116	_this->auth_id = -1;
117}
118
119int
120pap_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
134int
135pap_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 */
150int
151pap_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;
232fail:
233	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
234	return -1;
235}
236
237static void
238pap_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	}
261fail:
262	pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
263}
264
265static void
266pap_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
278static void
279pap_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
329static void
330pap_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 ***********************************************************************/
350int
351pap_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
383static void
384pap_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;
460fail:
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
469static void
470pap_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_framed_ip(_this->ppp, pkt);
512
513	return;
514auth_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