aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2004-01-14 23:01:55 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2004-01-14 23:01:55 +0000
commitcfd7fb7ed4b66da97f88338d991843fa7e2fe59d (patch)
treef433f1281eba10a7ab2e563fa39eaf3228df32e8 /src
parent01d320d421b3f82de799e86e8b9adac27c2f9a26 (diff)
downloadpostgresql-cfd7fb7ed4b66da97f88338d991843fa7e2fe59d.tar.gz
postgresql-cfd7fb7ed4b66da97f88338d991843fa7e2fe59d.zip
Fix permission-checking bug reported by Tim Burgess 10-Feb-03 (this time
for sure...). Rather than relying on the query context of a rangetable entry to identify what permissions it wants checked, store a full AclMode mask in each RTE, and check exactly those bits. This allows an RTE specifying, say, INSERT privilege on a view to be copied into a derived UPDATE query without changing meaning. Per recent discussion thread. initdb forced due to change of stored rule representation.
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/view.c6
-rw-r--r--src/backend/executor/execMain.c120
-rw-r--r--src/backend/executor/nodeSubplan.c7
-rw-r--r--src/backend/nodes/copyfuncs.c5
-rw-r--r--src/backend/nodes/equalfuncs.c5
-rw-r--r--src/backend/nodes/outfuncs.c7
-rw-r--r--src/backend/nodes/readfuncs.c7
-rw-r--r--src/backend/optimizer/path/allpaths.c5
-rw-r--r--src/backend/parser/analyze.c22
-rw-r--r--src/backend/parser/parse_clause.c20
-rw-r--r--src/backend/parser/parse_relation.c48
-rw-r--r--src/backend/rewrite/rewriteDefine.c10
-rw-r--r--src/backend/rewrite/rewriteHandler.c12
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/executor/executor.h4
-rw-r--r--src/include/nodes/parsenodes.h66
-rw-r--r--src/include/parser/parse_clause.h4
-rw-r--r--src/include/utils/acl.h14
18 files changed, 183 insertions, 183 deletions
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 346867bbfc4..a8c3cb5ce07 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.80 2004/01/10 23:28:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.81 2004/01/14 23:01:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -297,8 +297,8 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse)
makeAlias("*NEW*", NIL),
false, false);
/* Must override addRangeTableEntry's default access-check flags */
- rt_entry1->checkForRead = false;
- rt_entry2->checkForRead = false;
+ rt_entry1->requiredPerms = 0;
+ rt_entry2->requiredPerms = 0;
new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 9d64c979e08..a340477c47a 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.226 2004/01/10 23:28:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.227 2004/01/14 23:01:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,8 +86,8 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate);
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
-static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
-static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation);
+static void ExecCheckRTEPerms(RangeTblEntry *rte);
+static void ExecCheckXactReadOnly(Query *parsetree);
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
evalPlanQual *priorepq);
static void EvalPlanQualStop(evalPlanQual *epq);
@@ -136,8 +136,8 @@ ExecutorStart(QueryDesc *queryDesc, bool useCurrentSnapshot, bool explainOnly)
* If the transaction is read-only, we need to check if any writes are
* planned to non-temporary tables.
*/
- if (!explainOnly)
- ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation);
+ if (XactReadOnly && !explainOnly)
+ ExecCheckXactReadOnly(queryDesc->parsetree);
/*
* Build EState, switch into per-query memory context for startup.
@@ -351,7 +351,7 @@ ExecutorRewind(QueryDesc *queryDesc)
* Check access permissions for all relations listed in a range table.
*/
void
-ExecCheckRTPerms(List *rangeTable, CmdType operation)
+ExecCheckRTPerms(List *rangeTable)
{
List *lp;
@@ -359,7 +359,7 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation)
{
RangeTblEntry *rte = lfirst(lp);
- ExecCheckRTEPerms(rte, operation);
+ ExecCheckRTEPerms(rte);
}
}
@@ -368,18 +368,18 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation)
* Check access permissions for a single RTE.
*/
static void
-ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
+ExecCheckRTEPerms(RangeTblEntry *rte)
{
+ AclMode requiredPerms;
Oid relOid;
AclId userid;
- AclResult aclcheck_result;
/*
* If it's a subquery, recursively examine its rangetable.
*/
if (rte->rtekind == RTE_SUBQUERY)
{
- ExecCheckRTPerms(rte->subquery->rtable, operation);
+ ExecCheckRTPerms(rte->subquery->rtable);
return;
}
@@ -391,6 +391,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
if (rte->rtekind != RTE_RELATION)
return;
+ /*
+ * No work if requiredPerms is empty.
+ */
+ requiredPerms = rte->requiredPerms;
+ if (requiredPerms == 0)
+ return;
+
relOid = rte->relid;
/*
@@ -404,77 +411,68 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
*/
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
-#define CHECK(MODE) pg_class_aclcheck(relOid, userid, MODE)
+ /*
+ * For each bit in requiredPerms, apply the required check. (We can't
+ * do this in one aclcheck call because aclcheck treats multiple bits
+ * as OR semantics, when we want AND.)
+ *
+ * We use a well-known cute trick for isolating the rightmost one-bit
+ * in a nonzero word. See nodes/bitmapset.c for commentary.
+ */
+#define RIGHTMOST_ONE(x) ((int32) (x) & -((int32) (x)))
- if (rte->checkForRead)
+ while (requiredPerms != 0)
{
- aclcheck_result = CHECK(ACL_SELECT);
- if (aclcheck_result != ACLCHECK_OK)
- aclcheck_error(aclcheck_result, ACL_KIND_CLASS,
- get_rel_name(relOid));
- }
+ AclMode thisPerm;
+ AclResult aclcheck_result;
- if (rte->checkForWrite)
- {
- /*
- * Note: write access in a SELECT context means SELECT FOR UPDATE.
- * Right now we don't distinguish that from true update as far as
- * permissions checks are concerned.
- */
- switch (operation)
- {
- case CMD_INSERT:
- aclcheck_result = CHECK(ACL_INSERT);
- break;
- case CMD_SELECT:
- case CMD_UPDATE:
- aclcheck_result = CHECK(ACL_UPDATE);
- break;
- case CMD_DELETE:
- aclcheck_result = CHECK(ACL_DELETE);
- break;
- default:
- elog(ERROR, "unrecognized operation code: %d",
- (int) operation);
- aclcheck_result = ACLCHECK_OK; /* keep compiler quiet */
- break;
- }
+ thisPerm = RIGHTMOST_ONE(requiredPerms);
+ requiredPerms &= ~thisPerm;
+
+ aclcheck_result = pg_class_aclcheck(relOid, userid, thisPerm);
if (aclcheck_result != ACLCHECK_OK)
aclcheck_error(aclcheck_result, ACL_KIND_CLASS,
get_rel_name(relOid));
}
}
+/*
+ * Check that the query does not imply any writes to non-temp tables.
+ */
static void
-ExecCheckXactReadOnly(Query *parsetree, CmdType operation)
+ExecCheckXactReadOnly(Query *parsetree)
{
- if (!XactReadOnly)
- return;
+ List *lp;
- /* CREATE TABLE AS or SELECT INTO */
- if (operation == CMD_SELECT && parsetree->into != NULL)
+ /*
+ * CREATE TABLE AS or SELECT INTO?
+ *
+ * XXX should we allow this if the destination is temp?
+ */
+ if (parsetree->into != NULL)
goto fail;
- if (operation == CMD_DELETE || operation == CMD_INSERT
- || operation == CMD_UPDATE)
+ /* Fail if write permissions are requested on any non-temp table */
+ foreach(lp, parsetree->rtable)
{
- List *lp;
+ RangeTblEntry *rte = lfirst(lp);
- foreach(lp, parsetree->rtable)
+ if (rte->rtekind == RTE_SUBQUERY)
{
- RangeTblEntry *rte = lfirst(lp);
+ ExecCheckXactReadOnly(rte->subquery);
+ continue;
+ }
- if (rte->rtekind != RTE_RELATION)
- continue;
+ if (rte->rtekind != RTE_RELATION)
+ continue;
- if (!rte->checkForWrite)
- continue;
+ if ((rte->requiredPerms & (~ACL_SELECT)) == 0)
+ continue;
- if (isTempNamespace(get_rel_namespace(rte->relid)))
- continue;
+ if (isTempNamespace(get_rel_namespace(rte->relid)))
+ continue;
- goto fail;
- }
+ goto fail;
}
return;
@@ -511,7 +509,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
* rangetable here --- subplan RTEs will be checked during
* ExecInitSubPlan().
*/
- ExecCheckRTPerms(parseTree->rtable, operation);
+ ExecCheckRTPerms(parseTree->rtable);
/*
* get information from query descriptor
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index da7d5915f20..1624f41fd54 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.59 2003/11/29 19:51:48 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.60 2004/01/14 23:01:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -670,10 +670,9 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
MemoryContext oldcontext;
/*
- * Do access checking on the rangetable entries in the subquery. Here,
- * we assume the subquery is a SELECT.
+ * Do access checking on the rangetable entries in the subquery.
*/
- ExecCheckRTPerms(subplan->rtable, CMD_SELECT);
+ ExecCheckRTPerms(subplan->rtable);
/*
* initialize my state
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5a340ebaa94..39f454fd3c9 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.276 2004/01/10 23:28:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.277 2004/01/14 23:01:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1258,8 +1258,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
COPY_NODE_FIELD(eref);
COPY_SCALAR_FIELD(inh);
COPY_SCALAR_FIELD(inFromCl);
- COPY_SCALAR_FIELD(checkForRead);
- COPY_SCALAR_FIELD(checkForWrite);
+ COPY_SCALAR_FIELD(requiredPerms);
COPY_SCALAR_FIELD(checkAsUser);
return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 932d79f31f4..7951fad039c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.214 2004/01/10 23:28:45 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.215 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1574,8 +1574,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
COMPARE_NODE_FIELD(eref);
COMPARE_SCALAR_FIELD(inh);
COMPARE_SCALAR_FIELD(inFromCl);
- COMPARE_SCALAR_FIELD(checkForRead);
- COMPARE_SCALAR_FIELD(checkForWrite);
+ COMPARE_SCALAR_FIELD(requiredPerms);
COMPARE_SCALAR_FIELD(checkAsUser);
return true;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index ce80cae4bdb..cd1fde7b5b7 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.229 2004/01/06 04:31:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.230 2004/01/14 23:01:55 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1358,9 +1358,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
WRITE_BOOL_FIELD(inh);
WRITE_BOOL_FIELD(inFromCl);
- WRITE_BOOL_FIELD(checkForRead);
- WRITE_BOOL_FIELD(checkForWrite);
- WRITE_OID_FIELD(checkAsUser);
+ WRITE_UINT_FIELD(requiredPerms);
+ WRITE_UINT_FIELD(checkAsUser);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index bbfcb1b454e..93c71fd2247 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.164 2004/01/07 18:56:26 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.165 2004/01/14 23:01:55 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -939,9 +939,8 @@ _readRangeTblEntry(void)
READ_BOOL_FIELD(inh);
READ_BOOL_FIELD(inFromCl);
- READ_BOOL_FIELD(checkForRead);
- READ_BOOL_FIELD(checkForWrite);
- READ_OID_FIELD(checkAsUser);
+ READ_UINT_FIELD(requiredPerms);
+ READ_UINT_FIELD(checkAsUser);
READ_DONE();
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 2d724265f06..50d5006a960 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.111 2004/01/05 05:07:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.112 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -227,8 +227,7 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
* it examines the parent's inheritlist entry. There's no need to
* check twice, so turn off access check bits in the original RTE.
*/
- rte->checkForRead = false;
- rte->checkForWrite = false;
+ rte->requiredPerms = 0;
/*
* Initialize to compute size estimates for whole inheritance tree
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 33f32c1b377..89620821347 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.295 2004/01/11 04:58:17 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.296 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -472,7 +472,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
/* set up range table with just the result rel */
qry->resultRelation = setTargetTable(pstate, stmt->relation,
interpretInhOption(stmt->relation->inhOpt),
- true);
+ true,
+ ACL_DELETE);
qry->distinctClause = NIL;
@@ -539,7 +540,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* table is not added to the joinlist or namespace.
*/
qry->resultRelation = setTargetTable(pstate, stmt->relation,
- false, false);
+ false, false, ACL_INSERT);
/*
* Is it INSERT ... SELECT or INSERT ... VALUES?
@@ -1721,8 +1722,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
makeAlias("*NEW*", NIL),
false, true);
/* Must override addRangeTableEntry's default access-check flags */
- oldrte->checkForRead = false;
- newrte->checkForRead = false;
+ oldrte->requiredPerms = 0;
+ newrte->requiredPerms = 0;
/*
* They must be in the namespace too for lookup purposes, but only add
@@ -1820,8 +1821,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
newrte = addRangeTableEntry(sub_pstate, stmt->relation,
makeAlias("*NEW*", NIL),
false, false);
- oldrte->checkForRead = false;
- newrte->checkForRead = false;
+ oldrte->requiredPerms = 0;
+ newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true);
addRTEtoQuery(sub_pstate, newrte, false, true);
@@ -2493,7 +2494,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
qry->resultRelation = setTargetTable(pstate, stmt->relation,
interpretInhOption(stmt->relation->inhOpt),
- true);
+ true,
+ ACL_UPDATE);
/*
* the FROM clause is non-standard SQL syntax. We used to be able to
@@ -2880,7 +2882,7 @@ transformForUpdate(Query *qry, List *forUpdate)
case RTE_RELATION:
if (!intMember(i, rowMarks)) /* avoid duplicates */
rowMarks = lappendi(rowMarks, i);
- rte->checkForWrite = true;
+ rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
/*
@@ -2915,7 +2917,7 @@ transformForUpdate(Query *qry, List *forUpdate)
case RTE_RELATION:
if (!intMember(i, rowMarks)) /* avoid duplicates */
rowMarks = lappendi(rowMarks, i);
- rte->checkForWrite = true;
+ rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
/*
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index d4e6747df6f..8b7be43af13 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.125 2003/11/29 19:51:51 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.126 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -116,11 +116,14 @@ transformFromClause(ParseState *pstate, List *frmList)
* to check for namespace conflict; we assume that the namespace was
* initially empty in these cases.)
*
+ * Finally, we mark the relation as requiring the permissions specified
+ * by requiredPerms.
+ *
* Returns the rangetable index of the target relation.
*/
int
setTargetTable(ParseState *pstate, RangeVar *relation,
- bool inh, bool alsoSource)
+ bool inh, bool alsoSource, AclMode requiredPerms)
{
RangeTblEntry *rte;
int rtindex;
@@ -149,16 +152,15 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
/*
- * Override addRangeTableEntry's default checkForRead, and instead
- * mark target table as requiring write access.
+ * Override addRangeTableEntry's default ACL_SELECT permissions check,
+ * and instead mark target table as requiring exactly the specified
+ * permissions.
*
* If we find an explicit reference to the rel later during parse
- * analysis, scanRTEForColumn will change checkForRead to 'true'
- * again. That can't happen for INSERT but it is possible for UPDATE
- * and DELETE.
+ * analysis, scanRTEForColumn will add the ACL_SELECT bit back again.
+ * That can't happen for INSERT but it is possible for UPDATE and DELETE.
*/
- rte->checkForRead = false;
- rte->checkForWrite = true;
+ rte->requiredPerms = requiredPerms;
/*
* If UPDATE/DELETE, add table to joinlist and namespace.
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 76caa60aeb2..3e314bea963 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.91 2003/11/29 19:51:52 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.92 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -437,7 +437,7 @@ RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
* nothing. It might seem that we need to propagate the mark to all the
* contained RTEs, but that is not necessary. This is so because a join
* expression can only appear in a FROM clause, and any table named in
- * FROM will be marked checkForRead from the beginning.
+ * FROM will be marked as requiring read access from the beginning.
*/
static Node *
scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
@@ -477,7 +477,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
errmsg("column reference \"%s\" is ambiguous",
colname)));
result = (Node *) make_var(pstate, rte, attnum);
- rte->checkForRead = true;
+ /* Require read access */
+ rte->requiredPerms |= ACL_SELECT;
}
}
@@ -504,7 +505,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
0, 0))
{
result = (Node *) make_var(pstate, rte, attnum);
- rte->checkForRead = true;
+ /* Require read access */
+ rte->requiredPerms |= ACL_SELECT;
}
}
}
@@ -689,7 +691,7 @@ addRangeTableEntry(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should be checked for read/write access rights.
+ * - this RTE should be checked for appropriate access rights.
*
* The initial default on access checks is always check-for-READ-access,
* which is the right thing for all except target tables.
@@ -697,10 +699,9 @@ addRangeTableEntry(ParseState *pstate,
*/
rte->inh = inh;
rte->inFromCl = inFromCl;
- rte->checkForRead = true;
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
+ rte->requiredPerms = ACL_SELECT;
+ rte->checkAsUser = 0; /* not set-uid by default, either */
/*
* Add completed RTE to pstate's range table list, but not to join
@@ -784,7 +785,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should be checked for read/write access rights.
+ * - this RTE should be checked for appropriate access rights.
*
* The initial default on access checks is always check-for-READ-access,
* which is the right thing for all except target tables.
@@ -792,10 +793,9 @@ addRangeTableEntryForRelation(ParseState *pstate,
*/
rte->inh = inh;
rte->inFromCl = inFromCl;
- rte->checkForRead = true;
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
+ rte->requiredPerms = ACL_SELECT;
+ rte->checkAsUser = 0; /* not set-uid by default, either */
/*
* Add completed RTE to pstate's range table list, but not to join
@@ -864,17 +864,16 @@ addRangeTableEntryForSubquery(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should be checked for read/write access rights.
+ * - this RTE should be checked for appropriate access rights.
*
* Subqueries are never checked for access rights.
*----------
*/
rte->inh = false; /* never true for subqueries */
rte->inFromCl = inFromCl;
- rte->checkForRead = false;
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid;
+ rte->requiredPerms = 0;
+ rte->checkAsUser = 0;
/*
* Add completed RTE to pstate's range table list, but not to join
@@ -1034,15 +1033,17 @@ addRangeTableEntryForFunction(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should be checked for read/write access rights.
+ * - this RTE should be checked for appropriate access rights.
+ *
+ * Functions are never checked for access rights (at least, not by
+ * the RTE permissions mechanism).
*----------
*/
rte->inh = false; /* never true for functions */
rte->inFromCl = inFromCl;
- rte->checkForRead = true;
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid;
+ rte->requiredPerms = 0;
+ rte->checkAsUser = 0;
/*
* Add completed RTE to pstate's range table list, but not to join
@@ -1095,17 +1096,16 @@ addRangeTableEntryForJoin(ParseState *pstate,
* Flags:
* - this RTE should be expanded to include descendant tables,
* - this RTE is in the FROM clause,
- * - this RTE should be checked for read/write access rights.
+ * - this RTE should be checked for appropriate access rights.
*
* Joins are never checked for access rights.
*----------
*/
rte->inh = false; /* never true for joins */
rte->inFromCl = inFromCl;
- rte->checkForRead = false;
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid;
+ rte->requiredPerms = 0;
+ rte->checkAsUser = 0;
/*
* Add completed RTE to pstate's range table list, but not to join
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 90497cf5b88..f1cbe96fd2a 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.91 2003/11/29 19:51:55 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.92 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@
static void setRuleCheckAsUser(Query *qry, AclId userid);
-static bool setRuleCheckAsUser_walker(Node *node, Oid *context);
+static bool setRuleCheckAsUser_walker(Node *node, AclId *context);
/*
@@ -494,8 +494,8 @@ DefineQueryRewrite(RuleStmt *stmt)
* 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
* checkAsUser field of the *NEW* entry is irrelevant because that entry's
- * checkFor bits will never be set. However, for other types of rules it's
- * important to set these fields to match the rule owner. So we just set
+ * requiredPerms bits will always be zero. However, for other types of rules
+ * it's important to set these fields to match the rule owner. So we just set
* them always.
*/
static void
@@ -528,7 +528,7 @@ setRuleCheckAsUser(Query *qry, AclId userid)
* Expression-tree walker to find sublink queries
*/
static bool
-setRuleCheckAsUser_walker(Node *node, Oid *context)
+setRuleCheckAsUser_walker(Node *node, AclId *context)
{
if (node == NULL)
return false;
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 3f69110a36a..e66eb905f56 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.132 2004/01/14 03:39:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.133 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -655,13 +655,11 @@ ApplyRetrieveRule(Query *parsetree,
*/
subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
Assert(subrte->relid == relation->rd_id);
- subrte->checkForRead = rte->checkForRead;
- subrte->checkForWrite = rte->checkForWrite;
+ subrte->requiredPerms = rte->requiredPerms;
subrte->checkAsUser = rte->checkAsUser;
- rte->checkForRead = false; /* no permission check on subquery itself */
- rte->checkForWrite = false;
- rte->checkAsUser = InvalidOid;
+ rte->requiredPerms = 0; /* no permission check on subquery itself */
+ rte->checkAsUser = 0;
/*
* FOR UPDATE of view?
@@ -713,7 +711,7 @@ markQueryForUpdate(Query *qry, bool skipOldNew)
{
if (!intMember(rti, qry->rowMarks))
qry->rowMarks = lappendi(qry->rowMarks, rti);
- rte->checkForWrite = true;
+ rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
}
else if (rte->rtekind == RTE_SUBQUERY)
{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 1910e33e3b1..7dd262c1e46 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.215 2004/01/06 23:55:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.216 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200401061
+#define CATALOG_VERSION_NO 200401141
#endif
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 8f1dc7fafaf..050894708c8 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.104 2003/12/18 20:21:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.105 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,7 +91,7 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
extern void ExecutorRewind(QueryDesc *queryDesc);
-extern void ExecCheckRTPerms(List *rangeTable, CmdType operation);
+extern void ExecCheckRTPerms(List *rangeTable);
extern void ExecEndPlan(PlanState *planstate, EState *estate);
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 8b6446d8605..01ff239a444 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.252 2004/01/10 23:28:45 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.253 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,32 @@ typedef enum QuerySource
QSRC_NON_INSTEAD_RULE /* added by non-INSTEAD rule */
} QuerySource;
+/*
+ * Grantable rights are encoded so that we can OR them together in a bitmask.
+ * The present representation of AclItem limits us to 15 distinct rights,
+ * even though AclMode is defined as uint32. See utils/acl.h.
+ *
+ * Caution: changing these codes breaks stored ACLs, hence forces initdb.
+ */
+typedef uint32 AclMode; /* a bitmask of privilege bits */
+
+#define ACL_INSERT (1<<0) /* for relations */
+#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 ACL_EXECUTE (1<<7) /* for functions */
+#define ACL_USAGE (1<<8) /* for languages and namespaces */
+#define ACL_CREATE (1<<9) /* for namespaces and databases */
+#define ACL_CREATE_TEMP (1<<10) /* for databases */
+#define N_ACL_RIGHTS 11 /* 1 plus the last 1<<x */
+#define ACL_ALL_RIGHTS (-1) /* all-privileges marker in GRANT list */
+#define ACL_NO_RIGHTS 0
+/* Currently, SELECT ... FOR UPDATE requires UPDATE privileges */
+#define ACL_SELECT_FOR_UPDATE ACL_UPDATE
+
/*****************************************************************************
* Query Tree
@@ -425,12 +451,13 @@ typedef struct DefElem
* column names processed later, and it also shouldn't affect the
* expansion of '*'.
*
- * checkForRead, checkForWrite, and checkAsUser control run-time access
- * permissions checks. A rel will be checked for read or write access
- * (or both, or neither) per checkForRead and checkForWrite. If
- * checkAsUser is not InvalidOid, then do the permissions checks using
- * the access rights of that user, not the current effective user ID.
- * (This allows rules to act as setuid gateways.)
+ * requiredPerms and checkAsUser specify run-time access permissions
+ * checks to be performed at query startup. The user must have *all*
+ * of the permissions that are OR'd together in requiredPerms (zero
+ * indicates no permissions checking). If checkAsUser is not zero,
+ * then do the permissions checks using the access rights of that user,
+ * not the current effective user ID. (This allows rules to act as
+ * setuid gateways.)
*--------------------
*/
typedef enum RTEKind
@@ -490,9 +517,8 @@ typedef struct RangeTblEntry
Alias *eref; /* expanded reference names */
bool inh; /* inheritance requested? */
bool inFromCl; /* present in FROM clause */
- bool checkForRead; /* check rel for read access */
- bool checkForWrite; /* check rel for write access */
- Oid checkAsUser; /* if not zero, check access as this user */
+ AclMode requiredPerms; /* bitmask of required access permissions */
+ AclId checkAsUser; /* if not zero, check access as this user */
} RangeTblEntry;
/*
@@ -809,26 +835,6 @@ typedef enum GrantObjectType
ACL_OBJECT_NAMESPACE /* namespace */
} GrantObjectType;
-/*
- * Grantable rights are encoded so that we can OR them together in a bitmask.
- * The present representation of AclItem limits us to 15 distinct rights.
- * Caution: changing these codes breaks stored ACLs, hence forces initdb.
- */
-#define ACL_INSERT (1<<0) /* for relations */
-#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 ACL_EXECUTE (1<<7) /* for functions */
-#define ACL_USAGE (1<<8) /* for languages and namespaces */
-#define ACL_CREATE (1<<9) /* for namespaces and databases */
-#define ACL_CREATE_TEMP (1<<10) /* for databases */
-#define N_ACL_RIGHTS 11 /* 1 plus the last 1<<x */
-#define ACL_ALL_RIGHTS (-1) /* all-privileges marker in GRANT list */
-#define ACL_NO_RIGHTS 0
-
typedef struct GrantStmt
{
NodeTag type;
diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h
index a57a80325b5..d91f5e80643 100644
--- a/src/include/parser/parse_clause.h
+++ b/src/include/parser/parse_clause.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.38 2003/11/29 22:41:09 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.39 2004/01/14 23:01:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,7 @@
extern void transformFromClause(ParseState *pstate, List *frmList);
extern int setTargetTable(ParseState *pstate, RangeVar *relation,
- bool inh, bool alsoSource);
+ bool inh, bool alsoSource, AclMode requiredPerms);
extern bool interpretInhOption(InhOption inhOpt);
extern Node *transformWhereClause(ParseState *pstate, Node *clause,
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index be34fcce5ce..efe7af30b20 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.65 2003/11/29 22:41:15 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.66 2004/01/14 23:01:55 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@@ -28,7 +28,12 @@
#include "utils/array.h"
-/* typedef AclId is declared in c.h */
+/*
+ * typedef AclId is declared in c.h
+ *
+ * typedef AclMode is declared in parsenodes.h, also the individual privilege
+ * bit meanings are defined there
+ */
#define ACL_ID_WORLD 0 /* placeholder for id in a WORLD acl item */
@@ -40,11 +45,6 @@
#define ACL_IDTYPE_GID 0x02 /* group id - from pg_group */
/*
- * AclMode a bitmask of privilege bits
- */
-typedef uint32 AclMode;
-
-/*
* AclItem
*
* The IDTYPE included in ai_privs identifies the type of the grantee ID.