-# $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>
-/* $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>
YYERROR;
authen.auth = modref;
}
- /* XXX decoration doesn't work for this moment. */
| DECORATE_BY str_l {
int i;
struct radiusd_module_ref *modref;
-/* $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
*/
#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>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
-#include <util.h>
#include <radius.h>
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 *);
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;
goto found;
}
}
+found:
if (authen == NULL) {
log_warnx("Received %s(code=%d) from %s id=%d "
"username=%s: no `authenticate' matches.",
req_id, username);
goto on_error;
}
-found:
RADIUSD_ASSERT(authen->auth != NULL);
if (!MODULE_DO_USERPASS(authen->auth->module) &&
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;
}
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;
-
- 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);
- }
+ struct radiusd_authentication *authen = q->authen;
+
+ /* 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);
+ 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);
+ }
}
-static int
-radius_query_response_decoration(struct radius_query *q)
+static void
+radius_query_response(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);
- }
+ int sz, res_id, res_code;
+ char buf[NI_MAXHOST + NI_MAXSERV + 30];
+
+ /* 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;
}
- return (0);
+ if (q->deco != NULL) {
+ radiusd_module_response_decoration(q->deco->module, q);
+ return;
+ }
+
+ if (radiusd_access_response_fixup(q) != 0)
+ goto on_error;
+
+ res_id = radius_get_id(q->res);
+ res_code = radius_get_code(q->res);
+
+ /* Reset response/message authenticator */
+ if (radius_has_attr(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR))
+ radius_del_attr_all(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR);
+ radius_put_message_authenticator(q->res, q->client->secret);
+ radius_set_response_authenticator(q->res, q->client->secret);
+
+ log_info("Sending %s(code=%d) to %s id=%u q=%u",
+ radius_code_string(res_code), res_code,
+ addrport_tostring((struct sockaddr *)&q->clientaddr,
+ q->clientaddrlen, buf, sizeof(buf)), res_id, q->id);
+
+ if ((sz = sendto(q->listen->sock, radius_get_data(q->res),
+ radius_get_length(q->res), 0,
+ (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0)
+ log_warn("Sending a RADIUS response failed");
+on_error:
+ radiusd_access_request_aborted(q);
+
}
/***********************************************************************
void
radiusd_access_request_answer(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
+ * The module diddn't check the authenticators
*/
if (radius_check_response_authenticator(q->res,
q->client->secret) != 0) {
}
}
- /* Decorate the response */
- if (radius_query_response_decoration(q) != 0)
- goto on_error;
-
- if (radiusd_access_response_fixup(q) != 0)
- goto on_error;
-
- res_id = radius_get_id(q->res);
- res_code = radius_get_code(q->res);
-
- /* Reset response/message authenticator */
- if (radius_has_attr(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR))
- radius_del_attr_all(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR);
- radius_put_message_authenticator(q->res, q->client->secret);
- radius_set_response_authenticator(q->res, q->client->secret);
+ RADIUSD_ASSERT(q->deco == NULL);
+ radius_query_response(q);
- log_info("Sending %s(code=%d) to %s id=%u q=%u",
- radius_code_string(res_code), res_code,
- addrport_tostring((struct sockaddr *)&q->clientaddr,
- q->clientaddrlen, buf, sizeof(buf)), res_id, q->id);
-
- if ((sz = sendto(q->listen->sock, radius_get_data(q->res),
- radius_get_length(q->res), 0,
- (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0)
- log_warn("Sending a RADIUS response failed");
+ return;
on_error:
radiusd_access_request_aborted(q);
}
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;
}
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,
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;
}
break;
}
default:
- RADIUSD_DBG(("Unhandled imsg type=%d",
- imsg->hdr.type));
+ RADIUSD_DBG(("Unhandled imsg type=%d from %s", imsg->hdr.type,
+ module->name));
}
}
"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) {
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,
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 &&
(void)radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD,
pass, strlen(pass));
}
+ 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);
+}
+
+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(&accsreq, 0, sizeof(accsreq));
- accsreq.q_id = q->id;
- accsreq.pktlen = len;
+ memset(&arg, 0, sizeof(arg));
+ arg.q_id = q_id;
+ arg.pktlen = len;
while (off < len) {
- siz = MAX_IMSGSIZE - sizeof(accsreq);
+ siz = MAX_IMSGSIZE - sizeof(arg);
if (len - off > siz)
- accsreq.final = false;
+ arg.final = false;
else {
- accsreq.final = true;
+ arg.final = true;
siz = len - off;
}
- iov[0].iov_base = &accsreq;
- iov[0].iov_len = sizeof(accsreq);
+ iov[0].iov_base = &arg;
+ iov[0].iov_len = sizeof(arg);
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);
+ if (imsg_composev(ibuf, type, 0, 0, -1, iov, 2) == -1)
+ return (-1);
off += siz;
}
- radiusd_module_reset_ev_handler(module);
- radius_delete_packet(radpkt);
-
- return;
+ return (0);
}
-.\" $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
.\" 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
.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
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
.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 .
.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
.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
-/* $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
* 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
/* 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
};
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 {
-/* $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.
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]))
#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;
-/* $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>
= 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;
#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 *
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;
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);
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)
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;
module_stop(base);
return (-1);
}
-
for (;;) {
if ((n = imsg_get(&base->ibuf, &imsg)) == -1) {
syslog(LOG_ERR, "%s: imsg_get(): %m", __func__);
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;
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;
}
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;
}
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;
return (0);
}
-static void
+void
module_stop(struct module_base *base)
{
if (module_stop_module != NULL)
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) \
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 *);
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
--- /dev/null
+/* $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);
+}
--- /dev/null
+# $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>