]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
update to new state machine
authorAlan T. DeKok <aland@freeradius.org>
Tue, 23 Mar 2021 13:54:56 +0000 (09:54 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 31 Mar 2021 15:09:52 +0000 (16:09 +0100)
and fix a bunch of minor things, so that we have more unique
packet types

share/dictionary/tacacs/dictionary.freeradius.internal
src/listen/tacacs/proto_tacacs.c
src/listen/tacacs/proto_tacacs.h
src/process/tacacs/base.c
src/protocols/tacacs/base.c
src/protocols/tacacs/tacacs.h
src/tests/tacacs/config/radiusd.conf

index 7934c35783b11bbacdfad74df7698931404487d4..b72feece7f47913c84a5b5d721402e4b84bbd9ba 100644 (file)
@@ -17,12 +17,13 @@ FLAGS       internal
 
 ATTRIBUTE      Packet-Type                             65536   uint32
 VALUE  Packet-Type                     Authentication-Start    1
-VALUE  Packet-Type                     Authentication-Continue 2
-VALUE  Packet-Type                     Authentication-Reply    3
-VALUE  Packet-Type                     Authorization-Request   4
-VALUE  Packet-Type                     Authorization-Reply     5
-VALUE  Packet-Type                     Accounting-Request      6
-VALUE  Packet-Type                     Accounting-Reply        7
-VALUE  Packet-Type                     Do-Not-Respond          8
+VALUE  Packet-Type                     Authentication-Start-Reply      2
+VALUE  Packet-Type                     Authentication-Continue 3
+VALUE  Packet-Type                     Authentication-Continue-Reply   4
+VALUE  Packet-Type                     Authorization-Request   5
+VALUE  Packet-Type                     Authorization-Reply     6
+VALUE  Packet-Type                     Accounting-Request      7
+VALUE  Packet-Type                     Accounting-Reply        8
+VALUE  Packet-Type                     Do-Not-Respond          9
 
 ATTRIBUTE      State                           65537   octets
index ab1ebf145469974c91ccd52bad6d644a0cf382a8..e4356e8bb83e79db7ee869745430c90e3f03889c 100644 (file)
@@ -18,7 +18,6 @@
  * $Id$
  * @file proto_tacacs.c
  * @brief TACACS+ module.
- * @author Jorge Pereira <jpereira@freeradius.org>
  *
  * @copyright 2020 The FreeRADIUS server project.
  * @copyright 2020 Network RADIUS SARL (legal@networkradius.com)
@@ -110,7 +109,7 @@ static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM
        value = cf_pair_value(cp);
 
        dv = fr_dict_enum_by_name(attr_packet_type, value, -1);
-       if (!dv || (dv->value->vb_uint32 >= FR_PACKET_TYPE_MAX)) {
+       if (!dv || (dv->value->vb_uint32 >= FR_TACACS_CODE_MAX)) {
                cf_log_err(ci, "Unknown TACACS+ packet type '%s'", value);
                return -1;
        }
@@ -333,7 +332,7 @@ static ssize_t mod_encode(void const *instance, request_t *request, uint8_t *buf
         */
        if ((buffer_len == 1) ||
            (request->reply->code == FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND) ||
-           (request->reply->code == 0) || (request->reply->code >= FR_PACKET_TYPE_MAX)) {
+           (request->reply->code == 0) || (request->reply->code >= FR_TACACS_CODE_MAX)) {
                track->do_not_respond = true;
                return 1;
        }
index e499b5d6b12518ea196a6f39ee1d9a90768ff3da..8e1b8706868a6f6df50428d069937a1a553b91c6 100644 (file)
@@ -26,8 +26,6 @@
 #include <freeradius-devel/tacacs/tacacs.h>
 #include <freeradius-devel/protocol/tacacs/tacacs.h>
 
-#define FR_PACKET_TYPE_MAX (FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND + 1)
-
 /** An instance of a proto_tacacs listen section
  *
  */
@@ -35,12 +33,12 @@ typedef struct {
        fr_io_instance_t        io;                             //!< wrapper for IO abstraction
 
        char                    **allowed_types;                //!< names for for 'type = ...'
-       bool                    allowed[FR_PACKET_TYPE_MAX];    //!< indexed by value
+       bool                    allowed[FR_TACACS_CODE_MAX];    //!< indexed by value
 
        uint32_t                max_packet_size;                //!< for message ring buffer.
        uint32_t                num_messages;                   //!< for message ring buffer.
 
-       uint32_t                priorities[FR_PACKET_TYPE_MAX]; //!< priorities for individual packets
+       uint32_t                priorities[FR_TACACS_CODE_MAX]; //!< priorities for individual packets
 } proto_tacacs_t;
 
 /*
index c62d331c58712b6563dc9b0a02cc2d7bf43cb041..22ff8b620bb3999589393a3417cb7fc4be11f1e1 100644 (file)
 #include <freeradius-devel/io/master.h>
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/protocol.h>
-#include <freeradius-devel/server/process.h>
 #include <freeradius-devel/server/state.h>
 #include <freeradius-devel/unlang/base.h>
 #include <freeradius-devel/util/debug.h>
 
 #include <freeradius-devel/tacacs/tacacs.h>
 
-/*
- *     This module runs many packet types, but it does mostly the
- *     same things for each one.  So we abstract the configuration.
- */
-typedef struct {
-       fr_dict_attr_t const *attr_process;
-       int             reply;                          //!< reply code
-
-       fr_dict_attr_t const *attr_status;
-       uint8_t         status_fail;
-
-       char const      *fail_message;                  //!< failed message
-
-       CONF_SECTION    *recv_request;
-       void            *unlang_request;
-
-       CONF_SECTION    *send_reply;
-       void            *unlang_reply;
-} tacacs_unlang_t;
-
-typedef struct {
-       fr_time_delta_t session_timeout;                //!< Maximum time between the last response and next request.
-       uint32_t        max_session;                    //!< Maximum ongoing session allowed.
-
-       uint8_t         state_server_id;                //!< Sets a specific byte in the state to allow the
-                                                       //!< authenticating server to be identified in packet
-                                                       //!< captures.
-
-       fr_state_tree_t *state_tree;                    //!< State tree to link multiple requests/responses.
-
-       tacacs_unlang_t auth_start;
-       tacacs_unlang_t auth_cont;
-       tacacs_unlang_t autz;
-       tacacs_unlang_t acct;
-
-       CONF_SECTION    *server_cs;
-} process_tacacs_t;
-
-static const CONF_PARSER session_config[] = {
-       { FR_CONF_OFFSET("timeout", FR_TYPE_TIME_DELTA, process_tacacs_t, session_timeout), .dflt = "15" },
-       { FR_CONF_OFFSET("max", FR_TYPE_UINT32, process_tacacs_t, max_session), .dflt = "4096" },
-       { FR_CONF_OFFSET("state_server_id", FR_TYPE_UINT8, process_tacacs_t, state_server_id) },
-
-       CONF_PARSER_TERMINATOR
-};
-
-static const CONF_PARSER config[] = {
-       { FR_CONF_POINTER("session", FR_TYPE_SUBSECTION, NULL), .subcs = (void const *) session_config },
-
-       CONF_PARSER_TERMINATOR
-};
-
 static fr_dict_t const *dict_freeradius;
 static fr_dict_t const *dict_tacacs;
 
@@ -98,6 +45,7 @@ fr_dict_autoload_t process_tacacs_dict[] = {
 };
 
 static fr_dict_attr_t const *attr_auth_type;
+static fr_dict_attr_t const *attr_packet_type;
 
 static fr_dict_attr_t const *attr_tacacs_action;
 static fr_dict_attr_t const *attr_tacacs_authentication_flags;
@@ -120,6 +68,7 @@ static fr_dict_attr_t const *attr_tacacs_state;
 extern fr_dict_attr_autoload_t process_tacacs_dict_attr[];
 fr_dict_attr_autoload_t process_tacacs_dict_attr[] = {
        { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
+       { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_tacacs },
 
        { .out = &attr_tacacs_action, .name = "Action", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
        { .out = &attr_tacacs_authentication_flags, .name = "Authentication-Flags", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
@@ -143,11 +92,73 @@ fr_dict_attr_autoload_t process_tacacs_dict_attr[] = {
        { NULL }
 };
 
-static void message_failed(request_t *request, tacacs_unlang_t const *ctx, char const *msg)
+typedef struct {
+       uint64_t        nothing;                // so that the next field isn't at offset 0
+
+       CONF_SECTION    *auth_start;
+       CONF_SECTION    *auth_start_reply;
+
+       CONF_SECTION    *auth_cont;
+       CONF_SECTION    *auth_cont_reply;
+
+       CONF_SECTION    *autz_request;
+       CONF_SECTION    *autz_reply;
+
+       CONF_SECTION    *acct_request;
+       CONF_SECTION    *acct_reply;
+
+       CONF_SECTION    *do_not_respond;
+} process_tacacs_sections_t;
+
+typedef struct {
+       fr_time_delta_t session_timeout;                //!< Maximum time between the last response and next request.
+       uint32_t        max_session;                    //!< Maximum ongoing session allowed.
+
+       uint8_t         state_server_id;                //!< Sets a specific byte in the state to allow the
+                                                       //!< authenticating server to be identified in packet
+                                                       //!< captures.
+
+       fr_state_tree_t *state_tree;                    //!< State tree to link multiple requests/responses.
+
+       process_tacacs_sections_t sections;
+
+       CONF_SECTION    *server_cs;
+} process_tacacs_t;
+
+#define PROCESS_PACKET_TYPE            fr_tacacs_packet_code_t
+#define PROCESS_CODE_MAX               FR_TACACS_CODE_MAX
+#define PROCESS_CODE_DO_NOT_RESPOND    FR_TACACS_DO_NOT_RESPOND
+#define PROCESS_PACKET_CODE_VALID      FR_TACACS_PACKET_CODE_VALID
+#define PROCESS_INST                   process_tacacs_t
+
+#define PROCESS_STATE_EXTRA_FIELDS     fr_dict_attr_t const **attr_process; \
+                                       fr_dict_attr_t const **attr_status; \
+                                       char const      *attr_process_section; \
+                                       uint8_t         status_fail; \
+                                       char const      *fail_message;
+
+#include <freeradius-devel/server/process.h>
+
+static const CONF_PARSER session_config[] = {
+       { FR_CONF_OFFSET("timeout", FR_TYPE_TIME_DELTA, process_tacacs_t, session_timeout), .dflt = "15" },
+       { FR_CONF_OFFSET("max", FR_TYPE_UINT32, process_tacacs_t, max_session), .dflt = "4096" },
+       { FR_CONF_OFFSET("state_server_id", FR_TYPE_UINT8, process_tacacs_t, state_server_id) },
+
+       CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER config[] = {
+       { FR_CONF_POINTER("session", FR_TYPE_SUBSECTION, NULL), .subcs = (void const *) session_config },
+
+       CONF_PARSER_TERMINATOR
+};
+
+static void message_failed(request_t *request, PROCESS_INST *inst, fr_process_state_t const *ctx)
 {
        fr_pair_t       *vp;
+       char const      *msg;
 
-       if (!msg) msg = ctx->fail_message;
+       msg = ctx->fail_message;
 
        RPEDEBUG("%s", msg);
 
@@ -162,330 +173,414 @@ static void message_failed(request_t *request, tacacs_unlang_t const *ctx, char
        /*
         *      Set the status.
         */
-       MEM(pair_update_reply(&vp, ctx->attr_status) >= 0);
+       MEM(pair_update_reply(&vp, *ctx->attr_status) >= 0);
        vp->vp_uint8 = ctx->status_fail;
-}
 
+       fr_state_discard(inst->state_tree, request);
+       fr_pair_delete_by_da(&request->request_pairs, attr_tacacs_state);
+}
 
-static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
+RECV(tacacs)
 {
-       process_tacacs_t const  *inst = talloc_get_type_abort_const(mctx->instance, process_tacacs_t);
-       fr_pair_t                       *vp;
-       rlm_rcode_t                     rcode;
-       CONF_SECTION                    *unlang;
-       fr_dict_enum_t const            *dv = NULL;
-       fr_dcursor_t                    cursor;
-       tacacs_unlang_t const           *ctx;
+       CONF_SECTION                    *cs;
+       fr_process_state_t const        *state;
+       PROCESS_INST                    *inst = mctx->instance;
        fr_tacacs_packet_hdr_t const    *pkt = (fr_tacacs_packet_hdr_t const *) request->packet->data;
 
-       REQUEST_VERIFY(request);
+       PROCESS_TRACE;
 
-       /*
-        *      Wrapper to distinguish between Authentication Start & Continue.
-        */
-       switch (request->packet->code) {
-       case FR_PACKET_TYPE_VALUE_AUTHENTICATION_START:
-               ctx = &inst->auth_start;
-               break;
+       UPDATE_STATE_CS(packet);
+       request->reply->code = state->default_reply; /* TCP, so we always reply */
 
-       case FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE:
-               ctx = &inst->auth_start;
-               break;
+       if (!request->parent) {
+               fr_pair_t *vp;
+               uint8_t buffer[sizeof(request->async->listen) + sizeof(pkt->session_id)];
 
-       case FR_PACKET_TYPE_VALUE_AUTHORIZATION_REQUEST:
-               ctx = &inst->autz;
-               break;
+               fr_assert(request->async->listen);
+               memcpy(buffer, &request->async->listen, sizeof(request->async->listen));
+               memcpy(buffer + sizeof(request->async->listen), &pkt->session_id, sizeof(pkt->session_id));
 
-       case FR_PACKET_TYPE_VALUE_ACCOUNTING_REQUEST:
-               ctx = &inst->acct;
-               break;
+               vp = fr_pair_afrom_da(request->request_ctx, attr_tacacs_state);
+               if (vp) {
+                       fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
+                       fr_pair_append(&request->request_pairs, vp);
 
-       default:
-               REDEBUG("Ignoring packet - not a request from a client");
-               RETURN_MODULE_FAIL;
+                       fr_state_to_request(inst->state_tree, request);
+               }
        }
 
-       switch (request->request_state) {
-       case REQUEST_INIT:
-               request->component = "tacacs";
+       return CALL_RECV(generic);
+}
 
-               /*
-                *      We always reply, unless specifically set to "Do not respond"
-                */
-               request->reply->code = ctx->reply;
+RESUME(tacacs_type)
+{
+       rlm_rcode_t                     rcode = *p_result;
+       CONF_SECTION                    *cs;
+       fr_process_state_t const        *state;
+       PROCESS_INST                    *inst = mctx->instance;
 
-               /*
-                *      Grab the VPS and data associated with the
-                *      State attribute.  This is a synthetic /
-                *      internal attribute, which is composed of the
-                *      listener followed by the session ID
-                *
-                *      The session ID is unique per listener.
-                */
-               if (!request->parent) {
-                       uint8_t buffer[sizeof(request->async->listen) + sizeof(pkt->session_id)];
+       PROCESS_TRACE;
 
-                       fr_assert(request->async->listen);
-                       memcpy(buffer, &request->async->listen, sizeof(request->async->listen));
-                       memcpy(buffer + sizeof(request->async->listen), &pkt->session_id, sizeof(pkt->session_id));
+       fr_assert(rcode < RLM_MODULE_NUMCODES);
 
-                       vp = fr_pair_afrom_da(request->request_ctx, attr_tacacs_state);
-                       if (vp) {
-                               fr_pair_value_memdup(vp, buffer, sizeof(buffer), false);
-                               fr_pair_append(&request->request_pairs, vp);
-                       }
+       UPDATE_STATE(packet);
 
-                       fr_state_to_request(inst->state_tree, request);
-               }
+       switch (rcode) {
+       case RLM_MODULE_FAIL:
+       case RLM_MODULE_INVALID:
+       case RLM_MODULE_NOOP:
+       case RLM_MODULE_NOTFOUND:
+       case RLM_MODULE_REJECT:
+       case RLM_MODULE_UPDATED:
+       case RLM_MODULE_DISALLOW:
+       default:
+               message_failed(request, inst, state);
+               break;
 
-               /*
-                *      Push the conf section into the unlang stack.
-                */
-               RDEBUG("Running 'recv %s' from file %s", cf_section_name2(ctx->recv_request), cf_filename(ctx->recv_request));
-               if (unlang_interpret_push_instruction(request, ctx->unlang_request, RLM_MODULE_REJECT, UNLANG_TOP_FRAME) < 0) {
-                       RETURN_MODULE_FAIL;
-               }
+       case RLM_MODULE_OK:
+               break;
 
-               request->request_state = REQUEST_RECV;
-               FALL_THROUGH;
+       case RLM_MODULE_HANDLED:
+               break;
+       }
 
-       case REQUEST_RECV:
-               rcode = unlang_interpret(request);
+       UPDATE_STATE_CS(reply);
 
-               if (request->master_state == REQUEST_STOP_PROCESSING) {
-                       *p_result = RLM_MODULE_HANDLED;
-                       return UNLANG_ACTION_STOP_PROCESSING;
-               }
+       fr_assert(state->send != NULL);
+       return unlang_module_yield_to_section(p_result, request,
+                                             cs, state->rcode, state->send,
+                                             NULL, rctx);
+}
 
-               if (rcode == RLM_MODULE_YIELD) return UNLANG_ACTION_YIELD;
-
-               switch (rcode) {
-               case RLM_MODULE_NOOP:
-               case RLM_MODULE_NOTFOUND:
-               case RLM_MODULE_OK:
-               case RLM_MODULE_UPDATED:
-                       break;
-
-               case RLM_MODULE_HANDLED:
-                       goto setup_send;
-
-               case RLM_MODULE_FAIL:
-               case RLM_MODULE_INVALID:
-               case RLM_MODULE_REJECT:
-               case RLM_MODULE_DISALLOW:
-               default:
-                       message_failed(request, ctx, NULL);
-                       goto setup_send;
-               }
+RESUME(recv_tacacs)
+{
+       rlm_rcode_t                     rcode = *p_result;
+       CONF_SECTION                    *cs;
+       fr_process_state_t const        *state;
+       PROCESS_INST                    *inst = mctx->instance;
 
-               /*
-                *      Only some packet types run authenticate foo { ... }
-                */
-               if (ctx->attr_process == attr_tacacs_authentication_type) {
-                       fr_pair_t                       *auth_type;
+       PROCESS_TRACE;
 
-                       /*
-                        *      Find Authentication-Type, and complain if they have too many.
-                        */
-                       auth_type = NULL;
-                       for (vp = fr_dcursor_iter_by_da_init(&cursor, &request->control_pairs, attr_auth_type);
-                            vp;
-                            vp = fr_dcursor_next(&cursor)) {
-                               if (!auth_type) {
-                                       auth_type = vp;
-                                       continue;
-                               }
-
-                               RWDEBUG("Ignoring extra %pP", vp);
-                       }
+       fr_assert(rcode < RLM_MODULE_NUMCODES);
 
-                       /*
-                        *      No Auth-Type, force it to reject.
-                        */
-                       if (!auth_type) {
-                               vp = fr_pair_find_by_da(&request->request_pairs, attr_tacacs_authentication_type);
-                               if (!vp) {
-                                       message_failed(request, ctx, "No Auth-Type or Authentication-Type configured: rejecting authentication.");
-                                       goto setup_send;
-                               }
-
-                               /*
-                                *      Look up the name of Authentication-Type
-                                */
-                               dv = fr_dict_enum_by_value(vp->da, &vp->data);
-                               if (!dv) {
-                                       message_failed(request, ctx, "Unknown value for Authentication-Type: rejecting authentication.");
-                                       goto setup_send;
-                               }
-
-                               /*
-                                *      Use that name to search for a matching Auth-Type which has been defined.
-                                */
-                               dv = fr_dict_enum_by_name(attr_auth_type, dv->name, -1);
-                               if (!dv) {
-                                       message_failed(request, ctx, "No Auth-Type found to match Authentication-Type: rejecting authentication.");
-                                       goto setup_send;
-                               }
-                       } else {
-                               /*
-                                *      Find the appropriate Auth-Type by name.
-                                */
-                               vp = auth_type;
-                               dv = fr_dict_enum_by_value(attr_auth_type, &vp->data);
-                       }
+       UPDATE_STATE(packet);
 
-                       if (!dv) {
-                               message_failed(request, ctx, "Unknown Auth-Type found: rejecting the user");
-                               goto setup_send;
+       switch (rcode) {
+       case RLM_MODULE_NOOP:
+       case RLM_MODULE_NOTFOUND:
+       case RLM_MODULE_OK:
+       case RLM_MODULE_UPDATED:
+               request->reply->code = state->packet_type[rcode];
+
+               /*
+                *      Run "authenticate foo" or "accounting foo"
+                */
+               if (state->attr_process) {
+                       fr_pair_t *vp;
+                       fr_dict_enum_t const *dv;
+                       CONF_SECTION *subcs;
+
+                       vp = fr_pair_find_by_da(&request->request_pairs, *state->attr_process);
+                       if (!vp) vp = fr_pair_find_by_da(&request->control_pairs, *state->attr_process);
+                       if (!vp) {
+                               RDEBUG2("No attribute found for &request.%s - proceeding to 'send'", (*state->attr_process)->name);
+                               break;
                        }
 
-                       unlang = cf_section_find(unlang_call_current(request), "authenticate", dv->name);
-                       if (!unlang) {
-                               message_failed(request, ctx, "No matching 'authenticate' section found: rejecting the user");
-                               goto setup_send;
+                       dv = fr_dict_enum_by_value(vp->da, &vp->data);
+                       if (!dv) {
+                               RDEBUG2("No name found for &request.%s value %pV - proceeding to 'send'", (*state->attr_process)->name, &vp->data);
+                               break;
                        }
 
-                       RDEBUG("Running 'authenticate %s' from file %s", cf_section_name2(unlang), cf_filename(unlang));
-                       if (unlang_interpret_push_section(request, unlang, RLM_MODULE_NOTFOUND, UNLANG_TOP_FRAME) < 0) {
-                               RETURN_MODULE_FAIL;
+                       subcs = cf_section_find(unlang_call_current(request), state->attr_process_section, dv->name);
+                       if (!subcs) {
+                               RDEBUG2("No '%s %s { ... }' section found - skipping", state->attr_process_section, dv->name);
+                               break;
                        }
 
-               } else if (ctx->attr_process == attr_tacacs_accounting_flags) {
-                       vp = fr_pair_find_by_da(&request->request_pairs, attr_tacacs_accounting_flags);
-                       if (!vp) goto setup_send;
+                       return unlang_module_yield_to_section(p_result, request,
+                                                             subcs, RLM_MODULE_NOOP, resume_tacacs_type,
+                                                             NULL, rctx);
+               }
+               break;
 
-                       dv = fr_dict_enum_by_value(vp->da, &vp->data);
-                       if (!dv) goto setup_send;
+       case RLM_MODULE_HANDLED:
+               fr_assert(request->reply->code != 0);
+               break;
 
-                       unlang = cf_section_find(unlang_call_current(request), "accounting", dv->name);
-                       if (!unlang) {
-                               RDEBUG2("No 'accounting %s { ... }' section found - skipping...", dv->name);
-                               goto setup_send;
-                       }
+       case RLM_MODULE_FAIL:
+       case RLM_MODULE_INVALID:
+       case RLM_MODULE_REJECT:
+       case RLM_MODULE_DISALLOW:
+       default:
+               request->reply->code = state->packet_type[rcode];
+               message_failed(request, inst, state);
+               break;
+       }
 
-                       RDEBUG("Running 'accounting %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;
-                       }
+       UPDATE_STATE_CS(reply);
 
-                       request->request_state = REQUEST_PROCESS;
+       fr_assert(state->send != NULL);
 
-               } else {
-                       goto setup_send;
-               }
+       return unlang_module_yield_to_section(p_result, request,
+                                             cs, state->rcode, state->send,
+                                             NULL, rctx);
+}
 
-               request->request_state = REQUEST_PROCESS;
-               FALL_THROUGH;
+RESUME(send_tacacs)
+{
+       fr_pair_t *vp;
+       PROCESS_INST const              *inst = mctx->instance;
 
-       case REQUEST_PROCESS:
-               rcode = unlang_interpret(request);
+       PROCESS_TRACE;
 
-               if (request->master_state == REQUEST_STOP_PROCESSING) {
-                       *p_result = RLM_MODULE_HANDLED;
-                       return UNLANG_ACTION_STOP_PROCESSING;
-               }
+       /*
+        *      Save the state
+        */
+       if (!request->parent &&
+           ((vp = fr_pair_find_by_da(&request->request_pairs, attr_tacacs_state)) != NULL)) {
+               fr_tacacs_packet_hdr_t const    *pkt = (fr_tacacs_packet_hdr_t const *) request->packet->data;
 
-               if (rcode == RLM_MODULE_YIELD) return UNLANG_ACTION_YIELD;
+               /*
+                *      Keep the state around for
+                *      authorization and accounting packets.
+                */
+               if (pkt->seq_no >= 254) {
+                       fr_state_discard(inst->state_tree, request);
 
-               switch (rcode) {
                        /*
-                        *      An authentication module FAIL
-                        *      return code, or any return code that
-                        *      is not expected from authentication,
-                        *      is the same as an explicit REJECT!
+                        *      We can't save it, so... oh well.
                         */
-               case RLM_MODULE_FAIL:
-               case RLM_MODULE_INVALID:
-               case RLM_MODULE_NOOP:
-               case RLM_MODULE_NOTFOUND:
-               case RLM_MODULE_REJECT:
-               case RLM_MODULE_UPDATED:
-               case RLM_MODULE_DISALLOW:
-               default:
-                       message_failed(request, ctx, NULL);
-                       goto setup_send;
-
-               case RLM_MODULE_OK:
-                       break;
-
-               case RLM_MODULE_HANDLED:
-                       goto setup_send;
+               } else if (fr_request_to_state(inst->state_tree, request) < 0) {
+                       RWDEBUG("Failed saving state");
+                       request->reply->code = FR_TACACS_DO_NOT_RESPOND;
                }
+       }
 
-       setup_send:
-               RDEBUG("Running 'send %s' from file %s", cf_section_name2(ctx->send_reply), cf_filename(ctx->send_reply));
-               if (unlang_interpret_push_instruction(request, ctx->unlang_reply, RLM_MODULE_NOOP, UNLANG_TOP_FRAME) < 0) {
-                       RETURN_MODULE_FAIL;
-               }
+       return CALL_RESUME(send_generic);
+}
 
-               request->request_state = REQUEST_SEND;
-               FALL_THROUGH;
+static fr_process_state_t const process_state[] = {
+       [FR_TACACS_AUTH_START] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTH_START_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTH_START_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .default_reply = FR_TACACS_AUTH_START_REPLY,
+               .recv = recv_tacacs,
+               .resume = resume_recv_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, auth_start),
+
+               .attr_process = &attr_tacacs_authentication_type,
+               .attr_process_section = "authenticate",
+               .fail_message = "Failed to authenticate the user",
+               .attr_status = &attr_tacacs_authentication_status,
+               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
+       },
+       [FR_TACACS_AUTH_START_REPLY] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTH_START_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTH_START_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTH_START_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .send = send_generic,
+               .resume = resume_send_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, auth_start_reply),
 
-       case REQUEST_SEND:
-               rcode = unlang_interpret(request);
+               .fail_message = "Failed to authenticate the user",
+               .attr_status = &attr_tacacs_authentication_status,
+               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
+       },
 
-               if (request->master_state == REQUEST_STOP_PROCESSING) {
-                       *p_result = RLM_MODULE_HANDLED;
-                       return UNLANG_ACTION_STOP_PROCESSING;
-               }
+       [FR_TACACS_AUTH_CONTINUE] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTH_CONTINUE_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTH_CONTINUE_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .default_reply = FR_TACACS_AUTH_CONTINUE_REPLY,
+               .recv = recv_tacacs,
+               .resume = resume_recv_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, auth_cont),
+
+               .attr_process = &attr_tacacs_authentication_type,
+               .attr_process_section = "authenticate",
+               .fail_message = "Failed to authenticate the user",
+               .attr_status = &attr_tacacs_authentication_status,
+               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
+       },
+       [FR_TACACS_AUTH_CONTINUE_REPLY] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTH_CONTINUE_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTH_CONTINUE_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTH_CONTINUE_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .send = send_generic,
+               .resume = resume_send_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, auth_cont_reply),
 
-               if (rcode == RLM_MODULE_YIELD) return UNLANG_ACTION_YIELD;
-
-               switch (rcode) {
-               case RLM_MODULE_FAIL:
-               case RLM_MODULE_INVALID:
-               case RLM_MODULE_REJECT:
-               case RLM_MODULE_DISALLOW:
-               default:
-                       break;
-
-               case RLM_MODULE_HANDLED:
-               case RLM_MODULE_NOOP:
-               case RLM_MODULE_NOTFOUND:
-               case RLM_MODULE_OK:
-               case RLM_MODULE_UPDATED:
-                       /* reply code is already set */
-                       break;
-               }
+               .fail_message = "Failed to authenticate the user",
+               .attr_status = &attr_tacacs_authentication_status,
+               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
+       },
 
-               request->reply->timestamp = fr_time();
+       [FR_TACACS_AUTZ_REQUEST] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTZ_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTZ_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .default_reply = FR_TACACS_AUTZ_REPLY,
+               .recv = recv_tacacs,
+               .resume = resume_recv_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, autz_request),
 
-               /*
-                *      Save session-state list on Start discard it
-                *      for "Continue".
-                */
-               if (!request->parent) {
-                       /*
-                        *      Keep the state around for
-                        *      authorization and accounting packets.
-                        */
-                       if (pkt->seq_no >= 254) {
-                               fr_state_discard(inst->state_tree, request);
-
-                               /*
-                                *      We can't create a valid response
-                                */
-                       } else if (fr_request_to_state(inst->state_tree, request) < 0) {
-                               RWDEBUG("Failed saving state");
-                               request->reply->code = FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND;
-                       }
-               }
+               .fail_message = "Failed to authorize the user",
+               .attr_status = &attr_tacacs_authorization_status,
+               .status_fail = FR_TAC_PLUS_AUTHOR_STATUS_FAIL,
+       },
+       [FR_TACACS_AUTZ_REPLY] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_AUTZ_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_AUTZ_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_AUTZ_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .send = send_generic,
+               .resume = resume_send_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, autz_reply),
 
-               /*
-                *      Check for "do not respond".
-                */
-               if (request->reply->code == FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND) {
-                       RDEBUG("Not sending reply to client.");
-                       fr_state_discard(inst->state_tree, request);
-                       break;
-               }
-               break;
+               .fail_message = "Failed to authorize the user",
+               .attr_status = &attr_tacacs_authorization_status,
+               .status_fail = FR_TAC_PLUS_AUTHOR_STATUS_FAIL,
+       },
 
-       default:
-               RETURN_MODULE_FAIL;
-       }
+       [FR_TACACS_ACCT_REQUEST] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_ACCT_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_ACCT_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .default_reply = FR_TACACS_ACCT_REPLY,
+               .recv = recv_tacacs,
+               .resume = resume_recv_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, acct_request),
+
+               .attr_process = &attr_tacacs_accounting_flags,
+               .attr_process_section = "accounting",
+               .fail_message = "Failed to process the accounting packet",
+               .attr_status = &attr_tacacs_accounting_status,
+               .status_fail = FR_TAC_PLUS_ACCT_STATUS_ERROR,
+       },
+       [FR_TACACS_ACCT_REPLY] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_ACCT_REPLY,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_ACCT_REPLY,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_ACCT_REPLY,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .send = send_generic,
+               .resume = resume_send_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, acct_reply),
+
+               .fail_message = "Failed to process the accounting packet",
+               .attr_status = &attr_tacacs_accounting_status,
+               .status_fail = FR_TAC_PLUS_ACCT_STATUS_ERROR,
+       },
+
+       [FR_TACACS_DO_NOT_RESPOND] = {
+               .packet_type = {
+                       [RLM_MODULE_OK] =       FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_NOOP] =     FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_UPDATED] =  FR_TACACS_DO_NOT_RESPOND,
+
+                       [RLM_MODULE_REJECT] =   FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_FAIL] =     FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_INVALID] =  FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_DISALLOW] = FR_TACACS_DO_NOT_RESPOND,
+                       [RLM_MODULE_NOTFOUND] = FR_TACACS_DO_NOT_RESPOND,
+               },
+               .rcode = RLM_MODULE_NOOP,
+               .send = send_generic,
+               .resume = resume_send_tacacs,
+               .section_offset = offsetof(process_tacacs_sections_t, do_not_respond),
+       },
+};
+
+static unlang_action_t mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
+{
+       fr_process_state_t const *state;
+
+       PROCESS_TRACE;
+
+       (void)talloc_get_type_abort_const(mctx->instance, process_tacacs_t);
+       fr_assert(PROCESS_PACKET_CODE_VALID(request->packet->code));
+
+       request->component = "tacacs";
+       fr_assert(request->dict == dict_tacacs);
 
-       RETURN_MODULE_OK;
+       UPDATE_STATE(packet);
+
+       // @todo - debug stuff!
+//     tacacs_packet_debug(request, request->packet, &request->request_pairs, true);
+
+       return state->recv(p_result, mctx, request);
 }
 
 
