net/freeradius: quote password values literally so % is not expanded - #5695
Open
dotCooCoo wants to merge 3 commits into
Open
net/freeradius: quote password values literally so % is not expanded#5695dotCooCoo wants to merge 3 commits into
dotCooCoo wants to merge 3 commits into
Conversation
FreeRADIUS applies dynamic expansion to double-quoted strings, so a password containing % failed to parse and rlm_files discarded the whole user entry. The user was then rejected for having no Auth-Type, which is indistinguishable from a wrong password. Render the password as a single-quoted string, escaping the backslash and single quote that single-quoted strings honor. Widen the password mask to printable ASCII, keeping the 128 character limit, and align the field help text with it.
Both Tunnel-Password attributes were rendered with no quoting, so they failed on % in the same way as the user password and additionally ended at the first space. Render them single-quoted with the same escaping, and widen the tunnel_password and fallback_tunnel_password masks to printable ASCII to match.
Replace the repeated inline escaping with a q() macro and apply it to the remaining check items on the user line, Max-Daily-Session, Simultaneous-Use and Login-Time. Those three cannot currently hold a % given their masks, so they go through the macro to keep one rule in the file rather than a per-field judgment about which masks are safe.
This was referenced Sep 2, 2026
fichtner
reviewed
Sep 2, 2026
| <label>Password</label> | ||
| <type>password</type> | ||
| <help><![CDATA[Set the password for the user. Allowed characters are 0-9, a-z, A-Z, and ,._-!$%/()+#=:& with up to 128 characters.]]></help> | ||
| <help><![CDATA[Set the password for the user. Any printable ASCII character is allowed, with up to 128 characters.]]></help> |
Member
There was a problem hiding this comment.
FWIW: feels spurious to mention all characters are supported
fichtner
reviewed
Sep 2, 2026
| @@ -1,9 +1,10 @@ | |||
| {%- macro q(value) -%}'{{ value | replace('\\', '\\\\') | replace("'", "\\'") }}'{%- endmacro -%} | |||
Member
There was a problem hiding this comment.
I'm not really looking forward to reviewing if this is safe. Depending on concerns this may miss the bar for inclusion to not introduce other issues. In these cases a simpler fix may be the better approach.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Important notices
Before you submit a pull request, we ask you kindly to acknowledge the following:
Describe the problem
User.xmlpermits%in the password field, and theuserstemplate renders the valueinside double quotes. FreeRADIUS applies dynamic expansion to double-quoted strings, so it
reads
%as the start of an expansion sequence.Which failure you get depends on the character after the
%. A valid expansion such as%c,%dor%esubstitutes successfully, so the stored password silently becomes a differentstring and PAP reports
Cleartext password does not match "known good" password, with thegenerated file still showing the text that was typed. #5678 documents that mode with a
character-by-character table. A sequence that is not a valid expansion, such as
%7, fails toparse instead,
rlm_filesskips the whole user entry, and the server rejects the user forhaving no
Auth-Type. That rejection is the same one a wrong password produces.The template also renders both
Tunnel-Passwordvalues with no quoting at all, at lines 28and 124. Those masks permit
%as well, so the same expansion applies, and an unquoted valueadditionally ends at the first space. A tunnel password of
two wordsreaches FreeRADIUS astwo.The double-quoted password rendering dates to the plugin's first commit in 2017.
Describe the proposed solution
service/templates/OPNsense/Freeradius/usersgains aq()macro that wraps a value in singlequotes and escapes backslash and single quote, and the interpolated values go through it.
FreeRADIUS does not expand single-quoted strings, so
%and${...}reach the serverunchanged, and backslash and single quote are the only two escape sequences FreeRADIUS
processes inside them. The same plugin already single-quotes values elsewhere, in
mods-enabled-ldapat lines 15 and 25.The six call sites are the password,
Max-Daily-Session,Simultaneous-Use,Login-Time,and both
Tunnel-Passwordattributes. Only the password and the two tunnel passwords cancurrently hold a
%. The other three go through the same macro so the file has one rule,rather than a per-field judgment about which masks happen to be safe.
models/OPNsense/Freeradius/User.xmlandmodels/OPNsense/Freeradius/General.xmlwiden thepassword,tunnel_passwordandfallback_tunnel_passwordmasks to printable ASCII, keepingthe existing 128 character limit on each.
forms/dialogEditFreeRADIUSUser.xmlandforms/general.xmlbring the three help texts in line with the masks; the password help textalso listed a comma that its mask did not permit.
Widening the masks without the quoting change would extend the same failure to
\and', soboth parts are here together.
Verification
I rendered the template twice against the same stubbed configuration, once from master and
once patched, and diffed the generated file:
Tunnel-Password = tun%nel pass,becomesTunnel-Password = 'tun%nel pass',I then parsed each rendered value back under FreeRADIUS single-quoted string rules and checked
that the original is recovered byte for byte:
%,%{User-Name}and${...}sequencesOn a live OPNsense 26.7.3_8 install running os-freeradius 1.10.2 and FreeRADIUS 3.2.10, with
the single-quoted rendering applied, a 62 character password containing
%and$$changedfrom Access-Reject to Access-Accept, and a second user whose password was unaffected continued
to authenticate.
Not changed here
clients.conf,proxy.confandmods-enabled-sqlwrite secrets with a comparable weakness,reported separately in #5696. Those three model fields carry no mask, so an operator can have
stored an already-escaped value under the guidance given in #1655, and changing the rendering
would repair raw secrets while breaking escaped ones. The fields this pull request touches
have always been masked against
\and", so no escaped value can exist for them and thechange carries no such trade-off.
Related issue
Closes #5678.