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

Go to the source code of this file.

Data Structures

struct  InternalDefaultACL
 

Functions

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

Variables

bool binary_upgrade_record_init_privs = false
 

Function Documentation

◆ aclcheck_error()

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

Definition at line 2654 of file aclchk.c.

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

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(), 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(), RangeVarCallbackForDblink(), RangeVarCallbackForDropRelation(), RangeVarCallbackForLockTable(), RangeVarCallbackForPolicy(), RangeVarCallbackForReindexIndex(), RangeVarCallbackForRenameRule(), RangeVarCallbackForRenameTrigger(), RangeVarCallbackForStats(), RangeVarCallbackMaintainsTable(), RangeVarCallbackOwnsRelation(), RangeVarGetAndCheckCreationNamespace(), ReindexMultipleInternal(), ReindexMultipleTables(), renameatt_check(), RenameDatabase(), RenameSchema(), RenameTableSpace(), restrict_and_check_grant(), subquery_planner(), 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 2943 of file aclchk.c.

2945{
2946 switch (aclerr)
2947 {
2948 case ACLCHECK_OK:
2949 /* no error, so return to caller */
2950 break;
2951 case ACLCHECK_NO_PRIV:
2952 ereport(ERROR,
2953 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2954 errmsg("permission denied for column \"%s\" of relation \"%s\"",
2955 colname, objectname)));
2956 break;
2957 case ACLCHECK_NOT_OWNER:
2958 /* relation msg is OK since columns don't have separate owners */
2959 aclcheck_error(aclerr, objtype, objectname);
2960 break;
2961 default:
2962 elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2963 break;
2964 }
2965}
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2654

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

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

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

