PostgreSQL Source Code git master
aclchk.c File Reference
Include dependency graph for aclchk.c:

Go to the source code of this file.

Data Structures

struct  InternalDefaultACL
 

Functions

static void ExecGrantStmt_oids (InternalGrant *istmt)
 
static void ExecGrant_Relation (InternalGrant *istmt)
 
static void ExecGrant_common (InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
 
static void ExecGrant_Language_check (InternalGrant *istmt, HeapTuple tuple)
 
static void ExecGrant_Largeobject (InternalGrant *istmt)
 
static void ExecGrant_Type_check (InternalGrant *istmt, HeapTuple tuple)
 
static void ExecGrant_Parameter (InternalGrant *istmt)
 
static void SetDefaultACLsInSchemas (InternalDefaultACL *iacls, List *nspnames)
 
static void SetDefaultACL (InternalDefaultACL *iacls)
 
static ListobjectNamesToOids (ObjectType objtype, List *objnames, bool is_grant)
 
static ListobjectsInSchemaToOids (ObjectType objtype, List *nspnames)
 
static ListgetRelationsInNamespace (Oid namespaceId, char relkind)
 
static void expand_col_privileges (List *colnames, Oid table_oid, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
 
static void expand_all_col_privileges (Oid table_oid, Form_pg_class classForm, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
 
static AclMode string_to_privilege (const char *privname)
 
static const char * privilege_to_string (AclMode privilege)
 
static AclMode restrict_and_check_grant (bool is_grant, AclMode avail_goptions, bool all_privs, AclMode privileges, Oid objectId, Oid grantorId, ObjectType objtype, const char *objname, AttrNumber att_number, const char *colname)
 
static AclMode pg_aclmask (ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode object_aclmask (Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode object_aclmask_ext (Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
 
static AclMode pg_attribute_aclmask (Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode pg_attribute_aclmask_ext (Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
 
static AclMode pg_class_aclmask_ext (Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
 
static AclMode pg_parameter_acl_aclmask (Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode pg_largeobject_aclmask_snapshot (Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
 
static AclMode pg_namespace_aclmask_ext (Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
 
static AclMode pg_type_aclmask_ext (Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
 
static void recordExtensionInitPriv (Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
 
static void recordExtensionInitPrivWorker (Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
 
static Aclmerge_acl_with_grant (Acl *old_acl, bool is_grant, bool grant_option, DropBehavior behavior, List *grantees, AclMode privileges, Oid grantorId, Oid ownerId)
 
void ExecuteGrantStmt (GrantStmt *stmt)
 
void ExecAlterDefaultPrivilegesStmt (ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
 
void RemoveRoleFromObjectACL (Oid roleid, Oid classid, Oid objid)
 
static void ExecGrant_Attribute (InternalGrant *istmt, Oid relOid, const char *relname, AttrNumber attnum, Oid ownerId, AclMode col_privileges, Relation attRelation, const Acl *old_rel_acl)
 
void aclcheck_error (AclResult aclerr, ObjectType objtype, const char *objectname)
 
void aclcheck_error_col (AclResult aclerr, ObjectType objtype, const char *objectname, const char *colname)
 
void aclcheck_error_type (AclResult aclerr, Oid typeOid)
 
AclMode pg_class_aclmask (Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode pg_parameter_aclmask (const char *name, Oid roleid, AclMode mask, AclMaskHow how)
 
AclResult object_aclcheck (Oid classid, Oid objectid, Oid roleid, AclMode mode)
 
AclResult object_aclcheck_ext (Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
 
AclResult pg_attribute_aclcheck (Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
 
AclResult pg_attribute_aclcheck_ext (Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
 
AclResult pg_attribute_aclcheck_all (Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
 
AclResult pg_attribute_aclcheck_all_ext (Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
 
AclResult pg_class_aclcheck (Oid table_oid, Oid roleid, AclMode mode)
 
AclResult pg_class_aclcheck_ext (Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
 
AclResult pg_parameter_aclcheck (const char *name, Oid roleid, AclMode mode)
 
AclResult pg_largeobject_aclcheck_snapshot (Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
 
bool object_ownercheck (Oid classid, Oid objectid, Oid roleid)
 
bool has_createrole_privilege (Oid roleid)
 
bool has_bypassrls_privilege (Oid roleid)
 
static Aclget_default_acl_internal (Oid roleId, Oid nsp_oid, char objtype)
 
Aclget_user_default_acl (ObjectType objtype, Oid ownerId, Oid nsp_oid)
 
void recordDependencyOnNewAcl (Oid classId, Oid objectId, int32 objsubId, Oid ownerId, Acl *acl)
 
void recordExtObjInitPriv (Oid objoid, Oid classoid)
 
void removeExtObjInitPriv (Oid objoid, Oid classoid)
 
void ReplaceRoleInInitPriv (Oid oldroleid, Oid newroleid, Oid classid, Oid objid, int32 objsubid)
 
void RemoveRoleFromInitPriv (Oid roleid, Oid classid, Oid objid, int32 objsubid)
 

Variables

bool binary_upgrade_record_init_privs = false
 

Function Documentation

◆ aclcheck_error()

void aclcheck_error ( AclResult  aclerr,
ObjectType  objtype,
const char *  objectname 
)

Definition at line 2622 of file aclchk.c.

2624{
2625 switch (aclerr)
2626 {
2627 case ACLCHECK_OK:
2628 /* no error, so return to caller */
2629 break;
2630 case ACLCHECK_NO_PRIV:
2631 {
2632 const char *msg = "???";
2633
2634 switch (objtype)
2635 {
2636 case OBJECT_AGGREGATE:
2637 msg = gettext_noop("permission denied for aggregate %s");
2638 break;
2639 case OBJECT_COLLATION:
2640 msg = gettext_noop("permission denied for collation %s");
2641 break;
2642 case OBJECT_COLUMN:
2643 msg = gettext_noop("permission denied for column %s");
2644 break;
2645 case OBJECT_CONVERSION:
2646 msg = gettext_noop("permission denied for conversion %s");
2647 break;
2648 case OBJECT_DATABASE:
2649 msg = gettext_noop("permission denied for database %s");
2650 break;
2651 case OBJECT_DOMAIN:
2652 msg = gettext_noop("permission denied for domain %s");
2653 break;
2655 msg = gettext_noop("permission denied for event trigger %s");
2656 break;
2657 case OBJECT_EXTENSION:
2658 msg = gettext_noop("permission denied for extension %s");
2659 break;
2660 case OBJECT_FDW:
2661 msg = gettext_noop("permission denied for foreign-data wrapper %s");
2662 break;
2664 msg = gettext_noop("permission denied for foreign server %s");
2665 break;
2667 msg = gettext_noop("permission denied for foreign table %s");
2668 break;
2669 case OBJECT_FUNCTION:
2670 msg = gettext_noop("permission denied for function %s");
2671 break;
2672 case OBJECT_INDEX:
2673 msg = gettext_noop("permission denied for index %s");
2674 break;
2675 case OBJECT_LANGUAGE:
2676 msg = gettext_noop("permission denied for language %s");
2677 break;
2678 case OBJECT_LARGEOBJECT:
2679 msg = gettext_noop("permission denied for large object %s");
2680 break;
2681 case OBJECT_MATVIEW:
2682 msg = gettext_noop("permission denied for materialized view %s");
2683 break;
2684 case OBJECT_OPCLASS:
2685 msg = gettext_noop("permission denied for operator class %s");
2686 break;
2687 case OBJECT_OPERATOR:
2688 msg = gettext_noop("permission denied for operator %s");
2689 break;
2690 case OBJECT_OPFAMILY:
2691 msg = gettext_noop("permission denied for operator family %s");
2692 break;
2694 msg = gettext_noop("permission denied for parameter %s");
2695 break;
2696 case OBJECT_POLICY:
2697 msg = gettext_noop("permission denied for policy %s");
2698 break;
2699 case OBJECT_PROCEDURE:
2700 msg = gettext_noop("permission denied for procedure %s");
2701 break;
2702 case OBJECT_PUBLICATION:
2703 msg = gettext_noop("permission denied for publication %s");
2704 break;
2705 case OBJECT_ROUTINE:
2706 msg = gettext_noop("permission denied for routine %s");
2707 break;
2708 case OBJECT_SCHEMA:
2709 msg = gettext_noop("permission denied for schema %s");
2710 break;
2711 case OBJECT_SEQUENCE:
2712 msg = gettext_noop("permission denied for sequence %s");
2713 break;
2715 msg = gettext_noop("permission denied for statistics object %s");
2716 break;
2718 msg = gettext_noop("permission denied for subscription %s");
2719 break;
2720 case OBJECT_TABLE:
2721 msg = gettext_noop("permission denied for table %s");
2722 break;
2723 case OBJECT_TABLESPACE:
2724 msg = gettext_noop("permission denied for tablespace %s");
2725 break;
2727 msg = gettext_noop("permission denied for text search configuration %s");
2728 break;
2730 msg = gettext_noop("permission denied for text search dictionary %s");
2731 break;
2732 case OBJECT_TYPE:
2733 msg = gettext_noop("permission denied for type %s");
2734 break;
2735 case OBJECT_VIEW:
2736 msg = gettext_noop("permission denied for view %s");
2737 break;
2738 /* these currently aren't used */
2740 case OBJECT_AMOP:
2741 case OBJECT_AMPROC:
2742 case OBJECT_ATTRIBUTE:
2743 case OBJECT_CAST:
2744 case OBJECT_DEFAULT:
2745 case OBJECT_DEFACL:
2749 case OBJECT_ROLE:
2750 case OBJECT_RULE:
2752 case OBJECT_TRANSFORM:
2753 case OBJECT_TRIGGER:
2754 case OBJECT_TSPARSER:
2755 case OBJECT_TSTEMPLATE:
2757 elog(ERROR, "unsupported object type: %d", objtype);
2758 }
2759
2760 ereport(ERROR,
2761 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2762 errmsg(msg, objectname)));
2763 break;
2764 }
2765 case ACLCHECK_NOT_OWNER:
2766 {
2767 const char *msg = "???";
2768
2769 switch (objtype)
2770 {
2771 case OBJECT_AGGREGATE:
2772 msg = gettext_noop("must be owner of aggregate %s");
2773 break;
2774 case OBJECT_COLLATION:
2775 msg = gettext_noop("must be owner of collation %s");
2776 break;
2777 case OBJECT_CONVERSION:
2778 msg = gettext_noop("must be owner of conversion %s");
2779 break;
2780 case OBJECT_DATABASE:
2781 msg = gettext_noop("must be owner of database %s");
2782 break;
2783 case OBJECT_DOMAIN:
2784 msg = gettext_noop("must be owner of domain %s");
2785 break;
2787 msg = gettext_noop("must be owner of event trigger %s");
2788 break;
2789 case OBJECT_EXTENSION:
2790 msg = gettext_noop("must be owner of extension %s");
2791 break;
2792 case OBJECT_FDW:
2793 msg = gettext_noop("must be owner of foreign-data wrapper %s");
2794 break;
2796 msg = gettext_noop("must be owner of foreign server %s");
2797 break;
2799 msg = gettext_noop("must be owner of foreign table %s");
2800 break;
2801 case OBJECT_FUNCTION:
2802 msg = gettext_noop("must be owner of function %s");
2803 break;
2804 case OBJECT_INDEX:
2805 msg = gettext_noop("must be owner of index %s");
2806 break;
2807 case OBJECT_LANGUAGE:
2808 msg = gettext_noop("must be owner of language %s");
2809 break;
2810 case OBJECT_LARGEOBJECT:
2811 msg = gettext_noop("must be owner of large object %s");
2812 break;
2813 case OBJECT_MATVIEW:
2814 msg = gettext_noop("must be owner of materialized view %s");
2815 break;
2816 case OBJECT_OPCLASS:
2817 msg = gettext_noop("must be owner of operator class %s");
2818 break;
2819 case OBJECT_OPERATOR:
2820 msg = gettext_noop("must be owner of operator %s");
2821 break;
2822 case OBJECT_OPFAMILY:
2823 msg = gettext_noop("must be owner of operator family %s");
2824 break;
2825 case OBJECT_PROCEDURE:
2826 msg = gettext_noop("must be owner of procedure %s");
2827 break;
2828 case OBJECT_PUBLICATION:
2829 msg = gettext_noop("must be owner of publication %s");
2830 break;
2831 case OBJECT_ROUTINE:
2832 msg = gettext_noop("must be owner of routine %s");
2833 break;
2834 case OBJECT_SEQUENCE:
2835 msg = gettext_noop("must be owner of sequence %s");
2836 break;
2838 msg = gettext_noop("must be owner of subscription %s");
2839 break;
2840 case OBJECT_TABLE:
2841 msg = gettext_noop("must be owner of table %s");
2842 break;
2843 case OBJECT_TYPE:
2844 msg = gettext_noop("must be owner of type %s");
2845 break;
2846 case OBJECT_VIEW:
2847 msg = gettext_noop("must be owner of view %s");
2848 break;
2849 case OBJECT_SCHEMA:
2850 msg = gettext_noop("must be owner of schema %s");
2851 break;
2853 msg = gettext_noop("must be owner of statistics object %s");
2854 break;
2855 case OBJECT_TABLESPACE:
2856 msg = gettext_noop("must be owner of tablespace %s");
2857 break;
2859 msg = gettext_noop("must be owner of text search configuration %s");
2860 break;
2862 msg = gettext_noop("must be owner of text search dictionary %s");
2863 break;
2864
2865 /*
2866 * Special cases: For these, the error message talks
2867 * about "relation", because that's where the
2868 * ownership is attached. See also
2869 * check_object_ownership().
2870 */
2871 case OBJECT_COLUMN:
2872 case OBJECT_POLICY:
2873 case OBJECT_RULE:
2875 case OBJECT_TRIGGER:
2876 msg = gettext_noop("must be owner of relation %s");
2877 break;
2878 /* these currently aren't used */
2880 case OBJECT_AMOP:
2881 case OBJECT_AMPROC:
2882 case OBJECT_ATTRIBUTE:
2883 case OBJECT_CAST:
2884 case OBJECT_DEFAULT:
2885 case OBJECT_DEFACL:
2890 case OBJECT_ROLE:
2891 case OBJECT_TRANSFORM:
2892 case OBJECT_TSPARSER:
2893 case OBJECT_TSTEMPLATE:
2895 elog(ERROR, "unsupported object type: %d", objtype);
2896 }
2897
2898 ereport(ERROR,
2899 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2900 errmsg(msg, objectname)));
2901 break;
2902 }
2903 default:
2904 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2905 break;
2906 }
2907}
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define gettext_noop(x)
Definition: c.h:1167
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2326
@ OBJECT_FDW
Definition: parsenodes.h:2328
@ OBJECT_TSPARSER
Definition: parsenodes.h:2359
@ OBJECT_COLLATION
Definition: parsenodes.h:2319
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2362
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2312
@ OBJECT_OPCLASS
Definition: parsenodes.h:2336
@ OBJECT_DEFACL
Definition: parsenodes.h:2323
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2313
@ OBJECT_MATVIEW
Definition: parsenodes.h:2335
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
@ OBJECT_POLICY
Definition: parsenodes.h:2340
@ OBJECT_OPERATOR
Definition: parsenodes.h:2337
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2330
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2357
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2338
@ OBJECT_DOMAIN
Definition: parsenodes.h:2324
@ OBJECT_COLUMN
Definition: parsenodes.h:2318
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2354
@ OBJECT_ROLE
Definition: parsenodes.h:2345
@ OBJECT_ROUTINE
Definition: parsenodes.h:2346
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2334
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2343
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2341
@ OBJECT_EXTENSION
Definition: parsenodes.h:2327
@ OBJECT_INDEX
Definition: parsenodes.h:2332
@ OBJECT_DEFAULT
Definition: parsenodes.h:2322
@ OBJECT_DATABASE
Definition: parsenodes.h:2321
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2349
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2360
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2333
@ OBJECT_AMOP
Definition: parsenodes.h:2314
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2344
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2329
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2358
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2316
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2342
@ OBJECT_RULE
Definition: parsenodes.h:2347
@ OBJECT_CONVERSION
Definition: parsenodes.h:2320
@ OBJECT_AMPROC
Definition: parsenodes.h:2315
@ OBJECT_TABLE
Definition: parsenodes.h:2353
@ OBJECT_VIEW
Definition: parsenodes.h:2363
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2339
@ OBJECT_TYPE
Definition: parsenodes.h:2361
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2352
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2325
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2350
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2351
@ OBJECT_CAST
Definition: parsenodes.h:2317
@ OBJECT_TRIGGER
Definition: parsenodes.h:2356
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2355

References ACLCHECK_NO_PRIV, ACLCHECK_NOT_OWNER, ACLCHECK_OK, elog, ereport, errcode(), errmsg(), ERROR, gettext_noop, OBJECT_ACCESS_METHOD, OBJECT_AGGREGATE, OBJECT_AMOP, OBJECT_AMPROC, OBJECT_ATTRIBUTE, OBJECT_CAST, OBJECT_COLLATION, OBJECT_COLUMN, OBJECT_CONVERSION, OBJECT_DATABASE, OBJECT_DEFACL, OBJECT_DEFAULT, OBJECT_DOMAIN, OBJECT_DOMCONSTRAINT, OBJECT_EVENT_TRIGGER, OBJECT_EXTENSION, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FOREIGN_TABLE, OBJECT_FUNCTION, OBJECT_INDEX, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_MATVIEW, OBJECT_OPCLASS, OBJECT_OPERATOR, OBJECT_OPFAMILY, OBJECT_PARAMETER_ACL, OBJECT_POLICY, OBJECT_PROCEDURE, OBJECT_PUBLICATION, OBJECT_PUBLICATION_NAMESPACE, OBJECT_PUBLICATION_REL, OBJECT_ROLE, OBJECT_ROUTINE, OBJECT_RULE, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_STATISTIC_EXT, OBJECT_SUBSCRIPTION, OBJECT_TABCONSTRAINT, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TRANSFORM, OBJECT_TRIGGER, OBJECT_TSCONFIGURATION, OBJECT_TSDICTIONARY, OBJECT_TSPARSER, OBJECT_TSTEMPLATE, OBJECT_TYPE, OBJECT_USER_MAPPING, and OBJECT_VIEW.

Referenced by aclcheck_error_col(), aclcheck_error_type(), AlterCollation(), AlterDatabase(), AlterDatabaseOwner(), AlterDatabaseRefreshColl(), AlterDatabaseSet(), AlterEventTrigger(), AlterEventTriggerOwner_internal(), AlterExtensionNamespace(), AlterForeignServer(), AlterForeignServerOwner_internal(), AlterFunction(), AlterObjectNamespace_internal(), AlterObjectOwner_internal(), AlterObjectRename_internal(), AlterOperator(), AlterOpFamilyAdd(), AlterPublication(), AlterPublicationOwner_internal(), AlterRoleSet(), AlterSchemaOwner_internal(), AlterStatistics(), AlterSubscription(), AlterSubscriptionOwner_internal(), AlterTableMoveAll(), AlterTableSpaceOptions(), AlterTSConfiguration(), AlterTSDictionary(), AlterTypeOwner(), ATExecChangeOwner(), ATPrepSetTableSpace(), ATSimplePermissions(), brin_desummarize_range(), brin_summarize_range(), calculate_database_size(), calculate_tablespace_size(), call_pltcl_start_proc(), check_object_ownership(), check_temp_tablespaces(), checkFkeyPermissions(), CheckFunctionValidatorAccess(), compute_return_type(), CreateConversionCommand(), createdb(), CreateForeignServer(), CreateForeignTable(), CreateFunction(), CreateProceduralLanguage(), CreatePublication(), CreateSchemaCommand(), CreateStatistics(), CreateSubscription(), CreateTransform(), CreateTriggerFiringOn(), currtid_internal(), DefineAggregate(), DefineCollation(), DefineDomain(), DefineEnum(), DefineIndex(), DefineOpClass(), DefineOperator(), DefineOpFamily(), DefineQueryRewrite(), DefineRange(), DefineRelation(), DefineTSConfiguration(), DefineTSDictionary(), DefineType(), dropdb(), DropSubscription(), DropTableSpace(), EnableDisableRule(), ExecAlterExtensionContentsStmt(), ExecAlterExtensionStmt(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecCheckPermissions(), ExecInitAgg(), ExecInitExprRec(), ExecInitFunc(), ExecInitWindowAgg(), ExecReindex(), ExecuteCallStmt(), ExecuteDoStmt(), ExecuteTruncateGuts(), findRangeCanonicalFunction(), findRangeSubtypeDiffFunction(), get_connect_string(), get_other_operator(), get_rel_from_relname(), gin_clean_pending_list(), HandleFunctionRequest(), heap_force_common(), ImportForeignSchema(), init_sexpr(), initialize_peragg(), LockViewRecurse_walker(), LogicalRepSyncTableStart(), lookup_agg_function(), LookupCreationNamespace(), LookupExplicitNamespace(), MergeAttributes(), movedb(), OperatorCreate(), pg_prewarm(), pgrowlocks(), ProcedureCreate(), PublicationAddTables(), RangeVarCallbackForAlterRelation(), RangeVarCallbackForDropRelation(), RangeVarCallbackForLockTable(), RangeVarCallbackForPolicy(), RangeVarCallbackForReindexIndex(), RangeVarCallbackForRenameRule(), RangeVarCallbackForRenameTrigger(), RangeVarCallbackMaintainsTable(), RangeVarCallbackOwnsRelation(), RangeVarGetAndCheckCreationNamespace(), ReindexMultipleInternal(), ReindexMultipleTables(), renameatt_check(), RenameDatabase(), RenameSchema(), RenameTableSpace(), restrict_and_check_grant(), stats_lock_check_privileges(), TargetPrivilegesCheck(), transformTableLikeClause(), truncate_check_perms(), TypeCreate(), user_mapping_ddl_aclcheck(), ValidateJoinEstimator(), ValidateOperatorReference(), and ValidateRestrictionEstimator().

◆ aclcheck_error_col()

void aclcheck_error_col ( AclResult  aclerr,
ObjectType  objtype,
const char *  objectname,
const char *  colname 
)

Definition at line 2911 of file aclchk.c.

2913{
2914 switch (aclerr)
2915 {
2916 case ACLCHECK_OK:
2917 /* no error, so return to caller */
2918 break;
2919 case ACLCHECK_NO_PRIV:
2920 ereport(ERROR,
2921 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2922 errmsg("permission denied for column \"%s\" of relation \"%s\"",
2923 colname, objectname)));
2924 break;
2925 case ACLCHECK_NOT_OWNER:
2926 /* relation msg is OK since columns don't have separate owners */
2927 aclcheck_error(aclerr, objtype, objectname);
2928 break;
2929 default:
2930 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2931 break;
2932 }
2933}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622

References aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_NOT_OWNER, ACLCHECK_OK, elog, ereport, errcode(), errmsg(), and ERROR.

Referenced by restrict_and_check_grant().

◆ aclcheck_error_type()

void aclcheck_error_type ( AclResult  aclerr,
Oid  typeOid 
)

◆ ExecAlterDefaultPrivilegesStmt()

void ExecAlterDefaultPrivilegesStmt ( ParseState pstate,
AlterDefaultPrivilegesStmt stmt 
)

Definition at line 903 of file aclchk.c.

904{
905 GrantStmt *action = stmt->action;
906 InternalDefaultACL iacls;
907 ListCell *cell;
908 List *rolespecs = NIL;
909 List *nspnames = NIL;
910 DefElem *drolespecs = NULL;
911 DefElem *dnspnames = NULL;
912 AclMode all_privileges;
913 const char *errormsg;
914
915 /* Deconstruct the "options" part of the statement */
916 foreach(cell, stmt->options)
917 {
918 DefElem *defel = (DefElem *) lfirst(cell);
919
920 if (strcmp(defel->defname, "schemas") == 0)
921 {
922 if (dnspnames)
923 errorConflictingDefElem(defel, pstate);
924 dnspnames = defel;
925 }
926 else if (strcmp(defel->defname, "roles") == 0)
927 {
928 if (drolespecs)
929 errorConflictingDefElem(defel, pstate);
930 drolespecs = defel;
931 }
932 else
933 elog(ERROR, "option \"%s\" not recognized", defel->defname);
934 }
935
936 if (dnspnames)
937 nspnames = (List *) dnspnames->arg;
938 if (drolespecs)
939 rolespecs = (List *) drolespecs->arg;
940
941 /* Prepare the InternalDefaultACL representation of the statement */
942 /* roleid to be filled below */
943 /* nspid to be filled in SetDefaultACLsInSchemas */
944 iacls.is_grant = action->is_grant;
945 iacls.objtype = action->objtype;
946 /* all_privs to be filled below */
947 /* privileges to be filled below */
948 iacls.grantees = NIL; /* filled below */
949 iacls.grant_option = action->grant_option;
950 iacls.behavior = action->behavior;
951
952 /*
953 * Convert the RoleSpec list into an Oid list. Note that at this point we
954 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
955 * there shouldn't be any additional work needed to support this case.
956 */
957 foreach(cell, action->grantees)
958 {
959 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
960 Oid grantee_uid;
961
962 switch (grantee->roletype)
963 {
964 case ROLESPEC_PUBLIC:
965 grantee_uid = ACL_ID_PUBLIC;
966 break;
967 default:
968 grantee_uid = get_rolespec_oid(grantee, false);
969 break;
970 }
971 iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
972 }
973
974 /*
975 * Convert action->privileges, a list of privilege strings, into an
976 * AclMode bitmask.
977 */
978 switch (action->objtype)
979 {
980 case OBJECT_TABLE:
981 all_privileges = ACL_ALL_RIGHTS_RELATION;
982 errormsg = gettext_noop("invalid privilege type %s for relation");
983 break;
984 case OBJECT_SEQUENCE:
985 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
986 errormsg = gettext_noop("invalid privilege type %s for sequence");
987 break;
988 case OBJECT_FUNCTION:
989 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
990 errormsg = gettext_noop("invalid privilege type %s for function");
991 break;
992 case OBJECT_PROCEDURE:
993 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
994 errormsg = gettext_noop("invalid privilege type %s for procedure");
995 break;
996 case OBJECT_ROUTINE:
997 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
998 errormsg = gettext_noop("invalid privilege type %s for routine");
999 break;
1000 case OBJECT_TYPE:
1001 all_privileges = ACL_ALL_RIGHTS_TYPE;
1002 errormsg = gettext_noop("invalid privilege type %s for type");
1003 break;
1004 case OBJECT_SCHEMA:
1005 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1006 errormsg = gettext_noop("invalid privilege type %s for schema");
1007 break;
1008 default:
1009 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1010 (int) action->objtype);
1011 /* keep compiler quiet */
1012 all_privileges = ACL_NO_RIGHTS;
1013 errormsg = NULL;
1014 }
1015
1016 if (action->privileges == NIL)
1017 {
1018 iacls.all_privs = true;
1019
1020 /*
1021 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1022 * depending on the object type
1023 */
1024 iacls.privileges = ACL_NO_RIGHTS;
1025 }
1026 else
1027 {
1028 iacls.all_privs = false;
1029 iacls.privileges = ACL_NO_RIGHTS;
1030
1031 foreach(cell, action->privileges)
1032 {
1033 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1034 AclMode priv;
1035
1036 if (privnode->cols)
1037 ereport(ERROR,
1038 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1039 errmsg("default privileges cannot be set for columns")));
1040
1041 if (privnode->priv_name == NULL) /* parser mistake? */
1042 elog(ERROR, "AccessPriv node must specify privilege");
1043 priv = string_to_privilege(privnode->priv_name);
1044
1045 if (priv & ~((AclMode) all_privileges))
1046 ereport(ERROR,
1047 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1048 errmsg(errormsg, privilege_to_string(priv))));
1049
1050 iacls.privileges |= priv;
1051 }
1052 }
1053
1054 if (rolespecs == NIL)
1055 {
1056 /* Set permissions for myself */
1057 iacls.roleid = GetUserId();
1058
1059 SetDefaultACLsInSchemas(&iacls, nspnames);
1060 }
1061 else
1062 {
1063 /* Look up the role OIDs and do permissions checks */
1064 ListCell *rolecell;
1065
1066 foreach(rolecell, rolespecs)
1067 {
1068 RoleSpec *rolespec = lfirst(rolecell);
1069
1070 iacls.roleid = get_rolespec_oid(rolespec, false);
1071
1072 if (!has_privs_of_role(GetUserId(), iacls.roleid))
1073 ereport(ERROR,
1074 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1075 errmsg("permission denied to change default privileges")));
1076
1077 SetDefaultACLsInSchemas(&iacls, nspnames);
1078 }
1079 }
1080}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5570
#define ACL_ALL_RIGHTS_SCHEMA
Definition: acl.h:169
#define ACL_ALL_RIGHTS_SEQUENCE
Definition: acl.h:161
#define ACL_ALL_RIGHTS_FUNCTION
Definition: acl.h:165
#define ACL_ALL_RIGHTS_TYPE
Definition: acl.h:171
#define ACL_ALL_RIGHTS_RELATION
Definition: acl.h:160
#define ACL_ID_PUBLIC
Definition: acl.h:46
static AclMode string_to_privilege(const char *privname)
Definition: aclchk.c:2534
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1088
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2575
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
#define stmt
Definition: indent_codes.h:59
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
Oid GetUserId(void)
Definition: miscinit.c:520
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:409
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_NO_RIGHTS
Definition: parsenodes.h:92
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
char * priv_name
Definition: parsenodes.h:2609
List * cols
Definition: parsenodes.h:2610
char * defname
Definition: parsenodes.h:826
Node * arg
Definition: parsenodes.h:827
AclMode privileges
Definition: aclchk.c:99
List * grantees
Definition: aclchk.c:100
DropBehavior behavior
Definition: aclchk.c:102
ObjectType objtype
Definition: aclchk.c:97
Definition: pg_list.h:54
RoleSpecType roletype
Definition: parsenodes.h:415

References ACL_ALL_RIGHTS_FUNCTION, ACL_ALL_RIGHTS_RELATION, ACL_ALL_RIGHTS_SCHEMA, ACL_ALL_RIGHTS_SEQUENCE, ACL_ALL_RIGHTS_TYPE, ACL_ID_PUBLIC, ACL_NO_RIGHTS, generate_unaccent_rules::action, InternalDefaultACL::all_privs, DefElem::arg, InternalDefaultACL::behavior, AccessPriv::cols, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), get_rolespec_oid(), gettext_noop, GetUserId(), InternalDefaultACL::grant_option, InternalDefaultACL::grantees, has_privs_of_role(), if(), InternalDefaultACL::is_grant, lappend_oid(), lfirst, NIL, OBJECT_FUNCTION, OBJECT_PROCEDURE, OBJECT_ROUTINE, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TYPE, InternalDefaultACL::objtype, AccessPriv::priv_name, privilege_to_string(), InternalDefaultACL::privileges, InternalDefaultACL::roleid, ROLESPEC_PUBLIC, RoleSpec::roletype, SetDefaultACLsInSchemas(), stmt, and string_to_privilege().

Referenced by ProcessUtilitySlow().

◆ ExecGrant_Attribute()

static void ExecGrant_Attribute ( InternalGrant istmt,
Oid  relOid,
const char *  relname,
AttrNumber  attnum,
Oid  ownerId,
AclMode  col_privileges,
Relation  attRelation,
const Acl old_rel_acl 
)
static

Definition at line 1607 of file aclchk.c.

1610{
1611 HeapTuple attr_tuple;
1612 Form_pg_attribute pg_attribute_tuple;
1613 Acl *old_acl;
1614 Acl *new_acl;
1615 Acl *merged_acl;
1616 Datum aclDatum;
1617 bool isNull;
1618 Oid grantorId;
1619 AclMode avail_goptions;
1620 bool need_update;
1621 HeapTuple newtuple;
1622 Datum values[Natts_pg_attribute] = {0};
1623 bool nulls[Natts_pg_attribute] = {0};
1624 bool replaces[Natts_pg_attribute] = {0};
1625 int noldmembers;
1626 int nnewmembers;
1627 Oid *oldmembers;
1628 Oid *newmembers;
1629
1630 attr_tuple = SearchSysCache2(ATTNUM,
1631 ObjectIdGetDatum(relOid),
1633 if (!HeapTupleIsValid(attr_tuple))
1634 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1635 attnum, relOid);
1636 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1637
1638 /*
1639 * Get working copy of existing ACL. If there's no ACL, substitute the
1640 * proper default.
1641 */
1642 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1643 &isNull);
1644 if (isNull)
1645 {
1646 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1647 /* There are no old member roles according to the catalogs */
1648 noldmembers = 0;
1649 oldmembers = NULL;
1650 }
1651 else
1652 {
1653 old_acl = DatumGetAclPCopy(aclDatum);
1654 /* Get the roles mentioned in the existing ACL */
1655 noldmembers = aclmembers(old_acl, &oldmembers);
1656 }
1657
1658 /*
1659 * In select_best_grantor we should consider existing table-level ACL bits
1660 * as well as the per-column ACL. Build a new ACL that is their
1661 * concatenation. (This is a bit cheap and dirty compared to merging them
1662 * properly with no duplications, but it's all we need here.)
1663 */
1664 merged_acl = aclconcat(old_rel_acl, old_acl);
1665
1666 /* Determine ID to do the grant as, and available grant options */
1667 select_best_grantor(GetUserId(), col_privileges,
1668 merged_acl, ownerId,
1669 &grantorId, &avail_goptions);
1670
1671 pfree(merged_acl);
1672
1673 /*
1674 * Restrict the privileges to what we can actually grant, and emit the
1675 * standards-mandated warning and error messages. Note: we don't track
1676 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1677 * each column; we just approximate it by whether all the possible
1678 * privileges are specified now. Since the all_privs flag only determines
1679 * whether a warning is issued, this seems close enough.
1680 */
1681 col_privileges =
1682 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1683 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1684 col_privileges,
1685 relOid, grantorId, OBJECT_COLUMN,
1686 relname, attnum,
1687 NameStr(pg_attribute_tuple->attname));
1688
1689 /*
1690 * Generate new ACL.
1691 */
1692 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1693 istmt->grant_option,
1694 istmt->behavior, istmt->grantees,
1695 col_privileges, grantorId,
1696 ownerId);
1697
1698 /*
1699 * We need the members of both old and new ACLs so we can correct the
1700 * shared dependency information.
1701 */
1702 nnewmembers = aclmembers(new_acl, &newmembers);
1703
1704 /* finished building new ACL value, now insert it */
1705
1706 /*
1707 * If the updated ACL is empty, we can set attacl to null, and maybe even
1708 * avoid an update of the pg_attribute row. This is worth testing because
1709 * we'll come through here multiple times for any relation-level REVOKE,
1710 * even if there were never any column GRANTs. Note we are assuming that
1711 * the "default" ACL state for columns is empty.
1712 */
1713 if (ACL_NUM(new_acl) > 0)
1714 {
1715 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1716 need_update = true;
1717 }
1718 else
1719 {
1720 nulls[Anum_pg_attribute_attacl - 1] = true;
1721 need_update = !isNull;
1722 }
1723 replaces[Anum_pg_attribute_attacl - 1] = true;
1724
1725 if (need_update)
1726 {
1727 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1728 values, nulls, replaces);
1729
1730 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1731
1732 /* Update initial privileges for extensions */
1733 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1734 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1735
1736 /* Update the shared dependency ACL info */
1737 updateAclDependencies(RelationRelationId, relOid, attnum,
1738 ownerId,
1739 noldmembers, oldmembers,
1740 nnewmembers, newmembers);
1741 }
1742
1743 pfree(new_acl);
1744
1745 ReleaseSysCache(attr_tuple);
1746}
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:461
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:787
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5460
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1524
#define ACL_ALL_RIGHTS_COLUMN
Definition: acl.h:159
#define ACL_NUM(ACL)
Definition: acl.h:108
#define DatumGetAclPCopy(X)
Definition: acl.h:121
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4565
static Acl * merge_acl_with_grant(Acl *old_acl, bool is_grant, bool grant_option, DropBehavior behavior, List *grantees, AclMode privileges, Oid grantorId, Oid ownerId)
Definition: aclchk.c:182
static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, AclMode privileges, Oid objectId, Oid grantorId, ObjectType objtype, const char *objname, AttrNumber att_number, const char *colname)
Definition: aclchk.c:241
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define NameStr(name)
Definition: c.h:717
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void pfree(void *pointer)
Definition: mcxt.c:1524
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
NameData relname
Definition: pg_class.h:38
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:491
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define RelationGetDescr(relation)
Definition: rel.h:538
ItemPointerData t_self
Definition: htup.h:65
DropBehavior behavior
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232

References ACL_ALL_RIGHTS_COLUMN, ACL_NUM, aclconcat(), acldefault(), aclmembers(), attnum, InternalGrant::behavior, CatalogTupleUpdate(), DatumGetAclPCopy, elog, ERROR, GETSTRUCT(), GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, heap_modify_tuple(), HeapTupleIsValid, Int16GetDatum(), InternalGrant::is_grant, merge_acl_with_grant(), NameStr, OBJECT_COLUMN, ObjectIdGetDatum(), pfree(), PointerGetDatum(), recordExtensionInitPriv(), RelationGetDescr, ReleaseSysCache(), relname, restrict_and_check_grant(), SearchSysCache2(), select_best_grantor(), SysCacheGetAttr(), HeapTupleData::t_self, updateAclDependencies(), and values.

Referenced by ExecGrant_Relation().

◆ ExecGrant_common()

static void ExecGrant_common ( InternalGrant istmt,
Oid  classid,
AclMode  default_privs,
void(*)(InternalGrant *istmt, HeapTuple tuple)  object_check 
)
static

Definition at line 2083 of file aclchk.c.

2085{
2086 int cacheid;
2087 Relation relation;
2088 ListCell *cell;
2089
2090 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2091 istmt->privileges = default_privs;
2092
2093 cacheid = get_object_catcache_oid(classid);
2094
2095 relation = table_open(classid, RowExclusiveLock);
2096
2097 foreach(cell, istmt->objects)
2098 {
2099 Oid objectid = lfirst_oid(cell);
2100 Datum aclDatum;
2101 Datum nameDatum;
2102 bool isNull;
2103 AclMode avail_goptions;
2104 AclMode this_privileges;
2105 Acl *old_acl;
2106 Acl *new_acl;
2107 Oid grantorId;
2108 Oid ownerId;
2109 HeapTuple tuple;
2110 HeapTuple newtuple;
2111 Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2112 bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2113 bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2114 int noldmembers;
2115 int nnewmembers;
2116 Oid *oldmembers;
2117 Oid *newmembers;
2118
2119 tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2120 if (!HeapTupleIsValid(tuple))
2121 elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2122
2123 /*
2124 * Additional object-type-specific checks
2125 */
2126 if (object_check)
2127 object_check(istmt, tuple);
2128
2129 /*
2130 * Get owner ID and working copy of existing ACL. If there's no ACL,
2131 * substitute the proper default.
2132 */
2133 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2134 tuple,
2135 get_object_attnum_owner(classid)));
2136 aclDatum = SysCacheGetAttr(cacheid,
2137 tuple,
2138 get_object_attnum_acl(classid),
2139 &isNull);
2140 if (isNull)
2141 {
2142 old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2143 /* There are no old member roles according to the catalogs */
2144 noldmembers = 0;
2145 oldmembers = NULL;
2146 }
2147 else
2148 {
2149 old_acl = DatumGetAclPCopy(aclDatum);
2150 /* Get the roles mentioned in the existing ACL */
2151 noldmembers = aclmembers(old_acl, &oldmembers);
2152 }
2153
2154 /* Determine ID to do the grant as, and available grant options */
2156 old_acl, ownerId,
2157 &grantorId, &avail_goptions);
2158
2159 nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2160 get_object_attnum_name(classid));
2161
2162 /*
2163 * Restrict the privileges to what we can actually grant, and emit the
2164 * standards-mandated warning and error messages.
2165 */
2166 this_privileges =
2167 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2168 istmt->all_privs, istmt->privileges,
2169 objectid, grantorId, get_object_type(classid, objectid),
2170 NameStr(*DatumGetName(nameDatum)),
2171 0, NULL);
2172
2173 /*
2174 * Generate new ACL.
2175 */
2176 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2177 istmt->grant_option, istmt->behavior,
2178 istmt->grantees, this_privileges,
2179 grantorId, ownerId);
2180
2181 /*
2182 * We need the members of both old and new ACLs so we can correct the
2183 * shared dependency information.
2184 */
2185 nnewmembers = aclmembers(new_acl, &newmembers);
2186
2187 /* finished building new ACL value, now insert it */
2188 replaces[get_object_attnum_acl(classid) - 1] = true;
2189 values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2190
2191 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2192 nulls, replaces);
2193
2194 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2195 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2196
2197 /* Update initial privileges for extensions */
2198 recordExtensionInitPriv(objectid, classid, 0, new_acl);
2199
2200 /* Update the shared dependency ACL info */
2201 updateAclDependencies(classid,
2202 objectid, 0,
2203 ownerId,
2204 noldmembers, oldmembers,
2205 nnewmembers, newmembers);
2206
2207 ReleaseSysCache(tuple);
2208
2209 pfree(new_acl);
2210
2211 /* prevent error when processing duplicate objects */
2213 }
2214
2215 table_close(relation, RowExclusiveLock);
2216}
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
void UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
Definition: lmgr.c:601
#define InplaceUpdateTupleLock
Definition: lockdefs.h:48
#define RowExclusiveLock
Definition: lockdefs.h:38
AttrNumber get_object_attnum_owner(Oid class_id)
AttrNumber get_object_attnum_name(Oid class_id)
const char * get_object_class_descr(Oid class_id)
AttrNumber get_object_attnum_acl(Oid class_id)
int get_object_catcache_oid(Oid class_id)
ObjectType get_object_type(Oid class_id, Oid object_id)
#define lfirst_oid(lc)
Definition: pg_list.h:174
static Name DatumGetName(Datum X)
Definition: postgres.h:365
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:247
AclMode privileges
HeapTuple SearchSysCacheLocked1(int cacheId, Datum key1)
Definition: syscache.c:287
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:631
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void CommandCounterIncrement(void)
Definition: xact.c:1100

References ACL_NO_RIGHTS, acldefault(), aclmembers(), InternalGrant::all_privs, InternalGrant::behavior, CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetAclPCopy, DatumGetName(), DatumGetObjectId(), elog, ERROR, get_object_attnum_acl(), get_object_attnum_name(), get_object_attnum_owner(), get_object_catcache_oid(), get_object_class_descr(), get_object_type(), GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, heap_modify_tuple(), HeapTupleIsValid, InplaceUpdateTupleLock, InternalGrant::is_grant, lfirst_oid, merge_acl_with_grant(), NameStr, ObjectIdGetDatum(), InternalGrant::objects, palloc0_array, pfree(), PointerGetDatum(), InternalGrant::privileges, recordExtensionInitPriv(), RelationGetDescr, ReleaseSysCache(), restrict_and_check_grant(), RowExclusiveLock, SearchSysCacheLocked1(), select_best_grantor(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), HeapTupleData::t_self, table_close(), table_open(), UnlockTuple(), updateAclDependencies(), and values.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Language_check()

static void ExecGrant_Language_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2219 of file aclchk.c.

2220{
2221 Form_pg_language pg_language_tuple;
2222
2223 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2224
2225 if (!pg_language_tuple->lanpltrusted)
2226 ereport(ERROR,
2227 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2228 errmsg("language \"%s\" is not trusted",
2229 NameStr(pg_language_tuple->lanname)),
2230 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2231 "because only superusers can use untrusted languages.")));
2232}
int errdetail(const char *fmt,...)
Definition: elog.c:1203
FormData_pg_language * Form_pg_language
Definition: pg_language.h:65

References ereport, errcode(), errdetail(), errmsg(), ERROR, GETSTRUCT(), and NameStr.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Largeobject()

static void ExecGrant_Largeobject ( InternalGrant istmt)
static

Definition at line 2235 of file aclchk.c.

2236{
2237 Relation relation;
2238 ListCell *cell;
2239
2240 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2242
2243 relation = table_open(LargeObjectMetadataRelationId,
2245
2246 foreach(cell, istmt->objects)
2247 {
2248 Oid loid = lfirst_oid(cell);
2249 Form_pg_largeobject_metadata form_lo_meta;
2250 char loname[NAMEDATALEN];
2251 Datum aclDatum;
2252 bool isNull;
2253 AclMode avail_goptions;
2254 AclMode this_privileges;
2255 Acl *old_acl;
2256 Acl *new_acl;
2257 Oid grantorId;
2258 Oid ownerId;
2259 HeapTuple newtuple;
2260 Datum values[Natts_pg_largeobject_metadata] = {0};
2261 bool nulls[Natts_pg_largeobject_metadata] = {0};
2262 bool replaces[Natts_pg_largeobject_metadata] = {0};
2263 int noldmembers;
2264 int nnewmembers;
2265 Oid *oldmembers;
2266 Oid *newmembers;
2267 ScanKeyData entry[1];
2268 SysScanDesc scan;
2269 HeapTuple tuple;
2270
2271 /* There's no syscache for pg_largeobject_metadata */
2272 ScanKeyInit(&entry[0],
2273 Anum_pg_largeobject_metadata_oid,
2274 BTEqualStrategyNumber, F_OIDEQ,
2275 ObjectIdGetDatum(loid));
2276
2277 scan = systable_beginscan(relation,
2278 LargeObjectMetadataOidIndexId, true,
2279 NULL, 1, entry);
2280
2281 tuple = systable_getnext(scan);
2282 if (!HeapTupleIsValid(tuple))
2283 elog(ERROR, "could not find tuple for large object %u", loid);
2284
2285 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2286
2287 /*
2288 * Get owner ID and working copy of existing ACL. If there's no ACL,
2289 * substitute the proper default.
2290 */
2291 ownerId = form_lo_meta->lomowner;
2292 aclDatum = heap_getattr(tuple,
2293 Anum_pg_largeobject_metadata_lomacl,
2294 RelationGetDescr(relation), &isNull);
2295 if (isNull)
2296 {
2297 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2298 /* There are no old member roles according to the catalogs */
2299 noldmembers = 0;
2300 oldmembers = NULL;
2301 }
2302 else
2303 {
2304 old_acl = DatumGetAclPCopy(aclDatum);
2305 /* Get the roles mentioned in the existing ACL */
2306 noldmembers = aclmembers(old_acl, &oldmembers);
2307 }
2308
2309 /* Determine ID to do the grant as, and available grant options */
2311 old_acl, ownerId,
2312 &grantorId, &avail_goptions);
2313
2314 /*
2315 * Restrict the privileges to what we can actually grant, and emit the
2316 * standards-mandated warning and error messages.
2317 */
2318 snprintf(loname, sizeof(loname), "large object %u", loid);
2319 this_privileges =
2320 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2321 istmt->all_privs, istmt->privileges,
2322 loid, grantorId, OBJECT_LARGEOBJECT,
2323 loname, 0, NULL);
2324
2325 /*
2326 * Generate new ACL.
2327 */
2328 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2329 istmt->grant_option, istmt->behavior,
2330 istmt->grantees, this_privileges,
2331 grantorId, ownerId);
2332
2333 /*
2334 * We need the members of both old and new ACLs so we can correct the
2335 * shared dependency information.
2336 */
2337 nnewmembers = aclmembers(new_acl, &newmembers);
2338
2339 /* finished building new ACL value, now insert it */
2340 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2341 values[Anum_pg_largeobject_metadata_lomacl - 1]
2342 = PointerGetDatum(new_acl);
2343
2344 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2345 values, nulls, replaces);
2346
2347 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2348
2349 /* Update initial privileges for extensions */
2350 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2351
2352 /* Update the shared dependency ACL info */
2353 updateAclDependencies(LargeObjectRelationId,
2354 form_lo_meta->oid, 0,
2355 ownerId,
2356 noldmembers, oldmembers,
2357 nnewmembers, newmembers);
2358
2359 systable_endscan(scan);
2360
2361 pfree(new_acl);
2362
2363 /* prevent error when processing duplicate objects */
2365 }
2366
2367 table_close(relation, RowExclusiveLock);
2368}
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:903
#define NAMEDATALEN
FormData_pg_largeobject_metadata * Form_pg_largeobject_metadata
#define snprintf
Definition: port.h:239
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References ACL_ALL_RIGHTS_LARGEOBJECT, ACL_NO_RIGHTS, acldefault(), aclmembers(), InternalGrant::all_privs, InternalGrant::behavior, BTEqualStrategyNumber, CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetAclPCopy, elog, ERROR, GETSTRUCT(), GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, InternalGrant::is_grant, lfirst_oid, merge_acl_with_grant(), NAMEDATALEN, OBJECT_LARGEOBJECT, ObjectIdGetDatum(), InternalGrant::objects, pfree(), PointerGetDatum(), InternalGrant::privileges, recordExtensionInitPriv(), RelationGetDescr, restrict_and_check_grant(), RowExclusiveLock, ScanKeyInit(), select_best_grantor(), snprintf, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), updateAclDependencies(), and values.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Parameter()

