From: Alan T. DeKok Date: Sat, 6 Dec 2025 15:33:27 +0000 (-0500) Subject: enforce correct mapping between protocol name and number X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=012487542228259eb6fe92af47eba623ddd29a83;p=thirdparty%2Ffreeradius-server.git enforce correct mapping between protocol name and number This is necessary because we want to have some protocol-specific behavior in the core. It doesn't make sense to allow the administrator to change protocol numbers. --- diff --git a/src/lib/util/dict_priv.h b/src/lib/util/dict_priv.h index 9027fdcfa35..5ef272e6d2b 100644 --- a/src/lib/util/dict_priv.h +++ b/src/lib/util/dict_priv.h @@ -157,6 +157,22 @@ struct fr_dict_gctx_s { fr_dict_attr_t const *attr_protocol_encapsulation; }; +typedef enum { + FR_DICT_PROTO_RADIUS = 1, + FR_DICT_PROTO_DHCPv4 = 2, + FR_DICT_PROTO_DHCPv6 = 3, + FR_DICT_PROTO_ETHERNET = 4, + FR_DICT_PROTO_TACACS = 5, + FR_DICT_PROTO_VMPS = 6, + FR_DICT_PROTO_SNMP = 7, + FR_DICT_PROTO_ARP = 8, + FR_DICT_PROTO_TFTP = 9, + FR_DICT_PROTO_TLS = 10, + FR_DICT_PROTO_DNS = 11, + FR_DICT_PROTO_LDAP = 12, + FR_DICT_PROTO_BFD = 13, +} fr_dict_protocol_id_t; + extern fr_dict_gctx_t *dict_gctx; bool dict_has_dependents(fr_dict_t *dict); diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index 9a9af4fdca8..7d81e8b0502 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -2805,6 +2805,28 @@ static int dict_read_process_vendor(dict_tokenize_ctx_t *dctx, char **argv, int return 0; } +/** The main protocols that we care about. + * + * Not all of them are listed here, but that should be fine. + * + */ +static fr_table_num_ordered_t const dict_proto_table[] = { + { L("RADIUS"), FR_DICT_PROTO_RADIUS }, + { L("DHCPv4"), FR_DICT_PROTO_DHCPv4 }, + { L("DHCPv6"), FR_DICT_PROTO_DHCPv6 }, + { L("Ethernet"), FR_DICT_PROTO_ETHERNET }, + { L("TACACS"), FR_DICT_PROTO_TACACS }, + { L("VMPS"), FR_DICT_PROTO_VMPS }, + { L("SNMP"), FR_DICT_PROTO_SNMP }, + { L("ARP"), FR_DICT_PROTO_ARP }, + { L("TFTP"), FR_DICT_PROTO_TFTP }, + { L("TLS"), FR_DICT_PROTO_TLS }, + { L("DNS"), FR_DICT_PROTO_DNS }, + { L("LDAP"), FR_DICT_PROTO_LDAP }, + { L("BFD"), FR_DICT_PROTO_BFD }, +}; +static size_t const dict_proto_table_len = NUM_ELEMENTS(dict_proto_table); + /** Register the specified dictionary as a protocol dictionary * * Allows vendor and TLV context to persist across $INCLUDEs @@ -2815,6 +2837,8 @@ static int dict_read_process_protocol(dict_tokenize_ctx_t *dctx, char **argv, in unsigned int type_size = 0; fr_dict_t *dict; fr_dict_attr_t *mutable; + unsigned int required_value; + char const *required_name; bool require_dl = false; bool string_based = false; @@ -2850,6 +2874,26 @@ static int dict_read_process_protocol(dict_tokenize_ctx_t *dctx, char **argv, in return -1; } + /* + * While the numbers are in the dictionaries, the administrator cannot change "RADIUS" to be a + * different number. Similarly, they can't assign the RADIUS number to a different protocol. + */ + required_value = fr_table_value_by_str(dict_proto_table, argv[0], 0); + if (required_value && (required_value != value)) { + fr_strerror_printf("Invalid value '%u' following PROTOCOL - expected '%u'", value, required_value); + return -1; + } + + /* + * And the administrator can't define the name to be a different number. + */ + required_name = fr_table_str_by_value(dict_proto_table, value, NULL); + if (required_name && (strcasecmp(required_name, argv[0]) != 0)) { + fr_strerror_printf("Invalid value '%u' for PROTOCOL '%s' - that value is already used by '%s'", + value, argv[0], required_name); + return -1; + } + /* * Look for a format statement. This may specify the * type length of the protocol's types.