PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 2639 of file aclchk.c.

2641{
2642 switch (aclerr)
2643 {
2644 case ACLCHECK_OK:
2645 /* no error, so return to caller */
2646 break;
2647 case ACLCHECK_NO_PRIV:
2648 {
2649 const char *msg = "???";
2650
2651 switch (objtype)
2652 {
2653 case OBJECT_AGGREGATE:
2654 msg = gettext_noop("permission denied for aggregate %s");
2655 break;
2656 case OBJECT_COLLATION:
2657 msg = gettext_noop("permission denied for collation %s");
2658 break;
2659 case OBJECT_COLUMN:
2660 msg = gettext_noop("permission denied for column %s");
2661 break;
2662 case OBJECT_CONVERSION:
2663 msg = gettext_noop("permission denied for conversion %s");
2664 break;
2665 case OBJECT_DATABASE:
2666 msg = gettext_noop("permission denied for database %s");
2667 break;
2668 case OBJECT_DOMAIN:
2669 msg = gettext_noop("permission denied for domain %s");
2670 break;
2672 msg = gettext_noop("permission denied for event trigger %s");
2673 break;
2674 case OBJECT_EXTENSION:
2675 msg = gettext_noop("permission denied for extension %s");
2676 break;
2677 case OBJECT_FDW:
2678 msg = gettext_noop("permission denied for foreign-data wrapper %s");
2679 break;
2681 msg = gettext_noop("permission denied for foreign server %s");
2682 break;
2684 msg = gettext_noop("permission denied for foreign table %s");
2685 break;
2686 case OBJECT_FUNCTION:
2687 msg = gettext_noop("permission denied for function %s");
2688 break;
2689 case OBJECT_INDEX:
2690 msg = gettext_noop("permission denied for index %s");
2691 break;
2692 case OBJECT_LANGUAGE:
2693 msg = gettext_noop("permission denied for language %s");
2694 break;
2695 case OBJECT_LARGEOBJECT:
2696 msg = gettext_noop("permission denied for large object %s");
2697 break;
2698 case OBJECT_MATVIEW:
2699 msg = gettext_noop("permission denied for materialized view %s");
2700 break;
2701 case OBJECT_OPCLASS:
2702 msg = gettext_noop("permission denied for operator class %s");
2703 break;
2704 case OBJECT_OPERATOR:
2705 msg = gettext_noop("permission denied for operator %s");
2706 break;
2707 case OBJECT_OPFAMILY:
2708 msg = gettext_noop("permission denied for operator family %s");
2709 break;
2711 msg = gettext_noop("permission denied for parameter %s");
2712 break;
2713 case OBJECT_POLICY:
2714 msg = gettext_noop("permission denied for policy %s");
2715 break;
2716 case OBJECT_PROCEDURE:
2717 msg = gettext_noop("permission denied for procedure %s");
2718 break;
2719 case OBJECT_PUBLICATION:
2720 msg = gettext_noop("permission denied for publication %s");
2721 break;
2722 case OBJECT_ROUTINE:
2723 msg = gettext_noop("permission denied for routine %s");
2724 break;
2725 case OBJECT_SCHEMA:
2726 msg = gettext_noop("permission denied for schema %s");
2727 break;
2728 case OBJECT_SEQUENCE:
2729 msg = gettext_noop("permission denied for sequence %s");
2730 break;
2732 msg = gettext_noop("permission denied for statistics object %s");
2733 break;
2735 msg = gettext_noop("permission denied for subscription %s");
2736 break;
2737 case OBJECT_TABLE:
2738 msg = gettext_noop("permission denied for table %s");
2739 break;
2740 case OBJECT_TABLESPACE:
2741 msg = gettext_noop("permission denied for tablespace %s");
2742 break;
2744 msg = gettext_noop("permission denied for text search configuration %s");
2745 break;
2747 msg = gettext_noop("permission denied for text search dictionary %s");
2748 break;
2749 case OBJECT_TYPE:
2750 msg = gettext_noop("permission denied for type %s");
2751 break;
2752 case OBJECT_VIEW:
2753 msg = gettext_noop("permission denied for view %s");
2754 break;
2755 /* these currently aren't used */
2757 case OBJECT_AMOP:
2758 case OBJECT_AMPROC:
2759 case OBJECT_ATTRIBUTE:
2760 case OBJECT_CAST:
2761 case OBJECT_DEFAULT:
2762 case OBJECT_DEFACL:
2766 case OBJECT_ROLE:
2767 case OBJECT_RULE:
2769 case OBJECT_TRANSFORM:
2770 case OBJECT_TRIGGER:
2771 case OBJECT_TSPARSER:
2772 case OBJECT_TSTEMPLATE:
2774 elog(ERROR, "unsupported object type: %d", objtype);
2775 }
2776
2777 ereport(ERROR,
2778 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2779 errmsg(msg, objectname)));
2780 break;
2781 }
2782 case ACLCHECK_NOT_OWNER:
2783 {
2784 const char *msg = "???";
2785
2786 switch (objtype)
2787 {
2788 case OBJECT_AGGREGATE:
2789 msg = gettext_noop("must be owner of aggregate %s");
2790 break;
2791 case OBJECT_COLLATION:
2792 msg = gettext_noop("must be owner of collation %s");
2793 break;
2794 case OBJECT_CONVERSION:
2795 msg = gettext_noop("must be owner of conversion %s");
2796 break;
2797 case OBJECT_DATABASE:
2798 msg = gettext_noop("must be owner of database %s");
2799 break;
2800 case OBJECT_DOMAIN:
2801 msg = gettext_noop("must be owner of domain %s");
2802 break;
2804 msg = gettext_noop("must be owner of event trigger %s");
2805 break;
2806 case OBJECT_EXTENSION:
2807 msg = gettext_noop("must be owner of extension %s");
2808 break;
2809 case OBJECT_FDW:
2810 msg = gettext_noop("must be owner of foreign-data wrapper %s");
2811 break;
2813 msg = gettext_noop("must be owner of foreign server %s");
2814 break;
2816 msg = gettext_noop("must be owner of foreign table %s");
2817 break;
2818 case OBJECT_FUNCTION:
2819 msg = gettext_noop("must be owner of function %s");
2820 break;
2821 case OBJECT_INDEX:
2822 msg = gettext_noop("must be owner of index %s");
2823 break;
2824 case OBJECT_LANGUAGE:
2825 msg = gettext_noop("must be owner of language %s");
2826 break;
2827 case OBJECT_LARGEOBJECT:
2828 msg = gettext_noop("must be owner of large object %s");
2829 break;
2830 case OBJECT_MATVIEW:
2831 msg = gettext_noop("must be owner of materialized view %s");
2832 break;
2833 case OBJECT_OPCLASS:
2834 msg = gettext_noop("must be owner of operator class %s");
2835 break;
2836 case OBJECT_OPERATOR:
2837 msg = gettext_noop("must be owner of operator %s");
2838 break;
2839 case OBJECT_OPFAMILY:
2840 msg = gettext_noop("must be owner of operator family %s");
2841 break;
2842 case OBJECT_PROCEDURE:
2843 msg = gettext_noop("must be owner of procedure %s");
2844 break;
2845 case OBJECT_PUBLICATION:
2846 msg = gettext_noop("must be owner of publication %s");
2847 break;
2848 case OBJECT_ROUTINE:
2849 msg = gettext_noop("must be owner of routine %s");
2850 break;
2851 case OBJECT_SEQUENCE:
2852 msg = gettext_noop("must be owner of sequence %s");
2853 break;
2855 msg = gettext_noop("must be owner of subscription %s");
2856 break;
2857 case OBJECT_TABLE:
2858 msg = gettext_noop("must be owner of table %s");
2859 break;
2860 case OBJECT_TYPE:
2861 msg = gettext_noop("must be owner of type %s");
2862 break;
2863 case OBJECT_VIEW:
2864 msg = gettext_noop("must be owner of view %s");
2865 break;
2866 case OBJECT_SCHEMA:
2867 msg = gettext_noop("must be owner of schema %s");
2868 break;
2870 msg = gettext_noop("must be owner of statistics object %s");
2871 break;
2872 case OBJECT_TABLESPACE:
2873 msg = gettext_noop("must be owner of tablespace %s");
2874 break;
2876 msg = gettext_noop("must be owner of text search configuration %s");
2877 break;
2879 msg = gettext_noop("must be owner of text search dictionary %s");
2880 break;
2881
2882 /*
2883 * Special cases: For these, the error message talks
2884 * about "relation", because that's where the
2885 * ownership is attached. See also
2886 * check_object_ownership().
2887 */
2888 case OBJECT_COLUMN:
2889 case OBJECT_POLICY:
2890 case OBJECT_RULE:
2892 case OBJECT_TRIGGER:
2893 msg = gettext_noop("must be owner of relation %s");
2894 break;
2895 /* these currently aren't used */
2897 case OBJECT_AMOP:
2898 case OBJECT_AMPROC:
2899 case OBJECT_ATTRIBUTE:
2900 case OBJECT_CAST:
2901 case OBJECT_DEFAULT:
2902 case OBJECT_DEFACL:
2907 case OBJECT_ROLE:
2908 case OBJECT_TRANSFORM:
2909 case OBJECT_TSPARSER:
2910 case OBJECT_TSTEMPLATE:
2912 elog(ERROR, "unsupported object type: %d", objtype);
2913 }
2914
2915 ereport(ERROR,
2916 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2917 errmsg(msg, objectname)));
2918 break;
2919 }
2920 default:
2921 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2922 break;
2923 }
2924}
@ 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:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:149
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2331
@ OBJECT_FDW
Definition: parsenodes.h:2333
@ OBJECT_TSPARSER
Definition: parsenodes.h:2364
@ OBJECT_COLLATION
Definition: parsenodes.h:2324
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2367
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2317
@ OBJECT_OPCLASS
Definition: parsenodes.h:2341
@ OBJECT_DEFACL
Definition: parsenodes.h:2328
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2318
@ OBJECT_MATVIEW
Definition: parsenodes.h:2340
@ OBJECT_SCHEMA
Definition: parsenodes.h:2353
@ OBJECT_POLICY
Definition: parsenodes.h:2345
@ OBJECT_OPERATOR
Definition: parsenodes.h:2342
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2335
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2362
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2343
@ OBJECT_DOMAIN
Definition: parsenodes.h:2329
@ OBJECT_COLUMN
Definition: parsenodes.h:2323
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2359
@ OBJECT_ROLE
Definition: parsenodes.h:2350
@ OBJECT_ROUTINE
Definition: parsenodes.h:2351
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2339
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2348
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2346
@ OBJECT_EXTENSION
Definition: parsenodes.h:2332
@ OBJECT_INDEX
Definition: parsenodes.h:2337
@ OBJECT_DEFAULT
Definition: parsenodes.h:2327
@ OBJECT_DATABASE
Definition: parsenodes.h:2326
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2354
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2365
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2338
@ OBJECT_AMOP
Definition: parsenodes.h:2319
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2349
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2334
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2363
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2321
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2347
@ OBJECT_RULE
Definition: parsenodes.h:2352
@ OBJECT_CONVERSION
Definition: parsenodes.h:2325
@ OBJECT_AMPROC
Definition: parsenodes.h:2320
@ OBJECT_TABLE
Definition: parsenodes.h:2358
@ OBJECT_VIEW
Definition: parsenodes.h:2368
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2344
@ OBJECT_TYPE
Definition: parsenodes.h:2366
@ OBJECT_FUNCTION
Definition: parsenodes.h:2336
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2357
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2330
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2355
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2356
@ OBJECT_CAST
Definition: parsenodes.h:2322
@ OBJECT_TRIGGER
Definition: parsenodes.h:2361
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2360

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 2928 of file aclchk.c.