static void ExecGrant_Parameter ( InternalGrant istmt)
static

Definition at line 2391 of file aclchk.c.

2392{
2393 Relation relation;
2394 ListCell *cell;
2395
2396 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2398
2399 relation = table_open(ParameterAclRelationId, RowExclusiveLock);
2400
2401 foreach(cell, istmt->objects)
2402 {
2403 Oid parameterId = lfirst_oid(cell);
2404 Datum nameDatum;
2405 const char *parname;
2406 Datum aclDatum;
2407 bool isNull;
2408 AclMode avail_goptions;
2409 AclMode this_privileges;
2410 Acl *old_acl;
2411 Acl *new_acl;
2412 Oid grantorId;
2413 Oid ownerId;
2414 HeapTuple tuple;
2415 int noldmembers;
2416 int nnewmembers;
2417 Oid *oldmembers;
2418 Oid *newmembers;
2419
2420 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
2421 if (!HeapTupleIsValid(tuple))
2422 elog(ERROR, "cache lookup failed for parameter ACL %u",
2423 parameterId);
2424
2425 /* We'll need the GUC's name */
2426 nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
2427 Anum_pg_parameter_acl_parname);
2428 parname = TextDatumGetCString(nameDatum);
2429
2430 /* Treat all parameters as belonging to the bootstrap superuser. */
2431 ownerId = BOOTSTRAP_SUPERUSERID;
2432
2433 /*
2434 * Get working copy of existing ACL. If there's no ACL, substitute the
2435 * proper default.
2436 */
2437 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
2438 Anum_pg_parameter_acl_paracl,
2439 &isNull);
2440
2441 if (isNull)
2442 {
2443 old_acl = acldefault(istmt->objtype, ownerId);
2444 /* There are no old member roles according to the catalogs */
2445 noldmembers = 0;
2446 oldmembers = NULL;
2447 }
2448 else
2449 {
2450 old_acl = DatumGetAclPCopy(aclDatum);
2451 /* Get the roles mentioned in the existing ACL */
2452 noldmembers = aclmembers(old_acl, &oldmembers);
2453 }
2454
2455 /* Determine ID to do the grant as, and available grant options */
2457 old_acl, ownerId,
2458 &grantorId, &avail_goptions);
2459
2460 /*
2461 * Restrict the privileges to what we can actually grant, and emit the
2462 * standards-mandated warning and error messages.
2463 */
2464 this_privileges =
2465 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2466 istmt->all_privs, istmt->privileges,
2467 parameterId, grantorId,
2469 parname,
2470 0, NULL);
2471
2472 /*
2473 * Generate new ACL.
2474 */
2475 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2476 istmt->grant_option, istmt->behavior,
2477 istmt->grantees, this_privileges,
2478 grantorId, ownerId);
2479
2480 /*
2481 * We need the members of both old and new ACLs so we can correct the
2482 * shared dependency information.
2483 */
2484 nnewmembers = aclmembers(new_acl, &newmembers);
2485
2486 /*
2487 * If the new ACL is equal to the default, we don't need the catalog
2488 * entry any longer. Delete it rather than updating it, to avoid
2489 * leaving a degenerate entry.
2490 */
2491 if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
2492 {
2493 CatalogTupleDelete(relation, &tuple->t_self);
2494 }
2495 else
2496 {
2497 /* finished building new ACL value, now insert it */
2498 HeapTuple newtuple;
2499 Datum values[Natts_pg_parameter_acl] = {0};
2500 bool nulls[Natts_pg_parameter_acl] = {0};
2501 bool replaces[Natts_pg_parameter_acl] = {0};
2502
2503 replaces[Anum_pg_parameter_acl_paracl - 1] = true;
2504 values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
2505
2506 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2507 values, nulls, replaces);
2508
2509 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2510 }
2511
2512 /* Update initial privileges for extensions */
2513 recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
2514 new_acl);
2515
2516 /* Update the shared dependency ACL info */
2517 updateAclDependencies(ParameterAclRelationId, parameterId, 0,
2518 ownerId,
2519 noldmembers, oldmembers,
2520 nnewmembers, newmembers);
2521
2522 ReleaseSysCache(tuple);
2523 pfree(new_acl);
2524
2525 /* prevent error when processing duplicate objects */
2527 }
2528
2529 table_close(relation, RowExclusiveLock);
2530}
bool aclequal(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:543
#define ACL_ALL_RIGHTS_PARAMETER_ACL
Definition: acl.h:168
#define TextDatumGetCString(d)
Definition: builtins.h:98
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
ObjectType objtype
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References ACL_ALL_RIGHTS_PARAMETER_ACL, ACL_NO_RIGHTS, acldefault(), aclequal(), aclmembers(), InternalGrant::all_privs, InternalGrant::behavior, CatalogTupleDelete(), CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetAclPCopy, elog, ERROR, GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, heap_modify_tuple(), HeapTupleIsValid, InternalGrant::is_grant, lfirst_oid, merge_acl_with_grant(), OBJECT_PARAMETER_ACL, ObjectIdGetDatum(), InternalGrant::objects, InternalGrant::objtype, pfree(), PointerGetDatum(), InternalGrant::privileges, recordExtensionInitPriv(), RelationGetDescr, ReleaseSysCache(), restrict_and_check_grant(), RowExclusiveLock, SearchSysCache1(), select_best_grantor(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, updateAclDependencies(), and values.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Relation()

static void ExecGrant_Relation ( InternalGrant istmt)
static

Definition at line 1752 of file aclchk.c.

1753{
1754 Relation relation;
1755 Relation attRelation;
1756 ListCell *cell;
1757
1758 relation = table_open(RelationRelationId, RowExclusiveLock);
1759 attRelation = table_open(AttributeRelationId, RowExclusiveLock);
1760
1761 foreach(cell, istmt->objects)
1762 {
1763 Oid relOid = lfirst_oid(cell);
1764 Datum aclDatum;
1765 Form_pg_class pg_class_tuple;
1766 bool isNull;
1767 AclMode this_privileges;
1768 AclMode *col_privileges;
1769 int num_col_privileges;
1770 bool have_col_privileges;
1771 Acl *old_acl;
1772 Acl *old_rel_acl;
1773 int noldmembers;
1774 Oid *oldmembers;
1775 Oid ownerId;
1776 HeapTuple tuple;
1777 ListCell *cell_colprivs;
1778
1779 tuple = SearchSysCacheLocked1(RELOID, ObjectIdGetDatum(relOid));
1780 if (!HeapTupleIsValid(tuple))
1781 elog(ERROR, "cache lookup failed for relation %u", relOid);
1782 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
1783
1784 /* Not sensible to grant on an index */
1785 if (pg_class_tuple->relkind == RELKIND_INDEX ||
1786 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
1787 ereport(ERROR,
1788 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1789 errmsg("\"%s\" is an index",
1790 NameStr(pg_class_tuple->relname))));
1791
1792 /* Composite types aren't tables either */
1793 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
1794 ereport(ERROR,
1795 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1796 errmsg("\"%s\" is a composite type",
1797 NameStr(pg_class_tuple->relname))));
1798
1799 /* Used GRANT SEQUENCE on a non-sequence? */
1800 if (istmt->objtype == OBJECT_SEQUENCE &&
1801 pg_class_tuple->relkind != RELKIND_SEQUENCE)
1802 ereport(ERROR,
1803 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1804 errmsg("\"%s\" is not a sequence",
1805 NameStr(pg_class_tuple->relname))));
1806
1807 /* Adjust the default permissions based on object type */
1808 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1809 {
1810 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1811 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1812 else
1813 this_privileges = ACL_ALL_RIGHTS_RELATION;
1814 }
1815 else
1816 this_privileges = istmt->privileges;
1817
1818 /*
1819 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1820 * so we have to look at the relkind to determine the supported
1821 * permissions. The OR of table and sequence permissions were already
1822 * checked.
1823 */
1824 if (istmt->objtype == OBJECT_TABLE)
1825 {
1826 if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
1827 {
1828 /*
1829 * For backward compatibility, just throw a warning for
1830 * invalid sequence permissions when using the non-sequence
1831 * GRANT syntax.
1832 */
1833 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
1834 {
1835 /*
1836 * Mention the object name because the user needs to know
1837 * which operations succeeded. This is required because
1838 * WARNING allows the command to continue.
1839 */
1841 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1842 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1843 NameStr(pg_class_tuple->relname))));
1844 this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
1845 }
1846 }
1847 else
1848 {
1849 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
1850 {
1851 /*
1852 * USAGE is the only permission supported by sequences but
1853 * not by non-sequences. Don't mention the object name
1854 * because we didn't in the combined TABLE | SEQUENCE
1855 * check.
1856 */
1857 ereport(ERROR,
1858 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1859 errmsg("invalid privilege type %s for table",
1860 "USAGE")));
1861 }
1862 }
1863 }
1864
1865 /*
1866 * Set up array in which we'll accumulate any column privilege bits
1867 * that need modification. The array is indexed such that entry [0]
1868 * corresponds to FirstLowInvalidHeapAttributeNumber.
1869 */
1870 num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
1871 col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
1872 have_col_privileges = false;
1873
1874 /*
1875 * If we are revoking relation privileges that are also column
1876 * privileges, we must implicitly revoke them from each column too,
1877 * per SQL spec. (We don't need to implicitly add column privileges
1878 * during GRANT because the permissions-checking code always checks
1879 * both relation and per-column privileges.)
1880 */
1881 if (!istmt->is_grant &&
1882 (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
1883 {
1884 expand_all_col_privileges(relOid, pg_class_tuple,
1885 this_privileges & ACL_ALL_RIGHTS_COLUMN,
1886 col_privileges,
1887 num_col_privileges);
1888 have_col_privileges = true;
1889 }
1890
1891 /*
1892 * Get owner ID and working copy of existing ACL. If there's no ACL,
1893 * substitute the proper default.
1894 */
1895 ownerId = pg_class_tuple->relowner;
1896 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1897 &isNull);
1898 if (isNull)
1899 {
1900 switch (pg_class_tuple->relkind)
1901 {
1902 case RELKIND_SEQUENCE:
1903 old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
1904 break;
1905 default:
1906 old_acl = acldefault(OBJECT_TABLE, ownerId);
1907 break;
1908 }
1909 /* There are no old member roles according to the catalogs */
1910 noldmembers = 0;
1911 oldmembers = NULL;
1912 }
1913 else
1914 {
1915 old_acl = DatumGetAclPCopy(aclDatum);
1916 /* Get the roles mentioned in the existing ACL */
1917 noldmembers = aclmembers(old_acl, &oldmembers);
1918 }
1919
1920 /* Need an extra copy of original rel ACL for column handling */
1921 old_rel_acl = aclcopy(old_acl);
1922
1923 /*
1924 * Handle relation-level privileges, if any were specified
1925 */
1926 if (this_privileges != ACL_NO_RIGHTS)
1927 {
1928 AclMode avail_goptions;
1929 Acl *new_acl;
1930 Oid grantorId;
1931 HeapTuple newtuple;
1932 Datum values[Natts_pg_class] = {0};
1933 bool nulls[Natts_pg_class] = {0};
1934 bool replaces[Natts_pg_class] = {0};
1935 int nnewmembers;
1936 Oid *newmembers;
1937 ObjectType objtype;
1938
1939 /* Determine ID to do the grant as, and available grant options */
1940 select_best_grantor(GetUserId(), this_privileges,
1941 old_acl, ownerId,
1942 &grantorId, &avail_goptions);
1943
1944 switch (pg_class_tuple->relkind)
1945 {
1946 case RELKIND_SEQUENCE:
1947 objtype = OBJECT_SEQUENCE;
1948 break;
1949 default:
1950 objtype = OBJECT_TABLE;
1951 break;
1952 }
1953
1954 /*
1955 * Restrict the privileges to what we can actually grant, and emit
1956 * the standards-mandated warning and error messages.
1957 */
1958 this_privileges =
1959 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1960 istmt->all_privs, this_privileges,
1961 relOid, grantorId, objtype,
1962 NameStr(pg_class_tuple->relname),
1963 0, NULL);
1964
1965 /*
1966 * Generate new ACL.
1967 */
1968 new_acl = merge_acl_with_grant(old_acl,
1969 istmt->is_grant,
1970 istmt->grant_option,
1971 istmt->behavior,
1972 istmt->grantees,
1973 this_privileges,
1974 grantorId,
1975 ownerId);
1976
1977 /*
1978 * We need the members of both old and new ACLs so we can correct
1979 * the shared dependency information.
1980 */
1981 nnewmembers = aclmembers(new_acl, &newmembers);
1982
1983 /* finished building new ACL value, now insert it */
1984 replaces[Anum_pg_class_relacl - 1] = true;
1985 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
1986
1987 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
1988 values, nulls, replaces);
1989
1990 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
1991 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
1992
1993 /* Update initial privileges for extensions */
1994 recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
1995
1996 /* Update the shared dependency ACL info */
1997 updateAclDependencies(RelationRelationId, relOid, 0,
1998 ownerId,
1999 noldmembers, oldmembers,
2000 nnewmembers, newmembers);
2001
2002 pfree(new_acl);
2003 }
2004 else
2005 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2006
2007 /*
2008 * Handle column-level privileges, if any were specified or implied.
2009 * We first expand the user-specified column privileges into the
2010 * array, and then iterate over all nonempty array entries.
2011 */
2012 foreach(cell_colprivs, istmt->col_privs)
2013 {
2014 AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
2015
2016 if (col_privs->priv_name == NULL)
2017 this_privileges = ACL_ALL_RIGHTS_COLUMN;
2018 else
2019 this_privileges = string_to_privilege(col_privs->priv_name);
2020
2021 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
2022 ereport(ERROR,
2023 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2024 errmsg("invalid privilege type %s for column",
2025 privilege_to_string(this_privileges))));
2026
2027 if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
2028 this_privileges & ~((AclMode) ACL_SELECT))
2029 {
2030 /*
2031 * The only column privilege allowed on sequences is SELECT.
2032 * This is a warning not error because we do it that way for
2033 * relation-level privileges.
2034 */
2036 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2037 errmsg("sequence \"%s\" only supports SELECT column privileges",
2038 NameStr(pg_class_tuple->relname))));
2039
2040 this_privileges &= (AclMode) ACL_SELECT;
2041 }
2042
2043 expand_col_privileges(col_privs->cols, relOid,
2044 this_privileges,
2045 col_privileges,
2046 num_col_privileges);
2047 have_col_privileges = true;
2048 }
2049
2050 if (have_col_privileges)
2051 {
2052 AttrNumber i;
2053
2054 for (i = 0; i < num_col_privileges; i++)
2055 {
2056 if (col_privileges[i] == ACL_NO_RIGHTS)
2057 continue;
2058 ExecGrant_Attribute(istmt,
2059 relOid,
2060 NameStr(pg_class_tuple->relname),
2062 ownerId,
2063 col_privileges[i],
2064 attRelation,
2065 old_rel_acl);
2066 }
2067 }
2068
2069 pfree(old_rel_acl);
2070 pfree(col_privileges);
2071
2072 ReleaseSysCache(tuple);
2073
2074 /* prevent error when processing duplicate objects */
2076 }
2077
2078 table_close(attRelation, RowExclusiveLock);
2079 table_close(relation, RowExclusiveLock);
2080}
Acl * aclcopy(const Acl *orig_acl)
Definition: acl.c:441
static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1561
static void expand_col_privileges(List *colnames, Oid table_oid, AclMode this_privileges, AclMode *col_privileges, int num_col_privileges)
Definition: aclchk.c:1528
static void ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, AttrNumber attnum, Oid ownerId, AclMode col_privileges, Relation attRelation, const Acl *old_rel_acl)
Definition: aclchk.c:1607
int16 AttrNumber
Definition: attnum.h:21
#define WARNING
Definition: elog.h:36
int i
Definition: isn.c:74
void * palloc0(Size size)
Definition: mcxt.c:1347
ObjectType
Definition: parsenodes.h:2311
#define ACL_SELECT
Definition: parsenodes.h:77
FormData_pg_class * Form_pg_class
Definition: pg_class.h:156
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References ACL_ALL_RIGHTS_COLUMN, ACL_ALL_RIGHTS_RELATION, ACL_ALL_RIGHTS_SEQUENCE, ACL_NO_RIGHTS, ACL_SELECT, aclcopy(), acldefault(), aclmembers(), InternalGrant::all_privs, InternalGrant::behavior, CatalogTupleUpdate(), InternalGrant::col_privs, AccessPriv::cols, CommandCounterIncrement(), DatumGetAclPCopy, elog, ereport, errcode(), errmsg(), ERROR, ExecGrant_Attribute(), expand_all_col_privileges(), expand_col_privileges(), FirstLowInvalidHeapAttributeNumber, GETSTRUCT(), GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, heap_modify_tuple(), HeapTupleIsValid, i, InplaceUpdateTupleLock, InternalGrant::is_grant, lfirst, lfirst_oid, merge_acl_with_grant(), NameStr, OBJECT_SEQUENCE, OBJECT_TABLE, ObjectIdGetDatum(), InternalGrant::objects, InternalGrant::objtype, palloc0(), pfree(), PointerGetDatum(), AccessPriv::priv_name, privilege_to_string(), InternalGrant::privileges, recordExtensionInitPriv(), RelationGetDescr, ReleaseSysCache(), restrict_and_check_grant(), RowExclusiveLock, SearchSysCacheLocked1(), select_best_grantor(), string_to_privilege(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), UnlockTuple(), updateAclDependencies(), values, and WARNING.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Type_check()