1642{
1643 HeapTuple attr_tuple;
1644 Form_pg_attribute pg_attribute_tuple;
1645 Acl *old_acl;
1646 Acl *new_acl;
1647 Acl *merged_acl;
1648 Datum aclDatum;
1649 bool isNull;
1650 Oid grantorId;
1651 AclMode avail_goptions;
1652 bool need_update;
1653 HeapTuple newtuple;
1654 Datum values[Natts_pg_attribute] = {0};
1655 bool nulls[Natts_pg_attribute] = {0};
1656 bool replaces[Natts_pg_attribute] = {0};
1657 int noldmembers;
1658 int nnewmembers;
1659 Oid *oldmembers;
1660 Oid *newmembers;
1661
1662 attr_tuple = SearchSysCache2(ATTNUM,
1663 ObjectIdGetDatum(relOid),
1665 if (!HeapTupleIsValid(attr_tuple))
1666 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1667 attnum, relOid);
1668 pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
1669
1670 /*
1671 * Get working copy of existing ACL. If there's no ACL, substitute the
1672 * proper default.
1673 */
1674 aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
1675 &isNull);
1676 if (isNull)
1677 {
1678 old_acl = acldefault(OBJECT_COLUMN, ownerId);
1679 /* There are no old member roles according to the catalogs */
1680 noldmembers = 0;
1681 oldmembers = NULL;
1682 }
1683 else
1684 {
1685 old_acl = DatumGetAclPCopy(aclDatum);
1686 /* Get the roles mentioned in the existing ACL */
1687 noldmembers = aclmembers(old_acl, &oldmembers);
1688 }
1689
1690 /*
1691 * In select_best_grantor we should consider existing table-level ACL bits
1692 * as well as the per-column ACL. Build a new ACL that is their
1693 * concatenation. (This is a bit cheap and dirty compared to merging them
1694 * properly with no duplications, but it's all we need here.)
1695 */
1696 merged_acl = aclconcat(old_rel_acl, old_acl);
1697
1698 /* Determine ID to do the grant as, and available grant options */
1699 select_best_grantor(GetUserId(), col_privileges,
1700 merged_acl, ownerId,
1701 &grantorId, &avail_goptions);
1702
1703 pfree(merged_acl);
1704
1705 /*
1706 * Restrict the privileges to what we can actually grant, and emit the
1707 * standards-mandated warning and error messages. Note: we don't track
1708 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1709 * each column; we just approximate it by whether all the possible
1710 * privileges are specified now. Since the all_privs flag only determines
1711 * whether a warning is issued, this seems close enough.
1712 */
1713 col_privileges =
1714 restrict_and_check_grant(istmt->is_grant, avail_goptions,
1715 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
1716 col_privileges,
1717 relOid, grantorId, OBJECT_COLUMN,
1718 relname, attnum,
1719 NameStr(pg_attribute_tuple->attname));
1720
1721 /*
1722 * Generate new ACL.
1723 */
1724 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1725 istmt->grant_option,
1726 istmt->behavior, istmt->grantees,
1727 col_privileges, grantorId,
1728 ownerId);
1729
1730 /*
1731 * We need the members of both old and new ACLs so we can correct the
1732 * shared dependency information.
1733 */
1734 nnewmembers = aclmembers(new_acl, &newmembers);
1735
1736 /* finished building new ACL value, now insert it */
1737
1738 /*
1739 * If the updated ACL is empty, we can set attacl to null, and maybe even
1740 * avoid an update of the pg_attribute row. This is worth testing because
1741 * we'll come through here multiple times for any relation-level REVOKE,
1742 * even if there were never any column GRANTs. Note we are assuming that
1743 * the "default" ACL state for columns is empty.
1744 */
1745 if (ACL_NUM(new_acl) > 0)
1746 {
1747 values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
1748 need_update = true;
1749 }
1750 else
1751 {
1752 nulls[Anum_pg_attribute_attacl - 1] = true;
1753 need_update = !isNull;
1754 }
1755 replaces[Anum_pg_attribute_attacl - 1] = true;
1756
1757 if (need_update)
1758 {
1759 newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
1760 values, nulls, replaces);
1761
1762 CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
1763
1764 /* Update initial privileges for extensions */
1765 recordExtensionInitPriv(relOid, RelationRelationId, attnum,
1766 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
1767
1768 /* Update the shared dependency ACL info */
1769 updateAclDependencies(RelationRelationId, relOid, attnum,
1770 ownerId,
1771 noldmembers, oldmembers,
1772 nnewmembers, newmembers);
1773 }
1774
1775 pfree(new_acl);
1776
1777 ReleaseSysCache(attr_tuple);
1778}
Acl * aclconcat(const Acl *left_acl, const Acl *right_acl)
Definition: acl.c:477
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:803
void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, Oid *grantorId, AclMode *grantOptions)
Definition: acl.c:5476
int aclmembers(const Acl *acl, Oid **roleids)
Definition: acl.c:1540
#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:4601
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:181
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:240
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define NameStr(name)
Definition: c.h:765
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, const ItemPointerData *otid, HeapTuple tup)
Definition: indexing.c:313
void pfree(void *pointer)
Definition: mcxt.c:1594
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:332
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:182
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
#define RelationGetDescr(relation)
Definition: rel.h:541
ItemPointerData t_self
Definition: htup.h:65
DropBehavior behavior
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:230

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

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

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

2252{
2253 Form_pg_language pg_language_tuple;
2254
2255 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2256
2257 if (!pg_language_tuple->lanpltrusted)
2258 ereport(ERROR,
2259 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2260 errmsg("language \"%s\" is not trusted",
2261 NameStr(pg_language_tuple->lanname)),
2262 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2263 "because only superusers can use untrusted languages.")));
2264}
int errdetail(const char *fmt,...)
Definition: elog.c:1216
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 2267 of file aclchk.c.

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

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

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

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

2404{
2405 Form_pg_type pg_type_tuple;
2406
2407 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2408
2409 /* Disallow GRANT on dependent types */
2410 if (IsTrueArrayType(pg_type_tuple))
2411 ereport(ERROR,
2412 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2413 errmsg("cannot set privileges of array types"),
2414 errhint("Set the privileges of the element type instead.")));
2415 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2416 ereport(ERROR,
2417 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2418 errmsg("cannot set privileges of multirange types"),
2419 errhint("Set the privileges of the range type instead.")));
2420}
int errhint(const char *fmt,...)
Definition: elog.c:1330
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 601 of file aclchk.c.