2930{
2931 switch (aclerr)
2932 {
2933 case ACLCHECK_OK:
2934 /* no error, so return to caller */
2935 break;
2936 case ACLCHECK_NO_PRIV:
2937 ereport(ERROR,
2938 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2939 errmsg("permission denied for column \"%s\" of relation \"%s\"",
2940 colname, objectname)));
2941 break;
2942 case ACLCHECK_NOT_OWNER:
2943 /* relation msg is OK since columns don't have separate owners */
2944 aclcheck_error(aclerr, objtype, objectname);
2945 break;
2946 default:
2947 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2948 break;
2949 }
2950}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2639

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 case OBJECT_LARGEOBJECT:
1009 all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1010 errormsg = gettext_noop("invalid privilege type %s for large object");
1011 break;
1012 default:
1013 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1014 (int) action->objtype);
1015 /* keep compiler quiet */
1016 all_privileges = ACL_NO_RIGHTS;
1017 errormsg = NULL;
1018 }
1019
1020 if (action->privileges == NIL)
1021 {
1022 iacls.all_privs = true;
1023
1024 /*
1025 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1026 * depending on the object type
1027 */
1028 iacls.privileges = ACL_NO_RIGHTS;
1029 }
1030 else
1031 {
1032 iacls.all_privs = false;
1033 iacls.privileges = ACL_NO_RIGHTS;
1034
1035 foreach(cell, action->privileges)
1036 {
1037 AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1038 AclMode priv;
1039
1040 if (privnode->cols)
1041 ereport(ERROR,
1042 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1043 errmsg("default privileges cannot be set for columns")));
1044
1045 if (privnode->priv_name == NULL) /* parser mistake? */
1046 elog(ERROR, "AccessPriv node must specify privilege");
1047 priv = string_to_privilege(privnode->priv_name);
1048
1049 if (priv & ~((AclMode) all_privileges))
1050 ereport(ERROR,
1051 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1052 errmsg(errormsg, privilege_to_string(priv))));
1053
1054 iacls.privileges |= priv;
1055 }
1056 }
1057
1058 if (rolespecs == NIL)
1059 {
1060 /* Set permissions for myself */
1061 iacls.roleid = GetUserId();
1062
1063 SetDefaultACLsInSchemas(&iacls, nspnames);
1064 }
1065 else
1066 {
1067 /* Look up the role OIDs and do permissions checks */
1068 ListCell *rolecell;
1069
1070 foreach(rolecell, rolespecs)
1071 {
1072 RoleSpec *rolespec = lfirst(rolecell);
1073
1074 iacls.roleid = get_rolespec_oid(rolespec, false);
1075
1076 if (!has_privs_of_role(GetUserId(), iacls.roleid))
1077 ereport(ERROR,
1078 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1079 errmsg("permission denied to change default privileges")));
1080
1081 SetDefaultACLsInSchemas(&iacls, nspnames);
1082 }
1083 }
1084}
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
#define ACL_ALL_RIGHTS_LARGEOBJECT
Definition: acl.h:167
static AclMode string_to_privilege(const char *privname)
Definition: aclchk.c:2551
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1092
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2592
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:81
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:2616
List * cols
Definition: parsenodes.h:2617
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_LARGEOBJECT, 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_LARGEOBJECT, 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 1624 of file aclchk.c.

