27 #include <freeradius-devel/io/test_point.h>
28 #include <freeradius-devel/protocol/tacacs/tacacs.h>
29 #include <freeradius-devel/util/debug.h>
30 #include <freeradius-devel/util/net.h>
31 #include <freeradius-devel/util/struct.h>
40 if (pkt->
hdr.
seq_no == 1)
return FR_PACKET_TYPE_VALUE_AUTHENTICATION_START;
47 fr_strerror_printf(
"Invalid value %u for authentication continue flag", pkt->authen_cont.flags);
51 switch (pkt->authen_reply.status) {
53 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_PASS;
56 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_FAIL;
59 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETDATA;
62 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETUSER;
65 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETPASS;
68 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_RESTART;
71 return FR_PACKET_TYPE_VALUE_AUTHENTICATION_ERROR;
77 fr_strerror_printf(
"Invalid value %u for authentication reply status", pkt->authen_reply.status);
82 return FR_PACKET_TYPE_VALUE_AUTHORIZATION_REQUEST;
85 switch (pkt->author_reply.status) {
87 return FR_PACKET_TYPE_VALUE_AUTHORIZATION_PASS_ADD;
90 return FR_PACKET_TYPE_VALUE_AUTHORIZATION_PASS_REPLACE;
93 return FR_PACKET_TYPE_VALUE_AUTHORIZATION_FAIL;
99 fr_strerror_printf(
"Invalid value %u for authorization reply status", pkt->author_reply.status);
104 return FR_PACKET_TYPE_VALUE_ACCOUNTING_REQUEST;
107 switch (pkt->acct_reply.status) {
109 return FR_PACKET_TYPE_VALUE_ACCOUNTING_SUCCESS;
112 return FR_PACKET_TYPE_VALUE_ACCOUNTING_ERROR;
118 fr_strerror_printf(
"Invalid value %u for accounting reply status", pkt->acct_reply.status);
127 #define PACKET_HEADER_CHECK(_msg, _hdr) do { \
128 p = buffer + FR_HEADER_LENGTH; \
129 if (sizeof(_hdr) > (size_t) (end - p)) { \
130 fr_strerror_printf("Header for %s is too small (%zu < %zu)", _msg, end - (uint8_t const *) pkt, p - (uint8_t const *) pkt); \
133 body = p + sizeof(_hdr); \
134 data_len = sizeof(_hdr); \
140 #define ARG_COUNT_CHECK(_msg, _hdr) do { \
141 fr_assert(p == (uint8_t const *) &(_hdr)); \
142 if (data_len > (size_t) (end - p)) { \
143 fr_strerror_printf("Argument count %u overflows the remaining data (%zu) in the %s packet", _hdr.arg_cnt, end - p, _msg); \
147 attrs = buffer + FR_HEADER_LENGTH + data_len; \
148 body += _hdr.arg_cnt; \
150 for (int i = 0; i < _hdr.arg_cnt; i++) { \
151 if (_hdr.arg_len[i] > (size_t) (end - p)) { \
152 fr_strerror_printf("Argument %u length %u overflows packet", i, _hdr.arg_len[i]); \
155 p += _hdr.arg_len[i]; \
159 #define DECODE_FIELD_UINT8(_da, _field) do { \
160 vp = fr_pair_afrom_da(ctx, _da); \
161 if (!vp) goto fail; \
162 vp->vp_uint8 = _field; \
163 fr_pair_append(out, vp); \
166 #define DECODE_FIELD_STRING8(_da, _field) do { \
167 if (tacacs_decode_field(ctx, out, _da, &p, \
168 _field, end) < 0) goto fail; \
171 #define DECODE_FIELD_STRING16(_da, _field) do { \
172 if (tacacs_decode_field(ctx, out, _da, &p, \
173 ntohs(_field), end) < 0) goto fail; \
176 #define BODY(_x) (((uint8_t const *) pkt) + sizeof(pkt->hdr) + sizeof(pkt->_x))
194 if (!arg_cnt)
return 0;
205 if (!vendor)
return -1;
216 for (i = 0; i < arg_cnt; i++) {
224 if (argv[i] < 2)
goto next;
226 memcpy(
buffer, p, argv[i]);
229 arg_end =
buffer + argv[i];
249 if (!name_end)
goto next;
274 dst = &vendor->vp_group;
288 if ((arg_end >
value) &&
294 if ((arg_end >
value) &&
299 }
else if (arg_end ==
value) {
343 arg_end = p + argv[i];
345 if ((arg_end >
value) &&
374 uint8_t const *p = *field_data;
377 if (field_len > (end - p)) {
379 da->name, field_len, end - p);
411 const uint8_t *original,
char const *
const secret,
size_t secret_len,
int *code)
416 uint8_t const *p, *body, *argv, *attrs, *end;
445 end =
buffer + buffer_len;
451 if (buffer_len <
sizeof(pkt->
hdr)) {
459 if (!(pkt->
hdr.ver.major == 12 && (pkt->
hdr.ver.minor == 0 || pkt->
hdr.ver.minor == 1))) {
498 if (original && (memcmp(original + 4,
buffer + 4, 4) != 0)) {
537 decrypted = talloc_memdup(ctx,
buffer, buffer_len);
544 end = decrypted + buffer_len;
565 if (*code < 0)
goto fail;
595 data_len += p[4] + p[5] + p[6] + p[7];
596 if (data_len > (
size_t) (end - p)) {
600 fr_strerror_const(
"Invalid packet after decryption - is the secret key incorrect?");
607 if (data_len < (
size_t) (end - p)) {
631 pkt->authen_start.user_len);
634 pkt->authen_start.rem_addr_len);
643 switch (pkt->authen_start.authen_type) {
646 want = pkt->authen_start.data_len;
650 case FR_AUTHENTICATION_TYPE_VALUE_PAP:
651 want = pkt->authen_start.data_len;
655 case FR_AUTHENTICATION_TYPE_VALUE_CHAP:
661 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAP:
667 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAPV2:
681 if (raw || (pkt->authen_start.data_len < want)) {
686 if (!da_unknown)
goto fail;
688 want = pkt->authen_start.data_len;
693 }
else if (!challenge) {
696 }
else if (pkt->authen_start.data_len == want) {
701 uint8_t challenge_len = pkt->authen_start.data_len - want;
712 switch (pkt->authen_start.authen_type) {
713 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAP:
714 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAPV2:
715 hash[1] = p[want - 1];
716 memcpy(
hash + 2, p + 1 + challenge_len, want - 2);
720 memcpy(
hash + 1, p + 1 + challenge_len, want - 1);
744 p += pkt->authen_start.data_len;
768 if (pkt->
hdr.ver.minor != 0) {
776 if (data_len > (
size_t) (end - p))
goto overflow;
777 if (data_len < (
size_t) (end - p))
goto underflow;
813 if (data_len > (
size_t) (end - p))
goto overflow;
814 if (data_len < (
size_t) (end - p))
goto underflow;
863 if (pkt->
hdr.ver.minor != 0)
goto invalid_version;
866 data_len += p[4] + p[5] + p[6] + p[7];
888 pkt->author_req.rem_addr_len);
894 pkt->author_req.arg_cnt, argv, attrs, end) < 0)
goto fail;
947 pkt->author_reply.arg_cnt, argv, attrs, end) < 0)
goto fail;
984 if (pkt->
hdr.ver.minor != 0)
goto invalid_version;
987 data_len += p[5] + p[6] + p[7] + p[8];
988 if (data_len > (
size_t) (end - p))
goto overflow;
1016 pkt->acct_req.arg_cnt, argv, attrs, end) < 0)
goto fail;
1039 if (data_len > (
size_t) (end - p))
goto overflow;
1040 if (data_len < (
size_t) (end - p))
goto underflow;
1042 p =
BODY(acct_reply);
1079 test_ctx->
secret, (talloc_array_length(test_ctx->
secret)-1),
false);
1098 if (!test_ctx)
return -1;
1100 test_ctx->
secret = talloc_strdup(test_ctx,
"testing123");
static int const char char buffer[256]
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
@ L_DBG_LVL_4
4th highest priority debug messages (-xxxx | -Xxx).
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_OCTETS
Raw octets.
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
static fr_dict_attr_t const * attr_tacacs_authentication_flags
static fr_dict_attr_t const * attr_tacacs_user_message
static fr_dict_attr_t const * attr_tacacs_server_message
static fr_dict_attr_t const * attr_tacacs_privilege_level
static fr_dict_attr_t const * attr_tacacs_authentication_type
static fr_dict_attr_t const * attr_tacacs_accounting_status
static fr_dict_attr_t const * attr_tacacs_authentication_service
static fr_dict_attr_t const * attr_tacacs_authentication_status
static fr_dict_attr_t const * attr_tacacs_client_port
static fr_dict_attr_t const * attr_tacacs_remote_address
static fr_dict_attr_t const * attr_tacacs_action
static fr_dict_attr_t const * attr_tacacs_authorization_status
static fr_dict_attr_t const * attr_tacacs_accounting_flags
static fr_dict_attr_t const * attr_tacacs_data
static fr_dict_t const * dict_tacacs
static fr_dict_attr_t const * attr_tacacs_user_name
HIDDEN fr_dict_attr_t const * attr_tacacs_argument_list
HIDDEN fr_dict_attr_t const * attr_tacacs_chap_password
HIDDEN fr_dict_attr_t const * attr_tacacs_mschap_challenge
HIDDEN fr_dict_attr_t const * attr_tacacs_packet
HIDDEN fr_dict_attr_t const * attr_tacacs_mschap2_response
HIDDEN fr_dict_attr_t const * attr_tacacs_authentication_continue_flags
HIDDEN fr_dict_attr_t const * attr_tacacs_user_password
HIDDEN fr_dict_attr_t const * attr_tacacs_packet_body_type
HIDDEN fr_dict_attr_t const * attr_tacacs_chap_challenge
HIDDEN fr_dict_attr_t const * attr_tacacs_mschap_response
HIDDEN fr_dict_attr_t const * attr_tacacs_authentication_method
int fr_tacacs_body_xor(fr_tacacs_packet_t const *pkt, uint8_t *body, size_t body_len, char const *secret, size_t secret_len)
XOR the body based on the secret key.
void fr_tacacs_global_free(void)
int fr_tacacs_global_init(void)
static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t arg_cnt, uint8_t const *argv, uint8_t const *attrs, NDEBUG_UNUSED uint8_t const *end)
Decode a TACACS+ 'arg_N' fields.
static int _encode_test_ctx(fr_tacacs_ctx_t *proto_ctx)
ssize_t fr_tacacs_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *vendor, uint8_t const *buffer, size_t buffer_len, const uint8_t *original, char const *const secret, size_t secret_len, int *code)
Decode a TACACS+ packet.
#define DECODE_FIELD_UINT8(_da, _field)
fr_test_point_proto_decode_t tacacs_tp_decode_proto
static ssize_t fr_tacacs_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *proto_ctx)
#define PACKET_HEADER_CHECK(_msg, _hdr)
static int decode_test_ctx(void **out, TALLOC_CTX *ctx)
#define DECODE_FIELD_STRING16(_da, _field)
static int tacacs_decode_field(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const **field_data, uint16_t field_len, uint8_t const *end)
Decode a TACACS+ field.
#define DECODE_FIELD_STRING8(_da, _field)
int fr_tacacs_packet_to_code(fr_tacacs_packet_t const *pkt)
#define ARG_COUNT_CHECK(_msg, _hdr)
static unsigned int hash(char const *username, unsigned int tablesize)
static decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code, udp_handle_t *h, request_t *request, udp_request_t *u, uint8_t const request_authenticator[static RADIUS_AUTH_VECTOR_LENGTH], uint8_t *data, size_t data_len)
Decode response packet data, extracting relevant information and validating the packet.
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Stores an attribute, a value and various bits of other data.
#define packet_is_authen_reply(p)
#define packet_is_authen_continue(p)
@ FR_PACKET_BODY_TYPE_REQUEST
@ FR_PACKET_BODY_TYPE_CONTINUE
@ FR_PACKET_BODY_TYPE_RESPONSE
@ FR_PACKET_BODY_TYPE_REPLY
@ FR_PACKET_BODY_TYPE_START
@ FR_TAC_PLUS_CONTINUE_FLAG_UNSET
@ FR_TAC_PLUS_CONTINUE_FLAG_ABORT
@ FR_TAC_PLUS_UNENCRYPTED_FLAG
#define fr_tacacs_packet_log_hex(_log, _packet, _size)
fr_dict_attr_t const * root
@ FR_TAC_PLUS_AUTHOR_STATUS_PASS_ADD
@ FR_TAC_PLUS_AUTHOR_STATUS_FAIL
@ FR_TAC_PLUS_AUTHOR_STATUS_PASS_REPL
#define packet_is_acct_reply(p)
#define packet_is_encrypted(p)
#define packet_is_author_request(p)
#define packet_is_acct_request(p)
#define packet_is_authen_start_request(p)
3.4.
fr_tacacs_packet_hdr_t hdr
@ FR_TAC_PLUS_ACCT_STATUS_SUCCESS
@ FR_TAC_PLUS_ACCT_STATUS_ERROR
@ FR_TAC_PLUS_AUTHEN_STATUS_PASS
@ FR_TAC_PLUS_AUTHEN_STATUS_GETDATA
@ FR_TAC_PLUS_AUTHEN_STATUS_ERROR
@ FR_TAC_PLUS_AUTHEN_STATUS_GETUSER
@ FR_TAC_PLUS_AUTHEN_STATUS_FAIL
@ FR_TAC_PLUS_AUTHEN_STATUS_RESTART
@ FR_TAC_PLUS_AUTHEN_STATUS_GETPASS
#define packet_is_author_reply(p)
static int talloc_const_free(void const *ptr)
Free const'd memory.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Entry point for protocol decoders.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static size_t char ** out