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

Go to the source code of this file.

Data Structures

struct  InternalDefaultACL
 

Functions

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

Variables

bool binary_upgrade_record_init_privs = false
 

Function Documentation

◆ aclcheck_error()

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

Definition at line 2622 of file aclchk.c.

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

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

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

◆ aclcheck_error_col()

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

Definition at line 2911 of file aclchk.c.

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

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

Referenced by restrict_and_check_grant().

◆ aclcheck_error_type()

void aclcheck_error_type ( AclResult  aclerr,
Oid  typeOid 
)

◆ ExecAlterDefaultPrivilegesStmt()

void ExecAlterDefaultPrivilegesStmt ( ParseState pstate,
AlterDefaultPrivilegesStmt stmt 
)

Definition at line 903 of file aclchk.c.

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

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

Referenced by ProcessUtilitySlow().

◆ ExecGrant_Attribute()

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

Definition at line 1607 of file aclchk.c.

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

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

Referenced by ExecGrant_Relation().

◆ ExecGrant_common()

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

Definition at line 2083 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Language_check()

static void ExecGrant_Language_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2219 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Largeobject()

static void ExecGrant_Largeobject ( InternalGrant istmt)
static

Definition at line 2235 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Parameter()

static void ExecGrant_Parameter ( InternalGrant istmt)
static

Definition at line 2391 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Relation()

static void ExecGrant_Relation ( InternalGrant istmt)
static

Definition at line 1752 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Type_check()

static void ExecGrant_Type_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2371 of file aclchk.c.

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

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

Referenced by ExecGrantStmt_oids().

◆ ExecGrantStmt_oids()

static void ExecGrantStmt_oids ( InternalGrant istmt)
static

Definition at line 602 of file aclchk.c.

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

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

Referenced by ExecuteGrantStmt(), and RemoveRoleFromObjectACL().

◆ ExecuteGrantStmt()

void ExecuteGrantStmt ( GrantStmt stmt)

Definition at line 392 of file aclchk.c.

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

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

Referenced by ProcessUtilitySlow(), and standard_ProcessUtility().

◆ expand_all_col_privileges()

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

Definition at line 1561 of file aclchk.c.

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

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

Referenced by ExecGrant_Relation().

◆ expand_col_privileges()

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

Definition at line 1528 of file aclchk.c.

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

4189 {
4190  Acl *result = NULL;
4191  HeapTuple tuple;
4192 
4193  tuple = SearchSysCache3(DEFACLROLENSPOBJ,
4194  ObjectIdGetDatum(roleId),
4195  ObjectIdGetDatum(nsp_oid),
4196  CharGetDatum(objtype));
4197 
4198  if (HeapTupleIsValid(tuple))
4199  {
4200  Datum aclDatum;
4201  bool isNull;
4202 
4203  aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4204  Anum_pg_default_acl_defaclacl,
4205  &isNull);
4206  if (!isNull)
4207  result = DatumGetAclPCopy(aclDatum);
4208  ReleaseSysCache(tuple);
4209  }
4210 
4211  return result;
4212 }
static Datum CharGetDatum(char X)
Definition: postgres.h:122
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:243

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

Referenced by get_user_default_acl().

◆ get_user_default_acl()

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

Definition at line 4223 of file aclchk.c.

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

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

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

◆ getRelationsInNamespace()

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

Definition at line 865 of file aclchk.c.

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

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

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

4146 {
4147  bool result = false;
4148  HeapTuple utup;
4149 
4150  /* Superusers bypass all permission checking. */
4151  if (superuser_arg(roleid))
4152  return true;
4153 
4154  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4155  if (HeapTupleIsValid(utup))
4156  {
4157  result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4158  ReleaseSysCache(utup);
4159  }
4160  return result;
4161 }
bool rolcreaterole
Definition: pg_authid.h:37

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

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

◆ merge_acl_with_grant()

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

Definition at line 182 of file aclchk.c.

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

3811 {
3812  return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
3813 }
AclResult object_aclcheck_ext(Oid classid, Oid objectid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3820
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 3018 of file aclchk.c.

3020 {
3021  return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
3022 }

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

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

References acldefault(), aclmask(), Assert, DatumGetAclP, DatumGetObjectId(), DatumGetPointer(), ereport, errcode(), errmsg(), 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 4064 of file aclchk.c.

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

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

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

◆ objectNamesToOids()

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

Definition at line 664 of file aclchk.c.

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

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

Referenced by ExecuteGrantStmt().

◆ objectsInSchemaToOids()

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

Definition at line 776 of file aclchk.c.

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

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

Referenced by ExecuteGrantStmt().

◆ pg_aclmask()

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

Definition at line 2953 of file aclchk.c.

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

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

3844 {
3845  return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3846 }
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3854

References attnum, mode, and pg_attribute_aclcheck_ext().

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

◆ pg_attribute_aclcheck_all()

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

Definition at line 3884 of file aclchk.c.

3886 {
3887  return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
3888 }
AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3895

References mode, and pg_attribute_aclcheck_all_ext().

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

◆ pg_attribute_aclcheck_all_ext()

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

Definition at line 3895 of file aclchk.c.

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

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

3856 {
3857  if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3858  ACLMASK_ANY, is_missing) != 0)
3859  return ACLCHECK_OK;
3860  else
3861  return ACLCHECK_NO_PRIV;
3862 }
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3132

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