602{
603 switch (istmt->objtype)
604 {
605 case OBJECT_TABLE:
606 case OBJECT_SEQUENCE:
607 ExecGrant_Relation(istmt);
608 break;
609 case OBJECT_DATABASE:
610 ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
611 break;
612 case OBJECT_DOMAIN:
613 case OBJECT_TYPE:
615 break;
616 case OBJECT_FDW:
617 ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
618 break;
620 ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
621 break;
622 case OBJECT_FUNCTION:
623 case OBJECT_PROCEDURE:
624 case OBJECT_ROUTINE:
625 ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
626 break;
627 case OBJECT_LANGUAGE:
629 break;
632 break;
633 case OBJECT_SCHEMA:
634 ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
635 break;
637 ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
638 break;
640 ExecGrant_Parameter(istmt);
641 break;
642 default:
643 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
644 (int) istmt->objtype);
645 }
646
647 /*
648 * Pass the info to event triggers about the just-executed GRANT. Note
649 * that we prefer to do it after actually executing it, because that gives
650 * the functions a chance to adjust the istmt with privileges actually
651 * granted.
652 */
655}
#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:2403
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2115
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2267
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2423
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1784
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2251
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 391 of file aclchk.c.

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

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

1597{
1598 AttrNumber curr_att;
1599
1600 Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1601 for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1602 curr_att <= classForm->relnatts;
1603 curr_att++)
1604 {
1605 HeapTuple attTuple;
1606 bool isdropped;
1607
1608 if (curr_att == InvalidAttrNumber)
1609 continue;
1610
1611 /* Views don't have any system columns at all */
1612 if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1613 continue;
1614
1615 attTuple = SearchSysCache2(ATTNUM,
1616 ObjectIdGetDatum(table_oid),
1617 Int16GetDatum(curr_att));
1618 if (!HeapTupleIsValid(attTuple))
1619 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1620 curr_att, table_oid);
1621
1622 isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1623
1624 ReleaseSysCache(attTuple);
1625
1626 /* ignore dropped columns */
1627 if (isdropped)
1628 continue;
1629
1630 col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1631 }
1632}
#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 1560 of file aclchk.c.

1564{
1565 ListCell *cell;
1566
1567 foreach(cell, colnames)
1568 {
1569 char *colname = strVal(lfirst(cell));
1571
1572 attnum = get_attnum(table_oid, colname);
1574 ereport(ERROR,
1575 (errcode(ERRCODE_UNDEFINED_COLUMN),
1576 errmsg("column \"%s\" of relation \"%s\" does not exist",
1577 colname, get_rel_name(table_oid))));
1579 if (attnum <= 0 || attnum >= num_col_privileges)
1580 elog(ERROR, "column number out of range"); /* safety check */
1581 col_privileges[attnum] |= this_privileges;
1582 }
1583}
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2093
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:949
#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 4212 of file aclchk.c.

4213{
4214 Acl *result = NULL;
4215 HeapTuple tuple;
4216
4217 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4218 ObjectIdGetDatum(roleId),
4219 ObjectIdGetDatum(nsp_oid),
4220 CharGetDatum(objtype));
4221
4222 if (HeapTupleIsValid(tuple))
4223 {
4224 Datum aclDatum;
4225 bool isNull;
4226
4227 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4228 Anum_pg_default_acl_defaclacl,
4229 &isNull);
4230 if (!isNull)
4231 result = DatumGetAclPCopy(aclDatum);
4232 ReleaseSysCache(tuple);
4233 }
4234
4235 return result;
4236}
static Datum CharGetDatum(char X)
Definition: postgres.h:132
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:240

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