@@ -520,40 +615,6 @@ static int mod_bootstrap(void *instance, CONF_SECTION *process_app_cs)
        inst->server_cs = server_cs;
        if (virtual_server_section_attribute_define(server_cs, "authenticate", attr_auth_type) < 0) return -1;
 
-       /*
-        *      Set up the parameters for the various packet types.
-        */
-       inst->auth_start = (tacacs_unlang_t) {
-               .attr_process = attr_tacacs_authentication_type,
-               .fail_message = "Failed to authenticate the user",
-               .reply = FR_PACKET_TYPE_VALUE_AUTHENTICATION_REPLY,
-               .attr_status = attr_tacacs_authentication_status,
-               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
-       };
-
-       inst->auth_cont = (tacacs_unlang_t) {
-               .attr_process = attr_tacacs_authentication_type,
-               .fail_message = "Failed to authenticate the user",
-               .reply = FR_PACKET_TYPE_VALUE_AUTHENTICATION_REPLY,
-               .attr_status = attr_tacacs_authentication_status,
-               .status_fail = FR_TAC_PLUS_AUTHEN_STATUS_FAIL,
-       };
-
-       inst->autz = (tacacs_unlang_t) {
-               .fail_message = "Failed to authorize the user",
-               .reply = FR_PACKET_TYPE_VALUE_AUTHORIZATION_REPLY,
-               .attr_status = attr_tacacs_authorization_status,
-               .status_fail = FR_TAC_PLUS_AUTHOR_STATUS_FAIL,
-       };
-
-       inst->acct = (tacacs_unlang_t) {
-               .attr_process = attr_tacacs_accounting_flags,
-               .fail_message = "Failed to process the accounting packet",
-               .reply = FR_PACKET_TYPE_VALUE_ACCOUNTING_REPLY,
-               .attr_status = attr_tacacs_accounting_status,
-               .status_fail = FR_TAC_PLUS_ACCT_STATUS_ERROR,
-       };
-
        return 0;
 }
 
