summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorYASUOKA Masahiko <yasuoka@cvs.openbsd.org>2024-07-11 14:06:00 +0000
committerYASUOKA Masahiko <yasuoka@cvs.openbsd.org>2024-07-11 14:06:00 +0000
commit5319e8f6dc85dcf8cedc1b56d141585420c20f48 (patch)
tree66043a9de8a22023031f9917aff5d687d2e8b47d /usr.sbin
parent9d753634a6016996a6cb1e0ece9e2a90926747fa (diff)
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.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/npppd/npppd/npppd.c12
-rw-r--r--usr.sbin/npppd/npppd/npppd.conf.532
-rw-r--r--usr.sbin/npppd/npppd/npppd.h148
-rw-r--r--usr.sbin/npppd/npppd/npppd_config.c7
-rw-r--r--usr.sbin/npppd/npppd/npppd_local.h10
-rw-r--r--usr.sbin/npppd/npppd/npppd_radius.c316
-rw-r--r--usr.sbin/npppd/npppd/npppd_radius.h30
-rw-r--r--usr.sbin/npppd/npppd/parse.y91
8 files changed, 566 insertions, 80 deletions
diff --git a/usr.sbin/npppd/npppd/npppd.c b/usr.sbin/npppd/npppd/npppd.c
index e23f8308d06..295cb9ea33f 100644
--- a/usr.sbin/npppd/npppd/npppd.c
+++ b/usr.sbin/npppd/npppd/npppd.c
@@ -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;
diff --git a/usr.sbin/npppd/npppd/npppd.conf.5 b/usr.sbin/npppd/npppd/npppd.conf.5
index ab2ed0b5d60..559ce22f9c6 100644
--- a/usr.sbin/npppd/npppd/npppd.conf.5
+++ b/usr.sbin/npppd/npppd/npppd.conf.5
@@ -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
diff --git a/usr.sbin/npppd/npppd/npppd.h b/usr.sbin/npppd/npppd/npppd.h
index 3cf9b2bcbcc..1d33ce4bd5e 100644
--- a/usr.sbin/npppd/npppd/npppd.h
+++ b/usr.sbin/npppd/npppd/npppd.h
@@ -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 *);
-
-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);
+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 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
diff --git a/usr.sbin/npppd/npppd/npppd_config.c b/usr.sbin/npppd/npppd/npppd_config.c
index d5a93fbcc2e..614ac71dbfc 100644
--- a/usr.sbin/npppd/npppd/npppd_config.c
+++ b/usr.sbin/npppd/npppd/npppd_config.c
@@ -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;
}
diff --git a/usr.sbin/npppd/npppd/npppd_local.h b/usr.sbin/npppd/npppd/npppd_local.h
index 37205b65f6a..d3e692f510d 100644
--- a/usr.sbin/npppd/npppd/npppd_local.h
+++ b/usr.sbin/npppd/npppd/npppd_local.h
@@ -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 */
diff --git a/usr.sbin/npppd/npppd/npppd_radius.c b/usr.sbin/npppd/npppd/npppd_radius.c
index c9d030e2b45..8503bd41d77 100644
--- a/usr.sbin/npppd/npppd/npppd_radius.c
+++ b/usr.sbin/npppd/npppd/npppd_radius.c
@@ -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;
+ }
+}
diff --git a/usr.sbin/npppd/npppd/npppd_radius.h b/usr.sbin/npppd/npppd/npppd_radius.h
index a1334545e2b..a7c309bd419 100644
--- a/usr.sbin/npppd/npppd/npppd_radius.h
+++ b/usr.sbin/npppd/npppd/npppd_radius.h
@@ -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
}
diff --git a/usr.sbin/npppd/npppd/parse.y b/usr.sbin/npppd/npppd/parse.y
index a589c5a7047..2017fe9a7ac 100644
--- a/usr.sbin/npppd/npppd/parse.y
+++ b/usr.sbin/npppd/npppd/parse.y
@@ -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);