4248{
4249 Acl *result;
4250 Acl *glob_acl;
4251 Acl *schema_acl;
4252 Acl *def_acl;
4253 char defaclobjtype;
4254
4255 /*
4256 * Use NULL during bootstrap, since pg_default_acl probably isn't there
4257 * yet.
4258 */
4260 return NULL;
4261
4262 /* Check if object type is supported in pg_default_acl */
4263 switch (objtype)
4264 {
4265 case OBJECT_TABLE:
4266 defaclobjtype = DEFACLOBJ_RELATION;
4267 break;
4268
4269 case OBJECT_SEQUENCE:
4270 defaclobjtype = DEFACLOBJ_SEQUENCE;
4271 break;
4272
4273 case OBJECT_FUNCTION:
4274 defaclobjtype = DEFACLOBJ_FUNCTION;
4275 break;
4276
4277 case OBJECT_TYPE:
4278 defaclobjtype = DEFACLOBJ_TYPE;
4279 break;
4280
4281 case OBJECT_SCHEMA:
4282 defaclobjtype = DEFACLOBJ_NAMESPACE;
4283 break;
4284
4285 case OBJECT_LARGEOBJECT:
4286 defaclobjtype = DEFACLOBJ_LARGEOBJECT;
4287 break;
4288
4289 default:
4290 return NULL;
4291 }
4292
4293 /* Look up the relevant pg_default_acl entries */
4294 glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4295 schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4296
4297 /* Quick out if neither entry exists */
4298 if (glob_acl == NULL && schema_acl == NULL)
4299 return NULL;
4300
4301 /* We need to know the hard-wired default value, too */
4302 def_acl = acldefault(objtype, ownerId);
4303
4304 /* If there's no global entry, substitute the hard-wired default */
4305 if (glob_acl == NULL)
4306 glob_acl = def_acl;
4307
4308 /* Merge in any per-schema privileges */
4309 result = aclmerge(glob_acl, schema_acl, ownerId);
4310
4311 /*
4312 * For efficiency, we want to return NULL if the result equals default.
4313 * This requires sorting both arrays to get an accurate comparison.
4314 */
4315 aclitemsort(result);
4316 aclitemsort(def_acl);
4317 if (aclequal(result, def_acl))
4318 result = NULL;
4319
4320 return result;
4321}
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:501
void aclitemsort(Acl *acl)
Definition: acl.c:545
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4212
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:477
#define InvalidOid
Definition: postgres_ext.h:37

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

879{
880 List *relations = NIL;
881 ScanKeyData key[2];
882 Relation rel;
883 TableScanDesc scan;
884 HeapTuple tuple;
885
886 ScanKeyInit(&key[0],
887 Anum_pg_class_relnamespace,
888 BTEqualStrategyNumber, F_OIDEQ,
889 ObjectIdGetDatum(namespaceId));
890 ScanKeyInit(&key[1],
891 Anum_pg_class_relkind,
892 BTEqualStrategyNumber, F_CHAREQ,
893 CharGetDatum(relkind));
894
895 rel = table_open(RelationRelationId, AccessShareLock);
896 scan = table_beginscan_catalog(rel, 2, key);
897
898 while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
899 {
900 Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
901
902 relations = lappend_oid(relations, oid);
903 }
904
905 table_endscan(scan);
907
908 return relations;
909}
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1361
#define AccessShareLock
Definition: lockdefs.h:36
@ ForwardScanDirection
Definition: sdir.h:28
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition: tableam.c:113
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:985

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

4189{
4190 bool result = false;
4191 HeapTuple utup;
4192
4193 /* Superusers bypass all permission checking. */
4194 if (superuser_arg(roleid))
4195 return true;
4196
4197 utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4198 if (HeapTupleIsValid(utup))
4199 {
4200 result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4201 ReleaseSysCache(utup);
4202 }
4203 return result;
4204}
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 4169 of file aclchk.c.

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

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

3837{
3838 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3839}
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3846
static PgChecksumMode mode
Definition: pg_checksums.c:56

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(), CreateStatistics(), 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_function_in_from(), 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 3046 of file aclchk.c.

3048{
3049 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3050}

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

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

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

