From ed1dc9254db8b073d7fd62fc1db77495f408fd33 Mon Sep 17 00:00:00 2001 From: yasuoka Date: Sun, 14 Jul 2024 15:27:57 +0000 Subject: [PATCH] Add "authentication-filter". Add new 2 imsg types so that authentication modules can request the next authentication and the next authentication can receive the result of the previous and modify the result. --- usr.sbin/radiusd/parse.y | 92 +++++++---- usr.sbin/radiusd/radiusd.c | 250 ++++++++++++++++++++++-------- usr.sbin/radiusd/radiusd.h | 7 +- usr.sbin/radiusd/radiusd_local.h | 8 +- usr.sbin/radiusd/radiusd_module.c | 26 +++- usr.sbin/radiusd/radiusd_module.h | 5 + 6 files changed, 290 insertions(+), 98 deletions(-) diff --git a/usr.sbin/radiusd/parse.y b/usr.sbin/radiusd/parse.y index b8dc055eef1..294f6a1815c 100644 --- a/usr.sbin/radiusd/parse.y +++ b/usr.sbin/radiusd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.24 2024/07/14 13:44:30 yasuoka Exp $ */ +/* $OpenBSD: parse.y,v 1.25 2024/07/14 15:27:57 yasuoka Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -41,7 +41,10 @@ static struct radiusd_authentication authen; static struct radiusd_module *conf_module = NULL; static struct radiusd_client client; -static struct radiusd_module *find_module(const char *); +static struct radiusd_authentication + *create_authen(const char *, char **, int, char **); +static struct radiusd_module + *find_module(const char *); static void free_str_l(void *); static struct radiusd_module_ref *create_module_ref(const char *); static void radiusd_authentication_init(struct radiusd_authentication *); @@ -92,8 +95,8 @@ typedef struct { %} %token INCLUDE LISTEN ON PORT CLIENT SECRET LOAD MODULE MSGAUTH_REQUIRED -%token ACCOUNT ACCOUNTING AUTHENTICATE AUTHENTICATE_BY BY DECORATE_BY QUICK -%token SET TO ERROR YES NO +%token ACCOUNT ACCOUNTING AUTHENTICATE AUTHENTICATE_BY AUTHENTICATION_FILTER +%token BY DECORATE_BY QUICK SET TO ERROR YES NO %token STRING %token NUMBER %type optport optacct @@ -385,40 +388,30 @@ key : STRING ; authenticate : AUTHENTICATE str_l BY STRING optdeco { - int i; struct radiusd_authentication *auth; - struct radiusd_module_ref *modref, *modreft; - if ((auth = calloc(1, - sizeof(struct radiusd_authentication))) == NULL) { - yyerror("Out of memory: %s", strerror(errno)); - goto authenticate_error; - } - if ((auth->auth = create_module_ref($4)) == NULL) - goto authenticate_error; - auth->username = $2.v; - TAILQ_INIT(&auth->deco); - for (i = 0; i < $5.c; i++) { - if ((modref = create_module_ref($5.v[i])) - == NULL) - goto authenticate_error; - TAILQ_INSERT_TAIL(&auth->deco, modref, next); - } - TAILQ_INSERT_TAIL(&conf->authen, auth, next); - auth = NULL; - authenticate_error: - if (auth != NULL) { - free(auth->auth); - TAILQ_FOREACH_SAFE(modref, &auth->deco, next, - modreft) { - TAILQ_REMOVE(&auth->deco, modref, next); - free(modref); - } + auth = create_authen($4, $2.v, $5.c, $5.v); + free($4); + free_str_l(&$5); + if (auth == NULL) { free_str_l(&$2); - } - free(auth); + YYERROR; + } else + TAILQ_INSERT_TAIL(&conf->authen, auth, next); + } + | AUTHENTICATION_FILTER str_l BY STRING optdeco { + struct radiusd_authentication *auth; + + auth = create_authen($4, $2.v, $5.c, $5.v); free($4); free_str_l(&$5); + if (auth == NULL) { + free_str_l(&$2); + YYERROR; + } else { + auth->isfilter = true; + TAILQ_INSERT_TAIL(&conf->authen, auth, next); + } } /* the followings are for backward compatibilities */ | AUTHENTICATE str_l optnl '{' { @@ -609,6 +602,7 @@ lookup(char *s) { "accounting", ACCOUNTING}, { "authenticate", AUTHENTICATE}, { "authenticate-by", AUTHENTICATE_BY}, + { "authentication-filter", AUTHENTICATION_FILTER}, { "by", BY}, { "client", CLIENT}, { "decorate-by", DECORATE_BY}, @@ -940,6 +934,38 @@ out: return (errors ? -1 : 0); } +static struct radiusd_authentication * +create_authen(const char *byname, char **username, int decoc, char **deco) +{ + int i; + struct radiusd_authentication *auth; + struct radiusd_module_ref *modref, *modreft; + + if ((auth = calloc(1, sizeof(struct radiusd_authentication))) + == NULL) { + yyerror("Out of memory: %s", strerror(errno)); + return (NULL); + } + if ((auth->auth = create_module_ref(byname)) == NULL) + goto on_error; + + auth->username = username; + TAILQ_INIT(&auth->deco); + for (i = 0; i < decoc; i++) { + if ((modref = create_module_ref(deco[i])) == NULL) + goto on_error; + TAILQ_INSERT_TAIL(&auth->deco, modref, next); + } + return (auth); + on_error: + TAILQ_FOREACH_SAFE(modref, &auth->deco, next, modreft) { + TAILQ_REMOVE(&auth->deco, modref, next); + free(modref); + } + free(auth); + return (NULL); +} + static struct radiusd_module * find_module(const char *name) { diff --git a/usr.sbin/radiusd/radiusd.c b/usr.sbin/radiusd/radiusd.c index 973ce748f27..c3e8382d559 100644 --- a/usr.sbin/radiusd/radiusd.c +++ b/usr.sbin/radiusd/radiusd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd.c,v 1.48 2024/07/14 13:36:44 yasuoka Exp $ */ +/* $OpenBSD: radiusd.c,v 1.49 2024/07/14 15:27:57 yasuoka Exp $ */ /* * Copyright (c) 2013, 2023 Internet Initiative Japan Inc. @@ -66,13 +66,13 @@ static void raidus_query_access_request(struct radius_query *); static void radius_query_access_response(struct radius_query *); static void raidus_query_accounting_request( struct radiusd_accounting *, struct radius_query *); -static void radius_query_accounting_response(struct radius_query *); +static void radius_query_accounting_response( + struct radius_query *); +static const char *radius_query_client_secret(struct radius_query *); static const char *radius_code_string(int); static const char *radius_acct_status_type_string(uint32_t); -static int radiusd_access_response_fixup (struct radius_query *); - - - +static int radiusd_access_response_fixup(struct radius_query *, + struct radius_query *, bool); static void radiusd_module_reset_ev_handler( struct radiusd_module *); static int radiusd_module_imsg_read(struct radiusd_module *); @@ -90,6 +90,8 @@ 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_next_response(struct radiusd_module *, + struct radius_query *, RADIUS_PACKET *); static void radiusd_module_request_decoration( struct radiusd_module *, struct radius_query *); static void radiusd_module_response_decoration( @@ -678,9 +680,12 @@ raidus_query_access_request(struct radius_query *q) static void radius_query_access_response(struct radius_query *q) { - int sz, res_id, res_code; - char buf[NI_MAXHOST + NI_MAXSERV + 30]; + int sz, res_id, res_code; + char buf[NI_MAXHOST + NI_MAXSERV + 30]; + struct radius_query *q_last, *q0; + q_last = q; + next: /* first or next response decoration */ for (;;) { if (q->deco == NULL) @@ -696,7 +701,24 @@ radius_query_access_response(struct radius_query *q) return; } - if (radiusd_access_response_fixup(q) != 0) + if (q->prev != NULL) { + if (MODULE_DO_NEXTRES(q->prev->authen->auth->module)) { + if (radiusd_access_response_fixup(q->prev, q_last, 0) + != 0) + goto on_error; + q0 = q; + q = q->prev; + radiusd_module_next_response(q->authen->auth->module, + q, q_last->res); + q0->prev = NULL; + radiusd_access_request_aborted(q0); + return; + } + q = q->prev; + goto next; + } + + if (radiusd_access_response_fixup(q, q_last, 1) != 0) goto on_error; res_id = radius_get_id(q->res); @@ -768,6 +790,21 @@ radius_query_accounting_response(struct radius_query *q) (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0) log_warn("Sending a RADIUS response failed"); } + +static const char * +radius_query_client_secret(struct radius_query *q) +{ + struct radius_query *q0; + const char *client_secret = NULL; + + for (q0 = q; q0 != NULL && client_secret == NULL; q0 = q0->prev) { + if (q0->client != NULL) + client_secret = q0->client->secret; + } + RADIUSD_ASSERT(client_secret != NULL); + + return (client_secret); +} /*********************************************************************** * Callback functions from the modules ***********************************************************************/ @@ -806,9 +843,69 @@ on_error: radiusd_access_request_aborted(q); } +void +radiusd_access_request_next(struct radius_query *q, RADIUS_PACKET *pkt) +{ + struct radius_query *q_next = NULL; + static char username[256]; + struct radiusd_authentication *authen; + int i; + + RADIUSD_ASSERT(q->deco == NULL); + + if (!q->authen->isfilter) { + log_warnx("q=%u `%s' requested next authentication, but it's " + "not authentication-filter", q->id, + q->authen->auth->module->name); + goto on_error; + } + if (radius_get_string_attr(pkt, RADIUS_TYPE_USER_NAME, username, + sizeof(username)) != 0) + username[0] = '\0'; + + for (authen = TAILQ_NEXT(q->authen, next); authen != NULL; + authen = TAILQ_NEXT(authen, next)) { + for (i = 0; authen->username[i] != NULL; i++) { + if (fnmatch(authen->username[i], username, 0) + == 0) + goto found; + } + } + found: + if (authen == NULL) { /* no more authentication */ + log_warnx("q=%u module `%s' requested next authentication " + "no more `authenticate' matches", q->id, + q->authen->auth->module->name); + goto on_error; + } + + if ((q_next = calloc(1, sizeof(struct radius_query))) == NULL) { + log_warn("%s: q=%u calloc: %m", __func__, q->id); + goto on_error; + } + q_next->id = ++radius_query_id_seq; + q_next->radiusd = q->radiusd; + q_next->req_id = q->req_id; + q_next->req = pkt; + radius_get_authenticator(pkt, q_next->req_auth); + q_next->authen = authen; + q_next->prev = q; + strlcpy(q_next->username, username, sizeof(q_next->username)); + TAILQ_INSERT_TAIL(&q->radiusd->query, q_next, next); + + raidus_query_access_request(q_next); + return; + on_error: + RADIUSD_ASSERT(q_next == NULL); + radius_delete_packet(pkt); + radiusd_access_request_aborted(q); +} + void radiusd_access_request_aborted(struct radius_query *q) { + if (q->prev != NULL) + radiusd_access_request_aborted(q->prev); if (q->req != NULL) radius_delete_packet(q->req); if (q->res != NULL) @@ -949,76 +1046,81 @@ radiusd_conf_init(struct radiusd *conf) * Fix some attributes which depend the secret value. */ static int -radiusd_access_response_fixup(struct radius_query *q) +radiusd_access_response_fixup(struct radius_query *q, struct radius_query *q0, + bool islast) { - int res_id; - size_t attrlen; - u_char req_auth[16], attrbuf[256]; - const char *authen_secret = q->authen->auth->module->secret; - - radius_get_authenticator(q->req, req_auth); - - if ((authen_secret != NULL && - strcmp(authen_secret, q->client->secret) != 0) || - timingsafe_bcmp(q->req_auth, req_auth, 16) != 0) { - const char *olds = q->client->secret; - const char *news = authen_secret; - - if (news == NULL) - news = olds; - + int res_id; + size_t attrlen; + u_char authen_req_auth[16], attrbuf[256]; + const char *client_req_auth; + const char *authen_secret, *client_secret; + + authen_secret = q0->authen->auth->module->secret; + client_secret = (islast)? q->client->secret : + q->authen->auth->module->secret; + + radius_get_authenticator(q0->req, authen_req_auth); + client_req_auth = q->req_auth; + + if (client_secret == NULL && authen_secret == NULL) + return (0); + if (!(authen_secret != NULL && client_secret != NULL && + strcmp(authen_secret, client_secret) == 0 && + timingsafe_bcmp(authen_req_auth, client_req_auth, 16) == 0)) { /* RFC 2865 Tunnel-Password */ attrlen = sizeof(attrbuf); - if (radius_get_raw_attr(q->res, RADIUS_TYPE_TUNNEL_PASSWORD, + if (radius_get_raw_attr(q0->res, RADIUS_TYPE_TUNNEL_PASSWORD, attrbuf, &attrlen) == 0) { - radius_attr_unhide(news, req_auth, - attrbuf, attrbuf + 3, attrlen - 3); - radius_attr_hide(olds, q->req_auth, - attrbuf, attrbuf + 3, attrlen - 3); - - radius_del_attr_all(q->res, + if (authen_secret != NULL) + radius_attr_unhide(authen_secret, + authen_req_auth, attrbuf, attrbuf + 3, + attrlen - 3); + if (client_secret != NULL) + radius_attr_hide(client_secret, client_req_auth, + attrbuf, attrbuf + 3, attrlen - 3); + radius_del_attr_all(q0->res, RADIUS_TYPE_TUNNEL_PASSWORD); - radius_put_raw_attr(q->res, + radius_put_raw_attr(q0->res, RADIUS_TYPE_TUNNEL_PASSWORD, attrbuf, attrlen); } /* RFC 2548 Microsoft MPPE-{Send,Recv}-Key */ attrlen = sizeof(attrbuf); - if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, + if (radius_get_vs_raw_attr(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, &attrlen) == 0) { - - /* Re-crypt the KEY */ - radius_attr_unhide(news, req_auth, - attrbuf, attrbuf + 2, attrlen - 2); - radius_attr_hide(olds, q->req_auth, - attrbuf, attrbuf + 2, attrlen - 2); - - radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT, + if (authen_secret != NULL) + radius_attr_unhide(authen_secret, + authen_req_auth, attrbuf, attrbuf + 2, + attrlen - 2); + if (client_secret != NULL) + radius_attr_hide(client_secret, client_req_auth, + attrbuf, attrbuf + 2, attrlen - 2); + radius_del_vs_attr_all(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_SEND_KEY); - radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, + radius_put_vs_raw_attr(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, attrlen); } attrlen = sizeof(attrbuf); - if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, + if (radius_get_vs_raw_attr(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, &attrlen) == 0) { - - /* Re-crypt the KEY */ - radius_attr_unhide(news, req_auth, - attrbuf, attrbuf + 2, attrlen - 2); - radius_attr_hide(olds, q->req_auth, - attrbuf, attrbuf + 2, attrlen - 2); - - radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT, + if (authen_secret != NULL) + radius_attr_unhide(authen_secret, + authen_req_auth, attrbuf, attrbuf + 2, + attrlen - 2); + if (client_secret != NULL) + radius_attr_hide(client_secret, client_req_auth, + attrbuf, attrbuf + 2, attrlen - 2); + + radius_del_vs_attr_all(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_RECV_KEY); - radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, + radius_put_vs_raw_attr(q0->res, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, attrlen); } } - - res_id = radius_get_id(q->res); + res_id = radius_get_id(q0->res); if (res_id != q->req_id) { /* authentication server change the id */ - radius_set_id(q->res, q->req_id); + radius_set_id(q0->res, q->req_id); } return (0); @@ -1426,12 +1528,13 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg) radius_put_string_attr(q->res, RADIUS_TYPE_REPLY_MESSAGE, msg); radius_set_response_authenticator(q->res, - q->client->secret); + radius_query_client_secret(q)); radiusd_access_request_answer(q); } break; } case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER: + case IMSG_RADIUSD_MODULE_ACCSREQ_NEXT: case IMSG_RADIUSD_MODULE_REQDECO_DONE: case IMSG_RADIUSD_MODULE_RESDECO_DONE: { @@ -1442,6 +1545,9 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg) case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER: typestr = "ACCSREQ_ANSWER"; break; + case IMSG_RADIUSD_MODULE_ACCSREQ_NEXT: + typestr = "ACCSREQ_NEXT"; + break; case IMSG_RADIUSD_MODULE_REQDECO_DONE: typestr = "REQDECO_DONE"; break; @@ -1502,6 +1608,15 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg) q->res = radpkt; radiusd_access_request_answer(q); break; + case IMSG_RADIUSD_MODULE_ACCSREQ_NEXT: + if (radpkt == NULL) { + log_warnx("q=%u wrong pkt from module", + q->id); + radiusd_access_request_aborted(q); + break; + } + radiusd_access_request_next(q, radpkt); + break; case IMSG_RADIUSD_MODULE_RESDECO_DONE: if (q->deco == NULL || q->deco->type != IMSG_RADIUSD_MODULE_RESDECO) { @@ -1696,7 +1811,7 @@ radiusd_module_userpass(struct radiusd_module *module, struct radius_query *q) userpass.q_id = q->id; if (radius_get_user_password_attr(q->req, userpass.pass, - sizeof(userpass.pass), q->client->secret) == 0) + sizeof(userpass.pass), radius_query_client_secret(q)) == 0) userpass.has_pass = true; else userpass.has_pass = false; @@ -1717,8 +1832,8 @@ static void radiusd_module_access_request(struct radiusd_module *module, struct radius_query *q) { - RADIUS_PACKET *radpkt; - char pass[256]; + RADIUS_PACKET *radpkt; + char pass[256]; if ((radpkt = radius_convert_packet(radius_get_data(q->req), radius_get_length(q->req))) == NULL) { @@ -1744,6 +1859,19 @@ radiusd_module_access_request(struct radiusd_module *module, radius_delete_packet(radpkt); } +static void +radiusd_module_next_response(struct radiusd_module *module, + struct radius_query *q, RADIUS_PACKET *pkt) +{ + if (imsg_compose_radius_packet(&module->ibuf, + IMSG_RADIUSD_MODULE_NEXTRES, q->id, pkt) == -1) { + log_warn("q=%u Could not send NEXTRES to `%s'", q->id, + module->name); + radiusd_access_request_aborted(q); + } + radiusd_module_reset_ev_handler(module); +} + static void radiusd_module_request_decoration(struct radiusd_module *module, struct radius_query *q) diff --git a/usr.sbin/radiusd/radiusd.h b/usr.sbin/radiusd/radiusd.h index 047311aa09a..240fcf951f1 100644 --- a/usr.sbin/radiusd/radiusd.h +++ b/usr.sbin/radiusd/radiusd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd.h,v 1.8 2024/07/09 17:26:14 yasuoka Exp $ */ +/* $OpenBSD: radiusd.h,v 1.9 2024/07/14 15:27:57 yasuoka Exp $ */ #ifndef RADIUSD_H #define RADIUSD_H 1 @@ -41,6 +41,8 @@ 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_ACCSREQ_NEXT, /* fall through to the next auth */ + IMSG_RADIUSD_MODULE_NEXTRES, /* receive the respo from tht next */ IMSG_RADIUSD_MODULE_REQDECO, IMSG_RADIUSD_MODULE_REQDECO_DONE, IMSG_RADIUSD_MODULE_RESDECO0_REQ, /* request pkt for RESDECO */ @@ -55,13 +57,14 @@ enum imsg_type { /* Module sends LOAD when it becomes ready */ struct radiusd_module_load_arg { - uint32_t cap; /* module capabity bits */ + uint32_t cap; /* module capability bits */ #define RADIUSD_MODULE_CAP_USERPASS 0x01 #define RADIUSD_MODULE_CAP_ACCSREQ 0x02 #define RADIUSD_MODULE_CAP_REQDECO 0x04 #define RADIUSD_MODULE_CAP_RESDECO 0x08 #define RADIUSD_MODULE_CAP_ACCTREQ 0x10 #define RADIUSD_MODULE_CAP_CONTROL 0x20 +#define RADIUSD_MODULE_CAP_NEXTRES 0x40 }; struct radiusd_module_object { diff --git a/usr.sbin/radiusd/radiusd_local.h b/usr.sbin/radiusd/radiusd_local.h index 439f12fa8d3..32feca0ca40 100644 --- a/usr.sbin/radiusd/radiusd_local.h +++ b/usr.sbin/radiusd/radiusd_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd_local.h,v 1.13 2024/07/14 13:36:44 yasuoka Exp $ */ +/* $OpenBSD: radiusd_local.h,v 1.14 2024/07/14 15:27:57 yasuoka Exp $ */ /* * Copyright (c) 2013 Internet Initiative Japan Inc. @@ -97,6 +97,7 @@ struct radiusd_module_ref { struct radiusd_authentication { char **username; struct radiusd_module_ref *auth; + bool isfilter; TAILQ_HEAD(,radiusd_module_ref) deco; TAILQ_ENTRY(radiusd_authentication) next; }; @@ -140,6 +141,7 @@ struct radius_query { char username[256]; /* original username */ TAILQ_ENTRY(radius_query) next; struct radiusd_module_ref *deco; + struct radius_query *prev; }; struct imsgev { @@ -186,6 +188,9 @@ extern struct radiusd *radiusd_s; #define MODULE_DO_RESDECO(_m) \ ((_m)->fd >= 0 && \ ((_m)->capabilities & RADIUSD_MODULE_CAP_RESDECO) != 0) +#define MODULE_DO_NEXTRES(_m) \ + ((_m)->fd >= 0 && \ + ((_m)->capabilities & RADIUSD_MODULE_CAP_NEXTRES) != 0) int parse_config(const char *, struct radiusd *); void radiusd_conf_init(struct radiusd *); @@ -196,6 +201,7 @@ struct radiusd_module *radiusd_module_load(struct radiusd *, const char *, void radiusd_module_unload(struct radiusd_module *); void radiusd_access_request_answer(struct radius_query *); +void radiusd_access_request_next(struct radius_query *, RADIUS_PACKET *); void radiusd_access_request_aborted(struct radius_query *); int radiusd_imsg_compose_module(struct radiusd *, const char *, uint32_t, uint32_t, pid_t, int, void *, size_t); diff --git a/usr.sbin/radiusd/radiusd_module.c b/usr.sbin/radiusd/radiusd_module.c index 33fe5476365..02b3839626b 100644 --- a/usr.sbin/radiusd/radiusd_module.c +++ b/usr.sbin/radiusd/radiusd_module.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd_module.c,v 1.18 2024/07/09 17:26:14 yasuoka Exp $ */ +/* $OpenBSD: radiusd_module.c,v 1.19 2024/07/14 15:27:57 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko @@ -46,6 +46,8 @@ 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_next_response) (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 *, @@ -98,6 +100,7 @@ module_create(int sock, void *ctx, struct module_handlers *handler) module_userpass = handler->userpass; module_access_request = handler->access_request; + module_next_response = handler->next_response; module_config_set = handler->config_set; module_request_decoration = handler->request_decoration; module_response_decoration = handler->response_decoration; @@ -157,6 +160,8 @@ 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_next_response != NULL) + load.cap |= RADIUSD_MODULE_CAP_NEXTRES; if (module_request_decoration != NULL) load.cap |= RADIUSD_MODULE_CAP_REQDECO; if (module_response_decoration != NULL) @@ -273,6 +278,14 @@ module_accsreq_answer(struct module_base *base, u_int q_id, const u_char *pkt, q_id, pkt, pktlen)); } +int +module_accsreq_next(struct module_base *base, u_int q_id, const u_char *pkt, + size_t pktlen) +{ + return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_ACCSREQ_NEXT, + q_id, pkt, pktlen)); +} + int module_accsreq_aborted(struct module_base *base, u_int q_id) { @@ -453,6 +466,7 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg) break; } case IMSG_RADIUSD_MODULE_ACCSREQ: + case IMSG_RADIUSD_MODULE_NEXTRES: case IMSG_RADIUSD_MODULE_REQDECO: case IMSG_RADIUSD_MODULE_RESDECO0_REQ: case IMSG_RADIUSD_MODULE_RESDECO: @@ -469,6 +483,13 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg) break; } typestr = "ACCSREQ"; + } else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_NEXTRES) { + if (module_next_response == NULL) { + syslog(LOG_ERR, "Received NEXTRES message, but " + "module doesn't support"); + break; + } + typestr = "NEXTRES"; } else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCTREQ) { if (module_accounting_request == NULL) { syslog(LOG_ERR, "Received ACCTREQ message, but " @@ -537,6 +558,9 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg) 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_NEXTRES) + module_next_response(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); diff --git a/usr.sbin/radiusd/radiusd_module.h b/usr.sbin/radiusd/radiusd_module.h index 9b3b8476052..f33c876de4b 100644 --- a/usr.sbin/radiusd/radiusd_module.h +++ b/usr.sbin/radiusd/radiusd_module.h @@ -38,6 +38,9 @@ struct module_handlers { size_t pktlen); /* User-Password Attribute is encrypted if the module has the secret */ + void (*next_response)(void *ctx, u_int query_id, const u_char *pkt, + size_t pktlen); + void (*request_decoration)(void *ctx, u_int query_id, const u_char *pkt, size_t pktlen); @@ -78,6 +81,8 @@ int module_userpass_fail(struct module_base *, u_int, const char *); int module_accsreq_answer(struct module_base *, u_int, const u_char *, size_t); +int module_accsreq_next(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); -- 2.20.1