Is it possible to include timezones in list of roles? - postgresql

Can a list of postgresql roles be generated that includes the role's timezone?
I've learned, and tested, that a psql session will take on the timezone of the role used at login. Of course we can alter a role to a particular time zone with:
# ALTER ROLE testUser SET timezone TO 'America/Chicago';
But exactly how can that information be accessed to produce a list so that all the roles can be checked? I've tried \du+, but that returns very limited information. Surprisingly (to me anyway) the information_schema doesn't seem to include the timezone values. Internet searches have so far not helped in this quest.
Where else can I try?

The settings of a role can be retrieved from pg_db_role_setting, it's an text[] array of <setting name>=<setting value>. So this needs an unnest() and a split_part() to get to the individual components. Furthermore, as a setting can be set for a specific database (see the IN DATABASE option for the ALTER ROLE command), we need to involve the databases from pg_database. We cross join them with all the roles from pg_authid. To also include settings that aren't bound to a database but are valid for all databases we UNION ALL an empty database with a zero OID to the list of databases. From that we can left join the role settings.
So the following will give you the value set for timezone for all databases (including the "all" or "none" database) and all roles or null if the timezone isn't set for a user in a database.
SELECT rol.rolname,
dat.datname,
split_part(kvp.kvp, '=', 2) timezone
FROM pg_authid rol
CROSS JOIN (SELECT dat.oid,
dat.datname
FROM pg_database dat
UNION ALL
SELECT 0::oid oid,
'' datname) dat
LEFT JOIN pg_db_role_setting set
ON set.setdatabase = dat.oid
AND set.setrole = rol.oid
LEFT JOIN LATERAL unnest(set.setconfig) kvp (kvp)
ON lower(split_part(kvp.kvp, '=', 1)) = 'timezone'
ORDER BY 1,
2;

Related

Postgresql - running subquery doesn't show results for an user

i have this user in the database, this user only needs read permissions, here the permissions that has right now:
GRANT USAGE ON SCHEMA myschema TO "user";
GRANT SELECT ON TABLES TO "user";
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA myschema to "user";
If the runs this query didn't show results, but if I use an admin-user show me results:
SELECT "tableA"."tableA_id", "tableA"."first_name", "tableA"."last_name", "brands"."brand_id" AS "brands.brand_id",
"brands->tableB"."door_id" AS "brands.tableB.door_id", "brands->tableB"."agent_id" AS "brands.tableB.agent_id",
"brands->tableB"."tableA_id" AS "brands.tableB.tableA_id", "brands->tableB"."brand_id" AS "brands.tableB.brand_id",
"brands->tableB"."relationship_type" AS "brands.tableB.relationship_type", "agents"."agent_id" AS "agents.agent_id",
"agents"."relationship_type" AS "agents.relationship_type"
FROM "myschema"."tableA" AS "tableA"
INNER JOIN ( "myschema"."tableB" AS "brands->tableB" INNER JOIN "myschema"."brand" AS "brands" ON "brands"."brand_id" = "brands->tableB"."brand_id") ON "tableA"."tableA_id" = "brands->tableB"."tableA_id" AND "brands"."brand_id" = 1
INNER JOIN "myschema"."tableB" AS "agents" ON "tableA"."tableA_id" = "agents"."tableA_id" AND "agents"."relationship_type" = 'Employee'
WHERE "tableA"."active" = true ORDER BY "tableA"."first_name" ASC;
Any idea which privileges are need it to check this data?
Regards
Missing permissions don't influence the query result, they cause "permission denied" errors. The exceptions I know are
queries on information_schema views, which only show objects on which you have permissions
row-level security
If anything, your question suggests that row-level security is at play here.
If you need a more detailed answer, you have to add details to the question.

Table with list of database administrators in IBM i

I want a list of users on an IBMi Machine who have access to create RCAC permissions (Create Mask, Row permission etc). Is this data stored in any table?
Not just in one table but I think this is a good start to list users with administative authority
SELECT
distinct AUTHORIZATION_NAME
FROM QSYS2.USER_INFO cross
join lateral (select * from table(systools.split(SPECIAL_AUTHORITIES,' '))) a
where element in ('*SECADM','*ALLOBJ')
union
SELECT
user_name
FROM qsys2.function_usage
where function_id = 'QIBM_DB_SECADM'
and usage = 'ALLOWED'

Is there an equivalent to Oracle's user_role_privs view in Postgres?

Am trying to fetch information in Postgres equivalent to Oracle's user_role_privs.
select username,granted_role,admin_option from user_role_privs
I tried all the below views in Postgres but couldn't find the desired one
information_schema.role_table_grants
pg_roles;
pg_class;
pg_user
pg_catalog.pg_auth_members;
Can anyone suggest which view should be used to get username, granted_role and admin_option in Postgres?
You are looking for the pg_auth_members system catalog that contains relationships between roles (which feature as both users and groups in PostgreSQL).
To get the names of the users and roles, join with the pg_roles system catalog.

Why does a PostgreSQL SELECT query return different results when a schema name is specified?

I have a PostgreSQL database table with 4 columns - labeled column_a, column_b, etc. I want to query this table with a simple select query:
select * from table_name;
I get a handful of results looking like:
column_a | column_b
---------+---------
'a value'|'b_value'
But when I use this query:
select * from schema_name.table_name;
I get the full result:
column_a | column_b | column_c | column_d
---------+----------+----------+---------
'a value'|'b value' |'c value' |'d_value'
Columns c and d were added at a later date, after initial table creation. My question is: Why would the database ignore the later columns when the schema name is left out of the select query?
Table names are not unique within a database in Postgres. There can be any number of tables named 'table_name' in different schemas - including the temporary schema, which always comes first unless you explicitly list it after other schemas in the search_path. Obviously, there are multiple tables named table_name. You must understand the role of the search_path to interpret this correctly:
How does the search_path influence identifier resolution and the "current schema"
The first table lives in a schema that comes before schema_name in your search_path (or schema_name is not listed there at all). So the unqualified table name is resolved to this table (or view). Check the list of tables named 'table_name' that your current role has access to in your database:
SELECT *
FROM information_schema.tables
WHERE table_name = 'table_name';
Views are just special tables with an attached RULE internally. They could play the same role as a regular table and are included in the above query.
Details:
How to check if a table exists in a given schema

Retrieving all object privileges for specific role

