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:
parent
668a98a424
commit
9791a9c53b
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user