4091{
4092 int cacheid;
4093 Oid ownerId;
4094
4095 /* Superusers bypass all permission checking. */
4096 if (superuser_arg(roleid))
4097 return true;
4098
4099 /* For large objects, the catalog to consult is pg_largeobject_metadata */
4100 if (classid == LargeObjectRelationId)
4101 classid = LargeObjectMetadataRelationId;
4102
4103 cacheid = get_object_catcache_oid(classid);
4104 if (cacheid != -1)
4105 {
4106 /* we can get the object's tuple from the syscache */
4107 HeapTuple tuple;
4108
4109 tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
4110 if (!HeapTupleIsValid(tuple))
4111 elog(ERROR, "cache lookup failed for %s %u",
4112 get_object_class_descr(classid), objectid);
4113
4114 ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
4115 tuple,
4116 get_object_attnum_owner(classid)));
4117 ReleaseSysCache(tuple);
4118 }
4119 else
4120 {
4121 /* for catalogs without an appropriate syscache */
4122 Relation rel;
4123 ScanKeyData entry[1];
4124 SysScanDesc scan;
4125 HeapTuple tuple;
4126 bool isnull;
4127
4128 rel = table_open(classid, AccessShareLock);
4129
4130 ScanKeyInit(&entry[0],
4131 get_object_attnum_oid(classid),
4132 BTEqualStrategyNumber, F_OIDEQ,
4133 ObjectIdGetDatum(objectid));
4134
4135 scan = systable_beginscan(rel,
4136 get_object_oid_index(classid), true,
4137 NULL, 1, entry);
4138
4139 tuple = systable_getnext(scan);
4140 if (!HeapTupleIsValid(tuple))
4141 elog(ERROR, "could not find tuple for %s %u",
4142 get_object_class_descr(classid), objectid);
4143
4144 ownerId = DatumGetObjectId(heap_getattr(tuple,
4145 get_object_attnum_owner(classid),
4146 RelationGetDescr(rel),
4147 &isnull));
4148 Assert(!isnull);
4149
4150 systable_endscan(scan);
4152 }
4153
4154 return has_privs_of_role(roleid, ownerId);
4155}
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(), RangeVarCallbackForStats(), RangeVarCallbackOwnsRelation(), RangeVarGetAndCheckCreationNamespace(), ReindexMultipleTables(), RemoveObjects(), renameatt_check(), RenameDatabase(), RenameSchema(), RenameTableSpace(), RenameType(), RI_Initial_Check(), 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 677 of file aclchk.c.

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

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

2987{
2988 switch (objtype)
2989 {
2990 case OBJECT_COLUMN:
2991 return
2992 pg_class_aclmask(object_oid, roleid, mask, how) |
2993 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
2994 case OBJECT_TABLE:
2995 case OBJECT_SEQUENCE:
2996 return pg_class_aclmask(object_oid, roleid, mask, how);
2997 case OBJECT_DATABASE:
2998 return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
2999 case OBJECT_FUNCTION:
3000 return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3001 case OBJECT_LANGUAGE:
3002 return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3003 case OBJECT_LARGEOBJECT:
3004 return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3005 mask, how, NULL);
3007 return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3008 case OBJECT_SCHEMA:
3009 return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3011 elog(ERROR, "grantable rights not supported for statistics objects");
3012 /* not reached, but keep compiler quiet */
3013 return ACL_NO_RIGHTS;
3014 case OBJECT_TABLESPACE:
3015 return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3016 case OBJECT_FDW:
3017 return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3019 return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3021 elog(ERROR, "grantable rights not supported for event triggers");
3022 /* not reached, but keep compiler quiet */
3023 return ACL_NO_RIGHTS;
3024 case OBJECT_TYPE:
3025 return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3026 default:
3027 elog(ERROR, "unrecognized object type: %d",
3028 (int) objtype);
3029 /* not reached, but keep compiler quiet */
3030 return ACL_NO_RIGHTS;
3031 }
3032}
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3535
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3147
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3476
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3046
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3272

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

3870{
3871 return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3872}
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3880

References attnum, mode, and pg_attribute_aclcheck_ext().

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

◆ pg_attribute_aclcheck_all()

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

Definition at line 3910 of file aclchk.c.

3912{
3913 return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3914}
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3921

References mode, and pg_attribute_aclcheck_all_ext().

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

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

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

3882{
3883 if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3884 ACLMASK_ANY, is_missing) != 0)
3885 return ACLCHECK_OK;
3886 else
3887 return ACLCHECK_NO_PRIV;
3888}
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3158

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

3149{
3150 return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3151 mask, how, NULL);
3152}

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

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

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

4051{
4052 if (pg_class_aclmask_ext(table_oid, roleid, mode,
4053 ACLMASK_ANY, is_missing) != 0)
4054 return ACLCHECK_OK;
4055 else
4056 return ACLCHECK_NO_PRIV;
4057}
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3282

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

3274{
3275 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3276}

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

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

4078{
4079 if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4080 ACLMASK_ANY, snapshot) != 0)
4081 return ACLCHECK_OK;
4082 else
4083 return ACLCHECK_NO_PRIV;
4084}

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

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

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

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

