Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3eefc51

Browse files
committed
Match pg_user_mappings limits to information_schema.user_mapping_options.
Both views replace the umoptions field with NULL when the user does not meet qualifications to see it. They used different qualifications, and pg_user_mappings documented qualifications did not match its implemented qualifications. Make its documentation and implementation match those of user_mapping_options. One might argue for stronger qualifications, but these have long, documented tenure. pg_user_mappings has always exhibited this problem, so back-patch to 9.2 (all supported versions). Michael Paquier and Feike Steenbergen. Reviewed by Jeff Janes. Reported by Andrew Wheelwright. Security: CVE-2017-7486
1 parent 0170b10 commit 3eefc51

File tree

5 files changed

+82
-8
lines changed

5 files changed

+82
-8
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11084,8 +11084,11 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
1108411084
<entry></entry>
1108511085
<entry>
1108611086
User mapping specific options, as <quote>keyword=value</>
11087-
strings, if the current user is the owner of the foreign
11088-
server, else null
11087+
strings. This column will show as null unless the current user
11088+
is the user being mapped, or the mapping is for
11089+
<literal>PUBLIC</literal> and the current user is the server
11090+
owner, or the current user is a superuser. The intent is
11091+
to protect password information stored as user mapping option.
1108911092
</entry>
1109011093
</row>
1109111094
</tbody>

src/backend/catalog/system_views.sql

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -910,11 +910,11 @@ CREATE VIEW pg_user_mappings AS
910910
ELSE
911911
A.rolname
912912
END AS usename,
913-
CASE WHEN pg_has_role(S.srvowner, 'USAGE') OR has_server_privilege(S.oid, 'USAGE') THEN
914-
U.umoptions
915-
ELSE
916-
NULL
917-
END AS umoptions
913+
CASE WHEN (U.umuser <> 0 AND A.rolname = current_user)
914+
OR (U.umuser = 0 AND pg_has_role(S.srvowner, 'USAGE'))
915+
OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user)
916+
THEN U.umoptions
917+
ELSE NULL END AS umoptions
918918
FROM pg_user_mapping U
919919
JOIN pg_foreign_server S ON (U.umserver = S.oid)
920920
LEFT JOIN pg_authid A ON (A.oid = U.umuser);

src/test/regress/expected/foreign_data.out

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,61 @@ WARNING: no privileges were granted for "s9"
12001200
CREATE USER MAPPING FOR current_user SERVER s9;
12011201
DROP SERVER s9 CASCADE; -- ERROR
12021202
ERROR: must be owner of foreign server s9
1203+
-- Check visibility of user mapping data
1204+
SET ROLE regress_test_role;
1205+
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
1206+
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
1207+
GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
1208+
-- owner of server can see option fields
1209+
\deu+
1210+
List of user mappings
1211+
Server | User name | FDW Options
1212+
--------+---------------------------+-------------------
1213+
s10 | public | ("user" 'secret')
1214+
s4 | regress_foreign_data_user |
1215+
s5 | regress_test_role | (modified '1')
1216+
s6 | regress_test_role |
1217+
s8 | public |
1218+
s8 | regress_foreign_data_user |
1219+
s9 | regress_unprivileged_role |
1220+
t1 | public | (modified '1')
1221+
(8 rows)
1222+
1223+
RESET ROLE;
1224+
-- superuser can see option fields
1225+
\deu+
1226+
List of user mappings
1227+
Server | User name | FDW Options
1228+
--------+---------------------------+---------------------
1229+
s10 | public | ("user" 'secret')
1230+
s4 | regress_foreign_data_user |
1231+
s5 | regress_test_role | (modified '1')
1232+
s6 | regress_test_role |
1233+
s8 | public |
1234+
s8 | regress_foreign_data_user | (password 'public')
1235+
s9 | regress_unprivileged_role |
1236+
t1 | public | (modified '1')
1237+
(8 rows)
1238+
1239+
-- unprivileged user cannot see option fields
1240+
SET ROLE regress_unprivileged_role;
1241+
\deu+
1242+
List of user mappings
1243+
Server | User name | FDW Options
1244+
--------+---------------------------+-------------
1245+
s10 | public |
1246+
s4 | regress_foreign_data_user |
1247+
s5 | regress_test_role |
1248+
s6 | regress_test_role |
1249+
s8 | public |
1250+
s8 | regress_foreign_data_user |
1251+
s9 | regress_unprivileged_role |
1252+
t1 | public |
1253+
(8 rows)
1254+
12031255
RESET ROLE;
1256+
DROP SERVER s10 CASCADE;
1257+
NOTICE: drop cascades to user mapping for public on server s10
12041258
-- Triggers
12051259
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
12061260
BEGIN

src/test/regress/expected/rules.out

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2228,7 +2228,9 @@ pg_user_mappings| SELECT u.oid AS umid,
22282228
ELSE a.rolname
22292229
END AS usename,
22302230
CASE
2231-
WHEN (pg_has_role(s.srvowner, 'USAGE'::text) OR has_server_privilege(s.oid, 'USAGE'::text)) THEN u.umoptions
2231+
WHEN (((u.umuser <> (0)::oid) AND (a.rolname = CURRENT_USER)) OR ((u.umuser = (0)::oid) AND pg_has_role(s.srvowner, 'USAGE'::text)) OR ( SELECT pg_authid.rolsuper
2232+
FROM pg_authid
2233+
WHERE (pg_authid.rolname = CURRENT_USER))) THEN u.umoptions
22322234
ELSE NULL::text[]
22332235
END AS umoptions
22342236
FROM ((pg_user_mapping u

src/test/regress/sql/foreign_data.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,22 @@ ALTER SERVER s9 VERSION '1.2'; -- ERROR
493493
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role; -- WARNING
494494
CREATE USER MAPPING FOR current_user SERVER s9;
495495
DROP SERVER s9 CASCADE; -- ERROR
496+
497+
-- Check visibility of user mapping data
498+
SET ROLE regress_test_role;
499+
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
500+
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
501+
GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
502+
-- owner of server can see option fields
503+
\deu+
504+
RESET ROLE;
505+
-- superuser can see option fields
506+
\deu+
507+
-- unprivileged user cannot see option fields
508+
SET ROLE regress_unprivileged_role;
509+
\deu+
496510
RESET ROLE;
511+
DROP SERVER s10 CASCADE;
497512

498513
-- Triggers
499514
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$

0 commit comments

Comments
 (0)