right now the vendor attr has to be passed to the decode function.
The encoder should arguably be also passed a vendor, and then only
encode that vendor. But for now it's OK
fr_tacacs_packet_t const *pkt = (fr_tacacs_packet_t const *)data;
char const *secret;
size_t secretlen = 0;
+ fr_dict_attr_t const *dv = NULL;
RHEXDUMP3(data, data_len, "proto_tacacs decode packet");
secretlen = talloc_array_length(client->secret) - 1;
}
+ /*
+ * See if there's a client-specific vendor in the "nas_type" field.
+ *
+ * If there's no such vendor, too bad for you.
+ */
+ if (client->nas_type) {
+ dv = fr_dict_attr_by_name(NULL, fr_dict_root(dict_tacacs), client->nas_type);
+ }
+
/*
* Note that we don't set a limit on max_attributes here.
* That MUST be set and checked in the underlying
* transport, via a call to ???
*/
- if (fr_tacacs_decode(request->request_ctx, &request->request_pairs,
+ if (fr_tacacs_decode(request->request_ctx, &request->request_pairs, dv,
request->packet->data, request->packet->data_len,
NULL, secret, secretlen, &code) < 0) {
RPEDEBUG("Failed decoding packet");
* This only fails if the packet is strangely malformed,
* or if we run out of memory.
*/
- packet_len = fr_tacacs_decode(ctx, reply, data, data_len, NULL, inst->secret, inst->secretlen, &code);
+ packet_len = fr_tacacs_decode(ctx, reply, NULL, data, data_len, NULL, inst->secret, inst->secretlen, &code);
if (packet_len < 0) {
RPEDEBUG("Failed decoding TACACS+ reply packet");
fr_pair_list_free(reply);
* Argument-List += "name=value"
*/
if (parent) {
- da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_tacacs), (char *) buffer);
+ da = fr_dict_attr_by_name(NULL, parent, (char *) buffer);
if (!da) goto raw;
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) goto oom;
+
/*
* If it's OCTETS or STRING type, then just copy the value verbatim, as the
* contents are (should be?) binary-safe. But if it's zero length, then don't need to
raw:
vp = fr_pair_afrom_da(ctx, attr_tacacs_argument_list);
if (!vp) {
+ oom:
fr_strerror_const("Out of Memory");
return -1;
}
/**
* Decode a TACACS+ packet
*/
-ssize_t fr_tacacs_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *buffer, size_t buffer_len,
+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)
{
fr_tacacs_packet_t const *pkt;
/*
* Decode 'arg_N' arguments (horrible format)
*/
- if (tacacs_decode_args(ctx, out, NULL,
+ if (tacacs_decode_args(ctx, out, vendor,
pkt->author_req.arg_cnt, argv, attrs, end) < 0) goto fail;
} else if (packet_is_author_reply(pkt)) {
/*
* Decode 'arg_N' arguments (horrible format)
*/
- if (tacacs_decode_args(ctx, out, NULL,
+ if (tacacs_decode_args(ctx, out, vendor,
pkt->author_reply.arg_cnt, argv, attrs, end) < 0) goto fail;
} else {
/*
* Decode 'arg_N' arguments (horrible format)
*/
- if (tacacs_decode_args(ctx, out, NULL,
+ if (tacacs_decode_args(ctx, out, vendor,
pkt->acct_req.arg_cnt, argv, attrs, end) < 0) goto fail;
} else if (packet_is_acct_reply(pkt)) {
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_ctx_t *test_ctx = talloc_get_type_abort(proto_ctx, fr_tacacs_ctx_t);
+ fr_dict_attr_t const *dv;
+
+ dv = fr_dict_attr_by_name(NULL, fr_dict_root(dict_tacacs), "Test");
+ fr_assert(!dv || (dv->type == FR_TYPE_VENDOR));
- return fr_tacacs_decode(ctx, out, data, data_len, NULL,
+ return fr_tacacs_decode(ctx, out, dv, data, data_len, NULL,
test_ctx->secret, (talloc_array_length(test_ctx->secret)-1), false);
}
continue;
}
- /*
- * Maybe it's still a TACACS+ attribute?
- */
- if (fr_dict_by_da(vp->da) != dict_tacacs) continue;
+ fr_assert(fr_dict_by_da(vp->da) == dict_tacacs);
- if (!((vp->da->attr >= 1000) && (vp->da->attr <= 65000))) continue;
+ if (vp->da->parent->type != FR_TYPE_VENDOR) continue;
arg_cnt++;
}
for (vp = fr_pair_list_head(vps);
vp;
- vp = fr_pair_list_next(vps,vp)) {
+ vp = fr_pair_list_next(vps, vp)) {
int len;
if (i == 255) break;
FR_PROTO_TRACE("arg[%d] --> %s", i, vp->vp_strvalue);
len = vp->vp_length;
- } else if (fr_dict_by_da(vp->da) != dict_tacacs) {
- continue;
-
- } else if (!((vp->da->attr >= 1000) && (vp->da->attr <= 65000))) {
+ } else if (!vp->da->parent || (vp->da->parent->type != FR_TYPE_VENDOR)) {
continue;
} else {
int fr_tacacs_code_to_packet(fr_tacacs_packet_t *pkt, uint32_t code);
/* decode.c */
-ssize_t fr_tacacs_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *buffer, size_t buffer_len,
+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,
UNUSED const uint8_t *original, char const * const secret, size_t secret_len, int *code);
int fr_tacacs_packet_to_code(fr_tacacs_packet_t const *pkt);
-#
-# The numbers here don't matter. For now, just use 30000...40000
-#
-# We will document that users can define their own attributes in the space
-# 1000...9999
-#
-# @todo - define some magical *tacacs* format which doesn't use numbers?
-#
-ATTRIBUTE addr 60000 ipv4addr
+VENDOR Test 0xdeadbeef
+
+BEGIN-VENDOR Test
+
+DEFINE addr ipv4addr
+
+END-VENDOR Test
# Authorization - Response: (Client <- Server)
#
decode-proto c0 02 02 00 e1 66 78 e6 00 00 00 13 02 59 f9 90 38 81 e1 bb 9d a6 13 93 fc 86 7e 4a 14 1c 24
-match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Authorization, Packet.Sequence-Number = 2, Packet.Flags = None, Packet.Session-Id = 3781589222, Packet.Length = 19, Packet-Body-Type = Response, Authorization-Status = Pass-Add, Server-Message = "", Data = 0x, addr = 1.2.3.4
+match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Authorization, Packet.Sequence-Number = 2, Packet.Flags = None, Packet.Session-Id = 3781589222, Packet.Length = 19, Packet-Body-Type = Response, Authorization-Status = Pass-Add, Server-Message = "", Data = 0x, Test.addr = 1.2.3.4
encode-proto -
match c0 02 02 00 e1 66 78 e6 00 00 00 13 02 59 f9 90 38 81 e1 bb 9d a6 13 93 fc 86 7e 4a 14 1c 24