1627{
1628 HeapTuple attr_tuple;
1629 Form_pg_attribute pg_attribute_tuple;
1630 Acl *old_acl;
1631 Acl *new_acl;
1632 Acl *merged_acl;
1633 Datum aclDatum;
1634 bool isNull;
1635 Oid grantorId;
1636 AclMode avail_goptions;
1637 bool need_update;
1638 HeapTuple newtuple;
1639 Datum values[Natts_pg_attribute] = {0};
1640 bool nulls[Natts_pg_attribute] = {0};
1641 bool replaces[Natts_pg_attribute] = {0};
1642 int noldmembers;
1643 int nnewmembers;
1644 Oid *oldmembers;
1645 Oid *newmembers;
1646
1647 attr_tuple = SearchSysCache2(ATTNUM,
1648 ObjectIdGetDatum(relOid),
1650 if (!HeapTupleIsValid(attr_tuple))
1651 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1652 attnum, relOid);
1653 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1654
1655 /*
1656 * Get working copy of existing ACL. If there's no ACL, substitute the
1657 * proper default.
1658 */
1659 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1660 &isNull);
1661 if (isNull)
1662 {
1663 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1664 /* There are no old member roles according to the catalogs */
1665 noldmembers = 0;
1666 oldmembers = NULL;
1667 }
1668 else
1669 {
1670 old_acl = DatumGetAclPCopy(aclDatum);
1671 /* Get the roles mentioned in the existing ACL */
1672 noldmembers = aclmembers(old_acl, &oldmembers);
1673 }
1674
1675 /*
1676 * In select_best_grantor we should consider existing table-level ACL bits
1677 * as well as the per-column ACL. Build a new ACL that is their
1678 * concatenation. (This is a bit cheap and dirty compared to merging them
1679 * properly with no duplications, but it's all we need here.)
1680 */
1681 merged_acl = aclconcat(old_rel_acl, old_acl);
1682
1683 /* Determine ID to do the grant as, and available grant options */
1684 select_best_grantor(GetUserId(), col_privileges,
1685 merged_acl, ownerId,
1686 &grantorId, &avail_goptions);
1687
1688 pfree(merged_acl);
1689
1690 /*
1691 * Restrict the privileges to what we can actually grant, and emit the
1692 * standards-mandated warning and error messages. Note: we don't track
1693 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1694 * each column; we just approximate it by whether all the possible
1695 * privileges are specified now. Since the all_privs flag only determines
1696 * whether a warning is issued, this seems close enough.
1697 */
1698 col_privileges =
1699 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1700 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1701 col_privileges,
1702 relOid, grantorId, OBJECT_COLUMN,
1703 relname, attnum,
1704 NameStr(pg_attribute_tuple->attname));
1705
1706 /*
1707 * Generate new ACL.
1708 */
1709 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1710 istmt->grant_option,
1711 istmt->behavior, istmt->grantees,
1712 col_privileges, grantorId,
1713 ownerId);
1714
1715 /*
1716 * We need the members of both old and new ACLs so we can correct the
1717 * shared dependency information.
1718 */
1719 nnewmembers = aclmembers(new_acl, &newmembers);
1720
1721 /* finished building new ACL value, now insert it */
1722
1723 /*
1724 * If the updated ACL is empty, we can set attacl to null, and maybe even
1725 * avoid an update of the pg_attribute row. This is worth testing because
1726 * we'll come through here multiple times for any relation-level REVOKE,
1727 * even if there were never any column GRANTs. Note we are assuming that
1728 * the "default" ACL state for columns is empty.
1729 */
1730 if (ACL_NUM(new_acl) > 0)
1731 {
1732 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1733 need_update = true;
1734 }
1735 else
1736 {
1737 nulls[Anum_pg_attribute_attacl - 1] = true;
1738 need_update = !isNull;
1739 }
1740 replaces[Anum_pg_attribute_attacl - 1] = true;
1741
1742 if (need_update)
1743 {
1744 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1745 values, nulls, replaces);
1746
1747 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1748
1749 /* Update initial privileges for extensions */
1750 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1751 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1752
1753 /* Update the shared dependency ACL info */
1754 updateAclDependencies(RelationRelationId, relOid, attnum,
1755 ownerId,
1756 noldmembers, oldmembers,
1757 nnewmembers, newmembers);
1758 }
1759
1760 pfree(new_acl);
1761
1762 ReleaseSysCache(attr_tuple);
1763}
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:4586
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:202
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:542
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 2100 of file aclchk.c.

