From ae6f977d3e8885a6551e337af565ab136f50cb8d Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Wed, 28 May 2025 18:58:51 +0200 Subject: [PATCH 03/15] GRANT, REVOKE variable Access to session variables can be controlled by SELECT or UPDATE rights. Both rights are introduced by this patch too. Default ACL are supported. --- doc/src/sgml/catalogs.sgml | 3 +- doc/src/sgml/ddl.sgml | 19 +- doc/src/sgml/func.sgml | 24 +- .../sgml/ref/alter_default_privileges.sgml | 29 +- doc/src/sgml/ref/grant.sgml | 20 +- doc/src/sgml/ref/revoke.sgml | 8 + src/backend/catalog/aclchk.c | 74 ++++- src/backend/catalog/objectaddress.c | 22 +- src/backend/catalog/pg_variable.c | 11 +- src/backend/parser/gram.y | 21 +- src/backend/utils/adt/acl.c | 221 +++++++++++++ src/include/catalog/pg_default_acl.h | 1 + src/include/catalog/pg_proc.dat | 20 ++ src/include/parser/kwlist.h | 1 + src/include/utils/acl.h | 1 + .../expected/session_variables_acl.out | 307 ++++++++++++++++++ src/test/regress/parallel_schedule | 2 +- .../regress/sql/session_variables_acl.sql | 158 +++++++++ 18 files changed, 916 insertions(+), 26 deletions(-) create mode 100644 src/test/regress/expected/session_variables_acl.out create mode 100644 src/test/regress/sql/session_variables_acl.sql diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 6ada59c798a..23da444f18f 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -3366,7 +3366,8 @@ SCRAM-SHA-256$<iteration count>:&l f = function, T = type, n = schema, - L = large object + L = large object, + V = session variable diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index dfbf7dbab4d..66fa267facc 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -2015,6 +2015,7 @@ REVOKE ALL ON accounts FROM PUBLIC; For sequences, this privilege also allows use of the currval function. For large objects, this privilege allows the object to be read. + For session variables, this privilege allows the object to be read. @@ -2050,6 +2051,8 @@ REVOKE ALL ON accounts FROM PUBLIC; setval functions. For large objects, this privilege allows writing or truncating the object. + For session variables, this privilege allows to set a value to the + object. @@ -2293,7 +2296,8 @@ REVOKE ALL ON accounts FROM PUBLIC; LARGE OBJECT, SEQUENCE, TABLE (and table-like objects), - table column + table column, + SESSION VARIABLE @@ -2308,7 +2312,8 @@ REVOKE ALL ON accounts FROM PUBLIC; LARGE OBJECT, SEQUENCE, TABLE, - table column + table column, + SESSION VARIABLE @@ -2495,6 +2500,12 @@ REVOKE ALL ON accounts FROM PUBLIC; U \dT+ + + SESSION VARIABLE + rw + none + \dV+ + @@ -5364,6 +5375,10 @@ EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2008-01-01'; Session variables are database objects that can hold a value. + Session variables, like relations, exist within a schema and their access + is controlled via GRANT and REVOKE + commands. A session variable can be created by the CREATE + VARIABLE command. diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c67688cbf5f..3e8d4bea149 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25602,6 +25602,25 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); + + + + has_session_variable_privilege + + has_session_variable_privilege ( + user name or oid, + session_variable text or oid, + privilege text ) + boolean + + + Does user have privilege for session variable? + Allowable privilege types are + SELECT, and + UPDATE. + + + @@ -25841,8 +25860,8 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); 't' for TABLESPACE, 'F' for FOREIGN DATA WRAPPER, 'S' for FOREIGN SERVER, - or - 'T' for TYPE or DOMAIN. + 'T' for TYPE or DOMAIN or + 'V' for SESSION VARIABLE. @@ -26110,6 +26129,7 @@ SELECT relname FROM pg_class WHERE pg_table_is_visible(oid); Is type (or domain) visible in search path? + diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml index 6acd0f1df91..bc73817061f 100644 --- a/doc/src/sgml/ref/alter_default_privileges.sgml +++ b/doc/src/sgml/ref/alter_default_privileges.sgml @@ -56,6 +56,11 @@ GRANT { { SELECT | UPDATE } ON LARGE OBJECTS TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ] +GRANT { { SELECT | UPDATE } + [, ...] | ALL [ PRIVILEGES ] } + ON VARIABLES + TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ] + REVOKE [ GRANT OPTION FOR ] { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN } [, ...] | ALL [ PRIVILEGES ] } @@ -95,6 +100,14 @@ REVOKE [ GRANT OPTION FOR ] ON LARGE OBJECTS FROM { [ GROUP ] role_name | PUBLIC } [, ...] [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] + { { SELECT | UPDATE } + [, ...] | ALL [ PRIVILEGES ] } + { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } + ON VARIABLES + FROM { [ GROUP ] role_name | PUBLIC } [, ...] + [ CASCADE | RESTRICT ] @@ -129,14 +142,14 @@ REVOKE [ GRANT OPTION FOR ] Currently, only the privileges for schemas, tables (including views and foreign - tables), sequences, functions, types (including domains), and large objects - can be altered. For this command, functions include aggregates and procedures. - The words FUNCTIONS and ROUTINES are - equivalent in this command. (ROUTINES is preferred - going forward as the standard term for functions and procedures taken - together. In earlier PostgreSQL releases, only the - word FUNCTIONS was allowed. It is not possible to set - default privileges for functions and procedures separately.) + tables), sequences, functions, types (including domains), large objects + and session variables can be altered. For this command, functions include + aggregates and procedures. The words FUNCTIONS and + ROUTINES are equivalent in this command. + (ROUTINES is preferred going forward as the standard term + for functions and procedures taken together. In earlier PostgreSQL releases, + only the word FUNCTIONS was allowed. It is not possible + to set default privileges for functions and procedures separately.) diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 999f657d5c0..c11860fa200 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -101,6 +101,12 @@ GRANT role_name [, ...] TO role_specification ] +GRANT { SELECT | UPDATE | ALL [ PRIVILEGES ] } + ON { VARIABLE variable_name [, ...] + | ALL VARIABLES IN SCHEMA schema_name [, ...] } + TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] + where role_specification can be: [ GROUP ] role_name @@ -119,8 +125,8 @@ GRANT role_name [, ...] TO @@ -236,9 +242,9 @@ GRANT role_name [, ...] TO There is also an option to grant privileges on all objects of the same type within one or more schemas. This functionality is currently supported - only for tables, sequences, functions, and procedures. ALL - TABLES also affects views and foreign tables, just like the - specific-object GRANT command. ALL + only for tables, sequences, functions, procedures and variables. + ALL TABLES also affects views and foreign tables, just + like the specific-object GRANT command. ALL FUNCTIONS also affects aggregate and window functions, but not procedures, again just like the specific-object GRANT command. Use ALL ROUTINES to include procedures. @@ -518,8 +524,8 @@ GRANT admins TO joe; - Privileges on databases, tablespaces, schemas, languages, and - configuration parameters are + Privileges on databases, tablespaces, schemas, languages, session variables + and configuration parameters are PostgreSQL extensions. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 8df492281a1..760fddb7c20 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -130,6 +130,14 @@ REVOKE [ { ADMIN | INHERIT | SET } OPTION FOR ] [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] +REVOKE [ GRANT OPTION FOR ] + { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] } + ON { VARIABLE variable_name [, ...] + | ALL VARIABLES IN SCHEMA schema_name [, ...] } + FROM { role_specification | PUBLIC } [, ...] + [ GRANTED BY role_specification ] + [ CASCADE | RESTRICT ] + where role_specification can be: [ GROUP ] role_name diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 7075c86378a..e333ad22e25 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -64,6 +64,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" +#include "catalog/pg_variable.h" #include "commands/dbcommands.h" #include "commands/defrem.h" #include "commands/event_trigger.h" @@ -291,6 +292,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, case OBJECT_PARAMETER_ACL: whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL; break; + case OBJECT_VARIABLE: + whole_mask = ACL_ALL_RIGHTS_VARIABLE; + break; default: elog(ERROR, "unrecognized object type: %d", objtype); /* not reached, but keep compiler quiet */ @@ -535,6 +539,10 @@ ExecuteGrantStmt(GrantStmt *stmt) all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL; errormsg = gettext_noop("invalid privilege type %s for parameter"); break; + case OBJECT_VARIABLE: + all_privileges = ACL_ALL_RIGHTS_VARIABLE; + errormsg = gettext_noop("invalid privilege type %s for session variable"); + break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) stmt->objtype); @@ -640,6 +648,9 @@ ExecGrantStmt_oids(InternalGrant *istmt) case OBJECT_PARAMETER_ACL: ExecGrant_Parameter(istmt); break; + case OBJECT_VARIABLE: + ExecGrant_common(istmt, VariableRelationId, ACL_ALL_RIGHTS_VARIABLE, NULL); + break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) istmt->objtype); @@ -760,6 +771,18 @@ objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant) objects = lappend_oid(objects, parameterId); } break; + + case OBJECT_VARIABLE: + foreach_node(RangeVar, varvar, objnames) + { + Oid relOid; + + relOid = LookupVariable(varvar->schemaname, + varvar->relname, + false); + objects = lappend_oid(objects, relOid); + } + break; } return objects; @@ -846,6 +869,32 @@ objectsInSchemaToOids(ObjectType objtype, List *nspnames) table_close(rel, AccessShareLock); } break; + case OBJECT_VARIABLE: + { + ScanKeyData key; + Relation rel; + TableScanDesc scan; + HeapTuple tuple; + + ScanKeyInit(&key, + Anum_pg_variable_varnamespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(namespaceId)); + + rel = table_open(VariableRelationId, AccessShareLock); + scan = table_beginscan_catalog(rel, 1, &key); + + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid; + + objects = lappend_oid(objects, oid); + } + + table_endscan(scan); + table_close(rel, AccessShareLock); + } + break; default: /* should not happen */ elog(ERROR, "unrecognized GrantStmt.objtype: %d", @@ -1009,6 +1058,10 @@ ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *s all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT; errormsg = gettext_noop("invalid privilege type %s for large object"); break; + case OBJECT_VARIABLE: + all_privileges = ACL_ALL_RIGHTS_VARIABLE; + errormsg = gettext_noop("invalid privilege type %s for session variable"); + break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) action->objtype); @@ -1209,6 +1262,11 @@ SetDefaultACL(InternalDefaultACL *iacls) if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT; break; + case OBJECT_VARIABLE: + objtype = DEFACLOBJ_VARIABLE; + if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS) + this_privileges = ACL_ALL_RIGHTS_VARIABLE; + break; default: elog(ERROR, "unrecognized object type: %d", @@ -1456,6 +1514,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid) case DEFACLOBJ_LARGEOBJECT: iacls.objtype = OBJECT_LARGEOBJECT; break; + case DEFACLOBJ_VARIABLE: + iacls.objtype = OBJECT_VARIABLE; + break; default: /* Shouldn't get here */ elog(ERROR, "unexpected default ACL type: %d", @@ -1516,6 +1577,9 @@ RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid) case ParameterAclRelationId: istmt.objtype = OBJECT_PARAMETER_ACL; break; + case VariableRelationId: + istmt.objtype = OBJECT_VARIABLE; + break; default: elog(ERROR, "unexpected object class %u", classid); break; @@ -2749,6 +2813,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_TYPE: msg = gettext_noop("permission denied for type %s"); break; + case OBJECT_VARIABLE: + msg = gettext_noop("permission denied for session variable %s"); + break; case OBJECT_VIEW: msg = gettext_noop("permission denied for view %s"); break; @@ -2771,7 +2838,6 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: - case OBJECT_VARIABLE: elog(ERROR, "unsupported object type: %d", objtype); } @@ -3012,6 +3078,8 @@ pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, return ACL_NO_RIGHTS; case OBJECT_TYPE: return object_aclmask(TypeRelationId, object_oid, roleid, mask, how); + case OBJECT_VARIABLE: + return object_aclmask(VariableRelationId, object_oid, roleid, mask, how); default: elog(ERROR, "unrecognized object type: %d", (int) objtype); @@ -4275,6 +4343,10 @@ get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid) defaclobjtype = DEFACLOBJ_LARGEOBJECT; break; + case OBJECT_VARIABLE: + defaclobjtype = DEFACLOBJ_VARIABLE; + break; + default: return NULL; } diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 9413b7619c5..444892ad6ba 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2030,17 +2030,21 @@ get_object_address_defacl(List *object, bool missing_ok) case DEFACLOBJ_LARGEOBJECT: objtype_str = "large objects"; break; + case DEFACLOBJ_VARIABLE: + objtype_str = "variables"; + break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized default ACL object type \"%c\"", objtype), - errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".", + errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".", DEFACLOBJ_RELATION, DEFACLOBJ_SEQUENCE, DEFACLOBJ_FUNCTION, DEFACLOBJ_TYPE, DEFACLOBJ_NAMESPACE, - DEFACLOBJ_LARGEOBJECT))); + DEFACLOBJ_LARGEOBJECT, + DEFACLOBJ_VARIABLE))); } /* @@ -3922,6 +3926,16 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) _("default privileges on new large objects belonging to role %s"), rolename); break; + case DEFACLOBJ_VARIABLE: + if (nspname) + appendStringInfo(&buffer, + _("default privileges on new session variables belonging to role %s in schema %s"), + rolename, nspname); + else + appendStringInfo(&buffer, + _("default privileges on new session variables belonging to role %s"), + rolename); + break; default: /* shouldn't get here */ if (nspname) @@ -5852,6 +5866,10 @@ getObjectIdentityParts(const ObjectAddress *object, appendStringInfoString(&buffer, " on large objects"); break; + case DEFACLOBJ_VARIABLE: + appendStringInfoString(&buffer, + " on session variables"); + break; } if (objname) diff --git a/src/backend/catalog/pg_variable.c b/src/backend/catalog/pg_variable.c index bd6a29a79e5..d8ede4fa8c8 100644 --- a/src/backend/catalog/pg_variable.c +++ b/src/backend/catalog/pg_variable.c @@ -38,6 +38,7 @@ create_variable(const char *varName, Oid varCollation, bool if_not_exists) { + Acl *varacl; NameData varname; bool nulls[Natts_pg_variable]; Datum values[Natts_pg_variable]; @@ -97,7 +98,12 @@ create_variable(const char *varName, values[Anum_pg_variable_varowner - 1] = ObjectIdGetDatum(varOwner); values[Anum_pg_variable_varcollation - 1] = ObjectIdGetDatum(varCollation); - nulls[Anum_pg_variable_varacl - 1] = true; + varacl = get_user_default_acl(OBJECT_VARIABLE, varOwner, + varNamespace); + if (varacl != NULL) + values[Anum_pg_variable_varacl - 1] = PointerGetDatum(varacl); + else + nulls[Anum_pg_variable_varacl - 1] = true; tupdesc = RelationGetDescr(rel); @@ -131,6 +137,9 @@ create_variable(const char *varName, /* dependency on owner */ recordDependencyOnOwner(VariableRelationId, varid, varOwner); + /* dependencies on roles mentioned in default ACL */ + recordDependencyOnNewAcl(VariableRelationId, varid, 0, varOwner, varacl); + /* dependency on extension */ recordDependencyOnCurrentExtension(&myself, false); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 64db4b5e88b..61a5f762d85 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -785,7 +785,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); UNLISTEN UNLOGGED UNTIL UPDATE USER USING VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARIABLE - VARYING VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE + VARIABLES VARYING VERBOSE VERSION_P VIEW VIEWS VIRTUAL VOLATILE WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE @@ -7966,6 +7966,14 @@ privilege_target: n->objs = $2; $$ = n; } + | VARIABLE qualified_name_list + { + PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); + n->targtype = ACL_TARGET_OBJECT; + n->objtype = OBJECT_VARIABLE; + n->objs = $2; + $$ = n; + } | ALL TABLES IN_P SCHEMA name_list { PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); @@ -8011,6 +8019,14 @@ privilege_target: n->objs = $5; $$ = n; } + | ALL VARIABLES IN_P SCHEMA name_list + { + PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); + n->targtype = ACL_TARGET_ALL_IN_SCHEMA; + n->objtype = OBJECT_VARIABLE; + n->objs = $5; + $$ = n; + } ; @@ -8209,6 +8225,7 @@ defacl_privilege_target: | TYPES_P { $$ = OBJECT_TYPE; } | SCHEMAS { $$ = OBJECT_SCHEMA; } | LARGE_P OBJECTS_P { $$ = OBJECT_LARGEOBJECT; } + | VARIABLES { $$ = OBJECT_VARIABLE; } ; @@ -18101,6 +18118,7 @@ unreserved_keyword: | VALIDATOR | VALUE_P | VARIABLE + | VARIABLES | VARYING | VERSION_P | VIEW @@ -18758,6 +18776,7 @@ bare_label_keyword: | VALUES | VARCHAR | VARIABLE + | VARIABLES | VARIADIC | VERBOSE | VERSION_P diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index ca3c5ee3df3..07874d4ba39 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -31,6 +31,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" +#include "catalog/pg_variable.h" #include "commands/dbcommands.h" #include "commands/proclang.h" #include "commands/tablespace.h" @@ -129,6 +130,8 @@ static AclMode convert_type_priv_string(text *priv_type_text); static AclMode convert_parameter_priv_string(text *priv_text); static AclMode convert_largeobject_priv_string(text *priv_type_text); static AclMode convert_role_priv_string(text *priv_type_text); +static Oid convert_session_variable_name(text *varname); +static AclMode convert_session_variable_priv_string(text *priv_type_text); static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode); static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue); @@ -851,6 +854,10 @@ acldefault(ObjectType objtype, Oid ownerId) world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL; break; + case OBJECT_VARIABLE: + world_default = ACL_NO_RIGHTS; + owner_default = ACL_ALL_RIGHTS_VARIABLE; + break; default: elog(ERROR, "unrecognized object type: %d", (int) objtype); world_default = ACL_NO_RIGHTS; /* keep compiler quiet */ @@ -948,6 +955,9 @@ acldefault_sql(PG_FUNCTION_ARGS) case 'T': objtype = OBJECT_TYPE; break; + case 'V': + objtype = OBJECT_VARIABLE; + break; default: elog(ERROR, "unrecognized object type abbreviation: %c", objtypec); } @@ -5016,6 +5026,217 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode) return ACLCHECK_NO_PRIV; } +/* + * has_session_variable_privilege variants + * These are all named "has_session_variable_privilege" at the SQL level. + * They take various combinations of variable name, variable OID, + * user name, user OID, or implicit user = current_user. + * + * The result is a boolean value: true if user has the indicated + * privilege, false if not, or NULL if session variable doesn't + * exists. + */ + +/* + * has_session_variable_privilege_name_name + * Check user privileges on a session variable given + * name username, text session variable name, and text priv name. + */ +Datum +has_session_variable_privilege_name_name(PG_FUNCTION_ARGS) +{ + Name rolename = PG_GETARG_NAME(0); + text *varname = PG_GETARG_TEXT_PP(1); + text *priv_type_text = PG_GETARG_TEXT_PP(2); + Oid roleid; + Oid varid; + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + roleid = get_role_oid_or_public(NameStr(*rolename)); + mode = convert_session_variable_priv_string(priv_type_text); + varid = convert_session_variable_name(varname); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + if (is_missing) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * has_session_variable_privilege_name + * Check user privileges on a session variable given + * text session variable and text priv name. + * current_user is assumed + */ +Datum +has_session_variable_privilege_name(PG_FUNCTION_ARGS) +{ + text *varname = PG_GETARG_TEXT_PP(0); + text *priv_type_text = PG_GETARG_TEXT_PP(1); + Oid roleid; + Oid varid; + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + roleid = GetUserId(); + mode = convert_session_variable_priv_string(priv_type_text); + varid = convert_session_variable_name(varname); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * has_session_variable_privilege_name_id + * Check user privileges on a session variable given + * name usename, session variable oid, and text priv name. + */ +Datum +has_session_variable_privilege_name_id(PG_FUNCTION_ARGS) +{ + Name username = PG_GETARG_NAME(0); + Oid varid = PG_GETARG_OID(1); + text *priv_type_text = PG_GETARG_TEXT_PP(2); + Oid roleid; + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + roleid = get_role_oid_or_public(NameStr(*username)); + mode = convert_session_variable_priv_string(priv_type_text); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + if (is_missing) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * has_session_variable_privilege_id + * Check user privileges on a session variable given + * session variable oid, and text priv name. + * current_user is assumed + */ +Datum +has_session_variable_privilege_id(PG_FUNCTION_ARGS) +{ + Oid varid = PG_GETARG_OID(0); + text *priv_type_text = PG_GETARG_TEXT_PP(1); + Oid roleid; + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + roleid = GetUserId(); + mode = convert_session_variable_priv_string(priv_type_text); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + if (is_missing) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * has_session_variable_privilege_id_name + * Check user privileges on a session variable given + * roleid, text session variable name, and text priv name. + */ +Datum +has_session_variable_privilege_id_name(PG_FUNCTION_ARGS) +{ + Oid roleid = PG_GETARG_OID(0); + text *varname = PG_GETARG_TEXT_PP(1); + text *priv_type_text = PG_GETARG_TEXT_PP(2); + Oid varid; + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + mode = convert_session_variable_priv_string(priv_type_text); + varid = convert_session_variable_name(varname); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + if (is_missing) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * has_session_variable_privilege_id_id + * Check user privileges on a session variable given + * roleid, session variable oid, and text priv name. + */ +Datum +has_session_variable_privilege_id_id(PG_FUNCTION_ARGS) +{ + Oid roleid = PG_GETARG_OID(0); + Oid varid = PG_GETARG_OID(1); + text *priv_type_text = PG_GETARG_TEXT_PP(2); + AclMode mode; + AclResult aclresult; + bool is_missing = false; + + mode = convert_session_variable_priv_string(priv_type_text); + + aclresult = object_aclcheck_ext(VariableRelationId, varid, + roleid, mode, + &is_missing); + + if (is_missing) + PG_RETURN_NULL(); + + PG_RETURN_BOOL(aclresult == ACLCHECK_OK); +} + +/* + * Given a session variable name expressed as a string, look it up and return + * Oid + */ +static Oid +convert_session_variable_name(text *varname) +{ + return LookupVariableFromNameList(textToQualifiedNameList(varname), true); +} + +/* + * convert_variable_priv_string + * Convert text string to AclMode value. + */ +static AclMode +convert_session_variable_priv_string(text *priv_type_text) +{ + static const priv_map session_variable_priv_map[] = { + {"SELECT", ACL_SELECT}, + {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)}, + {"UPDATE", ACL_UPDATE}, + {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)}, + {NULL, 0} + }; + + return convert_any_priv_string(priv_type_text, session_variable_priv_map); +} /* * initialization function (called by InitPostgres) diff --git a/src/include/catalog/pg_default_acl.h b/src/include/catalog/pg_default_acl.h index ce6e5098eaf..087d35b943d 100644 --- a/src/include/catalog/pg_default_acl.h +++ b/src/include/catalog/pg_default_acl.h @@ -69,6 +69,7 @@ MAKE_SYSCACHE(DEFACLROLENSPOBJ, pg_default_acl_role_nsp_obj_index, 8); #define DEFACLOBJ_TYPE 'T' /* type */ #define DEFACLOBJ_NAMESPACE 'n' /* namespace */ #define DEFACLOBJ_LARGEOBJECT 'L' /* large object */ +#define DEFACLOBJ_VARIABLE 'V' /* variable */ #endif /* EXPOSE_TO_CLIENT_CODE */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d3d28a263fa..5da9959942c 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5466,6 +5466,26 @@ prorettype => 'bool', proargtypes => 'oid oid text', prosrc => 'has_largeobject_privilege_id_id' }, +{ oid => '9613', descr => 'user privilege on session variable by username, seq name', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name text text', + prosrc => 'has_session_variable_privilege_name_name' }, +{ oid => '9614', descr => 'user privilege on session variable by username, seq oid', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'name oid text', prosrc => 'has_session_variable_privilege_name_id' }, +{ oid => '9615', descr => 'user privilege on session variable by user oid, seq name', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text text', prosrc => 'has_session_variable_privilege_id_name' }, +{ oid => '9616', descr => 'user privilege on session variable by user oid, seq oid', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid oid text', prosrc => 'has_session_variable_privilege_id_id' }, +{ oid => '9617', descr => 'current user privilege on session variable by seq name', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'text text', prosrc => 'has_session_variable_privilege_name' }, +{ oid => '9618', descr => 'current user privilege on session variable by seq oid', + proname => 'has_session_variable_privilege', provolatile => 's', prorettype => 'bool', + proargtypes => 'oid text', prosrc => 'has_session_variable_privilege_id' }, + { oid => '3355', descr => 'I/O', proname => 'pg_ndistinct_in', prorettype => 'pg_ndistinct', proargtypes => 'cstring', prosrc => 'pg_ndistinct_in' }, diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 6f513f04225..0ea0265de7c 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -487,6 +487,7 @@ PG_KEYWORD("value", VALUE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("values", VALUES, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("varchar", VARCHAR, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("variable", VARIABLE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("variables", VARIABLES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("variadic", VARIADIC, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("varying", VARYING, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("verbose", VERBOSE, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 01ae5b719fd..5e1a8a82e90 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -169,6 +169,7 @@ typedef struct ArrayType Acl; #define ACL_ALL_RIGHTS_SCHEMA (ACL_USAGE|ACL_CREATE) #define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE) #define ACL_ALL_RIGHTS_TYPE (ACL_USAGE) +#define ACL_ALL_RIGHTS_VARIABLE (ACL_SELECT|ACL_UPDATE) /* operation codes for pg_*_aclmask */ typedef enum diff --git a/src/test/regress/expected/session_variables_acl.out b/src/test/regress/expected/session_variables_acl.out new file mode 100644 index 00000000000..478b47472f0 --- /dev/null +++ b/src/test/regress/expected/session_variables_acl.out @@ -0,0 +1,307 @@ +-- check access rights and supported ALTER +CREATE SCHEMA svartest_acl; +CREATE ROLE regress_variable_owner_acl; +CREATE ROLE regress_variable_reader_acl; +GRANT ALL ON SCHEMA svartest_acl TO regress_variable_owner_acl; +GRANT ALL ON SCHEMA public TO regress_variable_owner_acl; +ALTER DEFAULT PRIVILEGES + FOR ROLE regress_variable_owner_acl + IN SCHEMA svartest_acl + GRANT SELECT ON VARIABLES TO regress_variable_reader_acl; +-- creating variable with default privileges +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE svartest_acl.sesvar20 AS int; +SET ROLE TO DEFAULT; +-- should be ok. since ALTER DEFAULT PRIVILEGES +-- allow regress_variable_reader_acl to have SELECT priviledge +SELECT has_session_variable_privilege('regress_variable_reader_acl', 'svartest_acl.sesvar20', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +DROP VARIABLE svartest_acl.sesvar20; +DROP SCHEMA svartest_acl; +DROP ROLE regress_variable_reader_acl; +-- +-- begin of check GRANT WITH GRANT OPTION and REVOKE GRANTED BY +-- +CREATE ROLE regress_variable_r1_acl; +CREATE ROLE regress_variable_r2_acl; +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE sesvar22_acl AS int; --sesvar22_acl will owned by regress_variable_owner_acl +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r1_acl WITH GRANT OPTION; +SET ROLE TO regress_variable_r1_acl; +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r2_acl WITH GRANT OPTION; +SET ROLE TO DEFAULT; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +REVOKE ALL PRIVILEGES ON VARIABLE sesvar22_acl FROM regress_variable_r1_acl CASCADE; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SET ROLE TO regress_variable_owner_acl; +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r2_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +REVOKE ALL ON VARIABLE sesvar22_acl FROM regress_variable_r2_acl GRANTED BY regress_variable_owner_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_owner_acl', 'public.sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SET ROLE TO DEFAULT; +DROP VARIABLE sesvar22_acl; +-- +-- end of check GRANT WITH GRANT OPTION and REVOKE GRANTED BY +-- +-- +-- begin of test: GRANT|REVOKE SELECT|UPDATE ON ALL VARIABLES IN SCHEMA +-- +CREATE SCHEMA svartest_acl; +GRANT ALL ON SCHEMA svartest_acl TO regress_variable_owner_acl; +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE svartest_acl.sesvar20 AS int; +CREATE VARIABLE svartest_acl.sesvar21 AS int; +GRANT SELECT ON ALL VARIABLES IN SCHEMA svartest_acl TO regress_variable_r1_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar20', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar21', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +REVOKE SELECT ON ALL VARIABLES IN SCHEMA svartest_acl FROM regress_variable_r1_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar20', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar21', 'SELECT'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SET ROLE TO DEFAULT; +DROP VARIABLE svartest_acl.sesvar20; +DROP VARIABLE svartest_acl.sesvar21; +DROP SCHEMA svartest_acl; +-- +-- end of test: GRANT|REVOKE SELECT|UPDATE ON ALL VARIABLES IN SCHEMA +-- +-- +-- function has_session_variable_privilege have various kind of signature. +-- the following are extensive test for it. +-- +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE public.sesvar22_acl AS int; +SET search_path TO public; +GRANT SELECT ON VARIABLE public.sesvar22_acl TO regress_variable_r1_acl; +GRANT SELECT, UPDATE ON VARIABLE public.sesvar22_acl TO regress_variable_r2_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.notexists', 'SELECT') IS NULL; + ?column? +---------- + t +(1 row) + +SET ROLE TO regress_variable_r1_acl; +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'sesvar22_acl', 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'sesvar22_acl', 'UPDATE'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('sesvar22_acl', 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT oid AS varid + FROM pg_variable + WHERE varname = 'sesvar22_acl' AND varnamespace = 'public'::regnamespace \gset +SELECT has_session_variable_privilege('sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('sesvar22_acl', 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', :varid, 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl', :varid, 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', :varid, 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl', :varid, 'UPDATE'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege(:varid, 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege(:varid, 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, 'sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, 'sesvar22_acl', 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, 'sesvar22_acl', 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, 'sesvar22_acl', 'UPDATE'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, :varid, 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, :varid, 'UPDATE'); -- f + has_session_variable_privilege +-------------------------------- + f +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, :varid, 'SELECT'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, :varid, 'UPDATE'); -- t + has_session_variable_privilege +-------------------------------- + t +(1 row) + +-- +-- end of function has_session_variable_privilege tests. +-- +SET ROLE TO DEFAULT; +SET search_path TO DEFAULT; +DROP VARIABLE public.sesvar22_acl; +DROP ROLE regress_variable_r1_acl; +DROP ROLE regress_variable_r2_acl; +REVOKE ALL ON SCHEMA public FROM regress_variable_owner_acl; +DROP ROLE regress_variable_owner_acl; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 0f75bfaf5ae..1c67fdff564 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -115,7 +115,7 @@ test: json jsonb json_encoding jsonpath jsonpath_encoding jsonb_jsonpath sqljson # NB: temp.sql does reconnects which transiently use 2 connections, # so keep this parallel group to at most 19 tests # ---------- -test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml session_variables_ddl +test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml session_variables_ddl session_variables_acl # ---------- # Another group of parallel tests diff --git a/src/test/regress/sql/session_variables_acl.sql b/src/test/regress/sql/session_variables_acl.sql new file mode 100644 index 00000000000..e1a9d5ce5f4 --- /dev/null +++ b/src/test/regress/sql/session_variables_acl.sql @@ -0,0 +1,158 @@ +-- check access rights and supported ALTER +CREATE SCHEMA svartest_acl; +CREATE ROLE regress_variable_owner_acl; +CREATE ROLE regress_variable_reader_acl; + +GRANT ALL ON SCHEMA svartest_acl TO regress_variable_owner_acl; +GRANT ALL ON SCHEMA public TO regress_variable_owner_acl; + +ALTER DEFAULT PRIVILEGES + FOR ROLE regress_variable_owner_acl + IN SCHEMA svartest_acl + GRANT SELECT ON VARIABLES TO regress_variable_reader_acl; + +-- creating variable with default privileges +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE svartest_acl.sesvar20 AS int; +SET ROLE TO DEFAULT; + +-- should be ok. since ALTER DEFAULT PRIVILEGES +-- allow regress_variable_reader_acl to have SELECT priviledge +SELECT has_session_variable_privilege('regress_variable_reader_acl', 'svartest_acl.sesvar20', 'SELECT'); -- t + +DROP VARIABLE svartest_acl.sesvar20; +DROP SCHEMA svartest_acl; +DROP ROLE regress_variable_reader_acl; + +-- +-- begin of check GRANT WITH GRANT OPTION and REVOKE GRANTED BY +-- +CREATE ROLE regress_variable_r1_acl; +CREATE ROLE regress_variable_r2_acl; + +SET ROLE TO regress_variable_owner_acl; +CREATE VARIABLE sesvar22_acl AS int; --sesvar22_acl will owned by regress_variable_owner_acl + +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r1_acl WITH GRANT OPTION; +SET ROLE TO regress_variable_r1_acl; +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r2_acl WITH GRANT OPTION; +SET ROLE TO DEFAULT; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- t + +REVOKE ALL PRIVILEGES ON VARIABLE sesvar22_acl FROM regress_variable_r1_acl CASCADE; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- f + +SET ROLE TO regress_variable_owner_acl; +GRANT SELECT ON VARIABLE sesvar22_acl TO regress_variable_r2_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- t + +REVOKE ALL ON VARIABLE sesvar22_acl FROM regress_variable_r2_acl GRANTED BY regress_variable_owner_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'public.sesvar22_acl', 'SELECT'); -- f +SELECT has_session_variable_privilege('regress_variable_owner_acl', 'public.sesvar22_acl', 'SELECT'); -- t +SET ROLE TO DEFAULT; + +DROP VARIABLE sesvar22_acl; +-- +-- end of check GRANT WITH GRANT OPTION and REVOKE GRANTED BY +-- + +-- +-- begin of test: GRANT|REVOKE SELECT|UPDATE ON ALL VARIABLES IN SCHEMA +-- +CREATE SCHEMA svartest_acl; +GRANT ALL ON SCHEMA svartest_acl TO regress_variable_owner_acl; +SET ROLE TO regress_variable_owner_acl; + +CREATE VARIABLE svartest_acl.sesvar20 AS int; +CREATE VARIABLE svartest_acl.sesvar21 AS int; + +GRANT SELECT ON ALL VARIABLES IN SCHEMA svartest_acl TO regress_variable_r1_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar20', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar21', 'SELECT'); -- t + +REVOKE SELECT ON ALL VARIABLES IN SCHEMA svartest_acl FROM regress_variable_r1_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar20', 'SELECT'); -- f +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'svartest_acl.sesvar21', 'SELECT'); -- f + +SET ROLE TO DEFAULT; +DROP VARIABLE svartest_acl.sesvar20; +DROP VARIABLE svartest_acl.sesvar21; +DROP SCHEMA svartest_acl; +-- +-- end of test: GRANT|REVOKE SELECT|UPDATE ON ALL VARIABLES IN SCHEMA +-- + +-- +-- function has_session_variable_privilege have various kind of signature. +-- the following are extensive test for it. +-- +SET ROLE TO regress_variable_owner_acl; + +CREATE VARIABLE public.sesvar22_acl AS int; + +SET search_path TO public; + +GRANT SELECT ON VARIABLE public.sesvar22_acl TO regress_variable_r1_acl; +GRANT SELECT, UPDATE ON VARIABLE public.sesvar22_acl TO regress_variable_r2_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.sesvar22_acl', 'SELECT'); +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'public.notexists', 'SELECT') IS NULL; + +SET ROLE TO regress_variable_r1_acl; + +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r1_acl', 'sesvar22_acl', 'UPDATE'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r2_acl', 'sesvar22_acl', 'UPDATE'); -- t + +SELECT has_session_variable_privilege('sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('sesvar22_acl', 'UPDATE'); -- f + +SELECT oid AS varid + FROM pg_variable + WHERE varname = 'sesvar22_acl' AND varnamespace = 'public'::regnamespace \gset + +SELECT has_session_variable_privilege('sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('sesvar22_acl', 'UPDATE'); -- f + +SELECT has_session_variable_privilege('regress_variable_r1_acl', :varid, 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r1_acl', :varid, 'UPDATE'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl', :varid, 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r2_acl', :varid, 'UPDATE'); -- t + +SELECT has_session_variable_privilege(:varid, 'SELECT'); -- t +SELECT has_session_variable_privilege(:varid, 'UPDATE'); -- f + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, 'sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, 'sesvar22_acl', 'UPDATE'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, 'sesvar22_acl', 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, 'sesvar22_acl', 'UPDATE'); -- t + +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, :varid, 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r1_acl'::regrole, :varid, 'UPDATE'); -- f +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, :varid, 'SELECT'); -- t +SELECT has_session_variable_privilege('regress_variable_r2_acl'::regrole, :varid, 'UPDATE'); -- t +-- +-- end of function has_session_variable_privilege tests. +-- + +SET ROLE TO DEFAULT; +SET search_path TO DEFAULT; + +DROP VARIABLE public.sesvar22_acl; + +DROP ROLE regress_variable_r1_acl; +DROP ROLE regress_variable_r2_acl; + +REVOKE ALL ON SCHEMA public FROM regress_variable_owner_acl; +DROP ROLE regress_variable_owner_acl; -- 2.49.0