From 15c6a6dd5ab08027a324eeb11c0a9b519c4b3d94 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 14 Oct 2022 09:16:51 +0200 Subject: [PATCH] Refactor aclcheck functions Instead of dozens of mostly-duplicate pg_foo_aclcheck() functions, write one common function object_aclcheck() that can handle almost all of them. We already have all the information we need, such as which system catalog corresponds to which catalog table, and which column is the ACL column. I kept a few pg_foo_aclcheck() around as thin wrappers because they are widely used through the code. And there are also a few that don't work via the generic function, so those stay as is. I also changed most pg_foo_aclmask() functions to static functions, since they are not used outside of aclchk.c. --- contrib/dblink/dblink.c | 2 +- src/backend/catalog/aclchk.c | 601 +++++++--------------------- src/backend/commands/foreigncmds.c | 10 +- src/backend/commands/functioncmds.c | 6 +- src/backend/utils/adt/acl.c | 52 +-- src/backend/utils/fmgr/fmgr.c | 2 +- src/include/utils/acl.h | 47 +-- 7 files changed, 188 insertions(+), 532 deletions(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 9eef417c47b7..f8b017fd3a29 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -2838,7 +2838,7 @@ get_connect_string(const char *servername) fdw = GetForeignDataWrapper(fdwid); /* Check permissions, user must have usage on the server. */ - aclresult = pg_foreign_server_aclcheck(serverid, userid, ACL_USAGE); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, userid, ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, foreign_server->servername); diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index d67d3b522cef..9e8ec306f639 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -139,8 +139,26 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, Oid objectId, Oid grantorId, ObjectType objtype, const char *objname, AttrNumber att_number, const char *colname); -static AclMode pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, +static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how); +static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, + AclMode mask, AclMaskHow how); +static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mask, AclMaskHow how); +static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, + Oid roleid, AclMode mask, + AclMaskHow how, bool *is_missing); +static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing); +static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, + AclMode mask, AclMaskHow how); +static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, + AclMode mask, AclMaskHow how, Snapshot snapshot); +static AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, + AclMode mask, AclMaskHow how); +static AclMode pg_type_aclmask(Oid type_oid, Oid roleid, + AclMode mask, AclMaskHow how); static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl); static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, @@ -3787,47 +3805,47 @@ aclcheck_error_type(AclResult aclerr, Oid typeOid) * Relay for the various pg_*_mask routines depending on object kind */ static AclMode -pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid, +pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how) { switch (objtype) { case OBJECT_COLUMN: return - pg_class_aclmask(table_oid, roleid, mask, how) | - pg_attribute_aclmask(table_oid, attnum, roleid, mask, how); + pg_class_aclmask(object_oid, roleid, mask, how) | + pg_attribute_aclmask(object_oid, attnum, roleid, mask, how); case OBJECT_TABLE: case OBJECT_SEQUENCE: - return pg_class_aclmask(table_oid, roleid, mask, how); + return pg_class_aclmask(object_oid, roleid, mask, how); case OBJECT_DATABASE: - return pg_database_aclmask(table_oid, roleid, mask, how); + return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how); case OBJECT_FUNCTION: - return pg_proc_aclmask(table_oid, roleid, mask, how); + return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how); case OBJECT_LANGUAGE: - return pg_language_aclmask(table_oid, roleid, mask, how); + return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how); case OBJECT_LARGEOBJECT: - return pg_largeobject_aclmask_snapshot(table_oid, roleid, + return pg_largeobject_aclmask_snapshot(object_oid, roleid, mask, how, NULL); case OBJECT_PARAMETER_ACL: - return pg_parameter_acl_aclmask(table_oid, roleid, mask, how); + return pg_parameter_acl_aclmask(object_oid, roleid, mask, how); case OBJECT_SCHEMA: - return pg_namespace_aclmask(table_oid, roleid, mask, how); + return pg_namespace_aclmask(object_oid, roleid, mask, how); case OBJECT_STATISTIC_EXT: elog(ERROR, "grantable rights not supported for statistics objects"); /* not reached, but keep compiler quiet */ return ACL_NO_RIGHTS; case OBJECT_TABLESPACE: - return pg_tablespace_aclmask(table_oid, roleid, mask, how); + return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how); case OBJECT_FDW: - return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how); + return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how); case OBJECT_FOREIGN_SERVER: - return pg_foreign_server_aclmask(table_oid, roleid, mask, how); + return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how); case OBJECT_EVENT_TRIGGER: elog(ERROR, "grantable rights not supported for event triggers"); /* not reached, but keep compiler quiet */ return ACL_NO_RIGHTS; case OBJECT_TYPE: - return pg_type_aclmask(table_oid, roleid, mask, how); + return pg_type_aclmask(object_oid, roleid, mask, how); default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); @@ -3849,14 +3867,72 @@ pg_aclmask(ObjectType objtype, Oid table_oid, AttrNumber attnum, Oid roleid, */ /* - * Exported routine for examining a user's privileges for a column + * Generic routine for examining a user's privileges for an object + */ +static AclMode +object_aclmask(Oid classid, Oid objectid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + AclMode result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return mask; + + /* + * Get the objects's ACL from its catalog + */ + tuple = SearchSysCache1(get_object_catcache_oid(classid), ObjectIdGetDatum(objectid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid))); + + ownerId = DatumGetObjectId(SysCacheGetAttr(get_object_catcache_oid(classid), + tuple, + get_object_attnum_owner(classid), + &isNull)); + Assert(!isNull); + + aclDatum = SysCacheGetAttr(get_object_catcache_oid(classid), tuple, get_object_attnum_acl(classid), + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(get_object_type(classid, objectid), ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + result = aclmask(acl, roleid, ownerId, mask, how); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + +/* + * Routine for examining a user's privileges for a column * * Note: this considers only privileges granted specifically on the column. * It is caller's responsibility to take relation-level privileges into account * as appropriate. (For the same reason, we have no special case for * superuser-ness here.) */ -AclMode +static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how) { @@ -3865,12 +3941,12 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, } /* - * Exported routine for examining a user's privileges for a column + * Routine for examining a user's privileges for a column * * Does the bulk of the work for pg_attribute_aclmask(), and allows other * callers to avoid the missing attribute ERROR when is_missing is non-NULL. */ -AclMode +static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing) { @@ -3983,12 +4059,12 @@ pg_class_aclmask(Oid table_oid, Oid roleid, } /* - * Exported routine for examining a user's privileges for a table + * Routine for examining a user's privileges for a table * * Does the bulk of the work for pg_class_aclmask(), and allows other * callers to avoid the missing relation ERROR when is_missing is non-NULL. */ -AclMode +static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing) { @@ -4104,64 +4180,10 @@ pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, } /* - * Exported routine for examining a user's privileges for a database - */ -AclMode -pg_database_aclmask(Oid db_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - /* Superusers bypass all permission checking. */ - if (superuser_arg(roleid)) - return mask; - - /* - * Get the database's ACL from pg_database - */ - tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database with OID %u does not exist", db_oid))); - - ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba; - - aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl, - &isNull); - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_DATABASE, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a configuration + * Routine for examining a user's privileges for a configuration * parameter (GUC), identified by GUC name. */ -AclMode +static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how) { AclMode result; @@ -4222,10 +4244,10 @@ pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how) } /* - * Exported routine for examining a user's privileges for a configuration + * Routine for examining a user's privileges for a configuration * parameter (GUC), identified by the OID of its pg_parameter_acl entry. */ -AclMode +static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how) { AclMode result; @@ -4273,115 +4295,7 @@ pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how) } /* - * Exported routine for examining a user's privileges for a function - */ -AclMode -pg_proc_aclmask(Oid proc_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - /* Superusers bypass all permission checking. */ - if (superuser_arg(roleid)) - return mask; - - /* - * Get the function's ACL from pg_proc - */ - tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function with OID %u does not exist", proc_oid))); - - ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; - - aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, - &isNull); - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_FUNCTION, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a language - */ -AclMode -pg_language_aclmask(Oid lang_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - /* Superusers bypass all permission checking. */ - if (superuser_arg(roleid)) - return mask; - - /* - * Get the language's ACL from pg_language - */ - tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("language with OID %u does not exist", lang_oid))); - - ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner; - - aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl, - &isNull); - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_LANGUAGE, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a largeobject + * Routine for examining a user's privileges for a largeobject * * When a large object is opened for reading, it is opened relative to the * caller's snapshot, but when it is opened for writing, a current @@ -4392,7 +4306,7 @@ pg_language_aclmask(Oid lang_oid, Oid roleid, * snapshot, since all we do with the snapshot argument is pass it through * to systable_beginscan(). */ -AclMode +static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot) @@ -4463,9 +4377,9 @@ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, } /* - * Exported routine for examining a user's privileges for a namespace + * Routine for examining a user's privileges for a namespace */ -AclMode +static AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how) { @@ -4555,189 +4469,9 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid, } /* - * Exported routine for examining a user's privileges for a tablespace + * Routine for examining a user's privileges for a type. */ -AclMode -pg_tablespace_aclmask(Oid spc_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - /* Superusers bypass all permission checking. */ - if (superuser_arg(roleid)) - return mask; - - /* - * Get the tablespace's ACL from pg_tablespace - */ - tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("tablespace with OID %u does not exist", spc_oid))); - - ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner; - - aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple, - Anum_pg_tablespace_spcacl, - &isNull); - - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_TABLESPACE, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a foreign - * data wrapper - */ -AclMode -pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - Form_pg_foreign_data_wrapper fdwForm; - - /* Bypass permission checks for superusers */ - if (superuser_arg(roleid)) - return mask; - - /* - * Must get the FDW's tuple from pg_foreign_data_wrapper - */ - tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("foreign-data wrapper with OID %u does not exist", - fdw_oid))); - fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple); - - /* - * Normal case: get the FDW's ACL from pg_foreign_data_wrapper - */ - ownerId = fdwForm->fdwowner; - - aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple, - Anum_pg_foreign_data_wrapper_fdwacl, &isNull); - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_FDW, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast rel's ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a foreign - * server. - */ -AclMode -pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, - AclMode mask, AclMaskHow how) -{ - AclMode result; - HeapTuple tuple; - Datum aclDatum; - bool isNull; - Acl *acl; - Oid ownerId; - - Form_pg_foreign_server srvForm; - - /* Bypass permission checks for superusers */ - if (superuser_arg(roleid)) - return mask; - - /* - * Must get the FDW's tuple from pg_foreign_data_wrapper - */ - tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid)); - if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("foreign server with OID %u does not exist", - srv_oid))); - srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple); - - /* - * Normal case: get the foreign server's ACL from pg_foreign_server - */ - ownerId = srvForm->srvowner; - - aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple, - Anum_pg_foreign_server_srvacl, &isNull); - if (isNull) - { - /* No ACL, so build default ACL */ - acl = acldefault(OBJECT_FOREIGN_SERVER, ownerId); - aclDatum = (Datum) 0; - } - else - { - /* detoast rel's ACL if necessary */ - acl = DatumGetAclP(aclDatum); - } - - result = aclmask(acl, roleid, ownerId, mask, how); - - /* if we have a detoasted copy, free it */ - if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) - pfree(acl); - - ReleaseSysCache(tuple); - - return result; -} - -/* - * Exported routine for examining a user's privileges for a type. - */ -AclMode +static AclMode pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) { AclMode result; @@ -4811,6 +4545,40 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) return result; } +/* + * Exported generic routine for checking a user's access privileges to an object + */ +AclResult +object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode) +{ + if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0) + return ACLCHECK_OK; + else + return ACLCHECK_NO_PRIV; +} + +/* + * Wrapper functions for commonly used cases + */ + +AclResult +pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode) +{ + return object_aclcheck(DatabaseRelationId, db_oid, roleid, mode); +} + +AclResult +pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode) +{ + return object_aclcheck(ProcedureRelationId, proc_oid, roleid, mode); +} + +AclResult +pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode) +{ + return object_aclcheck(TableSpaceRelationId, spc_oid, roleid, mode); +} + /* * Exported routine for checking a user's access privileges to a column * @@ -4973,18 +4741,6 @@ pg_class_aclcheck_ext(Oid table_oid, Oid roleid, return ACLCHECK_NO_PRIV; } -/* - * Exported routine for checking a user's access privileges to a database - */ -AclResult -pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode) -{ - if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - /* * Exported routine for checking a user's access privileges to a configuration * parameter (GUC), identified by GUC name. @@ -4998,43 +4754,6 @@ pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode) return ACLCHECK_NO_PRIV; } -/* - * Exported routine for checking a user's access privileges to a configuration - * parameter (GUC), identified by the OID of its pg_parameter_acl entry. - */ -AclResult -pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid, AclMode mode) -{ - if (pg_parameter_acl_aclmask(acl_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - -/* - * Exported routine for checking a user's access privileges to a function - */ -AclResult -pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode) -{ - if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - -/* - * Exported routine for checking a user's access privileges to a language - */ -AclResult -pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode) -{ - if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - /* * Exported routine for checking a user's access privileges to a largeobject */ @@ -5061,44 +4780,6 @@ pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode) return ACLCHECK_NO_PRIV; } -/* - * Exported routine for checking a user's access privileges to a tablespace - */ -AclResult -pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode) -{ - if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - -/* - * Exported routine for checking a user's access privileges to a foreign - * data wrapper - */ -AclResult -pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode) -{ - if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - -/* - * Exported routine for checking a user's access privileges to a foreign - * server - */ -AclResult -pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode) -{ - if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0) - return ACLCHECK_OK; - else - return ACLCHECK_NO_PRIV; -} - /* * Exported routine for checking a user's access privileges to a type */ diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index e6e6d128d11a..55b0be9e1d11 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -366,7 +366,7 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) check_is_member_of_role(GetUserId(), newOwnerId); /* New owner must have USAGE privilege on foreign-data wrapper */ - aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, form->srvfdw, newOwnerId, ACL_USAGE); if (aclresult != ACLCHECK_OK) { ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw); @@ -891,7 +891,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt) */ fdw = GetForeignDataWrapperByName(stmt->fdwname, false); - aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdw->fdwid, ownerId, ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname); @@ -1082,7 +1082,7 @@ user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername) { AclResult aclresult; - aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, curuserid, ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, servername); } @@ -1433,7 +1433,7 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid) * get the actual FDW for option validation etc. */ server = GetForeignServerByName(stmt->servername, false); - aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE); + aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, ownerId, ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername); @@ -1492,7 +1492,7 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt) /* Check that the foreign server exists and that we have USAGE on it */ server = GetForeignServerByName(stmt->server_name, false); - aclresult = pg_foreign_server_aclcheck(server->serverid, GetUserId(), ACL_USAGE); + aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername); diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index e6fcfc23b931..e006033bd845 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1111,7 +1111,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) if (languageStruct->lanpltrusted) { /* if trusted language, need USAGE privilege */ - aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE); + aclresult = object_aclcheck(LanguageRelationId, languageOid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_LANGUAGE, NameStr(languageStruct->lanname)); @@ -1844,7 +1844,7 @@ CreateTransform(CreateTransformStmt *stmt) */ langid = get_language_oid(stmt->lang, false); - aclresult = pg_language_aclcheck(langid, GetUserId(), ACL_USAGE); + aclresult = object_aclcheck(LanguageRelationId, langid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_LANGUAGE, stmt->lang); @@ -2110,7 +2110,7 @@ ExecuteDoStmt(ParseState *pstate, DoStmt *stmt, bool atomic) /* if trusted language, need USAGE privilege */ AclResult aclresult; - aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(), + aclresult = object_aclcheck(LanguageRelationId, codeblock->langOid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_LANGUAGE, diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 4fac402e5b64..01862e26a916 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -23,7 +23,11 @@ #include "catalog/pg_authid.h" #include "catalog/pg_class.h" #include "catalog/pg_database.h" +#include "catalog/pg_foreign_data_wrapper.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/pg_language.h" #include "catalog/pg_parameter_acl.h" +#include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" #include "commands/proclang.h" @@ -3099,7 +3103,7 @@ has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS) fdwid = convert_foreign_data_wrapper_name(fdwname); mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3124,7 +3128,7 @@ has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS) fdwid = convert_foreign_data_wrapper_name(fdwname); mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3150,7 +3154,7 @@ has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) PG_RETURN_NULL(); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3176,7 +3180,7 @@ has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) PG_RETURN_NULL(); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3199,7 +3203,7 @@ has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS) fdwid = convert_foreign_data_wrapper_name(fdwname); mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3223,7 +3227,7 @@ has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) PG_RETURN_NULL(); - aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode); + aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3490,7 +3494,7 @@ has_language_privilege_name_name(PG_FUNCTION_ARGS) languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3515,7 +3519,7 @@ has_language_privilege_name(PG_FUNCTION_ARGS) languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3541,7 +3545,7 @@ has_language_privilege_name_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) PG_RETURN_NULL(); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3567,7 +3571,7 @@ has_language_privilege_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) PG_RETURN_NULL(); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3590,7 +3594,7 @@ has_language_privilege_id_name(PG_FUNCTION_ARGS) languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3614,7 +3618,7 @@ has_language_privilege_id_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) PG_RETURN_NULL(); - aclresult = pg_language_aclcheck(languageoid, roleid, mode); + aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3874,7 +3878,7 @@ has_server_privilege_name_name(PG_FUNCTION_ARGS) serverid = convert_server_name(servername); mode = convert_server_priv_string(priv_type_text); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3899,7 +3903,7 @@ has_server_privilege_name(PG_FUNCTION_ARGS) serverid = convert_server_name(servername); mode = convert_server_priv_string(priv_type_text); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3925,7 +3929,7 @@ has_server_privilege_name_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) PG_RETURN_NULL(); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3951,7 +3955,7 @@ has_server_privilege_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) PG_RETURN_NULL(); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3974,7 +3978,7 @@ has_server_privilege_id_name(PG_FUNCTION_ARGS) serverid = convert_server_name(servername); mode = convert_server_priv_string(priv_type_text); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3998,7 +4002,7 @@ has_server_privilege_id_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) PG_RETURN_NULL(); - aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode); + aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4065,7 +4069,7 @@ has_tablespace_privilege_name_name(PG_FUNCTION_ARGS) tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4090,7 +4094,7 @@ has_tablespace_privilege_name(PG_FUNCTION_ARGS) tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4116,7 +4120,7 @@ has_tablespace_privilege_name_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) PG_RETURN_NULL(); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4142,7 +4146,7 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) PG_RETURN_NULL(); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4165,7 +4169,7 @@ has_tablespace_privilege_id_name(PG_FUNCTION_ARGS) tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4189,7 +4193,7 @@ has_tablespace_privilege_id_id(PG_FUNCTION_ARGS) if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) PG_RETURN_NULL(); - aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); + aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index a9dd068095bf..b38bd1003ea0 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -2054,7 +2054,7 @@ CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid) langStruct->lanvalidator))); /* first validate that we have permissions to use the language */ - aclresult = pg_language_aclcheck(procStruct->prolang, GetUserId(), + aclresult = object_aclcheck(LanguageRelationId, procStruct->prolang, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_LANGUAGE, diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index bf461f24fde7..dac9993a0fbe 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -235,39 +235,18 @@ extern void ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivi extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid); -extern AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, - Oid roleid, AclMode mask, AclMaskHow how); -extern AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, - Oid roleid, AclMode mask, - AclMaskHow how, bool *is_missing); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how); -extern AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, - AclMode mask, AclMaskHow how, - bool *is_missing); -extern AclMode pg_database_aclmask(Oid db_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_parameter_aclmask(const char *name, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_proc_aclmask(Oid proc_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_language_aclmask(Oid lang_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, - AclMode mask, AclMaskHow how, Snapshot snapshot); -extern AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid, - AclMode mask, AclMaskHow how); -extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid, - AclMode mask, AclMaskHow how); +/* generic function */ +extern AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode); + +/* wrapper functions for commonly used cases */ +extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode); +extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode); +extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); + +/* special cases */ extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode); extern AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, @@ -278,19 +257,11 @@ extern AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode); extern AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing); -extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode); extern AclResult pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode); -extern AclResult pg_parameter_acl_aclcheck(Oid acl_oid, Oid roleid, - AclMode mode); -extern AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode); -extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode); extern AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot); extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode); -extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode); -extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode); -extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode); extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode); extern void aclcheck_error(AclResult aclerr, ObjectType objtype, -- 2.37.3