]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
allow detail files to be in any virtual server.
authorAlan T. DeKok <aland@freeradius.org>
Wed, 17 Mar 2021 17:46:11 +0000 (13:46 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Wed, 17 Mar 2021 18:06:20 +0000 (14:06 -0400)
Currently not allowed in RADIUS, but that has to be fixed :(

raddb/sites-available/detail
src/listen/detail/all.mk
src/listen/detail/proto_detail.c
src/listen/detail/proto_detail.h
src/listen/detail/proto_detail_process.c [deleted file]
src/listen/detail/proto_detail_process.mk [deleted file]

index 2a14d6b490ed5e852d8531ea9e5b4268a70d35d5..ca24d2e590a47b188aacece6e8d18d1e6f4dae35 100644 (file)
@@ -12,7 +12,9 @@ server detail {
        #  In v4, all "server" sections MUST start with a "namespace"
        #  parameter.  This tells the server which protocol is being used.
        #
-       namespace = detail
+       #  RADIUS, or DHCPv4, or any other protocol supported by the server.
+       #
+       namespace = radius
 
        #
        #  This virtual server will read detail files from the
@@ -21,28 +23,16 @@ server detail {
        directory = ${radacctdir}/detail
 
        listen {
-               #
-               #  This has to be listed first, sorry.
-               #
-               #  The value given here must match the `namespace` of
-               #  the virtual server which originally created the
-               #  detail files.
-               #
-               dictionary = radius
-
                #
                #  Types of packets we are reading.
                #
                type = Accounting-Request
 
                #
-               #  What transports are being used to read detail
-               #  files.  For now, only "file" is supported.
-               #
-               #  Future releases will allow reading "detail"
-               #  style information from sockets or streams.
+               #  There is no need to specify a transport.
+               #  The default is `file`, which is the only
+               #  one supported.
                #
-               transport = file
 
                #
                #  Unlike v3, there is no "load_factor" configuration.
@@ -231,10 +221,9 @@ server detail {
        }
 
 #
-#  All packets read by the detail listener are processed through the
-#  'recv' section.  Note that there is no second name to the section.
+#  The detail file reader runs the normal RADIUS / DHCP / etc. processing sections.
 #
-recv {
+recv Accounting-Request {
        update request {
                &Acct-Delay-Time := "%{expr:%{%{Acct-Delay-Time}:-0} + %c - %{%{integer:Event-Timestamp}:-%{integer:Packet-Original-Timestamp}}}"
        }
@@ -253,35 +242,26 @@ recv {
        #
 }
 
-#
-#  All successful packets sent by the detail listener are processed through the
-#  'send ok' section.  Note that the name is the same for all packet types.
 #
 #  If the listener is configured with 'track = yes', then the entry in
 #  the detail file is marked up as being "done".  Subsequent re-reads
 #  of the same detail file (e.g. on server restart) will skip the
 #  "done" entries.
 #
-send ok {
+send Accounting-Response {
        ok
 }
 
 #
-#  All failed packets sent by the detail listener are processed through the
-#  'send fail' section.  Note that the name is the same for all packet types.
+#  All failed packets sent by the detail listener should be processed
+#  through the 'send Do-Not-Respond' section.
 #
 #  If the listener is configured with 'track = yes', then the packet
 #  will be retransmitted by the detail file reader, until the packet
 #  returns "success".  See the "limit" subsection above for retransmission
 #  configuration.
 #
-send fail {
+send Do-Not-Respond {
        ok
 }
-
-#
-#  Note that unlike other listeners, there is no "send Do-Not-Respond"
-#  section.  You should just return "fail" instead.
-#
-
 } # virtual server "detail"
index 17905d0fd8e7a6bcfef99ac3b46acd9d2946b6c9..403e1e0ecc6bc4906ac51d816520f79749627449 100644 (file)
@@ -1 +1 @@
-SUBMAKEFILES := proto_detail.mk proto_detail_file.mk proto_detail_work.mk proto_detail_process.mk
+SUBMAKEFILES := proto_detail.mk proto_detail_file.mk proto_detail_work.mk
index 2ae1c49276fb147c00b0cd0ab6af845c412b57a6..50a548ddc21fafafff96588df10492b65d91f85c 100644 (file)
@@ -33,7 +33,6 @@
 #include "proto_detail.h"
 
 extern fr_app_t proto_detail;
-static int dictionary_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule);
 static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule);
 static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule);
 
@@ -51,12 +50,10 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF
  *
  */
 static CONF_PARSER const proto_detail_config[] = {
-       { FR_CONF_OFFSET("dictionary", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY | FR_TYPE_REQUIRED, proto_detail_t,
-                         dict), .dflt = "radius", .func = dictionary_parse },
        { FR_CONF_OFFSET("type", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY | FR_TYPE_REQUIRED, proto_detail_t,
-                         type_submodule), .func = type_parse },
+                         type), .func = type_parse },
        { FR_CONF_OFFSET("transport", FR_TYPE_VOID, proto_detail_t, io_submodule),
-         .func = transport_parse },
+         .func = transport_parse, .dflt = "file" },
 
        /*
         *      Add this as a synonym so normal humans can understand it.
@@ -106,33 +103,6 @@ fr_dict_attr_autoload_t proto_detail_dict_attr[] = {
        { NULL }
 };
 
-/** Wrapper around fr_dict_t* which translates the dictionary name into a dictionary
- *
- * @param[in] ctx      to allocate data in (instance of proto_detail).
- * @param[out] out     Where to write a fr_dict_t *
- * @param[in] parent   Base structure address.
- * @param[in] ci       #CONF_PAIR specifying the name of the type module.
- * @param[in] rule     unused.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int dictionary_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
-{
-       char const              *dict_str = cf_pair_value(cf_item_to_pair(ci));
-       fr_dict_t const         *dict;
-
-       dict = fr_dict_by_protocol_name(dict_str);
-       if (!dict) {
-               cf_log_err(ci, "Unknown dictionary");
-               return -1;
-       }
-
-       *(fr_dict_t **) out = fr_dict_unconst(dict);
-
-       return 0;
-}
-
 /** Wrapper around dl_instance which translates the packet-type into a submodule name
  *
  * @param[in] ctx      to allocate data in (instance of proto_detail).
@@ -144,41 +114,39 @@ static int dictionary_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *pare
  *     - 0 on success.
  *     - -1 on failure.
  */
-static int type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
+static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule)
 {
-       dl_module_inst_t        *process_dl;
-       proto_detail_process_t  *process_inst;
-       fr_dict_attr_t const    *attr_packet_type;
        proto_detail_t          *inst = talloc_get_type_abort(parent, proto_detail_t);
-       int                     code;
+       fr_dict_enum_t const    *type_enum;
+       CONF_PAIR               *cp = cf_item_to_pair(ci);
+       char const              *value = cf_pair_value(cp);
 
+       *((char const **) out) = value;
+
+       inst->dict = virtual_server_namespace_by_ci(ci);
        if (!inst->dict) {
-               cf_log_err(ci, "Please define 'dictionary' BEFORE 'type'");
+               cf_log_err(ci, "Please define 'namespace' in this virtual server");
                return -1;
        }
 
-       attr_packet_type = fr_dict_attr_by_name(NULL, fr_dict_root(inst->dict), "Packet-Type");
-       if (!attr_packet_type) {
+       inst->attr_packet_type = fr_dict_attr_by_name(NULL, fr_dict_root(inst->dict), "Packet-Type");
+       if (!inst->attr_packet_type) {
                cf_log_err(ci, "Failed to find 'Packet-Type' attribute");
                return -1;
        }
 
-       code = fr_app_process_type_parse(ctx, out, ci, attr_packet_type, "proto_detail",
-                                        NULL, 0, NULL, 0);
-       if (code < 0) return -1;
-
-       inst->code = code;
-
-       /*
-        *      Find the process module, and tell it what dictionary
-        *      and packet type to use.
-        */
-       process_dl = *(dl_module_inst_t **) out;
-       process_inst = inst->process_instance = talloc_get_type_abort(process_dl->data, proto_detail_process_t);
+       if (!value) {
+               cf_log_err(ci, "No value given for 'type'");
+               return -1;
+       }
 
-       process_inst->dict = inst->dict;
-       process_inst->attr_packet_type = attr_packet_type;
+       type_enum = fr_dict_enum_by_name(inst->attr_packet_type, value, -1);
+       if (!type_enum) {
+               cf_log_err(ci, "Invalid type \"%s\"", value);
+               return -1;
+       }
 
+       inst->code = type_enum->value->vb_uint32;
        return 0;
 }
 
@@ -230,6 +198,7 @@ static int mod_decode(void const *instance, request_t *request, uint8_t *const d
 
        RHEXDUMP3(data, data_len, "proto_detail decode packet");
 
+       request->dict = inst->dict;
        request->packet->code = inst->code;
 
        /*
@@ -376,19 +345,11 @@ static ssize_t mod_encode(UNUSED void const *instance, request_t *request, uint8
        return 1;
 }
 
-static void mod_entry_point_set(void const *instance, request_t *request)
+static void mod_entry_point_set(UNUSED void const *instance, request_t *request)
 {
-       proto_detail_t const *inst = talloc_get_type_abort_const(instance, proto_detail_t);
-       fr_app_worker_t const *app_process;
-
-       /*
-        *      Only one "process" function: proto_detail_process.
-        */
-       app_process = (fr_app_worker_t const *)inst->type_submodule->module->common;
+       fr_assert(request->server_cs != NULL);
 
-       request->server_cs = inst->server_cs;
-       request->async->process = app_process->entry_point;
-       request->async->process_inst = inst->process_instance;
+       virtual_server_entry_point_set(request);
 }
 
 /** Open listen sockets/connect to external event source
@@ -482,7 +443,6 @@ static int mod_open(void *instance, fr_schedule_t *sc, CONF_SECTION *conf)
 static int mod_instantiate(void *instance, CONF_SECTION *conf)
 {
        proto_detail_t          *inst = talloc_get_type_abort(instance, proto_detail_t);
-       CONF_PAIR               *cp = NULL;
 
        /*
         *      Instantiate the I/O module. But DON'T instantiate the
@@ -495,26 +455,6 @@ static int mod_instantiate(void *instance, CONF_SECTION *conf)
                return -1;
        }
 
-       /*
-        *      Instantiate the process module.
-        */
-       while ((cp = cf_pair_find_next(conf, cp, "type")) != NULL) {
-               fr_app_worker_t const *app_process;
-
-#ifdef __clang_analyzer__
-               DEBUG("Instantiating %s", cf_pair_value(cp));
-#endif
-
-               app_process = (fr_app_worker_t const *)inst->type_submodule->module->common;
-               if (app_process->instantiate && (app_process->instantiate(inst->type_submodule->data,
-                                                                         inst->type_submodule->conf) < 0)) {
-                       cf_log_err(conf, "Instantiation failed for \"%s\"", app_process->name);
-                       return -1;
-               }
-
-               break;
-       }
-
        /*
         *      These configuration items are not printed by default,
         *      because normal people shouldn't be touching them.
@@ -558,7 +498,6 @@ static int mod_instantiate(void *instance, CONF_SECTION *conf)
 static int mod_bootstrap(void *instance, CONF_SECTION *conf)
 {
        proto_detail_t          *inst = talloc_get_type_abort(instance, proto_detail_t);
-       CONF_PAIR               *cp = NULL;
 
        /*
         *      The listener is inside of a virtual server.
@@ -569,21 +508,6 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
 
        virtual_server_dict_set(inst->server_cs, inst->dict, false);
 
-       /*
-        *      Bootstrap the process module.
-        */
-       while ((cp = cf_pair_find_next(conf, cp, "type"))) {
-               dl_module_t const       *module = talloc_get_type_abort_const(inst->type_submodule->module,
-                                                                             dl_module_t);
-               fr_app_worker_t const   *app_process = (fr_app_worker_t const *)(module->common);
-
-               if (app_process->bootstrap && (app_process->bootstrap(inst->type_submodule->data,
-                                                                     inst->type_submodule->conf) < 0)) {
-                       cf_log_err(conf, "Bootstrap failed for \"%s\"", app_process->name);
-                       return -1;
-               }
-       }
-
        /*
         *      No IO module, it's an empty listener.  That's not
         *      allowed for the detail file reader.
index ac005661dde4ceeb374061dceb3a7591e56ac1e4..376e1e63ef477a0809c4d8ca4e19510a08b2334d 100644 (file)
@@ -33,15 +33,11 @@ RCSIDH(detail_h, "$Id$")
 extern "C" {
 #endif
 
-typedef struct {
-       fr_dict_t                       *dict;                          //!< root dictionary
-       fr_dict_attr_t const            *attr_packet_type;
-} proto_detail_process_t;
-
 typedef struct {
        CONF_SECTION                    *server_cs;                     //!< server CS for this listener
        CONF_SECTION                    *cs;                            //!< my configuration
        fr_app_t                        *self;                          //!< child / parent linking issues
+       char const                      *type;                          //!< packet type name
 
        dl_module_inst_t                *io_submodule;                  //!< As provided by the transport_parse
                                                                        ///< callback.  Broken out into the
@@ -58,10 +54,8 @@ typedef struct {
        void                            *work_io_instance;              //!< Easy access to the app_io instance.
        CONF_SECTION                    *work_io_conf;                  //!< Easy access to the app_io's config secti
 
-       void                            *process_instance;              //!< app_process instance
-
-       fr_dict_t                       *dict;                          //!< root dictionary
-       dl_module_inst_t                *type_submodule;                //!< Instance of the type
+       fr_dict_t const                 *dict;                          //!< root dictionary
+       fr_dict_attr_t const            *attr_packet_type;
 
        uint32_t                        code;                           //!< packet code to use for incoming packets
        uint32_t                        max_packet_size;                //!< for message ring buffer
diff --git a/src/listen/detail/proto_detail_process.c b/src/listen/detail/proto_detail_process.c
deleted file mode 100644 (file)
index a27a33b..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file proto_detail_process.c
- * @brief Detail file processing
- *
- * @copyright 2017 The FreeRADIUS server project.
- * @copyright 2017 Alan DeKok (aland@deployingradius.com)
- */
-#include <freeradius-devel/io/application.h>
-#include <freeradius-devel/server/protocol.h>
-#include <freeradius-devel/server/module.h>
-#include <freeradius-devel/unlang/base.h>
-#include <freeradius-devel/util/dict.h>
-#include <freeradius-devel/server/state.h>
-#include <freeradius-devel/util/debug.h>
-#include <freeradius-devel/radius/radius.h>
-
-#include "proto_detail.h"
-
-static fr_dict_t const *dict_freeradius;
-
-extern fr_dict_autoload_t proto_detail_process_dict[];
-fr_dict_autoload_t proto_detail_process_dict[] = {
-       { .out = &dict_freeradius, .proto = "freeradius" },
-
-       { NULL }
-};
-
-extern fr_dict_attr_autoload_t proto_detail_process_dict_attr[];
-fr_dict_attr_autoload_t proto_detail_process_dict_attr[] = {
-       { NULL }
-};
-
-static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
-{
-       proto_detail_process_t const    *inst = talloc_get_type_abort_const(mctx->instance, proto_detail_process_t);
-       fr_pair_t                       *vp;
-       rlm_rcode_t                     rcode;
-       CONF_SECTION                    *unlang;
-
-       REQUEST_VERIFY(request);
-
-       switch (request->request_state) {
-       case REQUEST_INIT:
-               RDEBUG("Received %s ID %i",
-                      fr_dict_enum_name_by_value(inst->attr_packet_type, fr_box_uint32(request->packet->code)),
-                      request->packet->id);
-               log_request_pair_list(L_DBG_LVL_1, request, NULL, &request->request_pairs, NULL);
-
-               request->component = "radius";
-
-               unlang = cf_section_find(request->server_cs, "recv", NULL);
-               if (!unlang) {
-                       REDEBUG("Failed to find 'recv' section");
-                       RETURN_MODULE_FAIL;
-               }
-
-               RDEBUG("Running 'recv' from file %s", cf_filename(unlang));
-               if (unlang_interpret_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME) < 0) {
-                       RETURN_MODULE_FAIL;
-               }
-
-               request->request_state = REQUEST_RECV;
-               FALL_THROUGH;
-
-       case REQUEST_RECV:
-               rcode = unlang_interpret(request);
-
-               if (request->master_state == REQUEST_STOP_PROCESSING) {
-                       *p_result = RLM_MODULE_HANDLED;
-                       return UNLANG_ACTION_STOP_PROCESSING;
-               }
-
-               if (rcode == RLM_MODULE_YIELD) RETURN_MODULE_YIELD;
-
-               switch (rcode) {
-               /*
-                *      The module has a number of OK return codes.
-                */
-               case RLM_MODULE_OK:
-               case RLM_MODULE_UPDATED:
-                       switch (request->packet->code) {
-                       case FR_CODE_ACCOUNTING_REQUEST:
-                               request->reply->code = FR_CODE_ACCOUNTING_RESPONSE;
-                               break;
-
-                       case FR_CODE_COA_REQUEST:
-                               request->reply->code = FR_CODE_COA_ACK;
-                               break;
-
-                       case FR_CODE_DISCONNECT_REQUEST:
-                               request->reply->code = FR_CODE_DISCONNECT_ACK;
-                               break;
-
-                       default:
-                               request->reply->code = 0;
-                               break;
-                       }
-                       FALL_THROUGH;
-
-               case RLM_MODULE_HANDLED:
-                       unlang = cf_section_find(request->server_cs, "send", "ok");
-                       break;
-
-               /*
-                *      The module failed, or said the request is
-                *      invalid, therefore we stop here.
-                */
-               case RLM_MODULE_NOOP:
-               case RLM_MODULE_FAIL:
-               case RLM_MODULE_INVALID:
-               case RLM_MODULE_NOTFOUND:
-               case RLM_MODULE_REJECT:
-               case RLM_MODULE_DISALLOW:
-               default:
-                       request->reply->code = 0;
-                       unlang = cf_section_find(request->server_cs, "send", "fail");
-                       break;
-               }
-
-               /*
-                *      Allow for over-ride of reply code.
-                */
-               vp = fr_pair_find_by_da(&request->reply_pairs, inst->attr_packet_type);
-               if (vp) request->reply->code = vp->vp_uint32;
-
-               if (request->reply->code == FR_CODE_DO_NOT_RESPOND) {
-                       RWARN("Ignoring 'do_not_respond' as it does not apply to detail files");
-               }
-
-               if (!unlang) goto send_reply;
-
-               RDEBUG("Running 'send %s { ... }' from file %s", cf_section_name2(unlang), cf_filename(unlang));
-               if (unlang_interpret_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME) < 0) {
-                       RETURN_MODULE_FAIL;
-               }
-
-               request->request_state = REQUEST_SEND;
-               FALL_THROUGH;
-
-       case REQUEST_SEND:
-               rcode = unlang_interpret(request);
-
-               if (request->master_state == REQUEST_STOP_PROCESSING) {
-                       *p_result = RLM_MODULE_HANDLED;
-                       return UNLANG_ACTION_STOP_PROCESSING;
-               }
-
-               if (rcode == RLM_MODULE_YIELD) RETURN_MODULE_YIELD;
-
-               switch (rcode) {
-               case RLM_MODULE_NOOP:
-               case RLM_MODULE_OK:
-               case RLM_MODULE_UPDATED:
-               case RLM_MODULE_HANDLED:
-                       /* reply is already set */
-                       break;
-
-               default:
-                       request->reply->code = 0;
-                       break;
-               }
-
-       send_reply:
-               /*
-                *      Failed, but we still reply with a magic code,
-                *      so that the reader can retransmit.
-                */
-               if (!request->reply->code) {
-                       REDEBUG("Failed ID %i", request->reply->id);
-               } else {
-                       RDEBUG("Sent %s ID %i",
-                              fr_dict_enum_name_by_value(inst->attr_packet_type, fr_box_uint32(request->reply->code)),
-                              request->reply->id);
-               }
-
-               log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, &request->reply_pairs, NULL);
-               break;
-
-       default:
-               RETURN_MODULE_FAIL;
-       }
-
-       RETURN_MODULE_OK;
-}
-
-
-static const virtual_server_compile_t compile_list[] = {
-       { .name = "recv", .name2 = NULL,        .component = MOD_AUTHORIZE },
-       { .name = "send", .name2 = "ok",        .component = MOD_POST_AUTH },
-       { .name = "send", .name2 = "fail",      .component = MOD_POST_AUTH },
-
-       COMPILE_TERMINATOR
-};
-
-
-static int mod_instantiate(void *instance, CONF_SECTION *conf)
-{
-       proto_detail_process_t *inst = talloc_get_type_abort(instance, proto_detail_process_t);
-       CONF_SECTION            *server_cs;
-       tmpl_rules_t            parse_rules;
-
-       /*
-        *      The detail file reader gets its dictionary from the
-        *      configuration, and not from a static protocol.  So we
-        *      have to set it manually.
-        */
-       memset(&parse_rules, 0, sizeof(parse_rules));
-       parse_rules.dict_def = inst->dict;
-
-       /*
-        *      We are passed a CONF_SECTION for our configuration.
-        *      The parent is the listener, and it's parent is the
-        *      virtual server.
-        */
-       server_cs = cf_item_to_section(cf_parent(cf_parent(conf)));
-       fr_assert(strcmp(cf_section_name1(server_cs), "server") == 0);
-
-       return virtual_server_compile_sections(server_cs, compile_list, &parse_rules, inst);
-}
-
-
-extern fr_app_worker_t proto_detail_process;
-fr_app_worker_t proto_detail_process = {
-       .magic          = RLM_MODULE_INIT,
-       .name           = "detail_process",
-       .inst_size      = sizeof(proto_detail_process_t),
-       .instantiate    = mod_instantiate,
-       .entry_point    = mod_process,
-};
diff --git a/src/listen/detail/proto_detail_process.mk b/src/listen/detail/proto_detail_process.mk
deleted file mode 100644 (file)
index 1a1d89f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-TARGETNAME     := proto_detail_process
-
-ifneq "$(TARGETNAME)" ""
-TARGET         := $(TARGETNAME).a
-endif
-
-SOURCES                := proto_detail_process.c
-
-TGT_PREREQS    := libfreeradius-util.a