]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
update code and documentation for structural attributes in "users"
authorAlan T. DeKok <aland@freeradius.org>
Thu, 21 Dec 2023 14:34:53 +0000 (09:34 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 21 Dec 2023 15:59:27 +0000 (10:59 -0500)
doc/antora/modules/raddb/pages/mods-config/files/users.adoc
src/lib/server/map.c
src/tests/modules/files/authorize
src/tests/modules/files/digest.attrs [new file with mode: 0644]
src/tests/modules/files/digest.unlang [new file with mode: 0644]

index 83fc165d2da01db4b9e7a30404d39cc5e2d84597..0808b78740bf7e347bd451f437c4391beed31cca 100644 (file)
@@ -152,7 +152,39 @@ The default list for the check items is `control`.  Specifying another list mean
 
 The default list for the reply items is `reply`.  Specifying another list means that the other list is updated, instead of the `reply` list.
 
-It is not possible in the `users` file to create, compare, or edit a structural data type such as `struct` or `tlv`.  Instead, the relevant leaf or child attribute has to be created, which will automatically create the parent.
+==== Structural Data Types
+
+Structural data types such as `tlv`, `group`, and `struct` are handled somewhat oddly in the `users` file.  The reason for this behavior is due to the limitations of the `users` file format.  In constrast, nested attributes are handled simply and clearly by the new xref:reference:unlang/edit.adoc[edit] functionality.  If there is any confusion or uncertainty about how the `users` file operates, we recommend just using the new xref:reference:unlang/edit.adoc[edit] functionality.
+
+It is not possible to perform comparisons structural data types.  It is only possible to create and edit them.
+
+Care should be taken when using `+=` with structural attributes.  Unlike the xref:reference:unlang/edit.adoc[edit] operations `+=` here means _create a new structural attribute and append it_.  The `+=` operator does not mean _append the child attributes to the structural attribute_.  The most common issue seen with using `+=` is where it creates two `Vendor-Specific` attributes, which will cause problems.
+
+The solution instead is to use `:=` when referring to structural attributes by name, or instead using the name of a leaf attribute (e.g. `Vendor-Specific.Cisco.AVPair`), and then using `+=` on the leaf.
+
+In most situations, the simplest approach for structural data types is to just create the leaf attributes.  e.g. `&foo.bar.baz := 5`.  If any parent attribute is missing, it will be automatically created.  That is, operations on leaf types will just "do the right thing" most of the time, so there is no need to explicitly refer to a structural data type by name.
+
+There are some situations where it is useful to refer to structural attributes by name, as given in the examples below.
+
+Structural attributes can be copied from another attribute.  Both source and destination attributes must have the same data type.
+
+.Copying a Structural attribute by name
+----
+bob    Password.Cleartext := "hello"
+       Vendor-Specific.Cisco := &control.Vendor-Specific.Cisco
+----
+
+This example copies the `Vendor-Specific.Cisco` group from the `&control` list.  If the attribute does not exist in the control list, nothing is done.
+
+Structural attributes can be created from a string, as with the xref:reference:unlang/edit.adoc[edit] funtionality.
+
+.Creating a Structural attribute from a string
+----
+bob    Password.Cleartext := "hello"
+       Vendor-Specific.Cisco := "AVPair = 'hello'"
+----
+
+This example creates the reply attribute `Vendor-Specific.Cisco.AVPair`, with value `hello`.  If the parent attributes `Vendor-Specific` or `Cisco` do not exist, they are created.
 
 === Item Operators
 
index 77df3f724d8b7c47e94588fabb9cd9c7e31771b4..9665037d98e23bb0abc54000e66e8646d201338f 100644 (file)
@@ -592,11 +592,21 @@ ssize_t map_afrom_substr(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, fr_sbuf
                         *
                         *      Which is a damned hack.
                         */
-                       if (map->op == T_OP_CMP_TRUE) goto parse_rhs;
+                       if ((map->op == T_OP_CMP_TRUE) || (map->op == T_OP_CMP_FALSE)) goto parse_rhs;
 
-                       fr_strerror_const("Structural attributes are not supported");
-                       goto error;
+                       if (fr_comparison_op[map->op]) {
+                               fr_sbuff_set(&our_in, &m_op);
+                               fr_strerror_const("Comparison operators cannot be used for structural attributes");
+                               goto error;
+                       }
 
+                       /*
+                        *      radius_legacy_map_cmp() and radius_legacy_map_apply() both support structural
+                        *      attributes with RHS strings.  And this function is only called from
+                        *      users_file.c.  The consumers of the users file only call the radius legacy map
+                        *      functions.
+                        */
+                       goto parse_rhs;
 #if 0
                        /*
                         *      @todo - check for, and allow '&'
index e0d9c02631cbc2060d41abd0a7948f3401652819..7260823c9949335a6af98b22c471b1a0653f8a77 100644 (file)
@@ -133,6 +133,9 @@ xlat        Password.Cleartext := "open"
 attrref_check Filter-Id == &NAS-Identifier, NAS-IP-Address == "%{Calling-Station-Id}", Password.Cleartext := "whoops"
              Reply-Message := "success"
 
+digest Password.Cleartext := "woo"
+       Digest-Attributes := 'Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093", Method = "Invite", URI = "sip:bob@biloxi.com"'
+
 DEFAULT        User-Name == "cmp_eq",  Password.Cleartext := "hopping"
        Reply-Message := "success-cmp_eq"
 
diff --git a/src/tests/modules/files/digest.attrs b/src/tests/modules/files/digest.attrs
new file mode 100644 (file)
index 0000000..f0abad6
--- /dev/null
@@ -0,0 +1,13 @@
+#
+#  Input packet
+#
+Packet-Type = Access-Request
+User-Name = "digest"
+User-Password = "woo"
+NAS-IP-Address = "1.2.3.4"
+
+#
+#  Expected answer
+#
+Packet-Type == Access-Accept
+Digest-Attributes == { Nonce == "dcd98b7102dd2f0e8b11d0f600bfb0c093", Method == "Invite", URI == "sip:bob@biloxi.com" }
diff --git a/src/tests/modules/files/digest.unlang b/src/tests/modules/files/digest.unlang
new file mode 100644 (file)
index 0000000..027271b
--- /dev/null
@@ -0,0 +1 @@
+files