/**
* Decode a TACACS+ 'arg_N' fields.
*/
-static int tacacs_decode_args(TALLOC_CTX *ctx, fr_dcursor_t *cursor, fr_dict_attr_t const *da,
+static int tacacs_decode_args(TALLOC_CTX *ctx, fr_dcursor_t *cursor, fr_dict_attr_t const *parent,
uint8_t arg_cnt, uint8_t const *arg_list, uint8_t const **data, uint8_t const *end)
{
uint8_t i;
* Then, do the dirty job...
*/
for (i = 0; i < arg_cnt; i++) {
- if ((p + arg_list[i]) > end) {
+ uint8_t const *value, *name_end, *arg_end;
+ fr_dict_attr_t const *da;
+ uint8_t buffer[256];
+
+ if (arg_list[i] < 2) goto next; /* skip malformed */
+
+ if (p + arg_list[i] > end) {
fr_strerror_printf("'%s' argument %u length %u overflows the remaining data in the packet",
- da->name, i, arg_list[i]);
+ parent->name, i, arg_list[i]);
return -1;
}
+ memcpy(buffer, p, arg_list[i]);
+ buffer[arg_list[i]] = '\0';
+
+ arg_end = buffer + arg_list[i];
+
+ for (value = buffer, name_end = NULL; value < arg_end; value++) {
+ /*
+ * RFC 8907 Section 3.7 says control
+ * characters MUST be excluded.
+ */
+ if (*value < ' ') goto next;
+
+ if ((*value == '=') || (*value == '*')) {
+ name_end = value;
+ buffer[value - buffer] = '\0';
+ value++;
+ break;
+ }
+ }
+
+ /*
+ * Skip fields which aren't in "name=value" or "name*value" format.
+ */
+ if (!name_end) goto next;
+
+ da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_tacacs), (char *) buffer);
+ if (!da) {
+ raw:
+ /*
+ * Dupe the whole thing so that we have:
+ *
+ * Argument-List += "name=value"
+ */
+ da = parent;
+ value = p;
+ arg_end = p + arg_list[i];
+ }
+
vp = fr_pair_afrom_da(ctx, da);
if (!vp) {
fr_strerror_const("Out of Memory");
return -1;
+
+ }
+
+ /*
+ * Parse the string, and try to convert it to the
+ * underlying data type. If it can't be
+ * converted as a data type, just convert it as
+ * Argument-List.
+ *
+ * And if that fails, just ignore it completely.
+ */
+ if (fr_pair_value_from_str(vp, (char const *) value, arg_end - value, 0, true) < 0) {
+ talloc_free(vp);
+ if (da != parent) goto raw;
+
+ goto next;
}
- fr_pair_value_bstrndup(vp, (char const *) p, arg_list[i], true);
fr_dcursor_append(cursor, vp);
+
+ next:
p += arg_list[i];
*data = p;
}
# Accounting - Request: (Client -> Server)
#
decode-proto c0 03 01 00 07 9b 35 d9 00 00 00 5b 7c 8a 99 d6 88 f9 32 3c ec 34 6d 23 89 71 72 dd 89 46 75 df 9c 00 a5 96 28 05 fc 57 88 02 0c 11 a3 60 9a 05 8b 71 6d 27 ca 83 b0 ab 2f 00 27 c8 da 58 d3 1a f1 3f 07 17 8d f6 35 c5 7b e2 07 be 29 86 d4 93 16 99 04 01 ef 03 6c 1c 2b ad 3a fb 5b 11 06 61 dc d9 09 1d 6a 08 1e
-match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Accounting, Packet.Sequence-Number = 1, Packet.Flags = None, Packet.Session-Id = 127612377, Packet.Length = 91, Packet-Body-Type = Request, Accounting-Flags = Start, Authentication-Method = TACACSPLUS, Privilege-Level = Minimum, Authentication-Type = PAP, Authentication-Service = PPP, User-Name = "bob", Client-Port = "tapioca/0", Remote-Address = "localhost", Argument-List = "", Argument-List = "start_time=1596565644", Argument-List = "task_id=17558", Argument-List = "service=ppp", Argument-List = "protocol=ip"
+match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Accounting, Packet.Sequence-Number = 1, Packet.Flags = None, Packet.Session-Id = 127612377, Packet.Length = 91, Packet-Body-Type = Request, Accounting-Flags = Start, Authentication-Method = TACACSPLUS, Privilege-Level = Minimum, Authentication-Type = PAP, Authentication-Service = PPP, User-Name = "bob", Client-Port = "tapioca/0", Remote-Address = "localhost", Argument-List = "start_time=1596565644", Argument-List = "task_id=17558", Argument-List = "service=ppp", Argument-List = "protocol=ip"
encode-proto -
-match c0 03 01 00 07 9b 35 d9 00 00 00 5b 7c 8a 99 d6 88 f9 32 3c ec 34 6d 23 89 71 72 dd 89 46 75 df 9c 00 a5 96 28 05 fc 57 88 02 0c 11 a3 60 9a 05 8b 71 6d 27 ca 83 b0 ab 2f 00 27 c8 da 58 d3 1a f1 3f 07 17 8d f6 35 c5 7b e2 07 be 29 86 d4 93 16 99 04 01 ef 03 6c 1c 2b ad 3a fb 5b 11 06 61 dc d9 09 1d 6a 08 1e
+match c0 03 01 00 07 9b 35 d9 00 00 00 5a 7c 8a 99 d6 88 f9 32 3c ed 21 75 25 89 18 7f d0 9f 53 64 c6 9a 0c a7 d8 37 59 ff 5b 8a 0f 08 16 bf 67 9d 02 9e 62 6b 0c e1 9e b4 a3 77 0c 23 c4 d5 5b d0 19 f2 3d 07 57 98 e4 2d f1 4d ef 5e b2 2f 84 d4 9e 5d 8f 13 05 f0 09 6a 44 66 ad 3a fb 59 0c 1d 7a d0 d5 0a 4c 3e 11
#
# Accounting - Response: (Client <- Server)