1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-19 17:02:53 +03:00

Fix inconsistent quoting of role names in ACLs.

getid() and putid(), which parse and deparse role names within ACL
input/output, applied isalnum() to see if a character within a role
name requires quoting.  They did this even for non-ASCII characters,
which is problematic because the results would depend on encoding,
locale, and perhaps even platform.  So it's possible that putid()
could elect not to quote some string that, later in some other
environment, getid() will decide is not a valid identifier, causing
dump/reload or similar failures.

To fix this in a way that won't risk interoperability problems
with unpatched versions, make getid() treat any non-ASCII as a
legitimate identifier character (hence not requiring quotes),
while making putid() treat any non-ASCII as requiring quoting.
We could remove the resulting excess quoting once we feel that
no unpatched servers remain in the wild, but that'll be years.

A lesser problem is that getid() did the wrong thing with an input
consisting of just two double quotes ("").  That has to represent an
empty string, but getid() read it as a single double quote instead.
The case cannot arise in the normal course of events, since we don't
allow empty-string role names.  But let's fix it while we're here.

Although we've not heard field reports of problems with non-ASCII
role names, there's clearly a hazard there, so back-patch to all
supported versions.

Reported-by: Peter Eisentraut <peter@eisentraut.org>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/3792884.1751492172@sss.pgh.pa.us
Backpatch-through: 13
This commit is contained in:
Tom Lane
2025-07-11 18:50:13 -04:00
parent 990571a08b
commit 64840e4624
3 changed files with 53 additions and 8 deletions

View File

@@ -2568,6 +2568,26 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
'SELECT, fake_privilege', FALSE); -- error
ERROR: unrecognized privilege type: "fake_privilege"
-- Test quoting and dequoting of user names in ACLs
CREATE ROLE "regress_""quoted";
SELECT makeaclitem('regress_"quoted'::regrole, 'regress_"quoted'::regrole,
'SELECT', TRUE);
makeaclitem
------------------------------------------
"regress_""quoted"=r*/"regress_""quoted"
(1 row)
SELECT '"regress_""quoted"=r*/"regress_""quoted"'::aclitem;
aclitem
------------------------------------------
"regress_""quoted"=r*/"regress_""quoted"
(1 row)
SELECT '""=r*/""'::aclitem; -- used to be misparsed as """"
ERROR: a name must follow the "/" sign
LINE 1: SELECT '""=r*/""'::aclitem;
^
DROP ROLE "regress_""quoted";
-- Test non-throwing aclitem I/O
SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
pg_input_is_valid

View File

@@ -1544,6 +1544,14 @@ SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
SELECT makeaclitem('regress_priv_user1'::regrole, 'regress_priv_user2'::regrole,
'SELECT, fake_privilege', FALSE); -- error
-- Test quoting and dequoting of user names in ACLs
CREATE ROLE "regress_""quoted";
SELECT makeaclitem('regress_"quoted'::regrole, 'regress_"quoted'::regrole,
'SELECT', TRUE);
SELECT '"regress_""quoted"=r*/"regress_""quoted"'::aclitem;
SELECT '""=r*/""'::aclitem; -- used to be misparsed as """"
DROP ROLE "regress_""quoted";
-- Test non-throwing aclitem I/O
SELECT pg_input_is_valid('regress_priv_user1=r/regress_priv_user2', 'aclitem');
SELECT pg_input_is_valid('regress_priv_user1=r/', 'aclitem');