static void ExecGrant_Type_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2371 of file aclchk.c.

2372{
2373 Form_pg_type pg_type_tuple;
2374
2375 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2376
2377 /* Disallow GRANT on dependent types */
2378 if (IsTrueArrayType(pg_type_tuple))
2379 ereport(ERROR,
2380 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2381 errmsg("cannot set privileges of array types"),
2382 errhint("Set the privileges of the element type instead.")));
2383 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2384 ereport(ERROR,
2385 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2386 errmsg("cannot set privileges of multirange types"),
2387 errhint("Set the privileges of the range type instead.")));
2388}
int errhint(const char *fmt,...)
Definition: elog.c:1317
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261

References ereport, errcode(), errhint(), errmsg(), ERROR, and GETSTRUCT().

Referenced by ExecGrantStmt_oids().

◆ ExecGrantStmt_oids()

static void ExecGrantStmt_oids ( InternalGrant istmt)
static

Definition at line 602 of file aclchk.c.

603{
604 switch (istmt->objtype)
605 {
606 case OBJECT_TABLE:
607 case OBJECT_SEQUENCE:
608 ExecGrant_Relation(istmt);
609 break;
610 case OBJECT_DATABASE:
611 ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
612 break;
613 case OBJECT_DOMAIN:
614 case OBJECT_TYPE:
616 break;
617 case OBJECT_FDW:
618 ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
619 break;
621 ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
622 break;
623 case OBJECT_FUNCTION:
624 case OBJECT_PROCEDURE:
625 case OBJECT_ROUTINE:
626 ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
627 break;
628 case OBJECT_LANGUAGE:
630 break;
633 break;
634 case OBJECT_SCHEMA:
635 ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
636 break;
638 ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
639 break;
641 ExecGrant_Parameter(istmt);
642 break;
643 default:
644 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
645 (int) istmt->objtype);
646 }
647
648 /*
649 * Pass the info to event triggers about the just-executed GRANT. Note
650 * that we prefer to do it after actually executing it, because that gives
651 * the functions a chance to adjust the istmt with privileges actually
652 * granted.
653 */
656}
#define ACL_ALL_RIGHTS_FOREIGN_SERVER
Definition: acl.h:164
#define ACL_ALL_RIGHTS_TABLESPACE
Definition: acl.h:170
#define ACL_ALL_RIGHTS_DATABASE
Definition: acl.h:162
#define ACL_ALL_RIGHTS_LANGUAGE
Definition: acl.h:166
#define ACL_ALL_RIGHTS_FDW
Definition: acl.h:163
static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2371
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2083
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2235
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2391
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1752
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2219
bool EventTriggerSupportsObjectType(ObjectType obtype)
void EventTriggerCollectGrant(InternalGrant *istmt)

References ACL_ALL_RIGHTS_DATABASE, ACL_ALL_RIGHTS_FDW, ACL_ALL_RIGHTS_FOREIGN_SERVER, ACL_ALL_RIGHTS_FUNCTION, ACL_ALL_RIGHTS_LANGUAGE, ACL_ALL_RIGHTS_SCHEMA, ACL_ALL_RIGHTS_TABLESPACE, ACL_ALL_RIGHTS_TYPE, elog, ERROR, EventTriggerCollectGrant(), EventTriggerSupportsObjectType(), ExecGrant_common(), ExecGrant_Language_check(), ExecGrant_Largeobject(), ExecGrant_Parameter(), ExecGrant_Relation(), ExecGrant_Type_check(), OBJECT_DATABASE, OBJECT_DOMAIN, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_PARAMETER_ACL, OBJECT_PROCEDURE, OBJECT_ROUTINE, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TYPE, and InternalGrant::objtype.

Referenced by ExecuteGrantStmt(), and RemoveRoleFromObjectACL().

◆ ExecuteGrantStmt()

void ExecuteGrantStmt ( GrantStmt stmt)

Definition at line 392 of file aclchk.c.

