sync code with last improvements from OpenBSD

This commit is contained in:
purplerain 2023-09-08 20:30:31 +00:00
parent 0e5a54c21a
commit 9bb7c570b7
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
33 changed files with 1190 additions and 596 deletions

View file

@ -1,6 +1,7 @@
# $OpenBSD: Makefile,v 1.1 2015/07/21 04:06:04 yasuoka Exp $
# $OpenBSD: Makefile,v 1.2 2023/09/08 05:56:22 yasuoka Exp $
SUBDIR= radiusd
SUBDIR+= radiusd_bsdauth
SUBDIR+= radiusd_radius
SUBDIR+= radiusd_standard
.include <bsd.prog.mk>

View file

@ -1,4 +1,4 @@
/* $OpenBSD: parse.y,v 1.16 2023/09/05 00:32:01 yasuoka Exp $ */
/* $OpenBSD: parse.y,v 1.17 2023/09/08 05:56:22 yasuoka Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -349,7 +349,6 @@ authopt : AUTHENTICATE_BY STRING {
YYERROR;
authen.auth = modref;
}
/* XXX decoration doesn't work for this moment. */
| DECORATE_BY str_l {
int i;
struct radiusd_module_ref *modref;

View file

@ -1,7 +1,7 @@
/* $OpenBSD: radiusd.c,v 1.31 2023/09/05 00:32:01 yasuoka Exp $ */
/* $OpenBSD: radiusd.c,v 1.32 2023/09/08 05:56:22 yasuoka Exp $ */
/*
* Copyright (c) 2013 Internet Initiative Japan Inc.
* Copyright (c) 2013, 2023 Internet Initiative Japan Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,13 +17,14 @@
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <dlfcn.h>
#include <err.h>
#include <errno.h>
#include <event.h>
@ -40,7 +41,6 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <util.h>
#include <radius.h>
@ -58,9 +58,8 @@ static void radiusd_on_sigterm(int, short, void *);
static void radiusd_on_sigint(int, short, void *);
static void radiusd_on_sighup(int, short, void *);
static void radiusd_on_sigchld(int, short, void *);
static int radius_query_request_decoration(struct radius_query *);
static int radius_query_response_decoration(
struct radius_query *);
static void radius_query_request(struct radius_query *);
static void radius_query_response(struct radius_query *);
static const char *radius_code_string(int);
static int radiusd_access_response_fixup (struct radius_query *);
@ -84,6 +83,12 @@ static void radiusd_module_userpass(struct radiusd_module *,
struct radius_query *);
static void radiusd_module_access_request(struct radiusd_module *,
struct radius_query *);
static void radiusd_module_request_decoration(
struct radiusd_module *, struct radius_query *);
static void radiusd_module_response_decoration(
struct radiusd_module *, struct radius_query *);
static int imsg_compose_radius_packet(struct imsgbuf *,
uint32_t, u_int, RADIUS_PACKET *);
static u_int radius_query_id_seq = 0;
int debug = 0;
@ -482,6 +487,7 @@ radiusd_listen_on_event(int fd, short evmask, void *ctx)
goto found;
}
}
found:
if (authen == NULL) {
log_warnx("Received %s(code=%d) from %s id=%d "
"username=%s: no `authenticate' matches.",
@ -489,7 +495,6 @@ radiusd_listen_on_event(int fd, short evmask, void *ctx)
req_id, username);
goto on_error;
}
found:
RADIUSD_ASSERT(authen->auth != NULL);
if (!MODULE_DO_USERPASS(authen->auth->module) &&
@ -515,25 +520,13 @@ found:
q->req_id = req_id;
radius_get_authenticator(packet, q->req_auth);
if (radius_query_request_decoration(q) != 0) {
log_warnx(
"Received %s(code=%d) from %s id=%d username=%s "
"q=%u: failed to decorate the request",
radius_code_string(req_code), req_code, peerstr,
q->req_id, q->username, q->id);
radiusd_access_request_aborted(q);
return;
}
log_info("Received %s(code=%d) from %s id=%d username=%s "
"q=%u: `%s' authentication is starting",
radius_code_string(req_code), req_code, peerstr, q->req_id,
q->username, q->id, q->authen->auth->module->name);
TAILQ_INSERT_TAIL(&listn->radiusd->query, q, next);
if (MODULE_DO_ACCSREQ(authen->auth->module)) {
radiusd_module_access_request(authen->auth->module, q);
} else if (MODULE_DO_USERPASS(authen->auth->module))
radiusd_module_userpass(authen->auth->module, q);
radius_query_request(q);
return;
}
@ -546,77 +539,52 @@ on_error:
return;
}
static int
radius_query_request_decoration(struct radius_query *q)
static void
radius_query_request(struct radius_query *q)
{
struct radiusd_module_ref *deco;
struct radiusd_authentication *authen = q->authen;
TAILQ_FOREACH(deco, &q->authen->deco, next) {
/* XXX decoration doesn't work for this moment. */
if (deco->module->request_decoration != NULL &&
deco->module->request_decoration(NULL, q) != 0) {
log_warnx("q=%u request decoration `%s' failed", q->id,
deco->module->name);
return (-1);
}
/* first or next request decoration */
for (;;) {
if (q->deco == NULL)
q->deco = TAILQ_FIRST(&q->authen->deco);
else
q->deco = TAILQ_NEXT(q->deco, next);
if (q->deco == NULL || MODULE_DO_REQDECO(q->deco->module))
break;
}
return (0);
}
static int
radius_query_response_decoration(struct radius_query *q)
{
struct radiusd_module_ref *deco;
TAILQ_FOREACH(deco, &q->authen->deco, next) {
/* XXX decoration doesn't work for this moment. */
if (deco->module->response_decoration != NULL &&
deco->module->response_decoration(NULL, q) != 0) {
log_warnx("q=%u response decoration `%s' failed", q->id,
deco->module->name);
return (-1);
}
if (q->deco != NULL)
radiusd_module_request_decoration(q->deco->module, q);
else {
RADIUSD_ASSERT(authen->auth != NULL);
if (MODULE_DO_ACCSREQ(authen->auth->module))
radiusd_module_access_request(authen->auth->module, q);
else if (MODULE_DO_USERPASS(authen->auth->module))
radiusd_module_userpass(authen->auth->module, q);
}
return (0);
}
/***********************************************************************
* Callback functions from the modules
***********************************************************************/
void
radiusd_access_request_answer(struct radius_query *q)
static void
radius_query_response(struct radius_query *q)
{
int sz, res_id, res_code;
char buf[NI_MAXHOST + NI_MAXSERV + 30];
const char *authen_secret = q->authen->auth->module->secret;
radius_set_request_packet(q->res, q->req);
if (authen_secret == NULL) {
/*
* The module couldn't check the authenticators
*/
if (radius_check_response_authenticator(q->res,
q->client->secret) != 0) {
log_info("Response from module has bad response "
"authenticator: id=%d", q->id);
goto on_error;
}
if (radius_has_attr(q->res,
RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
radius_check_message_authenticator(q->res,
q->client->secret) != 0) {
log_info("Response from module has bad message "
"authenticator: id=%d", q->id);
goto on_error;
}
/* first or next response decoration */
for (;;) {
if (q->deco == NULL)
q->deco = TAILQ_FIRST(&q->authen->deco);
else
q->deco = TAILQ_NEXT(q->deco, next);
if (q->deco == NULL || MODULE_DO_RESDECO(q->deco->module))
break;
}
/* Decorate the response */
if (radius_query_response_decoration(q) != 0)
goto on_error;
if (q->deco != NULL) {
radiusd_module_response_decoration(q->deco->module, q);
return;
}
if (radiusd_access_response_fixup(q) != 0)
goto on_error;
@ -641,6 +609,45 @@ radiusd_access_request_answer(struct radius_query *q)
log_warn("Sending a RADIUS response failed");
on_error:
radiusd_access_request_aborted(q);
}
/***********************************************************************
* Callback functions from the modules
***********************************************************************/
void
radiusd_access_request_answer(struct radius_query *q)
{
const char *authen_secret = q->authen->auth->module->secret;
radius_set_request_packet(q->res, q->req);
if (authen_secret == NULL) {
/*
* The module diddn't check the authenticators
*/
if (radius_check_response_authenticator(q->res,
q->client->secret) != 0) {
log_info("Response from module has bad response "
"authenticator: id=%d", q->id);
goto on_error;
}
if (radius_has_attr(q->res,
RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
radius_check_message_authenticator(q->res,
q->client->secret) != 0) {
log_info("Response from module has bad message "
"authenticator: id=%d", q->id);
goto on_error;
}
}
RADIUSD_ASSERT(q->deco == NULL);
radius_query_response(q);
return;
on_error:
radiusd_access_request_aborted(q);
}
void
@ -754,23 +761,6 @@ radiusd_conf_init(struct radiusd *conf)
TAILQ_INIT(&conf->authen);
TAILQ_INIT(&conf->client);
/*
* TODO: load the standard modules
*/
#if 0
static struct radiusd_module *radiusd_standard_modules[] = {
NULL
};
u_int i;
struct radiusd_module *module;
for (i = 0; radiusd_standard_modules[i] != NULL; i++) {
module = radiusd_create_module_class(
radiusd_standard_modules[i]);
TAILQ_INSERT_TAIL(&conf->module, module, next);
}
#endif
return;
}
@ -793,6 +783,9 @@ radiusd_access_response_fixup(struct radius_query *q)
const char *olds = q->client->secret;
const char *news = authen_secret;
if (news == NULL)
news = olds;
/* RFC 2865 Tunnel-Password */
attrlen = sizeof(attrlen);
if (radius_get_raw_attr(q->res, RADIUS_TYPE_TUNNEL_PASSWORD,
@ -1238,28 +1231,77 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
break;
}
case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
case IMSG_RADIUSD_MODULE_REQDECO_DONE:
case IMSG_RADIUSD_MODULE_RESDECO_DONE:
{
static struct radiusd_module_radpkt_arg *ans;
const char *typestr = "unknown";
switch (imsg->hdr.type) {
case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
typestr = "ACCSREQ_ANSWER";
break;
case IMSG_RADIUSD_MODULE_REQDECO_DONE:
typestr = "REQDECO_DONE";
break;
case IMSG_RADIUSD_MODULE_RESDECO_DONE:
typestr = "RESDECO_DONE";
break;
}
if (datalen <
(ssize_t)sizeof(struct radiusd_module_radpkt_arg)) {
log_warnx("Received ACCSREQ_ANSWER message, but "
"length is wrong");
log_warnx("Received %s message, but length is wrong",
typestr);
break;
}
q_id = ((struct radiusd_module_radpkt_arg *)imsg->data)->q_id;
q = radiusd_find_query(module->radiusd, q_id);
if (q == NULL) {
log_warnx("Received ACCSREQ_ANSWER from %s, but query "
"id=%u unknown", module->name, q_id);
log_warnx("Received %s from %s, but query id=%u "
"unknown", typestr, module->name, q_id);
break;
}
if ((ans = radiusd_module_recv_radpkt(module, imsg,
IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER,
"ACCSREQ_ANSWER")) != NULL) {
q->res = radius_convert_packet(
module->radpkt, module->radpktoff);
radiusd_access_request_answer(q);
imsg->hdr.type, typestr)) != NULL) {
RADIUS_PACKET *radpkt = NULL;
if (module->radpktoff > 0 &&
(radpkt = radius_convert_packet(
module->radpkt, module->radpktoff)) == NULL) {
log_warn("q=%u radius_convert_packet() failed",
q->id);
radiusd_access_request_aborted(q);
break;
}
module->radpktoff = 0;
switch (imsg->hdr.type) {
case IMSG_RADIUSD_MODULE_REQDECO_DONE:
if (radpkt != NULL) {
radius_delete_packet(q->req);
q->req = radpkt;
}
radius_query_request(q);
break;
case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
if (radpkt == NULL) {
log_warn("q=%u wrong pkt from module",
q->id);
radiusd_access_request_aborted(q);
}
q->res = radpkt;
radiusd_access_request_answer(q);
break;
case IMSG_RADIUSD_MODULE_RESDECO_DONE:
if (radpkt != NULL) {
radius_delete_packet(q->res);
radius_set_request_packet(radpkt,
q->req);
q->res = radpkt;
}
radius_query_response(q);
break;
}
}
break;
}
@ -1276,8 +1318,8 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
break;
}
default:
RADIUSD_DBG(("Unhandled imsg type=%d",
imsg->hdr.type));
RADIUSD_DBG(("Unhandled imsg type=%d from %s", imsg->hdr.type,
module->name));
}
}
@ -1306,9 +1348,11 @@ radiusd_module_recv_radpkt(struct radiusd_module *module, struct imsg *imsg,
"received length is too big", type_str, module->name);
goto on_fail;
}
memcpy(module->radpkt + module->radpktoff,
(caddr_t)(ans + 1), chunklen);
module->radpktoff += chunklen;
if (chunklen > 0) {
memcpy(module->radpkt + module->radpktoff,
(caddr_t)(ans + 1), chunklen);
module->radpktoff += chunklen;
}
if (!ans->final)
return (NULL); /* again */
if (module->radpktoff != ans->pktlen) {
@ -1427,11 +1471,9 @@ radiusd_module_userpass(struct radiusd_module *module, struct radius_query *q)
userpass.has_pass = true;
else
userpass.has_pass = false;
if (strlcpy(userpass.user, q->username, sizeof(userpass.user))
>= sizeof(userpass.user)) {
log_warnx("Could request USERPASS to module `%s': "
"User-Name too long", module->name);
if (radius_get_string_attr(q->req, RADIUS_TYPE_USER_NAME,
userpass.user, sizeof(userpass.user)) != 0) {
log_warnx("q=%u no User-Name attribute", q->id);
goto on_error;
}
imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_USERPASS, 0, 0, -1,
@ -1446,16 +1488,14 @@ static void
radiusd_module_access_request(struct radiusd_module *module,
struct radius_query *q)
{
struct radiusd_module_radpkt_arg accsreq;
struct iovec iov[2];
int off = 0, len, siz;
const u_char *pkt;
RADIUS_PACKET *radpkt;
char pass[256];
if ((radpkt = radius_convert_packet(radius_get_data(q->req),
radius_get_length(q->req))) == NULL) {
log_warn("Could not send ACCSREQ for `%s'", module->name);
log_warn("q=%u Could not send ACCSREQ to `%s'", q->id,
module->name);
radiusd_access_request_aborted(q);
return;
}
if (q->client->secret[0] != '\0' && module->secret != NULL &&
@ -1465,30 +1505,85 @@ radiusd_module_access_request(struct radiusd_module *module,
(void)radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD,
pass, strlen(pass));
}
pkt = radius_get_data(radpkt);
len = radius_get_length(radpkt);
memset(&accsreq, 0, sizeof(accsreq));
accsreq.q_id = q->id;
accsreq.pktlen = len;
while (off < len) {
siz = MAX_IMSGSIZE - sizeof(accsreq);
if (len - off > siz)
accsreq.final = false;
else {
accsreq.final = true;
siz = len - off;
}
iov[0].iov_base = &accsreq;
iov[0].iov_len = sizeof(accsreq);
iov[1].iov_base = (caddr_t)pkt + off;
iov[1].iov_len = siz;
imsg_composev(&module->ibuf, IMSG_RADIUSD_MODULE_ACCSREQ, 0, 0,
-1, iov, 2);
off += siz;
if (imsg_compose_radius_packet(&module->ibuf,
IMSG_RADIUSD_MODULE_ACCSREQ, q->id, radpkt) == -1) {
log_warn("q=%u Could not send ACCSREQ to `%s'", q->id,
module->name);
radiusd_access_request_aborted(q);
}
radiusd_module_reset_ev_handler(module);
radius_delete_packet(radpkt);
return;
}
static void
radiusd_module_request_decoration(struct radiusd_module *module,
struct radius_query *q)
{
if (module->fd < 0) {
log_warnx("q=%u Could not send REQDECO to `%s': module is "
"not running?", q->id, module->name);
radiusd_access_request_aborted(q);
return;
}
if (imsg_compose_radius_packet(&module->ibuf,
IMSG_RADIUSD_MODULE_REQDECO, q->id, q->req) == -1) {
log_warn("q=%u Could not send REQDECO to `%s'", q->id,
module->name);
radiusd_access_request_aborted(q);
return;
}
radiusd_module_reset_ev_handler(module);
}
static void
radiusd_module_response_decoration(struct radiusd_module *module,
struct radius_query *q)
{
if (module->fd < 0) {
log_warnx("q=%u Could not send RESDECO to `%s': module is "
"not running?", q->id, module->name);
radiusd_access_request_aborted(q);
return;
}
if (imsg_compose_radius_packet(&module->ibuf,
IMSG_RADIUSD_MODULE_RESDECO, q->id, q->res) == -1) {
log_warn("q=%u Could not send RESDECO to `%s'", q->id,
module->name);
radiusd_access_request_aborted(q);
return;
}
radiusd_module_reset_ev_handler(module);
}
static int
imsg_compose_radius_packet(struct imsgbuf *ibuf, uint32_t type, u_int q_id,
RADIUS_PACKET *radpkt)
{
struct radiusd_module_radpkt_arg arg;
int off = 0, len, siz;
struct iovec iov[2];
const u_char *pkt;
pkt = radius_get_data(radpkt);
len = radius_get_length(radpkt);
memset(&arg, 0, sizeof(arg));
arg.q_id = q_id;
arg.pktlen = len;
while (off < len) {
siz = MAX_IMSGSIZE - sizeof(arg);
if (len - off > siz)
arg.final = false;
else {
arg.final = true;
siz = len - off;
}
iov[0].iov_base = &arg;
iov[0].iov_len = sizeof(arg);
iov[1].iov_base = (caddr_t)pkt + off;
iov[1].iov_len = siz;
if (imsg_composev(ibuf, type, 0, 0, -1, iov, 2) == -1)
return (-1);
off += siz;
}
return (0);
}

View file

@ -1,7 +1,7 @@
.\" $OpenBSD: radiusd.conf.5,v 1.16 2023/09/04 12:28:18 yasuoka Exp $
.\" $OpenBSD: radiusd.conf.5,v 1.17 2023/09/08 05:56:22 yasuoka Exp $
.\"
.\" Copyright (c) 2014 Esdenera Networks GmbH
.\" Copyright (c) 2014 Internet Initiative Japan Inc.
.\" Copyright (c) 2014, 2023 Internet Initiative Japan Inc.
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,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: September 4 2023 $
.Dd $Mdocdate: September 8 2023 $
.Dt RADIUSD.CONF 5
.Os
.Sh NAME
@ -68,6 +68,7 @@ The following modules are available:
.It Sy "Path" Ta Sy "Description"
.It Pa /usr/libexec/radiusd/radiusd_bsdauth Ta Do bsdauth Dc module
.It Pa /usr/libexec/radiusd/radiusd_radius Ta Do radius Dc module
.It Pa /usr/libexec/radiusd/radiusd_standard Ta Do standard Dc module
.El
.Bl -tag -width Ds
.It Do bsdauth Dc module
@ -83,6 +84,11 @@ It only supports PAP, password based authentication.
The
.Dq radius
module provides authentication from upstream RADIUS servers.
.It Do standard Dc module
The
.Dq standard
module provides standard decorations for Access-Request messages or its
response messages.
.El
.It Ic module set Ar module key value ...
Configure the module specific configurations by
@ -146,6 +152,34 @@ and
.Ar max-failover
will not be used.
.El
.Pp
The
.Dq standard
module supports the following configuration key and value:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic strip-atmark-realm Ar true | false
Remove the realm part which starts with @
.Pq atmark
from the User-Name attribute of the Access-Request.
.Pp
.It Ic strip-nt-domain Ar true | false
Remove NT domain which ends with \\
.Pq backslash
from the User-Name attribute of the Access-Request.
.Pp
.It Cm remove-request-attribute Oo Ar vendor Oc Ar type
.It Cm remove-response-attribute Oo Ar vendor Oc Ar type
Remove all the specified attributes from request or response
messages of Access-Request.
Specify
.Ar type
of the attribute in a decimal number.
To specify a vendor attribute,
specify the Vendor-Id
in a decimal number for
.Ar vendor .
.El
.It Ic authenticate Ar username-pattern ... Brq ...
Specify an authentication configuration for the users specified by
.Ar username-pattern .
@ -162,6 +196,8 @@ It is followed by a block of options enclosed in curly brackets:
.Bl -tag -width Ds
.It Ic authenticate-by Ar module
Specify the module name.
.It Ic decorate-by Ar module
Specify the module name.
.El
.El
.Sh FILES
@ -182,28 +218,32 @@ module executable.
.Sh EXAMPLES
.Bd -literal -offset indent
listen on 0.0.0.0
#listen on ::
listen on ::
client 127.0.0.1/32 {
secret "secret"
msgauth-required no
}
client 192.168.0.0/24 {
secret "secret"
msgauth-required yes
}
module load bsdauth "/usr/libexec/radiusd/radiusd_bsdauth"
module set bsdauth restrict-group "operator"
module set bsdauth restrict-group operator
module load radius "/usr/libexec/radiusd/radiusd_radius"
module set radius secret "testing123"
module set radius server "127.0.0.1"
authenticate *@example.com {
authenticate-by radius
module load strip-realm "/usr/libexec/radiusd/radiusd_standard"
module set strip-realm strip-atmark-realm true
authenticate *@local {
authenticate-by bsdauth
decorate-by strip-realm
}
authenticate * {
authenticate-by bsdauth
authenticate-by radius
}
.Ed
.Sh SEE ALSO

View file

@ -1,4 +1,4 @@
/* $OpenBSD: radiusd.h,v 1.4 2019/04/03 11:54:56 yasuoka Exp $ */
/* $OpenBSD: radiusd.h,v 1.5 2023/09/08 05:56:22 yasuoka Exp $ */
#ifndef RADIUSD_H
#define RADIUSD_H 1
@ -17,6 +17,8 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#define RADIUSD_MODULE_NAME_LEN 32
@ -38,6 +40,10 @@ enum imsg_type {
/* Check the response's authenticator if the module doesn't */
IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER,
IMSG_RADIUSD_MODULE_ACCSREQ_ABORTED,
IMSG_RADIUSD_MODULE_REQDECO,
IMSG_RADIUSD_MODULE_REQDECO_DONE,
IMSG_RADIUSD_MODULE_RESDECO,
IMSG_RADIUSD_MODULE_RESDECO_DONE,
IMSG_RADIUSD_MODULE_STOP
};
@ -46,6 +52,8 @@ struct radiusd_module_load_arg {
uint32_t cap; /* module capabity bits */
#define RADIUSD_MODULE_CAP_USERPASS 0x1
#define RADIUSD_MODULE_CAP_ACCSREQ 0x2
#define RADIUSD_MODULE_CAP_REQDECO 0x4
#define RADIUSD_MODULE_CAP_RESDECO 0x8
};
struct radiusd_module_object {

View file

@ -1,4 +1,4 @@
/* $OpenBSD: radiusd_local.h,v 1.5 2019/04/01 11:05:41 yasuoka Exp $ */
/* $OpenBSD: radiusd_local.h,v 1.6 2023/09/08 05:56:22 yasuoka Exp $ */
/*
* Copyright (c) 2013 Internet Initiative Japan Inc.
@ -122,6 +122,7 @@ struct radius_query {
int req_modified;
char username[256]; /* original username */
TAILQ_ENTRY(radius_query) next;
struct radiusd_module_ref *deco;
};
#ifndef nitems
#define nitems(_x) (sizeof((_x)) / sizeof((_x)[0]))
@ -149,6 +150,12 @@ struct radius_query {
#define MODULE_DO_ACCSREQ(_m) \
((_m)->fd >= 0 && \
((_m)->capabilities & RADIUSD_MODULE_CAP_ACCSREQ) != 0)
#define MODULE_DO_REQDECO(_m) \
((_m)->fd >= 0 && \
((_m)->capabilities & RADIUSD_MODULE_CAP_REQDECO) != 0)
#define MODULE_DO_RESDECO(_m) \
((_m)->fd >= 0 && \
((_m)->capabilities & RADIUSD_MODULE_CAP_RESDECO) != 0)
extern struct radiusd_module mod_standard;
extern struct radiusd_module mod_radius;

View file

@ -1,4 +1,4 @@
/* $OpenBSD: radiusd_module.c,v 1.13 2019/06/28 13:32:49 deraadt Exp $ */
/* $OpenBSD: radiusd_module.c,v 1.14 2023/09/08 05:56:22 yasuoka Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@ -46,6 +46,10 @@ static void (*module_userpass) (void *, u_int, const char *, const char *)
= NULL;
static void (*module_access_request) (void *, u_int, const u_char *,
size_t) = NULL;
static void (*module_request_decoration) (void *, u_int, const u_char *,
size_t) = NULL;
static void (*module_response_decoration) (void *, u_int, const u_char *,
size_t) = NULL;
struct module_base {
void *ctx;
@ -73,7 +77,6 @@ static int module_imsg_handler(struct module_base *, struct imsg *);
#ifdef USE_LIBEVENT
static void module_on_event(int, short, void *);
#endif
static void module_stop(struct module_base *);
static void module_reset_event(struct module_base *);
struct module_base *
@ -90,6 +93,8 @@ module_create(int sock, void *ctx, struct module_handlers *handler)
module_userpass = handler->userpass;
module_access_request = handler->access_request;
module_config_set = handler->config_set;
module_request_decoration = handler->request_decoration;
module_response_decoration = handler->response_decoration;
module_start_module = handler->start;
module_stop_module = handler->stop;
@ -140,6 +145,10 @@ module_load(struct module_base *base)
load.cap |= RADIUSD_MODULE_CAP_USERPASS;
if (module_access_request != NULL)
load.cap |= RADIUSD_MODULE_CAP_ACCSREQ;
if (module_request_decoration != NULL)
load.cap |= RADIUSD_MODULE_CAP_REQDECO;
if (module_response_decoration != NULL)
load.cap |= RADIUSD_MODULE_CAP_RESDECO;
imsg_compose(&base->ibuf, IMSG_RADIUSD_MODULE_LOAD, 0, 0, -1, &load,
sizeof(load));
imsg_flush(&base->ibuf);
@ -260,6 +269,22 @@ module_accsreq_aborted(struct module_base *base, u_int q_id)
return (ret);
}
int
module_reqdeco_done(struct module_base *base, u_int q_id, const u_char *pkt,
size_t pktlen)
{
return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_REQDECO_DONE,
q_id, pkt, pktlen));
}
int
module_resdeco_done(struct module_base *base, u_int q_id, const u_char *pkt,
size_t pktlen)
{
return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_RESDECO_DONE,
q_id, pkt, pktlen));
}
static int
module_common_radpkt(struct module_base *base, uint32_t imsg_type, u_int q_id,
const u_char *pkt, size_t pktlen)
@ -271,19 +296,22 @@ module_common_radpkt(struct module_base *base, uint32_t imsg_type, u_int q_id,
len = pktlen;
ans.q_id = q_id;
ans.pktlen = pktlen;
while (off < len) {
ans.final = false;
while (!ans.final) {
siz = MAX_IMSGSIZE - sizeof(ans);
if (len - off > siz)
ans.final = false;
else {
if (len - off <= siz) {
ans.final = true;
siz = len - off;
}
iov[0].iov_base = &ans;
iov[0].iov_len = sizeof(ans);
iov[1].iov_base = (u_char *)pkt + off;
iov[1].iov_len = siz;
ret = imsg_composev(&base->ibuf, imsg_type, 0, 0, -1, iov, 2);
if (siz > 0) {
iov[1].iov_base = (u_char *)pkt + off;
iov[1].iov_len = siz;
}
ret = imsg_composev(&base->ibuf, imsg_type, 0, 0, -1, iov,
(siz > 0)? 2 : 1);
if (ret == -1)
break;
off += siz;
@ -305,7 +333,6 @@ module_recv_imsg(struct module_base *base)
module_stop(base);
return (-1);
}
for (;;) {
if ((n = imsg_get(&base->ibuf, &imsg)) == -1) {
syslog(LOG_ERR, "%s: imsg_get(): %m", __func__);
@ -410,19 +437,40 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg)
break;
}
case IMSG_RADIUSD_MODULE_ACCSREQ:
case IMSG_RADIUSD_MODULE_REQDECO:
case IMSG_RADIUSD_MODULE_RESDECO:
{
struct radiusd_module_radpkt_arg *accessreq;
int chunklen;
const char *typestr;
if (module_access_request == NULL) {
syslog(LOG_ERR, "Received ACCSREQ message, but "
"module doesn't support");
break;
if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCSREQ) {
if (module_access_request == NULL) {
syslog(LOG_ERR, "Received ACCSREQ message, but "
"module doesn't support");
break;
}
typestr = "ACCSREQ";
} else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_REQDECO) {
if (module_request_decoration == NULL) {
syslog(LOG_ERR, "Received REQDECO message, but "
"module doesn't support");
break;
}
typestr = "REQDECO";
} else {
if (module_response_decoration == NULL) {
syslog(LOG_ERR, "Received RESDECO message, but "
"module doesn't support");
break;
}
typestr = "RESDECO";
}
if (datalen <
(ssize_t)sizeof(struct radiusd_module_radpkt_arg)) {
syslog(LOG_ERR, "Received ACCSREQ message, but "
"length is wrong");
syslog(LOG_ERR, "Received %s message, but "
"length is wrong", typestr);
break;
}
accessreq = (struct radiusd_module_radpkt_arg *)imsg->data;
@ -431,7 +479,7 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg)
if ((nradpkt = realloc(base->radpkt,
accessreq->pktlen)) == NULL) {
syslog(LOG_ERR, "Could not handle received "
"ACCSREQ message: %m");
"%s message: %m", typestr);
base->radpktoff = 0;
goto accsreq_out;
}
@ -441,8 +489,8 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg)
chunklen = datalen - sizeof(struct radiusd_module_radpkt_arg);
if (chunklen > base->radpktsiz - base->radpktoff){
syslog(LOG_ERR,
"Could not handle received ACCSREQ message: "
"received length is too big");
"Could not handle received %s message: "
"received length is too big", typestr);
base->radpktoff = 0;
goto accsreq_out;
}
@ -453,13 +501,20 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg)
goto accsreq_out;
if (base->radpktoff != accessreq->pktlen) {
syslog(LOG_ERR,
"Could not handle received ACCSREQ "
"message: length is mismatch");
"Could not handle received %s "
"message: length is mismatch", typestr);
base->radpktoff = 0;
goto accsreq_out;
}
module_access_request(base->ctx, accessreq->q_id,
base->radpkt, base->radpktoff);
if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCSREQ)
module_access_request(base->ctx, accessreq->q_id,
base->radpkt, base->radpktoff);
else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_REQDECO)
module_request_decoration(base->ctx, accessreq->q_id,
base->radpkt, base->radpktoff);
else
module_response_decoration(base->ctx, accessreq->q_id,
base->radpkt, base->radpktoff);
base->radpktoff = 0;
accsreq_out:
break;
@ -469,7 +524,7 @@ accsreq_out:
return (0);
}
static void
void
module_stop(struct module_base *base)
{
if (module_stop_module != NULL)

View file

@ -35,8 +35,13 @@ struct module_handlers {
void (*access_request)(void *ctx, u_int query_id, const u_char *pkt,
size_t pktlen);
/* User-Password Attribute is encrypted if the module has the secret */
void (*request_decoration)(void *ctx, u_int query_id, const u_char *pkt,
size_t pktlen);
void (*response_decoration)(void *ctx, u_int query_id,
const u_char *pkt, size_t pktlen);
};
#define SYNTAX_ASSERT(_cond, _msg) \
@ -51,6 +56,7 @@ __BEGIN_DECLS
struct module_base *module_create(int, void *, struct module_handlers *);
void module_start(struct module_base *);
void module_stop(struct module_base *);
int module_run(struct module_base *);
void module_destroy(struct module_base *);
void module_load(struct module_base *);
@ -67,6 +73,10 @@ int module_userpass_fail(struct module_base *, u_int,
int module_accsreq_answer(struct module_base *, u_int,
const u_char *, size_t);
int module_accsreq_aborted(struct module_base *, u_int);
int module_reqdeco_done(struct module_base *, u_int,
const u_char *, size_t);
int module_resdeco_done(struct module_base *, u_int,
const u_char *, size_t);
__END_DECLS

View file

@ -0,0 +1,298 @@
/* $OpenBSD: radiusd_standard.c,v 1.1 2023/09/08 05:56:22 yasuoka Exp $ */
/*
* Copyright (c) 2013, 2023 Internet Initiative Japan Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <radius.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "radiusd.h"
#include "radiusd_module.h"
TAILQ_HEAD(attrs,attr);
struct attr {
uint8_t type;
uint32_t vendor;
uint32_t vtype;
TAILQ_ENTRY(attr) next;
};
struct module_standard {
struct module_base *base;
bool strip_atmark_realm;
bool strip_nt_domain;
struct attrs remove_reqattrs;
struct attrs remove_resattrs;
};
static void module_standard_config_set(void *, const char *, int,
char * const *);
static void module_standard_reqdeco(void *, u_int, const u_char *, size_t);
static void module_standard_resdeco(void *, u_int, const u_char *, size_t);
int
main(int argc, char *argv[])
{
struct module_standard module_standard;
struct module_handlers handlers = {
.config_set = module_standard_config_set,
.request_decoration = module_standard_reqdeco,
.response_decoration = module_standard_resdeco
};
struct attr *attr;
memset(&module_standard, 0, sizeof(module_standard));
TAILQ_INIT(&module_standard.remove_reqattrs);
TAILQ_INIT(&module_standard.remove_resattrs);
if ((module_standard.base = module_create(
STDIN_FILENO, &module_standard, &handlers)) == NULL)
err(1, "Could not create a module instance");
module_drop_privilege(module_standard.base);
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
module_load(module_standard.base);
openlog(NULL, LOG_PID, LOG_DAEMON);
while (module_run(module_standard.base) == 0)
;
module_destroy(module_standard.base);
while ((attr = TAILQ_FIRST(&module_standard.remove_reqattrs)) != NULL) {
TAILQ_REMOVE(&module_standard.remove_reqattrs, attr, next);
freezero(attr, sizeof(struct attr));
}
while ((attr = TAILQ_FIRST(&module_standard.remove_resattrs)) != NULL) {
TAILQ_REMOVE(&module_standard.remove_resattrs, attr, next);
freezero(attr, sizeof(struct attr));
}
exit(EXIT_SUCCESS);
}
static void
module_standard_config_set(void *ctx, const char *name, int argc,
char * const * argv)
{
struct module_standard *module = ctx;
struct attr *attr;
const char *errmsg = "none";
const char *errstr;
if (strcmp(name, "strip-atmark-realm") == 0) {
SYNTAX_ASSERT(argc == 1,
"`strip-atmark-realm' must have only one argment");
if (strcmp(argv[0], "true") == 0)
module->strip_atmark_realm = true;
else if (strcmp(argv[0], "false") == 0)
module->strip_atmark_realm = false;
else
SYNTAX_ASSERT(0,
"`strip-atmark-realm' must `true' or `false'");
} else if (strcmp(name, "strip-nt-domain") == 0) {
SYNTAX_ASSERT(argc == 1,
"`strip-nt-domain' must have only one argment");
if (strcmp(argv[0], "true") == 0)
module->strip_nt_domain = true;
else if (strcmp(argv[0], "false") == 0)
module->strip_nt_domain = false;
else
SYNTAX_ASSERT(0,
"`strip-nt-domain' must `true' or `false'");
} else if (strcmp(name, "remove-request-attribute") == 0 ||
strcmp(name, "remove-response-attribute") == 0) {
struct attrs *attrs;
if (strcmp(name, "remove-request-attribute") == 0) {
SYNTAX_ASSERT(argc == 1 || argc == 2,
"`remove-request-attribute' must have one or two "
"argment");
attrs = &module->remove_reqattrs;
} else {
SYNTAX_ASSERT(argc == 1 || argc == 2,
"`remove-response-attribute' must have one or two "
"argment");
attrs = &module->remove_resattrs;
}
if ((attr = calloc(1, sizeof(struct attr))) == NULL) {
module_send_message(module->base, IMSG_NG,
"Out of memory: %s", strerror(errno));
}
if (argc == 1) {
attr->type = strtonum(argv[0], 0, 255, &errstr);
if (errstr == NULL &&
attr->type != RADIUS_TYPE_VENDOR_SPECIFIC) {
TAILQ_INSERT_TAIL(attrs, attr, next);
attr = NULL;
}
} else {
attr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
attr->vendor = strtonum(argv[0], 0, UINT32_MAX,
&errstr);
if (errstr == NULL)
attr->vtype = strtonum(argv[1], 0, 255,
&errstr);
if (errstr == NULL) {
TAILQ_INSERT_TAIL(attrs, attr, next);
attr = NULL;
}
}
freezero(attr, sizeof(struct attr));
if (strcmp(name, "remove-request-attribute") == 0)
SYNTAX_ASSERT(attr == NULL,
"wrong number for `remove-request-attribute`");
else
SYNTAX_ASSERT(attr == NULL,
"wrong number for `remove-response-attribute`");
} else if (strncmp(name, "_", 1) == 0)
/* nothing */; /* ignore all internal messages */
else {
module_send_message(module->base, IMSG_NG,
"Unknown config parameter name `%s'", name);
return;
}
module_send_message(module->base, IMSG_OK, NULL);
return;
syntax_error:
module_send_message(module->base, IMSG_NG, "%s", errmsg);
}
/* request message decoration */
static void
module_standard_reqdeco(void *ctx, u_int q_id, const u_char *pkt, size_t pktlen)
{
struct module_standard *module = ctx;
RADIUS_PACKET *radpkt = NULL;
int changed = 0;
char *ch, *username, buf[256];
struct attr *attr;
if (module->strip_atmark_realm || module->strip_nt_domain) {
if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL) {
syslog(LOG_ERR,
"%s: radius_convert_packet() failed: %m", __func__);
module_stop(module->base);
return;
}
username = buf;
if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
username, sizeof(buf)) != 0) {
syslog(LOG_WARNING,
"standard: q=%u could not get User-Name attribute",
q_id);
goto skip;
}
if (module->strip_atmark_realm &&
(ch = strrchr(username, '@')) != NULL) {
*ch = '\0';
changed++;
}
if (module->strip_nt_domain &&
(ch = strchr(username, '\\')) != NULL) {
username = ch + 1;
changed++;
}
if (changed > 0) {
radius_del_attr_all(radpkt, RADIUS_TYPE_USER_NAME);
radius_put_string_attr(radpkt,
RADIUS_TYPE_USER_NAME, username);
}
}
skip:
TAILQ_FOREACH(attr, &module->remove_reqattrs, next) {
if (radpkt == NULL &&
(radpkt = radius_convert_packet(pkt, pktlen)) == NULL) {
syslog(LOG_ERR,
"%s: radius_convert_packet() failed: %m", __func__);
module_stop(module->base);
return;
}
if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)
radius_del_attr_all(radpkt, attr->type);
else
radius_del_vs_attr_all(radpkt, attr->vendor,
attr->vtype);
}
if (radpkt == NULL) {
pkt = NULL;
pktlen = 0;
} else {
pkt = radius_get_data(radpkt);
pktlen = radius_get_length(radpkt);
}
if (module_reqdeco_done(module->base, q_id, pkt, pktlen) == -1) {
syslog(LOG_ERR, "%s: module_reqdeco_done() failed: %m",
__func__);
module_stop(module->base);
}
if (radpkt != NULL)
radius_delete_packet(radpkt);
}
/* response message decoration */
static void
module_standard_resdeco(void *ctx, u_int q_id, const u_char *pkt, size_t pktlen)
{
struct module_standard *module = ctx;
RADIUS_PACKET *radpkt = NULL;
struct attr *attr;
TAILQ_FOREACH(attr, &module->remove_reqattrs, next) {
if (radpkt == NULL &&
(radpkt = radius_convert_packet(pkt, pktlen)) == NULL) {
syslog(LOG_ERR,
"%s: radius_convert_packet() failed: %m", __func__);
module_stop(module->base);
return;
}
if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)
radius_del_attr_all(radpkt, attr->type);
else
radius_del_vs_attr_all(radpkt, attr->vendor,
attr->vtype);
}
if (radpkt == NULL) {
pkt = NULL;
pktlen = 0;
} else {
pkt = radius_get_data(radpkt);
pktlen = radius_get_length(radpkt);
}
if (module_resdeco_done(module->base, q_id, pkt, pktlen) == -1) {
syslog(LOG_ERR, "%s: module_resdeco_done() failed: %m",
__func__);
module_stop(module->base);
}
if (radpkt != NULL)
radius_delete_packet(radpkt);
}

View file

@ -0,0 +1,8 @@
# $OpenBSD: Makefile,v 1.1 2023/09/08 05:56:22 yasuoka Exp $
PROG= radiusd_standard
BINDIR= /usr/libexec/radiusd
SRCS= radiusd_standard.c radiusd_module.c
LDADD= -lutil -lradius -lcrypto
NOMAN= #
.include <bsd.prog.mk>