3123 {
3124  return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
3125  mask, how, NULL);
3126 }

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

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

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

4025 {
4026  if (pg_class_aclmask_ext(table_oid, roleid, mode,
4027  ACLMASK_ANY, is_missing) != 0)
4028  return ACLCHECK_OK;
4029  else
4030  return ACLCHECK_NO_PRIV;
4031 }
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3256

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

3248 {
3249  return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3250 }

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

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

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

Referenced by pg_class_aclcheck_ext(), and pg_class_aclmask().

◆ pg_largeobject_aclcheck_snapshot()

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

Definition at line 4050 of file aclchk.c.

4052 {
4053  if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
4054  ACLMASK_ANY, snapshot) != 0)
4055  return ACLCHECK_OK;
4056  else
4057  return ACLCHECK_NO_PRIV;
4058 }

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

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

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

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

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

Referenced by object_aclmask_ext().

◆ pg_parameter_acl_aclmask()

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

Definition at line 3450 of file aclchk.c.

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

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

4039 {
4040  if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
4041  return ACLCHECK_OK;
4042  else
4043  return ACLCHECK_NO_PRIV;
4044 }
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3386
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 3386 of file aclchk.c.

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

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

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

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

Referenced by object_aclmask_ext().

◆ privilege_to_string()

static const char * privilege_to_string ( AclMode  privilege)
static

Definition at line 2575 of file aclchk.c.

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

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

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

◆ recordDependencyOnNewAcl()

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

Definition at line 4299 of file aclchk.c.

4301 {
4302  int nmembers;
4303  Oid *members;
4304 
4305  /* Nothing to do if ACL is defaulted */
4306  if (acl == NULL)
4307  return;
4308 
4309  /* Extract roles mentioned in ACL */
4310  nmembers = aclmembers(acl, &members);
4311 
4312  /* Update the shared dependency ACL info */
4313  updateAclDependencies(classId, objectId, objsubId,
4314  ownerId,
4315  0, NULL,
4316  nmembers, members);
4317 }

References aclmembers(), and updateAclDependencies().

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

◆ recordExtensionInitPriv()

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

Definition at line 4573 of file aclchk.c.

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

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

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

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

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

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

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

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

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

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

Referenced by shdepDropOwned().

◆ RemoveRoleFromObjectACL()

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

Definition at line 1393 of file aclchk.c.

1394 {
1395  if (classid == DefaultAclRelationId)
1396  {
1397  InternalDefaultACL iacls;
1398  Form_pg_default_acl pg_default_acl_tuple;
1399  Relation rel;
1400  ScanKeyData skey[1];
1401  SysScanDesc scan;
1402  HeapTuple tuple;
1403 
1404  /* first fetch info needed by SetDefaultACL */
1405  rel = table_open(DefaultAclRelationId, AccessShareLock);
1406 
1407  ScanKeyInit(&skey[0],
1408  Anum_pg_default_acl_oid,
1409  BTEqualStrategyNumber, F_OIDEQ,
1410  ObjectIdGetDatum(objid));
1411 
1412  scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1413  NULL, 1, skey);
1414 
1415  tuple = systable_getnext(scan);
1416 
1417  if (!HeapTupleIsValid(tuple))
1418  elog(ERROR, "could not find tuple for default ACL %u", objid);
1419 
1420  pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1421 
1422  iacls.roleid = pg_default_acl_tuple->defaclrole;
1423  iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1424 
1425  switch (pg_default_acl_tuple->defaclobjtype)
1426  {
1427  case DEFACLOBJ_RELATION:
1428  iacls.objtype = OBJECT_TABLE;
1429  break;
1430  case DEFACLOBJ_SEQUENCE:
1431  iacls.objtype = OBJECT_SEQUENCE;
1432  break;
1433  case DEFACLOBJ_FUNCTION:
1434  iacls.objtype = OBJECT_FUNCTION;
1435  break;
1436  case DEFACLOBJ_TYPE:
1437  iacls.objtype = OBJECT_TYPE;
1438  break;
1439  case DEFACLOBJ_NAMESPACE:
1440  iacls.objtype = OBJECT_SCHEMA;
1441  break;
1442  default:
1443  /* Shouldn't get here */
1444  elog(ERROR, "unexpected default ACL type: %d",
1445  (int) pg_default_acl_tuple->defaclobjtype);
1446  break;
1447  }
1448 
1449