Is there an easy way to enumerate all objects that a specific role has some access privilege to? I know of the set of has_*_privilege functions in pg_catalog but they don't do the job, I want to work the other way around. Effectively I want to have a view that gives oid and access privilege for anything stored in pg_class for a specific role.
Such a view would be extremely handy to check if the security of the database is correctly set up. Typically there are far fewer roles than relations so checking the roles is much less onerous IMHO. Should such an utility not be available in the standard PostgreSQL distribution?
According to the source code (acl.h) the aclitem is a struct:
typedef struct AclItem
{ Oid ai_grantee; /* ID that this item grants privs to */
Oid ai_grantor; /* grantor of privs */
AclMode ai_privs; /* privilege bits */
} AclItem;
Easy to work with. However, pg_type lists this as a user-defined, non-composite type. Why is that? The only way I see right now is to parse the aclitem[] array using string functions. Is there a better way to analyze the aclitem array?
Added information
Trawling through the various PG lists, it is obvious that this issue keeps popping up in various forms at least since 1997 (did we have computers then? was tv around?), most relevant in the discussion thread "Binary in/out for aclitem" on pgsql-hackers in early 2011. As a (technically skilled) user - rather than a hacker - of PG I appreciate the concern of the developers to maintain a stable interface, but some of the concern voiced in the thread goes a little far for my tastes. What is the real reason not to have a pg_acl table in the system catalogs with definition equal to the AclItem struct in the source code? When did that struct last change? I am also aware of SE developments that will likely introduce changes to the way security is handled - when a users opts to, presumably - so I will settle for something that presents acl information in such a way that it is easy to enumerate granted privileges for a specific user, such as:
SELECT * FROM pg_privileges WHERE grantee = 16384;
Like so it can still be an abstraction of the underlying structures so any changes under the hood could then (presumably) still be translated into the exposed interface. Not too different from the information_schema approach, I would say.
Cheers,
Patrick
There's no such view out of the box, but the data needed to create it is in the system catalogs:
http://www.postgresql.org/docs/current/static/catalogs.html
For instance, there's a relacl field in pg_class:
select oid::regclass, relacl from pg_class;
There are similar fields in other catalogs, namely typacl in pg_type and proacl in pg_proc.
You'll presumably want to use two more catalogs, namely pg_authid to know which roles are have superuser privileges, and pg_auth_members to know who has what role.
(The pg_default_acl is only used during object creation, so is not useful.)
There are a couple of aclitem-related internal functions that may come in handy in creating the view. You can list them in psql like so:
\df+ *acl*
In particular aclexplode(). The following example will hopefully be enough to get you started:
select oid::regclass,
(aclexplode(relacl)).grantor,
(aclexplode(relacl)).grantee,
(aclexplode(relacl)).privilege_type,
(aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;
It can be optimized by expanding the acl rows first, e.g.:
select oid::regclass,
aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub
It will lead you straight to the desired result.
Insofar as I'm aware, that's about as good as it'll get using the built-in tools. (Naturally, you could write your own set of operators in C if you'd like to try to optimize this further.)
With respect to your extra questions, I'm afraid they can only be answered by a handful of people in the world, aka the core devs themselves. They hang out on the pg hackers list more often than they do here.
Probably not the best / efficient way, but it helps me a lot! I needed it while having problems dropping roles and having the error.
ERROR: role ROLE_NAME cannot be dropped because some objects depend on it
You can use it as
SELECT * FROM upg_roles_privs WHERE grantee = 'testuser'
The code is below. I'm not including "system" objects (from pg_catalog and information_schema), you can take the conditions out of the query if you wish to enumerate them.
CREATE VIEW upg_roles_privs AS
/* Databases */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type
from
(select
'database'::text as type, datname as objname, datistemplate, datallowconn,
(aclexplode(datacl)).grantor as grantorI,
(aclexplode(datacl)).grantee as granteeI,
(aclexplode(datacl)).privilege_type,
(aclexplode(datacl)).is_grantable
from pg_database) as db
join pg_roles r1 on db.grantorI = r1.oid
join pg_roles r2 on db.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Schemas / Namespaces */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type from
(select
'schema'::text as type, nspname as objname,
(aclexplode(nspacl)).grantor as grantorI,
(aclexplode(nspacl)).grantee as granteeI,
(aclexplode(nspacl)).privilege_type,
(aclexplode(nspacl)).is_grantable
from pg_catalog.pg_namespace) as ns
join pg_roles r1 on ns.grantorI = r1.oid
join pg_roles r2 on ns.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Tabelas */
select 'tables'::text as type, table_name||' ('||table_schema||')' as objname, grantor, grantee, privilege_type
from information_schema.role_table_grants
where grantee not in ('postgres')
and table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Colunas (TODO: se o revoke on table from x retirar acesso das colunas, nao precisa desse bloco) */
select
'columns'::text as type, column_name||' ('||table_name||')' as objname,
grantor, grantee, privilege_type
from information_schema.role_column_grants
where
table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Funcoes / Procedures */
select 'routine'::text as type, routine_name as objname, grantor, grantee, privilege_type
from information_schema.role_routine_grants
where grantor <> grantee
and routine_schema not in ('information_schema', 'pg_catalog')
--union all information_schema.role_udt_grants
union all
/* Outros objetos */
select 'object'::text as type, object_name||'( '||object_type||')' as objname, grantor, grantee, privilege_type
from information_schema.role_usage_grants
where object_type <> 'COLLATION' and object_type <> 'DOMAIN'