393{
394 InternalGrant istmt;
395 ListCell *cell;
396 const char *errormsg;
397 AclMode all_privileges;
398
399 if (stmt->grantor)
400 {
401 Oid grantor;
402
403 grantor = get_rolespec_oid(stmt->grantor, false);
404
405 /*
406 * Currently, this clause is only for SQL compatibility, not very
407 * interesting otherwise.
408 */
409 if (grantor != GetUserId())
411 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
412 errmsg("grantor must be current user")));
413 }
414
415 /*
416 * Turn the regular GrantStmt into the InternalGrant form.
417 */
418 istmt.is_grant = stmt->is_grant;
419 istmt.objtype = stmt->objtype;
420
421 /* Collect the OIDs of the target objects */
422 switch (stmt->targtype)
423 {
425 istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
426 stmt->is_grant);
427 break;
429 istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
430 break;
431 /* ACL_TARGET_DEFAULTS should not be seen here */
432 default:
433 elog(ERROR, "unrecognized GrantStmt.targtype: %d",
434 (int) stmt->targtype);
435 }
436
437 /* all_privs to be filled below */
438 /* privileges to be filled below */
439 istmt.col_privs = NIL; /* may get filled below */
440 istmt.grantees = NIL; /* filled below */
441 istmt.grant_option = stmt->grant_option;
442 istmt.behavior = stmt->behavior;
443
444 /*
445 * Convert the RoleSpec list into an Oid list. Note that at this point we
446 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
447 * there shouldn't be any additional work needed to support this case.
448 */
449 foreach(cell, stmt->grantees)
450 {
451 RoleSpec *grantee = (RoleSpec *) lfirst(cell);
452 Oid grantee_uid;
453
454 switch (grantee->roletype)
455 {
456 case ROLESPEC_PUBLIC:
457 grantee_uid = ACL_ID_PUBLIC;
458 break;
459 default:
460 grantee_uid = get_rolespec_oid(grantee, false);
461 break;
462 }
463 istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
464 }
465
466 /*
467 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
468 * bitmask. Note: objtype can't be OBJECT_COLUMN.
469 */
470 switch (stmt->objtype)
471 {
472 case OBJECT_TABLE:
473
474 /*
475 * Because this might be a sequence, we test both relation and
476 * sequence bits, and later do a more limited test when we know
477 * the object type.
478 */
480 errormsg = gettext_noop("invalid privilege type %s for relation");
481 break;
482 case OBJECT_SEQUENCE:
483 all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
484 errormsg = gettext_noop("invalid privilege type %s for sequence");
485 break;
486 case OBJECT_DATABASE:
487 all_privileges = ACL_ALL_RIGHTS_DATABASE;
488 errormsg = gettext_noop("invalid privilege type %s for database");
489 break;
490 case OBJECT_DOMAIN:
491 all_privileges = ACL_ALL_RIGHTS_TYPE;
492 errormsg = gettext_noop("invalid privilege type %s for domain");
493 break;
494 case OBJECT_FUNCTION:
495 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
496 errormsg = gettext_noop("invalid privilege type %s for function");
497 break;
498 case OBJECT_LANGUAGE:
499 all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
500 errormsg = gettext_noop("invalid privilege type %s for language");
501 break;
503 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
504 errormsg = gettext_noop("invalid privilege type %s for large object");
505 break;
506 case OBJECT_SCHEMA:
507 all_privileges = ACL_ALL_RIGHTS_SCHEMA;
508 errormsg = gettext_noop("invalid privilege type %s for schema");
509 break;
510 case OBJECT_PROCEDURE:
511 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
512 errormsg = gettext_noop("invalid privilege type %s for procedure");
513 break;
514 case OBJECT_ROUTINE:
515 all_privileges = ACL_ALL_RIGHTS_FUNCTION;
516 errormsg = gettext_noop("invalid privilege type %s for routine");
517 break;
519 all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
520 errormsg = gettext_noop("invalid privilege type %s for tablespace");
521 break;
522 case OBJECT_TYPE:
523 all_privileges = ACL_ALL_RIGHTS_TYPE;
524 errormsg = gettext_noop("invalid privilege type %s for type");
525 break;
526 case OBJECT_FDW:
527 all_privileges = ACL_ALL_RIGHTS_FDW;
528 errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
529 break;
531 all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
532 errormsg = gettext_noop("invalid privilege type %s for foreign server");
533 break;
535 all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
536 errormsg = gettext_noop("invalid privilege type %s for parameter");
537 break;
538 default:
539 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
540 (int) stmt->objtype);
541 /* keep compiler quiet */
542 all_privileges = ACL_NO_RIGHTS;
543 errormsg = NULL;
544 }
545
546 if (stmt->privileges == NIL)
547 {
548 istmt.all_privs = true;
549
550 /*
551 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
552 * depending on the object type
553 */
555 }
556 else
557 {
558 istmt.all_privs = false;
560
561 foreach(cell, stmt->privileges)
562 {
563 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
564 AclMode priv;
565
566 /*
567 * If it's a column-level specification, we just set it aside in
568 * col_privs for the moment; but insist it's for a relation.
569 */
570 if (privnode->cols)
571 {
572 if (stmt->objtype != OBJECT_TABLE)
574 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
575 errmsg("column privileges are only valid for relations")));
576 istmt.col_privs = lappend(istmt.col_privs, privnode);
577 continue;
578 }
579
580 if (privnode->priv_name == NULL) /* parser mistake? */
581 elog(ERROR, "AccessPriv node must specify privilege or columns");
582 priv = string_to_privilege(privnode->priv_name);
583
584 if (priv & ~((AclMode) all_privileges))
586 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
587 errmsg(errormsg, privilege_to_string(priv))));
588
589 istmt.privileges |= priv;
590 }
591 }
592
593 ExecGrantStmt_oids(&istmt);
594}
static void ExecGrantStmt_oids(InternalGrant *istmt)
Definition: aclchk.c:602
static List * objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
Definition: aclchk.c:664
static List * objectsInSchemaToOids(ObjectType objtype, List *nspnames)
Definition: aclchk.c:776
List * lappend(List *list, void *datum)
Definition: list.c:339
@ ACL_TARGET_OBJECT
Definition: parsenodes.h:2552
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2553

References ACL_ALL_RIGHTS_DATABASE, ACL_ALL_RIGHTS_FDW, ACL_ALL_RIGHTS_FOREIGN_SERVER, ACL_ALL_RIGHTS_FUNCTION, ACL_ALL_RIGHTS_LANGUAGE, ACL_ALL_RIGHTS_LARGEOBJECT, ACL_ALL_RIGHTS_PARAMETER_ACL, ACL_ALL_RIGHTS_RELATION, ACL_ALL_RIGHTS_SCHEMA, ACL_ALL_RIGHTS_SEQUENCE, ACL_ALL_RIGHTS_TABLESPACE, ACL_ALL_RIGHTS_TYPE, ACL_ID_PUBLIC, ACL_NO_RIGHTS, ACL_TARGET_ALL_IN_SCHEMA, ACL_TARGET_OBJECT, InternalGrant::all_privs, InternalGrant::behavior, InternalGrant::col_privs, AccessPriv::cols, elog, ereport, errcode(), errmsg(), ERROR, ExecGrantStmt_oids(), get_rolespec_oid(), gettext_noop, GetUserId(), InternalGrant::grant_option, InternalGrant::grantees, InternalGrant::is_grant, lappend(), lappend_oid(), lfirst, NIL, OBJECT_DATABASE, OBJECT_DOMAIN, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_PARAMETER_ACL, OBJECT_PROCEDURE, OBJECT_ROUTINE, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TYPE, objectNamesToOids(), InternalGrant::objects, objectsInSchemaToOids(), InternalGrant::objtype, AccessPriv::priv_name, privilege_to_string(), InternalGrant::privileges, ROLESPEC_PUBLIC, RoleSpec::roletype, stmt, and string_to_privilege().

Referenced by ProcessUtilitySlow(), and standard_ProcessUtility().

◆ expand_all_col_privileges()

static void expand_all_col_privileges ( Oid  table_oid,
Form_pg_class  classForm,
AclMode  this_privileges,
AclMode col_privileges,
int  num_col_privileges 
)
static

Definition at line 1561 of file aclchk.c.

1565{
1566 AttrNumber curr_att;
1567
1568 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1569 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1570 curr_att <= classForm->relnatts;
1571 curr_att++)
1572 {
1573 HeapTuple attTuple;
1574 bool isdropped;
1575
1576 if (curr_att == InvalidAttrNumber)
1577 continue;
1578
1579 /* Views don't have any system columns at all */
1580 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1581 continue;
1582
1583 attTuple = SearchSysCache2(ATTNUM,
1584 ObjectIdGetDatum(table_oid),
1585 Int16GetDatum(curr_att));
1586 if (!HeapTupleIsValid(attTuple))
1587 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1588 curr_att, table_oid);
1589
1590 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1591
1592 ReleaseSysCache(attTuple);
1593
1594 /* ignore dropped columns */
1595 if (isdropped)
1596 continue;
1597
1598 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1599 }
1600}
#define InvalidAttrNumber
Definition: attnum.h:23
Assert(PointerIsAligned(start, uint64))

References Assert(), elog, ERROR, FirstLowInvalidHeapAttributeNumber, GETSTRUCT(), HeapTupleIsValid, Int16GetDatum(), InvalidAttrNumber, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache2().

Referenced by ExecGrant_Relation().

◆ expand_col_privileges()

static void expand_col_privileges ( List colnames,
Oid  table_oid,
AclMode  this_privileges,
AclMode col_privileges,
int  num_col_privileges 
)
static

Definition at line 1528 of file aclchk.c.

1532{
1533 ListCell *cell;
1534
1535 foreach(cell, colnames)
1536 {
1537 char *colname = strVal(lfirst(cell));
1539
1540 attnum = get_attnum(table_oid, colname);
1542 ereport(ERROR,
1543 (errcode(ERRCODE_UNDEFINED_COLUMN),
1544 errmsg("column \"%s\" of relation \"%s\" does not exist",
1545 colname, get_rel_name(table_oid))));
1547 if (attnum <= 0 || attnum >= num_col_privileges)
1548 elog(ERROR, "column number out of range"); /* safety check */
1549 col_privileges[attnum] |= this_privileges;
1550 }
1551}
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2011
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:893
#define strVal(v)
Definition: value.h:82

References attnum, elog, ereport, errcode(), errmsg(), ERROR, FirstLowInvalidHeapAttributeNumber, get_attnum(), get_rel_name(), InvalidAttrNumber, lfirst, and strVal.

Referenced by ExecGrant_Relation().

◆ get_default_acl_internal()

static Acl * get_default_acl_internal ( Oid  roleId,
Oid  nsp_oid,
char  objtype 
)
static

Definition at line 4180 of file aclchk.c.

4181{
4182 Acl *result = NULL;
4183 HeapTuple tuple;
4184
4185 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4186 ObjectIdGetDatum(roleId),
4187 ObjectIdGetDatum(nsp_oid),
4188 CharGetDatum(objtype));
4189
4190 if (HeapTupleIsValid(tuple))
4191 {
4192 Datum aclDatum;
4193 bool isNull;
4194
4195 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4196 Anum_pg_default_acl_defaclacl,
4197 &isNull);
4198 if (!isNull)
4199 result = DatumGetAclPCopy(aclDatum);
4200 ReleaseSysCache(tuple);
4201 }
4202
4203 return result;
4204}
static Datum CharGetDatum(char X)
Definition: postgres.h:127
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:243

References CharGetDatum(), DatumGetAclPCopy, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache3(), and SysCacheGetAttr().

Referenced by get_user_default_acl().

◆ get_user_default_acl()

Acl * get_user_default_acl ( ObjectType  objtype,
Oid  ownerId,
Oid  nsp_oid 
)

Definition at line 4215 of file aclchk.c.

4216{
4217 Acl *result;
4218 Acl *glob_acl;
4219 Acl *schema_acl;
4220 Acl *def_acl;
4221 char defaclobjtype;
4222
4223 /*
4224 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4225 * yet.
4226 */
4228 return NULL;
4229
4230 /* Check if object type is supported in pg_default_acl */
4231 switch (objtype)
4232 {
4233 case OBJECT_TABLE:
4234 defaclobjtype = DEFACLOBJ_RELATION;
4235 break;
4236
4237 case OBJECT_SEQUENCE:
4238 defaclobjtype = DEFACLOBJ_SEQUENCE;
4239 break;
4240
4241 case OBJECT_FUNCTION:
4242 defaclobjtype = DEFACLOBJ_FUNCTION;
4243 break;
4244
4245 case OBJECT_TYPE:
4246 defaclobjtype = DEFACLOBJ_TYPE;
4247 break;
4248
4249 case OBJECT_SCHEMA:
4250 defaclobjtype = DEFACLOBJ_NAMESPACE;
4251 break;
4252
4253 default:
4254 return NULL;
4255 }
4256
4257 /* Look up the relevant pg_default_acl entries */
4258 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4259 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4260
4261 /* Quick out if neither entry exists */
4262 if (glob_acl == NULL && schema_acl == NULL)
4263 return NULL;
4264
4265 /* We need to know the hard-wired default value, too */
4266 def_acl = acldefault(objtype, ownerId);
4267
4268 /* If there's no global entry, substitute the hard-wired default */
4269 if (glob_acl == NULL)
4270 glob_acl = def_acl;
4271
4272 /* Merge in any per-schema privileges */
4273 result = aclmerge(glob_acl, schema_acl, ownerId);
4274
4275 /*
4276 * For efficiency, we want to return NULL if the result equals default.
4277 * This requires sorting both arrays to get an accurate comparison.
4278 */
4279 aclitemsort(result);
4280 aclitemsort(def_acl);
4281 if (aclequal(result, def_acl))
4282 result = NULL;
4283
4284 return result;
4285}
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:485
void aclitemsort(Acl *acl)
Definition: acl.c:529
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4180
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:476
#define InvalidOid
Definition: postgres_ext.h:37

References acldefault(), aclequal(), aclitemsort(), aclmerge(), get_default_acl_internal(), InvalidOid, IsBootstrapProcessingMode, OBJECT_FUNCTION, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, and OBJECT_TYPE.

Referenced by heap_create_with_catalog(), NamespaceCreate(), ProcedureCreate(), and TypeCreate().

◆ getRelationsInNamespace()

static List * getRelationsInNamespace ( Oid  namespaceId,
char  relkind 
)
static

Definition at line 865 of file aclchk.c.

866{
867 List *relations = NIL;
868 ScanKeyData key[2];
869 Relation rel;
870 TableScanDesc scan;
871 HeapTuple tuple;
872
873 ScanKeyInit(&key[0],
874 Anum_pg_class_relnamespace,
875 BTEqualStrategyNumber, F_OIDEQ,
876 ObjectIdGetDatum(namespaceId));
877 ScanKeyInit(&key[1],
878 Anum_pg_class_relkind,
879 BTEqualStrategyNumber, F_CHAREQ,
880 CharGetDatum(relkind));
881
882 rel = table_open(RelationRelationId, AccessShareLock);
883 scan = table_beginscan_catalog(rel, 2, key);
884
885 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
886 {
887 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
888
889 relations = lappend_oid(relations, oid);
890 }
891
892 table_endscan(scan);
894
895 return relations;
896}
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1347
#define AccessShareLock
Definition: lockdefs.h:36
@ ForwardScanDirection
Definition: sdir.h:28
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, struct ScanKeyData *key)
Definition: tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:989

References AccessShareLock, BTEqualStrategyNumber, CharGetDatum(), ForwardScanDirection, GETSTRUCT(), heap_getnext(), sort-test::key, lappend_oid(), NIL, ObjectIdGetDatum(), ScanKeyInit(), table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by objectsInSchemaToOids().

◆ has_bypassrls_privilege()

bool has_bypassrls_privilege ( Oid  roleid)

Definition at line 4156 of file aclchk.c.

4157{
4158 bool result = false;
4159 HeapTuple utup;
4160
4161 /* Superusers bypass all permission checking. */
4162 if (superuser_arg(roleid))
4163 return true;
4164
4165 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4166 if (HeapTupleIsValid(utup))
4167 {
4168 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4169 ReleaseSysCache(utup);
4170 }
4171 return result;
4172}
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:56
bool rolbypassrls
Definition: pg_authid.h:41
bool superuser_arg(Oid roleid)
Definition: superuser.c:56

References GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), rolbypassrls, SearchSysCache1(), and superuser_arg().

Referenced by AlterRole(), check_enable_rls(), CreateRole(), and RI_Initial_Check().

◆ has_createrole_privilege()

bool has_createrole_privilege ( Oid  roleid)

Definition at line 4137 of file aclchk.c.

4138{
4139 bool result = false;
4140 HeapTuple utup;
4141
4142 /* Superusers bypass all permission checking. */
4143 if (superuser_arg(roleid))
4144 return true;
4145
4146 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4147 if (HeapTupleIsValid(utup))
4148 {
4149 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4150 ReleaseSysCache(utup);
4151 }
4152 return result;
4153}
bool rolcreaterole
Definition: pg_authid.h:37

References GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), rolcreaterole, SearchSysCache1(), and superuser_arg().

Referenced by check_object_ownership(), CreateRole(), and have_createrole_privilege().

◆ merge_acl_with_grant()

static Acl * merge_acl_with_grant ( Acl old_acl,
bool  is_grant,
bool  grant_option,
DropBehavior  behavior,
List grantees,
AclMode  privileges,
Oid  grantorId,
Oid  ownerId 
)
static

Definition at line 182 of file aclchk.c.

186{
187 unsigned modechg;
188 ListCell *j;
189 Acl *new_acl;
190
191 modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
192
193 new_acl = old_acl;
194
195 foreach(j, grantees)
196 {
197 AclItem aclitem;
198 Acl *newer_acl;
199
200 aclitem.ai_grantee = lfirst_oid(j);
201
202 /*
203 * Grant options can only be granted to individual roles, not PUBLIC.
204 * The reason is that if a user would re-grant a privilege that he
205 * held through PUBLIC, and later the user is removed, the situation
206 * is impossible to clean up.
207 */
208 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
210 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
211 errmsg("grant options can only be granted to roles")));
212
213 aclitem.ai_grantor = grantorId;
214
215 /*
216 * The asymmetry in the conditions here comes from the spec. In
217 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
218 * to grant both the basic privilege and its grant option. But in
219 * REVOKE, plain revoke revokes both the basic privilege and its grant
220 * option, while REVOKE GRANT OPTION revokes only the option.
221 */
223 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
224 (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
225
226 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
227
228 /* avoid memory leak when there are many grantees */
229 pfree(new_acl);
230 new_acl = newer_acl;
231 }
232
233 return new_acl;
234}
Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, int modechg, Oid ownerId, DropBehavior behavior)
Definition: acl.c:976
#define ACL_MODECHG_DEL
Definition: acl.h:130
#define ACL_MODECHG_ADD
Definition: acl.h:129
#define ACLITEM_SET_PRIVS_GOPTIONS(item, privs, goptions)
Definition: acl.h:82
int j
Definition: isn.c:75
Definition: acl.h:55
Oid ai_grantee
Definition: acl.h:56
Oid ai_grantor
Definition: acl.h:57

References ACL_ID_PUBLIC, ACL_MODECHG_ADD, ACL_MODECHG_DEL, ACL_NO_RIGHTS, ACLITEM_SET_PRIVS_GOPTIONS, aclupdate(), AclItem::ai_grantee, AclItem::ai_grantor, ereport, errcode(), errmsg(), ERROR, j, lfirst_oid, and pfree().

Referenced by ExecGrant_Attribute(), ExecGrant_common(), ExecGrant_Largeobject(), ExecGrant_Parameter(), ExecGrant_Relation(), RemoveRoleFromInitPriv(), and SetDefaultACL().

◆ object_aclcheck()

AclResult object_aclcheck ( Oid  classid,
Oid  objectid,
Oid  roleid,
AclMode  mode 
)

Definition at line 3804 of file aclchk.c.

3805{
3806 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3807}
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3814
static PgChecksumMode mode
Definition: pg_checksums.c:55

References mode, and object_aclcheck_ext().

Referenced by AggregateCreate(), AlterExtensionNamespace(), AlterForeignServerOwner_internal(), AlterObjectNamespace_internal(), AlterObjectOwner_internal(), AlterObjectRename_internal(), AlterPublicationOwner_internal(), AlterSchemaOwner_internal(), AlterSubscriptionOwner_internal(), AlterTableMoveAll(), AlterTypeOwner(), ATExecChangeOwner(), ATPrepAlterColumnType(), ATPrepSetTableSpace(), BuildDescForRelation(), calculate_database_size(), calculate_tablespace_size(), call_pltcl_start_proc(), check_temp_tablespaces(), CheckFunctionValidatorAccess(), CheckMyDatabase(), compute_return_type(), CreateCast(), CreateConversionCommand(), createdb(), CreateForeignServer(), CreateForeignTable(), CreateFunction(), CreatePublication(), CreateSchemaCommand(), CreateSubscription(), CreateTransform(), CreateTriggerFiringOn(), DefineAggregate(), DefineCollation(), DefineDomain(), DefineEnum(), DefineIndex(), DefineOpClass(), DefineOperator(), DefineOpFamily(), DefineRange(), DefineRelation(), DefineTSConfiguration(), DefineTSDictionary(), DefineType(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecInitAgg(), ExecInitExprRec(), ExecInitFunc(), ExecInitWindowAgg(), ExecReindex(), ExecuteCallStmt(), ExecuteDoStmt(), extension_is_trusted(), findRangeCanonicalFunction(), findRangeSubtypeDiffFunction(), get_connect_string(), get_other_operator(), HandleFunctionRequest(), has_database_privilege_id_name(), has_database_privilege_name(), has_database_privilege_name_name(), has_foreign_data_wrapper_privilege_id_name(), has_foreign_data_wrapper_privilege_name(), has_foreign_data_wrapper_privilege_name_name(), has_function_privilege_id_name(), has_function_privilege_name(), has_function_privilege_name_name(), has_language_privilege_id_name(), has_language_privilege_name(), has_language_privilege_name_name(), has_schema_privilege_id_name(), has_schema_privilege_name(), has_schema_privilege_name_name(), has_server_privilege_id_name(), has_server_privilege_name(), has_server_privilege_name_name(), has_tablespace_privilege_id_name(), has_tablespace_privilege_name(), has_tablespace_privilege_name_name(), has_type_privilege_id_name(), has_type_privilege_name(), has_type_privilege_name_name(), ImportForeignSchema(), init_sexpr(), initialize_peragg(), InitTempTableNamespace(), inline_function(), inline_set_returning_function(), interpret_function_parameter_list(), lookup_agg_function(), LookupCreationNamespace(), LookupExplicitNamespace(), movedb(), PrepareTempTablespaces(), preprocessNamespacePath(), RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), ReindexMultipleInternal(), RenameSchema(), transformTableLikeClause(), user_mapping_ddl_aclcheck(), ValidateJoinEstimator(), and ValidateRestrictionEstimator().

◆ object_aclcheck_ext()

◆ object_aclmask()