2102{
2103 int cacheid;
2104 Relation relation;
2105 ListCell *cell;
2106
2107 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2108 istmt->privileges = default_privs;
2109
2110 cacheid = get_object_catcache_oid(classid);
2111
2112 relation = table_open(classid, RowExclusiveLock);
2113
2114 foreach(cell, istmt->objects)
2115 {
2116 Oid objectid = lfirst_oid(cell);
2117 Datum aclDatum;
2118 Datum nameDatum;
2119 bool isNull;
2120 AclMode avail_goptions;
2121 AclMode this_privileges;
2122 Acl *old_acl;
2123 Acl *new_acl;
2124 Oid grantorId;
2125 Oid ownerId;
2126 HeapTuple tuple;
2127 HeapTuple newtuple;
2128 Datum *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
2129 bool *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
2130 bool *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
2131 int noldmembers;
2132 int nnewmembers;
2133 Oid *oldmembers;
2134 Oid *newmembers;
2135
2136 tuple = SearchSysCacheLocked1(cacheid, ObjectIdGetDatum(objectid));
2137 if (!HeapTupleIsValid(tuple))
2138 elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
2139
2140 /*
2141 * Additional object-type-specific checks
2142 */
2143 if (object_check)
2144 object_check(istmt, tuple);
2145
2146 /*
2147 * Get owner ID and working copy of existing ACL. If there's no ACL,
2148 * substitute the proper default.
2149 */
2150 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
2151 tuple,
2152 get_object_attnum_owner(classid)));
2153 aclDatum = SysCacheGetAttr(cacheid,
2154 tuple,
2155 get_object_attnum_acl(classid),
2156 &isNull);
2157 if (isNull)
2158 {
2159 old_acl = acldefault(get_object_type(classid, objectid), ownerId);
2160 /* There are no old member roles according to the catalogs */
2161 noldmembers = 0;
2162 oldmembers = NULL;
2163 }
2164 else
2165 {
2166 old_acl = DatumGetAclPCopy(aclDatum);
2167 /* Get the roles mentioned in the existing ACL */
2168 noldmembers = aclmembers(old_acl, &oldmembers);
2169 }
2170
2171 /* Determine ID to do the grant as, and available grant options */
2173 old_acl, ownerId,
2174 &grantorId, &avail_goptions);
2175
2176 nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
2177 get_object_attnum_name(classid));
2178
2179 /*
2180 * Restrict the privileges to what we can actually grant, and emit the
2181 * standards-mandated warning and error messages.
2182 */
2183 this_privileges =
2184 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2185 istmt->all_privs, istmt->privileges,
2186 objectid, grantorId, get_object_type(classid, objectid),
2187 NameStr(*DatumGetName(nameDatum)),
2188 0, NULL);
2189
2190 /*
2191 * Generate new ACL.
2192 */
2193 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2194 istmt->grant_option, istmt->behavior,
2195 istmt->grantees, this_privileges,
2196 grantorId, ownerId);
2197
2198 /*
2199 * We need the members of both old and new ACLs so we can correct the
2200 * shared dependency information.
2201 */
2202 nnewmembers = aclmembers(new_acl, &newmembers);
2203
2204 /* finished building new ACL value, now insert it */
2205 replaces[get_object_attnum_acl(classid) - 1] = true;
2206 values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
2207
2208 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
2209 nulls, replaces);
2210
2211 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2212 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
2213
2214 /* Update initial privileges for extensions */
2215 recordExtensionInitPriv(objectid, classid, 0, new_acl);
2216
2217 /* Update the shared dependency ACL info */
2218 updateAclDependencies(classid,
2219 objectid, 0,
2220 ownerId,
2221 noldmembers, oldmembers,
2222 nnewmembers, newmembers);
2223
2224 ReleaseSysCache(tuple);
2225
2226 pfree(new_acl);
2227
2228 /* prevent error when processing duplicate objects */
2230 }
2231
2232 table_close(relation, RowExclusiveLock);
2233}
#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 2236 of file aclchk.c.

2237{
2238 Form_pg_language pg_language_tuple;
2239
2240 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2241
2242 if (!pg_language_tuple->lanpltrusted)
2243 ereport(ERROR,
2244 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2245 errmsg("language \"%s\" is not trusted",
2246 NameStr(pg_language_tuple->lanname)),
2247 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2248 "because only superusers can use untrusted languages.")));
2249}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
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 2252 of file aclchk.c.

2253{
2254 Relation relation;
2255 ListCell *cell;
2256
2257 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
2259
2260 relation = table_open(LargeObjectMetadataRelationId,
2262
2263 foreach(cell, istmt->objects)
2264 {
2265 Oid loid = lfirst_oid(cell);
2266 Form_pg_largeobject_metadata form_lo_meta;
2267 char loname[NAMEDATALEN];
2268 Datum aclDatum;
2269 bool isNull;
2270 AclMode avail_goptions;
2271 AclMode this_privileges;
2272 Acl *old_acl;
2273 Acl *new_acl;
2274 Oid grantorId;
2275 Oid ownerId;
2276 HeapTuple newtuple;
2277 Datum values[Natts_pg_largeobject_metadata] = {0};
2278 bool nulls[Natts_pg_largeobject_metadata] = {0};
2279 bool replaces[Natts_pg_largeobject_metadata] = {0};
2280 int noldmembers;
2281 int nnewmembers;
2282 Oid *oldmembers;
2283 Oid *newmembers;
2284 ScanKeyData entry[1];
2285 SysScanDesc scan;
2286 HeapTuple tuple;
2287
2288 /* There's no syscache for pg_largeobject_metadata */
2289 ScanKeyInit(&entry[0],
2290 Anum_pg_largeobject_metadata_oid,
2291 BTEqualStrategyNumber, F_OIDEQ,
2292 ObjectIdGetDatum(loid));
2293
2294 scan = systable_beginscan(relation,
2295 LargeObjectMetadataOidIndexId, true,
2296 NULL, 1, entry);
2297
2298 tuple = systable_getnext(scan);
2299 if (!HeapTupleIsValid(tuple))
2300 elog(ERROR, "could not find tuple for large object %u", loid);
2301
2302 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
2303
2304 /*
2305 * Get owner ID and working copy of existing ACL. If there's no ACL,
2306 * substitute the proper default.
2307 */
2308 ownerId = form_lo_meta->lomowner;
2309 aclDatum = heap_getattr(tuple,
2310 Anum_pg_largeobject_metadata_lomacl,
2311 RelationGetDescr(relation), &isNull);
2312 if (isNull)
2313 {
2314 old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
2315 /* There are no old member roles according to the catalogs */
2316 noldmembers = 0;
2317 oldmembers = NULL;
2318 }
2319 else
2320 {
2321 old_acl = DatumGetAclPCopy(aclDatum);
2322 /* Get the roles mentioned in the existing ACL */
2323 noldmembers = aclmembers(old_acl, &oldmembers);
2324 }
2325
2326 /* Determine ID to do the grant as, and available grant options */
2328 old_acl, ownerId,
2329 &grantorId, &avail_goptions);
2330
2331 /*
2332 * Restrict the privileges to what we can actually grant, and emit the
2333 * standards-mandated warning and error messages.
2334 */
2335 snprintf(loname, sizeof(loname), "large object %u", loid);
2336 this_privileges =
2337 restrict_and_check_grant(istmt->is_grant, avail_goptions,
2338 istmt->all_privs, istmt->privileges,
2339 loid, grantorId, OBJECT_LARGEOBJECT,
2340 loname, 0, NULL);
2341
2342 /*
2343 * Generate new ACL.
2344 */
2345 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
2346 istmt->grant_option, istmt->behavior,
2347 istmt->grantees, this_privileges,
2348 grantorId, ownerId);
2349
2350 /*
2351 * We need the members of both old and new ACLs so we can correct the
2352 * shared dependency information.
2353 */
2354 nnewmembers = aclmembers(new_acl, &newmembers);
2355
2356 /* finished building new ACL value, now insert it */
2357 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
2358 values[Anum_pg_largeobject_metadata_lomacl - 1]
2359 = PointerGetDatum(new_acl);
2360
2361 newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
2362 values, nulls, replaces);
2363
2364 CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
2365
2366 /* Update initial privileges for extensions */
2367 recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
2368
2369 /* Update the shared dependency ACL info */
2370 updateAclDependencies(LargeObjectRelationId,
2371 form_lo_meta->oid, 0,
2372 ownerId,
2373 noldmembers, oldmembers,
2374 nnewmembers, newmembers);
2375
2376 systable_endscan(scan);
2377
2378 pfree(new_acl);
2379
2380 /* prevent error when processing duplicate objects */
2382 }
2383
2384 table_close(relation, RowExclusiveLock);
2385}
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:904
#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 2408 of file aclchk.c.

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

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

