From: Alan T. DeKok Date: Thu, 7 Jan 2021 15:28:26 +0000 (-0500) Subject: check tmpl types for casting X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ffd1edccf3856989011d847511f5b2e213fb403d;p=thirdparty%2Ffreeradius-server.git check tmpl types for casting there's no reason to cast a regex to anything. casts only apply to data types (data, attr, exec, xlat) and update tests to match --- diff --git a/src/lib/server/tmpl_tokenize.c b/src/lib/server/tmpl_tokenize.c index d71bdf1d27d..455518a77fc 100644 --- a/src/lib/server/tmpl_tokenize.c +++ b/src/lib/server/tmpl_tokenize.c @@ -2787,20 +2787,154 @@ ssize_t tmpl_cast_from_substr(fr_type_t *out, fr_sbuff_t *in) /** Set a cast for a tmpl * * @param[in,out] vpt to set cast for. - * @param[in] type to set. + * @param[in] dst_type to set. * @return * - 0 on success. * - -1 on failure. */ -int tmpl_cast_set(tmpl_t *vpt, fr_type_t type) +int tmpl_cast_set(tmpl_t *vpt, fr_type_t dst_type) { - if (fr_dict_non_data_types[type]) { - fr_strerror_const("Forbidden data type in cast"); + fr_type_t src_type; + + switch (dst_type) { + default: + fr_strerror_printf("Forbidden data type '%s' in cast", + fr_table_str_by_value(fr_value_box_type_table, dst_type, "??")); return -1; + + /* + * We can always remove a cast. + */ + case FR_TYPE_INVALID: + goto done; + + /* + * Only "base" data types are allowed. Structural types + * and horrid WiMAX crap is forbidden. + */ + case FR_TYPE_STRING: + case FR_TYPE_OCTETS: + case FR_TYPE_IPV4_ADDR: + case FR_TYPE_IPV4_PREFIX: + case FR_TYPE_IPV6_ADDR: + case FR_TYPE_IPV6_PREFIX: + case FR_TYPE_IFID: + case FR_TYPE_ETHERNET: + case FR_TYPE_BOOL: + case FR_TYPE_UINT8: + case FR_TYPE_UINT16: + case FR_TYPE_UINT32: + case FR_TYPE_UINT64: + case FR_TYPE_INT8: + case FR_TYPE_INT16: + case FR_TYPE_INT32: + case FR_TYPE_FLOAT32: + case FR_TYPE_FLOAT64: + case FR_TYPE_DATE: + case FR_TYPE_SIZE: + case FR_TYPE_TIME_DELTA: + break; } - vpt->cast = type; + switch (vpt->type) { + /* + * This should have been fixed before we got here. + */ + case TMPL_TYPE_ATTR_UNRESOLVED: + + /* + * By default, tmpl types cannot be cast to anything. + */ + default: + if (dst_type != FR_TYPE_INVALID) { + fr_strerror_const("Cannot use cast here."); + return -1; + } + break; + + /* + * These tmpl types are effectively of data type + * "string", so they can be cast to anything. + */ + case TMPL_TYPE_XLAT: + case TMPL_TYPE_EXEC: + case TMPL_TYPE_UNRESOLVED: + case TMPL_TYPE_EXEC_UNRESOLVED: + case TMPL_TYPE_XLAT_UNRESOLVED: + break; + + case TMPL_TYPE_DATA: + src_type = tmpl_value_type(vpt); + + /* + * Don't suppress duplicate casts for now, the + * conditional parser still needs them. + */ + goto check_types; + + case TMPL_TYPE_ATTR: + src_type = tmpl_da(vpt)->type; + + + /* + * Suppress casts where they are duplicate. + */ + if (src_type == dst_type) { + vpt->cast = FR_TYPE_INVALID; + return 0; + } + + check_types: + /* + * Anything can be cast to a string or octets. + */ + if ((dst_type == FR_TYPE_STRING) || (dst_type == FR_TYPE_OCTETS)) { + break; + } + + /* + * Integers, dates, etc. can all be cast to each + * other. We will do run-time checks to see if + * the _values_ being cast fit within the + * permitted data types. + */ + if ((src_type >= FR_TYPE_BOOL) && (dst_type >= FR_TYPE_BOOL)) { + break; + } + + /* + * IP address types can be cast to each other. + * + * IP addresses can also be cast to some integers, + * but we don't check for that. + */ + if (((src_type >= FR_TYPE_IPV4_ADDR) && (dst_type >= FR_TYPE_IPV4_ADDR)) && + ((src_type <= FR_TYPE_IPV6_PREFIX) && (dst_type <= FR_TYPE_IPV6_PREFIX))) { + break; + } + + /* + * IFID / Ethernet can only be cast to uint64. + * + * Note that we already check for dst_type of string/octets above. + */ + if (((src_type == FR_TYPE_IFID) || (src_type == FR_TYPE_IFID)) && (dst_type != FR_TYPE_UINT64)) { + fr_strerror_printf("Cannot cast type '%s' to '%s'", + fr_table_str_by_value(fr_value_box_type_table, src_type, "??"), + fr_table_str_by_value(fr_value_box_type_table, dst_type, "??")); + return -1; + } + /* + * Other casts MAY be forbidden, but we don't + * bother checking those here. :( + */ + break; + + } + +done: + vpt->cast = dst_type; return 0; } diff --git a/src/tests/unit/condition/base.txt b/src/tests/unit/condition/base.txt index 7218e1158c8..2fcc42034f1 100644 --- a/src/tests/unit/condition/base.txt +++ b/src/tests/unit/condition/base.txt @@ -135,8 +135,8 @@ match ERROR offset 0: Cannot do cast for existence check condition &Filter-Id == &Framed-IP-Address match &Filter-Id == &Framed-IP-Address -condition &Filter-Id == &Framed-IP-Address -match ERROR offset 22: Unexpected cast +condition &Filter-Id == &Framed-IP-Address +match &Filter-Id == &Framed-IP-Address condition &Filter-Id == &Framed-IP-Address match ERROR offset 22: Unexpected cast