static AclMode object_aclmask ( Oid  classid,
Oid  objectid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3014 of file aclchk.c.

3016{
3017 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3018}

References object_aclmask_ext().

Referenced by pg_aclmask().

◆ object_aclmask_ext()

static AclMode object_aclmask_ext ( Oid  classid,
Oid  objectid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
bool *  is_missing 
)
static

Definition at line 3025 of file aclchk.c.

3028{
3029 int cacheid;
3030 AclMode result;
3031 HeapTuple tuple;
3032 Datum aclDatum;
3033 bool isNull;
3034 Acl *acl;
3035 Oid ownerId;
3036
3037 /* Special cases */
3038 switch (classid)
3039 {
3040 case NamespaceRelationId:
3041 return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3042 is_missing);
3043 case TypeRelationId:
3044 return pg_type_aclmask_ext(objectid, roleid, mask, how,
3045 is_missing);
3046 }
3047
3048 /* Even more special cases */
3049 Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3050 Assert(classid != LargeObjectMetadataRelationId); /* should use
3051 * pg_largeobject_acl* */
3052
3053 /* Superusers bypass all permission checking. */
3054 if (superuser_arg(roleid))
3055 return mask;
3056
3057 /*
3058 * Get the object's ACL from its catalog
3059 */
3060
3061 cacheid = get_object_catcache_oid(classid);
3062
3063 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3064 if (!HeapTupleIsValid(tuple))
3065 {
3066 if (is_missing != NULL)
3067 {
3068 /* return "no privileges" instead of throwing an error */
3069 *is_missing = true;
3070 return 0;
3071 }
3072 else
3073 elog(ERROR, "cache lookup failed for %s %u",
3074 get_object_class_descr(classid), objectid);
3075 }
3076
3077 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3078 tuple,
3079 get_object_attnum_owner(classid)));
3080
3081 aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3082 &isNull);
3083 if (isNull)
3084 {
3085 /* No ACL, so build default ACL */
3086 acl = acldefault(get_object_type(classid, objectid), ownerId);
3087 aclDatum = (Datum) 0;
3088 }
3089 else
3090 {
3091 /* detoast ACL if necessary */
3092 acl = DatumGetAclP(aclDatum);
3093 }
3094
3095 result = aclmask(acl, roleid, ownerId, mask, how);
3096
3097 /* if we have a detoasted copy, free it */
3098 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3099 pfree(acl);
3100
3101 ReleaseSysCache(tuple);
3102
3103 return result;
3104}
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1372
#define DatumGetAclP(X)
Definition: acl.h:120
static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3576
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3678
char * Pointer
Definition: c.h:493
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317

References acldefault(), aclmask(), Assert(), DatumGetAclP, DatumGetObjectId(), DatumGetPointer(), elog, ERROR, get_object_attnum_acl(), get_object_attnum_owner(), get_object_catcache_oid(), get_object_class_descr(), get_object_type(), HeapTupleIsValid, ObjectIdGetDatum(), pfree(), pg_namespace_aclmask_ext(), pg_type_aclmask_ext(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), SysCacheGetAttr(), and SysCacheGetAttrNotNull().

Referenced by object_aclcheck_ext(), and object_aclmask().

◆ object_ownercheck()

bool object_ownercheck ( Oid  classid,
Oid  objectid,
Oid  roleid 
)

Definition at line 4058 of file aclchk.c.

4059{
4060 int cacheid;
4061 Oid ownerId;
4062
4063 /* Superusers bypass all permission checking. */
4064 if (superuser_arg(roleid))
4065 return true;
4066
4067 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4068 if (classid == LargeObjectRelationId)
4069 classid = LargeObjectMetadataRelationId;
4070
4071 cacheid = get_object_catcache_oid(classid);
4072 if (cacheid != -1)
4073 {
4074 /* we can get the object's tuple from the syscache */
4075 HeapTuple tuple;
4076
4077 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4078 if (!HeapTupleIsValid(tuple))
4079 elog(ERROR, "cache lookup failed for %s %u",
4080 get_object_class_descr(classid), objectid);
4081
4082 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4083 tuple,
4084 get_object_attnum_owner(classid)));
4085 ReleaseSysCache(tuple);
4086 }
4087 else
4088 {
4089 /* for catalogs without an appropriate syscache */
4090 Relation rel;
4091 ScanKeyData entry[1];
4092 SysScanDesc scan;
4093 HeapTuple tuple;
4094 bool isnull;
4095
4096 rel = table_open(classid, AccessShareLock);
4097
4098 ScanKeyInit(&entry[0],
4099 get_object_attnum_oid(classid),
4100 BTEqualStrategyNumber, F_OIDEQ,
4101 ObjectIdGetDatum(objectid));
4102
4103 scan = systable_beginscan(rel,
4104 get_object_oid_index(classid), true,
4105 NULL, 1, entry);
4106
4107 tuple = systable_getnext(scan);
4108 if (!HeapTupleIsValid(tuple))
4109 elog(ERROR, "could not find tuple for %s %u",
4110 get_object_class_descr(classid), objectid);
4111
4112 ownerId = DatumGetObjectId(heap_getattr(tuple,
4113 get_object_attnum_owner(classid),
4114 RelationGetDescr(rel),
4115 &isnull));
4116 Assert(!isnull);
4117
4118 systable_endscan(scan);
4120 }
4121
4122 return has_privs_of_role(roleid, ownerId);
4123}
AttrNumber get_object_attnum_oid(Oid class_id)
Oid get_object_oid_index(Oid class_id)

References AccessShareLock, Assert(), BTEqualStrategyNumber, DatumGetObjectId(), elog, ERROR, get_object_attnum_oid(), get_object_attnum_owner(), get_object_catcache_oid(), get_object_class_descr(), get_object_oid_index(), has_privs_of_role(), heap_getattr(), HeapTupleIsValid, ObjectIdGetDatum(), RelationGetDescr, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1(), superuser_arg(), SysCacheGetAttrNotNull(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterCollation(), AlterDatabase(), AlterDatabaseOwner(), AlterDatabaseRefreshColl(), AlterDatabaseSet(), AlterEventTrigger(), AlterEventTriggerOwner_internal(), AlterExtensionNamespace(), AlterForeignServer(), AlterForeignServerOwner_internal(), AlterFunction(), AlterOperator(), AlterOpFamilyAdd(), AlterPublication(), AlterPublicationOwner_internal(), AlterRoleSet(), AlterSchemaOwner_internal(), AlterStatistics(), AlterSubscription(), AlterSubscriptionOwner_internal(), AlterTableMoveAll(), AlterTableSpaceOptions(), AlterTSConfiguration(), AlterTSDictionary(), AlterType(), AlterTypeNamespace_oid(), AlterTypeOwner(), ATExecChangeOwner(), ATSimplePermissions(), be_lo_unlink(), brin_desummarize_range(), brin_summarize_range(), check_enable_rls(), check_object_ownership(), checkDomainOwner(), checkEnumOwner(), CreateCast(), createdb(), CreateProceduralLanguage(), CreateStatistics(), CreateTransform(), DefineOpClass(), DefineQueryRewrite(), DefineType(), dropdb(), DropSubscription(), DropTableSpace(), EnableDisableRule(), ExecAlterExtensionContentsStmt(), ExecAlterExtensionStmt(), ExecuteTruncateGuts(), gin_clean_pending_list(), heap_force_common(), MergeAttributes(), movedb(), OperatorCreate(), ProcedureCreate(), PublicationAddTables(), RangeVarCallbackForAlterRelation(), RangeVarCallbackForDropRelation(), RangeVarCallbackForPolicy(), RangeVarCallbackForRenameRule(), RangeVarCallbackForRenameTrigger(), RangeVarCallbackOwnsRelation(), RangeVarGetAndCheckCreationNamespace(), ReindexMultipleTables(), RemoveObjects(), renameatt_check(), RenameDatabase(), RenameSchema(), RenameTableSpace(), RenameType(), RI_Initial_Check(), stats_lock_check_privileges(), user_mapping_ddl_aclcheck(), vacuum_is_permitted_for_relation(), and ValidateOperatorReference().

◆ objectNamesToOids()

static List * objectNamesToOids ( ObjectType  objtype,
List objnames,
bool  is_grant 
)
static

Definition at line 664 of file aclchk.c.

665{
666 List *objects = NIL;
667 ListCell *cell;
668 const LOCKMODE lockmode = AccessShareLock;
669
670 Assert(objnames != NIL);
671
672 switch (objtype)
673 {
674 default:
675
676 /*
677 * For most object types, we use get_object_address() directly.
678 */
679 foreach(cell, objnames)
680 {
681 ObjectAddress address;
682
683 address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
684 objects = lappend_oid(objects, address.objectId);
685 }
686 break;
687
688 case OBJECT_TABLE:
689 case OBJECT_SEQUENCE:
690
691 /*
692 * Here, we don't use get_object_address(). It requires that the
693 * specified object type match the actual type of the object, but
694 * in GRANT/REVOKE, all table-like things are addressed as TABLE.
695 */
696 foreach(cell, objnames)
697 {
698 RangeVar *relvar = (RangeVar *) lfirst(cell);
699 Oid relOid;
700
701 relOid = RangeVarGetRelid(relvar, lockmode, false);
702 objects = lappend_oid(objects, relOid);
703 }
704 break;
705
706 case OBJECT_DOMAIN:
707 case OBJECT_TYPE:
708
709 /*
710 * The parse representation of types and domains in privilege
711 * targets is different from that expected by get_object_address()
712 * (for parse conflict reasons), so we have to do a bit of
713 * conversion here.
714 */
715 foreach(cell, objnames)
716 {
717 List *typname = (List *) lfirst(cell);
719 ObjectAddress address;
720 Relation relation;
721
722 address = get_object_address(objtype, (Node *) tn, &relation, lockmode, false);
723 Assert(relation == NULL);
724 objects = lappend_oid(objects, address.objectId);
725 }
726 break;
727
729
730 /*
731 * Parameters are handled completely differently.
732 */
733 foreach(cell, objnames)
734 {
735 /*
736 * In this code we represent a GUC by the OID of its entry in
737 * pg_parameter_acl, which we have to manufacture here if it
738 * doesn't exist yet. (That's a hack for sure, but it avoids
739 * messing with all the GRANT/REVOKE infrastructure that
740 * expects to use OIDs for object identities.) However, if
741 * this is a REVOKE, we can instead just ignore any GUCs that
742 * don't have such an entry, as they must not have any
743 * privileges needing removal.
744 */
745 char *parameter = strVal(lfirst(cell));
746 Oid parameterId = ParameterAclLookup(parameter, true);
747
748 if (!OidIsValid(parameterId) && is_grant)
749 {
750 parameterId = ParameterAclCreate(parameter);
751
752 /*
753 * Prevent error when processing duplicate objects, and
754 * make this new entry visible so that ExecGrant_Parameter
755 * can update it.
756 */
758 }
759 if (OidIsValid(parameterId))
760 objects = lappend_oid(objects, parameterId);
761 }
762 break;
763 }
764
765 return objects;
766}
#define OidIsValid(objectId)
Definition: c.h:746
int LOCKMODE
Definition: lockdefs.h:26
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:80
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
Oid ParameterAclLookup(const char *parameter, bool missing_ok)
Oid ParameterAclCreate(const char *parameter)
NameData typname
Definition: pg_type.h:41
Definition: nodes.h:131

References AccessShareLock, Assert(), CommandCounterIncrement(), get_object_address(), lappend_oid(), lfirst, makeTypeNameFromNameList(), NIL, OBJECT_DOMAIN, OBJECT_PARAMETER_ACL, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TYPE, ObjectAddress::objectId, OidIsValid, ParameterAclCreate(), ParameterAclLookup(), RangeVarGetRelid, strVal, and typname.

Referenced by ExecuteGrantStmt().

◆ objectsInSchemaToOids()

static List * objectsInSchemaToOids ( ObjectType  objtype,
List nspnames 
)
static

Definition at line 776 of file aclchk.c.

777{
778 List *objects = NIL;
779 ListCell *cell;
780
781 foreach(cell, nspnames)
782 {
783 char *nspname = strVal(lfirst(cell));
784 Oid namespaceId;
785 List *objs;
786
787 namespaceId = LookupExplicitNamespace(nspname, false);
788
789 switch (objtype)
790 {
791 case OBJECT_TABLE:
792 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
793 objects = list_concat(objects, objs);
794 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
795 objects = list_concat(objects, objs);
796 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
797 objects = list_concat(objects, objs);
798 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
799 objects = list_concat(objects, objs);
800 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
801 objects = list_concat(objects, objs);
802 break;
803 case OBJECT_SEQUENCE:
804 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
805 objects = list_concat(objects, objs);
806 break;
807 case OBJECT_FUNCTION:
808 case OBJECT_PROCEDURE:
809 case OBJECT_ROUTINE:
810 {
811 ScanKeyData key[2];
812 int keycount;
813 Relation rel;
814 TableScanDesc scan;
815 HeapTuple tuple;
816
817 keycount = 0;
818 ScanKeyInit(&key[keycount++],
819 Anum_pg_proc_pronamespace,
820 BTEqualStrategyNumber, F_OIDEQ,
821 ObjectIdGetDatum(namespaceId));
822
823 if (objtype == OBJECT_FUNCTION)
824 /* includes aggregates and window functions */
825 ScanKeyInit(&key[keycount++],
826 Anum_pg_proc_prokind,
827 BTEqualStrategyNumber, F_CHARNE,
828 CharGetDatum(PROKIND_PROCEDURE));
829 else if (objtype == OBJECT_PROCEDURE)
830 ScanKeyInit(&key[keycount++],
831 Anum_pg_proc_prokind,
832 BTEqualStrategyNumber, F_CHAREQ,
833 CharGetDatum(PROKIND_PROCEDURE));
834
835 rel = table_open(ProcedureRelationId, AccessShareLock);
836 scan = table_beginscan_catalog(rel, keycount, key);
837
838 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
839 {
840 Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
841
842 objects = lappend_oid(objects, oid);
843 }
844
845 table_endscan(scan);
847 }
848 break;
849 default:
850 /* should not happen */
851 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
852 (int) objtype);
853 }
854 }
855
856 return objects;
857}
static List * getRelationsInNamespace(Oid namespaceId, char relkind)
Definition: aclchk.c:865
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3385
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136

References AccessShareLock, BTEqualStrategyNumber, CharGetDatum(), elog, ERROR, ForwardScanDirection, getRelationsInNamespace(), GETSTRUCT(), heap_getnext(), sort-test::key, lappend_oid(), lfirst, list_concat(), LookupExplicitNamespace(), NIL, OBJECT_FUNCTION, OBJECT_PROCEDURE, OBJECT_ROUTINE, OBJECT_SEQUENCE, OBJECT_TABLE, ObjectIdGetDatum(), ScanKeyInit(), strVal, table_beginscan_catalog(), table_close(), table_endscan(), and table_open().

Referenced by ExecuteGrantStmt().

◆ pg_aclmask()

static AclMode pg_aclmask ( ObjectType  objtype,
Oid  object_oid,
AttrNumber  attnum,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 2953 of file aclchk.c.

2955{
2956 switch (objtype)
2957 {
2958 case OBJECT_COLUMN:
2959 return
2960 pg_class_aclmask(object_oid, roleid, mask, how) |
2961 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2962 case OBJECT_TABLE:
2963 case OBJECT_SEQUENCE:
2964 return pg_class_aclmask(object_oid, roleid, mask, how);
2965 case OBJECT_DATABASE:
2966 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2967 case OBJECT_FUNCTION:
2968 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
2969 case OBJECT_LANGUAGE:
2970 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
2971 case OBJECT_LARGEOBJECT:
2972 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
2973 mask, how, NULL);
2975 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
2976 case OBJECT_SCHEMA:
2977 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
2979 elog(ERROR, "grantable rights not supported for statistics objects");
2980 /* not reached, but keep compiler quiet */
2981 return ACL_NO_RIGHTS;
2982 case OBJECT_TABLESPACE:
2983 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
2984 case OBJECT_FDW:
2985 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
2987 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
2989 elog(ERROR, "grantable rights not supported for event triggers");
2990 /* not reached, but keep compiler quiet */
2991 return ACL_NO_RIGHTS;
2992 case OBJECT_TYPE:
2993 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
2994 default:
2995 elog(ERROR, "unrecognized object type: %d",
2996 (int) objtype);
2997 /* not reached, but keep compiler quiet */
2998 return ACL_NO_RIGHTS;
2999 }
3000}
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3503
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3115
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3444
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3014
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3240

References ACL_NO_RIGHTS, attnum, elog, ERROR, object_aclmask(), OBJECT_COLUMN, OBJECT_DATABASE, OBJECT_EVENT_TRIGGER, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_PARAMETER_ACL, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_STATISTIC_EXT, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TYPE, pg_attribute_aclmask(), pg_class_aclmask(), pg_largeobject_aclmask_snapshot(), and pg_parameter_acl_aclmask().

Referenced by restrict_and_check_grant().

◆ pg_attribute_aclcheck()

AclResult pg_attribute_aclcheck ( Oid  table_oid,
AttrNumber  attnum,
Oid  roleid,
AclMode  mode 
)

Definition at line 3836 of file aclchk.c.

3838{
3839 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3840}
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3848

References attnum, mode, and pg_attribute_aclcheck_ext().

Referenced by BuildIndexValueDescription(), checkFkeyPermissions(), examine_simple_variable(), ExecBuildSlotPartitionKeyDescription(), ExecBuildSlotValueDescription(), ExecCheckOneRelPerms(), ExecCheckPermissionsModified(), ri_ReportViolation(), and statext_is_compatible_clause().

◆ pg_attribute_aclcheck_all()

AclResult pg_attribute_aclcheck_all ( Oid  table_oid,
Oid  roleid,
AclMode  mode,
AclMaskHow  how 
)

Definition at line 3878 of file aclchk.c.

3880{
3881 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3882}
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3889

References mode, and pg_attribute_aclcheck_all_ext().

Referenced by ExecCheckOneRelPerms(), ExecCheckPermissionsModified(), has_any_column_privilege_id_name(), has_any_column_privilege_name(), has_any_column_privilege_name_name(), and statext_is_compatible_clause().

◆ pg_attribute_aclcheck_all_ext()

AclResult pg_attribute_aclcheck_all_ext ( Oid  table_oid,
Oid  roleid,
AclMode  mode,
AclMaskHow  how,
bool *  is_missing 
)

Definition at line 3889 of file aclchk.c.

3892{
3893 AclResult result;
3894 HeapTuple classTuple;
3895 Form_pg_class classForm;
3896 Oid ownerId;
3897 AttrNumber nattrs;
3898 AttrNumber curr_att;
3899
3900 /*
3901 * Must fetch pg_class row to get owner ID and number of attributes.
3902 */
3903 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3904 if (!HeapTupleIsValid(classTuple))
3905 {
3906 if (is_missing != NULL)
3907 {
3908 /* return "no privileges" instead of throwing an error */
3909 *is_missing = true;
3910 return ACLCHECK_NO_PRIV;
3911 }
3912 else
3913 ereport(ERROR,
3915 errmsg("relation with OID %u does not exist",
3916 table_oid)));
3917 }
3918 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3919
3920 ownerId = classForm->relowner;
3921 nattrs = classForm->relnatts;
3922
3923 ReleaseSysCache(classTuple);
3924
3925 /*
3926 * Initialize result in case there are no non-dropped columns. We want to
3927 * report failure in such cases for either value of 'how'.
3928 */
3929 result = ACLCHECK_NO_PRIV;
3930
3931 for (curr_att = 1; curr_att <= nattrs; curr_att++)
3932 {
3933 HeapTuple attTuple;
3934 Datum aclDatum;
3935 bool isNull;
3936 Acl *acl;
3937 AclMode attmask;
3938
3939 attTuple = SearchSysCache2(ATTNUM,
3940 ObjectIdGetDatum(table_oid),
3941 Int16GetDatum(curr_att));
3942
3943 /*
3944 * Lookup failure probably indicates that the table was just dropped,
3945 * but we'll treat it the same as a dropped column rather than
3946 * throwing error.
3947 */
3948 if (!HeapTupleIsValid(attTuple))
3949 continue;
3950
3951 /* ignore dropped columns */
3952 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3953 {
3954 ReleaseSysCache(attTuple);
3955 continue;
3956 }
3957
3958 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3959 &isNull);
3960
3961 /*
3962 * Here we hard-wire knowledge that the default ACL for a column
3963 * grants no privileges, so that we can fall out quickly in the very
3964 * common case where attacl is null.
3965 */
3966 if (isNull)
3967 attmask = 0;
3968 else
3969 {
3970 /* detoast column's ACL if necessary */
3971 acl = DatumGetAclP(aclDatum);
3972
3973 attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
3974
3975 /* if we have a detoasted copy, free it */
3976 if ((Pointer) acl != DatumGetPointer(aclDatum))
3977 pfree(acl);
3978 }
3979
3980 ReleaseSysCache(attTuple);
3981
3982 if (attmask != 0)
3983 {
3984 result = ACLCHECK_OK;
3985 if (how == ACLMASK_ANY)
3986 break; /* succeed on any success */
3987 }
3988 else
3989 {
3990 result = ACLCHECK_NO_PRIV;
3991 if (how == ACLMASK_ALL)
3992 break; /* fail on any failure */
3993 }
3994 }
3995
3996 return result;
3997}
AclResult
Definition: acl.h:182
@ ACLMASK_ALL
Definition: acl.h:176
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79

References ACLCHECK_NO_PRIV, ACLCHECK_OK, aclmask(), ACLMASK_ALL, ACLMASK_ANY, DatumGetAclP, DatumGetPointer(), ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, GETSTRUCT(), HeapTupleIsValid, Int16GetDatum(), mode, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), SearchSysCache2(), and SysCacheGetAttr().

Referenced by has_any_column_privilege_id(), has_any_column_privilege_id_id(), has_any_column_privilege_name_id(), and pg_attribute_aclcheck_all().

◆ pg_attribute_aclcheck_ext()

AclResult pg_attribute_aclcheck_ext ( Oid  table_oid,
AttrNumber  attnum,
Oid  roleid,
AclMode  mode,
bool *  is_missing 
)

Definition at line 3848 of file aclchk.c.

3850{
3851 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3852 ACLMASK_ANY, is_missing) != 0)
3853 return ACLCHECK_OK;
3854 else
3855 return ACLCHECK_NO_PRIV;
3856}
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3126

References ACLCHECK_NO_PRIV, ACLCHECK_OK, ACLMASK_ANY, attnum, mode, and pg_attribute_aclmask_ext().

Referenced by column_privilege_check(), and pg_attribute_aclcheck().

◆ pg_attribute_aclmask()

static AclMode pg_attribute_aclmask ( Oid  table_oid,
AttrNumber  attnum,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3115 of file aclchk.c.

3117{
3118 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3119 mask, how, NULL);
3120}

References attnum, and pg_attribute_aclmask_ext().

Referenced by pg_aclmask().

◆ pg_attribute_aclmask_ext()

static AclMode pg_attribute_aclmask_ext ( Oid  table_oid,
AttrNumber  attnum,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
bool *  is_missing 
)
static

Definition at line 3126 of file aclchk.c.

