|
7 | 7 | *
|
8 | 8 | *
|
9 | 9 | * 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 $ |
11 | 11 | *
|
12 | 12 | *-------------------------------------------------------------------------
|
13 | 13 | */
|
|
17 | 17 | #include"catalog/pg_shadow.h"
|
18 | 18 | #include"optimizer/clauses.h"
|
19 | 19 | #include"rewrite/locks.h"
|
| 20 | +#include"parser/parsetree.h" |
20 | 21 | #include"utils/acl.h"
|
21 | 22 | #include"utils/syscache.h"
|
22 |
| -#include"utils/syscache.h" |
23 | 23 |
|
24 | 24 |
|
25 | 25 | /*
|
@@ -152,93 +152,163 @@ matchLocks(CmdType event,
|
152 | 152 | }
|
153 | 153 |
|
154 | 154 |
|
| 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 | + |
155 | 267 | void
|
156 | 268 | checkLockPerms(List*locks,Query*parsetree,intrt_index)
|
157 | 269 | {
|
| 270 | +RangeTblEntry*rte; |
158 | 271 | Relationev_rel;
|
159 | 272 | HeapTupleusertup;
|
160 |
| -char*evowner; |
161 |
| -RangeTblEntry*rte; |
162 |
| -int32reqperm; |
163 |
| -int32aclcheck_res; |
164 |
| -inti; |
| 273 | +Form_pg_shadowuserform; |
| 274 | +checkLockPerms_contextcontext; |
165 | 275 | List*l;
|
166 | 276 |
|
167 | 277 | if (locks==NIL)
|
168 |
| -return; |
| 278 | +return;/* nothing to check */ |
169 | 279 |
|
170 | 280 | /*
|
171 |
| - * Get the usename of therules event relation owner |
| 281 | + * Get the usename of therule's event relation owner |
172 | 282 | */
|
173 |
| -rte=(RangeTblEntry*)nth(rt_index-1,parsetree->rtable); |
| 283 | +rte=rt_fetch(rt_index,parsetree->rtable); |
174 | 284 | ev_rel=heap_openr(rte->relname,AccessShareLock);
|
175 | 285 | usertup=SearchSysCacheTuple(SHADOWSYSID,
|
176 | 286 | ObjectIdGetDatum(ev_rel->rd_rel->relowner),
|
177 | 287 | 0,0,0);
|
178 | 288 | if (!HeapTupleIsValid(usertup))
|
179 |
| -{ |
180 | 289 | elog(ERROR,"cache lookup for userid %d failed",
|
181 | 290 | ev_rel->rd_rel->relowner);
|
182 |
| -} |
| 291 | +userform= (Form_pg_shadow)GETSTRUCT(usertup); |
| 292 | +context.evowner=pstrdup(NameStr(userform->usename)); |
183 | 293 | heap_close(ev_rel,AccessShareLock);
|
184 |
| -evowner=pstrdup(NameStr(((Form_pg_shadow)GETSTRUCT(usertup))->usename)); |
185 | 294 |
|
186 | 295 | /*
|
187 |
| - * Check all the locks, that should get fired on this query |
| 296 | + * Check all the locks that should get fired on this query |
188 | 297 | */
|
189 | 298 | foreach(l,locks)
|
190 | 299 | {
|
191 | 300 | RewriteRule*onelock= (RewriteRule*)lfirst(l);
|
192 | 301 | List*action;
|
193 | 302 |
|
194 | 303 | /*
|
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. |
196 | 306 | */
|
197 | 307 | foreach(action,onelock->actions)
|
198 | 308 | {
|
199 | 309 | Query*query= (Query*)lfirst(action);
|
200 | 310 |
|
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); |
237 | 312 | }
|
238 | 313 | }
|
239 |
| - |
240 |
| -/* |
241 |
| - * Phew, that was close |
242 |
| - */ |
243 |
| -return; |
244 | 314 | }
|