-<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.36 2008/12/19 16:25:16 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.37 2009/01/20 09:10:20 petere Exp $ -->
<chapter id="information-schema">
<title>The Information Schema</title>
<row>
<entry><literal>option_value</literal></entry>
<entry><type>character_data</type></entry>
- <entry>Value of the option</entry>
+ <entry>Value of the option. This column will show as null
+ unless the current user is the user being mapped, or the mapping
+ is for <literal>PUBLIC</literal> and the current user is the
+ server owner, or the current user is a superuser. The intent is
+ to protect password information stored as user mapping
+ option.</entry>
</row>
</tbody>
</tgroup>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_user_mapping.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_user_mapping.sgml,v 1.2 2009/01/20 09:10:20 petere Exp $
PostgreSQL documentation
-->
<para>
<command>ALTER USER MAPPING</command> changes the definition of a
- user mapping. Only the owner of the server can change the user
- mappings of that server.
+ user mapping.
</para>
+ <para>
+ The owner of a foreign server can alter user mappings for that
+ server for any user. Also, a user can alter a user mapping for
+ his own user name if <literal>USAGE</> privilege on the server has
+ been granted to the user.
+ </para>
</refsect1>
<refsect1>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_user_mapping.sgml,v 1.2 2009/01/17 04:24:41 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_user_mapping.sgml,v 1.3 2009/01/20 09:10:20 petere Exp $
PostgreSQL documentation
-->
<para>
<command>CREATE USER MAPPING</command> defines a mapping of a user
- to a foreign server. You must be the owner of the server to define
- user mappings for it.
+ to a foreign server.
</para>
+ <para>
+ The owner of a foreign server can create user mappings for that
+ server for any user. Also, a user can create a user mapping for
+ his own user name if <literal>USAGE</> privilege on the server has
+ been granted to the user.
+ </para>
</refsect1>
<refsect1>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/drop_user_mapping.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_user_mapping.sgml,v 1.2 2009/01/20 09:10:20 petere Exp $
PostgreSQL documentation
-->
<para>
<command>DROP USER MAPPING</command> removes an existing user
- mapping from foreign server. To execute this command, the current
- user must be the owner of the server containing the mapping.
+ mapping from foreign server.
+ </para>
+
+ <para>
+ The owner of a foreign server can drop user mappings for that server
+ for any user. Also, a user can drop a user mapping for his own
+ user name if <literal>USAGE</> privilege on the server has been
+ granted to the user.
</para>
</refsect1>
*
* Copyright (c) 2003-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.49 2009/01/14 21:12:09 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.50 2009/01/20 09:10:20 petere Exp $
*/
/*
s.srvoptions,
CAST(current_database() AS sql_identifier) AS foreign_server_catalog,
CAST(srvname AS sql_identifier) AS foreign_server_name,
- w.foreign_data_wrapper_catalog,
- w.foreign_data_wrapper_name,
+ CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog,
+ CAST(w.fdwname AS sql_identifier) AS foreign_data_wrapper_name,
CAST(srvtype AS character_data) AS foreign_server_type,
CAST(srvversion AS character_data) AS foreign_server_version,
CAST(u.rolname AS sql_identifier) AS authorization_identifier
- FROM pg_foreign_server s, _pg_foreign_data_wrappers w, pg_authid u
+ FROM pg_foreign_server s, pg_foreign_data_wrapper w, pg_authid u
WHERE w.oid = s.srvfdw
AND u.oid = s.srvowner
AND (pg_has_role(s.srvowner, 'USAGE')
CREATE VIEW _pg_user_mappings AS
SELECT um.oid,
um.umoptions,
+ um.umuser,
CAST(COALESCE(u.rolname,'PUBLIC') AS sql_identifier ) AS authorization_identifier,
s.foreign_server_catalog,
- s.foreign_server_name
+ s.foreign_server_name,
+ s.authorization_identifier AS srvowner
FROM pg_user_mapping um LEFT JOIN pg_authid u ON (u.oid = um.umuser),
_pg_foreign_servers s
WHERE s.oid = um.umserver;
foreign_server_catalog,
foreign_server_name,
CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
- CAST((pg_options_to_table(um.umoptions)).option_value AS character_data) AS option_value
+ CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
+ OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
+ OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) THEN (pg_options_to_table(um.umoptions)).option_value
+ ELSE NULL END AS character_data) AS option_value
FROM _pg_user_mappings um;
GRANT SELECT ON user_mapping_options TO PUBLIC;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.4 2009/01/01 17:23:38 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.5 2009/01/20 09:10:20 petere Exp $
*
*-------------------------------------------------------------------------
*/
}
+/*
+ * Common routine to check permission for user-mapping-related DDL
+ * commands. We allow server owners to operate on any mapping, and
+ * users to operate on their own mapping.
+ */
+static void
+user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
+{
+ Oid curuserid = GetUserId();
+
+ if (!pg_foreign_server_ownercheck(serverid, curuserid))
+ {
+ if (umuserid == curuserid)
+ {
+ AclResult aclresult;
+
+ aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, servername);
+ }
+ else
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ servername);
+ }
+}
+
+
/*
* Create user mapping
*/
HeapTuple tuple;
Oid useId;
Oid umId;
- Oid ownerId;
ObjectAddress myself;
ObjectAddress referenced;
ForeignServer *srv;
ForeignDataWrapper *fdw;
- ownerId = GetUserId();
-
useId = GetUserOidFromMapping(stmt->username, false);
- /*
- * Check that the server exists and that the we own it.
- */
+ /* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
- if (!pg_foreign_server_ownercheck(srv->serverid, ownerId))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
- stmt->servername);
+ user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
/*
* Check that the user mapping is unique within server.
errmsg("user mapping \"%s\" does not exist for the server",
MappingUserName(useId))));
- /*
- * Must be owner of the server to alter user mapping.
- */
- if (!pg_foreign_server_ownercheck(srv->serverid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
- stmt->servername);
+ user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
tp = SearchSysCacheCopy(USERMAPPINGOID,
ObjectIdGetDatum(umId),
return;
}
- /*
- * Only allow DROP if we own the server.
- */
- if (!pg_foreign_server_ownercheck(srv->serverid, GetUserId()))
- {
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
- srv->servername);
- }
+ user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
/*
* Do the deletion
CREATE USER MAPPING FOR current_user SERVER s5;
CREATE USER MAPPING FOR current_user SERVER s6 OPTIONS (username 'test');
CREATE USER MAPPING FOR current_user SERVER s7; -- ERROR
-ERROR: must be owner of foreign server s7
+ERROR: permission denied for foreign server s7
CREATE USER MAPPING FOR public SERVER s8; -- ERROR
ERROR: must be owner of foreign server s8
RESET ROLE;
(2 rows)
DROP USER MAPPING FOR current_user SERVER st1;
+SET ROLE regress_test_role2;
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
+ authorization_identifier | foreign_server_catalog | foreign_server_name | option_name | option_value
+--------------------------+------------------------+---------------------+-------------+--------------
+ regress_test_role | regression | s6 | username |
+(1 row)
+
RESET ROLE;
-- has_foreign_data_wrapper_privilege
SELECT has_foreign_data_wrapper_privilege('regress_test_role',
ERROR: must be owner of foreign server s9
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role; -- WARNING
WARNING: no privileges were granted for "s9"
-CREATE USER MAPPING FOR current_user SERVER s9; -- ERROR
-ERROR: must be owner of foreign server s9
+CREATE USER MAPPING FOR current_user SERVER s9;
DROP SERVER s9 CASCADE; -- ERROR
ERROR: must be owner of foreign server s9
RESET ROLE;
DROP SERVER st2;
DROP USER MAPPING FOR regress_test_role SERVER s6;
DROP FOREIGN DATA WRAPPER foo CASCADE;
-NOTICE: drop cascades to 4 other objects
+NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to server s4
drop cascades to user mapping for foreign_data_user
drop cascades to server s6
drop cascades to server s9
+drop cascades to user mapping for unprivileged_role
DROP SERVER s8 CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to user mapping for foreign_data_user
SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
DROP USER MAPPING FOR current_user SERVER st1;
+SET ROLE regress_test_role2;
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
RESET ROLE;
SET ROLE unprivileged_role;
ALTER SERVER s9 VERSION '1.2'; -- ERROR
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role; -- WARNING
-CREATE USER MAPPING FOR current_user SERVER s9; -- ERROR
+CREATE USER MAPPING FOR current_user SERVER s9;
DROP SERVER s9 CASCADE; -- ERROR
RESET ROLE;