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>
47 fr_strerror_printf(
"Invalid value %d for authentication continue flag", pkt->authen_cont.flags);
51 switch (pkt->authen_reply.status) {
80 fr_strerror_printf(
"Invalid value %d for authentication reply status", pkt->authen_reply.status);
88 switch (pkt->author_reply.status) {
106 fr_strerror_printf(
"Invalid value %d for authorization reply status", pkt->author_reply.status);
114 switch (pkt->acct_reply.status) {
126 fr_strerror_printf(
"Invalid value %d for accounting reply status", pkt->acct_reply.status);
135#define PACKET_HEADER_CHECK(_msg, _hdr) do { \
136 p = buffer + FR_HEADER_LENGTH; \
137 if (sizeof(_hdr) > (size_t) (end - p)) { \
138 fr_strerror_printf("Header for %s is too small (%zu < %zu)", _msg, (size_t) (end - p), sizeof(_hdr)); \
141 body = p + sizeof(_hdr); \
142 data_len = sizeof(_hdr); \
148#define ARG_COUNT_CHECK(_msg, _hdr) do { \
149 fr_assert(p == (uint8_t const *) &(_hdr)); \
150 if (data_len > (size_t) (end - p)) { \
151 fr_strerror_printf("Argument count %u overflows the remaining data (%zu) in the %s packet", _hdr.arg_cnt, (size_t) (end - p), _msg); \
155 attrs = buffer + FR_HEADER_LENGTH + data_len; \
156 body += _hdr.arg_cnt; \
158 for (unsigned int i = 0; i < _hdr.arg_cnt; i++) { \
159 if (_hdr.arg_len[i] > (size_t) (end - p)) { \
160 fr_strerror_printf("Argument %u length %u overflows packet", i, _hdr.arg_len[i]); \
163 p += _hdr.arg_len[i]; \
167#define DECODE_FIELD_UINT8(_da, _field) do { \
168 vp = fr_pair_afrom_da(ctx, _da); \
169 if (!vp) goto fail; \
170 vp->vp_uint8 = _field; \
171 FR_PAIR_APPEND(out, vp); \
174#define DECODE_FIELD_STRING8(_da, _field) do { \
175 if (tacacs_decode_field(ctx, out, _da, &p, \
176 _field, end) < 0) goto fail; \
179#define DECODE_FIELD_STRING16(_da, _field) do { \
180 if (tacacs_decode_field(ctx, out, _da, &p, \
181 ntohs(_field), end) < 0) goto fail; \
184#define BODY(_x) (((uint8_t const *) pkt) + sizeof(pkt->hdr) + sizeof(pkt->_x))
202 if (!arg_cnt)
return 0;
213 if (!vendor)
return -1;
225 for (i = 0; i < arg_cnt; i++) {
231 if (argv[i] > (end - p))
return -1;
233 if (argv[i] < 2)
goto next;
235 memcpy(
buffer, p, argv[i]);
238 arg_end =
buffer + argv[i];
245 if (*
value <
' ')
goto next;
258 if (!name_end)
goto next;
285 dst = &vendor->vp_group;
299 if ((arg_end >
value) &&
305 if ((arg_end >
value) &&
310 }
else if (arg_end ==
value) {
355 arg_end = p + argv[i];
357 if ((arg_end >
value) &&
386 uint8_t const *p = *field_data;
389 if (field_len > (end - p)) {
391 da->name, field_len, (
size_t) (end - p));
429 uint8_t const *p, *body, *argv, *attrs, *end;
458 end =
buffer + buffer_len;
464 if (buffer_len <
sizeof(pkt->
hdr)) {
472 if (!(pkt->
hdr.ver.major == 12 && (pkt->
hdr.ver.minor == 0 || pkt->
hdr.ver.minor == 1))) {
511 if (original && (memcmp(original + 4,
buffer + 4, 4) != 0)) {
550 decrypted = talloc_memdup(ctx,
buffer, buffer_len);
557 end = decrypted + buffer_len;
603 data_len += p[4] + p[5] + p[6] + p[7];
604 if (data_len > (
size_t) (end - p)) {
608 fr_strerror_const(
"Invalid packet after decryption - is the secret key incorrect?");
615 if (data_len < (
size_t) (end - p)) {
639 pkt->authen_start.user_len);
642 pkt->authen_start.rem_addr_len);
651 switch (pkt->authen_start.authen_type) {
654 want = pkt->authen_start.data_len;
658 case FR_AUTHENTICATION_TYPE_VALUE_PAP:
659 want = pkt->authen_start.data_len;
663 case FR_AUTHENTICATION_TYPE_VALUE_CHAP:
669 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAP:
675 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAPV2:
689 if (raw || (pkt->authen_start.data_len < want)) {
694 if (!da_unknown)
goto fail;
696 want = pkt->authen_start.data_len;
701 }
else if (!challenge) {
704 }
else if (pkt->authen_start.data_len == want) {
709 uint8_t challenge_len = pkt->authen_start.data_len - want;
720 switch (pkt->authen_start.authen_type) {
721 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAP:
722 case FR_AUTHENTICATION_TYPE_VALUE_MSCHAPV2:
723 hash[1] = p[want - 1];
724 memcpy(
hash + 2, p + 1 + challenge_len, want - 2);
728 memcpy(
hash + 1, p + 1 + challenge_len, want - 1);
752 p += pkt->authen_start.data_len;
776 if (pkt->
hdr.ver.minor != 0) {
784 if (data_len > (
size_t) (end - p))
goto overflow;
785 if (data_len < (
size_t) (end - p))
goto underflow;
821 if (data_len > (
size_t) (end - p))
goto overflow;
822 if (data_len < (
size_t) (end - p))
goto underflow;
871 if (pkt->
hdr.ver.minor != 0)
goto invalid_version;
874 data_len += p[4] + p[5] + p[6] + p[7];
896 pkt->author_req.rem_addr_len);
902 pkt->author_req.arg_cnt, argv, attrs, end) < 0)
goto fail;
955 pkt->author_reply.arg_cnt, argv, attrs, end) < 0)
goto fail;
992 if (pkt->
hdr.ver.minor != 0)
goto invalid_version;
995 data_len += p[5] + p[6] + p[7] + p[8];
996 if (data_len > (
size_t) (end - p))
goto overflow;
1024 pkt->acct_req.arg_cnt, argv, attrs, end) < 0)
goto fail;
1047 if (data_len > (
size_t) (end - p))
goto overflow;
1048 if (data_len < (
size_t) (end - p))
goto underflow;
1050 p =
BODY(acct_reply);
1101 if (slen < 0)
return slen;
1104 vp->vp_uint32 = code;
1127 if (!test_ctx)
return -1;
static int const char char buffer[256]
static uint8_t overflow[100]
fr_dict_attr_t const * root_da
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.
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
@ 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 fr_radius_decode_fail_t decode(TALLOC_CTX *ctx, fr_pair_list_t *reply, uint8_t *response_code, bio_handle_t *h, request_t *request, bio_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.
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)
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_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, UNUSED bool tainted)
Convert string value to native attribute value.
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.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
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_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
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
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
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_type
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)
#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)
fr_tacacs_packet_code_t fr_tacacs_packet_to_code(fr_tacacs_packet_t const *pkt)
static int _encode_test_ctx(fr_tacacs_ctx_t *test_ctx)
#define PACKET_HEADER_CHECK(_msg, _hdr)
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, uint8_t const *end)
Decode a TACACS+ 'arg_N' fields.
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, fr_tacacs_packet_code_t *code)
Decode a TACACS+ packet.
#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)
#define ARG_COUNT_CHECK(_msg, _hdr)
static unsigned int hash(char const *username, unsigned int tablesize)
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)
@ FR_TAC_PLUS_ACCT_STATUS_SUCCESS
@ FR_TAC_PLUS_ACCT_STATUS_FOLLOW
@ FR_TAC_PLUS_ACCT_STATUS_ERROR
@ FR_TACACS_CODE_ACCT_ERROR
@ FR_TACACS_CODE_ACCT_REQUEST
@ FR_TACACS_CODE_AUTZ_REQUEST
@ FR_TACACS_CODE_AUTH_GETDATA
@ FR_TACACS_CODE_AUTH_RESTART
@ FR_TACACS_CODE_AUTZ_PASS_REPLACE
@ FR_TACACS_CODE_AUTH_GETUSER
@ FR_TACACS_CODE_AUTH_GETPASS
@ FR_TACACS_CODE_AUTZ_FAIL
@ FR_TACACS_CODE_AUTH_CONT_ABORT
@ FR_TACACS_CODE_AUTH_PASS
@ FR_TACACS_CODE_AUTH_CONT
@ FR_TACACS_CODE_AUTZ_PASS_ADD
@ FR_TACACS_CODE_AUTH_START
@ FR_TACACS_CODE_AUTH_FAIL
@ FR_TACACS_CODE_AUTH_ERROR
@ FR_TACACS_CODE_AUTZ_ERROR
@ FR_TACACS_CODE_ACCT_SUCCESS
#define packet_is_authen_continue(p)
#define fr_tacacs_packet_log_hex(_log, _packet, _size)
fr_dict_attr_t const * root
#define packet_is_acct_reply(p)
@ 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_FOLLOW
@ FR_TAC_PLUS_AUTHEN_STATUS_RESTART
@ FR_TAC_PLUS_AUTHEN_STATUS_GETPASS
@ FR_TAC_PLUS_UNENCRYPTED_FLAG
#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_TAC_PLUS_CONTINUE_FLAG_UNSET
@ FR_TAC_PLUS_CONTINUE_FLAG_ABORT
@ 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_tacacs_packet_hdr_t hdr
@ FR_TAC_PLUS_AUTHOR_STATUS_PASS_ADD
@ FR_TAC_PLUS_AUTHOR_STATUS_FOLLOW
@ FR_TAC_PLUS_AUTHOR_STATUS_ERROR
@ FR_TAC_PLUS_AUTHOR_STATUS_FAIL
@ FR_TAC_PLUS_AUTHOR_STATUS_PASS_REPL
#define packet_is_author_reply(p)
static int talloc_const_free(void const *ptr)
Free const'd memory.
#define talloc_strdup(_ctx, _str)
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
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,...)
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)
static fr_sbuff_err_t char ** out