diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index d1f5dcd8bed..3ce6c09b44d 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -13,6 +13,27 @@ * NOTES * See acl.h. * + * The xxx_aclmask() functions in this file are wrappers around + * acl.c's aclmask() function; see that for basic usage information. + * The wrapper functions add object-type-specific lookup capability. + * Generally, they will throw error if the object doesn't exist. + * + * The xxx_aclmask_ext() functions add the ability to not throw + * error if the object doesn't exist. If their "is_missing" argument + * isn't NULL, then when the object isn't found they will set + * *is_missing = true and return zero (no privileges) instead of + * throwing an error. Caller must initialize *is_missing = false. + * + * The xxx_aclcheck() functions are simplified wrappers around the + * corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK + * if any of the privileges specified in "mode" are held, and otherwise + * a suitable error code (in practice, always ACLCHECK_NO_PRIV). + * Again, they will throw error if the object doesn't exist. + * + * The xxx_aclcheck_ext() functions add the ability to not throw + * error if the object doesn't exist. Their "is_missing" argument + * works similarly to the xxx_aclmask_ext() functions. + * *------------------------------------------------------------------------- */ #include "postgres.h" @@ -139,6 +160,9 @@ 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 object_aclmask_ext(Oid classid, Oid objectid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing); 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, @@ -151,10 +175,12 @@ 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 AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing); +static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing); static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl); static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, @@ -3064,6 +3090,18 @@ pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how) +{ + return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL); +} + +/* + * Generic routine for examining a user's privileges for an object, + * with is_missing + */ +static AclMode +object_aclmask_ext(Oid classid, Oid objectid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing) { int cacheid; AclMode result; @@ -3077,9 +3115,11 @@ object_aclmask(Oid classid, Oid objectid, Oid roleid, switch (classid) { case NamespaceRelationId: - return pg_namespace_aclmask(objectid, roleid, mask, how); + return pg_namespace_aclmask_ext(objectid, roleid, mask, how, + is_missing); case TypeRelationId: - return pg_type_aclmask(objectid, roleid, mask, how); + return pg_type_aclmask_ext(objectid, roleid, mask, how, + is_missing); } /* Even more special cases */ @@ -3092,16 +3132,26 @@ object_aclmask(Oid classid, Oid objectid, Oid roleid, return mask; /* - * Get the objects's ACL from its catalog + * Get the object's ACL from its catalog */ cacheid = get_object_catcache_oid(classid); tuple = SearchSysCache1(cacheid, 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))); + { + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("%s with OID %u does not exist", + get_object_class_descr(classid), objectid))); + } ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid, tuple, @@ -3149,10 +3199,7 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, } /* - * 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. + * Routine for examining a user's privileges for a column, with is_missing */ static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, @@ -3226,15 +3273,24 @@ pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, * Must get the relation's ownerId from pg_class. Since we already found * a pg_attribute entry, the only likely reason for this to fail is that a * concurrent DROP of the relation committed since then (which could only - * happen if we don't have lock on the relation). We prefer to report "no - * privileges" rather than failing in such a case, so as to avoid unwanted - * failures in has_column_privilege() tests. + * happen if we don't have lock on the relation). Treat that similarly to + * not finding the attribute entry. */ classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); if (!HeapTupleIsValid(classTuple)) { ReleaseSysCache(attTuple); - return 0; + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation with OID %u does not exist", + table_oid))); } classForm = (Form_pg_class) GETSTRUCT(classTuple); @@ -3267,10 +3323,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid, } /* - * 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. + * Routine for examining a user's privileges for a table, with is_missing */ static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, @@ -3585,11 +3638,12 @@ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, } /* - * Routine for examining a user's privileges for a namespace + * Routine for examining a user's privileges for a namespace, with is_missing */ static AclMode -pg_namespace_aclmask(Oid nsp_oid, Oid roleid, - AclMode mask, AclMaskHow how) +pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, + AclMode mask, AclMaskHow how, + bool *is_missing) { AclMode result; HeapTuple tuple; @@ -3623,8 +3677,8 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid, */ if (isTempNamespace(nsp_oid)) { - if (object_aclcheck(DatabaseRelationId, MyDatabaseId, roleid, - ACL_CREATE_TEMP) == ACLCHECK_OK) + if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid, + ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK) return mask & ACL_ALL_RIGHTS_SCHEMA; else return mask & ACL_USAGE; @@ -3635,9 +3689,18 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid, */ tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid)); if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_SCHEMA), - errmsg("schema with OID %u does not exist", nsp_oid))); + { + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema with OID %u does not exist", nsp_oid))); + } ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner; @@ -3677,20 +3740,20 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid, } /* - * Routine for examining a user's privileges for a type. + * Routine for examining a user's privileges for a type, with is_missing */ static AclMode -pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) +pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, + bool *is_missing) { AclMode result; HeapTuple tuple; + Form_pg_type typeForm; Datum aclDatum; bool isNull; Acl *acl; Oid ownerId; - Form_pg_type typeForm; - /* Bypass permission checks for superusers */ if (superuser_arg(roleid)) return mask; @@ -3700,10 +3763,19 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) */ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); if (!HeapTupleIsValid(tuple)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("type with OID %u does not exist", - type_oid))); + { + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type with OID %u does not exist", + type_oid))); + } typeForm = (Form_pg_type) GETSTRUCT(tuple); /* @@ -3717,9 +3789,20 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) ReleaseSysCache(tuple); tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid)); - /* this case is not a user-facing error, so elog not ereport */ if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for type %u", elttype_oid); + { + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return 0; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("type with OID %u does not exist", + elttype_oid))); + } typeForm = (Form_pg_type) GETSTRUCT(tuple); } @@ -3759,7 +3842,20 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how) AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode) { - if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0) + return object_aclcheck_ext(classid, objectid, roleid, mode, NULL); +} + +/* + * Exported generic routine for checking a user's access privileges to an + * object, with is_missing + */ +AclResult +object_aclcheck_ext(Oid classid, Oid objectid, + Oid roleid, AclMode mode, + bool *is_missing) +{ + if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY, + is_missing) != 0) return ACLCHECK_OK; else return ACLCHECK_NO_PRIV; @@ -3784,10 +3880,8 @@ pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, /* - * Exported routine for checking a user's access privileges to a column - * - * Does the bulk of the work for pg_attribute_aclcheck(), and allows other - * callers to avoid the missing attribute ERROR when is_missing is non-NULL. + * Exported routine for checking a user's access privileges to a column, + * with is_missing */ AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, @@ -3822,23 +3916,47 @@ pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how) +{ + return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL); +} + +/* + * Exported routine for checking a user's access privileges to any/all columns, + * with is_missing + */ +AclResult +pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, + AclMode mode, AclMaskHow how, + bool *is_missing) { AclResult result; HeapTuple classTuple; Form_pg_class classForm; + Oid ownerId; AttrNumber nattrs; AttrNumber curr_att; /* - * Must fetch pg_class row to check number of attributes. As in - * pg_attribute_aclmask, we prefer to return "no privileges" instead of - * throwing an error if we get any unexpected lookup errors. + * Must fetch pg_class row to get owner ID and number of attributes. */ classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid)); if (!HeapTupleIsValid(classTuple)) - return ACLCHECK_NO_PRIV; + { + if (is_missing != NULL) + { + /* return "no privileges" instead of throwing an error */ + *is_missing = true; + return ACLCHECK_NO_PRIV; + } + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation with OID %u does not exist", + table_oid))); + } classForm = (Form_pg_class) GETSTRUCT(classTuple); + ownerId = classForm->relowner; nattrs = classForm->relnatts; ReleaseSysCache(classTuple); @@ -3852,11 +3970,20 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, for (curr_att = 1; curr_att <= nattrs; curr_att++) { HeapTuple attTuple; + Datum aclDatum; + bool isNull; + Acl *acl; AclMode attmask; attTuple = SearchSysCache2(ATTNUM, ObjectIdGetDatum(table_oid), Int16GetDatum(curr_att)); + + /* + * Lookup failure probably indicates that the table was just dropped, + * but we'll treat it the same as a dropped column rather than + * throwing error. + */ if (!HeapTupleIsValid(attTuple)) continue; @@ -3867,16 +3994,27 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, continue; } + aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl, + &isNull); + /* * Here we hard-wire knowledge that the default ACL for a column * grants no privileges, so that we can fall out quickly in the very * common case where attacl is null. */ - if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL)) + if (isNull) attmask = 0; else - attmask = pg_attribute_aclmask(table_oid, curr_att, roleid, - mode, ACLMASK_ANY); + { + /* detoast column's ACL if necessary */ + acl = DatumGetAclP(aclDatum); + + attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY); + + /* if we have a detoasted copy, free it */ + if ((Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + } ReleaseSysCache(attTuple); @@ -3911,10 +4049,8 @@ pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode) } /* - * Exported routine for checking a user's access privileges to a table - * - * Does the bulk of the work for pg_class_aclcheck(), and allows other - * callers to avoid the missing relation ERROR when is_missing is non-NULL. + * Exported routine for checking a user's access privileges to a table, + * with is_missing */ AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 27eabb80abc..fe435108039 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -1915,14 +1915,15 @@ has_table_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_table_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1941,14 +1942,15 @@ has_table_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_table_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1989,13 +1991,14 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_table_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2134,6 +2137,7 @@ has_sequence_privilege_name_id(PG_FUNCTION_ARGS) AclMode mode; AclResult aclresult; char relkind; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_sequence_priv_string(priv_type_text); @@ -2146,7 +2150,10 @@ has_sequence_privilege_name_id(PG_FUNCTION_ARGS) errmsg("\"%s\" is not a sequence", get_rel_name(sequenceoid)))); - aclresult = pg_class_aclcheck(sequenceoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing); + + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2166,6 +2173,7 @@ has_sequence_privilege_id(PG_FUNCTION_ARGS) AclMode mode; AclResult aclresult; char relkind; + bool is_missing = false; roleid = GetUserId(); mode = convert_sequence_priv_string(priv_type_text); @@ -2178,7 +2186,10 @@ has_sequence_privilege_id(PG_FUNCTION_ARGS) errmsg("\"%s\" is not a sequence", get_rel_name(sequenceoid)))); - aclresult = pg_class_aclcheck(sequenceoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing); + + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2225,6 +2236,7 @@ has_sequence_privilege_id_id(PG_FUNCTION_ARGS) AclMode mode; AclResult aclresult; char relkind; + bool is_missing = false; mode = convert_sequence_priv_string(priv_type_text); relkind = get_rel_relkind(sequenceoid); @@ -2236,7 +2248,10 @@ has_sequence_privilege_id_id(PG_FUNCTION_ARGS) errmsg("\"%s\" is not a sequence", get_rel_name(sequenceoid)))); - aclresult = pg_class_aclcheck(sequenceoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing); + + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2345,18 +2360,22 @@ has_any_column_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_column_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); - /* First check at table level, then examine each column if needed */ - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); if (aclresult != ACLCHECK_OK) - aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode, - ACLMASK_ANY); + { + if (is_missing) + PG_RETURN_NULL(); + aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode, + ACLMASK_ANY, &is_missing); + if (is_missing) + PG_RETURN_NULL(); + } PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2375,18 +2394,22 @@ has_any_column_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_column_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); - /* First check at table level, then examine each column if needed */ - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); if (aclresult != ACLCHECK_OK) - aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode, - ACLMASK_ANY); + { + if (is_missing) + PG_RETURN_NULL(); + aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode, + ACLMASK_ANY, &is_missing); + if (is_missing) + PG_RETURN_NULL(); + } PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2431,17 +2454,21 @@ has_any_column_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_column_priv_string(priv_type_text); - if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid))) - PG_RETURN_NULL(); - /* First check at table level, then examine each column if needed */ - aclresult = pg_class_aclcheck(tableoid, roleid, mode); + aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing); if (aclresult != ACLCHECK_OK) - aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode, - ACLMASK_ANY); + { + if (is_missing) + PG_RETURN_NULL(); + aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode, + ACLMASK_ANY, &is_missing); + if (is_missing) + PG_RETURN_NULL(); + } PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2981,14 +3008,17 @@ has_database_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_database_priv_string(priv_type_text); - if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3007,14 +3037,17 @@ has_database_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_database_priv_string(priv_type_text); - if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3055,13 +3088,16 @@ has_database_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_database_priv_string(priv_type_text); - if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3178,14 +3214,17 @@ has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3204,14 +3243,17 @@ has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3252,13 +3294,16 @@ has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_foreign_data_wrapper_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3369,14 +3414,17 @@ has_function_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_function_priv_string(priv_type_text); - if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3395,14 +3443,17 @@ has_function_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_function_priv_string(priv_type_text); - if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3443,13 +3494,16 @@ has_function_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_function_priv_string(priv_type_text); - if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3569,14 +3623,17 @@ has_language_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_language_priv_string(priv_type_text); - if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(LanguageRelationId, languageoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3595,14 +3652,17 @@ has_language_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_language_priv_string(priv_type_text); - if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(LanguageRelationId, languageoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3643,13 +3703,16 @@ has_language_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_language_priv_string(priv_type_text); - if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(LanguageRelationId, languageoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3760,14 +3823,17 @@ has_schema_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_schema_priv_string(priv_type_text); - if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3786,14 +3852,17 @@ has_schema_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_schema_priv_string(priv_type_text); - if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3834,13 +3903,16 @@ has_schema_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_schema_priv_string(priv_type_text); - if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3953,14 +4025,17 @@ has_server_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_server_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -3979,14 +4054,17 @@ has_server_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_server_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4027,13 +4105,16 @@ has_server_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_server_priv_string(priv_type_text); - if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4144,14 +4225,17 @@ has_tablespace_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_tablespace_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4170,14 +4254,17 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_tablespace_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4218,13 +4305,16 @@ has_tablespace_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_tablespace_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4334,14 +4424,17 @@ has_type_privilege_name_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = get_role_oid_or_public(NameStr(*username)); mode = convert_type_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TypeRelationId, typeoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4360,14 +4453,17 @@ has_type_privilege_id(PG_FUNCTION_ARGS) Oid roleid; AclMode mode; AclResult aclresult; + bool is_missing = false; roleid = GetUserId(); mode = convert_type_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TypeRelationId, typeoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -4408,13 +4504,16 @@ has_type_privilege_id_id(PG_FUNCTION_ARGS) text *priv_type_text = PG_GETARG_TEXT_PP(2); AclMode mode; AclResult aclresult; + bool is_missing = false; mode = convert_type_priv_string(priv_type_text); - if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid))) - PG_RETURN_NULL(); + aclresult = object_aclcheck_ext(TypeRelationId, typeoid, + roleid, mode, + &is_missing); - aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode); + if (is_missing) + PG_RETURN_NULL(); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index aba1afa971c..02bc4d08d6c 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -239,8 +239,12 @@ extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how); -/* generic function */ -extern AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode); +/* generic functions */ +extern AclResult object_aclcheck(Oid classid, Oid objectid, + Oid roleid, AclMode mode); +extern AclResult object_aclcheck_ext(Oid classid, Oid objectid, + Oid roleid, AclMode mode, + bool *is_missing); /* special cases */ extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, @@ -250,6 +254,9 @@ extern AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, bool *is_missing); extern AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how); +extern AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, + AclMode mode, AclMaskHow how, + bool *is_missing); 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);