-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
What type of defect/bug is this?
Crash or memory corruption (segv, abort, etc...)
How can the issue be reproduced?
I am trying to configure FreeRADIUS 3.2.7 (originally encountered on 3.2.1, updated to 3.2.7) on Debian Bookworm to dynamically omit specific attributes from the Access-Accept reply for a given NAS, based on a configuration stored in a PostgreSQL database.
My goal is to control which attributes are sent to each NAS device individually from a frontend by defining omission rules in the database.
Initial Approach (Attempt 1): Dynamic Removal using foreach &reply in post-auth
My first approach was to:
Fetch a comma-separated string of attribute names to omit from a database table (e.g., nas_attr_omit) using a SQL query in post-auth, storing it in a control attribute (control:Tmp-String-0).
Iterate over the reply list using foreach &reply.
Check if the current attribute's name (%{Foreach-Variable-0}) was in the control:Tmp-String-0 list using a regex match (if (control:Tmp-String-0 =~ /.../)).
If matched, remove the current attribute from the reply list within the loop using update reply { reply -= ${.item} } or update reply { -${.item} }.
This configuration consistently failed to parse with errors like:
Reference "${.item}" not found
Errors related to the syntax within the update reply block inside the foreach.
After reviewing the Unlang documentation for the foreach statement, I realized that attributes being looped over cannot be modified or deleted within the foreach loop itself. This limitation explains why this first approach was fundamentally incorrect and likely caused the misleading parsing errors.
Recommended Approach (Attempt 2): Fetch Filter Profile Name from SQL and Use switch in post-auth
Based on further discussion, I adopted a new approach which seems more aligned with Unlang capabilities:
Fetch a "filter profile name" (e.g., 'omit_mikrotik_rate', 'standard_omissions') from a database table (nas_filter_profiles) based on the NAS IP (%{client:ipaddr}) in post-auth, storing it in control:Filter-Profile.
Use an if condition to check if control:Filter-Profile was successfully populated.
Inside the if block, use a switch statement based on the value of %{control:Filter-Profile}.
Within each case of the switch, define static attribute removals using update reply { -Attribute-Name } for the specific attributes associated with that profile.
Here is the relevant part of my post-auth configuration using this method:
post-auth {
# ... (update control to fetch Filter-Profile from DB) ...
# Check if Filter-Profile attribute exists and is not empty
if (!empty(control:Filter-Profile)) { # <--- Error occurs on this line
switch ("%{control:Filter-Profile}") {
case "omit_mikrotik_rate":
update reply { -Mikrotik-Rate-Limit }
case "standard_omissions":
update reply { -Attribute-A -Attribute-B }
# ... other cases ...
}
}
# ... (rest of post-auth, including sql and Post-Auth-Type REJECT) ...
}
Current Problem: Persistent Parse Error on if (!empty(control:Filter-Profile))
Using the configuration for Attempt 2, I consistently get a parse error specifically on the if (!empty(control:Filter-Profile)) { line. The exact error message is:
/etc/freeradius/sites-enabled/defaukt[XX]: Parse error in condition/etc/freeradius/sites-enabled/default[XX]: (!empty(control:Filter-Profile)) {/etc/freeradius/sites-enabled/default[XX]: ^ Expected a module return code
(Note: The line number XX shifts slightly with minor file edits, but it's consistently on the if (!empty(...)) line).
This error message is very unusual. if (!empty(attribute)) is standard Unlang syntax for checking if an attribute exists and is non-empty. The parser should not be expecting a "module return code" here.
Troubleshooting Performed for Current Problem:
Verified file encoding (using cat -vte, it looks clean).
Attempted alternative syntax for the condition: if (control:Filter-Profile) { ... }. This resulted in a similar parse error at the same location, also expecting a module return code.
Simplified the code inside the if block temporarily (e.g., if (1) { noop }) in earlier debugging stages. While this simpler structure parsed, reintroducing the if (!empty(...)) or if (attribute) condition caused the "Expected a module return code" error to reappear.
Updated FreeRADIUS from 3.2.1 to 3.2.7. The error persists in the newer version.
Confirmed that the sql module is enabled and configured correctly (it's used successfully elsewhere for authentication/accounting).
Summary:
I am unable to get a standard if condition checking for the existence/value of a control attribute (control:Filter-Profile) to parse correctly in the post-auth section using FreeRADIUS 3.2.7. The persistent error "Expected a module return code" on the if line suggests a problem with the parser's interpretation of this standard Unlang construct in this specific context and nesting level.
I suspect this may be a parser bug in the FreeRADIUS 3.x branch or a very specific issue with my server environment that affects parsing.
Could someone please review my configuration and advise on why this standard if (!empty(...)) condition might be failing to parse? Is there a known issue with this syntax in this context, or a recommended workaround if the standard syntax is problematic?
Thank you for your time and assistance.
Log output from the FreeRADIUS daemon
root@debianserver[/home/server/installer]# freeradius -X
FreeRADIUS Version 3.2.7
Copyright (C) 1999-2023 The FreeRADIUS server project and contributors
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE
You may redistribute copies of FreeRADIUS under the terms of the
GNU General Public License
For more information about these matters, see the file named COPYRIGHT
Starting - reading configuration files ...
including dictionary file /usr/share/freeradius/dictionary
including dictionary file /usr/share/freeradius/dictionary.dhcp
including dictionary file /usr/share/freeradius/dictionary.vqp
including dictionary file /etc/freeradius/dictionary
including configuration file /etc/freeradius/radiusd.conf
including configuration file /etc/freeradius/proxy.conf
including configuration file /etc/freeradius/clients.conf
including files in directory /etc/freeradius/mods-enabled/
including configuration file /etc/freeradius/mods-enabled/mschap
including configuration file /etc/freeradius/mods-enabled/ntlm_auth
including configuration file /etc/freeradius/mods-enabled/always
including configuration file /etc/freeradius/mods-enabled/linelog
including configuration file /etc/freeradius/mods-enabled/utf8
including configuration file /etc/freeradius/mods-enabled/sql
including configuration file /etc/freeradius/mods-config/sql/main/postgresql/queries.conf
including configuration file /etc/freeradius/mods-enabled/eap
including configuration file /etc/freeradius/mods-enabled/files
including configuration file /etc/freeradius/mods-enabled/passwd
including configuration file /etc/freeradius/mods-enabled/replicate
including configuration file /etc/freeradius/mods-enabled/sradutmp
including configuration file /etc/freeradius/mods-enabled/soh
including configuration file /etc/freeradius/mods-enabled/attr_filter
including configuration file /etc/freeradius/mods-enabled/proxy_rate_limit
including configuration file /etc/freeradius/mods-enabled/unpack
including configuration file /etc/freeradius/mods-enabled/preprocess
including configuration file /etc/freeradius/mods-enabled/date
including configuration file /etc/freeradius/mods-enabled/expr
including configuration file /etc/freeradius/mods-enabled/dynamic_clients
including configuration file /etc/freeradius/mods-enabled/realm
including configuration file /etc/freeradius/mods-enabled/detail.log
including configuration file /etc/freeradius/mods-enabled/exec
including configuration file /etc/freeradius/mods-enabled/radutmp
including configuration file /etc/freeradius/mods-enabled/pap
including configuration file /etc/freeradius/mods-enabled/echo
including configuration file /etc/freeradius/mods-enabled/unix
including configuration file /etc/freeradius/mods-enabled/array
including configuration file /etc/freeradius/mods-enabled/totp
including configuration file /etc/freeradius/mods-enabled/chap
including configuration file /etc/freeradius/mods-enabled/detail
including configuration file /etc/freeradius/mods-enabled/expiration
including configuration file /etc/freeradius/mods-enabled/logintime
including configuration file /etc/freeradius/mods-enabled/digest
including files in directory /etc/freeradius/policy.d/
including configuration file /etc/freeradius/policy.d/cui
including configuration file /etc/freeradius/policy.d/rfc7542
including configuration file /etc/freeradius/policy.d/accounting
including configuration file /etc/freeradius/policy.d/operator-name
including configuration file /etc/freeradius/policy.d/eap
including configuration file /etc/freeradius/policy.d/filter
including configuration file /etc/freeradius/policy.d/canonicalization
including configuration file /etc/freeradius/policy.d/abfab-tr
including configuration file /etc/freeradius/policy.d/moonshot-targeted-ids
including configuration file /etc/freeradius/policy.d/control
including configuration file /etc/freeradius/policy.d/debug
including configuration file /etc/freeradius/policy.d/dhcp
including files in directory /etc/freeradius/sites-enabled/
including configuration file /etc/freeradius/sites-enabled/default
/etc/freeradius/sites-enabled/default[84]: Expecting section start brace '{' after "foreach &attr"
Errors reading or parsing /etc/freeradius/radiusd.conf
root@debianserver[/home/server/installer]#Relevant log output from client utilities
No response