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

Commit e568e1e

Browse files
committed
Again match pg_user_mappings to information_schema.user_mapping_options.
Commit 3eefc51 claimed to make pg_user_mappings enforce the qualifications user_mapping_options had been enforcing, but its removal of a longstanding restriction left them distinct when the current user is the subject of a mapping yet has no server privileges. user_mapping_options emits no rows for such a mapping, but pg_user_mappings includes full umoptions. Change pg_user_mappings to show null for umoptions. Back-patch to 9.2, like the above commit. Reviewed by Tom Lane. Reported by Jeff Janes. Security: CVE-2017-7547
1 parent bf6b9e9 commit e568e1e

File tree

5 files changed

+61
-35
lines changed

5 files changed

+61
-35
lines changed

doc/src/sgml/catalogs.sgml

+26-6
Original file line numberDiff line numberDiff line change
@@ -11099,17 +11099,37 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
1109911099
<entry><type>text[]</type></entry>
1110011100
<entry></entry>
1110111101
<entry>
11102-
User mapping specific options, as <quote>keyword=value</>
11103-
strings. This column will show as null unless the current user
11104-
is the user being mapped, or the mapping is for
11105-
<literal>PUBLIC</literal> and the current user is the server
11106-
owner, or the current user is a superuser. The intent is
11107-
to protect password information stored as user mapping option.
11102+
User mapping specific options, as <quote>keyword=value</> strings
1110811103
</entry>
1110911104
</row>
1111011105
</tbody>
1111111106
</tgroup>
1111211107
</table>
11108+
11109+
<para>
11110+
To protect password information stored as a user mapping option,
11111+
the <structfield>umoptions</structfield> column will read as null
11112+
unless one of the following applies:
11113+
<itemizedlist>
11114+
<listitem>
11115+
<para>
11116+
current user is the user being mapped, and owns the server or
11117+
holds <literal>USAGE</> privilege on it
11118+
</para>
11119+
</listitem>
11120+
<listitem>
11121+
<para>
11122+
current user is the server owner and mapping is for <literal>PUBLIC</>
11123+
</para>
11124+
</listitem>
11125+
<listitem>
11126+
<para>
11127+
current user is a superuser
11128+
</para>
11129+
</listitem>
11130+
</itemizedlist>
11131+
</para>
11132+
1111311133
</sect1>
1111411134

1111511135

src/backend/catalog/system_views.sql

+3-1
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,9 @@ CREATE VIEW pg_user_mappings AS
910910
ELSE
911911
A.rolname
912912
END AS usename,
913-
CASE WHEN (U.umuser <> 0 AND A.rolname = current_user)
913+
CASE WHEN (U.umuser <> 0 AND A.rolname = current_user
914+
AND (pg_has_role(S.srvowner, 'USAGE')
915+
OR has_server_privilege(S.oid, 'USAGE')))
914916
OR (U.umuser = 0 AND pg_has_role(S.srvowner, 'USAGE'))
915917
OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user)
916918
THEN U.umoptions

src/test/regress/expected/foreign_data.out

+19-20
Original file line numberDiff line numberDiff line change
@@ -1185,10 +1185,11 @@ ERROR: permission denied for foreign-data wrapper foo
11851185
ALTER SERVER s9 VERSION '1.1';
11861186
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
11871187
CREATE USER MAPPING FOR current_user SERVER s9;
1188+
-- We use terse mode to avoid ordering issues in cascade detail output.
1189+
\set VERBOSITY terse
11881190
DROP SERVER s9 CASCADE;
11891191
NOTICE: drop cascades to 2 other objects
1190-
DETAIL: drop cascades to user mapping for public on server s9
1191-
drop cascades to user mapping for regress_unprivileged_role on server s9
1192+
\set VERBOSITY default
11921193
RESET ROLE;
11931194
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
11941195
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -1204,57 +1205,62 @@ ERROR: must be owner of foreign server s9
12041205
SET ROLE regress_test_role;
12051206
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
12061207
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
1208+
CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
1209+
-- owner of server can see some option fields
12091210
\deu+
12101211
List of user mappings
12111212
Server | User name | FDW options
12121213
--------+---------------------------+-------------------
12131214
s10 | public | ("user" 'secret')
1215+
s10 | regress_unprivileged_role |
12141216
s4 | regress_foreign_data_user |
12151217
s5 | regress_test_role | (modified '1')
12161218
s6 | regress_test_role |
12171219
s8 | public |
12181220
s8 | regress_foreign_data_user |
12191221
s9 | regress_unprivileged_role |
12201222
t1 | public | (modified '1')
1221-
(8 rows)
1223+
(9 rows)
12221224