2389{
2390 Form_pg_type pg_type_tuple;
2391
2392 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2393
2394 /* Disallow GRANT on dependent types */
2395 if (IsTrueArrayType(pg_type_tuple))
2396 ereport(ERROR,
2397 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2398 errmsg("cannot set privileges of array types"),
2399 errhint("Set the privileges of the element type instead.")));
2400 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2401 ereport(ERROR,
2402 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2403 errmsg("cannot set privileges of multirange types"),
2404 errhint("Set the privileges of the range type instead.")));
2405}
int errhint(const char *fmt,...)
Definition: elog.c:1318
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:2388
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2100
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2252
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2408
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1769
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2236
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:2559
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2560

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 1578 of file aclchk.c.

1582{
1583 AttrNumber curr_att;
1584
1585 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1586 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1587 curr_att <= classForm->relnatts;
1588 curr_att++)
1589 {
1590 HeapTuple attTuple;
1591 bool isdropped;
1592
1593 if (curr_att == InvalidAttrNumber)
1594 continue;
1595
1596 /* Views don't have any system columns at all */
1597 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1598 continue;
1599
1600 attTuple = SearchSysCache2(ATTNUM,
1601 ObjectIdGetDatum(table_oid),
1602 Int16GetDatum(curr_att));
1603 if (!HeapTupleIsValid(attTuple))
1604 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1605 curr_att, table_oid);
1606
1607 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1608
1609 ReleaseSysCache(attTuple);
1610
1611 /* ignore dropped columns */
1612 if (isdropped)
1613 continue;
1614
1615 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1616 }
1617}
#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 1545 of file aclchk.c.

1549{
1550 ListCell *cell;
1551
1552 foreach(cell, colnames)
1553 {
1554 char *colname = strVal(lfirst(cell));
1556
1557 attnum = get_attnum(table_oid, colname);
1559 ereport(ERROR,
1560 (errcode(ERRCODE_UNDEFINED_COLUMN),
1561 errmsg("column \"%s\" of relation \"%s\" does not exist",
1562 colname, get_rel_name(table_oid))));
1564 if (attnum <= 0 || attnum >= num_col_privileges)
1565 elog(ERROR, "column number out of range"); /* safety check */
1566 col_privileges[attnum] |= this_privileges;
1567 }
1568}
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2068
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:950
#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 4197 of file aclchk.c.

4198{
4199 Acl *result = NULL;
4200 HeapTuple tuple;
4201
4202 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4203 ObjectIdGetDatum(roleId),
4204 ObjectIdGetDatum(nsp_oid),
4205 CharGetDatum(objtype));
4206
4207 if (HeapTupleIsValid(tuple))
4208 {
4209 Datum aclDatum;
4210 bool isNull;
4211
4212 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4213 Anum_pg_default_acl_defaclacl,
4214 &isNull);
4215 if (!isNull)
4216 result = DatumGetAclPCopy(aclDatum);
4217 ReleaseSysCache(tuple);
4218 }
4219
4220 return result;
4221}
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 4232 of file aclchk.c.

4233{
4234 Acl *result;
4235 Acl *glob_acl;
4236 Acl *schema_acl;
4237 Acl *def_acl;
4238 char defaclobjtype;
4239
4240 /*
4241 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4242 * yet.
4243 */
4245 return NULL;
4246
4247 /* Check if object type is supported in pg_default_acl */
4248 switch (objtype)
4249 {
4250 case OBJECT_TABLE:
4251 defaclobjtype = DEFACLOBJ_RELATION;
4252 break;
4253
4254 case OBJECT_SEQUENCE:
4255 defaclobjtype = DEFACLOBJ_SEQUENCE;
4256 break;
4257
4258 case OBJECT_FUNCTION:
4259 defaclobjtype = DEFACLOBJ_FUNCTION;
4260 break;
4261
4262 case OBJECT_TYPE:
4263 defaclobjtype = DEFACLOBJ_TYPE;
4264 break;
4265
4266 case OBJECT_SCHEMA:
4267 defaclobjtype = DEFACLOBJ_NAMESPACE;
4268 break;
4269
4270 case OBJECT_LARGEOBJECT:
4271 defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4272 break;
4273
4274 default:
4275 return NULL;
4276 }
4277
4278 /* Look up the relevant pg_default_acl entries */
4279 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4280 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4281
4282 /* Quick out if neither entry exists */
4283 if (glob_acl == NULL && schema_acl == NULL)
4284 return NULL;
4285
4286 /* We need to know the hard-wired default value, too */
4287 def_acl = acldefault(objtype, ownerId);
4288
4289 /* If there's no global entry, substitute the hard-wired default */
4290 if (glob_acl == NULL)
4291 glob_acl = def_acl;
4292
4293 /* Merge in any per-schema privileges */
4294 result = aclmerge(glob_acl, schema_acl, ownerId);
4295
4296 /*
4297 * For efficiency, we want to return NULL if the result equals default.
4298 * This requires sorting both arrays to get an accurate comparison.
4299 */
4300 aclitemsort(result);
4301 aclitemsort(def_acl);
4302 if (aclequal(result, def_acl))
4303 result = NULL;
4304
4305 return result;
4306}
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:4197
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:476
#define InvalidOid
Definition: postgres_ext.h:35

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

Referenced by heap_create_with_catalog(), LargeObjectCreate(), 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:1314
#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:979

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 4173 of file aclchk.c.

4174{
4175 bool result = false;
4176 HeapTuple utup;
4177
4178 /* Superusers bypass all permission checking. */
4179 if (superuser_arg(roleid))
4180 return true;
4181
4182 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4183 if (HeapTupleIsValid(utup))
4184 {
4185 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4186 ReleaseSysCache(utup);
4187 }
4188 return result;
4189}
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 4154 of file aclchk.c.

4155{
4156 bool result = false;
4157 HeapTuple utup;
4158
4159 /* Superusers bypass all permission checking. */
4160 if (superuser_arg(roleid))
4161 return true;
4162
4163 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4164 if (HeapTupleIsValid(utup))
4165 {
4166 result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4167 ReleaseSysCache(utup);
4168 }
4169 return result;
4170}
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:78
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 3821 of file aclchk.c.

3822{
3823 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3824}
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3831
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 3031 of file aclchk.c.

3033{
3034 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3035}

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 3042 of file aclchk.c.

