]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
check tmpl types for casting
authorAlan T. DeKok <aland@freeradius.org>
Thu, 7 Jan 2021 15:28:26 +0000 (10:28 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 7 Jan 2021 20:50:10 +0000 (15:50 -0500)
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

src/lib/server/tmpl_tokenize.c
src/tests/unit/condition/base.txt

index d71bdf1d27de6287abb03d7f4f0f393c18187564..455518a77fc1a3af86cfe5c472ecfa41629cb1dd 100644 (file)
@@ -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;
 }
 
index 7218e1158c8060158082b1ac0317dfc857c3720c..2fcc42034f151012b7b9790fd1acb83c660a8c10 100644 (file)
@@ -135,8 +135,8 @@ match ERROR offset 0: Cannot do cast for existence check
 condition <ipaddr>&Filter-Id == &Framed-IP-Address
 match <ipaddr>&Filter-Id == &Framed-IP-Address
 
-condition <ipaddr>&Filter-Id == <ipaddr>&Framed-IP-Address
-match ERROR offset 22: Unexpected cast
+condition <ipaddr>&Filter-Id == &Framed-IP-Address
+match <ipaddr>&Filter-Id == &Framed-IP-Address
 
 condition <ipaddr>&Filter-Id == <integer>&Framed-IP-Address
 match ERROR offset 22: Unexpected cast