From: Alvaro Herrera Date: Thu, 1 Dec 2005 02:03:01 +0000 (+0000) Subject: Refactor some bits in aclchk.c in order to reduce code duplication. X-Git-Tag: REL9_0_0~8822 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=7415e083e4ae97b601912899ecfdc6ff9656d12b;p=pg-rex%2Fsyncrep.git Refactor some bits in aclchk.c in order to reduce code duplication. --- diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 690a24e3f3..643d31c199 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.122 2005/11/22 18:17:07 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.123 2005/12/01 02:03:00 alvherre Exp $ * * NOTES * See acl.h. @@ -42,28 +42,22 @@ #include "utils/syscache.h" -static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior); -static List *objectNamesToOids(GrantObjectType objtype, List *objnames); +static void ExecGrant_Relation(InternalGrant *grantStmt); +static void ExecGrant_Database(InternalGrant *grantStmt); +static void ExecGrant_Function(InternalGrant *grantStmt); +static void ExecGrant_Language(InternalGrant *grantStmt); +static void ExecGrant_Namespace(InternalGrant *grantStmt); +static void ExecGrant_Tablespace(InternalGrant *grantStmt); +static List *objectNamesToOids(GrantObjectType objtype, List *objnames); static AclMode string_to_privilege(const char *privname); static const char *privilege_to_string(AclMode privilege); +static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, + bool all_privs, AclMode privileges, + Oid objectId, Oid grantorId, + AclObjectKind objkind, char *objname); +static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how); #ifdef ACLDEBUG @@ -153,6 +147,91 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant, return new_acl; } +/* + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. + */ +static AclMode +restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, + AclMode privileges, Oid objectId, Oid grantorId, + AclObjectKind objkind, char *objname) +{ + AclMode this_privileges; + AclMode whole_mask; + + switch (objkind) + { + case ACL_KIND_CLASS: + whole_mask = ACL_ALL_RIGHTS_RELATION; + break; + case ACL_KIND_DATABASE: + whole_mask = ACL_ALL_RIGHTS_DATABASE; + break; + case ACL_KIND_PROC: + whole_mask = ACL_ALL_RIGHTS_FUNCTION; + break; + case ACL_KIND_LANGUAGE: + whole_mask = ACL_ALL_RIGHTS_LANGUAGE; + break; + case ACL_KIND_NAMESPACE: + whole_mask = ACL_ALL_RIGHTS_NAMESPACE; + break; + case ACL_KIND_TABLESPACE: + whole_mask = ACL_ALL_RIGHTS_TABLESPACE; + break; + default: + elog(ERROR, "unrecognized object kind: %d", objkind); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + } + + /* + * If we found no grant options, consider whether to issue a hard + * error. Per spec, having any privilege at all on the object will + * get you by here. + */ + if (avail_goptions == ACL_NO_RIGHTS) + { + if (pg_aclmask(objkind, objectId, grantorId, + whole_mask | ACL_GRANT_OPTION_FOR(whole_mask), + ACLMASK_ANY) == ACL_NO_RIGHTS) + aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname); + } + + /* + * Restrict the operation to what we can actually grant or revoke, and + * issue a warning if appropriate. (For REVOKE this isn't quite what + * the spec says to do: the spec seems to want a warning only if no + * privilege bits actually change in the ACL. In practice that + * behavior seems much too noisy, as well as inconsistent with the + * GRANT case.) + */ + this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); + if (is_grant) + { + if (this_privileges == 0) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("no privileges were granted"))); + else if (!all_privs && this_privileges != privileges) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), + errmsg("not all privileges were granted"))); + } + else + { + if (this_privileges == 0) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("no privileges could be revoked"))); + else if (!all_privs && this_privileges != privileges) + ereport(WARNING, + (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), + errmsg("not all privileges could be revoked"))); + } + + return this_privileges; +} /* * Called to execute the utility commands GRANT and REVOKE @@ -160,13 +239,24 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant, void ExecuteGrantStmt(GrantStmt *stmt) { - List *objects; - List *grantees = NIL; - AclMode privileges; + InternalGrant istmt; ListCell *cell; - bool all_privs; - AclMode all_privileges = (AclMode) 0; - char *errormsg = NULL; + char *errormsg; + AclMode all_privileges; + + /* + * Turn the regular GrantStmt into the InternalGrant form. + */ + istmt.is_grant = stmt->is_grant; + istmt.objtype = stmt->objtype; + istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects); + /* all_privs to be filled below */ + /* privileges to be filled below */ + istmt.grantees = NIL; + /* filled below */ + istmt.grant_option = stmt->grant_option; + istmt.behavior = stmt->behavior; + /* * Convert the PrivGrantee list into an Oid list. Note that at this point @@ -180,15 +270,15 @@ ExecuteGrantStmt(GrantStmt *stmt) PrivGrantee *grantee = (PrivGrantee *) lfirst(cell); if (grantee->rolname == NULL) - grantees = lappend_oid(grantees, ACL_ID_PUBLIC); + istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC); else - grantees = lappend_oid(grantees, - get_roleid_checked(grantee->rolname)); + istmt.grantees = + lappend_oid(istmt.grantees, + get_roleid_checked(grantee->rolname)); } /* - * Convert stmt->privileges, a textual list, into an AclMode bitmask - * appropiate for the given object class. + * Convert stmt->privileges, a textual list, into an AclMode bitmask. */ switch (stmt->objtype) { @@ -217,19 +307,26 @@ ExecuteGrantStmt(GrantStmt *stmt) errormsg = _("invalid privilege type %s for tablespace"); break; default: + /* keep compiler quiet */ + all_privileges = ACL_NO_RIGHTS; + errormsg = NULL; elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) stmt->objtype); } if (stmt->privileges == NIL) { - all_privs = true; - privileges = all_privileges; + istmt.all_privs = true; + /* + * will be turned into ACL_ALL_RIGHTS_* by the internal routines + * depending on the object type + */ + istmt.privileges = ACL_NO_RIGHTS; } else { - all_privs = false; - privileges = ACL_NO_RIGHTS; + istmt.all_privs = false; + istmt.privileges = ACL_NO_RIGHTS; foreach(cell, stmt->privileges) { char *privname = strVal(lfirst(cell)); @@ -241,61 +338,44 @@ ExecuteGrantStmt(GrantStmt *stmt) errmsg(errormsg, privilege_to_string(priv)))); - privileges |= priv; + istmt.privileges |= priv; } } - /* Turn the list of object names into an Oid list */ - objects = objectNamesToOids(stmt->objtype, stmt->objects); - - ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs, - privileges, grantees, stmt->grant_option, - stmt->behavior); + ExecGrantStmt_oids(&istmt); } /* * ExecGrantStmt_oids * - * "Internal" entrypoint for granting and revoking privileges. The arguments - * it receives are lists of Oids or have been otherwise converted from text - * format to internal format. + * "Internal" entrypoint for granting and revoking privileges. */ void -ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects, - bool all_privs, AclMode privileges, List *grantees, - bool grant_option, DropBehavior behavior) +ExecGrantStmt_oids(InternalGrant *istmt) { - switch (objtype) + switch (istmt->objtype) { case ACL_OBJECT_RELATION: - ExecGrant_Relation(is_grant, objects, all_privs, privileges, - grantees, grant_option, behavior); + ExecGrant_Relation(istmt); break; case ACL_OBJECT_DATABASE: - ExecGrant_Database(is_grant, objects, all_privs, privileges, - grantees, grant_option, behavior); + ExecGrant_Database(istmt); break; case ACL_OBJECT_FUNCTION: - ExecGrant_Function(is_grant, objects, all_privs, privileges, - grantees, grant_option, behavior); + ExecGrant_Function(istmt); break; case ACL_OBJECT_LANGUAGE: - ExecGrant_Language(is_grant, objects, all_privs, privileges, - grantees, grant_option, behavior); + ExecGrant_Language(istmt); break; case ACL_OBJECT_NAMESPACE: - ExecGrant_Namespace(is_grant, objects, all_privs, - privileges, grantees, grant_option, - behavior); + ExecGrant_Namespace(istmt); break; case ACL_OBJECT_TABLESPACE: - ExecGrant_Tablespace(is_grant, objects, all_privs, - privileges, grantees, grant_option, - behavior); + ExecGrant_Tablespace(istmt); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", - (int) objtype); + (int) istmt->objtype); } } @@ -444,19 +524,17 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) } static void -ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Relation(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_RELATION; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_RELATION; relation = heap_open(RelationRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { Oid relOid = lfirst_oid(cell); Datum aclDatum; @@ -512,56 +590,19 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_class_aclmask(relOid, - grantorId, - ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, - NameStr(pg_class_tuple->relname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) - */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + relOid, grantorId, ACL_KIND_CLASS, + NameStr(pg_class_tuple->relname)); /* * Generate new ACL. @@ -571,9 +612,9 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -595,7 +636,7 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -611,19 +652,17 @@ ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, } static void -ExecGrant_Database(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Database(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_DATABASE; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_DATABASE; relation = heap_open(DatabaseRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { Oid datId = lfirst_oid(cell); Form_pg_database pg_database_tuple; @@ -675,56 +714,19 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. - */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_database_aclmask(HeapTupleGetOid(tuple), - grantorId, - ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE, - NameStr(pg_database_tuple->datname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + datId, grantorId, ACL_KIND_DATABASE, + NameStr(pg_database_tuple->datname)); /* * Generate new ACL. @@ -734,9 +736,9 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -759,7 +761,7 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -775,19 +777,17 @@ ExecGrant_Database(bool is_grant, List *objects, bool all_privs, } static void -ExecGrant_Function(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Function(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_FUNCTION; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_FUNCTION; relation = heap_open(ProcedureRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { Oid funcId = lfirst_oid(cell); Form_pg_proc pg_proc_tuple; @@ -830,56 +830,19 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_proc_aclmask(funcId, - grantorId, - ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC, - NameStr(pg_proc_tuple->proname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) - */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + funcId, grantorId, ACL_KIND_PROC, + NameStr(pg_proc_tuple->proname)); /* * Generate new ACL. @@ -889,9 +852,9 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -914,7 +877,7 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(ProcedureRelationId, funcId, - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -930,21 +893,19 @@ ExecGrant_Function(bool is_grant, List *objects, bool all_privs, } static void -ExecGrant_Language(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Language(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_LANGUAGE; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE; relation = heap_open(LanguageRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { - Oid langid = lfirst_oid(cell); + Oid langId = lfirst_oid(cell); Form_pg_language pg_language_tuple; Datum aclDatum; bool isNull; @@ -965,10 +926,10 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs, Oid *newmembers; tuple = SearchSysCache(LANGOID, - ObjectIdGetDatum(langid), + ObjectIdGetDatum(langId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for language %u", langid); + elog(ERROR, "cache lookup failed for language %u", langId); pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); @@ -995,56 +956,19 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_language_aclmask(HeapTupleGetOid(tuple), - grantorId, - ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE, - NameStr(pg_language_tuple->lanname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) - */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + langId, grantorId, ACL_KIND_LANGUAGE, + NameStr(pg_language_tuple->lanname)); /* * Generate new ACL. @@ -1054,9 +978,9 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -1079,7 +1003,7 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -1095,19 +1019,17 @@ ExecGrant_Language(bool is_grant, List *objects, bool all_privs, } static void -ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Namespace(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_NAMESPACE; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE; relation = heap_open(NamespaceRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { Oid nspid = lfirst_oid(cell); Form_pg_namespace pg_namespace_tuple; @@ -1151,56 +1073,19 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. - */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_namespace_aclmask(HeapTupleGetOid(tuple), - grantorId, - ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE, - NameStr(pg_namespace_tuple->nspname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + nspid, grantorId, ACL_KIND_NAMESPACE, + NameStr(pg_namespace_tuple->nspname)); /* * Generate new ACL. @@ -1210,9 +1095,9 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -1235,7 +1120,7 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -1251,19 +1136,17 @@ ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, } static void -ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, - AclMode privileges, List *grantees, bool grant_option, - DropBehavior behavior) +ExecGrant_Tablespace(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (all_privs && privileges == ACL_NO_RIGHTS) - privileges = ACL_ALL_RIGHTS_TABLESPACE; + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE; relation = heap_open(TableSpaceRelationId, RowExclusiveLock); - foreach(cell, objects) + foreach(cell, istmt->objects) { Oid tblId = lfirst_oid(cell); Form_pg_tablespace pg_tablespace_tuple; @@ -1313,56 +1196,19 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), privileges, + select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* - * If we found no grant options, consider whether to issue a hard - * error. Per spec, having any privilege at all on the object will - * get you by here. + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. */ - if (avail_goptions == ACL_NO_RIGHTS) - { - if (pg_tablespace_aclmask(HeapTupleGetOid(tuple), - grantorId, - ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE), - ACLMASK_ANY) == ACL_NO_RIGHTS) - aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, - NameStr(pg_tablespace_tuple->spcname)); - } - - /* - * Restrict the operation to what we can actually grant or revoke, and - * issue a warning if appropriate. (For REVOKE this isn't quite what - * the spec says to do: the spec seems to want a warning only if no - * privilege bits actually change in the ACL. In practice that - * behavior seems much too noisy, as well as inconsistent with the - * GRANT case.) - */ - this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions); - if (is_grant) - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); - } - else - { - if (this_privileges == 0) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); - else if (!all_privs && this_privileges != privileges) - ereport(WARNING, - (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); - } + this_privileges = + restrict_and_check_grant(istmt->is_grant, avail_goptions, + istmt->all_privs, istmt->privileges, + tblId, grantorId, ACL_KIND_TABLESPACE, + NameStr(pg_tablespace_tuple->spcname)); /* * Generate new ACL. @@ -1372,9 +1218,9 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, */ noldmembers = aclmembers(old_acl, &oldmembers); - new_acl = merge_acl_with_grant(old_acl, is_grant, - grant_option, behavior, - grantees, this_privileges, + new_acl = merge_acl_with_grant(old_acl, istmt->is_grant, + istmt->grant_option, istmt->behavior, + istmt->grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); @@ -1397,7 +1243,7 @@ ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, /* Update the shared dependency ACL info */ updateAclDependencies(TableSpaceRelationId, tblId, - ownerId, is_grant, + ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); @@ -1583,6 +1429,34 @@ has_rolcatupdate(Oid roleid) return rolcatupdate; } +/* + * Relay for the various pg_*_mask routines depending on object kind + */ +static AclMode +pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid, + AclMode mask, AclMaskHow how) +{ + switch (objkind) + { + case ACL_KIND_CLASS: + return pg_class_aclmask(table_oid, roleid, mask, how); + case ACL_KIND_DATABASE: + return pg_database_aclmask(table_oid, roleid, mask, how); + case ACL_KIND_PROC: + return pg_proc_aclmask(table_oid, roleid, mask, how); + case ACL_KIND_LANGUAGE: + return pg_language_aclmask(table_oid, roleid, mask, how); + case ACL_KIND_NAMESPACE: + return pg_namespace_aclmask(table_oid, roleid, mask, how); + case ACL_KIND_TABLESPACE: + return pg_tablespace_aclmask(table_oid, roleid, mask, how); + default: + elog(ERROR, "unrecognized objkind: %d", + (int) objkind); + /* not reached, but keep compiler quiet */ + return ACL_NO_RIGHTS; + } +} /* * Exported routine for examining a user's privileges for a table diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 703f613916..faa64c22fc 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.5 2005/11/22 18:17:08 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.6 2005/12/01 02:03:00 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -1122,6 +1122,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior) { ObjectAddress obj; GrantObjectType objtype; + InternalGrant istmt; /* Shouldn't happen */ case SHARED_DEPENDENCY_PIN: @@ -1132,22 +1133,22 @@ shdepDropOwned(List *roleids, DropBehavior behavior) switch (sdepForm->classid) { case RelationRelationId: - objtype = ACL_OBJECT_RELATION; + istmt.objtype = ACL_OBJECT_RELATION; break; case DatabaseRelationId: - objtype = ACL_OBJECT_DATABASE; + istmt.objtype = ACL_OBJECT_DATABASE; break; case ProcedureRelationId: - objtype = ACL_OBJECT_FUNCTION; + istmt.objtype = ACL_OBJECT_FUNCTION; break; case LanguageRelationId: - objtype = ACL_OBJECT_LANGUAGE; + istmt.objtype = ACL_OBJECT_LANGUAGE; break; case NamespaceRelationId: - objtype = ACL_OBJECT_NAMESPACE; + istmt.objtype = ACL_OBJECT_NAMESPACE; break; case TableSpaceRelationId: - objtype = ACL_OBJECT_TABLESPACE; + istmt.objtype = ACL_OBJECT_TABLESPACE; break; default: elog(ERROR, "unexpected object type %d", @@ -1156,11 +1157,15 @@ shdepDropOwned(List *roleids, DropBehavior behavior) objtype = (GrantObjectType) 0; break; } - - ExecGrantStmt_oids(false, objtype, - list_make1_oid(sdepForm->objid), true, - ACL_NO_RIGHTS, list_make1_oid(roleid), - false, DROP_CASCADE); + istmt.is_grant = false; + istmt.objects = list_make1_oid(sdepForm->objid); + istmt.all_privs = true; + istmt.privileges = ACL_NO_RIGHTS; + istmt.grantees = list_make1_oid(roleid); + istmt.grant_option = false; + istmt.behavior = DROP_CASCADE; + + ExecGrantStmt_oids(&istmt); break; case SHARED_DEPENDENCY_OWNER: diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 04c5631214..8e6cb95d25 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.90 2005/11/22 18:17:31 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.91 2005/12/01 02:03:01 alvherre Exp $ * * NOTES * An ACL array is simply an array of AclItems, representing the union @@ -182,6 +182,26 @@ typedef enum AclObjectKind } AclObjectKind; /* + * The information about one Grant/Revoke statement, in internal format: object + * and grantees names have been turned into Oids, the privilege list is an + * AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and + * all_privs is true, it will be internally turned into the right kind of + * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the + * InternalGrant struct!) + */ +typedef struct +{ + bool is_grant; + GrantObjectType objtype; + List *objects; + bool all_privs; + AclMode privileges; + List *grantees; + bool grant_option; + DropBehavior behavior; +} InternalGrant; + +/* * routines used internally */ extern Acl *acldefault(GrantObjectType objtype, Oid ownerId); @@ -221,9 +241,7 @@ extern Datum hash_aclitem(PG_FUNCTION_ARGS); * prototypes for functions in aclchk.c */ extern void ExecuteGrantStmt(GrantStmt *stmt); -extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, - List *objects, bool all_privs, AclMode privileges, - List *grantees, bool grant_option, DropBehavior behavior); +extern void ExecGrantStmt_oids(InternalGrant *istmt); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how);