3477{
3478 AclMode result;
3479 HeapTuple tuple;
3480 Datum aclDatum;
3481 bool isNull;
3482 Acl *acl;
3483
3484 /* Superusers bypass all permission checking. */
3485 if (superuser_arg(roleid))
3486 return mask;
3487
3488 /* Get the ACL from pg_parameter_acl */
3489 tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
3490 if (!HeapTupleIsValid(tuple))
3491 ereport(ERROR,
3492 (errcode(ERRCODE_UNDEFINED_OBJECT),
3493 errmsg("parameter ACL with OID %u does not exist",
3494 acl_oid)));
3495
3496 aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
3497 Anum_pg_parameter_acl_paracl,
3498 &isNull);
3499 if (isNull)
3500 {
3501 /* No ACL, so build default ACL */
3502 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3503 aclDatum = (Datum) 0;
3504 }
3505 else
3506 {
3507 /* detoast ACL if necessary */
3508 acl = DatumGetAclP(aclDatum);
3509 }
3510
3511 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3512
3513 /* if we have a detoasted copy, free it */
3514 if (acl && acl != DatumGetPointer(aclDatum))
3515 pfree(acl);
3516
3517 ReleaseSysCache(tuple);
3518
3519 return result;
3520}

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

4065{
4066 if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4067 return ACLCHECK_OK;
4068 else
4069 return ACLCHECK_NO_PRIV;
4070}
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3412
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 3412 of file aclchk.c.

3413{
3414 AclMode result;
3415 char *parname;
3416 text *partext;
3417 HeapTuple tuple;
3418
3419 /* Superusers bypass all permission checking. */
3420 if (superuser_arg(roleid))
3421 return mask;
3422
3423 /* Convert name to the form it should have in pg_parameter_acl... */
3425 partext = cstring_to_text(parname);
3426
3427 /* ... and look it up */
3428 tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
3429
3430 if (!HeapTupleIsValid(tuple))
3431 {
3432 /* If no entry, GUC has no permissions for non-superusers */
3433 result = ACL_NO_RIGHTS;
3434 }
3435 else
3436 {
3437 Datum aclDatum;
3438 bool isNull;
3439 Acl *acl;
3440
3441 aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
3442 Anum_pg_parameter_acl_paracl,
3443 &isNull);
3444 if (isNull)
3445 {
3446 /* No ACL, so build default ACL */
3447 acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
3448 aclDatum = (Datum) 0;
3449 }
3450 else
3451 {
3452 /* detoast ACL if necessary */
3453 acl = DatumGetAclP(aclDatum);
3454 }
3455
3456 result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
3457
3458 /* if we have a detoasted copy, free it */
3459 if (acl && acl != DatumGetPointer(aclDatum))
3460 pfree(acl);
3461
3462 ReleaseSysCache(tuple);
3463 }
3464
3465 pfree(parname);
3466 pfree(partext);
3467
3468 return result;
3469}
char * convert_GUC_name_for_parameter_acl(const char *name)
Definition: guc.c:1251
Definition: c.h:706
text * cstring_to_text(const char *s)
Definition: varlena.c:181

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

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

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

2608{
2609 switch (privilege)
2610 {
2611 case ACL_INSERT:
2612 return "INSERT";
2613 case ACL_SELECT:
2614 return "SELECT";
2615 case ACL_UPDATE:
2616 return "UPDATE";
2617 case ACL_DELETE:
2618 return "DELETE";
2619 case ACL_TRUNCATE:
2620 return "TRUNCATE";
2621 case ACL_REFERENCES:
2622 return "REFERENCES";
2623 case ACL_TRIGGER:
2624 return "TRIGGER";
2625 case ACL_EXECUTE:
2626 return "EXECUTE";
2627 case ACL_USAGE:
2628 return "USAGE";
2629 case ACL_CREATE:
2630 return "CREATE";
2631 case ACL_CREATE_TEMP:
2632 return "TEMP";
2633 case ACL_CONNECT:
2634 return "CONNECT";
2635 case ACL_SET:
2636 return "SET";
2637 case ACL_ALTER_SYSTEM:
2638 return "ALTER SYSTEM";
2639 case ACL_MAINTAIN:
2640 return "MAINTAIN";
2641 default:
2642 elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2643 }
2644 return NULL; /* appease compiler */
2645}
#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 4327 of file aclchk.c.

