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

Commit 1560996

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 f6fc72c commit 1560996

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
@@ -10050,17 +10050,37 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
1005010050
<entry><type>text[]</type></entry>
1005110051
<entry></entry>
1005210052
<entry>
10053-
User mapping specific options, as <quote>keyword=value</>
10054-
strings. This column will show as null unless the current user
10055-
is the user being mapped, or the mapping is for
10056-
<literal>PUBLIC</literal> and the current user is the server
10057-
owner, or the current user is a superuser. The intent is
10058-
to protect password information stored as user mapping option.
10053+
User mapping specific options, as <quote>keyword=value</> strings
1005910054
</entry>
1006010055
</row>
1006110056
</tbody>
1006210057
</tgroup>
1006310058
</table>
10059+
10060+
<para>
10061+
To protect password information stored as a user mapping option,
10062+
the <structfield>umoptions</structfield> column will read as null
10063+
unless one of the following applies:
10064+
<itemizedlist>
10065+
<listitem>
10066+
<para>
10067+
current user is the user being mapped, and owns the server or
10068+
holds <literal>USAGE</> privilege on it
10069+
</para>
10070+
</listitem>
10071+
<listitem>
10072+
<para>
10073+
current user is the server owner and mapping is for <literal>PUBLIC</>
10074+
</para>
10075+
</listitem>
10076+
<listitem>
10077+
<para>
10078+
current user is a superuser
10079+
</para>
10080+
</listitem>
10081+
</itemizedlist>
10082+
</para>
10083+
1006410084
</sect1>
1006510085

1006610086

src/backend/catalog/system_views.sql

+3-1
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,9 @@ CREATE VIEW pg_user_mappings AS
826826
ELSE
827827
A.rolname
828828
END AS usename,
829-
CASE WHEN (U.umuser <> 0 AND A.rolname = current_user)
829+
CASE WHEN (U.umuser <> 0 AND A.rolname = current_user
830+
AND (pg_has_role(S.srvowner, 'USAGE')
831+
OR has_server_privilege(S.oid, 'USAGE')))
830832
OR (U.umuser = 0 AND pg_has_role(S.srvowner, 'USAGE'))
831833
OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user)
832834
THEN U.umoptions

src/test/regress/expected/foreign_data.out

+19-20
Original file line numberDiff line numberDiff line change
@@ -1179,10 +1179,11 @@ ERROR: permission denied for foreign-data wrapper foo
11791179
ALTER SERVER s9 VERSION '1.1';
11801180
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
11811181
CREATE USER MAPPING FOR current_user SERVER s9;
1182+
-- We use terse mode to avoid ordering issues in cascade detail output.
1183+
\set VERBOSITY terse
11821184
DROP SERVER s9 CASCADE;
11831185
NOTICE: drop cascades to 2 other objects
1184-
DETAIL: drop cascades to user mapping for public on server s9
1185-
drop cascades to user mapping for regress_unprivileged_role on server s9
1186+
\set VERBOSITY default
11861187
RESET ROLE;
11871188
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
11881189
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -1198,57 +1199,62 @@ ERROR: must be owner of foreign server s9
11981199
SET ROLE regress_test_role;
11991200
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
12001201
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
1201-
GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
1202-
-- owner of server can see option fields
1202+
CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
1203+
-- owner of server can see some option fields
12031204
\deu+
12041205
List of user mappings
12051206
Server | User name | FDW Options
12061207
--------+---------------------------+-------------------
12071208
s10 | public | ("user" 'secret')
1209+
s10 | regress_unprivileged_role |
12081210
s4 | regress_foreign_data_user |
12091211
s5 | regress_test_role | (modified '1')
12101212
s6 | regress_test_role |
12111213
s8 | public |
12121214
s8 | regress_foreign_data_user |
12131215
s9 | regress_unprivileged_role |
12141216
t1 | public | (modified '1')
1215-
(8 rows)
1217+
(9 rows)
12161218

12171219
RESET ROLE;
1218-
-- superuser can see option fields
1220+
-- superuser can see all option fields
12191221
\deu+
12201222
List of user mappings
12211223
Server | User name | FDW Options
12221224
--------+---------------------------+---------------------
12231225
s10 | public | ("user" 'secret')
1226+
s10 | regress_unprivileged_role | ("user" 'secret')
12241227
s4 | regress_foreign_data_user |
12251228
s5 | regress_test_role | (modified '1')
12261229
s6 | regress_test_role |
12271230
s8 | public |
12281231
s8 | regress_foreign_data_user | (password 'public')
12291232
s9 | regress_unprivileged_role |
12301233
t1 | public | (modified '1')
1231-
(8 rows)
1234+
(9 rows)
12321235

1233-
-- unprivileged user cannot see option fields
1236+
-- unprivileged user cannot see any option field
12341237
SET ROLE regress_unprivileged_role;
12351238
\deu+
12361239
List of user mappings
12371240
Server | User name | FDW Options
12381241
--------+---------------------------+-------------
12391242
s10 | public |
1243+
s10 | regress_unprivileged_role |
12401244
s4 | regress_foreign_data_user |
12411245
s5 | regress_test_role |
12421246
s6 | regress_test_role |
12431247
s8 | public |
12441248
s8 | regress_foreign_data_user |
12451249
s9 | regress_unprivileged_role |
12461250
t1 | public |
1247-
(8 rows)
1251+
(9 rows)
12481252

