summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2009-03-05 17:30:29 +0000
committerTom Lane2009-03-05 17:30:29 +0000
commitc2ac14c0b403b2772778445e9244aa0df2ae65d1 (patch)
treefdf7bd6d5a04632bd204926a716ff6e28ec7c0db
parent3b0614d01166c6acb106641de235a27bccf7b1af (diff)
Fix column privilege checking for cases where parent and child have different
attribute numbering. Also, a parent whole-row reference should not require select privilege on child columns that aren't inherited from the parent. Problem diagnosed by KaiGai Kohei, though this isn't exactly his patch.
-rw-r--r--src/backend/optimizer/prep/prepunion.c69
-rw-r--r--src/test/regress/expected/privileges.out45
-rw-r--r--src/test/regress/sql/privileges.sql26
3 files changed, 140 insertions, 0 deletions
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index cbb78128f4..6698917987 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -30,6 +30,7 @@
#include "access/heapam.h"
+#include "access/sysattr.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
@@ -95,6 +96,8 @@ static void make_inh_translation_list(Relation oldrelation,
Relation newrelation,
Index newvarno,
List **translated_vars);
+static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
+ List *translated_vars);
static Node *adjust_appendrel_attrs_mutator(Node *node,
AppendRelInfo *context);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
@@ -1296,6 +1299,19 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
appinfos = lappend(appinfos, appinfo);
/*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do this).
+ * But if this is the parent table, leave copyObject's result alone.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ appinfo->translated_vars);
+ childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
+ appinfo->translated_vars);
+ }
+
+ /*
* Build a RowMarkClause if parent is marked FOR UPDATE/SHARE.
*/
if (oldrc)
@@ -1438,6 +1454,59 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
}
/*
+ * translate_col_privs
+ * Translate a bitmapset representing per-column privileges from the
+ * parent rel's attribute numbering to the child's.
+ *
+ * The only surprise here is that we don't translate a parent whole-row
+ * reference into a child whole-row reference. That would mean requiring
+ * permissions on all child columns, which is overly strict, since the
+ * query is really only going to reference the inherited columns. Instead
+ * we set the per-column bits for all inherited columns.
+ */
+static Bitmapset *
+translate_col_privs(const Bitmapset *parent_privs,
+ List *translated_vars)
+{
+ Bitmapset *child_privs = NULL;
+ bool whole_row;
+ int attno;
+ ListCell *lc;
+
+ /* System attributes have the same numbers in all tables */
+ for (attno = FirstLowInvalidHeapAttributeNumber+1; attno < 0; attno++)
+ {
+ if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
+ parent_privs))
+ child_privs = bms_add_member(child_privs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* Check if parent has whole-row reference */
+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
+ parent_privs);
+
+ /* And now translate the regular user attributes, using the vars list */
+ attno = InvalidAttrNumber;
+ foreach(lc, translated_vars)
+ {
+ Var *var = (Var *) lfirst(lc);
+
+ attno++;
+ if (var == NULL) /* ignore dropped columns */
+ continue;
+ Assert(IsA(var, Var));
+ if (whole_row ||
+ bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
+ parent_privs))
+ child_privs = bms_add_member(child_privs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ return child_privs;
+}
+
+/*
* adjust_appendrel_attrs
* Copy the specified query or expression and translate Vars referring
* to the parent rel of the specified AppendRelInfo to refer to the
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 8129f5b915..a17ff59d0c 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -393,6 +393,48 @@ SET SESSION AUTHORIZATION regressuser3;
DELETE FROM atest5 WHERE one = 1; -- fail
ERROR: permission denied for relation atest5
DELETE FROM atest5 WHERE two = 2; -- ok
+-- check inheritance cases
+SET SESSION AUTHORIZATION regressuser1;
+CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
+CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
+CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
+GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
+GRANT SELECT(fx) ON atestc TO regressuser2;
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- ok
+ fx
+----
+(0 rows)
+
+SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
+ERROR: permission denied for relation atestc
+SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
+ERROR: permission denied for relation atestc
+SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
+ERROR: permission denied for relation atestc
+SET SESSION AUTHORIZATION regressuser1;
+GRANT SELECT(fy,oid) ON atestc TO regressuser2;
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- still ok
+ fx
+----
+(0 rows)
+
+SELECT fy FROM atestp2; -- ok
+ fy
+----
+(0 rows)
+
+SELECT atestp2 FROM atestp2; -- ok
+ atestp2
+---------
+(0 rows)
+
+SELECT oid FROM atestp2; -- ok
+ oid
+-----
+(0 rows)
+
-- privileges on functions, languages
-- switch to superuser
\c -
@@ -791,6 +833,9 @@ DROP TABLE atest3;
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
+DROP TABLE atestc;
+DROP TABLE atestp1;
+DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 2316d11616..5aa1012f3f 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -267,6 +267,29 @@ SET SESSION AUTHORIZATION regressuser3;
DELETE FROM atest5 WHERE one = 1; -- fail
DELETE FROM atest5 WHERE two = 2; -- ok
+-- check inheritance cases
+SET SESSION AUTHORIZATION regressuser1;
+CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
+CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
+CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
+GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
+GRANT SELECT(fx) ON atestc TO regressuser2;
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- ok
+SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
+SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
+SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
+
+SET SESSION AUTHORIZATION regressuser1;
+GRANT SELECT(fy,oid) ON atestc TO regressuser2;
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- still ok
+SELECT fy FROM atestp2; -- ok
+SELECT atestp2 FROM atestp2; -- ok
+SELECT oid FROM atestp2; -- ok
+
-- privileges on functions, languages
-- switch to superuser
@@ -466,6 +489,9 @@ DROP TABLE atest3;
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
+DROP TABLE atestc;
+DROP TABLE atestp1;
+DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;