3128{
3129 AclMode result;
3130 HeapTuple classTuple;
3131 HeapTuple attTuple;
3132 Form_pg_class classForm;
3133 Form_pg_attribute attributeForm;
3134 Datum aclDatum;
3135 bool isNull;
3136 Acl *acl;
3137 Oid ownerId;
3138
3139 /*
3140 * First, get the column's ACL from its pg_attribute entry
3141 */
3142 attTuple = SearchSysCache2(ATTNUM,
3143 ObjectIdGetDatum(table_oid),
3145 if (!HeapTupleIsValid(attTuple))
3146 {
3147 if (is_missing != NULL)
3148 {
3149 /* return "no privileges" instead of throwing an error */
3150 *is_missing = true;
3151 return 0;
3152 }
3153 else
3154 ereport(ERROR,
3155 (errcode(ERRCODE_UNDEFINED_COLUMN),
3156 errmsg("attribute %d of relation with OID %u does not exist",
3157 attnum, table_oid)));
3158 }
3159
3160 attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
3161
3162 /* Check dropped columns, too */
3163 if (attributeForm->attisdropped)
3164 {
3165 if (is_missing != NULL)
3166 {
3167 /* return "no privileges" instead of throwing an error */
3168 *is_missing = true;
3169 ReleaseSysCache(attTuple);
3170 return 0;
3171 }
3172 else
3173 ereport(ERROR,
3174 (errcode(ERRCODE_UNDEFINED_COLUMN),
3175 errmsg("attribute %d of relation with OID %u does not exist",
3176 attnum, table_oid)));
3177 }
3178
3179 aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
3180 &isNull);
3181
3182 /*
3183 * Here we hard-wire knowledge that the default ACL for a column grants no
3184 * privileges, so that we can fall out quickly in the very common case
3185 * where attacl is null.
3186 */
3187 if (isNull)
3188 {
3189 ReleaseSysCache(attTuple);
3190 return 0;
3191 }
3192
3193 /*
3194 * Must get the relation's ownerId from pg_class. Since we already found
3195 * a pg_attribute entry, the only likely reason for this to fail is that a
3196 * concurrent DROP of the relation committed since then (which could only
3197 * happen if we don't have lock on the relation). Treat that similarly to
3198 * not finding the attribute entry.
3199 */
3200 classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3201 if (!HeapTupleIsValid(classTuple))
3202 {
3203 ReleaseSysCache(attTuple);
3204 if (is_missing != NULL)
3205 {
3206 /* return "no privileges" instead of throwing an error */
3207 *is_missing = true;
3208 return 0;
3209 }
3210 else
3211 ereport(ERROR,
3213 errmsg("relation with OID %u does not exist",
3214 table_oid)));
3215 }
3216 classForm = (Form_pg_class) GETSTRUCT(classTuple);
3217
3218 ownerId = classForm->relowner;
3219
3220 ReleaseSysCache(classTuple);
3221
3222 /* detoast column's ACL if necessary */
3223 acl = DatumGetAclP(aclDatum);
3224
3225 result = aclmask(acl, roleid, ownerId, mask, how);
3226
3227 /* if we have a detoasted copy, free it */
3228 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3229 pfree(acl);
3230
3231 ReleaseSysCache(attTuple);
3232
3233 return result;
3234}

References aclmask(), attnum, DatumGetAclP, DatumGetPointer(), ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, GETSTRUCT(), HeapTupleIsValid, Int16GetDatum(), ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), SearchSysCache2(), and SysCacheGetAttr().

Referenced by pg_attribute_aclcheck_ext(), and pg_attribute_aclmask().

◆ pg_class_aclcheck()

◆ pg_class_aclcheck_ext()

AclResult pg_class_aclcheck_ext ( Oid  table_oid,
Oid  roleid,
AclMode  mode,
bool *  is_missing 
)

Definition at line 4017 of file aclchk.c.

4019{
4020 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4021 ACLMASK_ANY, is_missing) != 0)
4022 return ACLCHECK_OK;
4023 else
4024 return ACLCHECK_NO_PRIV;
4025}
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3250

References ACLCHECK_NO_PRIV, ACLCHECK_OK, ACLMASK_ANY, mode, and pg_class_aclmask_ext().

Referenced by column_privilege_check(), has_any_column_privilege_id(), has_any_column_privilege_id_id(), has_any_column_privilege_name_id(), has_sequence_privilege_id(), has_sequence_privilege_id_id(), has_sequence_privilege_name_id(), has_table_privilege_id(), has_table_privilege_id_id(), has_table_privilege_name_id(), and pg_class_aclcheck().

◆ pg_class_aclmask()

AclMode pg_class_aclmask ( Oid  table_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)

Definition at line 3240 of file aclchk.c.

3242{
3243 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3244}

References pg_class_aclmask_ext().

Referenced by ExecCheckOneRelPerms(), and pg_aclmask().

◆ pg_class_aclmask_ext()

static AclMode pg_class_aclmask_ext ( Oid  table_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
bool *  is_missing 
)
static

Definition at line 3250 of file aclchk.c.

3252{
3253 AclMode result;
3254 HeapTuple tuple;
3255 Form_pg_class classForm;
3256 Datum aclDatum;
3257 bool isNull;
3258 Acl *acl;
3259 Oid ownerId;
3260
3261 /*
3262 * Must get the relation's tuple from pg_class
3263 */
3264 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3265 if (!HeapTupleIsValid(tuple))
3266 {
3267 if (is_missing != NULL)
3268 {
3269 /* return "no privileges" instead of throwing an error */
3270 *is_missing = true;
3271 return 0;
3272 }
3273 else
3274 ereport(ERROR,
3276 errmsg("relation with OID %u does not exist",
3277 table_oid)));
3278 }
3279
3280 classForm = (Form_pg_class) GETSTRUCT(tuple);
3281
3282 /*
3283 * Deny anyone permission to update a system catalog unless
3284 * pg_authid.rolsuper is set.
3285 *
3286 * As of 7.4 we have some updatable system views; those shouldn't be
3287 * protected in this way. Assume the view rules can take care of
3288 * themselves. ACL_USAGE is if we ever have system sequences.
3289 */
3290 if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
3291 IsSystemClass(table_oid, classForm) &&
3292 classForm->relkind != RELKIND_VIEW &&
3293 !superuser_arg(roleid))
3295
3296 /*
3297 * Otherwise, superusers bypass all permission-checking.
3298 */
3299 if (superuser_arg(roleid))
3300 {
3301 ReleaseSysCache(tuple);
3302 return mask;
3303 }
3304
3305 /*
3306 * Normal case: get the relation's ACL from pg_class
3307 */
3308 ownerId = classForm->relowner;
3309
3310 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
3311 &isNull);
3312 if (isNull)
3313 {
3314 /* No ACL, so build default ACL */
3315 switch (classForm->relkind)
3316 {
3317 case RELKIND_SEQUENCE:
3318 acl = acldefault(OBJECT_SEQUENCE, ownerId);
3319 break;
3320 default:
3321 acl = acldefault(OBJECT_TABLE, ownerId);
3322 break;
3323 }
3324 aclDatum = (Datum) 0;
3325 }
3326 else
3327 {
3328 /* detoast rel's ACL if necessary */
3329 acl = DatumGetAclP(aclDatum);
3330 }
3331
3332 result = aclmask(acl, roleid, ownerId, mask, how);
3333
3334 /* if we have a detoasted copy, free it */
3335 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3336 pfree(acl);
3337
3338 ReleaseSysCache(tuple);
3339
3340 /*
3341 * Check if ACL_SELECT is being checked and, if so, and not set already as
3342 * part of the result, then check if the user is a member of the
3343 * pg_read_all_data role, which allows read access to all relations.
3344 */
3345 if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
3346 has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
3347 result |= ACL_SELECT;
3348
3349 /*
3350 * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
3351 * so, and not set already as part of the result, then check if the user
3352 * is a member of the pg_write_all_data role, which allows
3353 * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
3354 * which requires superuser, see above).
3355 */
3356 if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
3357 !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
3358 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
3359 result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
3360
3361 /*
3362 * Check if ACL_MAINTAIN is being checked and, if so, and not already set
3363 * as part of the result, then check if the user is a member of the
3364 * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3365 * MATERIALIZED VIEW, REINDEX, and LOCK TABLE on all relations.
3366 */
3367 if (mask & ACL_MAINTAIN &&
3368 !(result & ACL_MAINTAIN) &&
3369 has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3370 result |= ACL_MAINTAIN;
3371
3372 return result;
3373}
bool IsSystemClass(Oid relid, Form_pg_class reltuple)
Definition: catalog.c:85
#define ACL_DELETE
Definition: parsenodes.h:79
#define ACL_MAINTAIN
Definition: parsenodes.h:90
#define ACL_USAGE
Definition: parsenodes.h:84
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_UPDATE
Definition: parsenodes.h:78
#define ACL_TRUNCATE
Definition: parsenodes.h:80

References ACL_DELETE, ACL_INSERT, ACL_MAINTAIN, ACL_SELECT, ACL_TRUNCATE, ACL_UPDATE, ACL_USAGE, acldefault(), aclmask(), DatumGetAclP, DatumGetPointer(), ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, GETSTRUCT(), has_privs_of_role(), HeapTupleIsValid, IsSystemClass(), OBJECT_SEQUENCE, OBJECT_TABLE, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by pg_class_aclcheck_ext(), and pg_class_aclmask().

◆ pg_largeobject_aclcheck_snapshot()

AclResult pg_largeobject_aclcheck_snapshot ( Oid  lobj_oid,
Oid  roleid,
AclMode  mode,
Snapshot  snapshot 
)

Definition at line 4044 of file aclchk.c.

4046{
4047 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4048 ACLMASK_ANY, snapshot) != 0)
4049 return ACLCHECK_OK;
4050 else
4051 return ACLCHECK_NO_PRIV;
4052}

References ACLCHECK_NO_PRIV, ACLCHECK_OK, ACLMASK_ANY, mode, and pg_largeobject_aclmask_snapshot().

Referenced by has_lo_priv_byid(), and inv_open().

◆ pg_largeobject_aclmask_snapshot()

static AclMode pg_largeobject_aclmask_snapshot ( Oid  lobj_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
Snapshot  snapshot 
)
static

Definition at line 3503 of file aclchk.c.

3506{
3507 AclMode result;
3508 Relation pg_lo_meta;
3509 ScanKeyData entry[1];
3510 SysScanDesc scan;
3511 HeapTuple tuple;
3512 Datum aclDatum;
3513 bool isNull;
3514 Acl *acl;
3515 Oid ownerId;
3516
3517 /* Superusers bypass all permission checking. */
3518 if (superuser_arg(roleid))
3519 return mask;
3520
3521 /*
3522 * Get the largeobject's ACL from pg_largeobject_metadata
3523 */
3524 pg_lo_meta = table_open(LargeObjectMetadataRelationId,
3526
3527 ScanKeyInit(&entry[0],
3528 Anum_pg_largeobject_metadata_oid,
3529 BTEqualStrategyNumber, F_OIDEQ,
3530 ObjectIdGetDatum(lobj_oid));
3531
3532 scan = systable_beginscan(pg_lo_meta,
3533 LargeObjectMetadataOidIndexId, true,
3534 snapshot, 1, entry);
3535
3536 tuple = systable_getnext(scan);
3537 if (!HeapTupleIsValid(tuple))
3538 ereport(ERROR,
3539 (errcode(ERRCODE_UNDEFINED_OBJECT),
3540 errmsg("large object %u does not exist", lobj_oid)));
3541
3542 ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
3543
3544 aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
3545 RelationGetDescr(pg_lo_meta), &isNull);
3546
3547 if (isNull)
3548 {
3549 /* No ACL, so build default ACL */
3550 acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
3551 aclDatum = (Datum) 0;
3552 }
3553 else
3554 {
3555 /* detoast ACL if necessary */
3556 acl = DatumGetAclP(aclDatum);
3557 }
3558
3559 result = aclmask(acl, roleid, ownerId, mask, how);
3560
3561 /* if we have a detoasted copy, free it */
3562 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3563 pfree(acl);
3564
3565 systable_endscan(scan);
3566
3567 table_close(pg_lo_meta, AccessShareLock);
3568
3569 return result;
3570}

References AccessShareLock, acldefault(), aclmask(), BTEqualStrategyNumber, DatumGetAclP, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), heap_getattr(), HeapTupleIsValid, OBJECT_LARGEOBJECT, ObjectIdGetDatum(), pfree(), RelationGetDescr, ScanKeyInit(), superuser_arg(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by pg_aclmask(), and pg_largeobject_aclcheck_snapshot().

◆ pg_namespace_aclmask_ext()

static AclMode pg_namespace_aclmask_ext ( Oid  nsp_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
bool *  is_missing 
)
static

Definition at line 3576 of file aclchk.c.

3579{
3580 AclMode result;
3581 HeapTuple tuple;
3582 Datum aclDatum;
3583 bool isNull;
3584 Acl *acl;
3585 Oid ownerId;
3586
3587 /* Superusers bypass all permission checking. */
3588 if (superuser_arg(roleid))
3589 return mask;
3590
3591 /*
3592 * If we have been assigned this namespace as a temp namespace, check to
3593 * make sure we have CREATE TEMP permission on the database, and if so act
3594 * as though we have all standard (but not GRANT OPTION) permissions on
3595 * the namespace. If we don't have CREATE TEMP, act as though we have
3596 * only USAGE (and not CREATE) rights.
3597 *
3598 * This may seem redundant given the check in InitTempTableNamespace, but
3599 * it really isn't since current user ID may have changed since then. The
3600 * upshot of this behavior is that a SECURITY DEFINER function can create
3601 * temp tables that can then be accessed (if permission is granted) by
3602 * code in the same session that doesn't have permissions to create temp
3603 * tables.
3604 *
3605 * XXX Would it be safe to ereport a special error message as
3606 * InitTempTableNamespace does? Returning zero here means we'll get a
3607 * generic "permission denied for schema pg_temp_N" message, which is not
3608 * remarkably user-friendly.
3609 */
3610 if (isTempNamespace(nsp_oid))
3611 {
3612 if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
3613 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
3614 return mask & ACL_ALL_RIGHTS_SCHEMA;
3615 else
3616 return mask & ACL_USAGE;
3617 }
3618
3619 /*
3620 * Get the schema's ACL from pg_namespace
3621 */
3622 tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
3623 if (!HeapTupleIsValid(tuple))
3624 {
3625 if (is_missing != NULL)
3626 {
3627 /* return "no privileges" instead of throwing an error */
3628 *is_missing = true;
3629 return 0;
3630 }
3631 else
3632 ereport(ERROR,
3633 (errcode(ERRCODE_UNDEFINED_SCHEMA),
3634 errmsg("schema with OID %u does not exist", nsp_oid)));
3635 }
3636
3637 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
3638
3639 aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
3640 &isNull);
3641 if (isNull)
3642 {
3643 /* No ACL, so build default ACL */
3644 acl = acldefault(OBJECT_SCHEMA, ownerId);
3645 aclDatum = (Datum) 0;
3646 }
3647 else
3648 {
3649 /* detoast ACL if necessary */
3650 acl = DatumGetAclP(aclDatum);
3651 }
3652
3653 result = aclmask(acl, roleid, ownerId, mask, how);
3654
3655 /* if we have a detoasted copy, free it */
3656 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3657 pfree(acl);
3658
3659 ReleaseSysCache(tuple);
3660
3661 /*
3662 * Check if ACL_USAGE is being checked and, if so, and not set already as
3663 * part of the result, then check if the user is a member of the
3664 * pg_read_all_data or pg_write_all_data roles, which allow usage access
3665 * to all schemas.
3666 */
3667 if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
3668 (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
3669 has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
3670 result |= ACL_USAGE;
3671 return result;
3672}
Oid MyDatabaseId
Definition: globals.c:93
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3649
#define ACL_CREATE_TEMP
Definition: parsenodes.h:86
FormData_pg_namespace * Form_pg_namespace
Definition: pg_namespace.h:52

References ACL_ALL_RIGHTS_SCHEMA, ACL_CREATE_TEMP, ACL_USAGE, ACLCHECK_OK, acldefault(), aclmask(), DatumGetAclP, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), has_privs_of_role(), HeapTupleIsValid, isTempNamespace(), MyDatabaseId, object_aclcheck_ext(), OBJECT_SCHEMA, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by object_aclmask_ext().

◆ pg_parameter_acl_aclmask()

static AclMode pg_parameter_acl_aclmask ( Oid  acl_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3444 of file aclchk.c.

3445{
3446 AclMode result;
3447 HeapTuple tuple;
3448 Datum aclDatum;
3449 bool isNull;
3450 Acl *acl;
3451
3452 /* Superusers bypass all permission checking. */
3453 if (superuser_arg(roleid))
3454 return mask;
3455
3456 /* Get the ACL from pg_parameter_acl */
3457 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3458 if (!HeapTupleIsValid(tuple))
3459 ereport(ERROR,
3460 (errcode(ERRCODE_UNDEFINED_OBJECT),
3461 errmsg("parameter ACL with OID %u does not exist",
3462 acl_oid)));
3463
3464 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3465 Anum_pg_parameter_acl_paracl,
3466 &isNull);
3467 if (isNull)
3468 {
3469 /* No ACL, so build default ACL */
3470 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3471 aclDatum = (Datum) 0;
3472 }
3473 else
3474 {
3475 /* detoast ACL if necessary */
3476 acl = DatumGetAclP(aclDatum);
3477 }
3478
3479 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3480
3481 /* if we have a detoasted copy, free it */
3482 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3483 pfree(acl);
3484
3485 ReleaseSysCache(tuple);
3486
3487 return result;
3488}

References acldefault(), aclmask(), DatumGetAclP, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, HeapTupleIsValid, OBJECT_PARAMETER_ACL, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by pg_aclmask().

◆ pg_parameter_aclcheck()

AclResult pg_parameter_aclcheck ( const char *  name,
Oid  roleid,
AclMode  mode 
)

Definition at line 4032 of file aclchk.c.

4033{
4034 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4035 return ACLCHECK_OK;
4036 else
4037 return ACLCHECK_NO_PRIV;
4038}
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3380
const char * name

References ACLCHECK_NO_PRIV, ACLCHECK_OK, ACLMASK_ANY, mode, name, and pg_parameter_aclmask().

Referenced by AlterSystemSetConfigFile(), has_param_priv_byname(), set_config_with_handle(), and validate_option_array_item().

◆ pg_parameter_aclmask()

static AclMode pg_parameter_aclmask ( const char *  name,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3380 of file aclchk.c.

3381{
3382 AclMode result;
3383 char *parname;
3384 text *partext;
3385 HeapTuple tuple;
3386
3387 /* Superusers bypass all permission checking. */
3388 if (superuser_arg(roleid))
3389 return mask;
3390
3391 /* Convert name to the form it should have in pg_parameter_acl... */
3393 partext = cstring_to_text(parname);
3394
3395 /* ... and look it up */
3396 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3397
3398 if (!HeapTupleIsValid(tuple))
3399 {
3400 /* If no entry, GUC has no permissions for non-superusers */
3401 result = ACL_NO_RIGHTS;
3402 }
3403 else
3404 {
3405 Datum aclDatum;
3406 bool isNull;
3407 Acl *acl;
3408
3409 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3410 Anum_pg_parameter_acl_paracl,
3411 &isNull);
3412 if (isNull)
3413 {
3414 /* No ACL, so build default ACL */
3415 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3416 aclDatum = (Datum) 0;
3417 }
3418 else
3419 {
3420 /* detoast ACL if necessary */
3421 acl = DatumGetAclP(aclDatum);
3422 }
3423
3424 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3425
3426 /* if we have a detoasted copy, free it */
3427 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3428 pfree(acl);
3429
3430 ReleaseSysCache(tuple);
3431 }
3432
3433 pfree(parname);
3434 pfree(partext);
3435
3436 return result;
3437}
char * convert_GUC_name_for_parameter_acl(const char *name)
Definition: guc.c:1374
Definition: c.h:658
text * cstring_to_text(const char *s)
Definition: varlena.c:192

References ACL_NO_RIGHTS, acldefault(), aclmask(), convert_GUC_name_for_parameter_acl(), cstring_to_text(), DatumGetAclP, DatumGetPointer(), HeapTupleIsValid, name, OBJECT_PARAMETER_ACL, pfree(), PointerGetDatum(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by pg_parameter_aclcheck().

◆ pg_type_aclmask_ext()

static AclMode pg_type_aclmask_ext ( Oid  type_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how,
bool *  is_missing 
)
static

Definition at line 3678 of file aclchk.c.

3680{
3681 AclMode result;
3682 HeapTuple tuple;
3683 Form_pg_type typeForm;
3684 Datum aclDatum;
3685 bool isNull;
3686 Acl *acl;
3687 Oid ownerId;
3688
3689 /* Bypass permission checks for superusers */
3690 if (superuser_arg(roleid))
3691 return mask;
3692
3693 /*
3694 * Must get the type's tuple from pg_type
3695 */
3696 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3697 if (!HeapTupleIsValid(tuple))
3698 {
3699 if (is_missing != NULL)
3700 {
3701 /* return "no privileges" instead of throwing an error */
3702 *is_missing = true;
3703 return 0;
3704 }
3705 else
3706 ereport(ERROR,
3707 (errcode(ERRCODE_UNDEFINED_OBJECT),
3708 errmsg("type with OID %u does not exist",
3709 type_oid)));
3710 }
3711 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3712
3713 /*
3714 * "True" array types don't manage permissions of their own; consult the
3715 * element type instead.
3716 */
3717 if (IsTrueArrayType(typeForm))
3718 {
3719 Oid elttype_oid = typeForm->typelem;
3720
3721 ReleaseSysCache(tuple);
3722
3723 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3724 if (!HeapTupleIsValid(tuple))
3725 {
3726 if (is_missing != NULL)
3727 {
3728 /* return "no privileges" instead of throwing an error */
3729 *is_missing = true;
3730 return 0;
3731 }
3732 else
3733 ereport(ERROR,
3734 (errcode(ERRCODE_UNDEFINED_OBJECT),
3735 errmsg("type with OID %u does not exist",
3736 elttype_oid)));
3737 }
3738 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3739 }
3740
3741 /*
3742 * Likewise, multirange types don't manage their own permissions; consult
3743 * the associated range type. (Note we must do this after the array step
3744 * to get the right answer for arrays of multiranges.)
3745 */
3746 if (typeForm->typtype == TYPTYPE_MULTIRANGE)
3747 {
3748 Oid rangetype = get_multirange_range(typeForm->oid);
3749
3750 ReleaseSysCache(tuple);
3751
3752 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
3753 if (!HeapTupleIsValid(tuple))
3754 {
3755 if (is_missing != NULL)
3756 {
3757 /* return "no privileges" instead of throwing an error */
3758 *is_missing = true;
3759 return 0;
3760 }
3761 else
3762 ereport(ERROR,
3763 (errcode(ERRCODE_UNDEFINED_OBJECT),
3764 errmsg("type with OID %u does not exist",
3765 rangetype)));
3766 }
3767 typeForm = (Form_pg_type) GETSTRUCT(tuple);
3768 }
3769
3770 /*
3771 * Now get the type's owner and ACL from the tuple
3772 */
3773 ownerId = typeForm->typowner;
3774
3775 aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3776 Anum_pg_type_typacl, &isNull);
3777 if (isNull)
3778 {
3779 /* No ACL, so build default ACL */
3780 acl = acldefault(OBJECT_TYPE, ownerId);
3781 aclDatum = (Datum) 0;
3782 }
3783 else
3784 {
3785 /* detoast rel's ACL if necessary */
3786 acl = DatumGetAclP(aclDatum);
3787 }
3788
3789 result = aclmask(acl, roleid, ownerId, mask, how);
3790
3791 /* if we have a detoasted copy, free it */
3792 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3793 pfree(acl);
3794
3795 ReleaseSysCache(tuple);
3796
3797 return result;
3798}
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3566

References acldefault(), aclmask(), DatumGetAclP, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, get_multirange_range(), GETSTRUCT(), HeapTupleIsValid, OBJECT_TYPE, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by object_aclmask_ext().

◆ privilege_to_string()

static const char * privilege_to_string ( AclMode  privilege)
static

Definition at line 2575 of file aclchk.c.

2576{
2577 switch (privilege)
2578 {
2579 case ACL_INSERT:
2580 return "INSERT";
2581 case ACL_SELECT:
2582 return "SELECT";
2583 case ACL_UPDATE:
2584 return "UPDATE";
2585 case ACL_DELETE:
2586 return "DELETE";
2587 case ACL_TRUNCATE:
2588 return "TRUNCATE";
2589 case ACL_REFERENCES:
2590 return "REFERENCES";
2591 case ACL_TRIGGER:
2592 return "TRIGGER";
2593 case ACL_EXECUTE:
2594 return "EXECUTE";
2595 case ACL_USAGE:
2596 return "USAGE";
2597 case ACL_CREATE:
2598 return "CREATE";
2599 case ACL_CREATE_TEMP:
2600 return "TEMP";
2601 case ACL_CONNECT:
2602 return "CONNECT";
2603 case ACL_SET:
2604 return "SET";
2605 case ACL_ALTER_SYSTEM:
2606 return "ALTER SYSTEM";
2607 case ACL_MAINTAIN:
2608 return "MAINTAIN";
2609 default:
2610 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2611 }
2612 return NULL; /* appease compiler */
2613}
#define ACL_SET
Definition: parsenodes.h:88
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:89
#define ACL_REFERENCES
Definition: parsenodes.h:81
#define ACL_EXECUTE
Definition: parsenodes.h:83
#define ACL_CREATE
Definition: parsenodes.h:85
#define ACL_TRIGGER
Definition: parsenodes.h:82

