sync code with last improvements from OpenBSD
This commit is contained in:
parent
0e5a54c21a
commit
9bb7c570b7
33 changed files with 1190 additions and 596 deletions
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
298
usr.sbin/radiusd/radiusd_standard.c
Normal file
298
usr.sbin/radiusd/radiusd_standard.c
Normal 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);
|
||||
}
|
8
usr.sbin/radiusd/radiusd_standard/Makefile
Normal file
8
usr.sbin/radiusd/radiusd_standard/Makefile
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue