27
27
*
28
28
*
29
29
* IDENTIFICATION
30
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.109 2000/02/15 03:36:49 thomas Exp $
30
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.110 2000/03/09 05:15:33 tgl Exp $
31
31
*
32
32
*-------------------------------------------------------------------------
33
33
*/
46
46
#include "utils/builtins.h"
47
47
#include "utils/syscache.h"
48
48
49
- void ExecCheckPerms ( CmdType operation , int resultRelation , List * rangeTable ,
50
- Query * parseTree );
51
-
49
+ /* XXX no points for style */
50
+ extern TupleTableSlot * EvalPlanQual ( EState * estate , Index rti ,
51
+ ItemPointer tid );
52
52
53
53
/* decls for local routines only used within this module */
54
54
static TupleDesc InitPlan (CmdType operation ,
@@ -72,13 +72,18 @@ static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
72
72
EState * estate );
73
73
static void ExecReplace (TupleTableSlot * slot ,ItemPointer tupleid ,
74
74
EState * estate );
75
-
76
- TupleTableSlot * EvalPlanQual (EState * estate ,Index rti ,ItemPointer tid );
77
75
static TupleTableSlot * EvalPlanQualNext (EState * estate );
78
-
79
-
76
+ static void ExecCheckQueryPerms (CmdType operation ,Query * parseTree ,
77
+ Plan * plan );
78
+ static void ExecCheckPlanPerms (Plan * plan ,CmdType operation ,
79
+ int resultRelation ,bool resultIsScanned );
80
+ static void ExecCheckRTPerms (List * rangeTable ,CmdType operation ,
81
+ int resultRelation ,bool resultIsScanned );
82
+ static void ExecCheckRTEPerms (RangeTblEntry * rte ,CmdType operation ,
83
+ bool isResultRelation ,bool resultIsScanned );
80
84
/* end of local decls */
81
85
86
+
82
87
/* ----------------------------------------------------------------
83
88
*ExecutorStart
84
89
*
@@ -378,104 +383,257 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
378
383
}
379
384
}
380
385
381
- void
382
- ExecCheckPerms (CmdType operation ,
383
- int resultRelation ,
384
- List * rangeTable ,
385
- Query * parseTree )
386
+
387
+ /*
388
+ * ExecCheckQueryPerms
389
+ *Check access permissions for all relations referenced in a query.
390
+ */
391
+ static void
392
+ ExecCheckQueryPerms (CmdType operation ,Query * parseTree ,Plan * plan )
386
393
{
387
- int rtindex = 0 ;
394
+ List * rangeTable = parseTree -> rtable ;
395
+ int resultRelation = parseTree -> resultRelation ;
396
+ bool resultIsScanned = false;
388
397
List * lp ;
389
- List * qvars ,
390
- * tvars ;
391
- int32 ok = 1 ,
392
- aclcheck_result = -1 ;
393
- char * opstr ;
394
- char * relName = NULL ;
395
- char * userName ;
396
398
397
- #define CHECK (MODE )pg_aclcheck(relName, userName, MODE)
399
+ /*
400
+ * If we have a result relation, determine whether the result rel is
401
+ * scanned or merely written. If scanned, we will insist on read
402
+ * permission as well as modify permission.
403
+ */
404
+ if (resultRelation > 0 )
405
+ {
406
+ List * qvars = pull_varnos (parseTree -> qual );
407
+ List * tvars = pull_varnos ((Node * )parseTree -> targetList );
398
408
399
- userName = GetPgUserName ();
409
+ resultIsScanned = (intMember (resultRelation ,qvars )||
410
+ intMember (resultRelation ,tvars ));
411
+ freeList (qvars );
412
+ freeList (tvars );
413
+ }
400
414
401
- foreach (lp ,rangeTable )
415
+ /*
416
+ * Check RTEs in the query's primary rangetable.
417
+ */
418
+ ExecCheckRTPerms (rangeTable ,operation ,resultRelation ,resultIsScanned );
419
+
420
+ /*
421
+ * Check SELECT FOR UPDATE access rights.
422
+ */
423
+ foreach (lp ,parseTree -> rowMark )
402
424
{
403
- RangeTblEntry * rte = lfirst (lp );
425
+ RowMark * rm = lfirst (lp );
404
426
405
- ++ rtindex ;
427
+ if (!(rm -> info & ROW_ACL_FOR_UPDATE ))
428
+ continue ;
429
+
430
+ ExecCheckRTEPerms (rt_fetch (rm -> rti ,rangeTable ),
431
+ CMD_UPDATE , true, false);
432
+ }
433
+
434
+ /*
435
+ * Search for subplans and APPEND nodes to check their rangetables.
436
+ */
437
+ ExecCheckPlanPerms (plan ,operation ,resultRelation ,resultIsScanned );
438
+ }
439
+
440
+ /*
441
+ * ExecCheckPlanPerms
442
+ *Recursively scan the plan tree to check access permissions in
443
+ *subplans.
444
+ *
445
+ * We also need to look at the local rangetables in Append plan nodes,
446
+ * which is pretty bogus --- most likely, those tables should be mentioned
447
+ * in the query's main rangetable. But at the moment, they're not.
448
+ */
449
+ static void
450
+ ExecCheckPlanPerms (Plan * plan ,CmdType operation ,
451
+ int resultRelation ,bool resultIsScanned )
452
+ {
453
+ List * subp ;
454
+
455
+ if (plan == NULL )
456
+ return ;
457
+
458
+ /* Check subplans, which we assume are plain SELECT queries */
459
+
460
+ foreach (subp ,plan -> initPlan )
461
+ {
462
+ SubPlan * subplan = (SubPlan * )lfirst (subp );
463
+
464
+ ExecCheckRTPerms (subplan -> rtable ,CMD_SELECT ,0 , false);
465
+ ExecCheckPlanPerms (subplan -> plan ,CMD_SELECT ,0 , false);
466
+ }
467
+ foreach (subp ,plan -> subPlan )
468
+ {
469
+ SubPlan * subplan = (SubPlan * )lfirst (subp );
470
+
471
+ ExecCheckRTPerms (subplan -> rtable ,CMD_SELECT ,0 , false);
472
+ ExecCheckPlanPerms (subplan -> plan ,CMD_SELECT ,0 , false);
473
+ }
474
+
475
+ /* Check lower plan nodes */
476
+
477
+ ExecCheckPlanPerms (plan -> lefttree ,operation ,
478
+ resultRelation ,resultIsScanned );
479
+ ExecCheckPlanPerms (plan -> righttree ,operation ,
480
+ resultRelation ,resultIsScanned );
481
+
482
+ /* Do node-type-specific checks */
406
483
407
- if (rte -> skipAcl )
484
+ switch (nodeTag (plan ))
485
+ {
486
+ case T_Append :
408
487
{
488
+ Append * app = (Append * )plan ;
489
+ List * appendplans ;
409
490
410
- /*
411
- * This happens if the access to this table is due to a view
412
- * query rewriting - the rewrite handler checked the
413
- *permissions against the view owner, so we just skip this
414
- *entry .
415
- */
416
- continue ;
417
- }
491
+ if ( app -> inheritrelid > 0 )
492
+ {
493
+ /*
494
+ *Append implements expansion of inheritance; all members
495
+ *of inheritrtable list will be plugged into same RTE slot .
496
+ * Therefore, they are either all result relations or none.
497
+ */
498
+ List * rtable ;
418
499
419
- relName = rte -> relname ;
420
- if (rtindex == resultRelation )
421
- {/* this is the result relation */
422
- qvars = pull_varnos (parseTree -> qual );
423
- tvars = pull_varnos ((Node * )parseTree -> targetList );
424
- if (intMember (resultRelation ,qvars )||
425
- intMember (resultRelation ,tvars ))
500
+ foreach (rtable ,app -> inheritrtable )
501
+ {
502
+ ExecCheckRTEPerms ((RangeTblEntry * )lfirst (rtable ),
503
+ operation ,
504
+ (app -> inheritrelid == resultRelation ),
505
+ resultIsScanned );
506
+ }
507
+ }
508
+ else
426
509
{
427
- /* result relation is scanned */
428
- ok = ((aclcheck_result = CHECK (ACL_RD ))== ACLCHECK_OK );
429
- opstr = "read" ;
430
- if (!ok )
431
- break ;
510
+ /* Append implements UNION, which must be a SELECT */
511
+ List * rtables ;
512
+
513
+ foreach (rtables ,app -> unionrtables )
514
+ {
515
+ ExecCheckRTPerms ((List * )lfirst (rtables ),
516
+ CMD_SELECT ,0 , false);
517
+ }
432
518
}
433
- switch (operation )
519
+
520
+ /* Check appended plans */
521
+ foreach (appendplans ,app -> appendplans )
434
522
{
435
- case CMD_INSERT :
436
- ok = ((aclcheck_result = CHECK (ACL_AP ))== ACLCHECK_OK )||
437
- ((aclcheck_result = CHECK (ACL_WR ))== ACLCHECK_OK );
438
- opstr = "append" ;
439
- break ;
440
- case CMD_DELETE :
441
- case CMD_UPDATE :
442
- ok = ((aclcheck_result = CHECK (ACL_WR ))== ACLCHECK_OK );
443
- opstr = "write" ;
444
- break ;
445
- default :
446
- elog (ERROR ,"ExecCheckPerms: bogus operation %d" ,
447
- operation );
523
+ ExecCheckPlanPerms ((Plan * )lfirst (appendplans ),
524
+ operation ,
525
+ resultRelation ,
526
+ resultIsScanned );
448
527
}
528
+ break ;
449
529
}
450
- else
451
- {
452
- ok = ((aclcheck_result = CHECK (ACL_RD ))== ACLCHECK_OK );
453
- opstr = "read" ;
454
- }
455
- if (!ok )
530
+
531
+ default :
456
532
break ;
457
533
}
458
- if (!ok )
459
- elog (ERROR ,"%s: %s" ,relName ,aclcheck_error_strings [aclcheck_result ]);
534
+ }
460
535
461
- if (parseTree != NULL && parseTree -> rowMark != NULL )
536
+ /*
537
+ * ExecCheckRTPerms
538
+ *Check access permissions for all relations listed in a range table.
539
+ *
540
+ * If resultRelation is not 0, it is the RT index of the relation to be
541
+ * treated as the result relation. All other relations are assumed to be
542
+ * read-only for the query.
543
+ */
544
+ static void
545
+ ExecCheckRTPerms (List * rangeTable ,CmdType operation ,
546
+ int resultRelation ,bool resultIsScanned )
547
+ {
548
+ int rtindex = 0 ;
549
+ List * lp ;
550
+
551
+ foreach (lp ,rangeTable )
462
552
{
463
- foreach (lp ,parseTree -> rowMark )
464
- {
465
- RowMark * rm = lfirst (lp );
553
+ RangeTblEntry * rte = lfirst (lp );
466
554
467
- if (!(rm -> info & ROW_ACL_FOR_UPDATE ))
468
- continue ;
555
+ ++ rtindex ;
556
+
557
+ ExecCheckRTEPerms (rte ,
558
+ operation ,
559
+ (rtindex == resultRelation ),
560
+ resultIsScanned );
561
+ }
562
+ }
563
+
564
+ /*
565
+ * ExecCheckRTEPerms
566
+ *Check access permissions for a single RTE.
567
+ */
568
+ static void
569
+ ExecCheckRTEPerms (RangeTblEntry * rte ,CmdType operation ,
570
+ bool isResultRelation ,bool resultIsScanned )
571
+ {
572
+ char * relName ;
573
+ char * userName ;
574
+ int32 aclcheck_result ;
575
+
576
+ if (rte -> skipAcl )
577
+ {
578
+ /*
579
+ * This happens if the access to this table is due to a view
580
+ * query rewriting - the rewrite handler already checked the
581
+ * permissions against the view owner, so we just skip this entry.
582
+ */
583
+ return ;
584
+ }
469
585
470
- relName = rt_fetch (rm -> rti ,rangeTable )-> relname ;
471
- ok = ((aclcheck_result = CHECK (ACL_WR ))== ACLCHECK_OK );
472
- opstr = "write" ;
473
- if (!ok )
474
- elog (ERROR ,"%s: %s" ,relName ,aclcheck_error_strings [aclcheck_result ]);
586
+ relName = rte -> relname ;
587
+
588
+ /*
589
+ * Note: GetPgUserName is presently fast enough that there's no harm
590
+ * in calling it separately for each RTE. If that stops being true,
591
+ * we could call it once in ExecCheckQueryPerms and pass the userName
592
+ * down from there. But for now, no need for the extra clutter.
593
+ */
594
+ userName = GetPgUserName ();
595
+
596
+ #define CHECK (MODE )pg_aclcheck(relName, userName, MODE)
597
+
598
+ if (isResultRelation )
599
+ {
600
+ if (resultIsScanned )
601
+ {
602
+ aclcheck_result = CHECK (ACL_RD );
603
+ if (aclcheck_result != ACLCHECK_OK )
604
+ elog (ERROR ,"%s: %s" ,
605
+ relName ,aclcheck_error_strings [aclcheck_result ]);
606
+ }
607
+ switch (operation )
608
+ {
609
+ case CMD_INSERT :
610
+ /* Accept either APPEND or WRITE access for this */
611
+ aclcheck_result = CHECK (ACL_AP );
612
+ if (aclcheck_result != ACLCHECK_OK )
613
+ aclcheck_result = CHECK (ACL_WR );
614
+ break ;
615
+ case CMD_DELETE :
616
+ case CMD_UPDATE :
617
+ aclcheck_result = CHECK (ACL_WR );
618
+ break ;
619
+ default :
620
+ elog (ERROR ,"ExecCheckRTEPerms: bogus operation %d" ,
621
+ operation );
622
+ aclcheck_result = ACLCHECK_OK ;/* keep compiler quiet */
623
+ break ;
475
624
}
476
625
}
626
+ else
627
+ {
628
+ aclcheck_result = CHECK (ACL_RD );
629
+ }
630
+
631
+ if (aclcheck_result != ACLCHECK_OK )
632
+ elog (ERROR ,"%s: %s" ,
633
+ relName ,aclcheck_error_strings [aclcheck_result ]);
477
634
}
478
635
636
+
479
637
/* ===============================================================
480
638
* ===============================================================
481
639
static routines follow
@@ -514,16 +672,19 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
514
672
TupleDesc tupType ;
515
673
List * targetList ;
516
674
675
+ /*
676
+ * Do permissions checks.
677
+ */
678
+ #ifndef NO_SECURITY
679
+ ExecCheckQueryPerms (operation ,parseTree ,plan );
680
+ #endif
681
+
517
682
/*
518
683
* get information from query descriptor
519
684
*/
520
685
rangeTable = parseTree -> rtable ;
521
686
resultRelation = parseTree -> resultRelation ;
522
687
523
- #ifndef NO_SECURITY
524
- ExecCheckPerms (operation ,resultRelation ,rangeTable ,parseTree );
525
- #endif
526
-
527
688
/*
528
689
* initialize the node's execution state
529
690
*/