Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb59c03f

Browse files
committed
Make view/rule permission checking behave properly with
subqueries in the rule.
1 parent7c57890 commitb59c03f

File tree

1 file changed

+126
-56
lines changed

1 file changed

+126
-56
lines changed

‎src/backend/rewrite/locks.c

Lines changed: 126 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.29 2000/05/30 00:49:51 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.30 2000/07/09 04:56:32 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -17,9 +17,9 @@
1717
#include"catalog/pg_shadow.h"
1818
#include"optimizer/clauses.h"
1919
#include"rewrite/locks.h"
20+
#include"parser/parsetree.h"
2021
#include"utils/acl.h"
2122
#include"utils/syscache.h"
22-
#include"utils/syscache.h"
2323

2424

2525
/*
@@ -152,93 +152,163 @@ matchLocks(CmdType event,
152152
}
153153

154154

155+
/*
156+
* Check the access permissions of tables that are referred to by a rule.
157+
* We want to check the access permissions using the userid of the rule's
158+
* owner, *not* of the current user (the one accessing the rule). So, we
159+
* do the permission check here and set skipAcl = TRUE in each of the rule's
160+
* RTEs, to prevent the executor from running another check with the current
161+
* user's ID.
162+
*
163+
* XXX This routine is called before the rule's query tree has been copied
164+
* out of the relcache entry where it is kept. Therefore, when we set
165+
* skipAcl = TRUE, we are destructively modifying the relcache entry for
166+
* the event relation! This seems fairly harmless because the relcache
167+
* querytree is only used as a source for the rewriter, but it's a tad
168+
* unclean anyway.
169+
*
170+
* Note that we must check permissions every time, even if skipAcl was
171+
* already set TRUE by a prior call. This ensures that we enforce the
172+
* current permission settings for each referenced table, even if they
173+
* have changed since the relcache entry was loaded.
174+
*/
175+
176+
typedefstruct
177+
{
178+
char*evowner;
179+
}checkLockPerms_context;
180+
181+
staticbool
182+
checkLockPerms_walker(Node*node,
183+
checkLockPerms_context*context)
184+
{
185+
if (node==NULL)
186+
return false;
187+
if (IsA(node,SubLink))
188+
{
189+
/*
190+
* Standard expression_tree_walker will not recurse into
191+
* subselect, but here we must do so.
192+
*/
193+
SubLink*sub= (SubLink*)node;
194+
195+
if (checkLockPerms_walker((Node*) (sub->lefthand),context))
196+
return true;
197+
if (checkLockPerms_walker((Node*) (sub->subselect),context))
198+
return true;
199+
return false;
200+
}
201+
if (IsA(node,Query))
202+
{
203+
/* Reach here after recursing down into subselect above... */
204+
Query*qry= (Query*)node;
205+
intrtablength=length(qry->rtable);
206+
inti;
207+
208+
/* Check all the RTEs in this query node, except OLD and NEW */
209+
for (i=1;i <=rtablength;i++)
210+
{
211+
RangeTblEntry*rte=rt_fetch(i,qry->rtable);
212+
int32reqperm;
213+
int32aclcheck_res;
214+
215+
if (rte->ref!=NULL)
216+
{
217+
if (strcmp(rte->ref->relname,"*NEW*")==0)
218+
continue;
219+
if (strcmp(rte->ref->relname,"*OLD*")==0)
220+
continue;
221+
}
222+
223+
if (i==qry->resultRelation)
224+
switch (qry->commandType)
225+
{
226+
caseCMD_INSERT:
227+
reqperm=ACL_AP;
228+
break;
229+
default:
230+
reqperm=ACL_WR;
231+
break;
232+
}
233+
else
234+
reqperm=ACL_RD;
235+
236+
aclcheck_res=pg_aclcheck(rte->relname,
237+
context->evowner,
238+
reqperm);
239+
if (aclcheck_res!=ACLCHECK_OK)
240+
elog(ERROR,"%s: %s",
241+
rte->relname,
242+
aclcheck_error_strings[aclcheck_res]);
243+
244+
/*
245+
* Mark RTE to prevent executor from checking again with the
246+
* current user's ID...
247+
*/
248+
rte->skipAcl= true;
249+
}
250+
251+
/* If there are sublinks, search for them and check their RTEs */
252+
if (qry->hasSubLinks)
253+
{
254+
if (checkLockPerms_walker((Node*) (qry->targetList),context))
255+
return true;
256+
if (checkLockPerms_walker((Node*) (qry->qual),context))
257+
return true;
258+
if (checkLockPerms_walker((Node*) (qry->havingQual),context))
259+
return true;
260+
}
261+
return false;
262+
}
263+
returnexpression_tree_walker(node,checkLockPerms_walker,
264+
(void*)context);
265+
}
266+
155267
void
156268
checkLockPerms(List*locks,Query*parsetree,intrt_index)
157269
{
270+
RangeTblEntry*rte;
158271
Relationev_rel;
159272
HeapTupleusertup;
160-
char*evowner;
161-
RangeTblEntry*rte;
162-
int32reqperm;
163-
int32aclcheck_res;
164-
inti;
273+
Form_pg_shadowuserform;
274+
checkLockPerms_contextcontext;
165275
List*l;
166276

167277
if (locks==NIL)
168-
return;
278+
return;/* nothing to check */
169279

170280
/*
171-
* Get the usename of therules event relation owner
281+
* Get the usename of therule's event relation owner
172282
*/
173-
rte=(RangeTblEntry*)nth(rt_index-1,parsetree->rtable);
283+
rte=rt_fetch(rt_index,parsetree->rtable);
174284
ev_rel=heap_openr(rte->relname,AccessShareLock);
175285
usertup=SearchSysCacheTuple(SHADOWSYSID,
176286
ObjectIdGetDatum(ev_rel->rd_rel->relowner),
177287
0,0,0);
178288
if (!HeapTupleIsValid(usertup))
179-
{
180289
elog(ERROR,"cache lookup for userid %d failed",
181290
ev_rel->rd_rel->relowner);
182-
}
291+
userform= (Form_pg_shadow)GETSTRUCT(usertup);
292+
context.evowner=pstrdup(NameStr(userform->usename));
183293
heap_close(ev_rel,AccessShareLock);
184-
evowner=pstrdup(NameStr(((Form_pg_shadow)GETSTRUCT(usertup))->usename));
185294

186295
/*
187-
* Check all the locks, that should get fired on this query
296+
* Check all the locks that should get fired on this query
188297
*/
189298
foreach(l,locks)
190299
{
191300
RewriteRule*onelock= (RewriteRule*)lfirst(l);
192301
List*action;
193302

194303
/*
195-
* In each lock check every action
304+
* In each lock check every action. We must scan the action
305+
* recursively in case there are any sub-queries within it.
196306
*/
197307
foreach(action,onelock->actions)
198308
{
199309
Query*query= (Query*)lfirst(action);
200310

201-
/*
202-
* In each action check every rangetable entry for read/write
203-
* permission of the event relations owner depending on if
204-
* it's the result relation (write) or not (read)
205-
*/
206-
for (i=2;i<length(query->rtable);i++)
207-
{
208-
if (i+1==query->resultRelation)
209-
switch (query->resultRelation)
210-
{
211-
caseCMD_INSERT:
212-
reqperm=ACL_AP;
213-
break;
214-
default:
215-
reqperm=ACL_WR;
216-
break;
217-
}
218-
else
219-
reqperm=ACL_RD;
220-
221-
rte= (RangeTblEntry*)nth(i,query->rtable);
222-
aclcheck_res=pg_aclcheck(rte->relname,
223-
evowner,reqperm);
224-
if (aclcheck_res!=ACLCHECK_OK)
225-
{
226-
elog(ERROR,"%s: %s",
227-
rte->relname,
228-
aclcheck_error_strings[aclcheck_res]);
229-
}
230-
231-
/*
232-
* So this is allowed due to the permissions of the rules
233-
* event relation owner. But let's see if the next one too
234-
*/
235-
rte->skipAcl= TRUE;
236-
}
311+
checkLockPerms_walker((Node*)query,&context);
237312
}
238313
}
239-
240-
/*
241-
* Phew, that was close
242-
*/
243-
return;
244314
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp