1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-03 06:45:37 -08:00

Add Dynamic Authorization Extensions (DAE) for RADIUS server feature

to npppd.  It can be configured now so that it accepts disconnect
requests and this works together with radiusd_ipcp(8) module.  Also
"nas-id" becomes configurable.
This commit is contained in:
yasuoka 2024-07-11 14:05:59 +00:00
parent 668a98a424
commit 9791a9c53b
8 changed files with 564 additions and 78 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: npppd.c,v 1.53 2022/07/01 09:57:24 mvs Exp $ */
/* $OpenBSD: npppd.c,v 1.54 2024/07/11 14:05:59 yasuoka Exp $ */
/*-
* Copyright (c) 2005-2008,2009 Internet Initiative Japan Inc.
@ -29,7 +29,7 @@
* Next pppd(nppd). This file provides a npppd daemon process and operations
* for npppd instance.
* @author Yasuoka Masahiko
* $Id: npppd.c,v 1.53 2022/07/01 09:57:24 mvs Exp $
* $Id: npppd.c,v 1.54 2024/07/11 14:05:59 yasuoka Exp $
*/
#include "version.h"
#include <sys/param.h> /* ALIGNED_POINTER */
@ -101,7 +101,6 @@ static void npppd_timer(int, short, void *);
static void npppd_auth_finalizer_periodic(npppd *);
static int rd2slist_walk (struct radish *, void *);
static int rd2slist (struct radish_head *, slist *);
static slist *npppd_get_ppp_by_user (npppd *, const char *);
static int npppd_get_all_users (npppd *, slist *);
static struct ipcpstat
*npppd_get_ipcp_stat(struct ipcpstat_head *, const char *);
@ -255,6 +254,7 @@ npppd_init(npppd *_this, const char *config_file)
_this->pid = getpid();
slist_init(&_this->realms);
npppd_conf_init(&_this->conf);
TAILQ_INIT(&_this->raddae_listens);
log_printf(LOG_NOTICE, "Starting npppd pid=%u version=%s",
_this->pid, VERSION);
@ -444,6 +444,10 @@ npppd_stop(npppd *_this)
_this->finalizing = 1;
npppd_reset_timer(_this);
#ifdef USE_NPPPD_RADIUS
npppd_radius_dae_fini(_this);
#endif
}
static void
@ -763,7 +767,7 @@ npppd_get_ppp_by_ip(npppd *_this, struct in_addr ipaddr)
* @return {@link slist} that contains the {@link npppd_ppp} instances.
* NULL may be returned if no instance has been found.
*/
static slist *
slist *
npppd_get_ppp_by_user(npppd *_this, const char *username)
{
hash_link *hl;

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: npppd.conf.5,v 1.34 2024/07/01 14:56:19 jmc Exp $
.\" $OpenBSD: npppd.conf.5,v 1.35 2024/07/11 14:05:59 yasuoka Exp $
.\"
.\" Copyright (c) 2012 YASUOKA Masahiko <yasuoka@openbsd.org>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 1 2024 $
.Dd $Mdocdate: July 11 2024 $
.Dt NPPPD.CONF 5
.Os
.Sh NAME
@ -41,6 +41,8 @@ Interface settings.
Authentication settings.
.It Sy Bind
Bind settings.
.It Sy RADIUS
RADIUS settings.
.El
.Sh GLOBAL
The global options are as follows:
@ -664,6 +666,32 @@ settings so that they are used together.
.Pp
.Ic bind tunnel from Ar tunnel Ic authenticated by Ar authentication
.Ic to Ar ifname
.Sh RADIUS
.Ic radius
configures the RADIUS features.
The supported options are as follows:
.Bl -tag -width Ds
.It Ic radius nas-id Ar identifier
Specify the
.Ar identifier
that is noticed to the RADIUS peers in the NAS-Identifier attribute.
.It Ic radius dae listen on Ar address Oo port Ar number Oc
Enable the Dynamic Authorization Extensions for RADIUS
.Po DAE, RFC 5176 Pc
server.
Specify the local
.Ar address
.Xr npppd 8
should listen on for the DAE requests.
Optionally specify a port
.Ar number ,
the default port number is 3799.
.It Ic radius dae client Ar address Ic secret Ar secret
Specify
.Ar address
for a DAE client and
.Ar secret .
.El
.Sh EXAMPLES
A very simple configuration example is below:
.Bd -literal -offset indent

View File

@ -1,4 +1,4 @@
/* $OpenBSD: npppd.h,v 1.20 2024/07/01 07:09:07 yasuoka Exp $ */
/* $OpenBSD: npppd.h,v 1.21 2024/07/11 14:05:59 yasuoka Exp $ */
/*-
* Copyright (c) 2009 Internet Initiative Japan Inc.
@ -43,6 +43,7 @@
#include "l2tp_conf.h"
#include "pptp_conf.h"
#include "pppoe_conf.h"
#include "slist.h"
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
@ -170,6 +171,25 @@ struct authconf {
} data;
};
struct radclientconf {
union {
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
} addr;
TAILQ_ENTRY(radclientconf) entry;
char secret[];
};
TAILQ_HEAD(radclientconfs,radclientconf);
struct radlistenconf {
union {
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
} addr;
TAILQ_ENTRY(radlistenconf) entry;
};
TAILQ_HEAD(radlistenconfs,radlistenconf);
struct ipcpconf {
TAILQ_ENTRY(ipcpconf) entry;
char name[NPPPD_GENERIC_NAME_LEN];
@ -207,6 +227,9 @@ struct npppd_conf {
TAILQ_HEAD(ipcpconfs, ipcpconf) ipcpconfs;
TAILQ_HEAD(ifaces, iface) ifaces;
TAILQ_HEAD(confbinds, confbind) confbinds;
struct radclientconfs raddaeclientconfs;
struct radlistenconfs raddaelistenconfs;
char nas_id[NPPPD_GENERIC_NAME_LEN];
struct l2tp_confs l2tp_confs;
struct pptp_confs pptp_confs;
struct pppoe_confs pppoe_confs;
@ -266,65 +289,70 @@ TAILQ_HEAD(ctl_conn_list, ctl_conn);
extern struct ctl_conn_list ctl_conns;
__BEGIN_DECLS
npppd *npppd_get_npppd (void);
int npppd_init (npppd *, const char *);
void npppd_start (npppd *);
void npppd_stop (npppd *);
void npppd_fini (npppd *);
int npppd_reset_routing_table (npppd *, int);
int npppd_get_user_password (npppd *, npppd_ppp *, const char *, char *, int *);
struct in_addr *npppd_get_user_framed_ip_address (npppd *, npppd_ppp *, const char *);
int npppd_check_calling_number (npppd *, npppd_ppp *);
npppd_ppp *npppd_get_ppp_by_ip (npppd *, struct in_addr);
npppd_ppp *npppd_get_ppp_by_id (npppd *, u_int);
int npppd_check_user_max_session (npppd *, npppd_ppp *);
void npppd_network_output (npppd *, npppd_ppp *, int, u_char *, int);
int npppd_ppp_pipex_enable (npppd *, npppd_ppp *);
int npppd_ppp_pipex_disable (npppd *, npppd_ppp *);
int npppd_prepare_ip (npppd *, npppd_ppp *);
void npppd_release_ip (npppd *, npppd_ppp *);
void npppd_set_ip_enabled (npppd *, npppd_ppp *, int);
int npppd_assign_ip_addr (npppd *, npppd_ppp *, uint32_t);
int npppd_set_radish (npppd *, void *);
int npppd_ppp_bind_realm (npppd *, npppd_ppp *, const char *, int);
int npppd_ppp_is_realm_local (npppd *, npppd_ppp *);
int npppd_ppp_is_realm_radius (npppd *, npppd_ppp *);
int npppd_ppp_is_realm_ready (npppd *, npppd_ppp *);
const char *npppd_ppp_get_realm_name (npppd *, npppd_ppp *);
const char *npppd_ppp_get_iface_name (npppd *, npppd_ppp *);
int npppd_ppp_iface_is_ready (npppd *, npppd_ppp *);
int npppd_ppp_bind_iface (npppd *, npppd_ppp *);
void npppd_ppp_unbind_iface (npppd *, npppd_ppp *);
void *npppd_get_radius_auth_setting (npppd *, npppd_ppp *);
int sockaddr_npppd_match (void *, void *);
const char *npppd_ppp_get_username_for_auth (npppd *, npppd_ppp *, const char *, char *);
const char *npppd_ppp_tunnel_protocol_name (npppd *, npppd_ppp *);
const char *npppd_tunnel_protocol_name (int);
struct tunnconf *npppd_get_tunnconf (npppd *, const char *);
int npppd_reload_config (npppd *);
int npppd_modules_reload (npppd *);
int npppd_ifaces_load_config (npppd *);
npppd *npppd_get_npppd(void);
int npppd_init(npppd *, const char *);
void npppd_start(npppd *);
void npppd_stop(npppd *);
void npppd_fini(npppd *);
int npppd_reset_routing_table(npppd *, int);
int npppd_get_user_password(npppd *, npppd_ppp *, const char *,
char *, int *);
struct in_addr *npppd_get_user_framed_ip_address(npppd *, npppd_ppp *,
const char *);
int npppd_check_calling_number(npppd *, npppd_ppp *);
npppd_ppp *npppd_get_ppp_by_ip(npppd *, struct in_addr);
npppd_ppp *npppd_get_ppp_by_id(npppd *, u_int);
slist *npppd_get_ppp_by_user(npppd *, const char *);
int npppd_check_user_max_session(npppd *, npppd_ppp *);
void npppd_network_output(npppd *, npppd_ppp *, int, u_char *, int);
int npppd_ppp_pipex_enable(npppd *, npppd_ppp *);
int npppd_ppp_pipex_disable(npppd *, npppd_ppp *);
int npppd_prepare_ip(npppd *, npppd_ppp *);
void npppd_release_ip(npppd *, npppd_ppp *);
void npppd_set_ip_enabled(npppd *, npppd_ppp *, int);
int npppd_assign_ip_addr(npppd *, npppd_ppp *, uint32_t);
int npppd_set_radish(npppd *, void *);
int npppd_ppp_bind_realm(npppd *, npppd_ppp *, const char *, int);
int npppd_ppp_is_realm_local(npppd *, npppd_ppp *);
int npppd_ppp_is_realm_radius(npppd *, npppd_ppp *);
int npppd_ppp_is_realm_ready(npppd *, npppd_ppp *);
const char *npppd_ppp_get_realm_name(npppd *, npppd_ppp *);
const char *npppd_ppp_get_iface_name(npppd *, npppd_ppp *);
int npppd_ppp_iface_is_ready(npppd *, npppd_ppp *);
int npppd_ppp_bind_iface(npppd *, npppd_ppp *);
void npppd_ppp_unbind_iface(npppd *, npppd_ppp *);
void *npppd_get_radius_auth_setting(npppd *, npppd_ppp *);
int sockaddr_npppd_match(void *, void *);
const char *npppd_ppp_get_username_for_auth(npppd *, npppd_ppp *,
const char *, char *);
const char *npppd_ppp_tunnel_protocol_name(npppd *, npppd_ppp *);
const char *npppd_tunnel_protocol_name(int);
struct tunnconf *npppd_get_tunnconf(npppd *, const char *);
int npppd_reload_config(npppd *);
int npppd_modules_reload(npppd *);
int npppd_ifaces_load_config(npppd *);
int npppd_conf_parse (struct npppd_conf *, const char *);
void npppd_conf_init (struct npppd_conf *);
void npppd_conf_fini (struct npppd_conf *);
int npppd_config_check (const char *);
void npppd_on_ppp_start (npppd *, npppd_ppp *);
void npppd_on_ppp_stop (npppd *, npppd_ppp *);
void imsg_event_add(struct imsgev *);
int npppd_conf_parse(struct npppd_conf *, const char *);
void npppd_conf_init(struct npppd_conf *);
void npppd_conf_fini(struct npppd_conf *);
int npppd_config_check(const char *);
void npppd_on_ppp_start(npppd *, npppd_ppp *);
void npppd_on_ppp_stop(npppd *, npppd_ppp *);
void imsg_event_add(struct imsgev *);
int control_init (struct control_sock *);
int control_listen (struct control_sock *);
void control_cleanup (struct control_sock *);
struct npppd_ctl *npppd_ctl_create (npppd *);
void npppd_ctl_destroy (struct npppd_ctl *);
int npppd_ctl_who (struct npppd_ctl *);
int npppd_ctl_monitor (struct npppd_ctl *);
int npppd_ctl_who_and_monitor (struct npppd_ctl *);
int npppd_ctl_add_started_ppp_id (struct npppd_ctl *, uint32_t);
int npppd_ctl_add_stopped_ppp (struct npppd_ctl *, npppd_ppp *);
int npppd_ctl_imsg_compose (struct npppd_ctl *, struct imsgbuf *);
int npppd_ctl_disconnect (struct npppd_ctl *, u_int *, int);
int control_init(struct control_sock *);
int control_listen(struct control_sock *);
void control_cleanup(struct control_sock *);
struct npppd_ctl
*npppd_ctl_create(npppd *);
void npppd_ctl_destroy(struct npppd_ctl *);
int npppd_ctl_who(struct npppd_ctl *);
int npppd_ctl_monitor(struct npppd_ctl *);
int npppd_ctl_who_and_monitor(struct npppd_ctl *);
int npppd_ctl_add_started_ppp_id(struct npppd_ctl *, uint32_t);
int npppd_ctl_add_stopped_ppp(struct npppd_ctl *, npppd_ppp *);
int npppd_ctl_imsg_compose(struct npppd_ctl *, struct imsgbuf *);
int npppd_ctl_disconnect(struct npppd_ctl *, u_int *, int);
__END_DECLS

View File

@ -1,4 +1,4 @@
/* $OpenBSD: npppd_config.c,v 1.14 2015/01/19 01:48:59 deraadt Exp $ */
/* $OpenBSD: npppd_config.c,v 1.15 2024/07/11 14:05:59 yasuoka Exp $ */
/*-
* Copyright (c) 2009 Internet Initiative Japan Inc.
@ -25,7 +25,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* $Id: npppd_config.c,v 1.14 2015/01/19 01:48:59 deraadt Exp $ */
/* $Id: npppd_config.c,v 1.15 2024/07/11 14:05:59 yasuoka Exp $ */
/*@file
* This file provides functions which operates configuration and so on.
*/
@ -131,6 +131,9 @@ npppd_modules_reload(npppd *_this)
#ifdef USE_NPPPD_PPPOE
rval |= pppoed_reload(&_this->pppoed, &_this->conf.pppoe_confs);
#endif
#ifdef USE_NPPPD_RADIUS
npppd_radius_dae_init(_this);
#endif
return rval;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: npppd_local.h,v 1.18 2024/02/26 08:29:37 yasuoka Exp $ */
/* $OpenBSD: npppd_local.h,v 1.19 2024/07/11 14:05:59 yasuoka Exp $ */
/*-
* Copyright (c) 2009 Internet Initiative Japan Inc.
@ -73,6 +73,10 @@
#include "npppd_pool.h"
#include "npppd_ctl.h"
#ifdef USE_NPPPD_RADIUS
#include "npppd_radius.h"
#endif
/** structure of pool */
struct _npppd_pool {
/** base of npppd structure */
@ -169,6 +173,10 @@ struct _npppd {
struct control_sock ctl_sock;
#ifdef USE_NPPPD_RADIUS
struct npppd_radius_dae_listens raddae_listens;
#endif
u_int /** whether finalizing or not */
finalizing:1,
/** whether finalize completed or not */

View File

@ -1,4 +1,4 @@
/* $Id: npppd_radius.c,v 1.11 2024/07/01 07:09:07 yasuoka Exp $ */
/* $Id: npppd_radius.c,v 1.12 2024/07/11 14:05:59 yasuoka Exp $ */
/*-
* Copyright (c) 2009 Internet Initiative Japan Inc.
* All rights reserved.
@ -45,18 +45,22 @@
#include <string.h>
#include <stdbool.h>
#include <radius.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <event.h>
#include "radius_req.h"
#include "npppd_local.h"
#include "npppd_radius.h"
#include "net_utils.h"
#ifdef NPPPD_RADIUS_DEBUG
#define NPPPD_RADIUS_DBG(x) ppp_log x
#define NPPPD_RADIUS_ASSERT(x) ASSERT(x)
#else
#define NPPPD_RADIUS_DBG(x)
#define NPPPD_RADIUS_DBG(x)
#define NPPPD_RADIUS_ASSERT(x)
#endif
@ -72,7 +76,7 @@ static void npppd_ppp_radius_acct_reqcb(void *, RADIUS_PACKET *, int, RADIUS_REQ
/**
* Retribute Framed-IP-Address and Framed-IP-Netmask attribute of from
* the given RADIUS packet and set them as the fields of ppp context.
*/
*/
void
ppp_process_radius_attrs(npppd_ppp *_this, RADIUS_PACKET *pkt)
{
@ -269,7 +273,7 @@ radius_acct_request(npppd *pppd, npppd_ppp *ppp, int stop)
/* npppd has no physical / virtual ports in design. */
/* RFC 2865 5.32. NAS-Identifier */
ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, "npppd");
ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, pppd->conf.nas_id);
/* RFC 2865 5.31. Calling-Station-Id */
if (ppp->calling_number[0] != '\0')
@ -398,7 +402,7 @@ radius_acct_on(npppd *pppd, radius_req_setting *rad_setting)
/* RFC 2866 5.1. Acct-Status-Type */
ATTR_INT32(RADIUS_TYPE_ACCT_STATUS_TYPE, RADIUS_ACCT_STATUS_TYPE_ACCT_ON);
/* RFC 2865 5.32. NAS-Identifier */
ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, "npppd");
ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, pppd->conf.nas_id);
/* Send the request */
radius_request(radctx, radpkt);
@ -562,3 +566,305 @@ ppp_set_radius_attrs_for_authreq(npppd_ppp *_this,
fail:
return 1;
}
/***********************************************************************
* Dynamic Authorization Extensions for RADIUS
***********************************************************************/
static int npppd_radius_dae_listen_start(struct npppd_radius_dae_listen *);
static void npppd_radius_dae_on_event(int, short, void *);
static void npppd_radius_dae_listen_stop(struct npppd_radius_dae_listen *);
void
npppd_radius_dae_init(npppd *_this)
{
struct npppd_radius_dae_listens listens;
struct npppd_radius_dae_listen *listen, *listent;
struct radlistenconf *listenconf;
TAILQ_INIT(&listens);
TAILQ_FOREACH(listenconf, &_this->conf.raddaelistenconfs, entry) {
TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry,
listent) {
if ((listen->addr.sin4.sin_family == AF_INET &&
listenconf->addr.sin4.sin_family == AF_INET &&
memcmp(&listen->addr.sin4, &listenconf->addr.sin4,
sizeof(struct sockaddr_in)) == 0) ||
(listen->addr.sin6.sin6_family == AF_INET6 &&
listenconf->addr.sin6.sin6_family == AF_INET6 &&
memcmp(&listen->addr.sin6, &listenconf->addr.sin6,
sizeof(struct sockaddr_in6)) == 0))
break;
}
if (listen != NULL)
/* keep using this */
TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
else {
if ((listen = calloc(1, sizeof(*listen))) == NULL) {
log_printf(LOG_ERR, "%s: calloc failed: %m",
__func__);
goto fail;
}
listen->pppd = _this;
listen->sock = -1;
if (listenconf->addr.sin4.sin_family == AF_INET)
listen->addr.sin4 = listenconf->addr.sin4;
else
listen->addr.sin6 = listenconf->addr.sin6;
}
TAILQ_INSERT_TAIL(&listens, listen, entry);
}
/* listen on the new addresses */
TAILQ_FOREACH(listen, &listens, entry) {
if (listen->sock == -1)
npppd_radius_dae_listen_start(listen);
}
/* stop listening on the old addresses */
TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry, listent) {
TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
npppd_radius_dae_listen_stop(listen);
free(listen);
}
fail:
TAILQ_CONCAT(&_this->raddae_listens, &listens, entry);
return;
}
void
npppd_radius_dae_fini(npppd *_this)
{
struct npppd_radius_dae_listen *listen, *listent;
TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry, listent) {
TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
npppd_radius_dae_listen_stop(listen);
free(listen);
}
}
int
npppd_radius_dae_listen_start(struct npppd_radius_dae_listen *listen)
{
char buf[80];
int sock = -1, on = 1;
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
log_printf(LOG_ERR, "%s: socket(): %m", __func__);
goto on_error;
}
on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
log_printf(LOG_WARNING, "%s: setsockopt(,,SO_REUSEADDR): %m",
__func__);
goto on_error;
}
if (bind(sock, (struct sockaddr *)&listen->addr,
listen->addr.sin4.sin_len) == -1) {
log_printf(LOG_ERR, "%s: bind(): %m", __func__);
goto on_error;
}
listen->sock = sock;
event_set(&listen->evsock, listen->sock, EV_READ | EV_PERSIST,
npppd_radius_dae_on_event, listen);
event_add(&listen->evsock, NULL);
log_printf(LOG_INFO, "radius Listening %s/udp (DAE)",
addrport_tostring((struct sockaddr *)&listen->addr,
listen->addr.sin4.sin_len, buf, sizeof(buf)));
return (0);
on_error:
if (sock >= 0)
close(sock);
return (-1);
}
void
npppd_radius_dae_on_event(int fd, short ev, void *ctx)
{
char buf[80], attr[256], username[256];
char *endp;
const char *reason, *nakcause = NULL;
struct npppd_radius_dae_listen *listen = ctx;
struct radclientconf *client;
npppd *_this = listen->pppd;
RADIUS_PACKET *req = NULL, *res = NULL;
struct sockaddr_storage ss;
socklen_t sslen;
unsigned long long ppp_id;
int code, n = 0;
uint32_t cause = 0;
struct in_addr ina;
slist *users;
npppd_ppp *ppp;
reason = "disconnect requested";
sslen = sizeof(ss);
req = radius_recvfrom(listen->sock, 0, (struct sockaddr *)&ss, &sslen);
if (req == NULL) {
log_printf(LOG_WARNING, "%s: receiving a RADIUS message "
"failed: %m", __func__);
return;
}
TAILQ_FOREACH(client, &_this->conf.raddaeclientconfs, entry) {
if (ss.ss_family == AF_INET &&
((struct sockaddr_in *)&ss)->sin_addr.s_addr ==
client->addr.sin4.sin_addr.s_addr)
break;
else if (ss.ss_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)&ss)->sin6_addr,
&client->addr.sin6.sin6_addr))
break;
}
if (client == NULL) {
log_printf(LOG_WARNING, "radius received a RADIUS message from "
"%s: unknown client", addrport_tostring(
(struct sockaddr *)&ss, ss.ss_len, buf, sizeof(buf)));
goto out;
}
if (radius_check_accounting_request_authenticator(req,
client->secret) != 0) {
log_printf(LOG_WARNING, "radius received an invalid RADIUS "
"message from %s: bad response authenticator",
addrport_tostring(
(struct sockaddr *)&ss, ss.ss_len, buf, sizeof(buf)));
goto out;
}
if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) {
/* Code other than Disconnect-Request is not supported */
if (code == RADIUS_CODE_COA_REQUEST) {
log_printf(LOG_INFO, "received CoA-Request from %s",
addrport_tostring(
(struct sockaddr *)&ss, ss.ss_len, buf,
sizeof(buf)));
code = RADIUS_CODE_COA_NAK;
cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
goto send;
}
log_printf(LOG_WARNING, "radius received an invalid RADIUS "
"message from %s: unknown code %d",
addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
sizeof(buf)), code);
goto out;
}
log_printf(LOG_INFO, "radius received Disconnect-Request from %s",
addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
sizeof(buf)));
if (radius_get_string_attr(req, RADIUS_TYPE_NAS_IDENTIFIER, attr,
sizeof(attr)) == 0 && strcmp(attr, _this->conf.nas_id) != 0) {
cause = RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH;
nakcause = "NAS Identification is mimatch";
goto search_done;
}
/* prepare User-Name attribute */
memset(&username, 0, sizeof(username));
radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, username,
sizeof(username));
cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
/* Our Session-Id is represented in "%08X%08x" (boot_id, ppp_id) */
snprintf(buf, sizeof(buf), "%08X", _this->boot_id);
if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
sizeof(attr)) == 0) {
ppp = NULL;
/* the client is to disconnect a session */
if (strlen(attr) != 16 || strncmp(buf, attr, 8) != 0) {
cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
nakcause = "Session-Id is wrong";
goto search_done;
}
ppp_id = strtoull(attr + 8, &endp, 16);
if (*endp != '\0' || errno == ERANGE || ppp_id == ULLONG_MAX) {
cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
nakcause = "Session-Id is invalid";
goto search_done;
}
if ((ppp = npppd_get_ppp_by_id(_this, ppp_id)) == NULL)
goto search_done;
if (username[0] != '\0' &&
strcmp(username, ppp->username) != 0) {
/* specified User-Name attribute is mismatched */
cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
nakcause = "User-Name is mismatched";
goto search_done;
}
ppp_stop(ppp, reason);
n++;
} else if (username[0] != '\0') {
users = npppd_get_ppp_by_user(_this, username);
if (users == NULL)
goto search_done;
memset(&ina, 0, sizeof(ina));
radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
&ina.s_addr);
slist_itr_first(users);
while ((ppp = slist_itr_next(users)) != NULL) {
if (ntohl(ina.s_addr) != 0 &&
ina.s_addr != ppp->ppp_framed_ip_address.s_addr)
continue;
ppp_stop(ppp, reason);
n++;
}
} else if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
&ina.s_addr) == 0) {
ppp = npppd_get_ppp_by_ip(_this, ina);
if (ppp != NULL) {
ppp_stop(ppp, reason);
n++;
}
}
search_done:
if (n > 0)
code = RADIUS_CODE_DISCONNECT_ACK;
else {
if (nakcause == NULL)
nakcause = "session not found";
code = RADIUS_CODE_DISCONNECT_NAK;
}
send:
res = radius_new_response_packet(code, req);
if (res == NULL) {
log_printf(LOG_WARNING, "%s: radius_new_response_packet: %m",
__func__);
goto out;
}
if (cause != 0)
radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
radius_set_response_authenticator(res, client->secret);
if (radius_sendto(listen->sock, res, 0, (struct sockaddr *)&ss, sslen)
== -1)
log_printf(LOG_WARNING, "%s: sendto(): %m", __func__);
log_printf(LOG_INFO, "radius send %s to %s%s%s",
(code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
(code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
sizeof(buf)), (nakcause)? ": " : "", (nakcause)? nakcause : "");
out:
radius_delete_packet(req);
if (res != NULL)
radius_delete_packet(res);
}
void
npppd_radius_dae_listen_stop(struct npppd_radius_dae_listen *listen)
{
char buf[80];
if (listen->sock >= 0) {
log_printf(LOG_INFO, "radius Shutdown %s/udp (DAE)",
addrport_tostring((struct sockaddr *)&listen->addr,
listen->addr.sin4.sin_len, buf, sizeof(buf)));
event_del(&listen->evsock);
close(listen->sock);
listen->sock = -1;
}
}

