I'm using a postgresql server and I want to forbid my users to see what other databases are on the same server.
Essentially a \l
should only list his own database.
I'm pretty sure that there is a right which I need to revoke from the user but I can't find it in the docs.
This seems to work but might have unforeseen consequences. It requires tinkering with system catalogues, which isn't really a good idea!
First off, you have to permit superusers to update system catalogues by adding this to your postgresql config:
allow_system_table_mods = on
and restart.
Now, you can use DDL statements to modify system catalogues (you should be afraid). Connect to one of the user databases (a test one would be a good idea) and:
alter table pg_catalog.pg_database rename to pg_database_catalog; create view pg_catalog.pg_database as select oid, 1262::oid as tableoid, pg_database_catalog.* from pg_catalog.pg_database_catalog where has_database_privilege(pg_database_catalog.oid, 'connect'); grant select on pg_catalog.pg_database to public;
You should now find that if you connect to that database as a low-priv user, the \l
command will just list the databases that that user can connect to.
The problem is you now need to guess which database the users connect to initially to fetch their database list from. If they connect to their own database initially, then you're probably done at this point. If they connect to postgres
or template1
first, then you need to make this change on that database instead.
It seems to me that this should work, since the pg_database
catalog is referred to by postgres backends directly by oid, rather than by name, so moving it out of the way and changing which rows are shown in it should be invisible to them. In particular, you can't stop the server distinguishing to the user between a database not existing and them not having connection privilege.
I'm not going to make any promises that this sort of change doesn't screw something else up down the line. If it breaks, you get to keep the pieces.
You probably want to make this change in a template database, and create user databases from that in future, and deactivate the allow_system_table_mods
setting when you're done (which requires a server restart, remember).
Also, I tested this on 9.0: it seems to me it should work on some earlier versions too, caveat emptor.
There's no such setting in pgsql. There are settings to prevent users from connecting to databases that they shouldn't (grant / revoke connect). Being able to see there's a database is no big deal. Being able to connect / have edit rights etc. is.
I would imagine this might have negative repercussions for the user, such as not being able to connect to the database since the system does not have access to the sytem tables, not sure though. But as far as figuring out what table to revoke - this a good general way to see what the psql meta commands are doing:
To see what \l
is doing you can also use the -E flag from the command line with psql.
~$ psql -E -c '\l' ********* QUERY ********** SELECT d.datname as "Name", pg_catalog.pg_get_userbyid(d.datdba) as "Owner", pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding", d.datcollate as "Collation", d.datctype as "Ctype", pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges" FROM pg_catalog.pg_database d ORDER BY 1; **************************
So if the user does not have access to pg_database they will not be able to use the \l command.