From 96147a6d1c15b7604838dcd5de5ebd771f551d96 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sun, 27 May 2001 09:59:30 +0000 Subject: [PATCH] Make UPDATE and DELETE privileges distinct. Add REFERENCES and TRIGGER privileges. INSERT and COPY FROM now require INSERT (only). Add privileges regression test. --- doc/src/sgml/ref/copy.sgml | 6 +- doc/src/sgml/ref/create_rule.sgml | 6 +- doc/src/sgml/ref/create_trigger.sgml | 6 +- doc/src/sgml/ref/delete.sgml | 6 +- doc/src/sgml/ref/grant.sgml | 555 ++++++++--------------- doc/src/sgml/ref/insert.sgml | 6 +- doc/src/sgml/ref/psql-ref.sgml | 6 +- doc/src/sgml/ref/revoke.sgml | 394 +++------------- doc/src/sgml/ref/select.sgml | 6 +- doc/src/sgml/ref/update.sgml | 6 +- src/backend/catalog/aclchk.c | 28 +- src/backend/commands/command.c | 7 +- src/backend/commands/comment.c | 4 +- src/backend/commands/copy.c | 4 +- src/backend/commands/sequence.c | 8 +- src/backend/commands/trigger.c | 8 +- src/backend/executor/execMain.c | 15 +- src/backend/parser/gram.y | 32 +- src/backend/tcop/utility.c | 6 +- src/backend/utils/adt/acl.c | 46 +- src/include/utils/acl.h | 33 +- src/test/regress/expected/privileges.out | 198 ++++++++ src/test/regress/parallel_schedule | 1 + src/test/regress/pg_regress.sh | 14 +- src/test/regress/serial_schedule | 3 +- src/test/regress/sql/privileges.sql | 146 ++++++ 26 files changed, 724 insertions(+), 826 deletions(-) create mode 100644 src/test/regress/expected/privileges.out create mode 100644 src/test/regress/sql/privileges.sql diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index 6019eb7a08..3c4dd31a5a 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -1,13 +1,11 @@ - - COPY - + COPY SQL - Language Statements diff --git a/doc/src/sgml/ref/create_rule.sgml b/doc/src/sgml/ref/create_rule.sgml index e6a1a7b146..430026a786 100644 --- a/doc/src/sgml/ref/create_rule.sgml +++ b/doc/src/sgml/ref/create_rule.sgml @@ -1,13 +1,11 @@ - - CREATE RULE - + CREATE RULE SQL - Language Statements diff --git a/doc/src/sgml/ref/create_trigger.sgml b/doc/src/sgml/ref/create_trigger.sgml index c4fbe0203b..1dc633ce9d 100644 --- a/doc/src/sgml/ref/create_trigger.sgml +++ b/doc/src/sgml/ref/create_trigger.sgml @@ -1,13 +1,11 @@ - - CREATE TRIGGER - + CREATE TRIGGER SQL - Language Statements diff --git a/doc/src/sgml/ref/delete.sgml b/doc/src/sgml/ref/delete.sgml index 1f684b946f..261ac32708 100644 --- a/doc/src/sgml/ref/delete.sgml +++ b/doc/src/sgml/ref/delete.sgml @@ -1,13 +1,11 @@ - - DELETE - + DELETE SQL - Language Statements diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 9770c3dd54..1399d049d7 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -1,444 +1,253 @@ - - GRANT - + GRANT SQL - Language Statements + - - GRANT - - - Grants access privilege to a user, a group or all users - + GRANT + Grants access privileges to a user, a group, or all users - - - 1999-07-20 - - -GRANT privilege [, ...] ON object [, ...] - TO { PUBLIC | GROUP group | username } - - - - - 1998-09-23 - - - Inputs - - - - - - privilege - - - The possible privileges are: - - - - SELECT - - - Access all of the columns of a specific - table/view. - - - - - - INSERT - - - Insert data into all columns of a - specific table. - - - - - - UPDATE - - - Update all columns of a specific - table. - - - - - - DELETE - - - Delete rows from a specific table. - - - - - - RULE - - - Define rules on the table/view - (See CREATE RULE statement). - - - - - - ALL - - - Grant all privileges. - - - - - - - - - - object - - - The name of an object to which to grant access. - The possible objects are: - - - - - table - - - - - - view - - - - - - sequence - - - - - - - - - - PUBLIC - - - A short form representing all users. - - - - - - GROUP group - - - A group to whom to grant privileges. - - - - - - - username - - - - The name of a user to whom to grant privileges. PUBLIC is a short form - representing all users. - - - - - - - - - - 1998-09-23 - - - Outputs - - - - - -CHANGE - - - - Message returned if successful. - - - - - - -ERROR: ChangeAcl: class "object" not found - - - - Message returned if the specified object is not available or - if it is impossible - to give privileges to the specified group or users. - - - - - - + + +GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } + ON [ TABLE ] objectname [, ...] + TO { username | GROUP groupname | PUBLIC } + - - - 1998-09-23 - - - Description - + + Description + + + The GRANT command gives specific permissions on + an object (table, view, sequence) to a user or a group of users. + The special key word PUBLIC indicates that the + privileges are to be granted to all users, including those that may + be created later. + - GRANT allows the creator of an object to give specific permissions to - all users (PUBLIC) or to a certain user or group. - Users other than the creator don't have any access permission - unless the creator GRANTs permissions, after the object - is created. + Users other than the creator do not have any access privileges + unless the creator grants permissions, after the object is created. + There is no need to grant privileges to the creator of an object, + as the creator automatically holds all privileges, and can also + drop the object. - Once a user has a privilege on an object, he is enabled to exercise - that privilege. - There is no need to GRANT privileges to the creator of - an object, the creator automatically holds ALL privileges, and can - also drop the object. + The possible privileges are: + + + + SELECT + + + Allows from any column of the + specified table, view, or sequence. Also allows the use of + FROM. + + + + + + INSERT + + + Allows of a new row into the + specified table. Also allows TO. + + + + + + UPDATE + + + Allows of any column of the + specified table. SELECT ... FOR UPDATE + also requires this privilege (besides the + SELECT privilege). For sequences, this + privilege allows the use of currval and + nextval. + + + + + + DELETE + + + Allows the of a row from the + specified table. + + + + + + RULE + + + Allows the creation of a rule on the table/view. (See statement). + + + + + + REFERENCES + + + To create of a table with a foreign key constraint, it is + necessary to have this privilege on the table with the primary + key. + + + + + + TRIGGER + + + Allows the creation of a trigger on the specified table. (See + statement). + + + + + + ALL PRIVILEGES + + + Grant all of the above privileges at once. The + PRIVILEGES key word is optional, but it is + required by strict SQL. + + + + + + The privileges required by other commands are listed on the + reference page of the respective command. + + - - - 1998-09-23 - - - Notes - + + Notes Currently, to grant privileges in Postgres to only a few columns, you must - create a view having desired columns and then grant privileges + create a view having the desired columns and then grant privileges to that view. - Use psql \z - for further information about permissions + Use 's \z command + to obtain information about privileges on existing objects: - - Database = lusitania + + Database = lusitania +------------------+---------------------------------------------+ | Relation | Grant/Revoke Permissions | +------------------+---------------------------------------------+ - | mytable | {"=rw","miriam=arwR","group todos=rw"} | + | mytable | {"=rw","miriam=arwdRxt","group todos=rw"} | +------------------+---------------------------------------------+ Legend: uname=arwR -- privileges granted to a user - group gname=arwR -- privileges granted to a GROUP + group gname=arwR -- privileges granted to a group =arwR -- privileges granted to PUBLIC - r -- SELECT - w -- UPDATE/DELETE - a -- INSERT + r -- SELECT ("read") + w -- UPDATE ("write") + a -- INSERT ("append") + d -- DELETE R -- RULE - arwR -- ALL - - + x -- REFERENCES + t -- TRIGGER + arwdRxt -- ALL PRIVILEGES + - Refer to REVOKE statements to revoke access privileges. + The command is used to revoke access + privileges. - - - - Usage - + + Examples + Grant insert privilege to all users on table films: - + GRANT INSERT ON films TO PUBLIC; - + Grant all privileges to user manuel on view kinds: - -GRANT ALL ON kinds TO manuel; - + +GRANT ALL PRIVILEGES ON kinds TO manuel; + - - - Compatibility - + + Compatibility - - - 1998-09-23 - - - SQL92 - + + SQL92 + - The SQL92 syntax for GRANT allows setting privileges - for individual columns - within a table, and allows setting a privilege to grant - the same privileges to others: + The PRIVILEGES key word in ALL + PRIVILEGES is required. SQL does not + support setting the privileges on more than one table per command. + + + + The SQL92 syntax for GRANT allows setting + privileges for individual columns within a table, and allows + setting a privilege to grant the same privileges to others: - + GRANT privilege [, ...] ON object [ ( column [, ...] ) ] [, ...] TO { PUBLIC | username [, ...] } [ WITH GRANT OPTION ] - + + + + + SQL allows to grant the USAGE privilege on + other kinds of objects: CHARACTER SET, COLLATION, TRANSLATION, DOMAIN. - Fields are compatible with those in the Postgres - implementation, with the following additions: - - - - privilege - - - SQL92 permits additional privileges to be specified: - - - - SELECT - - - - - - - - REFERENCES - - - Allowed to reference some or all of the columns of a specific - table/view in integrity constraints. - - - - - - USAGE - - - Allowed to use a domain, character set, collation - or translation. - If an object specifies anything other than a table/view, - privilege - must specify only USAGE. - - - - - - - - - - object - - - - - - [ TABLE ] table - - - SQL92 allows the additional - non-functional keyword TABLE. - - - - - - CHARACTER SET - - - Allowed to use the specified character set. - - - - - - COLLATION - - - Allowed to use the specified collation sequence. - - - - - - TRANSLATION - - - Allowed to use the specified character set translation. - - - - - - DOMAIN - - - Allowed to use the specified domain. - - - - - - WITH GRANT OPTION - - - Allowed to grant the same privilege to others. - - - - - - - - + The TRIGGER privilege was introduced in SQL99. The RULE privilege + is a PostgreSQL extension. + + + + + + See Also + + + + + - - INSERT - + INSERT SQL - Language Statements diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 3a1c8ab0e0..ac58fdb384 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1,5 +1,5 @@ @@ -1187,8 +1187,8 @@ Access permissions for database "test" - The commands and - + The commands and + are used to set access permissions. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index d7e83c822d..a9988fbc1e 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -1,379 +1,96 @@ - - REVOKE - + REVOKE SQL - Language Statements + - - REVOKE - - - Revokes access privilege from a user, a group or all users. - + REVOKE + Revokes access privilege from a user, a group, or all users. - - - 1999-07-20 - - -REVOKE privilege [, ...] - ON object [, ...] - FROM { PUBLIC | GROUP groupname | username } - - - - - 1998-09-24 - - - Inputs - - - - - - privilege - - - The possible privileges are: - - - - SELECT - - - Privilege to access all of the columns of a specific - table/view. - - - - - - INSERT - - - Privilege to insert data into all columns of a - specific table. - - - - - - UPDATE - - - Privilege to update all columns of a specific - table. - - - - - - DELETE - - - Privilege to delete rows from a specific table. - - - - - - RULE - - - Privilege to define rules on table/view. - (See - ). - - - - - - ALL - - - Rescind all privileges. - - - - - - - - - - object - - - The name of an object from which to revoke access. - - The possible objects are: - - - - table - - - - - view - - - - - - sequence - - - - - - - - - - group - - - The name of a group from whom to revoke privileges. - - - - - - username - - - The name of a user from whom revoke privileges. Use the PUBLIC keyword - to specify all users. - - - - - - PUBLIC - - - Rescind the specified privilege(s) for all users. - - - - - - - - - - 1998-09-24 - - - Outputs - - - - - - -CHANGE - - - - Message returned if successfully. - - - - - - -ERROR - - - - Message returned if object is not available or impossible - to revoke privileges from a group or users. - - - - - - + + +REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } + ON [ TABLE ] object [, ...] + FROM { username | GROUP groupname | PUBLIC } + - - - 1998-09-24 - - - Description - + + Description + - REVOKE allows creator of an object to revoke permissions granted - before, from all users (via PUBLIC) or a certain user or group. + REVOKE allows the creator of an object to revoke + permissions granted before, from a users or a group of users. The + key word PUBLIC means to revoke this privilege + from all users. - - - 1998-09-24 - - - Notes - - - Refer to psql \z command for further information about permissions - on existing objects: - - -Database = lusitania -+------------------+---------------------------------------------+ -| Relation | Grant/Revoke Permissions | -+------------------+---------------------------------------------+ -| mytable | {"=rw","miriam=arwR","group todos=rw"} | -+------------------+---------------------------------------------+ -Legend: - uname=arwR -- privileges granted to a user - group gname=arwR -- privileges granted to a GROUP - =arwR -- privileges granted to PUBLIC - - r -- SELECT - w -- UPDATE/DELETE - a -- INSERT - R -- RULE - arwR -- ALL - - - - - Currently, to create a GROUP you have to insert - data manually into table pg_group as: + + See the description of the command for + the meaning of the privilege types. + + - -INSERT INTO pg_group VALUES ('todos'); -CREATE USER miriam IN GROUP todos; - - - + + Notes - + + Use 's \z command to + display the privileges granted on existing objects. See also for information about the format. + - - - Usage - + + Examples + Revoke insert privilege from all users on table films: - + REVOKE INSERT ON films FROM PUBLIC; - + Revoke all privileges from user manuel on view kinds: - -REVOKE ALL ON kinds FROM manuel; - + +REVOKE ALL PRIVILEGES ON kinds FROM manuel; + - - - Compatibility - + + Compatibility - - - 1998-09-01 - - - SQL92 - + + SQL92 - The SQL92 syntax for REVOKE - has additional capabilities for rescinding - privileges, including those on individual columns in tables: - - - - - -REVOKE { SELECT | DELETE | USAGE | ALL PRIVILEGES } [, ...] - ON object - FROM { PUBLIC | username [, ...] } { RESTRICT | CASCADE } -REVOKE { INSERT | UPDATE | REFERENCES } [, ...] [ ( column [, ...] ) ] - ON object - FROM { PUBLIC | username [, ...] } { RESTRICT | CASCADE } - - - - - Refer to - - for details on individual fields. - - - - - - - -REVOKE GRANT OPTION FOR privilege [, ...] - ON object - FROM { PUBLIC | username [, ...] } { RESTRICT | CASCADE } - - - - - Rescinds authority for a user to grant the specified privilege - to others. - Refer to - - for details on individual fields. - - - - - - - - The possible objects are: - - - [ TABLE ] table/view - - - CHARACTER SET character-set - - - COLLATION collation - - - TRANSLATION translation - - - DOMAIN domain - - + The compatibility notes of the command + apply analogously to REVOKE. The syntax summary is: + + +REVOKE [ GRANT OPTION FOR ] { SELECT | INSERT | UPDATE | DELETE | REFERENCES } + ON object [ ( column [, ...] ) ] + FROM { PUBLIC | username [, ...] } + { RESTRICT | CASCADE } + If user1 gives a privilege WITH GRANT OPTION to user2, and user2 gives it to user3 then user1 can revoke this privilege in cascade using the CASCADE keyword. - - - If user1 gives a privilege WITH GRANT OPTION to user2, and user2 gives it to user3, then if user1 tries to revoke this privilege it fails if he specify the RESTRICT @@ -381,6 +98,15 @@ REVOKE GRANT OPTION FOR privilege [ + + + See Also + + + + + + - - SELECT - + SELECT SQL - Language Statements diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index 58966c9b4a..f47b2663ac 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -1,13 +1,11 @@ - - UPDATE - + UPDATE SQL - Language Statements diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index bfc4cc2a45..5ef74cb1d5 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.47 2001/03/22 03:59:18 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.48 2001/05/27 09:59:28 petere Exp $ * * NOTES * See acl.h. @@ -46,7 +46,7 @@ char *aclcheck_error_strings[] = { }; -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG static dumpacl(Acl *acl) { @@ -62,7 +62,7 @@ dumpacl(Acl *acl) PointerGetDatum(aip + i)))); } -#endif +#endif /* ACLDEBUG */ /* * ChangeAcl @@ -116,13 +116,13 @@ ChangeAcl(char *relname, old_acl = DatumGetAclPCopy(aclDatum); } -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG dumpacl(old_acl); #endif new_acl = aclinsert3(old_acl, mod_aip, modechg); -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG dumpacl(new_acl); #endif @@ -285,7 +285,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) { if (aip->ai_id == id) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "aclcheck: found user %u/%d", aip->ai_id, aip->ai_mode); #endif @@ -301,7 +301,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) { if (in_group(id, aip->ai_id)) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "aclcheck: found group %u/%d", aip->ai_id, aip->ai_mode); #endif @@ -324,7 +324,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) { if (aip->ai_id == id) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "aclcheck: found group %u/%d", aip->ai_id, aip->ai_mode); #endif @@ -341,7 +341,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) break; } -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode); #endif return (aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV; @@ -371,7 +371,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) * pg_shadow.usecatupd is set. (This is to let superusers protect * themselves from themselves.) */ - if (((mode & ACL_WR) || (mode & ACL_AP)) && + if (((mode & ACL_UPDATE) || (mode & ACL_INSERT) || (mode & ACL_DELETE)) && !allowSystemTableMods && IsSystemRelationName(relname) && strncmp(relname, "pg_temp.", strlen("pg_temp.")) != 0 && !((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd) @@ -387,7 +387,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) */ if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "pg_aclcheck: \"%s\" is superuser", usename); #endif @@ -454,7 +454,7 @@ pg_ownercheck(Oid userid, */ if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser", usename); #endif @@ -528,7 +528,7 @@ pg_func_ownercheck(Oid userid, */ if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser", usename); #endif @@ -576,7 +576,7 @@ pg_aggr_ownercheck(Oid userid, */ if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) { -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser", usename); #endif diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index bc5153b800..90cfba50be 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.128 2001/05/21 14:22:11 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.129 2001/05/27 09:59:28 petere Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -1939,9 +1939,10 @@ LockTableCommand(LockStmt *lockstmt) elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname); if (lockstmt->mode == AccessShareLock) - aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_RD); + aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_SELECT); else - aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_WR); + aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), + ACL_UPDATE | ACL_DELETE); if (aclresult != ACLCHECK_OK) elog(ERROR, "LOCK TABLE: permission denied"); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 06397ab323..7d3ba9b561 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1999, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.27 2001/03/22 03:59:21 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.28 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -468,7 +468,7 @@ CommentRewrite(char *rule, char *comment) #ifndef NO_SECURITY relation = RewriteGetRuleEventRel(rule); - aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RU); + aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RULE); if (aclcheck != ACLCHECK_OK) { elog(ERROR, "you are not permitted to comment on rule '%s'", diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 0f249fa385..fbbade1033 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.136 2001/03/22 06:16:11 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.137 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -271,7 +271,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, FILE *fp; Relation rel; - const AclMode required_access = from ? ACL_WR : ACL_RD; + const AclMode required_access = from ? ACL_INSERT : ACL_SELECT; int result; /* diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index f1dbbf6d25..f37b6199b2 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.55 2001/05/10 20:38:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.56 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -243,7 +243,7 @@ nextval(PG_FUNCTION_ARGS) rescnt = 0; bool logit = false; - if (pg_aclcheck(seqname, GetUserId(), ACL_WR) != ACLCHECK_OK) + if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s", seqname, seqname); @@ -390,7 +390,7 @@ currval(PG_FUNCTION_ARGS) SeqTable elm; int32 result; - if (pg_aclcheck(seqname, GetUserId(), ACL_RD) != ACLCHECK_OK) + if (pg_aclcheck(seqname, GetUserId(), ACL_SELECT) != ACLCHECK_OK) elog(ERROR, "%s.currval: you don't have permissions to read sequence %s", seqname, seqname); @@ -428,7 +428,7 @@ do_setval(char *seqname, int32 next, bool iscalled) Buffer buf; Form_pg_sequence seq; - if (pg_aclcheck(seqname, GetUserId(), ACL_WR) != ACLCHECK_OK) + if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) elog(ERROR, "%s.setval: you don't have permissions to set sequence %s", seqname, seqname); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 70f2e1b295..70c146530f 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.90 2001/03/22 06:16:11 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.91 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -69,8 +69,10 @@ CreateTrigger(CreateTrigStmt *stmt) if (!allowSystemTableMods && IsSystemRelationName(stmt->relname)) elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relname); - if (!pg_ownercheck(GetUserId(), stmt->relname, RELNAME)) - elog(ERROR, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]); + if (pg_aclcheck(stmt->relname, GetUserId(), + stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER) + != ACLCHECK_OK) + elog(ERROR, "permission denied"); /* * If trigger is a constraint, user trigger name as constraint name diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index eda6ce518d..f87b674b07 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.140 2001/05/15 00:33:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.141 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -420,7 +420,7 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) if (rte->checkForRead) { - aclcheck_result = CHECK(ACL_RD); + aclcheck_result = CHECK(ACL_SELECT); if (aclcheck_result != ACLCHECK_OK) elog(ERROR, "%s: %s", relName, aclcheck_error_strings[aclcheck_result]); @@ -437,15 +437,14 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) switch (operation) { case CMD_INSERT: - /* Accept either APPEND or WRITE access for this */ - aclcheck_result = CHECK(ACL_AP); - if (aclcheck_result != ACLCHECK_OK) - aclcheck_result = CHECK(ACL_WR); + aclcheck_result = CHECK(ACL_INSERT); break; case CMD_SELECT: - case CMD_DELETE: case CMD_UPDATE: - aclcheck_result = CHECK(ACL_WR); + aclcheck_result = CHECK(ACL_UPDATE); + break; + case CMD_DELETE: + aclcheck_result = CHECK(ACL_DELETE); break; default: elog(ERROR, "ExecCheckRTEPerms: bogus operation %d", diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 5857f6ee64..37c28495e5 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.226 2001/05/14 20:30:20 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.227 2001/05/27 09:59:29 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2234,19 +2234,19 @@ from_in: IN * *****************************************************************************/ -GrantStmt: GRANT privileges ON relation_name_list TO grantee opt_with_grant +GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee opt_with_grant { - $$ = (Node*)makeAclStmt($2,$4,$6,'+'); + $$ = (Node*)makeAclStmt($2,$5,$7,'+'); } ; privileges: ALL PRIVILEGES { - $$ = aclmakepriv("rwaR",0); + $$ = aclmakepriv(ACL_MODE_STR,0); } | ALL { - $$ = aclmakepriv("rwaR",0); + $$ = aclmakepriv(ACL_MODE_STR,0); } | operation_commalist { @@ -2266,23 +2266,31 @@ operation_commalist: operation operation: SELECT { - $$ = ACL_MODE_RD_CHR; + $$ = ACL_MODE_SELECT_CHR; } | INSERT { - $$ = ACL_MODE_AP_CHR; + $$ = ACL_MODE_INSERT_CHR; } | UPDATE { - $$ = ACL_MODE_WR_CHR; + $$ = ACL_MODE_UPDATE_CHR; } | DELETE { - $$ = ACL_MODE_WR_CHR; + $$ = ACL_MODE_DELETE_CHR; } | RULE { - $$ = ACL_MODE_RU_CHR; + $$ = ACL_MODE_RULE_CHR; + } + | REFERENCES + { + $$ = ACL_MODE_REFERENCES_CHR; + } + | TRIGGER + { + $$ = ACL_MODE_TRIGGER_CHR; } ; @@ -2315,9 +2323,9 @@ opt_with_grant: WITH GRANT OPTION * *****************************************************************************/ -RevokeStmt: REVOKE privileges ON relation_name_list FROM grantee +RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee { - $$ = (Node*)makeAclStmt($2,$4,$6,'-'); + $$ = (Node*)makeAclStmt($2,$5,$7,'-'); } ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index b616f7e68e..dc569455b2 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.110 2001/05/07 00:43:23 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.111 2001/05/27 09:59:29 petere Exp $ * *------------------------------------------------------------------------- */ @@ -267,7 +267,7 @@ ProcessUtility(Node *parsetree, int aclcheck_result; relationName = RewriteGetRuleEventRel(rulename); - aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RU); + aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RULE); if (aclcheck_result != ACLCHECK_OK) elog(ERROR, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]); @@ -550,7 +550,7 @@ ProcessUtility(Node *parsetree, int aclcheck_result; relname = stmt->object->relname; - aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RU); + aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE); if (aclcheck_result != ACLCHECK_OK) elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]); set_ps_display(commandTag = "CREATE"); diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 10e2f13bc3..f4e3fe9986 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.58 2001/03/22 03:59:48 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.59 2001/05/27 09:59:30 petere Exp $ * *------------------------------------------------------------------------- */ @@ -113,8 +113,8 @@ aclparse(char *s, AclItem *aip, unsigned *modechg) Assert(s && aip && modechg); -#ifdef ACLDEBUG_TRACE - printf("aclparse: input = '%s'\n", s); +#ifdef ACLDEBUG + elog(DEBUG, "aclparse: input = '%s'", s); #endif aip->ai_idtype = ACL_IDTYPE_UID; s = getid(s, name); @@ -155,17 +155,26 @@ aclparse(char *s, AclItem *aip, unsigned *modechg) { switch (*s) { - case ACL_MODE_AP_CHR: - aip->ai_mode |= ACL_AP; + case ACL_MODE_INSERT_CHR: + aip->ai_mode |= ACL_INSERT; break; - case ACL_MODE_RD_CHR: - aip->ai_mode |= ACL_RD; + case ACL_MODE_SELECT_CHR: + aip->ai_mode |= ACL_SELECT; break; - case ACL_MODE_WR_CHR: - aip->ai_mode |= ACL_WR; + case ACL_MODE_UPDATE_CHR: + aip->ai_mode |= ACL_UPDATE; break; - case ACL_MODE_RU_CHR: - aip->ai_mode |= ACL_RU; + case ACL_MODE_DELETE_CHR: + aip->ai_mode |= ACL_DELETE; + break; + case ACL_MODE_RULE_CHR: + aip->ai_mode |= ACL_RULE; + break; + case ACL_MODE_REFERENCES_CHR: + aip->ai_mode |= ACL_REFERENCES; + break; + case ACL_MODE_TRIGGER_CHR: + aip->ai_mode |= ACL_TRIGGER; break; default: elog(ERROR, "aclparse: mode flags must use \"%s\"", @@ -192,7 +201,7 @@ aclparse(char *s, AclItem *aip, unsigned *modechg) break; } -#ifdef ACLDEBUG_TRACE +#ifdef ACLDEBUG elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x", aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg); #endif @@ -269,7 +278,7 @@ aclitemout(PG_FUNCTION_ARGS) unsigned i; char *tmpname; - p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN); + p = out = palloc(strlen("group =" ACL_MODE_STR " ") + 1 + NAMEDATALEN); *p = '\0'; switch (aip->ai_idtype) @@ -368,14 +377,13 @@ acldefault(char *relname, AclId ownerid) AclItem *aip; #define ACL_WORLD_DEFAULT (ACL_NO) -/* #define ACL_WORLD_DEFAULT (ACL_RD|ACL_WR|ACL_AP|ACL_RU) */ -#define ACL_OWNER_DEFAULT (ACL_RD|ACL_WR|ACL_AP|ACL_RU) +#define ACL_OWNER_DEFAULT (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER) acl = makeacl(2); aip = ACL_DAT(acl); aip[0].ai_idtype = ACL_IDTYPE_WORLD; aip[0].ai_id = ACL_ID_WORLD; - aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_RD : ACL_WORLD_DEFAULT; + aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_SELECT : ACL_WORLD_DEFAULT; aip[1].ai_idtype = ACL_IDTYPE_UID; aip[1].ai_id = ownerid; aip[1].ai_mode = ACL_OWNER_DEFAULT; @@ -651,8 +659,8 @@ aclmakepriv(char *old_privlist, char new_priv) int i; int l; - Assert(strlen(old_privlist) < 5); - priv = palloc(5); /* at most "rwaR" */ ; + Assert(strlen(old_privlist) <= strlen(ACL_MODE_STR)); + priv = palloc(strlen(ACL_MODE_STR)+1); if (old_privlist == NULL || old_privlist[0] == '\0') { @@ -665,7 +673,7 @@ aclmakepriv(char *old_privlist, char new_priv) l = strlen(old_privlist); - if (l == 4) + if (l == strlen(ACL_MODE_STR)) { /* can't add any more privileges */ return priv; } diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 7e09390c3c..02e6094c51 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: acl.h,v 1.31 2001/03/22 04:01:10 momjian Exp $ + * $Id: acl.h,v 1.32 2001/05/27 09:59:30 petere Exp $ * * NOTES * For backward-compatibility purposes we have to allow there @@ -52,11 +52,14 @@ typedef uint8 AclIdType; typedef uint8 AclMode; #define ACL_NO 0 /* no permissions */ -#define ACL_AP (1<<0) /* append */ -#define ACL_RD (1<<1) /* read */ -#define ACL_WR (1<<2) /* write (append/delete/replace) */ -#define ACL_RU (1<<3) /* place rules */ -#define N_ACL_MODES 4 +#define ACL_INSERT (1<<0) +#define ACL_SELECT (1<<1) +#define ACL_UPDATE (1<<2) +#define ACL_DELETE (1<<3) +#define ACL_RULE (1<<4) +#define ACL_REFERENCES (1<<5) +#define ACL_TRIGGER (1<<6) +#define N_ACL_MODES 7 /* 1 plus the last 1</dev/null +if [ $? -eq 2 ]; then + echo "$me: could not drop user accounts" + (exit 2); exit +fi + + # ---------- # Install the PL/pgSQL language in it # ---------- diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 14ad6f505e..afb0090cda 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -1,4 +1,4 @@ -# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.3 2000/11/22 13:37:44 petere Exp $ +# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.4 2001/05/27 09:59:30 petere Exp $ # This should probably be in an order similar to parallel_schedule. test: boolean test: char @@ -68,6 +68,7 @@ test: portals test: arrays test: btree_index test: hash_index +test: privileges test: misc test: select_views test: alter_table diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql new file mode 100644 index 0000000000..1558273f7b --- /dev/null +++ b/src/test/regress/sql/privileges.sql @@ -0,0 +1,146 @@ +-- +-- Test access privileges +-- + +CREATE USER regressuser1; +CREATE USER regressuser2; +CREATE USER regressuser3; +CREATE USER regressuser4; +CREATE USER regressuser4; -- duplicate + +CREATE GROUP regressgroup1; +CREATE GROUP regressgroup2 WITH USER regressuser1, regressuser2; + +ALTER GROUP regressgroup1 ADD USER regressuser4; + +ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate +ALTER GROUP regressgroup2 DROP USER regressuser2; +ALTER GROUP regressgroup2 ADD USER regressuser4; + + +-- test owner privileges + +SET SESSION AUTHORIZATION regressuser1; +SELECT session_user, current_user; + +CREATE TABLE atest1 ( a int, b text ); +SELECT * FROM atest1; +INSERT INTO atest1 VALUES (1, 'one'); +DELETE FROM atest1; +UPDATE atest1 SET a = 1 WHERE b = 'blech'; +LOCK atest1 IN ACCESS EXCLUSIVE MODE; + +REVOKE ALL ON atest1 FROM PUBLIC; +SELECT * FROM atest1; + +GRANT ALL ON atest1 TO regressuser2; +GRANT SELECT ON atest1 TO regressuser3; +SELECT * FROM atest1; + +CREATE TABLE atest2 (col1 varchar(10), col2 boolean); +GRANT SELECT ON atest2 TO regressuser2; +GRANT UPDATE ON atest2 TO regressuser3; +GRANT INSERT ON atest2 TO regressuser4; + + +SET SESSION AUTHORIZATION regressuser2; +SELECT session_user, current_user; + +-- try various combinations of queries on atest1 and atest2 + +SELECT * FROM atest1; -- ok +SELECT * FROM atest2; -- ok +INSERT INTO atest1 VALUES (2, 'two'); -- ok +INSERT INTO atest2 VALUES ('foo', true); -- fail +INSERT INTO atest1 SELECT 1, b FROM atest1; -- ok +UPDATE atest1 SET a = 1 WHERE a = 2; -- ok +UPDATE atest2 SET col2 = NOT col2; -- fail +SELECT * FROM atest1 FOR UPDATE; -- ok +SELECT * FROM atest2 FOR UPDATE; -- fail +DELETE FROM atest2; -- fail +LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- fail +COPY atest2 FROM stdin; -- fail +GRANT ALL ON atest1 TO PUBLIC; -- fail + +-- checks in subquery, both ok +SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); +SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) ); + + +SET SESSION AUTHORIZATION regressuser3; +SELECT session_user, current_user; + +SELECT * FROM atest1; -- ok +SELECT * FROM atest2; -- fail +INSERT INTO atest1 VALUES (2, 'two'); -- fail +INSERT INTO atest2 VALUES ('foo', true); -- fail +INSERT INTO atest1 SELECT 1, b FROM atest1; -- fail +UPDATE atest1 SET a = 1 WHERE a = 2; -- fail +UPDATE atest2 SET col2 = NULL; -- ok +UPDATE atest2 SET col2 = NOT col2; -- fails; requires SELECT on atest2 +UPDATE atest2 SET col2 = true WHERE atest1.a = 5; -- ok +SELECT * FROM atest1 FOR UPDATE; -- fail +SELECT * FROM atest2 FOR UPDATE; -- fail +DELETE FROM atest2; -- fail +LOCK atest2 IN ACCESS EXCLUSIVE MODE; -- ok +COPY atest2 FROM stdin; -- fail + +-- checks in subquery, both fail +SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); +SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) ); + +SET SESSION AUTHORIZATION regressuser4; +COPY atest2 FROM stdin; -- ok +bar true +\. + + +-- groups + +SET SESSION AUTHORIZATION regressuser3; +CREATE TABLE atest3 (one int, two int, three int); +GRANT DELETE ON atest3 TO GROUP regressgroup2; + +SET SESSION AUTHORIZATION regressuser1; + +SELECT * FROM atest3; -- fail +DELETE FROM atest3; -- ok + + +-- views + +SET SESSION AUTHORIZATION regressuser3; + +CREATE VIEW atestv1 AS SELECT * FROM atest1; -- ok +/* The next *should* fail, but it's not implemented that way yet. */ +CREATE VIEW atestv2 AS SELECT * FROM atest2; +CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok + +SELECT * FROM atestv1; -- ok +GRANT SELECT ON atestv1 TO regressuser4; +GRANT SELECT ON atestv3 TO regressuser4; + +SET SESSION AUTHORIZATION regressuser4; + +SELECT * FROM atestv1; -- ok +SELECT * FROM atestv3; -- ok + + +-- clean up + +\c regression +DROP TABLE atest1; +DROP TABLE atest2; +DROP TABLE atest3; + +DROP VIEW atestv1; +DROP VIEW atestv2; +DROP VIEW atestv3; + +DROP GROUP regressgroup1; +DROP GROUP regressgroup2; + +DROP USER regressuser1; +DROP USER regressuser2; +DROP USER regressuser3; +DROP USER regressuser4; -- GitLab