]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix column privilege checking for cases where parent and child have different
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Mar 2009 17:30:29 +0000 (17:30 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 5 Mar 2009 17:30:29 +0000 (17:30 +0000)
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.

src/backend/optimizer/prep/prepunion.c
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index 13d08eef3eec666f984f6bc310d49bb24bcfb59e..43aa515ae5efa404d133c1c41fb6df69587ca7ba 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.166 2009/02/25 03:30:37 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.167 2009/03/05 17:30:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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);
@@ -1295,6 +1298,19 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
                appinfo->parent_reloid = parentOID;
                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.
                 */
@@ -1437,6 +1453,59 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
        *translated_vars = vars;
 }
 
+/*
+ * 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
index 8129f5b915b0e3d8c8a6bbd91f5d72516ae98f11..a17ff59d0c81182b11f094c21ec7c1ef00cc55e0 100644 (file)
@@ -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;
index 2316d1161628fe11d920ed47fe8d3986d28eda70..5aa1012f3f619de7befd2d2222874d6a6c938a7e 100644 (file)
@@ -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;