3045{
3046 int cacheid;
3047 AclMode result;
3048 HeapTuple tuple;
3049 Datum aclDatum;
3050 bool isNull;
3051 Acl *acl;
3052 Oid ownerId;
3053
3054 /* Special cases */
3055 switch (classid)
3056 {
3057 case NamespaceRelationId:
3058 return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
3059 is_missing);
3060 case TypeRelationId:
3061 return pg_type_aclmask_ext(objectid, roleid, mask, how,
3062 is_missing);
3063 }
3064
3065 /* Even more special cases */
3066 Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3067 Assert(classid != LargeObjectMetadataRelationId); /* should use
3068 * pg_largeobject_acl* */
3069
3070 /* Superusers bypass all permission checking. */
3071 if (superuser_arg(roleid))
3072 return mask;
3073
3074 /*
3075 * Get the object's ACL from its catalog
3076 */
3077
3078 cacheid = get_object_catcache_oid(classid);
3079
3080 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3081 if (!HeapTupleIsValid(tuple))
3082 {
3083 if (is_missing != NULL)
3084 {
3085 /* return "no privileges" instead of throwing an error */
3086 *is_missing = true;
3087 return 0;
3088 }
3089 else
3090 elog(ERROR, "cache lookup failed for %s %u",
3091 get_object_class_descr(classid), objectid);
3092 }
3093
3094 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3095 tuple,
3096 get_object_attnum_owner(classid)));
3097
3098 aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3099 &isNull);
3100 if (isNull)
3101 {
3102 /* No ACL, so build default ACL */
3103 acl = acldefault(get_object_type(classid, objectid), ownerId);
3104 aclDatum = (Datum) 0;
3105 }
3106 else
3107 {
3108 /* detoast ACL if necessary */
3109 acl = DatumGetAclP(aclDatum);
3110 }
3111
3112 result = aclmask(acl, roleid, ownerId, mask, how);
3113
3114 /* if we have a detoasted copy, free it */
3115 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3116 pfree(acl);
3117
3118 ReleaseSysCache(tuple);
3119
3120 return result;
3121}
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:3593
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3695
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 4075 of file aclchk.c.

4076{
4077 int cacheid;
4078 Oid ownerId;
4079
4080 /* Superusers bypass all permission checking. */
4081 if (superuser_arg(roleid))
4082 return true;
4083
4084 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4085 if (classid == LargeObjectRelationId)
4086 classid = LargeObjectMetadataRelationId;
4087
4088 cacheid = get_object_catcache_oid(classid);
4089 if (cacheid != -1)
4090 {
4091 /* we can get the object's tuple from the syscache */
4092 HeapTuple tuple;
4093
4094 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4095 if (!HeapTupleIsValid(tuple))
4096 elog(ERROR, "cache lookup failed for %s %u",
4097 get_object_class_descr(classid), objectid);
4098
4099 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4100 tuple,
4101 get_object_attnum_owner(classid)));
4102 ReleaseSysCache(tuple);
4103 }
4104 else
4105 {
4106 /* for catalogs without an appropriate syscache */
4107 Relation rel;
4108 ScanKeyData entry[1];
4109 SysScanDesc scan;
4110 HeapTuple tuple;
4111 bool isnull;
4112
4113 rel = table_open(classid, AccessShareLock);
4114
4115 ScanKeyInit(&entry[0],
4116 get_object_attnum_oid(classid),
4117 BTEqualStrategyNumber, F_OIDEQ,
4118 ObjectIdGetDatum(objectid));
4119
4120 scan = systable_beginscan(rel,
4121 get_object_oid_index(classid), true,
4122 NULL, 1, entry);
4123
4124 tuple = systable_getnext(scan);
4125 if (!HeapTupleIsValid(tuple))
4126 elog(ERROR, "could not find tuple for %s %u",
4127 get_object_class_descr(classid), objectid);
4128
4129 ownerId = DatumGetObjectId(heap_getattr(tuple,
4130 get_object_attnum_owner(classid),
4131 RelationGetDescr(rel),
4132 &isnull));
4133 Assert(!isnull);
4134
4135 systable_endscan(scan);
4137 }
4138
4139 return has_privs_of_role(roleid, ownerId);
4140}
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:135

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 2970 of file aclchk.c.

2972{
2973 switch (objtype)
2974 {
2975 case OBJECT_COLUMN:
2976 return
2977 pg_class_aclmask(object_oid, roleid, mask, how) |
2978 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2979 case OBJECT_TABLE:
2980 case OBJECT_SEQUENCE:
2981 return pg_class_aclmask(object_oid, roleid, mask, how);
2982 case OBJECT_DATABASE:
2983 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2984 case OBJECT_FUNCTION:
2985 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
2986 case OBJECT_LANGUAGE:
2987 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
2988 case OBJECT_LARGEOBJECT:
2989 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
2990 mask, how, NULL);
2992 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
2993 case OBJECT_SCHEMA:
2994 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
2996 elog(ERROR, "grantable rights not supported for statistics objects");
2997 /* not reached, but keep compiler quiet */
2998 return ACL_NO_RIGHTS;
2999 case OBJECT_TABLESPACE:
3000 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3001 case OBJECT_FDW:
3002 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3004 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3006 elog(ERROR, "grantable rights not supported for event triggers");
3007 /* not reached, but keep compiler quiet */
3008 return ACL_NO_RIGHTS;
3009 case OBJECT_TYPE:
3010 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3011 default:
3012 elog(ERROR, "unrecognized object type: %d",
3013 (int) objtype);
3014 /* not reached, but keep compiler quiet */
3015 return ACL_NO_RIGHTS;
3016 }
3017}
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3520
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3132
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3461
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3031
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3257

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 3853 of file aclchk.c.

3855{
3856 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3857}
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3865

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 3895 of file aclchk.c.

3897{
3898 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3899}
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3906

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 3906 of file aclchk.c.

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

3867{
3868 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3869 ACLMASK_ANY, is_missing) != 0)
3870 return ACLCHECK_OK;
3871 else
3872 return ACLCHECK_NO_PRIV;
3873}
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3143

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 3132 of file aclchk.c.

3134{
3135 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3136 mask, how, NULL);
3137}

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 3143 of file aclchk.c.

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

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 4034 of file aclchk.c.

4036{
4037 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4038 ACLMASK_ANY, is_missing) != 0)
4039 return ACLCHECK_OK;
4040 else
4041 return ACLCHECK_NO_PRIV;
4042}
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3267

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 3257 of file aclchk.c.

3259{
3260 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3261}

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 3267 of file aclchk.c.

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

4063{
4064 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4065 ACLMASK_ANY, snapshot) != 0)
4066 return ACLCHECK_OK;
4067 else
4068 return ACLCHECK_NO_PRIV;
4069}

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 3520 of file aclchk.c.

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

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 3593 of file aclchk.c.

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