12231225
RESET ROLE;
1224-
-- superuser can see option fields
1226+
-- superuser can see all option fields
12251227
\deu+
12261228
List of user mappings
12271229
Server | User name | FDW options
12281230
--------+---------------------------+---------------------
12291231
s10 | public | ("user" 'secret')
1232+
s10 | regress_unprivileged_role | ("user" 'secret')
12301233
s4 | regress_foreign_data_user |
12311234
s5 | regress_test_role | (modified '1')
12321235
s6 | regress_test_role |
12331236
s8 | public |
12341237
s8 | regress_foreign_data_user | (password 'public')
12351238
s9 | regress_unprivileged_role |
12361239
t1 | public | (modified '1')
1237-
(8 rows)
1240+
(9 rows)
12381241

1239-
-- unprivileged user cannot see option fields
1242+
-- unprivileged user cannot see any option field
12401243
SET ROLE regress_unprivileged_role;
12411244
\deu+
12421245
List of user mappings
12431246
Server | User name | FDW options
12441247
--------+---------------------------+-------------
12451248
s10 | public |
1249+
s10 | regress_unprivileged_role |
12461250
s4 | regress_foreign_data_user |
12471251
s5 | regress_test_role |
12481252
s6 | regress_test_role |
12491253
s8 | public |
12501254
s8 | regress_foreign_data_user |
12511255
s9 | regress_unprivileged_role |
12521256
t1 | public |
1253-
(8 rows)
1257+
(9 rows)
12541258

12551259
RESET ROLE;
1260+
\set VERBOSITY terse
12561261
DROP SERVER s10 CASCADE;
1257-
NOTICE: drop cascades to user mapping for public on server s10
1262+
NOTICE: drop cascades to 2 other objects
1263+
\set VERBOSITY default
12581264
-- Triggers
12591265
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
12601266
BEGIN
@@ -1596,15 +1602,12 @@ Inherits: pt1
15961602
Child tables: ct3,
15971603
ft3
15981604