@@ -565,35 +626,35 @@ static virtual_server_compile_t compile_list[] = {
         *      to allow the user to have different logic for that.
         *
         *      If you want to cry, just take a look at
-        *      https://tools.ietf.org/id/draft-ietf-opsawg-07.html#rfc.section.4
+        *
+        *        https://tools.ietf.org/html/rfc8907 Section 4.
+        *
+        *      This should be an abject lesson in how NOT to design a
+        *      protocol.  Pretty much everything they did was wrong.
         */
        {
                .name = "recv",
                .name2 = "Authentication-Start",
                .component = MOD_AUTHENTICATE,
-               .offset = offsetof(process_tacacs_t, auth_start.recv_request),
-               .instruction = offsetof(process_tacacs_t, auth_start.unlang_request),
+               .offset = PROCESS_CONF_OFFSET(auth_start),
        },
        {
                .name = "send",
                .name2 = "Authentication-Start-Reply",
                .component = MOD_POST_AUTH,
-               .offset = offsetof(process_tacacs_t, auth_start.send_reply),
-               .instruction = offsetof(process_tacacs_t, auth_start.unlang_reply),
+               .offset = PROCESS_CONF_OFFSET(auth_start_reply),
        },
        {
                .name = "recv",
                .name2 = "Authentication-Continue",
                .component = MOD_AUTHENTICATE,
-               .offset = offsetof(process_tacacs_t, auth_cont.recv_request),
-               .instruction = offsetof(process_tacacs_t, auth_cont.unlang_request),
+               .offset = PROCESS_CONF_OFFSET(auth_cont),
        },
        {
                .name = "send",
                .name2 = "Authentication-Continue-Reply",
                .component = MOD_POST_AUTH,
-               .offset = offsetof(process_tacacs_t, auth_cont.send_reply),
-               .instruction = offsetof(process_tacacs_t, auth_cont.unlang_reply),
+               .offset = PROCESS_CONF_OFFSET(auth_cont_reply),
        },
 
        {
@@ -608,15 +669,13 @@ static virtual_server_compile_t compile_list[] = {
                .name = "recv",
                .name2 = "Authorization-Request",
                .component = MOD_AUTHORIZE,
-               .offset = offsetof(process_tacacs_t, autz.recv_request),
-               .instruction = offsetof(process_tacacs_t, autz.unlang_request),
+               .offset = PROCESS_CONF_OFFSET(autz_request),
        },
        {
                .name = "send",
                .name2 = "Authorization-Reply",
                .component = MOD_POST_AUTH,
-               .offset = offsetof(process_tacacs_t, autz.send_reply),
-               .instruction = offsetof(process_tacacs_t, autz.unlang_reply),
+               .offset = PROCESS_CONF_OFFSET(autz_reply),
        },
 
        /* accounting */
@@ -625,15 +684,13 @@ static virtual_server_compile_t compile_list[] = {
                .name = "recv",
                .name2 = "Accounting-Request",
                .component = MOD_ACCOUNTING,
-               .offset = offsetof(process_tacacs_t, acct.recv_request),
-               .instruction = offsetof(process_tacacs_t, acct.unlang_request),
+               .offset = PROCESS_CONF_OFFSET(acct_request),
        },
        {
                .name = "send",
                .name2 = "Accounting-Reply",
                .component = MOD_POST_AUTH,
-               .offset = offsetof(process_tacacs_t, acct.send_reply),
-               .instruction = offsetof(process_tacacs_t, acct.unlang_reply),
+               .offset = PROCESS_CONF_OFFSET(acct_reply),
        },
        {
                .name = "accounting",
@@ -641,6 +698,13 @@ static virtual_server_compile_t compile_list[] = {
                .component = MOD_ACCOUNTING,
        },
 
+       {
+               .name = "send",
+               .name2 = "Do-Not-Response",
+               .component = MOD_POST_AUTH,
+               .offset = PROCESS_CONF_OFFSET(do_not_respond),
+       },
+
        COMPILE_TERMINATOR
 };
 
index de09b591b8990f9b41629568f7a2fdbe35a86874..b10cc9a7c1a9e62f6fe95460bf1bf9ddfaf877d4 100644 (file)
@@ -105,12 +105,16 @@ fr_dict_attr_autoload_t libfreeradius_tacacs_dict_attr[] = {
        { NULL }
 };
 
-char const *fr_tacacs_packet_codes[] = {
+char const *fr_tacacs_packet_codes[FR_TACACS_CODE_MAX] = {
        [FR_PACKET_TYPE_VALUE_AUTHENTICATION_START] = "Authentication-Start",
+       [FR_PACKET_TYPE_VALUE_AUTHENTICATION_START_REPLY] = "Authentication-Start-Reply",
+
        [FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE] = "Authentication-Continue",
-       [FR_PACKET_TYPE_VALUE_AUTHENTICATION_REPLY] = "Authentication-Reply",
+       [FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE_REPLY] = "Authentication-Continue-Reply",
+
        [FR_PACKET_TYPE_VALUE_AUTHORIZATION_REQUEST] = "Authorization-Request",
        [FR_PACKET_TYPE_VALUE_AUTHORIZATION_REPLY] = "Authorization-Reply",
+
        [FR_PACKET_TYPE_VALUE_ACCOUNTING_REQUEST] = "Accounting-Request",
        [FR_PACKET_TYPE_VALUE_ACCOUNTING_REPLY] = "Accounting-Reply",
 };
index 64c0d3171730cf6f9a6fbbef00343b3fa428020c..7fc00ac017857eed56999795a6971231ffa6ad32 100644 (file)
@@ -270,7 +270,26 @@ typedef struct CC_HINT(__packed__) {
        };
 } fr_tacacs_packet_t;
 
-extern char const *fr_tacacs_packet_codes[];
+/*
+ *     Shorter names, and in an enum, so that mere humans can understand them.
+ */
+typedef enum {
+       FR_TACACS_INVALID =     0,
+       FR_TACACS_AUTH_START =          FR_PACKET_TYPE_VALUE_AUTHENTICATION_START,
+       FR_TACACS_AUTH_START_REPLY =    FR_PACKET_TYPE_VALUE_AUTHENTICATION_START_REPLY,
+       FR_TACACS_AUTH_CONTINUE =       FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE,
+       FR_TACACS_AUTH_CONTINUE_REPLY = FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE_REPLY,
+       FR_TACACS_AUTZ_REQUEST =        FR_PACKET_TYPE_VALUE_AUTHORIZATION_REQUEST,
+       FR_TACACS_AUTZ_REPLY =          FR_PACKET_TYPE_VALUE_AUTHORIZATION_REPLY,
+       FR_TACACS_ACCT_REQUEST =        FR_PACKET_TYPE_VALUE_ACCOUNTING_REQUEST,
+       FR_TACACS_ACCT_REPLY =          FR_PACKET_TYPE_VALUE_ACCOUNTING_REPLY,
+       FR_TACACS_DO_NOT_RESPOND =      FR_PACKET_TYPE_VALUE_DO_NOT_RESPOND,
+       FR_TACACS_CODE_MAX =            9,
+} fr_tacacs_packet_code_t;
+
+#define FR_TACACS_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_TACACS_CODE_MAX))
+
+extern char const *fr_tacacs_packet_codes[FR_TACACS_CODE_MAX];
 
 /** Used as the decoder ctx
  *
index 885e844b8cc522d706cfcbdffde63d898b2ca9d6..8b2e5afdf2f5043d3b0644bf4236b723bcf340e1 100644 (file)
@@ -119,14 +119,14 @@ server test {
                                &Authentication-Status := Pass
                                &Server-Message := "Authentication-Start accepted"
                        }
+                       ok
+
                } else {
                        update reply {
                                &Authentication-Status := Fail
                                &Server-Message := "Authentication-Start failed for %{User-Name}"
                        }
                }
-
-               handled
        }
 
        send Authentication-Start-Reply {
@@ -141,14 +141,14 @@ server test {
                                &Authentication-Status := Pass
                                &Server-Message := "Authentication-Cont accepted"
                        }
+                       ok
+
                } else {
                        update reply {
                                &Authentication-Status := Fail
                                &Server-Message := "Authentication-Cont failed for %{User-Name}"
                        }
                }
-
-               handled
        }
 
        send Authentication-Continue-Reply {
@@ -163,14 +163,14 @@ server test {
                                &Authorization-Status := Pass-Add
                                &Server-Message := "Authorization-Request accepted"
                        }
+                       ok
+
                } else {
                        update reply {
                                &Authorization-Status := Error
                                &Server-Message := "Authorization-Request failed for %{User-Name}"
                        }
                }
-
-               handled
        }
 
        send Authorization-Response {