3462{
3463 AclMode result;
3464 HeapTuple tuple;
3465 Datum aclDatum;
3466 bool isNull;
3467 Acl *acl;
3468
3469 /* Superusers bypass all permission checking. */
3470 if (superuser_arg(roleid))
3471 return mask;
3472
3473 /* Get the ACL from pg_parameter_acl */
3474 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3475 if (!HeapTupleIsValid(tuple))
3476 ereport(ERROR,
3477 (errcode(ERRCODE_UNDEFINED_OBJECT),
3478 errmsg("parameter ACL with OID %u does not exist",
3479 acl_oid)));
3480
3481 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3482 Anum_pg_parameter_acl_paracl,
3483 &isNull);
3484 if (isNull)
3485 {
3486 /* No ACL, so build default ACL */
3487 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3488 aclDatum = (Datum) 0;
3489 }
3490 else
3491 {
3492 /* detoast ACL if necessary */
3493 acl = DatumGetAclP(aclDatum);
3494 }
3495
3496 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3497
3498 /* if we have a detoasted copy, free it */
3499 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3500 pfree(acl);
3501
3502 ReleaseSysCache(tuple);
3503
3504 return result;
3505}

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 4049 of file aclchk.c.

4050{
4051 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4052 return ACLCHECK_OK;
4053 else
4054 return ACLCHECK_NO_PRIV;
4055}
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3397
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 3397 of file aclchk.c.

3398{
3399 AclMode result;
3400 char *parname;
3401 text *partext;
3402 HeapTuple tuple;
3403
3404 /* Superusers bypass all permission checking. */
3405 if (superuser_arg(roleid))
3406 return mask;
3407
3408 /* Convert name to the form it should have in pg_parameter_acl... */
3410 partext = cstring_to_text(parname);
3411
3412 /* ... and look it up */
3413 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3414
3415 if (!HeapTupleIsValid(tuple))
3416 {
3417 /* If no entry, GUC has no permissions for non-superusers */
3418 result = ACL_NO_RIGHTS;
3419 }
3420 else
3421 {
3422 Datum aclDatum;
3423 bool isNull;
3424 Acl *acl;
3425
3426 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3427 Anum_pg_parameter_acl_paracl,
3428 &isNull);
3429 if (isNull)
3430 {
3431 /* No ACL, so build default ACL */
3432 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3433 aclDatum = (Datum) 0;
3434 }
3435 else
3436 {
3437 /* detoast ACL if necessary */
3438 acl = DatumGetAclP(aclDatum);
3439 }
3440
3441 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3442
3443 /* if we have a detoasted copy, free it */
3444 if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3445 pfree(acl);
3446
3447 ReleaseSysCache(tuple);
3448 }
3449
3450 pfree(parname);
3451 pfree(partext);
3452
3453 return result;
3454}
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 3695 of file aclchk.c.

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

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 2592 of file aclchk.c.

2593{
2594 switch (privilege)
2595 {
2596 case ACL_INSERT:
2597 return "INSERT";
2598 case ACL_SELECT:
2599 return "SELECT";
2600 case ACL_UPDATE:
2601 return "UPDATE";
2602 case ACL_DELETE:
2603 return "DELETE";
2604 case ACL_TRUNCATE:
2605 return "TRUNCATE";
2606 case ACL_REFERENCES:
2607 return "REFERENCES";
2608 case ACL_TRIGGER:
2609 return "TRIGGER";
2610 case ACL_EXECUTE:
2611 return "EXECUTE";
2612 case ACL_USAGE:
2613 return "USAGE";
2614 case ACL_CREATE:
2615 return "CREATE";
2616 case ACL_CREATE_TEMP:
2617 return "TEMP";
2618 case ACL_CONNECT:
2619 return "CONNECT";
2620 case ACL_SET:
2621 return "SET";
2622 case ACL_ALTER_SYSTEM:
2623 return "ALTER SYSTEM";
2624 case ACL_MAINTAIN:
2625 return "MAINTAIN";
2626 default:
2627 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2628 }
2629 return NULL; /* appease compiler */
2630}
#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 4312 of file aclchk.c.

4314{
4315 int nmembers;
4316 Oid *members;
4317
4318 /* Nothing to do if ACL is defaulted */
4319 if (acl == NULL)
4320 return;
4321
4322 /* Extract roles mentioned in ACL */
4323 nmembers = aclmembers(acl, &members);
4324
4325 /* Update the shared dependency ACL info */
4326 updateAclDependencies(classId, objectId, objsubId,
4327 ownerId,
4328 0, NULL,
4329 nmembers, members);
4330}

References aclmembers(), and updateAclDependencies().

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

◆ recordExtensionInitPriv()

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

Definition at line 4586 of file aclchk.c.

4587{
4588 /*
4589 * Generally, we only record the initial privileges when an extension is
4590 * being created, but because we don't actually use CREATE EXTENSION
4591 * during binary upgrades with pg_upgrade, there is a variable to let us
4592 * know that the GRANT and REVOKE statements being issued, while this
4593 * variable is true, are for the initial privileges of the extension
4594 * object and therefore we need to record them.
4595 */
4597 return;
4598
4599 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4600}
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4615
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 4615 of file aclchk.c.

4617{
4618 Relation relation;
4619 ScanKeyData key[3];
4620 SysScanDesc scan;
4621 HeapTuple tuple;
4622 HeapTuple oldtuple;
4623 int noldmembers;
4624 int nnewmembers;
4625 Oid *oldmembers;
4626 Oid *newmembers;
4627
4628 /* We'll need the role membership of the new ACL. */
4629 nnewmembers = aclmembers(new_acl, &newmembers);
4630
4631 /* Search pg_init_privs for an existing entry. */
4632 relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4633
4634 ScanKeyInit(&key[0],
4635 Anum_pg_init_privs_objoid,
4636 BTEqualStrategyNumber, F_OIDEQ,
4637 ObjectIdGetDatum(objoid));
4638 ScanKeyInit(&key[1],
4639 Anum_pg_init_privs_classoid,
4640 BTEqualStrategyNumber, F_OIDEQ,
4641 ObjectIdGetDatum(classoid));
4642 ScanKeyInit(&key[2],
4643 Anum_pg_init_privs_objsubid,
4644 BTEqualStrategyNumber, F_INT4EQ,
4645 Int32GetDatum(objsubid));
4646
4647 scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4648 NULL, 3, key);
4649
4650 /* There should exist only one entry or none. */
4651 oldtuple = systable_getnext(scan);
4652
4653 /* If we find an entry, update it with the latest ACL. */
4654 if (HeapTupleIsValid(oldtuple))
4655 {
4656 Datum values[Natts_pg_init_privs] = {0};
4657 bool nulls[Natts_pg_init_privs] = {0};
4658 bool replace[Natts_pg_init_privs] = {0};
4659 Datum oldAclDatum;
4660 bool isNull;
4661 Acl *old_acl;
4662
4663 /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
4664 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4665 RelationGetDescr(relation), &isNull);
4666 Assert(!isNull);
4667 old_acl = DatumGetAclP(oldAclDatum);
4668 noldmembers = aclmembers(old_acl, &oldmembers);
4669
4670 updateInitAclDependencies(classoid, objoid, objsubid,
4671 noldmembers, oldmembers,
4672 nnewmembers, newmembers);
4673
4674 /* If we have a new ACL to set, then update the row with it. */
4675 if (new_acl && ACL_NUM(new_acl) != 0)
4676 {
4677 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4678 replace[Anum_pg_init_privs_initprivs - 1] = true;
4679
4680 oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4681 values, nulls, replace);
4682
4683 CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4684 }
4685 else
4686 {
4687 /* new_acl is NULL/empty, so delete the entry we found. */
4688 CatalogTupleDelete(relation, &oldtuple->t_self);
4689 }
4690 }
4691 else
4692 {
4693 Datum values[Natts_pg_init_privs] = {0};
4694 bool nulls[Natts_pg_init_privs] = {0};
4695
4696 /*
4697 * Only add a new entry if the new ACL is non-NULL.
4698 *
4699 * If we are passed in a NULL ACL and no entry exists, we can just
4700 * fall through and do nothing.
4701 */
4702 if (new_acl && ACL_NUM(new_acl) != 0)
4703 {
4704 /* No entry found, so add it. */
4705 values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4706 values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4707 values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4708
4709 /* This function only handles initial privileges of extensions */
4710 values[Anum_pg_init_privs_privtype - 1] =
4712
4713 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4714
4715 tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4716
4717 CatalogTupleInsert(relation, tuple);
4718
4719 /* Update pg_shdepend, too. */
4720 noldmembers = 0;
4721 oldmembers = NULL;
4722
4723 updateInitAclDependencies(classoid, objoid, objsubid,
4724 noldmembers, oldmembers,
4725 nnewmembers, newmembers);
4726 }
4727 }
4728
4729 systable_endscan(scan);
4730
4731 /* prevent error when processing objects multiple times */
4733
4734 table_close(relation, RowExclusiveLock);
4735}
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 4339 of file aclchk.c.

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

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 4503 of file aclchk.c.

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

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 4852 of file aclchk.c.

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

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