View File

@ -1,15 +1,35 @@
#ifndef NPPPD_RADIUS_H
#define NPPPD_RADIUS_H 1
#include <sys/tree.h>
#include <netinet/in.h>
#include <event.h>
struct npppd_radius_dae_listen {
int sock;
struct event evsock;
union {
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
} addr;
npppd *pppd;
TAILQ_ENTRY(npppd_radius_dae_listen) entry;
};
TAILQ_HEAD(npppd_radius_dae_listens, npppd_radius_dae_listen);
#ifdef __cplusplus
extern "C" {
#endif
void ppp_proccess_radius_framed_ip (npppd_ppp *, RADIUS_PACKET *);
int ppp_set_radius_attrs_for_authreq (npppd_ppp *, radius_req_setting *, RADIUS_PACKET *);
void npppd_ppp_radius_acct_start (npppd *, npppd_ppp *);
void npppd_ppp_radius_acct_stop (npppd *, npppd_ppp *);
void radius_acct_on(npppd *, radius_req_setting *);
void ppp_proccess_radius_framed_ip(npppd_ppp *, RADIUS_PACKET *);
int ppp_set_radius_attrs_for_authreq(npppd_ppp *, radius_req_setting *,
RADIUS_PACKET *);
void npppd_ppp_radius_acct_start(npppd *, npppd_ppp *);
void npppd_ppp_radius_acct_stop(npppd *, npppd_ppp *);
void radius_acct_on(npppd *, radius_req_setting *);
void npppd_radius_dae_init(npppd *);
void npppd_radius_dae_fini(npppd *);
#ifdef __cplusplus
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: parse.y,v 1.28 2024/07/01 07:09:07 yasuoka Exp $ */
/* $OpenBSD: parse.y,v 1.29 2024/07/11 14:05:59 yasuoka Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -32,6 +32,7 @@
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -134,6 +135,7 @@ typedef struct {
%token INTERFACE ADDRESS IPCP
%token BIND FROM AUTHENTICATED BY TO
%token ERROR
%token DAE CLIENT NAS_ID
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.yesno> yesno
@ -164,6 +166,7 @@ grammar : /* empty */
| grammar ipcp '\n'
| grammar interface '\n'
| grammar bind '\n'
| grammar radius '\n'
| grammar error '\n' { file->errors++; }
;
@ -513,6 +516,80 @@ tunnopt : LISTEN ON addressport {
curr_tunnconf->debug_dump_pktout = $2;
}
;
radius : RADIUS NAS_ID STRING {
if (strlcpy(conf->nas_id, $3, sizeof(conf->nas_id))
>= sizeof(conf->nas_id)) {
yyerror("`radius nas-id' is too long. use "
"less than %u chars.",
(unsigned)sizeof(conf->nas_id) - 1);
free($3);
YYERROR;
}
free($3);
}
| RADIUS DAE CLIENT address SECRET STRING {
struct radclientconf *client;
int secretsiz;
secretsiz = strlen($6) + 1;
if ((client = calloc(1, offsetof(struct radclientconf,
secret[secretsiz]))) == NULL) {
yyerror("%s", strerror(errno));
free($6);
YYERROR;
}
strlcpy(client->secret, $6, secretsiz);
switch ($4.ss_family) {
case AF_INET:
memcpy(&client->addr, &$4,
sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(&client->addr, &$4,
sizeof(struct sockaddr_in6));
break;
default:
yyerror("address family %d not supported",
$4.ss_family);
free($6);
YYERROR;
break;
}
TAILQ_INSERT_TAIL(&conf->raddaeclientconfs, client,
entry);
free($6);
}
| RADIUS DAE LISTEN ON addressport {
struct radlistenconf *listen;
if (ntohs(((struct sockaddr_in *)&$5)->sin_port) == 0)
((struct sockaddr_in *)&$5)->sin_port = htons(
RADIUS_DAE_DEFAULT_PORT);
if ((listen = calloc(1, sizeof(*listen))) == NULL) {
yyerror("%s", strerror(errno));
YYERROR;
}
switch ($5.ss_family) {
case AF_INET:
memcpy(&listen->addr, &$5,
sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(&listen->addr, &$5,
sizeof(struct sockaddr_in6));
break;
default:
yyerror("address family %d not supported",
$5.ss_family);
YYERROR;
break;
}
TAILQ_INSERT_TAIL(&conf->raddaelistenconfs, listen,
entry);
}
;
tunnelproto : L2TP { $$ = NPPPD_TUNNEL_L2TP; }
| PPTP { $$ = NPPPD_TUNNEL_PPTP; }
@ -1011,6 +1088,8 @@ lookup(char *s)
{ "ccp-timeout", CCP_TIMEOUT},
{ "chap", CHAP},
{ "chap-name", CHAP_NAME},
{ "client", CLIENT},
{ "dae", DAE},
{ "debug-dump-pktin", DEBUG_DUMP_PKTIN},
{ "debug-dump-pktout", DEBUG_DUMP_PKTOUT},
{ "dns-servers", DNS_SERVERS},
@ -1061,6 +1140,7 @@ lookup(char *s)
{ "mppe-key-state", MPPE_KEY_STATE},
{ "mru", MRU},
{ "mschapv2", MSCHAPV2},
{ "nas-id", NAS_ID},
{ "nbns-servers", NBNS_SERVERS},
{ "no", NO},
{ "on", ON},
@ -1429,6 +1509,9 @@ npppd_conf_init(struct npppd_conf *xconf)
TAILQ_INIT(&xconf->l2tp_confs);
TAILQ_INIT(&xconf->pptp_confs);
TAILQ_INIT(&xconf->pppoe_confs);
TAILQ_INIT(&xconf->raddaeclientconfs);
TAILQ_INIT(&xconf->raddaelistenconfs);
strlcpy(xconf->nas_id, "npppd", sizeof(xconf->nas_id));
}
void
@ -1439,6 +1522,8 @@ npppd_conf_fini(struct npppd_conf *xconf)
struct ipcpconf *ipcp, *ipcp0;
struct iface *iface, *iface0;
struct confbind *confbind, *confbind0;
struct radclientconf *radc, *radct;
struct radlistenconf *radl, *radlt;
TAILQ_FOREACH_SAFE(tunn, &xconf->tunnconfs, entry, tunn0) {
tunnconf_fini(tunn);
@ -1455,6 +1540,10 @@ npppd_conf_fini(struct npppd_conf *xconf)
TAILQ_FOREACH_SAFE(confbind, &xconf->confbinds, entry, confbind0) {
free(confbind);
}
TAILQ_FOREACH_SAFE(radc, &xconf->raddaeclientconfs, entry, radct)
free(radc);
TAILQ_FOREACH_SAFE(radl, &xconf->raddaelistenconfs, entry, radlt)
free(radl);
TAILQ_INIT(&xconf->l2tp_confs);
TAILQ_INIT(&xconf->pptp_confs);
TAILQ_INIT(&xconf->pppoe_confs);