Index: src/backend/catalog/aclchk.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v retrieving revision 1.121 diff -c -r1.121 aclchk.c *** src/backend/catalog/aclchk.c 21 Nov 2005 12:49:30 -0000 1.121 --- src/backend/catalog/aclchk.c 21 Nov 2005 15:05:19 -0000 *************** *** 42,69 **** #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 AclMode string_to_privilege(const char *privname); static const char *privilege_to_string(AclMode privilege); #ifdef ACLDEBUG --- 42,62 ---- #include "utils/syscache.h" ! 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, + AclMode whole_mask, + AclObjectKind objkind, char *objname); #ifdef ACLDEBUG *************** *** 160,172 **** void ExecuteGrantStmt(GrantStmt *stmt) { ! List *objects; ! List *grantees = NIL; ! AclMode privileges; ListCell *cell; ! bool all_privs; ! AclMode all_privileges = (AclMode) 0; ! char *errormsg = NULL; /* * Convert the PrivGrantee list into an Oid list. Note that at this point --- 153,174 ---- void ExecuteGrantStmt(GrantStmt *stmt) { ! InternalGrant istmt; ListCell *cell; ! 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 */ ! /* grantees to be 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,194 **** PrivGrantee *grantee = (PrivGrantee *) lfirst(cell); if (grantee->rolname == NULL) ! grantees = lappend_oid(grantees, ACL_ID_PUBLIC); else ! grantees = lappend_oid(grantees, ! get_roleid_checked(grantee->rolname)); } /* ! * Convert stmt->privileges, a textual list, into an AclMode bitmask ! * appropiate for the given object class. */ switch (stmt->objtype) { --- 182,196 ---- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell); if (grantee->rolname == NULL) ! istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC); else ! istmt.grantees = ! lappend_oid(istmt.grantees, ! get_roleid_checked(grantee->rolname)); } /* ! * Convert stmt->privileges, a textual list, into an AclMode bitmask. */ switch (stmt->objtype) { *************** *** 217,235 **** errormsg = _("invalid privilege type %s for tablespace"); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) stmt->objtype); } if (stmt->privileges == NIL) { ! all_privs = true; ! privileges = all_privileges; } else { ! all_privs = false; ! privileges = ACL_NO_RIGHTS; foreach(cell, stmt->privileges) { char *privname = strVal(lfirst(cell)); --- 219,244 ---- 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) { ! 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 { ! istmt.all_privs = false; ! istmt.privileges = ACL_NO_RIGHTS; foreach(cell, stmt->privileges) { char *privname = strVal(lfirst(cell)); *************** *** 241,301 **** errmsg(errormsg, privilege_to_string(priv)))); ! 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 * ! * "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. */ void ! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects, ! bool all_privs, AclMode privileges, List *grantees, ! bool grant_option, DropBehavior behavior) { ! switch (objtype) { case ACL_OBJECT_RELATION: ! ExecGrant_Relation(is_grant, objects, all_privs, privileges, ! grantees, grant_option, behavior); break; case ACL_OBJECT_DATABASE: ! ExecGrant_Database(is_grant, objects, all_privs, privileges, ! grantees, grant_option, behavior); break; case ACL_OBJECT_FUNCTION: ! ExecGrant_Function(is_grant, objects, all_privs, privileges, ! grantees, grant_option, behavior); break; case ACL_OBJECT_LANGUAGE: ! ExecGrant_Language(is_grant, objects, all_privs, privileges, ! grantees, grant_option, behavior); break; case ACL_OBJECT_NAMESPACE: ! ExecGrant_Namespace(is_grant, objects, all_privs, ! privileges, grantees, grant_option, ! behavior); break; case ACL_OBJECT_TABLESPACE: ! ExecGrant_Tablespace(is_grant, objects, all_privs, ! privileges, grantees, grant_option, ! behavior); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", ! (int) objtype); } } --- 250,293 ---- errmsg(errormsg, privilege_to_string(priv)))); ! istmt.privileges |= priv; } } ! ExecGrantStmt_oids(&istmt); } /* * ExecGrantStmt_oids * ! * "Internal" entrypoint for granting and revoking privileges. */ void ! ExecGrantStmt_oids(InternalGrant *istmt) { ! switch (istmt->objtype) { case ACL_OBJECT_RELATION: ! ExecGrant_Relation(istmt); break; case ACL_OBJECT_DATABASE: ! ExecGrant_Database(istmt); break; case ACL_OBJECT_FUNCTION: ! ExecGrant_Function(istmt); break; case ACL_OBJECT_LANGUAGE: ! ExecGrant_Language(istmt); break; case ACL_OBJECT_NAMESPACE: ! ExecGrant_Namespace(istmt); break; case ACL_OBJECT_TABLESPACE: ! ExecGrant_Tablespace(istmt); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", ! (int) istmt->objtype); } } *************** *** 443,462 **** return objects; } static void ! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_RELATION; relation = heap_open(RelationRelationId, RowExclusiveLock); ! foreach (cell, objects) { Oid relOid = lfirst_oid(cell); Datum aclDatum; --- 435,513 ---- return objects; } + /* + * 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, + AclMode whole_mask, AclObjectKind objkind, + char *objname) + { + AclMode this_privileges; + + /* + * 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_class_aclmask(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; + } + static void ! ExecGrant_Relation(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_RELATION; relation = heap_open(RelationRelationId, RowExclusiveLock); ! foreach (cell, istmt->objects) { Oid relOid = lfirst_oid(cell); Datum aclDatum; *************** *** 511,566 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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_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"))); ! } /* * Generate new ACL. --- 562,581 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! relOid, grantorId, ! ACL_ALL_RIGHTS_RELATION, ACL_KIND_CLASS, ! NameStr(pg_class_tuple->relname)); /* * Generate new ACL. *************** *** 570,578 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 585,593 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 594,600 **** /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 609,615 ---- /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); *************** *** 610,628 **** } static void ! ExecGrant_Database(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_DATABASE; relation = heap_open(DatabaseRelationId, RowExclusiveLock); ! foreach (cell, objects) { Oid datId = lfirst_oid(cell); Form_pg_database pg_database_tuple; --- 625,641 ---- } static void ! ExecGrant_Database(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_DATABASE; relation = heap_open(DatabaseRelationId, RowExclusiveLock); ! foreach (cell, istmt->objects) { Oid datId = lfirst_oid(cell); Form_pg_database pg_database_tuple; *************** *** 674,729 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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.) */ ! 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"))); ! } /* * Generate new ACL. --- 687,706 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! datId, grantorId, ACL_ALL_RIGHTS_DATABASE, ! ACL_KIND_DATABASE, ! NameStr(pg_database_tuple->datname)); /* * Generate new ACL. *************** *** 733,741 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 710,718 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 758,764 **** /* Update the shared dependency ACL info */ updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 735,741 ---- /* Update the shared dependency ACL info */ updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); *************** *** 774,792 **** } static void ! ExecGrant_Function(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_FUNCTION; relation = heap_open(ProcedureRelationId, RowExclusiveLock); ! foreach (cell, objects) { Oid funcId = lfirst_oid(cell); Form_pg_proc pg_proc_tuple; --- 751,767 ---- } static void ! ExecGrant_Function(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_FUNCTION; relation = heap_open(ProcedureRelationId, RowExclusiveLock); ! foreach (cell, istmt->objects) { Oid funcId = lfirst_oid(cell); Form_pg_proc pg_proc_tuple; *************** *** 829,884 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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_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"))); ! } /* * Generate new ACL. --- 804,824 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! funcId, grantorId, ! ACL_ALL_RIGHTS_FUNCTION, ! ACL_KIND_PROC, ! NameStr(pg_proc_tuple->proname)); /* * Generate new ACL. *************** *** 888,896 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 828,836 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 913,919 **** /* Update the shared dependency ACL info */ updateAclDependencies(ProcedureRelationId, funcId, ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 853,859 ---- /* Update the shared dependency ACL info */ updateAclDependencies(ProcedureRelationId, funcId, ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); *************** *** 929,949 **** } static void ! ExecGrant_Language(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_LANGUAGE; relation = heap_open(LanguageRelationId, RowExclusiveLock); ! foreach (cell, objects) { ! Oid langid = lfirst_oid(cell); Form_pg_language pg_language_tuple; Datum aclDatum; bool isNull; --- 869,887 ---- } static void ! ExecGrant_Language(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE; relation = heap_open(LanguageRelationId, RowExclusiveLock); ! foreach (cell, istmt->objects) { ! Oid langId = lfirst_oid(cell); Form_pg_language pg_language_tuple; Datum aclDatum; bool isNull; *************** *** 964,973 **** Oid *newmembers; tuple = SearchSysCache(LANGOID, ! ObjectIdGetDatum(langid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for language %u", langid); pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); --- 902,911 ---- Oid *newmembers; tuple = SearchSysCache(LANGOID, ! ObjectIdGetDatum(langId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ! elog(ERROR, "cache lookup failed for language %u", langId); pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); *************** *** 994,1049 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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_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"))); ! } /* * Generate new ACL. --- 932,952 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! langId, grantorId, ! ACL_ALL_RIGHTS_LANGUAGE, ! ACL_KIND_LANGUAGE, ! NameStr(pg_language_tuple->lanname)); /* * Generate new ACL. *************** *** 1053,1061 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 956,964 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 1078,1084 **** /* Update the shared dependency ACL info */ updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 981,987 ---- /* Update the shared dependency ACL info */ updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); *************** *** 1094,1112 **** } static void ! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_NAMESPACE; relation = heap_open(NamespaceRelationId, RowExclusiveLock); ! foreach(cell, objects) { Oid nspid = lfirst_oid(cell); Form_pg_namespace pg_namespace_tuple; --- 997,1013 ---- } static void ! ExecGrant_Namespace(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE; relation = heap_open(NamespaceRelationId, RowExclusiveLock); ! foreach(cell, istmt->objects) { Oid nspid = lfirst_oid(cell); Form_pg_namespace pg_namespace_tuple; *************** *** 1150,1205 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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.) ! */ ! 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"))); ! } /* * Generate new ACL. --- 1051,1071 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! nspid, grantorId, ! ACL_ALL_RIGHTS_NAMESPACE, ! ACL_KIND_NAMESPACE, ! NameStr(pg_namespace_tuple->nspname)); /* * Generate new ACL. *************** *** 1209,1217 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 1075,1083 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 1234,1240 **** /* Update the shared dependency ACL info */ updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 1100,1106 ---- /* Update the shared dependency ACL info */ updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); *************** *** 1250,1268 **** } static void ! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs, ! AclMode privileges, List *grantees, bool grant_option, ! DropBehavior behavior) { Relation relation; ListCell *cell; ! if (all_privs && privileges == ACL_NO_RIGHTS) ! privileges = ACL_ALL_RIGHTS_TABLESPACE; relation = heap_open(TableSpaceRelationId, RowExclusiveLock); ! foreach(cell, objects) { Oid tblId = lfirst_oid(cell); Form_pg_tablespace pg_tablespace_tuple; --- 1116,1132 ---- } static void ! ExecGrant_Tablespace(InternalGrant *istmt) { Relation relation; ListCell *cell; ! if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) ! istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE; relation = heap_open(TableSpaceRelationId, RowExclusiveLock); ! foreach(cell, istmt->objects) { Oid tblId = lfirst_oid(cell); Form_pg_tablespace pg_tablespace_tuple; *************** *** 1312,1367 **** old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), 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_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"))); ! } /* * Generate new ACL. --- 1176,1196 ---- old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ ! select_best_grantor(GetUserId(), istmt->privileges, old_acl, ownerId, &grantorId, &avail_goptions); /* ! * Restrict the privileges to what we can actually grant, and emit ! * the standards-mandated warning and error messages. */ ! this_privileges = ! restrict_and_check_grant(istmt->is_grant, avail_goptions, ! istmt->all_privs, istmt->privileges, ! tblId, grantorId, ! ACL_ALL_RIGHTS_TABLESPACE, ! ACL_KIND_TABLESPACE, ! NameStr(pg_tablespace_tuple->spcname)); /* * Generate new ACL. *************** *** 1371,1379 **** */ noldmembers = aclmembers(old_acl, &oldmembers); ! new_acl = merge_acl_with_grant(old_acl, is_grant, ! grant_option, behavior, ! grantees, this_privileges, grantorId, ownerId); nnewmembers = aclmembers(new_acl, &newmembers); --- 1200,1208 ---- */ noldmembers = aclmembers(old_acl, &oldmembers); ! 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); *************** *** 1396,1402 **** /* Update the shared dependency ACL info */ updateAclDependencies(TableSpaceRelationId, tblId, ! ownerId, is_grant, noldmembers, oldmembers, nnewmembers, newmembers); --- 1225,1231 ---- /* Update the shared dependency ACL info */ updateAclDependencies(TableSpaceRelationId, tblId, ! ownerId, istmt->is_grant, noldmembers, oldmembers, nnewmembers, newmembers); Index: src/backend/catalog/pg_shdepend.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v retrieving revision 1.4 diff -c -r1.4 pg_shdepend.c *** src/backend/catalog/pg_shdepend.c 21 Nov 2005 12:49:30 -0000 1.4 --- src/backend/catalog/pg_shdepend.c 21 Nov 2005 15:08:16 -0000 *************** *** 1122,1127 **** --- 1122,1128 ---- { ObjectAddress obj; GrantObjectType objtype; + InternalGrant istmt; /* Shouldn't happen */ case SHARED_DEPENDENCY_PIN: *************** *** 1132,1153 **** switch (sdepForm->classid) { case RelationRelationId: ! objtype = ACL_OBJECT_RELATION; break; case DatabaseRelationId: ! objtype = ACL_OBJECT_DATABASE; break; case ProcedureRelationId: ! objtype = ACL_OBJECT_FUNCTION; break; case LanguageRelationId: ! objtype = ACL_OBJECT_LANGUAGE; break; case NamespaceRelationId: ! objtype = ACL_OBJECT_NAMESPACE; break; case TableSpaceRelationId: ! objtype = ACL_OBJECT_TABLESPACE; break; default: elog(ERROR, "unexpected object type %d", --- 1133,1154 ---- switch (sdepForm->classid) { case RelationRelationId: ! istmt.objtype = ACL_OBJECT_RELATION; break; case DatabaseRelationId: ! istmt.objtype = ACL_OBJECT_DATABASE; break; case ProcedureRelationId: ! istmt.objtype = ACL_OBJECT_FUNCTION; break; case LanguageRelationId: ! istmt.objtype = ACL_OBJECT_LANGUAGE; break; case NamespaceRelationId: ! istmt.objtype = ACL_OBJECT_NAMESPACE; break; case TableSpaceRelationId: ! istmt.objtype = ACL_OBJECT_TABLESPACE; break; default: elog(ERROR, "unexpected object type %d", *************** *** 1156,1166 **** objtype = (GrantObjectType) 0; break; } ! ExecGrantStmt_oids(false, objtype, ! list_make1_oid(sdepForm->objid), true, ! ACL_NO_RIGHTS, list_make1_oid(roleid), ! false, DROP_CASCADE); break; case SHARED_DEPENDENCY_OWNER: /* --- 1157,1171 ---- objtype = (GrantObjectType) 0; break; } + 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: /* Index: src/include/utils/acl.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v retrieving revision 1.89 diff -c -r1.89 acl.h *** src/include/utils/acl.h 21 Nov 2005 12:49:33 -0000 1.89 --- src/include/utils/acl.h 21 Nov 2005 14:32:59 -0000 *************** *** 182,187 **** --- 182,207 ---- } 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,229 **** * 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 AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how); --- 241,247 ---- * prototypes for functions in aclchk.c */ extern void ExecuteGrantStmt(GrantStmt *stmt); ! extern void ExecGrantStmt_oids(InternalGrant *istmt); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how);