*
*
* 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.
#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
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
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
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)
{
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));
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);
}
}
}
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;
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(RelationRelationId, relOid,
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
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;
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
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;
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(ProcedureRelationId, funcId,
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
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;
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);
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
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;
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
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;
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.
*/
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);
/* Update the shared dependency ACL info */
updateAclDependencies(TableSpaceRelationId, tblId,
- ownerId, is_grant,
+ ownerId, istmt->is_grant,
noldmembers, oldmembers,
nnewmembers, newmembers);
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