1/*	$OpenBSD: npppd_auth.c,v 1.23 2024/02/26 10:42:05 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 authentication realm */
29/* $Id: npppd_auth.c,v 1.23 2024/02/26 10:42:05 yasuoka Exp $ */
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34#include <net/if_dl.h>
35#include <arpa/inet.h>
36#include <stdio.h>
37#include <syslog.h>
38#include <string.h>
39#include <time.h>
40#include <event.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <netdb.h>
44#include <errno.h>
45
46#include "debugutil.h"
47#include "npppd_local.h"
48#include "npppd_auth.h"
49#include "net_utils.h"
50
51#include "npppd_auth_local.h"
52#include "npppd_radius.h"
53
54/**
55 * Create a npppd_auth_base object.
56 * @param auth_type	the authentication type.
57 *	specify {@link ::NPPPD_AUTH_TYPE_LOCAL} to authenticate by the local
58 *	file, or specify {@link ::NPPPD_AUTH_TYPE_RADIUS} for RADIUS
59 *	authentication.
60 * @param name		the configuration name
61 * @param _npppd	the parent {@link ::npppd} object
62 * @see	::NPPPD_AUTH_TYPE_LOCAL
63 * @see	::NPPPD_AUTH_TYPE_RADIUS
64 * @return The pointer to the {@link ::npppd_auth_base} object will be returned
65 * in case success otherwise NULL will be returned.
66 */
67npppd_auth_base *
68npppd_auth_create(int auth_type, const char *name, void *_npppd)
69{
70	npppd_auth_base *base;
71
72	NPPPD_AUTH_ASSERT(name != NULL);
73
74	switch (auth_type) {
75	case NPPPD_AUTH_TYPE_LOCAL:
76		if ((base = calloc(1, sizeof(npppd_auth_local))) != NULL) {
77			base->type = NPPPD_AUTH_TYPE_LOCAL;
78			strlcpy(base->name, name, sizeof(base->name));
79			base->npppd = _npppd;
80
81			return base;
82		}
83		break;
84
85#ifdef USE_NPPPD_RADIUS
86	case NPPPD_AUTH_TYPE_RADIUS:
87		if ((base = calloc(1, sizeof(npppd_auth_radius))) != NULL) {
88			npppd_auth_radius *_this = (npppd_auth_radius *)base;
89			base->type = NPPPD_AUTH_TYPE_RADIUS;
90			strlcpy(base->name, name, sizeof(base->name));
91			base->npppd = _npppd;
92			if ((_this->rad_auth_setting =
93			    radius_req_setting_create()) == NULL)
94				goto radius_fail;
95			if ((_this->rad_acct_setting =
96			    radius_req_setting_create()) == NULL)
97				goto radius_fail;
98
99			return base;
100radius_fail:
101			if (_this->rad_auth_setting != NULL)
102				radius_req_setting_destroy(
103				    _this->rad_auth_setting);
104			if (_this->rad_acct_setting != NULL)
105				radius_req_setting_destroy(
106				    _this->rad_acct_setting);
107			free(base);
108			return NULL;
109		}
110
111		break;
112#endif
113
114	default:
115		NPPPD_AUTH_ASSERT(0);
116		break;
117	}
118
119	return NULL;
120}
121
122/**
123 * Call this function to make the object unusable.
124 * <p>
125 * {@link ::npppd_auth_base} objects is referred by the {@link ::npppd_ppp}
126 * object.   After this function is called, npppd will disconnect the PPP
127 * links that refers the object, it will call {@link ::npppd_auth_destroy()}
128 * when all the references to the object are released.</p>
129 */
130void
131npppd_auth_dispose(npppd_auth_base *base)
132{
133
134	base->disposing = 1;
135
136	return;
137}
138
139/** Destroy the {@link ::npppd_auth_base} object.  */
140void
141npppd_auth_destroy(npppd_auth_base *base)
142{
143
144	if (base->disposing == 0)
145		npppd_auth_dispose(base);
146
147	npppd_auth_base_log(base, LOG_INFO, "Finalized");
148
149	switch(base->type) {
150	case NPPPD_AUTH_TYPE_LOCAL:
151		memset(base, 0, sizeof(npppd_auth_local));
152		break;
153
154#ifdef USE_NPPPD_RADIUS
155	case NPPPD_AUTH_TYPE_RADIUS:
156	    {
157		npppd_auth_radius *_this = (npppd_auth_radius *)base;
158		if (_this->rad_auth_setting != NULL)
159			radius_req_setting_destroy(_this->rad_auth_setting);
160		_this->rad_auth_setting = NULL;
161		if (_this->rad_acct_setting != NULL)
162			radius_req_setting_destroy(_this->rad_acct_setting);
163		_this->rad_acct_setting = NULL;
164		memset(base, 0, sizeof(npppd_auth_local));
165		break;
166	    }
167#endif
168	}
169	free(base);
170
171	return;
172}
173
174/** Reload the configuration */
175int
176npppd_auth_reload(npppd_auth_base *base)
177{
178	struct authconf *auth;
179
180	TAILQ_FOREACH(auth, &base->npppd->conf.authconfs, entry) {
181		if (strcmp(auth->name, base->name) == 0)
182			break;
183	}
184	if (auth == NULL)
185		return 1;
186
187	base->pppsuffix[0] = '\0';
188	if (auth->username_suffix != NULL)
189		strlcpy(base->pppsuffix, auth->username_suffix,
190		    sizeof(base->pppsuffix));
191	base->eap_capable = auth->eap_capable;
192	base->strip_nt_domain = auth->strip_nt_domain;
193	base->strip_atmark_realm = auth->strip_atmark_realm;
194	base->has_users_file = 0;
195	base->radius_ready = 0;
196	base->user_max_session = auth->user_max_session;
197
198	if (strlen(auth->users_file_path) > 0) {
199		strlcpy(base->users_file_path, auth->users_file_path,
200		    sizeof(base->users_file_path));
201		base->has_users_file = 1;
202	} else {
203		if (base->type == NPPPD_AUTH_TYPE_LOCAL) {
204			npppd_auth_base_log(base,
205			    LOG_WARNING, "missing users_file property.");
206			goto fail;
207		}
208	}
209
210	switch (base->type) {
211#ifdef USE_NPPPD_RADIUS
212	case NPPPD_AUTH_TYPE_RADIUS:
213		if (npppd_auth_radius_reload(base, auth) != 0)
214			goto fail;
215		break;
216#endif
217	}
218	base->initialized = 1;
219
220	return 0;
221
222fail:
223	base->initialized = 0;
224	base->has_users_file = 0;
225	base->radius_ready = 0;
226
227	return 1;
228}
229
230/**
231 * This function gets specified user's password. The value 0 is returned
232 * if the call succeeds.
233 *
234 * @param	username	username which gets the password
235 * @param	password	buffers which stores the password
236 *				Specify NULL if you want to known the length of
237 *				the password only.
238 * @param	lppassword	pointer which indicates the length of
239 *				the buffer which stores the password.
240 * @return A value 1 is returned if user is unknown. A value 2 is returned
241 *				if password buffer is sufficient. A negative value is
242 *				returned if other error occurred.
243 */
244int
245npppd_auth_get_user_password(npppd_auth_base *base,
246    const char *username, char *password, int *plpassword)
247{
248	int              retval, sz, lpassword;
249	npppd_auth_user *user;
250
251	NPPPD_AUTH_ASSERT(base != NULL);
252	NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username));
253
254	user = NULL;
255	retval = 0;
256	if (base->has_users_file == 0) {
257		retval = -1;
258		goto out;
259	}
260	if ((user = npppd_auth_get_user(base, username)) == NULL) {
261		retval = 1;
262		goto out;
263	}
264	if (password == NULL && plpassword == NULL) {
265		retval = 0;
266		goto out;
267	}
268	if (plpassword == NULL) {
269		retval = -1;
270		goto out;
271	}
272	lpassword = strlen(user->password) + 1;
273	sz = *plpassword;
274	*plpassword = lpassword;
275	if (password == NULL) {
276		retval = 0;
277		goto out;
278	}
279	if (sz < lpassword) {
280		retval = 2;
281		goto out;
282	}
283	strlcpy(password, user->password, sz);
284out:
285	free(user);
286
287	return retval;
288}
289
290/**
291 * This function gets specified users' Framed-IP-{Address,Netmask}.
292 * The value 0 is returned if the call succeeds.
293 * <p>
294 * Because authentication database is updated at any time, the password is
295 * possible to be inconsistent if this function is not called immediately
296 * after authentication. So this function is called immediately after
297 * authentication. </p>
298 * @param	username	username which gets the password
299 * @param	ip4address	pointer which indicates struct in_addr which
300 *						stores the Framed-IP-Address
301 * @param	ip4netmask	pointer which indicates struct in_addr which
302 *						stores Framed-IP-Netmask
303 */
304int
305npppd_auth_get_framed_ip(npppd_auth_base *base, const char *username,
306    struct in_addr *ip4address, struct in_addr *ip4netmask)
307{
308	npppd_auth_user *user;
309
310	NPPPD_AUTH_ASSERT(base != NULL);
311	NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username));
312	if (base->has_users_file == 0)
313		return -1;
314
315	if ((user = npppd_auth_get_user(base, username)) == NULL)
316		return 1;
317
318	if (user->framed_ip_address.s_addr != 0) {
319		*ip4address = user->framed_ip_address;
320		if (ip4netmask != NULL)
321			*ip4netmask = user->framed_ip_netmask;
322
323		free(user);
324		return 0;
325	}
326	free(user);
327
328	return 1;
329}
330
331/**
332 * Retribute "Calling-Number" attribute of the user from the realm.
333 *
334 * @param username	Username.
335 * @param number	Pointer to the space for the Calling-Number.  This
336 *	can be NULL in case retributing the Calling-Number only.
337 * @param plnumber	Pointer to the length of the space for the
338 *	Calling-Number.
339 * @return 0 if the Calling-Number attribute is successfully retributed.
340 *	1 if the user has no Calling-Number attribute.  return -1 if the realm
341 *	doesn't have user attributes or other errors.   return 2 if the space
342 *	is not enough.
343 */
344int
345npppd_auth_get_calling_number(npppd_auth_base *base, const char *username,
346    char *number, int *plnumber)
347{
348	int              retval, lcallnum, sz;
349	npppd_auth_user *user;
350
351	user = NULL;
352	retval = 0;
353	if (base->has_users_file == 0)
354		return -1;
355
356	if ((user = npppd_auth_get_user(base, username)) == NULL)
357		return 1;
358
359	if (number == NULL && plnumber == NULL) {
360		retval = 0;
361		goto out;
362	}
363	if (plnumber == NULL) {
364		retval = -1;
365		goto out;
366	}
367	lcallnum = strlen(user->calling_number) + 1;
368	sz = *plnumber;
369	*plnumber = lcallnum;
370	if (sz < lcallnum) {
371		retval = 2;
372		goto out;
373	}
374	strlcpy(number, user->calling_number, sz);
375
376out:
377	free(user);
378
379	return retval;
380}
381
382int
383npppd_auth_get_type(npppd_auth_base *base)
384{
385	return base->type;
386}
387
388int
389npppd_auth_is_usable(npppd_auth_base *base)
390{
391    	return (base->initialized != 0 && base->disposing == 0)? 1 : 0;
392}
393
394int
395npppd_auth_is_ready(npppd_auth_base *base)
396{
397	if (!npppd_auth_is_usable(base))
398		return 0;
399
400	switch(base->type) {
401	case NPPPD_AUTH_TYPE_LOCAL:
402		return (base->has_users_file)? 1 : 0;
403		/* NOTREACHED */
404
405	case NPPPD_AUTH_TYPE_RADIUS:
406		return (base->has_users_file != 0 ||
407		    base->radius_ready != 0)? 1 : 0;
408		/* NOTREACHED */
409	}
410	NPPPD_AUTH_ASSERT(0);
411
412    	return 0;
413}
414
415int
416npppd_auth_is_disposing(npppd_auth_base *base)
417{
418	return (base->disposing != 0)? 1 : 0;
419}
420
421int
422npppd_auth_is_eap_capable(npppd_auth_base *base)
423{
424	return (base->eap_capable != 0)? 1 : 0;
425}
426
427const char *
428npppd_auth_get_name(npppd_auth_base *base)
429{
430	return base->name;
431}
432
433const char *
434npppd_auth_get_suffix(npppd_auth_base *base)
435{
436	return base->pppsuffix;
437}
438
439const char *
440npppd_auth_username_for_auth(npppd_auth_base *base, const char *username,
441    char *username_buffer)
442{
443	const char *u0;
444	char *atmark, *u1;
445
446	u0 = NULL;
447	if (base->strip_nt_domain != 0) {
448		if ((u0 = strchr(username, '\\')) != NULL)
449			u0++;
450	}
451	if (u0 == NULL)
452		u0 = username;
453	u1 = username_buffer;
454	if (username_buffer != u0)
455		memmove(username_buffer, u0, MINIMUM(strlen(u0) + 1,
456		    MAX_USERNAME_LENGTH));
457	if (base->strip_atmark_realm != 0) {
458		if ((atmark = strrchr(u1, '@')) != NULL)
459			*atmark = '\0';
460	}
461
462	return username_buffer;
463}
464
465int
466npppd_auth_user_session_unlimited(npppd_auth_base *_this)
467{
468	return (_this->user_max_session == 0) ? 1 : 0;
469}
470
471int
472npppd_check_auth_user_max_session(npppd_auth_base *_this, int count)
473{
474	if (!npppd_auth_user_session_unlimited(_this) &&
475	    _this->user_max_session <= count)
476		return 1;
477	else
478		return 0;
479}
480
481/***********************************************************************
482 * Account list related functions
483 ***********************************************************************/
484static npppd_auth_user *
485npppd_auth_get_user(npppd_auth_base *base, const char *username)
486{
487	int              lsuffix, lusername;
488	const char      *un;
489	char             buf[MAX_USERNAME_LENGTH];
490	npppd_auth_user *u;
491
492	un = username;
493	lsuffix = strlen(base->pppsuffix);
494	lusername = strlen(username);
495	if (lsuffix > 0 && lusername > lsuffix &&
496	    strcmp(username + lusername - lsuffix, base->pppsuffix) == 0 &&
497	    lusername - lsuffix < sizeof(buf)) {
498		memcpy(buf, username, lusername - lsuffix);
499		buf[lusername - lsuffix] = '\0';
500		un = buf;
501	}
502
503	if (priv_get_user_info(base->users_file_path, un, &u) == 0)
504		return u;
505
506	return NULL;
507}
508
509#ifdef USE_NPPPD_RADIUS
510/***********************************************************************
511 * RADIUS
512 ***********************************************************************/
513/** reload the configuration of RADIUS authentication realm */
514static int
515npppd_auth_radius_reload(npppd_auth_base *base, struct authconf *auth)
516{
517	npppd_auth_radius  *_this = (npppd_auth_radius *)base;
518	radius_req_setting *rad;
519	struct radserver   *server;
520	int                 i, nauth, nacct;
521
522	_this->rad_auth_setting->timeout =
523	    (auth->data.radius.auth.timeout == 0)
524		    ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.auth.timeout;
525	_this->rad_acct_setting->timeout =
526	    (auth->data.radius.acct.timeout == 0)
527		    ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.acct.timeout;
528
529
530	_this->rad_auth_setting->max_tries =
531	    (auth->data.radius.auth.max_tries == 0)
532		    ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.auth.max_tries;
533	_this->rad_acct_setting->max_tries =
534	    (auth->data.radius.acct.max_tries == 0)
535		    ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.acct.max_tries;
536
537	_this->rad_auth_setting->max_failovers =
538	    (auth->data.radius.auth.max_failovers == 0)
539		    ? DEFAULT_RADIUS_MAX_FAILOVERS
540		    : auth->data.radius.auth.max_failovers;
541	_this->rad_acct_setting->max_failovers =
542	    (auth->data.radius.acct.max_failovers == 0)
543		    ? DEFAULT_RADIUS_MAX_FAILOVERS
544		    : auth->data.radius.acct.max_failovers;
545
546	_this->rad_acct_setting->curr_server =
547	_this->rad_auth_setting->curr_server = 0;
548
549	/* load configs for authentication server */
550	rad = _this->rad_auth_setting;
551	for (i = 0; i < countof(rad->server); i++)
552		memset(&rad->server[i], 0, sizeof(rad->server[0]));
553	i = 0;
554	TAILQ_FOREACH(server, &auth->data.radius.auth.servers, entry) {
555		if (i >= countof(rad->server))
556			break;
557		memcpy(&rad->server[i].peer, &server->address,
558		    server->address.ss_len);
559		if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port
560		    == 0)
561			((struct sockaddr_in *)&rad->server[i].peer)->sin_port
562			    = htons(DEFAULT_RADIUS_AUTH_PORT);
563		strlcpy(rad->server[i].secret, server->secret,
564		    sizeof(rad->server[i].secret));
565		rad->server[i].enabled = 1;
566		i++;
567	}
568	nauth = i;
569
570	/* load configs for accounting server */
571	rad = _this->rad_acct_setting;
572	for (i = 0; i < countof(rad->server); i++)
573		memset(&rad->server[i], 0, sizeof(rad->server[0]));
574	i = 0;
575	TAILQ_FOREACH(server, &auth->data.radius.acct.servers, entry) {
576		if (i >= countof(rad->server))
577			break;
578		memcpy(&rad->server[i].peer, &server->address,
579		    server->address.ss_len);
580		if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port
581		    == 0)
582			((struct sockaddr_in *)&rad->server[i].peer)->sin_port
583			    = htons(DEFAULT_RADIUS_ACCT_PORT);
584		strlcpy(rad->server[i].secret, server->secret,
585		    sizeof(rad->server[i].secret));
586		rad->server[i].enabled = 1;
587		i++;
588	}
589	nacct = i;
590
591	for (i = 0; i < countof(_this->rad_auth_setting->server); i++) {
592		if (_this->rad_auth_setting->server[i].enabled)
593			base->radius_ready = 1;
594	}
595
596	npppd_auth_base_log(&_this->nar_base, LOG_INFO,
597	    "Loaded configuration.  %d authentication server%s, %d accounting "
598	    "server%s.",
599	    nauth, (nauth > 1)? "s" : "", nacct, (nacct > 1)? "s" : "");
600
601	if (nacct > 0 && _this->rad_acct_on == 0) {
602		radius_acct_on(base->npppd, _this->rad_acct_setting);
603		_this->rad_acct_on = 1;
604	}
605
606	return 0;
607}
608
609/**
610 * Get {@link ::radius_req_setting} for RADIUS authentication of specified
611 * {@link ::npppd_auth_base} object.
612 */
613void *
614npppd_auth_radius_get_radius_auth_setting(npppd_auth_radius *_this)
615{
616	return _this->rad_auth_setting;
617}
618
619/**
620 * Get {@link ::radius_req_setting} for RADIUS accounting of specified
621 * {@link ::npppd_auth_base} object.
622 */
623void *
624npppd_auth_radius_get_radius_acct_setting(npppd_auth_radius *_this)
625{
626	return _this->rad_acct_setting;
627}
628
629#endif
630
631/***********************************************************************
632 * Helper functions
633 ***********************************************************************/
634/** Log it which starts the label based on this instance. */
635static int
636npppd_auth_base_log(npppd_auth_base *_this, int prio, const char *fmt, ...)
637{
638	int status;
639	char logbuf[BUFSIZ];
640	va_list ap;
641
642	NPPPD_AUTH_ASSERT(_this != NULL);
643	va_start(ap, fmt);
644	snprintf(logbuf, sizeof(logbuf), "realm name=%s %s",
645	    _this->name, fmt);
646	status = vlog_printf(prio, logbuf, ap);
647	va_end(ap);
648
649	return status;
650}
651