1605+
\set VERBOSITY terse
15991606
DROP FOREIGN TABLE ft2; -- ERROR
16001607
ERROR: cannot drop foreign table ft2 because other objects depend on it
1601-
DETAIL: table ct3 depends on foreign table ft2
1602-
foreign table ft3 depends on foreign table ft2
1603-
HINT: Use DROP ... CASCADE to drop the dependent objects too.
16041608
DROP FOREIGN TABLE ft2 CASCADE;
16051609
NOTICE: drop cascades to 2 other objects
1606-
DETAIL: drop cascades to table ct3
1607-
drop cascades to foreign table ft3
1610+
\set VERBOSITY default
16081611
CREATE FOREIGN TABLE ft2 (
16091612
c1 integer NOT NULL,
16101613
c2 text,
@@ -2026,16 +2029,12 @@ owner of user mapping for regress_test_role on server s6
20262029
DROP SERVER t1 CASCADE;
20272030
NOTICE: drop cascades to user mapping for public on server t1
20282031
DROP USER MAPPING FOR regress_test_role SERVER s6;
2029-
-- This test causes some order dependent cascade detail output,
2030-
-- so switch to terse mode for it.
20312032
\set VERBOSITY terse
20322033
DROP FOREIGN DATA WRAPPER foo CASCADE;
20332034
NOTICE: drop cascades to 5 other objects
2034-
\set VERBOSITY default
20352035
DROP SERVER s8 CASCADE;
20362036
NOTICE: drop cascades to 2 other objects
2037-
DETAIL: drop cascades to user mapping for regress_foreign_data_user on server s8
2038-
drop cascades to user mapping for public on server s8
2037+
\set VERBOSITY default
20392038
DROP ROLE regress_test_indirect;
20402039
DROP ROLE regress_test_role;
20412040
DROP ROLE regress_unprivileged_role; -- ERROR

src/test/regress/expected/rules.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -2228,7 +2228,7 @@ pg_user_mappings| SELECT u.oid AS umid,
22282228
ELSE a.rolname
22292229
END AS usename,
22302230
CASE
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
2231+
WHEN (((u.umuser <> (0)::oid) AND (a.rolname = CURRENT_USER) AND (pg_has_role(s.srvowner, 'USAGE'::text) OR has_server_privilege(s.oid, 'USAGE'::text))) OR ((u.umuser = (0)::oid) AND pg_has_role(s.srvowner, 'USAGE'::text)) OR ( SELECT pg_authid.rolsuper
22322232
FROM pg_authid
22332233
WHERE (pg_authid.rolname = CURRENT_USER))) THEN u.umoptions
22342234
ELSE NULL::text[]

src/test/regress/sql/foreign_data.sql

+12-7
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,10 @@ CREATE SERVER s10 FOREIGN DATA WRAPPER foo; -- ERROR
484484
ALTER SERVER s9 VERSION '1.1';
485485
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
486486
CREATE USER MAPPING FOR current_user SERVER s9;
487+
-- We use terse mode to avoid ordering issues in cascade detail output.
488+
\set VERBOSITY terse
487489
DROP SERVER s9 CASCADE;
490+
\set VERBOSITY default
488491
RESET ROLE;
489492
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
490493
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -498,17 +501,19 @@ DROP SERVER s9 CASCADE; -- ERROR
498501
SET ROLE regress_test_role;
499502
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
500503
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
504+
CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
505+
-- owner of server can see some option fields
503506
\deu+
504507
RESET ROLE;
505-
-- superuser can see option fields
508+
-- superuser can see all option fields
506509
\deu+
507-
-- unprivileged user cannot see option fields
510+
-- unprivileged user cannot see any option field
508511
SET ROLE regress_unprivileged_role;
509512
\deu+
510513
RESET ROLE;
514+
\set VERBOSITY terse
511515
DROP SERVER s10 CASCADE;
516+
\set VERBOSITY default
512517

513518
-- Triggers
514519
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
@@ -638,8 +643,10 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit
638643
-- child does not inherit NO INHERIT constraints
639644
\d+ pt1
640645
\d+ ft2
646+
\set VERBOSITY terse
641647
DROP FOREIGN TABLE ft2; -- ERROR
642648
DROP FOREIGN TABLE ft2 CASCADE;
649+
\set VERBOSITY default
643650
CREATE FOREIGN TABLE ft2 (
644651
c1 integer NOT NULL,
645652
c2 text,
@@ -784,12 +791,10 @@ DROP SCHEMA foreign_schema CASCADE;
784791
DROP ROLE regress_test_role; -- ERROR
785792
DROP SERVER t1 CASCADE;
786793
DROP USER MAPPING FOR regress_test_role SERVER s6;
787-
-- This test causes some order dependent cascade detail output,
788-
-- so switch to terse mode for it.
789794
\set VERBOSITY terse
790795
DROP FOREIGN DATA WRAPPER foo CASCADE;
791-
\set VERBOSITY default
792796
DROP SERVER s8 CASCADE;
797+
\set VERBOSITY default
793798
DROP ROLE regress_test_indirect;
794799
DROP ROLE regress_test_role;
795800
DROP ROLE regress_unprivileged_role; -- ERROR

0 commit comments

Comments
 (0)