References ACL_ALTER_SYSTEM, ACL_CONNECT, ACL_CREATE, ACL_CREATE_TEMP, ACL_DELETE, ACL_EXECUTE, ACL_INSERT, ACL_MAINTAIN, ACL_REFERENCES, ACL_SELECT, ACL_SET, ACL_TRIGGER, ACL_TRUNCATE, ACL_UPDATE, ACL_USAGE, elog, and ERROR.

Referenced by ExecAlterDefaultPrivilegesStmt(), ExecGrant_Relation(), and ExecuteGrantStmt().

◆ recordDependencyOnNewAcl()

void recordDependencyOnNewAcl ( Oid  classId,
Oid  objectId,
int32  objsubId,
Oid  ownerId,
Acl acl 
)

Definition at line 4291 of file aclchk.c.

4293{
4294 int nmembers;
4295 Oid *members;
4296
4297 /* Nothing to do if ACL is defaulted */
4298 if (acl == NULL)
4299 return;
4300
4301 /* Extract roles mentioned in ACL */
4302 nmembers = aclmembers(acl, &members);
4303
4304 /* Update the shared dependency ACL info */
4305 updateAclDependencies(classId, objectId, objsubId,
4306 ownerId,
4307 0, NULL,
4308 nmembers, members);
4309}

References aclmembers(), and updateAclDependencies().

Referenced by GenerateTypeDependencies(), heap_create_with_catalog(), NamespaceCreate(), and ProcedureCreate().

◆ recordExtensionInitPriv()

static void recordExtensionInitPriv ( Oid  objoid,
Oid  classoid,
int  objsubid,
Acl new_acl 
)
static

Definition at line 4565 of file aclchk.c.

4566{
4567 /*
4568 * Generally, we only record the initial privileges when an extension is
4569 * being created, but because we don't actually use CREATE EXTENSION
4570 * during binary upgrades with pg_upgrade, there is a variable to let us
4571 * know that the GRANT and REVOKE statements being issued, while this
4572 * variable is true, are for the initial privileges of the extension
4573 * object and therefore we need to record them.
4574 */
4576 return;
4577
4578 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4579}
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4594
bool binary_upgrade_record_init_privs
Definition: aclchk.c:110
bool creating_extension
Definition: extension.c:77

References binary_upgrade_record_init_privs, creating_extension, and recordExtensionInitPrivWorker().

Referenced by ExecGrant_Attribute(), ExecGrant_common(), ExecGrant_Largeobject(), ExecGrant_Parameter(), and ExecGrant_Relation().

◆ recordExtensionInitPrivWorker()

static void recordExtensionInitPrivWorker ( Oid  objoid,
Oid  classoid,
int  objsubid,
Acl new_acl 
)
static

Definition at line 4594 of file aclchk.c.

4596{
4597 Relation relation;
4598 ScanKeyData key[3];
4599 SysScanDesc scan;
4600 HeapTuple tuple;
4601 HeapTuple oldtuple;
4602 int noldmembers;
4603 int nnewmembers;
4604 Oid *oldmembers;
4605 Oid *newmembers;
4606
4607 /* We'll need the role membership of the new ACL. */
4608 nnewmembers = aclmembers(new_acl, &newmembers);
4609
4610 /* Search pg_init_privs for an existing entry. */
4611 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4612
4613 ScanKeyInit(&key[0],
4614 Anum_pg_init_privs_objoid,
4615 BTEqualStrategyNumber, F_OIDEQ,
4616 ObjectIdGetDatum(objoid));
4617 ScanKeyInit(&key[1],
4618 Anum_pg_init_privs_classoid,
4619 BTEqualStrategyNumber, F_OIDEQ,
4620 ObjectIdGetDatum(classoid));
4621 ScanKeyInit(&key[2],
4622 Anum_pg_init_privs_objsubid,
4623 BTEqualStrategyNumber, F_INT4EQ,
4624 Int32GetDatum(objsubid));
4625
4626 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4627 NULL, 3, key);
4628
4629 /* There should exist only one entry or none. */
4630 oldtuple = systable_getnext(scan);
4631
4632 /* If we find an entry, update it with the latest ACL. */
4633 if (HeapTupleIsValid(oldtuple))
4634 {
4635 Datum values[Natts_pg_init_privs] = {0};
4636 bool nulls[Natts_pg_init_privs] = {0};
4637 bool replace[Natts_pg_init_privs] = {0};
4638 Datum oldAclDatum;
4639 bool isNull;
4640 Acl *old_acl;
4641
4642 /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4643 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4644 RelationGetDescr(relation), &isNull);
4645 Assert(!isNull);
4646 old_acl = DatumGetAclP(oldAclDatum);
4647 noldmembers = aclmembers(old_acl, &oldmembers);
4648
4649 updateInitAclDependencies(classoid, objoid, objsubid,
4650 noldmembers, oldmembers,
4651 nnewmembers, newmembers);
4652
4653 /* If we have a new ACL to set, then update the row with it. */
4654 if (new_acl && ACL_NUM(new_acl) != 0)
4655 {
4656 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4657 replace[Anum_pg_init_privs_initprivs - 1] = true;
4658
4659 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4660 values, nulls, replace);
4661
4662 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4663 }
4664 else
4665 {
4666 /* new_acl is NULL/empty, so delete the entry we found. */
4667 CatalogTupleDelete(relation, &oldtuple->t_self);
4668 }
4669 }
4670 else
4671 {
4672 Datum values[Natts_pg_init_privs] = {0};
4673 bool nulls[Natts_pg_init_privs] = {0};
4674
4675 /*
4676 * Only add a new entry if the new ACL is non-NULL.
4677 *
4678 * If we are passed in a NULL ACL and no entry exists, we can just
4679 * fall through and do nothing.
4680 */
4681 if (new_acl && ACL_NUM(new_acl) != 0)
4682 {
4683 /* No entry found, so add it. */
4684 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4685 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4686 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4687
4688 /* This function only handles initial privileges of extensions */
4689 values[Anum_pg_init_privs_privtype - 1] =
4691
4692 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4693
4694 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4695
4696 CatalogTupleInsert(relation, tuple);
4697
4698 /* Update pg_shdepend, too. */
4699 noldmembers = 0;
4700 oldmembers = NULL;
4701
4702 updateInitAclDependencies(classoid, objoid, objsubid,
4703 noldmembers, oldmembers,
4704 nnewmembers, newmembers);
4705 }
4706 }
4707
4708 systable_endscan(scan);
4709
4710 /* prevent error when processing objects multiple times */
4712
4713 table_close(relation, RowExclusiveLock);
4714}
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
@ INITPRIVS_EXTENSION
Definition: pg_init_privs.h:80
void updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:512
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217

References ACL_NUM, aclmembers(), Assert(), BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), CommandCounterIncrement(), DatumGetAclP, heap_form_tuple(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, INITPRIVS_EXTENSION, Int32GetDatum(), sort-test::key, ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), updateInitAclDependencies(), and values.

Referenced by recordExtensionInitPriv(), recordExtObjInitPriv(), and removeExtObjInitPriv().

◆ recordExtObjInitPriv()

void recordExtObjInitPriv ( Oid  objoid,
Oid  classoid 
)

Definition at line 4318 of file aclchk.c.

4319{
4320 /*
4321 * pg_class / pg_attribute
4322 *
4323 * If this is a relation then we need to see if there are any sub-objects
4324 * (eg: columns) for it and, if so, be sure to call
4325 * recordExtensionInitPrivWorker() for each one.
4326 */
4327 if (classoid == RelationRelationId)
4328 {
4329 Form_pg_class pg_class_tuple;
4330 Datum aclDatum;
4331 bool isNull;
4332 HeapTuple tuple;
4333
4334 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4335 if (!HeapTupleIsValid(tuple))
4336 elog(ERROR, "cache lookup failed for relation %u", objoid);
4337 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4338
4339 /*
4340 * Indexes don't have permissions, neither do the pg_class rows for
4341 * composite types. (These cases are unreachable given the
4342 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4343 */
4344 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4345 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4346 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4347 {
4348 ReleaseSysCache(tuple);
4349 return;
4350 }
4351
4352 /*
4353 * If this isn't a sequence then it's possibly going to have
4354 * column-level ACLs associated with it.
4355 */
4356 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4357 {
4358 AttrNumber curr_att;
4359 AttrNumber nattrs = pg_class_tuple->relnatts;
4360
4361 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4362 {
4363 HeapTuple attTuple;
4364 Datum attaclDatum;
4365
4366 attTuple = SearchSysCache2(ATTNUM,
4367 ObjectIdGetDatum(objoid),
4368 Int16GetDatum(curr_att));
4369
4370 if (!HeapTupleIsValid(attTuple))
4371 continue;
4372
4373 /* ignore dropped columns */
4374 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4375 {
4376 ReleaseSysCache(attTuple);
4377 continue;
4378 }
4379
4380 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4381 Anum_pg_attribute_attacl,
4382 &isNull);
4383
4384 /* no need to do anything for a NULL ACL */
4385 if (isNull)
4386 {
4387 ReleaseSysCache(attTuple);
4388 continue;
4389 }
4390
4391 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4392 DatumGetAclP(attaclDatum));
4393
4394 ReleaseSysCache(attTuple);
4395 }
4396 }
4397
4398 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4399 &isNull);
4400
4401 /* Add the record, if any, for the top-level object */
4402 if (!isNull)
4403 recordExtensionInitPrivWorker(objoid, classoid, 0,
4404 DatumGetAclP(aclDatum));
4405
4406 ReleaseSysCache(tuple);
4407 }
4408 else if (classoid == LargeObjectRelationId)
4409 {
4410 /* For large objects, we must consult pg_largeobject_metadata */
4411 Datum aclDatum;
4412 bool isNull;
4413 HeapTuple tuple;
4414 ScanKeyData entry[1];
4415 SysScanDesc scan;
4416 Relation relation;
4417
4418 /*
4419 * Note: this is dead code, given that we don't allow large objects to
4420 * be made extension members. But it seems worth carrying in case
4421 * some future caller of this function has need for it.
4422 */
4423 relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4424
4425 /* There's no syscache for pg_largeobject_metadata */
4426 ScanKeyInit(&entry[0],
4427 Anum_pg_largeobject_metadata_oid,
4428 BTEqualStrategyNumber, F_OIDEQ,
4429 ObjectIdGetDatum(objoid));
4430
4431 scan = systable_beginscan(relation,
4432 LargeObjectMetadataOidIndexId, true,
4433 NULL, 1, entry);
4434
4435 tuple = systable_getnext(scan);
4436 if (!HeapTupleIsValid(tuple))
4437 elog(ERROR, "could not find tuple for large object %u", objoid);
4438
4439 aclDatum = heap_getattr(tuple,
4440 Anum_pg_largeobject_metadata_lomacl,
4441 RelationGetDescr(relation), &isNull);
4442
4443 /* Add the record, if any, for the top-level object */
4444 if (!isNull)
4445 recordExtensionInitPrivWorker(objoid, classoid, 0,
4446 DatumGetAclP(aclDatum));
4447
4448 systable_endscan(scan);
4449 }
4450 /* This will error on unsupported classoid. */
4451 else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4452 {
4453 int cacheid;
4454 Datum aclDatum;
4455 bool isNull;
4456 HeapTuple tuple;
4457
4458 cacheid = get_object_catcache_oid(classoid);
4459 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
4460 if (!HeapTupleIsValid(tuple))
4461 elog(ERROR, "cache lookup failed for %s %u",
4462 get_object_class_descr(classoid), objoid);
4463
4464 aclDatum = SysCacheGetAttr(cacheid, tuple,
4465 get_object_attnum_acl(classoid),
4466 &isNull);
4467
4468 /* Add the record, if any, for the top-level object */
4469 if (!isNull)
4470 recordExtensionInitPrivWorker(objoid, classoid, 0,
4471 DatumGetAclP(aclDatum));
4472
4473 ReleaseSysCache(tuple);
4474 }
4475}

References BTEqualStrategyNumber, DatumGetAclP, elog, ERROR, get_object_attnum_acl(), get_object_catcache_oid(), get_object_class_descr(), GETSTRUCT(), heap_getattr(), HeapTupleIsValid, Int16GetDatum(), InvalidAttrNumber, ObjectIdGetDatum(), recordExtensionInitPrivWorker(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SearchSysCache2(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), and table_open().

Referenced by ExecAlterExtensionContentsRecurse().

◆ removeExtObjInitPriv()

void removeExtObjInitPriv ( Oid  objoid,
Oid  classoid 
)

Definition at line 4482 of file aclchk.c.

4483{
4484 /*
4485 * If this is a relation then we need to see if there are any sub-objects
4486 * (eg: columns) for it and, if so, be sure to call
4487 * recordExtensionInitPrivWorker() for each one.
4488 */
4489 if (classoid == RelationRelationId)
4490 {
4491 Form_pg_class pg_class_tuple;
4492 HeapTuple tuple;
4493
4494 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4495 if (!HeapTupleIsValid(tuple))
4496 elog(ERROR, "cache lookup failed for relation %u", objoid);
4497 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4498
4499 /*
4500 * Indexes don't have permissions, neither do the pg_class rows for
4501 * composite types. (These cases are unreachable given the
4502 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4503 */
4504 if (pg_class_tuple->relkind == RELKIND_INDEX ||
4505 pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4506 pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4507 {
4508 ReleaseSysCache(tuple);
4509 return;
4510 }
4511
4512 /*
4513 * If this isn't a sequence then it's possibly going to have
4514 * column-level ACLs associated with it.
4515 */
4516 if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4517 {
4518 AttrNumber curr_att;
4519 AttrNumber nattrs = pg_class_tuple->relnatts;
4520
4521 for (curr_att = 1; curr_att <= nattrs; curr_att++)
4522 {
4523 HeapTuple attTuple;
4524
4525 attTuple = SearchSysCache2(ATTNUM,
4526 ObjectIdGetDatum(objoid),
4527 Int16GetDatum(curr_att));
4528
4529 if (!HeapTupleIsValid(attTuple))
4530 continue;
4531
4532 /* when removing, remove all entries, even dropped columns */
4533
4534 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4535
4536 ReleaseSysCache(attTuple);
4537 }
4538 }
4539
4540 ReleaseSysCache(tuple);
4541 }
4542
4543 /* Remove the record, if any, for the top-level object */
4544 recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4545}

References elog, ERROR, GETSTRUCT(), HeapTupleIsValid, Int16GetDatum(), ObjectIdGetDatum(), recordExtensionInitPrivWorker(), ReleaseSysCache(), SearchSysCache1(), and SearchSysCache2().

Referenced by ExecAlterExtensionContentsRecurse().

◆ RemoveRoleFromInitPriv()

void RemoveRoleFromInitPriv ( Oid  roleid,
Oid  classid,
Oid  objid,
int32  objsubid 
)

Definition at line 4831 of file aclchk.c.

4832{
4833 Relation rel;
4834 ScanKeyData key[3];
4835 SysScanDesc scan;
4836 HeapTuple oldtuple;
4837 int cacheid;
4838 HeapTuple objtuple;
4839 Oid ownerId;
4840 Datum oldAclDatum;
4841 bool isNull;
4842 Acl *old_acl;
4843 Acl *new_acl;
4844 HeapTuple newtuple;
4845 int noldmembers;
4846 int nnewmembers;
4847 Oid *oldmembers;
4848 Oid *newmembers;
4849
4850 /* Search for existing pg_init_privs entry for the target object. */
4851 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4852
4853 ScanKeyInit(&key[0],
4854 Anum_pg_init_privs_objoid,
4855 BTEqualStrategyNumber, F_OIDEQ,
4856 ObjectIdGetDatum(objid));
4857 ScanKeyInit(&key[1],
4858 Anum_pg_init_privs_classoid,
4859 BTEqualStrategyNumber, F_OIDEQ,
4860 ObjectIdGetDatum(classid));
4861 ScanKeyInit(&key[2],
4862 Anum_pg_init_privs_objsubid,
4863 BTEqualStrategyNumber, F_INT4EQ,
4864 Int32GetDatum(objsubid));
4865
4866 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4867 NULL, 3, key);
4868
4869 /* There should exist only one entry or none. */
4870 oldtuple = systable_getnext(scan);
4871
4872 if (!HeapTupleIsValid(oldtuple))
4873 {
4874 /*
4875 * Hmm, why are we here if there's no entry? But pack up and go away
4876 * quietly.
4877 */
4878 systable_endscan(scan);
4880 return;
4881 }
4882
4883 /* Get a writable copy of the existing ACL. */
4884 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4885 RelationGetDescr(rel), &isNull);
4886 Assert(!isNull);
4887 old_acl = DatumGetAclPCopy(oldAclDatum);
4888
4889 /*
4890 * We need the members of both old and new ACLs so we can correct the
4891 * shared dependency information. Collect data before
4892 * merge_acl_with_grant throws away old_acl.
4893 */
4894 noldmembers = aclmembers(old_acl, &oldmembers);
4895
4896 /* Must find out the owner's OID the hard way. */
4897 cacheid = get_object_catcache_oid(classid);
4898 objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
4899 if (!HeapTupleIsValid(objtuple))
4900 elog(ERROR, "cache lookup failed for %s %u",
4901 get_object_class_descr(classid), objid);
4902
4903 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4904 objtuple,
4905 get_object_attnum_owner(classid)));
4906 ReleaseSysCache(objtuple);
4907
4908 /*
4909 * Generate new ACL. Grantor of rights is always the same as the owner.
4910 */
4911 if (old_acl != NULL)
4912 new_acl = merge_acl_with_grant(old_acl,
4913 false, /* is_grant */
4914 false, /* grant_option */
4916 list_make1_oid(roleid),
4918 ownerId,
4919 ownerId);
4920 else
4921 new_acl = NULL; /* this case shouldn't happen, probably */
4922
4923 /* If we end with an empty ACL, delete the pg_init_privs entry. */
4924 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4925 {
4926 CatalogTupleDelete(rel, &oldtuple->t_self);
4927 }
4928 else
4929 {
4930 Datum values[Natts_pg_init_privs] = {0};
4931 bool nulls[Natts_pg_init_privs] = {0};
4932 bool replaces[Natts_pg_init_privs] = {0};
4933
4934 /* Update existing entry. */
4935 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4936 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4937
4938 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4939 values, nulls, replaces);
4940 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4941 }
4942
4943 /*
4944 * Update the shared dependency ACL info.
4945 */
4946 nnewmembers = aclmembers(new_acl, &newmembers);
4947
4948 updateInitAclDependencies(classid, objid, objsubid,
4949 noldmembers, oldmembers,
4950 nnewmembers, newmembers);
4951
4952 systable_endscan(scan);
4953
4954 /* prevent error when processing objects multiple times */
4956
4958}
#define ACLITEM_ALL_PRIV_BITS
Definition: acl.h:87
@ DROP_RESTRICT
Definition: parsenodes.h:2385
#define list_make1_oid(x1)
Definition: pg_list.h:242

References ACL_NUM, ACLITEM_ALL_PRIV_BITS, aclmembers(), Assert(), BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetAclPCopy, DatumGetObjectId(), DROP_RESTRICT, elog, ERROR, get_object_attnum_owner(), get_object_catcache_oid(), get_object_class_descr(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, Int32GetDatum(), sort-test::key, list_make1_oid, merge_acl_with_grant(), ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SysCacheGetAttrNotNull(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), updateInitAclDependencies(), and values.

Referenced by shdepDropOwned().

◆ RemoveRoleFromObjectACL()

void RemoveRoleFromObjectACL ( Oid  roleid,
Oid  classid,
Oid  objid 
)

Definition at line 1393 of file aclchk.c.

1394{
1395 if (classid == DefaultAclRelationId)
1396 {
1397 InternalDefaultACL iacls;
1398 Form_pg_default_acl pg_default_acl_tuple;
1399 Relation rel;
1400 ScanKeyData skey[1];
1401 SysScanDesc scan;
1402 HeapTuple tuple;
1403
1404 /* first fetch info needed by SetDefaultACL */
1405 rel = table_open(DefaultAclRelationId, AccessShareLock);
1406
1407 ScanKeyInit(&skey[0],
1408 Anum_pg_default_acl_oid,
1409 BTEqualStrategyNumber, F_OIDEQ,
1410 ObjectIdGetDatum(objid));
1411
1412 scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1413 NULL, 1, skey);
1414
1415 tuple = systable_getnext(scan);
1416
1417 if (!HeapTupleIsValid(tuple))
1418 elog(ERROR, "could not find tuple for default ACL %u", objid);
1419
1420 pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1421
1422 iacls.roleid = pg_default_acl_tuple->defaclrole;
1423 iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1424
1425 switch (pg_default_acl_tuple->defaclobjtype)
1426 {
1427 case DEFACLOBJ_RELATION:
1428 iacls.objtype = OBJECT_TABLE;
1429 break;
1430 case DEFACLOBJ_SEQUENCE:
1431 iacls.objtype = OBJECT_SEQUENCE;
1432 break;
1433 case DEFACLOBJ_FUNCTION:
1434 iacls.objtype = OBJECT_FUNCTION;
1435 break;
1436 case DEFACLOBJ_TYPE:
1437 iacls.objtype = OBJECT_TYPE;
1438 break;
1439 case DEFACLOBJ_NAMESPACE:
1440 iacls.objtype = OBJECT_SCHEMA;
1441 break;
1442 default:
1443 /* Shouldn't get here */
1444 elog(ERROR, "unexpected default ACL type: %d",
1445 (int) pg_default_acl_tuple->defaclobjtype);
1446 break;
1447 }
1448
1449 systable_endscan(scan);
1451
1452 iacls.is_grant = false;
1453 iacls.all_privs = true;
1454 iacls.privileges = ACL_NO_RIGHTS;
1455 iacls.grantees = list_make1_oid(roleid);
1456 iacls.grant_option = false;
1457 iacls.behavior = DROP_CASCADE;
1458
1459 /* Do it */
1460 SetDefaultACL(&iacls);
1461 }
1462 else
1463 {
1464 InternalGrant istmt;
1465
1466 switch (classid)
1467 {
1468 case RelationRelationId:
1469 /* it's OK to use TABLE for a sequence */
1470 istmt.objtype = OBJECT_TABLE;
1471 break;
1472 case DatabaseRelationId:
1473 istmt.objtype = OBJECT_DATABASE;
1474 break;
1475 case TypeRelationId:
1476 istmt.objtype = OBJECT_TYPE;
1477 break;
1478 case ProcedureRelationId:
1479 istmt.objtype = OBJECT_ROUTINE;
1480 break;
1481 case LanguageRelationId:
1482 istmt.objtype = OBJECT_LANGUAGE;
1483 break;
1484 case LargeObjectRelationId:
1486 break;
1487 case NamespaceRelationId:
1488 istmt.objtype = OBJECT_SCHEMA;
1489 break;
1490 case TableSpaceRelationId:
1491 istmt.objtype = OBJECT_TABLESPACE;
1492 break;
1493 case ForeignServerRelationId:
1495 break;
1496 case ForeignDataWrapperRelationId:
1497 istmt.objtype = OBJECT_FDW;
1498 break;
1499 case ParameterAclRelationId:
1501 break;
1502 default:
1503 elog(ERROR, "unexpected object class %u", classid);
1504 break;
1505 }
1506 istmt.is_grant = false;
1507 istmt.objects = list_make1_oid(objid);
1508 istmt.all_privs = true;
1509 istmt.privileges = ACL_NO_RIGHTS;
1510 istmt.col_privs = NIL;
1511 istmt.grantees = list_make1_oid(roleid);
1512 istmt.grant_option = false;
1513 istmt.behavior = DROP_CASCADE;
1514
1515 ExecGrantStmt_oids(&istmt);
1516 }
1517}
static void SetDefaultACL(InternalDefaultACL *iacls)
Definition: aclchk.c:1130
@ DROP_CASCADE
Definition: parsenodes.h:2386
FormData_pg_default_acl * Form_pg_default_acl

