-/* $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.
* 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 */
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 *);
_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);
_this->finalizing = 1;
npppd_reset_timer(_this);
+
+#ifdef USE_NPPPD_RADIUS
+ npppd_radius_dae_fini(_this);
+#endif
}
static void
* @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;
-.\" $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>
.\"
.\" 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
Authentication settings.
.It Sy Bind
Bind settings.
+.It Sy RADIUS
+RADIUS settings.
.El
.Sh GLOBAL
The global options are as follows:
.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
-/* $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.
#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))
} 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];
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;
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
-/* $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.
* 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.
*/
#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;
}
-/* $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.
#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 */
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 */
-/* $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.
#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
/**
* 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)
{
/* 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')
/* 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);
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;
+ }
+}
#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
}
-/* $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>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%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
| grammar ipcp '\n'
| grammar interface '\n'
| grammar bind '\n'
+ | grammar radius '\n'
| grammar error '\n' { file->errors++; }
;
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; }
{ "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},
{ "mppe-key-state", MPPE_KEY_STATE},
{ "mru", MRU},
{ "mschapv2", MSCHAPV2},
+ { "nas-id", NAS_ID},
{ "nbns-servers", NBNS_SERVERS},
{ "no", NO},
{ "on", ON},
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
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);
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);