Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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

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

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

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

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

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 & ~((AclMode) 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:2564
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1105
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2605
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:2626
List * cols
Definition: parsenodes.h:2627
char * defname
Definition: parsenodes.h:842
Node * arg
Definition: parsenodes.h:843
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 1637 of file aclchk.c.

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

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Language_check()

static void ExecGrant_Language_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2249 of file aclchk.c.

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

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Parameter()

static void ExecGrant_Parameter ( InternalGrant istmt)
static

Definition at line 2421 of file aclchk.c.

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

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

2402{
2403 Form_pg_type pg_type_tuple;
2404
2405 pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2406
2407 /* Disallow GRANT on dependent types */
2408 if (IsTrueArrayType(pg_type_tuple))
2409 ereport(ERROR,
2410 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2411 errmsg("cannot set privileges of array types"),
2412 errhint("Set the privileges of the element type instead.")));
2413 if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
2414 ereport(ERROR,
2415 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2416 errmsg("cannot set privileges of multirange types"),
2417 errhint("Set the privileges of the range type instead.")));
2418}
int errhint(const char *fmt,...)
Definition: elog.c:1321
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:2401
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2113
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2265
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2421
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1782
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2249
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 & ~((AclMode) 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:2569
@ ACL_TARGET_ALL_IN_SCHEMA
Definition: parsenodes.h:2570

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

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

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

4211{
4212 Acl *result = NULL;
4213 HeapTuple tuple;
4214
4215 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4216 ObjectIdGetDatum(roleId),
4217 ObjectIdGetDatum(nsp_oid),
4218 CharGetDatum(objtype));
4219
4220 if (HeapTupleIsValid(tuple))
4221 {
4222 Datum aclDatum;
4223 bool isNull;
4224
4225 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4226 Anum_pg_default_acl_defaclacl,
4227 &isNull);
4228 if (!isNull)
4229 result = DatumGetAclPCopy(aclDatum);
4230 ReleaseSysCache(tuple);
4231 }
4232
4233 return result;
4234}
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 4245 of file aclchk.c.

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

References acldefault(), aclequal(), aclitemsort(), aclmerge(), get_default_acl_internal(), InvalidOid, IsBootstrapProcessingMode, OBJECT_FUNCTION, OBJECT_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:1346
#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 4186 of file aclchk.c.

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

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

3835{
3836 return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3837}
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3844
static PgChecksumMode mode
Definition: pg_checksums.c:55

References mode, and object_aclcheck_ext().

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

◆ object_aclcheck_ext()

◆ object_aclmask()

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

Definition at line 3044 of file aclchk.c.

3046{
3047 return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3048}

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

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

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

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

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

◆ objectNamesToOids()

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

