From 7bae5a289c8fbe33aceb56f04e273eee2c1e7c39 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 5 Sep 2006 21:08:36 +0000 Subject: [PATCH] Get rid of the separate RULE privilege for tables: now only a table's owner can create or modify rules for the table. Do setRuleCheckAsUser() while loading rules into the relcache, rather than when defining a rule. This ensures that permission checks for tables referenced in a rule are done with respect to the current owner of the rule's table, whereas formerly ALTER TABLE OWNER would fail to update the permission checking for associated rules. Removal of separate RULE privilege is needed to prevent various scenarios in which a grantee of RULE privilege could effectively have any privilege of the table owner. For backwards compatibility, GRANT/REVOKE RULE is still accepted, but it doesn't do anything. Per discussion here: http://archives.postgresql.org/pgsql-hackers/2006-04/msg01138.php --- doc/src/sgml/ddl.sgml | 4 +- doc/src/sgml/func.sgml | 9 +-- doc/src/sgml/information_schema.sgml | 6 +- doc/src/sgml/ref/create_rule.sgml | 5 +- doc/src/sgml/ref/grant.sgml | 26 ++------ doc/src/sgml/ref/revoke.sgml | 4 +- doc/src/sgml/user-manag.sgml | 4 +- src/backend/catalog/aclchk.c | 8 +-- src/backend/catalog/information_schema.sql | 9 +-- src/backend/commands/comment.c | 8 +-- src/backend/rewrite/rewriteDefine.c | 75 ++++++++-------------- src/backend/rewrite/rewriteRemove.c | 8 +-- src/backend/utils/adt/acl.c | 22 +++---- src/backend/utils/cache/relcache.c | 19 +++++- src/include/catalog/catversion.h | 4 +- src/include/nodes/parsenodes.h | 4 +- src/include/rewrite/rewriteDefine.h | 4 +- src/include/utils/acl.h | 5 +- src/test/regress/expected/dependency.out | 16 ++--- src/test/regress/expected/privileges.out | 20 ++---- src/test/regress/sql/privileges.sql | 8 +-- 21 files changed, 113 insertions(+), 155 deletions(-) diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 5f3f724b7c..f21a4797bd 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1,4 +1,4 @@ - + Data Definition @@ -1342,7 +1342,7 @@ ALTER TABLE products RENAME TO items; There are several different privileges: SELECT, INSERT, UPDATE, DELETE, - RULE, REFERENCES, TRIGGER, + REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, and USAGE. The privileges applicable to a particular diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index ebf793ae55..13209c87a2 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ - + Functions and Operators @@ -9543,9 +9543,10 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); the name can be schema-qualified if necessary. The desired access privilege type is specified by a text string, which must evaluate to one of the - values SELECT, INSERT, UPDATE, - DELETE, RULE, REFERENCES, or - TRIGGER. (Case of the string is not significant, however.) + values SELECT, INSERT, + UPDATE, DELETE, + REFERENCES, or TRIGGER. + (Case of the string is not significant, however.) An example is: SELECT has_table_privilege('myschema.mytable', 'select'); diff --git a/doc/src/sgml/information_schema.sgml b/doc/src/sgml/information_schema.sgml index 1ce808463d..544b811c54 100644 --- a/doc/src/sgml/information_schema.sgml +++ b/doc/src/sgml/information_schema.sgml @@ -1,4 +1,4 @@ - + The Information Schema @@ -2832,7 +2832,7 @@ ORDER BY c.ordinal_position; Type of the privilege: SELECT, DELETE, INSERT, UPDATE, REFERENCES, - RULE, or TRIGGER + or TRIGGER @@ -4418,7 +4418,7 @@ ORDER BY c.ordinal_position; Type of the privilege: SELECT, DELETE, INSERT, UPDATE, REFERENCES, - RULE, or TRIGGER + or TRIGGER diff --git a/doc/src/sgml/ref/create_rule.sgml b/doc/src/sgml/ref/create_rule.sgml index 9380ab5a18..1c9cf0b91a 100644 --- a/doc/src/sgml/ref/create_rule.sgml +++ b/doc/src/sgml/ref/create_rule.sgml @@ -1,5 +1,5 @@ @@ -200,8 +200,7 @@ CREATE [ OR REPLACE ] RULE name AS Notes - You must have the privilege RULE on a table to - be allowed to define a rule on it. + You must be the owner of a table to create or change rules for it. diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index d846cd07fd..e00ea521e9 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -1,5 +1,5 @@ @@ -20,7 +20,7 @@ PostgreSQL documentation -GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } +GRANT { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] tablename [, ...] TO { username | GROUP groupname | PUBLIC } [, ...] [ WITH GRANT OPTION ] @@ -178,16 +178,6 @@ GRANT role [, ...] TO - - RULE - - - Allows the creation of a rule on the table/view. (See the statement.) - - - - REFERENCES @@ -418,8 +408,8 @@ GRANT role [, ...] TO The entries shown by \z are interpreted thus: @@ -432,7 +422,6 @@ GRANT role [, ...] TO role [, ...] TO PUBLIC depending on the object type, as explained above. The first GRANT or REVOKE on an object will instantiate the default privileges (producing, for example, -{miriam=arwdRxt/miriam}) and then modify them per the +{miriam=arwdxt/miriam}) and then modify them per the specified request. @@ -548,8 +537,7 @@ GRANT privileges - The RULE privilege, and privileges on - databases, tablespaces, schemas, and languages are + Privileges on databases, tablespaces, schemas, and languages are PostgreSQL extensions. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index df38437436..03746d5622 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -1,5 +1,5 @@ @@ -21,7 +21,7 @@ PostgreSQL documentation REVOKE [ GRANT OPTION FOR ] - { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } + { { SELECT | INSERT | UPDATE | DELETE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] tablename [, ...] FROM { username | GROUP groupname | PUBLIC } [, ...] diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml index c86837d1f7..ec5c6e43c4 100644 --- a/doc/src/sgml/user-manag.sgml +++ b/doc/src/sgml/user-manag.sgml @@ -1,4 +1,4 @@ - + Database Roles and Privileges @@ -293,7 +293,7 @@ ALTER ROLE myname SET enable_indexscan TO off; granted. There are several different kinds of privilege: SELECT, INSERT, UPDATE, DELETE, - RULE, REFERENCES, TRIGGER, + REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE, and USAGE. For more information on the different types of privileges supported by diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 73b9ef6e9d..e74c9b4410 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.130 2006/07/14 14:52:17 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.131 2006/09/05 21:08:35 tgl Exp $ * * NOTES * See acl.h. @@ -1328,8 +1328,6 @@ string_to_privilege(const char *privname) return ACL_UPDATE; if (strcmp(privname, "delete") == 0) return ACL_DELETE; - if (strcmp(privname, "rule") == 0) - return ACL_RULE; if (strcmp(privname, "references") == 0) return ACL_REFERENCES; if (strcmp(privname, "trigger") == 0) @@ -1346,6 +1344,8 @@ string_to_privilege(const char *privname) return ACL_CREATE_TEMP; if (strcmp(privname, "connect") == 0) return ACL_CONNECT; + if (strcmp(privname, "rule") == 0) + return 0; /* ignore old RULE privileges */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized privilege type \"%s\"", privname))); @@ -1365,8 +1365,6 @@ privilege_to_string(AclMode privilege) return "UPDATE"; case ACL_DELETE: return "DELETE"; - case ACL_RULE: - return "RULE"; case ACL_REFERENCES: return "REFERENCES"; case ACL_TRIGGER: diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index a30cddd287..a735fa3081 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -4,7 +4,7 @@ * * Copyright (c) 2003-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.35 2006/09/04 23:13:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.36 2006/09/05 21:08:35 tgl Exp $ */ /* @@ -1194,7 +1194,6 @@ CREATE VIEW role_table_grants AS SELECT 'INSERT' UNION ALL SELECT 'UPDATE' UNION ALL SELECT 'REFERENCES' UNION ALL - SELECT 'RULE' UNION ALL SELECT 'TRIGGER') AS pr (type) WHERE c.relnamespace = nc.oid @@ -1705,7 +1704,6 @@ CREATE VIEW table_constraints AS OR has_table_privilege(r.oid, 'INSERT') OR has_table_privilege(r.oid, 'UPDATE') OR has_table_privilege(r.oid, 'DELETE') - OR has_table_privilege(r.oid, 'RULE') OR has_table_privilege(r.oid, 'REFERENCES') OR has_table_privilege(r.oid, 'TRIGGER') ) @@ -1739,7 +1737,6 @@ CREATE VIEW table_constraints AS OR has_table_privilege(r.oid, 'INSERT') OR has_table_privilege(r.oid, 'UPDATE') OR has_table_privilege(r.oid, 'DELETE') - OR has_table_privilege(r.oid, 'RULE') OR has_table_privilege(r.oid, 'REFERENCES') OR has_table_privilege(r.oid, 'TRIGGER') ); @@ -1785,7 +1782,6 @@ CREATE VIEW table_privileges AS SELECT 'INSERT' UNION ALL SELECT 'UPDATE' UNION ALL SELECT 'REFERENCES' UNION ALL - SELECT 'RULE' UNION ALL SELECT 'TRIGGER') AS pr (type) WHERE c.relnamespace = nc.oid @@ -1841,7 +1837,6 @@ CREATE VIEW tables AS OR has_table_privilege(c.oid, 'INSERT') OR has_table_privilege(c.oid, 'UPDATE') OR has_table_privilege(c.oid, 'DELETE') - OR has_table_privilege(c.oid, 'RULE') OR has_table_privilege(c.oid, 'REFERENCES') OR has_table_privilege(c.oid, 'TRIGGER') ); @@ -1963,7 +1958,6 @@ CREATE VIEW triggers AS OR has_table_privilege(c.oid, 'INSERT') OR has_table_privilege(c.oid, 'UPDATE') OR has_table_privilege(c.oid, 'DELETE') - OR has_table_privilege(c.oid, 'RULE') OR has_table_privilege(c.oid, 'REFERENCES') OR has_table_privilege(c.oid, 'TRIGGER') ); @@ -2162,7 +2156,6 @@ CREATE VIEW views AS OR has_table_privilege(c.oid, 'INSERT') OR has_table_privilege(c.oid, 'UPDATE') OR has_table_privilege(c.oid, 'DELETE') - OR has_table_privilege(c.oid, 'RULE') OR has_table_privilege(c.oid, 'REFERENCES') OR has_table_privilege(c.oid, 'TRIGGER') ); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 2e29535c4e..f54243a495 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1996-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.90 2006/07/14 14:52:18 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.91 2006/09/05 21:08:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -741,7 +741,6 @@ CommentRule(List *qualname, char *comment) HeapTuple tuple; Oid reloid; Oid ruleoid; - AclResult aclcheck; /* Separate relname and trig name */ nnames = list_length(qualname); @@ -819,9 +818,8 @@ CommentRule(List *qualname, char *comment) } /* Check object security */ - aclcheck = pg_class_aclcheck(reloid, GetUserId(), ACL_RULE); - if (aclcheck != ACLCHECK_OK) - aclcheck_error(aclcheck, ACL_KIND_CLASS, + if (!pg_class_ownercheck(reloid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, get_rel_name(reloid)); /* Call CreateComments() to create/drop the comments */ diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index a961f49d9b..17f437c385 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.113 2006/09/02 17:06:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.114 2006/09/05 21:08:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,9 +33,8 @@ static void checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect); -static void setRuleCheckAsUser_Query(Query *qry, Oid userid); -static void setRuleCheckAsUser_Expr(Node *node, Oid userid); static bool setRuleCheckAsUser_walker(Node *node, Oid *context); +static void setRuleCheckAsUser_Query(Query *qry, Oid userid); /* @@ -193,7 +192,6 @@ DefineQueryRewrite(RuleStmt *stmt) int event_attno; ListCell *l; Query *query; - AclResult aclresult; bool RelisBecomingView = false; /* @@ -209,9 +207,8 @@ DefineQueryRewrite(RuleStmt *stmt) /* * Check user has permission to apply rules to this relation. */ - aclresult = pg_class_aclcheck(ev_relid, GetUserId(), ACL_RULE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, + if (!pg_class_ownercheck(ev_relid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(event_relation)); /* @@ -411,19 +408,6 @@ DefineQueryRewrite(RuleStmt *stmt) */ event_attno = -1; - /* - * We want the rule's table references to be checked as though by the rule - * owner, not the user referencing the rule. Therefore, scan through the - * rule's rtables and set the checkAsUser field on all rtable entries. We - * have to look at event_qual as well, in case it contains sublinks. - */ - foreach(l, action) - { - query = (Query *) lfirst(l); - setRuleCheckAsUser_Query(query, GetUserId()); - } - setRuleCheckAsUser_Expr(event_qual, GetUserId()); - /* discard rule if it's null action and not INSTEAD; it's a no-op */ if (action != NIL || is_instead) { @@ -554,9 +538,9 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect) } /* - * setRuleCheckAsUser_Query - * Recursively scan a query and set the checkAsUser field to the - * given userid in all rtable entries. + * setRuleCheckAsUser + * Recursively scan a query or expression tree and set the checkAsUser + * field to the given userid in all rtable entries. * * Note: for a view (ON SELECT rule), the checkAsUser field of the *OLD* * RTE entry will be overridden when the view rule is expanded, and the @@ -565,6 +549,26 @@ checkRuleResultList(List *targetList, TupleDesc resultDesc, bool isSelect) * it's important to set these fields to match the rule owner. So we just set * them always. */ +void +setRuleCheckAsUser(Node *node, Oid userid) +{ + (void) setRuleCheckAsUser_walker(node, &userid); +} + +static bool +setRuleCheckAsUser_walker(Node *node, Oid *context) +{ + if (node == NULL) + return false; + if (IsA(node, Query)) + { + setRuleCheckAsUser_Query((Query *) node, *context); + return false; + } + return expression_tree_walker(node, setRuleCheckAsUser_walker, + (void *) context); +} + static void setRuleCheckAsUser_Query(Query *qry, Oid userid) { @@ -591,31 +595,6 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid) QTW_IGNORE_RT_SUBQUERIES); } -/* - * Expression-tree walker to find sublink queries - */ -static void -setRuleCheckAsUser_Expr(Node *node, Oid userid) -{ - (void) setRuleCheckAsUser_walker(node, &userid); -} - -static bool -setRuleCheckAsUser_walker(Node *node, Oid *context) -{ - if (node == NULL) - return false; - if (IsA(node, Query)) - { - Query *qry = (Query *) node; - - setRuleCheckAsUser_Query(qry, *context); - return false; - } - return expression_tree_walker(node, setRuleCheckAsUser_walker, - (void *) context); -} - /* * Rename an existing rewrite rule. diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index b0acc01f82..e57724af4d 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.65 2006/06/16 20:23:44 adunstan Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.66 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,6 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior, { HeapTuple tuple; Oid eventRelationOid; - AclResult aclresult; ObjectAddress object; /* @@ -72,9 +71,8 @@ RemoveRewriteRule(Oid owningRel, const char *ruleName, DropBehavior behavior, */ eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; Assert(eventRelationOid == owningRel); - aclresult = pg_class_aclcheck(eventRelationOid, GetUserId(), ACL_RULE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_CLASS, + if (!pg_class_ownercheck(eventRelationOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, get_rel_name(eventRelationOid)); /* diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index c3ac26dce4..509c6dea92 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.134 2006/07/14 14:52:23 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.135 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -265,9 +265,6 @@ aclparse(const char *s, AclItem *aip) case ACL_DELETE_CHR: read = ACL_DELETE; break; - case ACL_RULE_CHR: - read = ACL_RULE; - break; case ACL_REFERENCES_CHR: read = ACL_REFERENCES; break; @@ -289,6 +286,9 @@ aclparse(const char *s, AclItem *aip) case ACL_CONNECT_CHR: read = ACL_CONNECT; break; + case 'R': /* ignore old RULE privileges */ + read = 0; + break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -1325,8 +1325,6 @@ convert_priv_string(text *priv_type_text) return ACL_UPDATE; if (pg_strcasecmp(priv_type, "DELETE") == 0) return ACL_DELETE; - if (pg_strcasecmp(priv_type, "RULE") == 0) - return ACL_RULE; if (pg_strcasecmp(priv_type, "REFERENCES") == 0) return ACL_REFERENCES; if (pg_strcasecmp(priv_type, "TRIGGER") == 0) @@ -1343,6 +1341,8 @@ convert_priv_string(text *priv_type_text) return ACL_CREATE_TEMP; if (pg_strcasecmp(priv_type, "CONNECT") == 0) return ACL_CONNECT; + if (pg_strcasecmp(priv_type, "RULE") == 0) + return 0; /* ignore old RULE privileges */ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1553,11 +1553,6 @@ convert_table_priv_string(text *priv_type_text) if (pg_strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_DELETE); - if (pg_strcasecmp(priv_type, "RULE") == 0) - return ACL_RULE; - if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0) - return ACL_GRANT_OPTION_FOR(ACL_RULE); - if (pg_strcasecmp(priv_type, "REFERENCES") == 0) return ACL_REFERENCES; if (pg_strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0) @@ -1568,6 +1563,11 @@ convert_table_priv_string(text *priv_type_text) if (pg_strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_TRIGGER); + if (pg_strcasecmp(priv_type, "RULE") == 0) + return 0; /* ignore old RULE privileges */ + if (pg_strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0) + return 0; + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 08697d5036..190543e2bd 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.247 2006/07/31 20:09:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.248 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -51,6 +51,7 @@ #include "optimizer/clauses.h" #include "optimizer/planmain.h" #include "optimizer/prep.h" +#include "rewrite/rewriteDefine.h" #include "storage/fd.h" #include "storage/smgr.h" #include "utils/builtins.h" @@ -683,6 +684,22 @@ RelationBuildRuleLock(Relation relation) if ((Pointer) rule_text != DatumGetPointer(rule_datum)) pfree(rule_text); + /* + * We want the rule's table references to be checked as though by the + * table owner, not the user referencing the rule. Therefore, scan + * through the rule's actions and set the checkAsUser field on all + * rtable entries. We have to look at the qual as well, in case it + * contains sublinks. + * + * The reason for doing this when the rule is loaded, rather than + * when it is stored, is that otherwise ALTER TABLE OWNER would have + * to grovel through stored rules to update checkAsUser fields. + * Scanning the rule tree during load is relatively cheap (compared + * to constructing it in the first place), so we do it here. + */ + setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner); + setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner); + if (numlocks >= maxlocks) { maxlocks *= 2; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 6266b591ca..7e207a8ee2 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.353 2006/08/25 04:06:54 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.354 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200608211 +#define CATALOG_VERSION_NO 200609051 #endif diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 40708404fc..0b9de4905d 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.329 2006/09/03 03:19:45 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.330 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -50,7 +50,7 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */ #define ACL_SELECT (1<<1) #define ACL_UPDATE (1<<2) #define ACL_DELETE (1<<3) -#define ACL_RULE (1<<4) +/* #define ACL_RULE (1<<4) unused, available */ #define ACL_REFERENCES (1<<5) #define ACL_TRIGGER (1<<6) #define ACL_EXECUTE (1<<7) /* for functions */ diff --git a/src/include/rewrite/rewriteDefine.h b/src/include/rewrite/rewriteDefine.h index 3d284894e3..e404ac526a 100644 --- a/src/include/rewrite/rewriteDefine.h +++ b/src/include/rewrite/rewriteDefine.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.21 2006/03/05 15:58:58 momjian Exp $ + * $PostgreSQL: pgsql/src/include/rewrite/rewriteDefine.h,v 1.22 2006/09/05 21:08:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,4 +21,6 @@ extern void DefineQueryRewrite(RuleStmt *args); extern void RenameRewriteRule(Oid owningRel, const char *oldName, const char *newName); +extern void setRuleCheckAsUser(Node *node, Oid userid); + #endif /* REWRITEDEFINE_H */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 27aaf0dfbf..56226b4216 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.96 2006/05/03 22:45:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.97 2006/09/05 21:08:36 tgl Exp $ * * NOTES * An ACL array is simply an array of AclItems, representing the union @@ -128,7 +128,6 @@ typedef ArrayType Acl; #define ACL_SELECT_CHR 'r' /* formerly known as "read" */ #define ACL_UPDATE_CHR 'w' /* formerly known as "write" */ #define ACL_DELETE_CHR 'd' -#define ACL_RULE_CHR 'R' #define ACL_REFERENCES_CHR 'x' #define ACL_TRIGGER_CHR 't' #define ACL_EXECUTE_CHR 'X' @@ -143,7 +142,7 @@ typedef ArrayType Acl; /* * Bitmasks defining "all rights" for each supported object type */ -#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER) +#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_REFERENCES|ACL_TRIGGER) #define ACL_ALL_RIGHTS_SEQUENCE (ACL_USAGE|ACL_SELECT|ACL_UPDATE) #define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT) #define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) diff --git a/src/test/regress/expected/dependency.out b/src/test/regress/expected/dependency.out index ba65a351bc..82c1bf0138 100644 --- a/src/test/regress/expected/dependency.out +++ b/src/test/regress/expected/dependency.out @@ -68,19 +68,19 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "deptest_pkey" fo GRANT ALL ON deptest1 TO regression_user2; RESET SESSION AUTHORIZATION; \z deptest1 - Access privileges for database "regression" - Schema | Name | Type | Access privileges ---------+----------+-------+---------------------------------------------------------------------------------------------------------------------------------------- - public | deptest1 | table | {regression_user0=arwdRxt/regression_user0,regression_user1=a*r*w*d*R*x*t*/regression_user0,regression_user2=arwdRxt/regression_user1} + Access privileges for database "regression" + Schema | Name | Type | Access privileges +--------+----------+-------+------------------------------------------------------------------------------------------------------------------------------------ + public | deptest1 | table | {regression_user0=arwdxt/regression_user0,regression_user1=a*r*w*d*x*t*/regression_user0,regression_user2=arwdxt/regression_user1} (1 row) DROP OWNED BY regression_user1; -- all grants revoked \z deptest1 - Access privileges for database "regression" - Schema | Name | Type | Access privileges ---------+----------+-------+--------------------------------------------- - public | deptest1 | table | {regression_user0=arwdRxt/regression_user0} + Access privileges for database "regression" + Schema | Name | Type | Access privileges +--------+----------+-------+-------------------------------------------- + public | deptest1 | table | {regression_user0=arwdxt/regression_user0} (1 row) -- table was dropped diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 201e8a11d3..5404969c60 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -301,7 +301,7 @@ select has_table_privilege('pg_authid','sel'); ERROR: unrecognized privilege type: "sel" select has_table_privilege(-999999,'pg_authid','update'); ERROR: role with OID 4293967297 does not exist -select has_table_privilege(1,'rule'); +select has_table_privilege(1,'select'); ERROR: relation with OID 1 does not exist -- superuser \c - @@ -331,11 +331,13 @@ from (select oid from pg_roles where rolname = current_user) as t2; t (1 row) +-- 'rule' privilege no longer exists, but for backwards compatibility +-- has_table_privilege still recognizes the keyword and says FALSE select has_table_privilege(current_user,t1.oid,'rule') from (select oid from pg_class where relname = 'pg_authid') as t1; has_table_privilege --------------------- - t + f (1 row) select has_table_privilege(current_user,t1.oid,'references') @@ -415,13 +417,6 @@ from (select oid from pg_roles where rolname = current_user) as t2; f (1 row) -select has_table_privilege(current_user,t1.oid,'rule') -from (select oid from pg_class where relname = 'pg_class') as t1; - has_table_privilege ---------------------- - f -(1 row) - select has_table_privilege(current_user,t1.oid,'references') from (select oid from pg_class where relname = 'pg_class') as t1; has_table_privilege @@ -497,13 +492,6 @@ from (select oid from pg_roles where rolname = current_user) as t2; f (1 row) -select has_table_privilege(current_user,t1.oid,'rule') -from (select oid from pg_class where relname = 'atest1') as t1; - has_table_privilege ---------------------- - f -(1 row) - select has_table_privilege(current_user,t1.oid,'references') from (select oid from pg_class where relname = 'atest1') as t1; has_table_privilege diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 3b96abe87e..4c0d9c43f2 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -214,7 +214,7 @@ select has_table_privilege('pg_shad','select'); select has_table_privilege('nosuchuser','pg_authid','select'); select has_table_privilege('pg_authid','sel'); select has_table_privilege(-999999,'pg_authid','update'); -select has_table_privilege(1,'rule'); +select has_table_privilege(1,'select'); -- superuser \c - @@ -227,6 +227,8 @@ from (select oid from pg_roles where rolname = current_user) as t2; select has_table_privilege(t2.oid,'pg_authid','delete') from (select oid from pg_roles where rolname = current_user) as t2; +-- 'rule' privilege no longer exists, but for backwards compatibility +-- has_table_privilege still recognizes the keyword and says FALSE select has_table_privilege(current_user,t1.oid,'rule') from (select oid from pg_class where relname = 'pg_authid') as t1; select has_table_privilege(current_user,t1.oid,'references') @@ -258,8 +260,6 @@ from (select oid from pg_roles where rolname = current_user) as t2; select has_table_privilege(t2.oid,'pg_class','delete') from (select oid from pg_roles where rolname = current_user) as t2; -select has_table_privilege(current_user,t1.oid,'rule') -from (select oid from pg_class where relname = 'pg_class') as t1; select has_table_privilege(current_user,t1.oid,'references') from (select oid from pg_class where relname = 'pg_class') as t1; @@ -286,8 +286,6 @@ from (select oid from pg_roles where rolname = current_user) as t2; select has_table_privilege(t2.oid,'atest1','delete') from (select oid from pg_roles where rolname = current_user) as t2; -select has_table_privilege(current_user,t1.oid,'rule') -from (select oid from pg_class where relname = 'atest1') as t1; select has_table_privilege(current_user,t1.oid,'references') from (select oid from pg_class where relname = 'atest1') as t1; -- 2.40.0