References AccessShareLock, ACL_NO_RIGHTS, InternalDefaultACL::all_privs, InternalGrant::all_privs, InternalDefaultACL::behavior, InternalGrant::behavior, BTEqualStrategyNumber, InternalGrant::col_privs, DROP_CASCADE, elog, ERROR, ExecGrantStmt_oids(), GETSTRUCT(), InternalDefaultACL::grant_option, InternalGrant::grant_option, InternalDefaultACL::grantees, InternalGrant::grantees, HeapTupleIsValid, InternalDefaultACL::is_grant, InternalGrant::is_grant, list_make1_oid, NIL, InternalDefaultACL::nspid, OBJECT_DATABASE, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_PARAMETER_ACL, OBJECT_ROUTINE, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TYPE, ObjectIdGetDatum(), InternalGrant::objects, InternalDefaultACL::objtype, InternalGrant::objtype, InternalDefaultACL::privileges, InternalGrant::privileges, InternalDefaultACL::roleid, ScanKeyInit(), SetDefaultACL(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by shdepDropOwned().

◆ ReplaceRoleInInitPriv()

void ReplaceRoleInInitPriv ( Oid  oldroleid,
Oid  newroleid,
Oid  classid,
Oid  objid,
int32  objsubid 
)

Definition at line 4722 of file aclchk.c.

4724{
4725 Relation rel;
4726 ScanKeyData key[3];
4727 SysScanDesc scan;
4728 HeapTuple oldtuple;
4729 Datum oldAclDatum;
4730 bool isNull;
4731 Acl *old_acl;
4732 Acl *new_acl;
4733 HeapTuple newtuple;
4734 int noldmembers;
4735 int nnewmembers;
4736 Oid *oldmembers;
4737 Oid *newmembers;
4738
4739 /* Search for existing pg_init_privs entry for the target object. */
4740 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4741
4742 ScanKeyInit(&key[0],
4743 Anum_pg_init_privs_objoid,
4744 BTEqualStrategyNumber, F_OIDEQ,
4745 ObjectIdGetDatum(objid));
4746 ScanKeyInit(&key[1],
4747 Anum_pg_init_privs_classoid,
4748 BTEqualStrategyNumber, F_OIDEQ,
4749 ObjectIdGetDatum(classid));
4750 ScanKeyInit(&key[2],
4751 Anum_pg_init_privs_objsubid,
4752 BTEqualStrategyNumber, F_INT4EQ,
4753 Int32GetDatum(objsubid));
4754
4755 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4756 NULL, 3, key);
4757
4758 /* There should exist only one entry or none. */
4759 oldtuple = systable_getnext(scan);
4760
4761 if (!HeapTupleIsValid(oldtuple))
4762 {
4763 /*
4764 * Hmm, why are we here if there's no entry? But pack up and go away
4765 * quietly.
4766 */
4767 systable_endscan(scan);
4769 return;
4770 }
4771
4772 /* Get a writable copy of the existing ACL. */
4773 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4774 RelationGetDescr(rel), &isNull);
4775 Assert(!isNull);
4776 old_acl = DatumGetAclPCopy(oldAclDatum);
4777
4778 /*
4779 * Generate new ACL. This usage of aclnewowner is a bit off-label when
4780 * oldroleid isn't the owner; but it does the job fine.
4781 */
4782 new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4783
4784 /*
4785 * If we end with an empty ACL, delete the pg_init_privs entry. (That
4786 * probably can't happen here, but we may as well cover the case.)
4787 */
4788 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4789 {
4790 CatalogTupleDelete(rel, &oldtuple->t_self);
4791 }
4792 else
4793 {
4794 Datum values[Natts_pg_init_privs] = {0};
4795 bool nulls[Natts_pg_init_privs] = {0};
4796 bool replaces[Natts_pg_init_privs] = {0};
4797
4798 /* Update existing entry. */
4799 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4800 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4801
4802 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4803 values, nulls, replaces);
4804 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4805 }
4806
4807 /*
4808 * Update the shared dependency ACL info.
4809 */
4810 noldmembers = aclmembers(old_acl, &oldmembers);
4811 nnewmembers = aclmembers(new_acl, &newmembers);
4812
4813 updateInitAclDependencies(classid, objid, objsubid,
4814 noldmembers, oldmembers,
4815 nnewmembers, newmembers);
4816
4817 systable_endscan(scan);
4818
4819 /* prevent error when processing objects multiple times */
4821
4823}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1103

References ACL_NUM, aclmembers(), aclnewowner(), Assert(), BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleUpdate(), CommandCounterIncrement(), DatumGetAclPCopy, heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, Int32GetDatum(), sort-test::key, ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), updateInitAclDependencies(), and values.

Referenced by shdepReassignOwned_InitAcl().

◆ restrict_and_check_grant()

static AclMode restrict_and_check_grant ( bool  is_grant,
AclMode  avail_goptions,
bool  all_privs,
AclMode  privileges,
Oid  objectId,
Oid  grantorId,
ObjectType  objtype,
const char *  objname,
AttrNumber  att_number,
const char *  colname 
)
static

Definition at line 241 of file aclchk.c.

245{
246 AclMode this_privileges;
247 AclMode whole_mask;
248
249 switch (objtype)
250 {
251 case OBJECT_COLUMN:
252 whole_mask = ACL_ALL_RIGHTS_COLUMN;
253 break;
254 case OBJECT_TABLE:
255 whole_mask = ACL_ALL_RIGHTS_RELATION;
256 break;
257 case OBJECT_SEQUENCE:
258 whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
259 break;
260 case OBJECT_DATABASE:
261 whole_mask = ACL_ALL_RIGHTS_DATABASE;
262 break;
263 case OBJECT_FUNCTION:
264 whole_mask = ACL_ALL_RIGHTS_FUNCTION;
265 break;
266 case OBJECT_LANGUAGE:
267 whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
268 break;
270 whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
271 break;
272 case OBJECT_SCHEMA:
273 whole_mask = ACL_ALL_RIGHTS_SCHEMA;
274 break;
276 whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
277 break;
278 case OBJECT_FDW:
279 whole_mask = ACL_ALL_RIGHTS_FDW;
280 break;
283 break;
285 elog(ERROR, "grantable rights not supported for event triggers");
286 /* not reached, but keep compiler quiet */
287 return ACL_NO_RIGHTS;
288 case OBJECT_TYPE:
289 whole_mask = ACL_ALL_RIGHTS_TYPE;
290 break;
292 whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
293 break;
294 default:
295 elog(ERROR, "unrecognized object type: %d", objtype);
296 /* not reached, but keep compiler quiet */
297 return ACL_NO_RIGHTS;
298 }
299
300 /*
301 * If we found no grant options, consider whether to issue a hard error.
302 * Per spec, having any privilege at all on the object will get you by
303 * here.
304 */
305 if (avail_goptions == ACL_NO_RIGHTS)
306 {
307 if (pg_aclmask(objtype, objectId, att_number, grantorId,
308 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
310 {
311 if (objtype == OBJECT_COLUMN && colname)
312 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
313 else
314 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
315 }
316 }
317
318 /*
319 * Restrict the operation to what we can actually grant or revoke, and
320 * issue a warning if appropriate. (For REVOKE this isn't quite what the
321 * spec says to do: the spec seems to want a warning only if no privilege
322 * bits actually change in the ACL. In practice that behavior seems much
323 * too noisy, as well as inconsistent with the GRANT case.)
324 */
325 this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
326 if (is_grant)
327 {
328 if (this_privileges == 0)
329 {
330 if (objtype == OBJECT_COLUMN && colname)
332 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
333 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
334 colname, objname)));
335 else
337 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
338 errmsg("no privileges were granted for \"%s\"",
339 objname)));
340 }
341 else if (!all_privs && this_privileges != privileges)
342 {
343 if (objtype == OBJECT_COLUMN && colname)
345 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
346 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
347 colname, objname)));
348 else
350 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
351 errmsg("not all privileges were granted for \"%s\"",
352 objname)));
353 }
354 }
355 else
356 {
357 if (this_privileges == 0)
358 {
359 if (objtype == OBJECT_COLUMN && colname)
361 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
362 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
363 colname, objname)));
364 else
366 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
367 errmsg("no privileges could be revoked for \"%s\"",
368 objname)));
369 }
370 else if (!all_privs && this_privileges != privileges)
371 {
372 if (objtype == OBJECT_COLUMN && colname)
374 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
375 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
376 colname, objname)));
377 else
379 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
380 errmsg("not all privileges could be revoked for \"%s\"",
381 objname)));
382 }
383 }
384
385 return this_privileges;
386}
#define ACL_OPTION_TO_PRIVS(privs)
Definition: acl.h:71
#define ACL_GRANT_OPTION_FOR(privs)
Definition: acl.h:70
void aclcheck_error_col(AclResult aclerr, ObjectType objtype, const char *objectname, const char *colname)
Definition: aclchk.c:2911
static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:2953

References ACL_ALL_RIGHTS_COLUMN, ACL_ALL_RIGHTS_DATABASE, ACL_ALL_RIGHTS_FDW, ACL_ALL_RIGHTS_FOREIGN_SERVER, ACL_ALL_RIGHTS_FUNCTION, ACL_ALL_RIGHTS_LANGUAGE, ACL_ALL_RIGHTS_LARGEOBJECT, ACL_ALL_RIGHTS_PARAMETER_ACL, ACL_ALL_RIGHTS_RELATION, ACL_ALL_RIGHTS_SCHEMA, ACL_ALL_RIGHTS_SEQUENCE, ACL_ALL_RIGHTS_TABLESPACE, ACL_ALL_RIGHTS_TYPE, ACL_GRANT_OPTION_FOR, ACL_NO_RIGHTS, ACL_OPTION_TO_PRIVS, aclcheck_error(), aclcheck_error_col(), ACLCHECK_NO_PRIV, ACLMASK_ANY, elog, ereport, errcode(), errmsg(), ERROR, OBJECT_COLUMN, OBJECT_DATABASE, OBJECT_EVENT_TRIGGER, OBJECT_FDW, OBJECT_FOREIGN_SERVER, OBJECT_FUNCTION, OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_PARAMETER_ACL, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TABLESPACE, OBJECT_TYPE, pg_aclmask(), and WARNING.

Referenced by ExecGrant_Attribute(), ExecGrant_common(), ExecGrant_Largeobject(), ExecGrant_Parameter(), and ExecGrant_Relation().

◆ SetDefaultACL()

static void SetDefaultACL ( InternalDefaultACL iacls)
static

Definition at line 1130 of file aclchk.c.

1131{
1132 AclMode this_privileges = iacls->privileges;
1133 char objtype;
1134 Relation rel;
1135 HeapTuple tuple;
1136 bool isNew;
1137 Acl *def_acl;
1138 Acl *old_acl;
1139 Acl *new_acl;
1140 HeapTuple newtuple;
1141 int noldmembers;
1142 int nnewmembers;
1143 Oid *oldmembers;
1144 Oid *newmembers;
1145
1146 rel = table_open(DefaultAclRelationId, RowExclusiveLock);
1147
1148 /*
1149 * The default for a global entry is the hard-wired default ACL for the
1150 * particular object type. The default for non-global entries is an empty
1151 * ACL. This must be so because global entries replace the hard-wired
1152 * defaults, while others are added on.
1153 */
1154 if (!OidIsValid(iacls->nspid))
1155 def_acl = acldefault(iacls->objtype, iacls->roleid);
1156 else
1157 def_acl = make_empty_acl();
1158
1159 /*
1160 * Convert ACL object type to pg_default_acl object type and handle
1161 * all_privs option
1162 */
1163 switch (iacls->objtype)
1164 {
1165 case OBJECT_TABLE:
1166 objtype = DEFACLOBJ_RELATION;
1167 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1168 this_privileges = ACL_ALL_RIGHTS_RELATION;
1169 break;
1170
1171 case OBJECT_SEQUENCE:
1172 objtype = DEFACLOBJ_SEQUENCE;
1173 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1174 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1175 break;
1176
1177 case OBJECT_FUNCTION:
1178 objtype = DEFACLOBJ_FUNCTION;
1179 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1180 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
1181 break;
1182
1183 case OBJECT_TYPE:
1184 objtype = DEFACLOBJ_TYPE;
1185 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1186 this_privileges = ACL_ALL_RIGHTS_TYPE;
1187 break;
1188
1189 case OBJECT_SCHEMA:
1190 if (OidIsValid(iacls->nspid))
1191 ereport(ERROR,
1192 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1193 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1194 objtype = DEFACLOBJ_NAMESPACE;
1195 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1196 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1197 break;
1198
1199 default:
1200 elog(ERROR, "unrecognized object type: %d",
1201 (int) iacls->objtype);
1202 objtype = 0; /* keep compiler quiet */
1203 break;
1204 }
1205
1206 /* Search for existing row for this object type in catalog */
1207 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1208 ObjectIdGetDatum(iacls->roleid),
1209 ObjectIdGetDatum(iacls->nspid),
1210 CharGetDatum(objtype));
1211
1212 if (HeapTupleIsValid(tuple))
1213 {
1214 Datum aclDatum;
1215 bool isNull;
1216
1217 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1218 Anum_pg_default_acl_defaclacl,
1219 &isNull);
1220 if (!isNull)
1221 old_acl = DatumGetAclPCopy(aclDatum);
1222 else
1223 old_acl = NULL; /* this case shouldn't happen, probably */
1224 isNew = false;
1225 }
1226 else
1227 {
1228 old_acl = NULL;
1229 isNew = true;
1230 }
1231
1232 if (old_acl != NULL)
1233 {
1234 /*
1235 * We need the members of both old and new ACLs so we can correct the
1236 * shared dependency information. Collect data before
1237 * merge_acl_with_grant throws away old_acl.
1238 */
1239 noldmembers = aclmembers(old_acl, &oldmembers);
1240 }
1241 else
1242 {
1243 /* If no or null entry, start with the default ACL value */
1244 old_acl = aclcopy(def_acl);
1245 /* There are no old member roles according to the catalogs */
1246 noldmembers = 0;
1247 oldmembers = NULL;
1248 }
1249
1250 /*
1251 * Generate new ACL. Grantor of rights is always the same as the target
1252 * role.
1253 */
1254 new_acl = merge_acl_with_grant(old_acl,
1255 iacls->is_grant,
1256 iacls->grant_option,
1257 iacls->behavior,
1258 iacls->grantees,
1259 this_privileges,
1260 iacls->roleid,
1261 iacls->roleid);
1262
1263 /*
1264 * If the result is the same as the default value, we do not need an
1265 * explicit pg_default_acl entry, and should in fact remove the entry if
1266 * it exists. Must sort both arrays to compare properly.
1267 */
1268 aclitemsort(new_acl);
1269 aclitemsort(def_acl);
1270 if (aclequal(new_acl, def_acl))
1271 {
1272 /* delete old entry, if indeed there is one */
1273 if (!isNew)
1274 {
1275 ObjectAddress myself;
1276
1277 /*
1278 * The dependency machinery will take care of removing all
1279 * associated dependency entries. We use DROP_RESTRICT since
1280 * there shouldn't be anything depending on this entry.
1281 */
1282 myself.classId = DefaultAclRelationId;
1283 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1284 myself.objectSubId = 0;
1285
1286 performDeletion(&myself, DROP_RESTRICT, 0);
1287 }
1288 }
1289 else
1290 {
1291 Datum values[Natts_pg_default_acl] = {0};
1292 bool nulls[Natts_pg_default_acl] = {0};
1293 bool replaces[Natts_pg_default_acl] = {0};
1294 Oid defAclOid;
1295
1296 if (isNew)
1297 {
1298 /* insert new entry */
1299 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1300 Anum_pg_default_acl_oid);
1301 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1302 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1303 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1304 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1305 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1306
1307 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1308 CatalogTupleInsert(rel, newtuple);
1309 }
1310 else
1311 {
1312 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1313
1314 /* update existing entry */
1315 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1316 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1317
1318 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1319 values, nulls, replaces);
1320 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1321 }
1322
1323 /* these dependencies don't change in an update */
1324 if (isNew)
1325 {
1326 /* dependency on role */
1327 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1328 iacls->roleid);
1329
1330 /* dependency on namespace */
1331 if (OidIsValid(iacls->nspid))
1332 {
1333 ObjectAddress myself,
1334 referenced;
1335
1336 myself.classId = DefaultAclRelationId;
1337 myself.objectId = defAclOid;
1338 myself.objectSubId = 0;
1339
1340 referenced.classId = NamespaceRelationId;
1341 referenced.objectId = iacls->nspid;
1342 referenced.objectSubId = 0;
1343
1344 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1345 }
1346 }
1347
1348 /*
1349 * Update the shared dependency ACL info
1350 */
1351 nnewmembers = aclmembers(new_acl, &newmembers);
1352
1353 updateAclDependencies(DefaultAclRelationId,
1354 defAclOid, 0,
1355 iacls->roleid,
1356 noldmembers, oldmembers,
1357 nnewmembers, newmembers);
1358
1359 if (isNew)
1360 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1361 else
1362 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1363 }
1364
1365 if (HeapTupleIsValid(tuple))
1366 ReleaseSysCache(tuple);
1367
1369
1370 /* prevent error when processing duplicate objects */
1372}
Acl * make_empty_acl(void)
Definition: acl.c:432
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DEPENDENCY_AUTO
Definition: dependency.h:34
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168

References ACL_ALL_RIGHTS_FUNCTION, ACL_ALL_RIGHTS_RELATION, ACL_ALL_RIGHTS_SCHEMA, ACL_ALL_RIGHTS_SEQUENCE, ACL_ALL_RIGHTS_TYPE, ACL_NO_RIGHTS, aclcopy(), acldefault(), aclequal(), aclitemsort(), aclmembers(), InternalDefaultACL::all_privs, InternalDefaultACL::behavior, CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetAclPCopy, DEPENDENCY_AUTO, DROP_RESTRICT, elog, ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), GETSTRUCT(), InternalDefaultACL::grant_option, InternalDefaultACL::grantees, heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, InvokeObjectPostCreateHook, InternalDefaultACL::is_grant, make_empty_acl(), merge_acl_with_grant(), InternalDefaultACL::nspid, OBJECT_FUNCTION, OBJECT_SCHEMA, OBJECT_SEQUENCE, OBJECT_TABLE, OBJECT_TYPE, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, InternalDefaultACL::objtype, OidIsValid, performDeletion(), PointerGetDatum(), InternalDefaultACL::privileges, recordDependencyOn(), recordDependencyOnOwner(), RelationGetDescr, ReleaseSysCache(), InternalDefaultACL::roleid, RowExclusiveLock, SearchSysCache3(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), updateAclDependencies(), and values.

Referenced by RemoveRoleFromObjectACL(), and SetDefaultACLsInSchemas().

◆ SetDefaultACLsInSchemas()

static void SetDefaultACLsInSchemas ( InternalDefaultACL iacls,
List nspnames 
)
static

Definition at line 1088 of file aclchk.c.

1089{
1090 if (nspnames == NIL)
1091 {
1092 /* Set database-wide permissions if no schema was specified */
1093 iacls->nspid = InvalidOid;
1094
1095 SetDefaultACL(iacls);
1096 }
1097 else
1098 {
1099 /* Look up the schema OIDs and set permissions for each one */
1100 ListCell *nspcell;
1101
1102 foreach(nspcell, nspnames)
1103 {
1104 char *nspname = strVal(lfirst(nspcell));
1105
1106 iacls->nspid = get_namespace_oid(nspname, false);
1107
1108 /*
1109 * We used to insist that the target role have CREATE privileges
1110 * on the schema, since without that it wouldn't be able to create
1111 * an object for which these default privileges would apply.
1112 * However, this check proved to be more confusing than helpful,
1113 * and it also caused certain database states to not be
1114 * dumpable/restorable, since revoking CREATE doesn't cause
1115 * default privileges for the schema to go away. So now, we just
1116 * allow the ALTER; if the user lacks CREATE he'll find out when
1117 * he tries to create an object.
1118 */
1119
1120 SetDefaultACL(iacls);
1121 }
1122 }
1123}
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3535

References get_namespace_oid(), InvalidOid, lfirst, NIL, InternalDefaultACL::nspid, SetDefaultACL(), and strVal.

Referenced by ExecAlterDefaultPrivilegesStmt().

◆ string_to_privilege()

static AclMode string_to_privilege ( const char *  privname)
static

Definition at line 2534 of file aclchk.c.

2535{
2536 if (strcmp(privname, "insert") == 0)
2537 return ACL_INSERT;
2538 if (strcmp(privname, "select") == 0)
2539 return ACL_SELECT;
2540 if (strcmp(privname, "update") == 0)
2541 return ACL_UPDATE;
2542 if (strcmp(privname, "delete") == 0)
2543 return ACL_DELETE;
2544 if (strcmp(privname, "truncate") == 0)
2545 return ACL_TRUNCATE;
2546 if (strcmp(privname, "references") == 0)
2547 return ACL_REFERENCES;
2548 if (strcmp(privname, "trigger") == 0)
2549 return ACL_TRIGGER;
2550 if (strcmp(privname, "execute") == 0)
2551 return ACL_EXECUTE;
2552 if (strcmp(privname, "usage") == 0)
2553 return ACL_USAGE;
2554 if (strcmp(privname, "create") == 0)
2555 return ACL_CREATE;
2556 if (strcmp(privname, "temporary") == 0)
2557 return ACL_CREATE_TEMP;
2558 if (strcmp(privname, "temp") == 0)
2559 return ACL_CREATE_TEMP;
2560 if (strcmp(privname, "connect") == 0)
2561 return ACL_CONNECT;
2562 if (strcmp(privname, "set") == 0)
2563 return ACL_SET;
2564 if (strcmp(privname, "alter system") == 0)
2565 return ACL_ALTER_SYSTEM;
2566 if (strcmp(privname, "maintain") == 0)
2567 return ACL_MAINTAIN;
2568 ereport(ERROR,
2569 (errcode(ERRCODE_SYNTAX_ERROR),
2570 errmsg("unrecognized privilege type \"%s\"", privname)));
2571 return 0; /* appease compiler */
2572}

References ACL_ALTER_SYSTEM, ACL_CONNECT, ACL_CREATE, ACL_CREATE_TEMP, ACL_DELETE, ACL_EXECUTE, ACL_INSERT, ACL_MAINTAIN, ACL_REFERENCES, ACL_SELECT, ACL_SET, ACL_TRIGGER, ACL_TRUNCATE, ACL_UPDATE, ACL_USAGE, ereport, errcode(), errmsg(), and ERROR.

Referenced by ExecAlterDefaultPrivilegesStmt(), ExecGrant_Relation(), and ExecuteGrantStmt().

Variable Documentation

◆ binary_upgrade_record_init_privs

bool binary_upgrade_record_init_privs = false

Definition at line 110 of file aclchk.c.

Referenced by binary_upgrade_set_record_init_privs(), and recordExtensionInitPriv().