Definition at line 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:775
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 2983 of file aclchk.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3272{
3273 return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3274}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 GRANT/REVOKE ON SCHEMAS")));
1211 objtype = DEFACLOBJ_NAMESPACE;
1212 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1213 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
1214 break;
1215
1216 case OBJECT_LARGEOBJECT:
1217 if (OidIsValid(iacls->nspid))
1218 ereport(ERROR,
1219 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1220 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON LARGE OBJECTS")));
1221 objtype = DEFACLOBJ_LARGEOBJECT;
1222 if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
1223 this_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
1224 break;
1225
1226 default:
1227 elog(ERROR, "unrecognized object type: %d",
1228 (int) iacls->objtype);
1229 objtype = 0; /* keep compiler quiet */
1230 break;
1231 }
1232
1233 /* Search for existing row for this object type in catalog */
1234 tuple = SearchSysCache3(DEFACLROLENSPOBJ,
1235 ObjectIdGetDatum(iacls->roleid),
1236 ObjectIdGetDatum(iacls->nspid),
1237 CharGetDatum(objtype));
1238
1239 if (HeapTupleIsValid(tuple))
1240 {
1241 Datum aclDatum;
1242 bool isNull;
1243
1244 aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
1245 Anum_pg_default_acl_defaclacl,
1246 &isNull);
1247 if (!isNull)
1248 old_acl = DatumGetAclPCopy(aclDatum);
1249 else
1250 old_acl = NULL; /* this case shouldn't happen, probably */
1251 isNew = false;
1252 }
1253 else
1254 {
1255 old_acl = NULL;
1256 isNew = true;
1257 }
1258
1259 if (old_acl != NULL)
1260 {
1261 /*
1262 * We need the members of both old and new ACLs so we can correct the
1263 * shared dependency information. Collect data before
1264 * merge_acl_with_grant throws away old_acl.
1265 */
1266 noldmembers = aclmembers(old_acl, &oldmembers);
1267 }
1268 else
1269 {
1270 /* If no or null entry, start with the default ACL value */
1271 old_acl = aclcopy(def_acl);
1272 /* There are no old member roles according to the catalogs */
1273 noldmembers = 0;
1274 oldmembers = NULL;
1275 }
1276
1277 /*
1278 * Generate new ACL. Grantor of rights is always the same as the target
1279 * role.
1280 */
1281 new_acl = merge_acl_with_grant(old_acl,
1282 iacls->is_grant,
1283 iacls->grant_option,
1284 iacls->behavior,
1285 iacls->grantees,
1286 this_privileges,
1287 iacls->roleid,
1288 iacls->roleid);
1289
1290 /*
1291 * If the result is the same as the default value, we do not need an
1292 * explicit pg_default_acl entry, and should in fact remove the entry if
1293 * it exists. Must sort both arrays to compare properly.
1294 */
1295 aclitemsort(new_acl);
1296 aclitemsort(def_acl);
1297 if (aclequal(new_acl, def_acl))
1298 {
1299 /* delete old entry, if indeed there is one */
1300 if (!isNew)
1301 {
1302 ObjectAddress myself;
1303
1304 /*
1305 * The dependency machinery will take care of removing all
1306 * associated dependency entries. We use DROP_RESTRICT since
1307 * there shouldn't be anything depending on this entry.
1308 */
1309 myself.classId = DefaultAclRelationId;
1310 myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1311 myself.objectSubId = 0;
1312
1313 performDeletion(&myself, DROP_RESTRICT, 0);
1314 }
1315 }
1316 else
1317 {
1318 Datum values[Natts_pg_default_acl] = {0};
1319 bool nulls[Natts_pg_default_acl] = {0};
1320 bool replaces[Natts_pg_default_acl] = {0};
1321 Oid defAclOid;
1322
1323 if (isNew)
1324 {
1325 /* insert new entry */
1326 defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
1327 Anum_pg_default_acl_oid);
1328 values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
1329 values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
1330 values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
1331 values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
1332 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1333
1334 newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
1335 CatalogTupleInsert(rel, newtuple);
1336 }
1337 else
1338 {
1339 defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
1340
1341 /* update existing entry */
1342 values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
1343 replaces[Anum_pg_default_acl_defaclacl - 1] = true;
1344
1345 newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
1346 values, nulls, replaces);
1347 CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
1348 }
1349
1350 /* these dependencies don't change in an update */
1351 if (isNew)
1352 {
1353 /* dependency on role */
1354 recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
1355 iacls->roleid);
1356
1357 /* dependency on namespace */
1358 if (OidIsValid(iacls->nspid))
1359 {
1360 ObjectAddress myself,
1361 referenced;
1362
1363 myself.classId = DefaultAclRelationId;
1364 myself.objectId = defAclOid;
1365 myself.objectSubId = 0;
1366
1367 referenced.classId = NamespaceRelationId;
1368 referenced.objectId = iacls->nspid;
1369 referenced.objectSubId = 0;
1370
1371 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1372 }
1373 }
1374
1375 /*
1376 * Update the shared dependency ACL info
1377 */
1378 nnewmembers = aclmembers(new_acl, &newmembers);
1379
1380 updateAclDependencies(DefaultAclRelationId,
1381 defAclOid, 0,
1382 iacls->roleid,
1383 noldmembers, oldmembers,
1384 nnewmembers, newmembers);
1385
1386 if (isNew)
1387 InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
1388 else
1389 InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
1390 }
1391
1392 if (HeapTupleIsValid(tuple))
1393 ReleaseSysCache(tuple);
1394
1396
1397 /* prevent error when processing duplicate objects */
1399}
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:273
@ DEPENDENCY_AUTO
Definition: dependency.h:34
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168

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

Referenced by RemoveRoleFromObjectACL(), and SetDefaultACLsInSchemas().

◆ SetDefaultACLsInSchemas()

static void SetDefaultACLsInSchemas ( InternalDefaultACL iacls,
List nspnames 
)
static

Definition at line 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 2564 of file aclchk.c.

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

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