4745{
4746 Relation rel;
4747 ScanKeyData key[3];
4748 SysScanDesc scan;
4749 HeapTuple oldtuple;
4750 Datum oldAclDatum;
4751 bool isNull;
4752 Acl *old_acl;
4753 Acl *new_acl;
4754 HeapTuple newtuple;
4755 int noldmembers;
4756 int nnewmembers;
4757 Oid *oldmembers;
4758 Oid *newmembers;
4759
4760 /* Search for existing pg_init_privs entry for the target object. */
4761 rel = table_open(InitPrivsRelationId, RowExclusiveLock);
4762
4763 ScanKeyInit(&key[0],
4764 Anum_pg_init_privs_objoid,
4765 BTEqualStrategyNumber, F_OIDEQ,
4766 ObjectIdGetDatum(objid));
4767 ScanKeyInit(&key[1],
4768 Anum_pg_init_privs_classoid,
4769 BTEqualStrategyNumber, F_OIDEQ,
4770 ObjectIdGetDatum(classid));
4771 ScanKeyInit(&key[2],
4772 Anum_pg_init_privs_objsubid,
4773 BTEqualStrategyNumber, F_INT4EQ,
4774 Int32GetDatum(objsubid));
4775
4776 scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
4777 NULL, 3, key);
4778
4779 /* There should exist only one entry or none. */
4780 oldtuple = systable_getnext(scan);
4781
4782 if (!HeapTupleIsValid(oldtuple))
4783 {
4784 /*
4785 * Hmm, why are we here if there's no entry? But pack up and go away
4786 * quietly.
4787 */
4788 systable_endscan(scan);
4790 return;
4791 }
4792
4793 /* Get a writable copy of the existing ACL. */
4794 oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
4795 RelationGetDescr(rel), &isNull);
4796 Assert(!isNull);
4797 old_acl = DatumGetAclPCopy(oldAclDatum);
4798
4799 /*
4800 * Generate new ACL. This usage of aclnewowner is a bit off-label when
4801 * oldroleid isn't the owner; but it does the job fine.
4802 */
4803 new_acl = aclnewowner(old_acl, oldroleid, newroleid);
4804
4805 /*
4806 * If we end with an empty ACL, delete the pg_init_privs entry. (That
4807 * probably can't happen here, but we may as well cover the case.)
4808 */
4809 if (new_acl == NULL || ACL_NUM(new_acl) == 0)
4810 {
4811 CatalogTupleDelete(rel, &oldtuple->t_self);
4812 }
4813 else
4814 {
4815 Datum values[Natts_pg_init_privs] = {0};
4816 bool nulls[Natts_pg_init_privs] = {0};
4817 bool replaces[Natts_pg_init_privs] = {0};
4818
4819 /* Update existing entry. */
4820 values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4821 replaces[Anum_pg_init_privs_initprivs - 1] = true;
4822
4823 newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
4824 values, nulls, replaces);
4825 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
4826 }
4827
4828 /*
4829 * Update the shared dependency ACL info.
4830 */
4831 noldmembers = aclmembers(old_acl, &oldmembers);
4832 nnewmembers = aclmembers(new_acl, &newmembers);
4833
4834 updateInitAclDependencies(classid, objid, objsubid,
4835 noldmembers, oldmembers,
4836 nnewmembers, newmembers);
4837
4838 systable_endscan(scan);
4839
4840 /* prevent error when processing objects multiple times */
4842
4844}
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:2928
static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:2970

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 1134 of file aclchk.c.

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

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

2552{
2553 if (strcmp(privname, "insert") == 0)
2554 return ACL_INSERT;
2555 if (strcmp(privname, "select") == 0)
2556 return ACL_SELECT;
2557 if (strcmp(privname, "update") == 0)
2558 return ACL_UPDATE;
2559 if (strcmp(privname, "delete") == 0)
2560 return ACL_DELETE;
2561 if (strcmp(privname, "truncate") == 0)
2562 return ACL_TRUNCATE;
2563 if (strcmp(privname, "references") == 0)
2564 return ACL_REFERENCES;
2565 if (strcmp(privname, "trigger") == 0)
2566 return ACL_TRIGGER;
2567 if (strcmp(privname, "execute") == 0)
2568 return ACL_EXECUTE;
2569 if (strcmp(privname, "usage") == 0)
2570 return ACL_USAGE;
2571 if (strcmp(privname, "create") == 0)
2572 return ACL_CREATE;
2573 if (strcmp(privname, "temporary") == 0)
2574 return ACL_CREATE_TEMP;
2575 if (strcmp(privname, "temp") == 0)
2576 return ACL_CREATE_TEMP;
2577 if (strcmp(privname, "connect") == 0)
2578 return ACL_CONNECT;
2579 if (strcmp(privname, "set") == 0)
2580 return ACL_SET;
2581 if (strcmp(privname, "alter system") == 0)
2582 return ACL_ALTER_SYSTEM;
2583 if (strcmp(privname, "maintain") == 0)
2584 return ACL_MAINTAIN;
2585 ereport(ERROR,
2586 (errcode(ERRCODE_SYNTAX_ERROR),
2587 errmsg("unrecognized privilege type \"%s\"", privname)));
2588 return 0; /* appease compiler */
2589}

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().