PS-9704 [8.0]: Escape all RFC 4515 special chars in LDAP filter substitutions - #5928
PS-9704 [8.0]: Escape all RFC 4515 special chars in LDAP filter substitutions#5928VarunNagaraju wants to merge 2 commits into
Conversation
5020350 to
2aa1caa
Compare
2aa1caa to
2fdf2fa
Compare
2fdf2fa to
dd89e05
Compare
| std::string out; | ||
| out.reserve(input.size() * 3); // worst case every byte becomes "\XX" | ||
|
|
||
| for (unsigned char c : input) { |
There was a problem hiding this comment.
Why do we have unsigned char here?
There was a problem hiding this comment.
Typically, raw byte manipulation is done using unsigned char and It covers the cases in the future if the input contains any non-ascii values, then the comparison would be accurate and the default case casts back to char.
But, we could modify it to char since MySQL usernames and LDAP DNs, both are constrained to valid UTF-8.
There was a problem hiding this comment.
My point here is that you have a sequence of chars (std::string), than you iterate over individual characters performing conversions to unsigned chars, and after that you use switch statement in which you have case: clauses with literals of type char ('(' for instance). Moreover, in the default: clause you do static_cast back to original char again. This can work (I do not see any problems that these conversions will cause any value-changing side effects), but I just don't see the reason why we need it as we do not do any computations on the unsigned values here.
There was a problem hiding this comment.
Right. The sole reason was to handle any non-ascii values in the future. But, it's not entirely necessary for now. Will update it to char.
dd89e05 to
729347c
Compare
…ions https://perconadev.atlassian.net/browse/PS-9704 User-supplied values (user_name, user_dn) substituted into LDAP search filters via {UA} and {UD} were not properly escaped. Only double-quote received a partial treatment; parentheses, asterisk, and backslash were passed through verbatim, producing malformed filters that silently broke group lookups for users whose DN contained those characters. Add ldap_filter_escape() which applies the mandatory RFC 4515 §3 \XX hex encoding for LPAREN (\28), RPAREN (\29), ASTERISK (\2a), and ESC (\5c). Apply it to all three substitution sites: search_dn() for user_name, and search_groups() for both {UA} (user_name) and {UD} (user_dn). MTR test exercises DN containing a double-quote, parentheses, an asterisk, and a backslash — all expected to authenticate and receive their group role via the dn_test_group groupOfNames entry.
https://perconadev.atlassian.net/browse/PS-11253 Fix heap-use-after-free when granting external roles during login. acl_authenticate() was calling grant_role() with the acl_user pointer from mpvio, which is a copy allocated on the connection's mem_root and freed when the command ends. grant_role() stores ACL_USER by value in the role graph, retaining the raw user/host char* pointers. Subsequent DROP USER walks that graph and dereferences those freed pointers, causing corrupted reads and Warning 1366 on the role_edges table columns. Fix: look up the durable ACL cache entry via find_acl_user() and pass that to grant_role() instead of the mem_root copy. This ensures the role graph holds pointers that remain valid for the lifetime of the ACL cache.
729347c to
46f816a
Compare
https://perconadev.atlassian.net/browse/PS-9704
User-supplied values (user_name, user_dn) substituted into LDAP search
filters via {UA} and {UD} were not properly escaped. Only double-quote
received a partial treatment; parentheses, asterisk, and backslash were
passed through verbatim, producing malformed filters that silently broke
group lookups for users whose DN contained those characters.
Add ldap_filter_escape() which applies the mandatory RFC 4515 §3 \XX
hex encoding for LPAREN (\28), RPAREN (\29), ASTERISK (\2a), and
ESC (\5c). Apply it to all three substitution sites: search_dn() for
user_name, and search_groups() for both {UA} (user_name) and {UD}
(user_dn).
Fix heap-use-after-free when granting external roles during login.
acl_authenticate() was calling grant_role() with the acl_user pointer
from mpvio, which is a copy allocated on the connection's mem_root and
freed when the command ends. grant_role() stores ACL_USER by value in
the role graph, retaining the raw user/host char* pointers. Subsequent
DROP USER walks that graph and dereferences those freed pointers, causing
corrupted reads and Warning 1366 on the role_edges table columns.
Fix: look up the durable ACL cache entry via find_acl_user() and pass
that to grant_role() instead of the mem_root copy. This ensures the
role graph holds pointers that remain valid for the lifetime of the
ACL cache.
MTR test exercises DN containing a double-quote, parentheses, an
asterisk, and a backslash — all expected to authenticate and receive
their group role via the dn_test_group groupOfNames entry.