diff options
Diffstat (limited to 'src/backend/catalog/aclchk.c')
| -rw-r--r-- | src/backend/catalog/aclchk.c | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 643d31c199..dbdf523dd5 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.123 2005/12/01 02:03:00 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.124 2006/01/21 02:16:18 momjian Exp $ * * NOTES * See acl.h. @@ -164,6 +164,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, case ACL_KIND_CLASS: whole_mask = ACL_ALL_RIGHTS_RELATION; break; + case ACL_KIND_SEQUENCE: + whole_mask = ACL_ALL_RIGHTS_SEQUENCE; + break; case ACL_KIND_DATABASE: whole_mask = ACL_ALL_RIGHTS_DATABASE; break; @@ -212,22 +215,22 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, if (this_privileges == 0) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); + errmsg("no privileges were granted for \"%s\"", objname))); else if (!all_privs && this_privileges != privileges) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); + errmsg("not all privileges were granted for \"%s\"", objname))); } else { if (this_privileges == 0) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); + errmsg("no privileges could be revoked for \"%s\"", objname))); else if (!all_privs && this_privileges != privileges) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); + errmsg("not all privileges could be revoked for \"%s\"", objname))); } return this_privileges; @@ -282,9 +285,18 @@ ExecuteGrantStmt(GrantStmt *stmt) */ switch (stmt->objtype) { + /* + * Because this might be a sequence, we test both relation + * and sequence bits, and later do a more limited test + * when we know the object type. + */ case ACL_OBJECT_RELATION: - all_privileges = ACL_ALL_RIGHTS_RELATION; - errormsg = _("invalid privilege type %s for table"); + all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE; + errormsg = _("invalid privilege type %s for relation"); + break; + case ACL_OBJECT_SEQUENCE: + all_privileges = ACL_ALL_RIGHTS_SEQUENCE; + errormsg = _("invalid privilege type %s for sequence"); break; case ACL_OBJECT_DATABASE: all_privileges = ACL_ALL_RIGHTS_DATABASE; @@ -327,6 +339,7 @@ ExecuteGrantStmt(GrantStmt *stmt) { istmt.all_privs = false; istmt.privileges = ACL_NO_RIGHTS; + foreach(cell, stmt->privileges) { char *privname = strVal(lfirst(cell)); @@ -356,6 +369,7 @@ ExecGrantStmt_oids(InternalGrant *istmt) switch (istmt->objtype) { case ACL_OBJECT_RELATION: + case ACL_OBJECT_SEQUENCE: ExecGrant_Relation(istmt); break; case ACL_OBJECT_DATABASE: @@ -395,6 +409,7 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) switch (objtype) { case ACL_OBJECT_RELATION: + case ACL_OBJECT_SEQUENCE: foreach(cell, objnames) { Oid relOid; @@ -523,15 +538,15 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) return objects; } +/* + * This processes both sequences and non-sequences. + */ 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) @@ -577,6 +592,69 @@ ExecGrant_Relation(InternalGrant *istmt) errmsg("\"%s\" is a composite type", NameStr(pg_class_tuple->relname)))); + /* Used GRANT SEQUENCE on a non-sequence? */ + if (istmt->objtype == ACL_OBJECT_SEQUENCE && + pg_class_tuple->relkind != RELKIND_SEQUENCE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a sequence", + NameStr(pg_class_tuple->relname)))); + + /* Adjust the default permissions based on whether it is a sequence */ + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + this_privileges = ACL_ALL_RIGHTS_SEQUENCE; + else + this_privileges = ACL_ALL_RIGHTS_RELATION; + } + else + this_privileges = istmt->privileges; + + /* + * The GRANT TABLE syntax can be used for sequences and + * non-sequences, so we have to look at the relkind to + * determine the supported permissions. The OR of + * table and sequence permissions were already checked. + */ + if (istmt->objtype == ACL_OBJECT_RELATION) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + { + /* + * For backward compatibility, throw just a warning + * for invalid sequence permissions when using the + * non-sequence GRANT syntax is used. + */ + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE)) + { + /* + * Mention the object name because the user needs to + * know which operations succeeded. This is required + * because WARNING allows the command to continue. + */ + ereport(WARNING, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE", + NameStr(pg_class_tuple->relname)))); + this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE; + } + } + else + { + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION)) + /* + * USAGE is the only permission supported by sequences + * but not by non-sequences. Don't mention the object + * name because we didn't in the combined TABLE | + * SEQUENCE check. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("invalid privilege type USAGE for table"))); + } + } + /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. @@ -585,12 +663,14 @@ ExecGrant_Relation(InternalGrant *istmt) aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull); if (isNull) - old_acl = acldefault(ACL_OBJECT_RELATION, ownerId); + old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ? + ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, + ownerId); else old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), istmt->privileges, + select_best_grantor(GetUserId(), this_privileges, old_acl, ownerId, &grantorId, &avail_goptions); @@ -600,8 +680,10 @@ ExecGrant_Relation(InternalGrant *istmt) */ this_privileges = restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - relOid, grantorId, ACL_KIND_CLASS, + istmt->all_privs, this_privileges, + relOid, grantorId, + pg_class_tuple->relkind == RELKIND_SEQUENCE + ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS, NameStr(pg_class_tuple->relname)); /* @@ -1336,6 +1418,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] = { /* ACL_KIND_CLASS */ gettext_noop("permission denied for relation %s"), + /* ACL_KIND_SEQUENCE */ + gettext_noop("permission denied for sequence %s"), /* ACL_KIND_DATABASE */ gettext_noop("permission denied for database %s"), /* ACL_KIND_PROC */ @@ -1360,6 +1444,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] = { /* ACL_KIND_CLASS */ gettext_noop("must be owner of relation %s"), + /* ACL_KIND_SEQUENCE */ + gettext_noop("must be owner of sequence %s"), /* ACL_KIND_DATABASE */ gettext_noop("must be owner of database %s"), /* ACL_KIND_PROC */ @@ -1439,6 +1525,7 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid, switch (objkind) { case ACL_KIND_CLASS: + case ACL_KIND_SEQUENCE: return pg_class_aclmask(table_oid, roleid, mask, how); case ACL_KIND_DATABASE: return pg_database_aclmask(table_oid, roleid, mask, how); @@ -1500,9 +1587,9 @@ pg_class_aclmask(Oid table_oid, Oid roleid, * * As of 7.4 we have some updatable system views; those shouldn't be * protected in this way. Assume the view rules can take care of - * themselves. + * themselves. ACL_USAGE is if we ever have system sequences. */ - if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) && + if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE)) && IsSystemClass(classForm) && classForm->relkind != RELKIND_VIEW && !has_rolcatupdate(roleid) && @@ -1511,7 +1598,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid, #ifdef ACLDEBUG elog(DEBUG2, "permission denied for system catalog update"); #endif - mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE); + mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE); } /* @@ -1536,7 +1623,9 @@ pg_class_aclmask(Oid table_oid, Oid roleid, if (isNull) { /* No ACL, so build default ACL */ - acl = acldefault(ACL_OBJECT_RELATION, ownerId); + acl = acldefault(classForm->relkind == RELKIND_SEQUENCE ? + ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, + ownerId); aclDatum = (Datum) 0; } else |