12491253
RESET ROLE;
1254+
\set VERBOSITY terse
12501255
DROP SERVER s10 CASCADE;
1251-
NOTICE: drop cascades to user mapping for public on server s10
1256+
NOTICE: drop cascades to 2 other objects
1257+
\set VERBOSITY default
12521258
-- Triggers
12531259
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
12541260
BEGIN
@@ -1583,15 +1589,12 @@ Inherits: pt1
15831589
Child tables: ct3,
15841590
ft3
15851591

1592+
\set VERBOSITY terse
15861593
DROP FOREIGN TABLE ft2; -- ERROR
15871594
ERROR: cannot drop foreign table ft2 because other objects depend on it
1588-
DETAIL: table ct3 depends on foreign table ft2
1589-
foreign table ft3 depends on foreign table ft2
1590-
HINT: Use DROP ... CASCADE to drop the dependent objects too.
15911595
DROP FOREIGN TABLE ft2 CASCADE;
15921596
NOTICE: drop cascades to 2 other objects
1593-
DETAIL: drop cascades to table ct3
1594-
drop cascades to foreign table ft3
1597+
\set VERBOSITY default
15951598
CREATE FOREIGN TABLE ft2 (
15961599
c1 integer NOT NULL,
15971600
c2 text,
@@ -1815,16 +1818,12 @@ owner of user mapping for regress_test_role on server s6
18151818
DROP SERVER t1 CASCADE;
18161819
NOTICE: drop cascades to user mapping for public on server t1
18171820
DROP USER MAPPING FOR regress_test_role SERVER s6;
1818-
-- This test causes some order dependent cascade detail output,
1819-
-- so switch to terse mode for it.
18201821
\set VERBOSITY terse
18211822
DROP FOREIGN DATA WRAPPER foo CASCADE;
18221823
NOTICE: drop cascades to 5 other objects
1823-
\set VERBOSITY default
18241824
DROP SERVER s8 CASCADE;
18251825
NOTICE: drop cascades to 2 other objects
1826-
DETAIL: drop cascades to user mapping for regress_foreign_data_user on server s8
1827-
drop cascades to user mapping for public on server s8
1826+
\set VERBOSITY default
18281827
DROP ROLE regress_test_indirect;
18291828
DROP ROLE regress_test_role;
18301829
DROP ROLE regress_unprivileged_role; -- ERROR

src/test/regress/expected/rules.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -2151,7 +2151,7 @@ pg_user_mappings| SELECT u.oid AS umid,
21512151
ELSE a.rolname
21522152
END AS usename,
21532153
CASE
2154-
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
2154+
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
21552155
FROM pg_authid
21562156
WHERE (pg_authid.rolname = "current_user"()))) THEN u.umoptions
21572157
ELSE NULL::text[]

src/test/regress/sql/foreign_data.sql

+12-7
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,10 @@ CREATE SERVER s10 FOREIGN DATA WRAPPER foo; -- ERROR
481481
ALTER SERVER s9 VERSION '1.1';
482482
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
483483
CREATE USER MAPPING FOR current_user SERVER s9;
484+
-- We use terse mode to avoid ordering issues in cascade detail output.
485+
\set VERBOSITY terse
484486
DROP SERVER s9 CASCADE;
487+
\set VERBOSITY default
485488
RESET ROLE;
486489
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
487490
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -495,17 +498,19 @@ DROP SERVER s9 CASCADE; -- ERROR
495498
SET ROLE regress_test_role;
496499
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
497500
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
498-
GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
499-
-- owner of server can see option fields
501+
CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
502+
-- owner of server can see some option fields
500503
\deu+
501504
RESET ROLE;
502-
-- superuser can see option fields
505+
-- superuser can see all option fields
503506
\deu+
504-
-- unprivileged user cannot see option fields
507+
-- unprivileged user cannot see any option field
505508
SET ROLE regress_unprivileged_role;
506509
\deu+
507510
RESET ROLE;
511+
\set VERBOSITY terse
508512
DROP SERVER s10 CASCADE;
513+
\set VERBOSITY default
509514

510515
-- Triggers
511516
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
@@ -629,8 +634,10 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit
629634
-- child does not inherit NO INHERIT constraints
630635
\d+ pt1
631636
\d+ ft2
637+
\set VERBOSITY terse
632638
DROP FOREIGN TABLE ft2; -- ERROR
633639
DROP FOREIGN TABLE ft2 CASCADE;
640+
\set VERBOSITY default
634641
CREATE FOREIGN TABLE ft2 (
635642
c1 integer NOT NULL,
636643
c2 text,
@@ -704,12 +711,10 @@ DROP SCHEMA foreign_schema CASCADE;
704711
DROP ROLE regress_test_role; -- ERROR
705712
DROP SERVER t1 CASCADE;
706713
DROP USER MAPPING FOR regress_test_role SERVER s6;
707-
-- This test causes some order dependent cascade detail output,
708-
-- so switch to terse mode for it.
709714
\set VERBOSITY terse
710715
DROP FOREIGN DATA WRAPPER foo CASCADE;
711-
\set VERBOSITY default
712716
DROP SERVER s8 CASCADE;
717+
\set VERBOSITY default
713718
DROP ROLE regress_test_indirect;
714719
DROP ROLE regress_test_role;
715720
DROP ROLE regress_unprivileged_role; -- ERROR

0 commit comments

Comments
 (0)