Allow postgres user to only list his own database

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.

Tags:

Postgresql