Add "authentication-filter". Add new 2 imsg types so that
authoryasuoka <yasuoka@openbsd.org>
Sun, 14 Jul 2024 15:27:57 +0000 (15:27 +0000)
committeryasuoka <yasuoka@openbsd.org>
Sun, 14 Jul 2024 15:27:57 +0000 (15:27 +0000)
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
usr.sbin/radiusd/radiusd.c
usr.sbin/radiusd/radiusd.h
usr.sbin/radiusd/radiusd_local.h
usr.sbin/radiusd/radiusd_module.c
usr.sbin/radiusd/radiusd_module.h

index b8dc055..294f6a1 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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 <v.string>              STRING
 %token <v.number>              NUMBER
 %type  <v.number>              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)
 {
index 973ce74..c3e8382 100644 (file)
@@ -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)
index 047311a..240fcf9 100644 (file)
@@ -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 {
index 439f12f..32feca0 100644 (file)
@@ -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);
index 33fe547..02b3839 100644 (file)
@@ -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 <yasuoka@yasuoka.net>
@@ -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);
index 9b3b847..f33c876 100644 (file)
@@ -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);