sync with OpenBSD -current
This commit is contained in:
parent
d68c02c8a8
commit
550dd57439
39 changed files with 1599 additions and 402 deletions
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: radiusd.c,v 1.34 2024/01/08 04:16:48 yasuoka Exp $ */
|
||||
/* $OpenBSD: radiusd.c,v 1.35 2024/02/09 07:46:32 yasuoka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, 2023 Internet Initiative Japan Inc.
|
||||
|
@ -54,12 +54,14 @@ static int radiusd_start(struct radiusd *);
|
|||
static void radiusd_stop(struct radiusd *);
|
||||
static void radiusd_free(struct radiusd *);
|
||||
static void radiusd_listen_on_event(int, short, void *);
|
||||
static void radiusd_listen_handle_packet(struct radiusd_listen *,
|
||||
RADIUS_PACKET *, struct sockaddr *, socklen_t);
|
||||
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 void radius_query_request(struct radius_query *);
|
||||
static void radius_query_response(struct radius_query *);
|
||||
static void raidus_query_access_request(struct radius_query *);
|
||||
static void radius_query_access_response(struct radius_query *);
|
||||
static const char *radius_code_string(int);
|
||||
static int radiusd_access_response_fixup (struct radius_query *);
|
||||
|
||||
|
@ -350,19 +352,12 @@ radiusd_free(struct radiusd *radiusd)
|
|||
static void
|
||||
radiusd_listen_on_event(int fd, short evmask, void *ctx)
|
||||
{
|
||||
int i, sz, req_id, req_code;
|
||||
struct radiusd_listen *listn = ctx;
|
||||
static u_char buf[65535];
|
||||
static char username[256];
|
||||
int sz;
|
||||
RADIUS_PACKET *packet = NULL;
|
||||
struct sockaddr_storage peer;
|
||||
socklen_t peersz;
|
||||
RADIUS_PACKET *packet = NULL;
|
||||
char peerstr[NI_MAXHOST + NI_MAXSERV + 30];
|
||||
struct radiusd_authentication *authen;
|
||||
struct radiusd_client *client;
|
||||
struct radius_query *q;
|
||||
#define in(_x) (((struct sockaddr_in *)_x)->sin_addr)
|
||||
#define in6(_x) (((struct sockaddr_in6 *)_x)->sin6_addr)
|
||||
struct radiusd_listen *listn = ctx;
|
||||
static u_char buf[65535];
|
||||
|
||||
if (evmask & EV_READ) {
|
||||
peersz = sizeof(peer);
|
||||
|
@ -371,115 +366,128 @@ radiusd_listen_on_event(int fd, short evmask, void *ctx)
|
|||
if (errno == EAGAIN)
|
||||
return;
|
||||
log_warn("%s: recvfrom() failed", __func__);
|
||||
goto on_error;
|
||||
return;
|
||||
}
|
||||
RADIUSD_ASSERT(peer.ss_family == AF_INET ||
|
||||
peer.ss_family == AF_INET6);
|
||||
|
||||
/* prepare some information about this messages */
|
||||
if (addrport_tostring((struct sockaddr *)&peer, peersz,
|
||||
peerstr, sizeof(peerstr)) == NULL) {
|
||||
log_warn("%s: getnameinfo() failed", __func__);
|
||||
goto on_error;
|
||||
}
|
||||
if ((packet = radius_convert_packet(buf, sz)) == NULL) {
|
||||
if ((packet = radius_convert_packet(buf, sz)) == NULL)
|
||||
log_warn("%s: radius_convert_packet() failed",
|
||||
__func__);
|
||||
goto on_error;
|
||||
}
|
||||
req_id = radius_get_id(packet);
|
||||
req_code = radius_get_code(packet);
|
||||
else
|
||||
radiusd_listen_handle_packet(listn, packet,
|
||||
(struct sockaddr *)&peer, peersz);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a matching `client' entry
|
||||
*/
|
||||
TAILQ_FOREACH(client, &listn->radiusd->client, next) {
|
||||
if (client->af != peer.ss_family)
|
||||
continue;
|
||||
if (peer.ss_family == AF_INET &&
|
||||
IPv4_cmp(&((struct sockaddr_in *)&peer)->sin_addr,
|
||||
&client->addr, &client->mask))
|
||||
break;
|
||||
else if (peer.ss_family == AF_INET6 &&
|
||||
IPv6_cmp(&((struct sockaddr_in6 *)&peer)->sin6_addr,
|
||||
&client->addr, &client->mask))
|
||||
break;
|
||||
}
|
||||
if (client == NULL) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: "
|
||||
"no `client' matches", radius_code_string(req_code),
|
||||
req_code, peerstr, req_id);
|
||||
goto on_error;
|
||||
}
|
||||
static void
|
||||
radiusd_listen_handle_packet(struct radiusd_listen *listn,
|
||||
RADIUS_PACKET *packet, struct sockaddr *peer, socklen_t peerlen)
|
||||
{
|
||||
int i, req_id, req_code;
|
||||
static char username[256];
|
||||
char peerstr[NI_MAXHOST + NI_MAXSERV + 30];
|
||||
struct radiusd_authentication *authen;
|
||||
struct radiusd_client *client;
|
||||
struct radius_query *q = NULL;
|
||||
#define in(_x) (((struct sockaddr_in *)_x)->sin_addr)
|
||||
#define in6(_x) (((struct sockaddr_in6 *)_x)->sin6_addr)
|
||||
|
||||
/* Check the client's Message-Authenticator */
|
||||
if (client->msgauth_required &&
|
||||
!radius_has_attr(packet,
|
||||
RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: "
|
||||
"no message authenticator",
|
||||
radius_code_string(req_code), req_code, peerstr,
|
||||
req_id);
|
||||
goto on_error;
|
||||
}
|
||||
req_id = radius_get_id(packet);
|
||||
req_code = radius_get_code(packet);
|
||||
/* prepare some information about this messages */
|
||||
if (addrport_tostring(peer, peerlen, peerstr, sizeof(peerstr)) ==
|
||||
NULL) {
|
||||
log_warn("%s: getnameinfo() failed", __func__);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if (radius_has_attr(packet,
|
||||
RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
|
||||
radius_check_message_authenticator(packet, client->secret)
|
||||
!= 0) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: "
|
||||
"bad message authenticator",
|
||||
radius_code_string(req_code), req_code, peerstr,
|
||||
req_id);
|
||||
goto on_error;
|
||||
}
|
||||
/*
|
||||
* Find a matching `client' entry
|
||||
*/
|
||||
TAILQ_FOREACH(client, &listn->radiusd->client, next) {
|
||||
if (client->af != peer->sa_family)
|
||||
continue;
|
||||
if (peer->sa_family == AF_INET && IPv4_cmp(
|
||||
&in(peer), &client->addr, &client->mask))
|
||||
break;
|
||||
else if (peer->sa_family == AF_INET6 && IPv6_cmp(
|
||||
&in6(peer), &client->addr, &client->mask))
|
||||
break;
|
||||
}
|
||||
if (client == NULL) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: no `client' "
|
||||
"matches", radius_code_string(req_code), req_code, peerstr,
|
||||
req_id);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a duplicate request. In RFC 2865, it has the same
|
||||
* source IP address and source UDP port and Identifier.
|
||||
*/
|
||||
TAILQ_FOREACH(q, &listn->radiusd->query, next) {
|
||||
if (peer.ss_family == q->clientaddr.ss_family &&
|
||||
((peer.ss_family == AF_INET &&
|
||||
in(&q->clientaddr).s_addr ==
|
||||
in(&peer).s_addr) ||
|
||||
(peer.ss_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(
|
||||
&in6(&q->clientaddr), &in6(&peer)))) &&
|
||||
((struct sockaddr_in *)&q->clientaddr)->sin_port ==
|
||||
((struct sockaddr_in *)&peer)->sin_port &&
|
||||
req_id == q->req_id)
|
||||
break; /* found it */
|
||||
}
|
||||
if (q != NULL) {
|
||||
log_info("Received %s(code=%d) from %s id=%d: "
|
||||
"duplicate request by q=%u",
|
||||
radius_code_string(req_code), req_code, peerstr,
|
||||
req_id, q->id);
|
||||
/* XXX RFC 5080 suggests to answer the cached result */
|
||||
goto on_error;
|
||||
}
|
||||
/* Check the client's Message-Authenticator */
|
||||
if (client->msgauth_required && !radius_has_attr(packet,
|
||||
RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: no message "
|
||||
"authenticator", radius_code_string(req_code), req_code,
|
||||
peerstr, req_id);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* FIXME: we can support other request codes */
|
||||
if (req_code != RADIUS_CODE_ACCESS_REQUEST) {
|
||||
log_info("Received %s(code=%d) from %s id=%d: %s "
|
||||
"is not supported in this implementation",
|
||||
radius_code_string(req_code), req_code, peerstr,
|
||||
req_id, radius_code_string(req_code));
|
||||
goto on_error;
|
||||
}
|
||||
if (radius_has_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
|
||||
radius_check_message_authenticator(packet, client->secret) != 0) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d: bad message "
|
||||
"authenticator", radius_code_string(req_code), req_code,
|
||||
peerstr, req_id);
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a duplicate request. In RFC 2865, it has the same source IP
|
||||
* address and source UDP port and Identifier.
|
||||
*/
|
||||
TAILQ_FOREACH(q, &listn->radiusd->query, next) {
|
||||
if (peer->sa_family == q->clientaddr.ss_family &&
|
||||
((peer->sa_family == AF_INET && in(&q->clientaddr).s_addr ==
|
||||
in(peer).s_addr) || (peer->sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&in6(&q->clientaddr), &in6(peer)))) &&
|
||||
((struct sockaddr_in *)&q->clientaddr)->sin_port ==
|
||||
((struct sockaddr_in *)peer)->sin_port &&
|
||||
req_id == q->req_id)
|
||||
break; /* found it */
|
||||
}
|
||||
if (q != NULL) {
|
||||
log_info("Received %s(code=%d) from %s id=%d: duplicate "
|
||||
"request by q=%u", radius_code_string(req_code), req_code,
|
||||
peerstr, req_id, q->id);
|
||||
/* XXX RFC 5080 suggests to answer the cached result */
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
if ((q = calloc(1, sizeof(struct radius_query))) == NULL) {
|
||||
log_warn("%s: Out of memory", __func__);
|
||||
goto on_error;
|
||||
}
|
||||
if (radius_get_string_attr(packet, RADIUS_TYPE_USER_NAME, username,
|
||||
sizeof(username)) != 0) {
|
||||
log_info("Received %s(code=%d) from %s id=%d: no User-Name "
|
||||
"attribute", radius_code_string(req_code), req_code,
|
||||
peerstr, req_id);
|
||||
} else
|
||||
strlcpy(q->username, username, sizeof(q->username));
|
||||
|
||||
q->id = ++radius_query_id_seq;
|
||||
q->clientaddrlen = peerlen;
|
||||
memcpy(&q->clientaddr, peer, peerlen);
|
||||
q->listen = listn;
|
||||
q->req = packet;
|
||||
q->client = client;
|
||||
q->req_id = req_id;
|
||||
radius_get_authenticator(packet, q->req_auth);
|
||||
packet = NULL;
|
||||
TAILQ_INSERT_TAIL(&listn->radiusd->query, q, next);
|
||||
|
||||
switch (req_code) {
|
||||
case RADIUS_CODE_ACCESS_REQUEST:
|
||||
/*
|
||||
* Find a matching `authenticate' entry
|
||||
*/
|
||||
if (radius_get_string_attr(packet, RADIUS_TYPE_USER_NAME,
|
||||
username, sizeof(username)) != 0) {
|
||||
log_info("Received %s(code=%d) from %s id=%d: "
|
||||
"no User-Name attribute",
|
||||
radius_code_string(req_code), req_code, peerstr,
|
||||
req_id);
|
||||
goto on_error;
|
||||
}
|
||||
TAILQ_FOREACH(authen, &listn->radiusd->authen, next) {
|
||||
for (i = 0; authen->username[i] != NULL; i++) {
|
||||
if (fnmatch(authen->username[i], username, 0)
|
||||
|
@ -487,7 +495,7 @@ radiusd_listen_on_event(int fd, short evmask, void *ctx)
|
|||
goto found;
|
||||
}
|
||||
}
|
||||
found:
|
||||
found:
|
||||
if (authen == NULL) {
|
||||
log_warnx("Received %s(code=%d) from %s id=%d "
|
||||
"username=%s: no `authenticate' matches.",
|
||||
|
@ -495,7 +503,7 @@ found:
|
|||
req_id, username);
|
||||
goto on_error;
|
||||
}
|
||||
RADIUSD_ASSERT(authen->auth != NULL);
|
||||
q->authen = authen;
|
||||
|
||||
if (!MODULE_DO_USERPASS(authen->auth->module) &&
|
||||
!MODULE_DO_ACCSREQ(authen->auth->module)) {
|
||||
|
@ -505,42 +513,32 @@ found:
|
|||
req_id, username, authen->auth->module->name);
|
||||
goto on_error;
|
||||
}
|
||||
if ((q = calloc(1, sizeof(struct radius_query))) == NULL) {
|
||||
log_warn("%s: Out of memory", __func__);
|
||||
goto on_error;
|
||||
}
|
||||
memcpy(&q->clientaddr, &peer, peersz);
|
||||
strlcpy(q->username, username, sizeof(q->username));
|
||||
q->id = ++radius_query_id_seq;
|
||||
q->clientaddrlen = peersz;
|
||||
q->authen = authen;
|
||||
q->listen = listn;
|
||||
q->req = packet;
|
||||
q->client = client;
|
||||
q->req_id = req_id;
|
||||
radius_get_authenticator(packet, q->req_auth);
|
||||
|
||||
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);
|
||||
|
||||
radius_query_request(q);
|
||||
|
||||
raidus_query_access_request(q);
|
||||
return;
|
||||
default:
|
||||
log_info("Received %s(code=%d) from %s id=%d: %s is not "
|
||||
"supported in this implementation", radius_code_string(
|
||||
req_code), req_code, peerstr, req_id, radius_code_string(
|
||||
req_code));
|
||||
break;
|
||||
}
|
||||
on_error:
|
||||
if (packet != NULL)
|
||||
radius_delete_packet(packet);
|
||||
if (q != NULL)
|
||||
radiusd_access_request_aborted(q);
|
||||
#undef in
|
||||
#undef in6
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
radius_query_request(struct radius_query *q)
|
||||
raidus_query_access_request(struct radius_query *q)
|
||||
{
|
||||
struct radiusd_authentication *authen = q->authen;
|
||||
|
||||
|
@ -566,7 +564,7 @@ radius_query_request(struct radius_query *q)
|
|||
}
|
||||
|
||||
static void
|
||||
radius_query_response(struct radius_query *q)
|
||||
radius_query_access_response(struct radius_query *q)
|
||||
{
|
||||
int sz, res_id, res_code;
|
||||
char buf[NI_MAXHOST + NI_MAXSERV + 30];
|
||||
|
@ -609,7 +607,6 @@ radius_query_response(struct radius_query *q)
|
|||
log_warn("Sending a RADIUS response failed");
|
||||
on_error:
|
||||
radiusd_access_request_aborted(q);
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -643,7 +640,7 @@ radiusd_access_request_answer(struct radius_query *q)
|
|||
}
|
||||
|
||||
RADIUSD_ASSERT(q->deco == NULL);
|
||||
radius_query_response(q);
|
||||
radius_query_access_response(q);
|
||||
|
||||
return;
|
||||
on_error:
|
||||
|
@ -957,7 +954,8 @@ radiusd_module_load(struct radiusd *radiusd, const char *path, const char *name)
|
|||
goto on_error;
|
||||
}
|
||||
if (fcntl(module->fd, F_SETFL, ival | O_NONBLOCK) == -1) {
|
||||
log_warn("Could not load module `%s': fcntl(F_SETFL,O_NONBLOCK)",
|
||||
log_warn(
|
||||
"Could not load module `%s': fcntl(F_SETFL,O_NONBLOCK)",
|
||||
name);
|
||||
goto on_error;
|
||||
}
|
||||
|
@ -1281,7 +1279,7 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
|
|||
radius_delete_packet(q->req);
|
||||
q->req = radpkt;
|
||||
}
|
||||
radius_query_request(q);
|
||||
raidus_query_access_request(q);
|
||||
break;
|
||||
case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
|
||||
if (radpkt == NULL) {
|
||||
|
@ -1299,7 +1297,7 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
|
|||
q->req);
|
||||
q->res = radpkt;
|
||||
}
|
||||
radius_query_response(q);
|
||||
radius_query_access_response(q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue