#include <freeradius-devel/unlang/call.h>
#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/protocol/tacacs/tacacs.h>
+
static fr_dict_t const *dict_freeradius;
static fr_dict_t const *dict_tacacs;
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_action;
static fr_dict_attr_t const *attr_tacacs_authentication_flags;
static fr_dict_attr_t const *attr_tacacs_authentication_type;
static fr_dict_attr_t const *attr_tacacs_authentication_service;
{ .out = &attr_tacacs_data, .name = "Data", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
{ .out = &attr_tacacs_privilege_level, .name = "Privilege-Level", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
{ .out = &attr_tacacs_remote_address, .name = "Remote-Address", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
+ { .out = &attr_tacacs_authentication_action, .name = "Action", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
{ .out = &attr_tacacs_session_id, .name = "Packet.Session-Id", .type = FR_TYPE_UINT32, .dict = &dict_tacacs },
{ .out = &attr_tacacs_sequence_number, .name = "Packet.Sequence-Number", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
{ .out = &attr_tacacs_server_message, .name = "Server-Message", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
RECV(auth_start)
{
-// process_tacacs_t *inst = talloc_get_type_abort(mctx->inst->data, process_tacacs_t);
+ fr_process_state_t const *state;
+ fr_pair_t *vp;
+
+ /*
+ * Only "Login" is supported. The others are "change password" and "sendauth", which aren't
+ * used.
+ */
+ vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_tacacs_action);
+ if (!vp) {
+ fail:
+ request->reply->code = FR_TACACS_CODE_AUTH_REPLY_ERROR;
+ UPDATE_STATE(reply);
+
+ fr_assert(state->send != NULL);
+ return CALL_SEND_STATE(state);
+ }
+
+ if (vp->vp_uint8 != FR_ACTION_VALUE_LOGIN) {
+ RDEBUG("Invalid authentication action %u", vp->vp_uint8);
+ goto fail;
+ }
/*
* There is no state to restore, so we just run the section as normal.
rlm_rcode_t rcode = *p_result;
fr_process_state_t const *state;
+ fr_pair_t *vp;
PROCESS_TRACE;
switch (request->reply->code) {
case 0:
RDEBUG("No reply code was set. Forcing to Authentication-Reply-Fail");
+ fail:
request->reply->code = FR_TACACS_CODE_AUTH_REPLY_FAIL;
FALL_THROUGH;
RDEBUG2("Failed to authenticate the user");
break;
+ case FR_TACACS_CODE_AUTH_REPLY_GETDATA:
+ case FR_TACACS_CODE_AUTH_REPLY_GETUSER:
+ case FR_TACACS_CODE_AUTH_REPLY_GETPASS:
+ vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_tacacs_authentication_type);
+ if (vp && (vp->vp_uint32 != FR_AUTHENTICATION_TYPE_VALUE_ASCII)) {
+ RDEBUG2("Cannot send challenges for %pP", vp);
+ goto fail;
+ }
+ break;
+
default:
break;
auth_message(&inst->auth, request, false, "Login incorrect");
}
+ // @todo - insert server message saying "failed"
+ // and also for FAIL
+
fr_state_discard(inst->auth.state_tree, request);
RETURN_MODULE_OK;
}
RECV(auth_cont)
{
process_tacacs_t const *inst = talloc_get_type_abort_const(mctx->inst->data, process_tacacs_t);
+ fr_pair_t *vp;
if ((state_create(request->request_ctx, &request->request_pairs, request, false) < 0) ||
(fr_state_to_request(inst->auth.state_tree, request) < 0)) {
return CALL_SEND_TYPE(FR_TACACS_CODE_AUTH_REPLY_ERROR);
}
+ vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_tacacs_sequence_number);\
+ fr_assert(vp != NULL);
+
+ /*
+ * Can't allow too many sequences.
+ */
+ if ((vp->vp_uint8 >> 1) > 3) {
+ RDEBUG("Too many rounds of challenge / response");
+ return CALL_SEND_TYPE(FR_TACACS_CODE_AUTH_REPLY_FAIL);
+ }
+
return CALL_RECV(generic);
}