4329{
4330 int nmembers;
4331 Oid *members;
4332
4333 /* Nothing to do if ACL is defaulted */
4334 if (acl == NULL)
4335 return;
4336
4337 /* Extract roles mentioned in ACL */
4338 nmembers = aclmembers(acl, &members);
4339
4340 /* Update the shared dependency ACL info */
4341 updateAclDependencies(classId, objectId, objsubId,
4342 ownerId,
4343 0, NULL,
4344 nmembers, members);
4345}

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

4602{
4603 /*
4604 * Generally, we only record the initial privileges when an extension is
4605 * being created, but because we don't actually use CREATE EXTENSION
4606 * during binary upgrades with pg_upgrade, there is a variable to let us
4607 * know that the GRANT and REVOKE statements being issued, while this
4608 * variable is true, are for the initial privileges of the extension
4609 * object and therefore we need to record them.
4610 */
4612 return;
4613
4614 recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4615}
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4630
bool binary_upgrade_record_init_privs
Definition: aclchk.c:109
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 4630 of file aclchk.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

1106{
1107 if (nspnames == NIL)
1108 {
1109 /* Set database-wide permissions if no schema was specified */
1110 iacls->nspid = InvalidOid;
1111
1112 SetDefaultACL(iacls);
1113 }
1114 else
1115 {
1116 /* Look up the schema OIDs and set permissions for each one */
1117 ListCell *nspcell;
1118
1119 foreach(nspcell, nspnames)
1120 {
1121 char *nspname = strVal(lfirst(nspcell));
1122
1123 iacls->nspid = get_namespace_oid(nspname, false);
1124
1125 /*
1126 * We used to insist that the target role have CREATE privileges
1127 * on the schema, since without that it wouldn't be able to create
1128 * an object for which these default privileges would apply.
1129 * However, this check proved to be more confusing than helpful,
1130 * and it also caused certain database states to not be
1131 * dumpable/restorable, since revoking CREATE doesn't cause
1132 * default privileges for the schema to go away. So now, we just
1133 * allow the ALTER; if the user lacks CREATE he'll find out when
1134 * he tries to create an object.
1135 */
1136
1137 SetDefaultACL(iacls);
1138 }
1139 }
1140}
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3605

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

2567{
2568 if (strcmp(privname, "insert") == 0)
2569 return ACL_INSERT;
2570 if (strcmp(privname, "select") == 0)
2571 return ACL_SELECT;
2572 if (strcmp(privname, "update") == 0)
2573 return ACL_UPDATE;
2574 if (strcmp(privname, "delete") == 0)
2575 return ACL_DELETE;
2576 if (strcmp(privname, "truncate") == 0)
2577 return ACL_TRUNCATE;
2578 if (strcmp(privname, "references") == 0)
2579 return ACL_REFERENCES;
2580 if (strcmp(privname, "trigger") == 0)
2581 return ACL_TRIGGER;
2582 if (strcmp(privname, "execute") == 0)
2583 return ACL_EXECUTE;
2584 if (strcmp(privname, "usage") == 0)
2585 return ACL_USAGE;
2586 if (strcmp(privname, "create") == 0)
2587 return ACL_CREATE;
2588 if (strcmp(privname, "temporary") == 0)
2589 return ACL_CREATE_TEMP;
2590 if (strcmp(privname, "temp") == 0)
2591 return ACL_CREATE_TEMP;
2592 if (strcmp(privname, "connect") == 0)
2593 return ACL_CONNECT;
2594 if (strcmp(privname, "set") == 0)
2595 return ACL_SET;
2596 if (strcmp(privname, "alter system") == 0)
2597 return ACL_ALTER_SYSTEM;
2598 if (strcmp(privname, "maintain") == 0)
2599 return ACL_MAINTAIN;
2600 ereport(ERROR,
2601 (errcode(ERRCODE_SYNTAX_ERROR),
2602 errmsg("unrecognized privilege type \"%s\"", privname)));
2603 return 0; /* appease compiler */
2604}

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

Referenced by binary_upgrade_set_record_init_privs(), and recordExtensionInitPriv().