diff options
author | Tom Lane | 2009-03-05 17:30:29 +0000 |
---|---|---|
committer | Tom Lane | 2009-03-05 17:30:29 +0000 |
commit | c2ac14c0b403b2772778445e9244aa0df2ae65d1 (patch) | |
tree | fdf7bd6d5a04632bd204926a716ff6e28ec7c0db | |
parent | 3b0614d01166c6acb106641de235a27bccf7b1af (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.c | 69 | ||||
-rw-r--r-- | src/test/regress/expected/privileges.out | 45 | ||||
-rw-r--r-- | src/test/regress/sql/privileges.sql | 26 |
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; |