PostgreSQL Source Code  git master
aclchk.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_am.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_init_privs.h"
#include "catalog/pg_language.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_parameter_acl.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_transform.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/tablespace.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/aclchk_internal.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
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 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 (Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how)
 
static AclMode pg_type_aclmask (Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
 
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 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_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)
 

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

2675 {
2676  switch (aclerr)
2677  {
2678  case ACLCHECK_OK:
2679  /* no error, so return to caller */
2680  break;
2681  case ACLCHECK_NO_PRIV:
2682  {
2683  const char *msg = "???";
2684 
2685  switch (objtype)
2686  {
2687  case OBJECT_AGGREGATE:
2688  msg = gettext_noop("permission denied for aggregate %s");
2689  break;
2690  case OBJECT_COLLATION:
2691  msg = gettext_noop("permission denied for collation %s");
2692  break;
2693  case OBJECT_COLUMN:
2694  msg = gettext_noop("permission denied for column %s");
2695  break;
2696  case OBJECT_CONVERSION:
2697  msg = gettext_noop("permission denied for conversion %s");
2698  break;
2699  case OBJECT_DATABASE:
2700  msg = gettext_noop("permission denied for database %s");
2701  break;
2702  case OBJECT_DOMAIN:
2703  msg = gettext_noop("permission denied for domain %s");
2704  break;
2705  case OBJECT_EVENT_TRIGGER:
2706  msg = gettext_noop("permission denied for event trigger %s");
2707  break;
2708  case OBJECT_EXTENSION:
2709  msg = gettext_noop("permission denied for extension %s");
2710  break;
2711  case OBJECT_FDW:
2712  msg = gettext_noop("permission denied for foreign-data wrapper %s");
2713  break;
2714  case OBJECT_FOREIGN_SERVER:
2715  msg = gettext_noop("permission denied for foreign server %s");
2716  break;
2717  case OBJECT_FOREIGN_TABLE:
2718  msg = gettext_noop("permission denied for foreign table %s");
2719  break;
2720  case OBJECT_FUNCTION:
2721  msg = gettext_noop("permission denied for function %s");
2722  break;
2723  case OBJECT_INDEX:
2724  msg = gettext_noop("permission denied for index %s");
2725  break;
2726  case OBJECT_LANGUAGE:
2727  msg = gettext_noop("permission denied for language %s");
2728  break;
2729  case OBJECT_LARGEOBJECT:
2730  msg = gettext_noop("permission denied for large object %s");
2731  break;
2732  case OBJECT_MATVIEW:
2733  msg = gettext_noop("permission denied for materialized view %s");
2734  break;
2735  case OBJECT_OPCLASS:
2736  msg = gettext_noop("permission denied for operator class %s");
2737  break;
2738  case OBJECT_OPERATOR:
2739  msg = gettext_noop("permission denied for operator %s");
2740  break;
2741  case OBJECT_OPFAMILY:
2742  msg = gettext_noop("permission denied for operator family %s");
2743  break;
2744  case OBJECT_PARAMETER_ACL:
2745  msg = gettext_noop("permission denied for parameter %s");
2746  break;
2747  case OBJECT_POLICY:
2748  msg = gettext_noop("permission denied for policy %s");
2749  break;
2750  case OBJECT_PROCEDURE:
2751  msg = gettext_noop("permission denied for procedure %s");
2752  break;
2753  case OBJECT_PUBLICATION:
2754  msg = gettext_noop("permission denied for publication %s");
2755  break;
2756  case OBJECT_ROUTINE:
2757  msg = gettext_noop("permission denied for routine %s");
2758  break;
2759  case OBJECT_SCHEMA:
2760  msg = gettext_noop("permission denied for schema %s");
2761  break;
2762  case OBJECT_SEQUENCE:
2763  msg = gettext_noop("permission denied for sequence %s");
2764  break;
2765  case OBJECT_STATISTIC_EXT:
2766  msg = gettext_noop("permission denied for statistics object %s");
2767  break;
2768  case OBJECT_SUBSCRIPTION:
2769  msg = gettext_noop("permission denied for subscription %s");
2770  break;
2771  case OBJECT_TABLE:
2772  msg = gettext_noop("permission denied for table %s");
2773  break;
2774  case OBJECT_TABLESPACE:
2775  msg = gettext_noop("permission denied for tablespace %s");
2776  break;
2778  msg = gettext_noop("permission denied for text search configuration %s");
2779  break;
2780  case OBJECT_TSDICTIONARY:
2781  msg = gettext_noop("permission denied for text search dictionary %s");
2782  break;
2783  case OBJECT_TYPE:
2784  msg = gettext_noop("permission denied for type %s");
2785  break;
2786  case OBJECT_VIEW:
2787  msg = gettext_noop("permission denied for view %s");
2788  break;
2789  /* these currently aren't used */
2790  case OBJECT_ACCESS_METHOD:
2791  case OBJECT_AMOP:
2792  case OBJECT_AMPROC:
2793  case OBJECT_ATTRIBUTE:
2794  case OBJECT_CAST:
2795  case OBJECT_DEFAULT:
2796  case OBJECT_DEFACL:
2797  case OBJECT_DOMCONSTRAINT:
2800  case OBJECT_ROLE:
2801  case OBJECT_RULE:
2802  case OBJECT_TABCONSTRAINT:
2803  case OBJECT_TRANSFORM:
2804  case OBJECT_TRIGGER:
2805  case OBJECT_TSPARSER:
2806  case OBJECT_TSTEMPLATE:
2807  case OBJECT_USER_MAPPING:
2808  elog(ERROR, "unsupported object type: %d", objtype);
2809  }
2810 
2811  ereport(ERROR,
2812  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2813  errmsg(msg, objectname)));
2814  break;
2815  }
2816  case ACLCHECK_NOT_OWNER:
2817  {
2818  const char *msg = "???";
2819 
2820  switch (objtype)
2821  {
2822  case OBJECT_AGGREGATE:
2823  msg = gettext_noop("must be owner of aggregate %s");
2824  break;
2825  case OBJECT_COLLATION:
2826  msg = gettext_noop("must be owner of collation %s");
2827  break;
2828  case OBJECT_CONVERSION:
2829  msg = gettext_noop("must be owner of conversion %s");
2830  break;
2831  case OBJECT_DATABASE:
2832  msg = gettext_noop("must be owner of database %s");
2833  break;
2834  case OBJECT_DOMAIN:
2835  msg = gettext_noop("must be owner of domain %s");
2836  break;
2837  case OBJECT_EVENT_TRIGGER:
2838  msg = gettext_noop("must be owner of event trigger %s");
2839  break;
2840  case OBJECT_EXTENSION:
2841  msg = gettext_noop("must be owner of extension %s");
2842  break;
2843  case OBJECT_FDW:
2844  msg = gettext_noop("must be owner of foreign-data wrapper %s");
2845  break;
2846  case OBJECT_FOREIGN_SERVER:
2847  msg = gettext_noop("must be owner of foreign server %s");
2848  break;
2849  case OBJECT_FOREIGN_TABLE:
2850  msg = gettext_noop("must be owner of foreign table %s");
2851  break;
2852  case OBJECT_FUNCTION:
2853  msg = gettext_noop("must be owner of function %s");
2854  break;
2855  case OBJECT_INDEX:
2856  msg = gettext_noop("must be owner of index %s");
2857  break;
2858  case OBJECT_LANGUAGE:
2859  msg = gettext_noop("must be owner of language %s");
2860  break;
2861  case OBJECT_LARGEOBJECT:
2862  msg = gettext_noop("must be owner of large object %s");
2863  break;
2864  case OBJECT_MATVIEW:
2865  msg = gettext_noop("must be owner of materialized view %s");
2866  break;
2867  case OBJECT_OPCLASS:
2868  msg = gettext_noop("must be owner of operator class %s");
2869  break;
2870  case OBJECT_OPERATOR:
2871  msg = gettext_noop("must be owner of operator %s");
2872  break;
2873  case OBJECT_OPFAMILY:
2874  msg = gettext_noop("must be owner of operator family %s");
2875  break;
2876  case OBJECT_PROCEDURE:
2877  msg = gettext_noop("must be owner of procedure %s");
2878  break;
2879  case OBJECT_PUBLICATION:
2880  msg = gettext_noop("must be owner of publication %s");
2881  break;
2882  case OBJECT_ROUTINE:
2883  msg = gettext_noop("must be owner of routine %s");
2884  break;
2885  case OBJECT_SEQUENCE:
2886  msg = gettext_noop("must be owner of sequence %s");
2887  break;
2888  case OBJECT_SUBSCRIPTION:
2889  msg = gettext_noop("must be owner of subscription %s");
2890  break;
2891  case OBJECT_TABLE:
2892  msg = gettext_noop("must be owner of table %s");
2893  break;
2894  case OBJECT_TYPE:
2895  msg = gettext_noop("must be owner of type %s");
2896  break;
2897  case OBJECT_VIEW:
2898  msg = gettext_noop("must be owner of view %s");
2899  break;
2900  case OBJECT_SCHEMA:
2901  msg = gettext_noop("must be owner of schema %s");
2902  break;
2903  case OBJECT_STATISTIC_EXT:
2904  msg = gettext_noop("must be owner of statistics object %s");
2905  break;
2906  case OBJECT_TABLESPACE:
2907  msg = gettext_noop("must be owner of tablespace %s");
2908  break;
2910  msg = gettext_noop("must be owner of text search configuration %s");
2911  break;
2912  case OBJECT_TSDICTIONARY:
2913  msg = gettext_noop("must be owner of text search dictionary %s");
2914  break;
2915 
2916  /*
2917  * Special cases: For these, the error message talks
2918  * about "relation", because that's where the
2919  * ownership is attached. See also
2920  * check_object_ownership().
2921  */
2922  case OBJECT_COLUMN:
2923  case OBJECT_POLICY:
2924  case OBJECT_RULE:
2925  case OBJECT_TABCONSTRAINT:
2926  case OBJECT_TRIGGER:
2927  msg = gettext_noop("must be owner of relation %s");
2928  break;
2929  /* these currently aren't used */
2930  case OBJECT_ACCESS_METHOD:
2931  case OBJECT_AMOP:
2932  case OBJECT_AMPROC:
2933  case OBJECT_ATTRIBUTE:
2934  case OBJECT_CAST:
2935  case OBJECT_DEFAULT:
2936  case OBJECT_DEFACL:
2937  case OBJECT_DOMCONSTRAINT:
2938  case OBJECT_PARAMETER_ACL:
2941  case OBJECT_ROLE:
2942  case OBJECT_TRANSFORM:
2943  case OBJECT_TSPARSER:
2944  case OBJECT_TSTEMPLATE:
2945  case OBJECT_USER_MAPPING:
2946  elog(ERROR, "unsupported object type: %d", objtype);
2947  }
2948 
2949  ereport(ERROR,
2950  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2951  errmsg(msg, objectname)));
2952  break;
2953  }
2954  default:
2955  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2956  break;
2957  }
2958 }
@ 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:1186
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
@ OBJECT_EVENT_TRIGGER
Definition: parsenodes.h:2096
@ OBJECT_FDW
Definition: parsenodes.h:2098
@ OBJECT_TSPARSER
Definition: parsenodes.h:2129
@ OBJECT_COLLATION
Definition: parsenodes.h:2089
@ OBJECT_USER_MAPPING
Definition: parsenodes.h:2132
@ OBJECT_ACCESS_METHOD
Definition: parsenodes.h:2082
@ OBJECT_OPCLASS
Definition: parsenodes.h:2106
@ OBJECT_DEFACL
Definition: parsenodes.h:2093
@ OBJECT_AGGREGATE
Definition: parsenodes.h:2083
@ OBJECT_MATVIEW
Definition: parsenodes.h:2105
@ OBJECT_SCHEMA
Definition: parsenodes.h:2118
@ OBJECT_POLICY
Definition: parsenodes.h:2110
@ OBJECT_OPERATOR
Definition: parsenodes.h:2107
@ OBJECT_FOREIGN_TABLE
Definition: parsenodes.h:2100
@ OBJECT_TSCONFIGURATION
Definition: parsenodes.h:2127
@ OBJECT_OPFAMILY
Definition: parsenodes.h:2108
@ OBJECT_DOMAIN
Definition: parsenodes.h:2094
@ OBJECT_COLUMN
Definition: parsenodes.h:2088
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2124
@ OBJECT_ROLE
Definition: parsenodes.h:2115
@ OBJECT_ROUTINE
Definition: parsenodes.h:2116
@ OBJECT_LARGEOBJECT
Definition: parsenodes.h:2104
@ OBJECT_PUBLICATION_NAMESPACE
Definition: parsenodes.h:2113
@ OBJECT_PROCEDURE
Definition: parsenodes.h:2111
@ OBJECT_EXTENSION
Definition: parsenodes.h:2097
@ OBJECT_INDEX
Definition: parsenodes.h:2102
@ OBJECT_DEFAULT
Definition: parsenodes.h:2092
@ OBJECT_DATABASE
Definition: parsenodes.h:2091
@ OBJECT_SEQUENCE
Definition: parsenodes.h:2119
@ OBJECT_TSTEMPLATE
Definition: parsenodes.h:2130
@ OBJECT_LANGUAGE
Definition: parsenodes.h:2103
@ OBJECT_AMOP
Definition: parsenodes.h:2084
@ OBJECT_PUBLICATION_REL
Definition: parsenodes.h:2114
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2099
@ OBJECT_TSDICTIONARY
Definition: parsenodes.h:2128
@ OBJECT_ATTRIBUTE
Definition: parsenodes.h:2086
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2112
@ OBJECT_RULE
Definition: parsenodes.h:2117
@ OBJECT_CONVERSION
Definition: parsenodes.h:2090
@ OBJECT_AMPROC
Definition: parsenodes.h:2085
@ OBJECT_TABLE
Definition: parsenodes.h:2123
@ OBJECT_VIEW
Definition: parsenodes.h:2133
@ OBJECT_PARAMETER_ACL
Definition: parsenodes.h:2109
@ OBJECT_TYPE
Definition: parsenodes.h:2131
@ OBJECT_FUNCTION
Definition: parsenodes.h:2101
@ OBJECT_TABCONSTRAINT
Definition: parsenodes.h:2122
@ OBJECT_DOMCONSTRAINT
Definition: parsenodes.h:2095
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2120
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2121
@ OBJECT_CAST
Definition: parsenodes.h:2087
@ OBJECT_TRIGGER
Definition: parsenodes.h:2126
@ OBJECT_TRANSFORM
Definition: parsenodes.h:2125

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(), TargetPrivilegesCheck(), transformTableLikeClause(), truncate_check_perms(), TypeCreate(), user_mapping_ddl_aclcheck(), ValidateJoinEstimator(), and ValidateRestrictionEstimator().

◆ aclcheck_error_col()

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

Definition at line 2962 of file aclchk.c.

2964 {
2965  switch (aclerr)
2966  {
2967  case ACLCHECK_OK:
2968  /* no error, so return to caller */
2969  break;
2970  case ACLCHECK_NO_PRIV:
2971  ereport(ERROR,
2972  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2973  errmsg("permission denied for column \"%s\" of relation \"%s\"",
2974  colname, objectname)));
2975  break;
2976  case ACLCHECK_NOT_OWNER:
2977  /* relation msg is OK since columns don't have separate owners */
2978  aclcheck_error(aclerr, objtype, objectname);
2979  break;
2980  default:
2981  elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
2982  break;
2983  }
2984 }
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2673

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

967 {
968  GrantStmt *action = stmt->action;
969  InternalDefaultACL iacls;
970  ListCell *cell;
971  List *rolespecs = NIL;
972  List *nspnames = NIL;
973  DefElem *drolespecs = NULL;
974  DefElem *dnspnames = NULL;
975  AclMode all_privileges;
976  const char *errormsg;
977 
978  /* Deconstruct the "options" part of the statement */
979  foreach(cell, stmt->options)
980  {
981  DefElem *defel = (DefElem *) lfirst(cell);
982 
983  if (strcmp(defel->defname, "schemas") == 0)
984  {
985  if (dnspnames)
986  errorConflictingDefElem(defel, pstate);
987  dnspnames = defel;
988  }
989  else if (strcmp(defel->defname, "roles") == 0)
990  {
991  if (drolespecs)
992  errorConflictingDefElem(defel, pstate);
993  drolespecs = defel;
994  }
995  else
996  elog(ERROR, "option \"%s\" not recognized", defel->defname);
997  }
998 
999  if (dnspnames)
1000  nspnames = (List *) dnspnames->arg;
1001  if (drolespecs)
1002  rolespecs = (List *) drolespecs->arg;
1003 
1004  /* Prepare the InternalDefaultACL representation of the statement */
1005  /* roleid to be filled below */
1006  /* nspid to be filled in SetDefaultACLsInSchemas */
1007  iacls.is_grant = action->is_grant;
1008  iacls.objtype = action->objtype;
1009  /* all_privs to be filled below */
1010  /* privileges to be filled below */
1011  iacls.grantees = NIL; /* filled below */
1012  iacls.grant_option = action->grant_option;
1013  iacls.behavior = action->behavior;
1014 
1015  /*
1016  * Convert the RoleSpec list into an Oid list. Note that at this point we
1017  * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
1018  * there shouldn't be any additional work needed to support this case.
1019  */
1020  foreach(cell, action->grantees)
1021  {
1022  RoleSpec *grantee = (RoleSpec *) lfirst(cell);
1023  Oid grantee_uid;
1024 
1025  switch (grantee->roletype)
1026  {
1027  case ROLESPEC_PUBLIC:
1028  grantee_uid = ACL_ID_PUBLIC;
1029  break;
1030  default:
1031  grantee_uid = get_rolespec_oid(grantee, false);
1032  break;
1033  }
1034  iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
1035  }
1036 
1037  /*
1038  * Convert action->privileges, a list of privilege strings, into an
1039  * AclMode bitmask.
1040  */
1041  switch (action->objtype)
1042  {
1043  case OBJECT_TABLE:
1044  all_privileges = ACL_ALL_RIGHTS_RELATION;
1045  errormsg = gettext_noop("invalid privilege type %s for relation");
1046  break;
1047  case OBJECT_SEQUENCE:
1048  all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
1049  errormsg = gettext_noop("invalid privilege type %s for sequence");
1050  break;
1051  case OBJECT_FUNCTION:
1052  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1053  errormsg = gettext_noop("invalid privilege type %s for function");
1054  break;
1055  case OBJECT_PROCEDURE:
1056  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1057  errormsg = gettext_noop("invalid privilege type %s for procedure");
1058  break;
1059  case OBJECT_ROUTINE:
1060  all_privileges = ACL_ALL_RIGHTS_FUNCTION;
1061  errormsg = gettext_noop("invalid privilege type %s for routine");
1062  break;
1063  case OBJECT_TYPE:
1064  all_privileges = ACL_ALL_RIGHTS_TYPE;
1065  errormsg = gettext_noop("invalid privilege type %s for type");
1066  break;
1067  case OBJECT_SCHEMA:
1068  all_privileges = ACL_ALL_RIGHTS_SCHEMA;
1069  errormsg = gettext_noop("invalid privilege type %s for schema");
1070  break;
1071  default:
1072  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
1073  (int) action->objtype);
1074  /* keep compiler quiet */
1075  all_privileges = ACL_NO_RIGHTS;
1076  errormsg = NULL;
1077  }
1078 
1079  if (action->privileges == NIL)
1080  {
1081  iacls.all_privs = true;
1082 
1083  /*
1084  * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1085  * depending on the object type
1086  */
1087  iacls.privileges = ACL_NO_RIGHTS;
1088  }
1089  else
1090  {
1091  iacls.all_privs = false;
1092  iacls.privileges = ACL_NO_RIGHTS;
1093 
1094  foreach(cell, action->privileges)
1095  {
1096  AccessPriv *privnode = (AccessPriv *) lfirst(cell);
1097  AclMode priv;
1098 
1099  if (privnode->cols)
1100  ereport(ERROR,
1101  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1102  errmsg("default privileges cannot be set for columns")));
1103 
1104  if (privnode->priv_name == NULL) /* parser mistake? */
1105  elog(ERROR, "AccessPriv node must specify privilege");
1106  priv = string_to_privilege(privnode->priv_name);
1107 
1108  if (priv & ~((AclMode) all_privileges))
1109  ereport(ERROR,
1110  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
1111  errmsg(errormsg, privilege_to_string(priv))));
1112 
1113  iacls.privileges |= priv;
1114  }
1115  }
1116 
1117  if (rolespecs == NIL)
1118  {
1119  /* Set permissions for myself */
1120  iacls.roleid = GetUserId();
1121 
1122  SetDefaultACLsInSchemas(&iacls, nspnames);
1123  }
1124  else
1125  {
1126  /* Look up the role OIDs and do permissions checks */
1127  ListCell *rolecell;
1128 
1129  foreach(rolecell, rolespecs)
1130  {
1131  RoleSpec *rolespec = lfirst(rolecell);
1132 
1133  iacls.roleid = get_rolespec_oid(rolespec, false);
1134 
1135  if (!has_privs_of_role(GetUserId(), iacls.roleid))
1136  ereport(ERROR,
1137  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1138  errmsg("permission denied to change default privileges")));
1139 
1140  SetDefaultACLsInSchemas(&iacls, nspnames);
1141  }
1142  }
1143 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4969
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5289
#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:2583
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
Definition: aclchk.c:1151
static const char * privilege_to_string(AclMode privilege)
Definition: aclchk.c:2626
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
#define stmt
Definition: indent_codes.h:59
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
List * lappend_oid(List *list, Oid datum)
Definition: list.c:374
Oid GetUserId(void)
Definition: miscinit.c:510
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:396
uint64 AclMode
Definition: parsenodes.h:81
#define ACL_NO_RIGHTS
Definition: parsenodes.h:99
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
char * priv_name
Definition: parsenodes.h:2366
List * cols
Definition: parsenodes.h:2367
char * defname
Definition: parsenodes.h:810
Node * arg
Definition: parsenodes.h:811
bool grant_option
Definition: aclchk.c:96
AclMode privileges
Definition: aclchk.c:94
List * grantees
Definition: aclchk.c:95
DropBehavior behavior
Definition: aclchk.c:97
ObjectType objtype
Definition: aclchk.c:92
Definition: pg_list.h:54
RoleSpecType roletype
Definition: parsenodes.h:402

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

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

References ACL_ALL_RIGHTS_COLUMN, ACL_NUM, aclconcat(), acldefault(), aclmembers(), attnum, 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 2131 of file aclchk.c.

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

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, 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, SearchSysCache1(), select_best_grantor(), SysCacheGetAttr(), SysCacheGetAttrNotNull(), HeapTupleData::t_self, table_close(), table_open(), updateAclDependencies(), and values.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Language_check()

static void ExecGrant_Language_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2266 of file aclchk.c.

2267 {
2268  Form_pg_language pg_language_tuple;
2269 
2270  pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
2271 
2272  if (!pg_language_tuple->lanpltrusted)
2273  ereport(ERROR,
2274  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2275  errmsg("language \"%s\" is not trusted",
2276  NameStr(pg_language_tuple->lanname)),
2277  errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2278  "because only superusers can use untrusted languages.")));
2279 }
int errdetail(const char *fmt,...)
Definition: elog.c:1202
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 2282 of file aclchk.c.

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

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

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, PARAMETERACLOID, 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 1803 of file aclchk.c.

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

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, 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(), RELOID, restrict_and_check_grant(), RowExclusiveLock, SearchSysCache1(), select_best_grantor(), string_to_privilege(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), updateAclDependencies(), values, and WARNING.

Referenced by ExecGrantStmt_oids().

◆ ExecGrant_Type_check()

static void ExecGrant_Type_check ( InternalGrant istmt,
HeapTuple  tuple 
)
static

Definition at line 2418 of file aclchk.c.

2419 {
2420  Form_pg_type pg_type_tuple;
2421 
2422  pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
2423 
2424  if (IsTrueArrayType(pg_type_tuple))
2425  ereport(ERROR,
2426  (errcode(ERRCODE_INVALID_GRANT_OPERATION),
2427  errmsg("cannot set privileges of array types"),
2428  errhint("Set the privileges of the element type instead.")));
2429 
2430  /* Used GRANT DOMAIN on a non-domain? */
2431  if (istmt->objtype == OBJECT_DOMAIN &&
2432  pg_type_tuple->typtype != TYPTYPE_DOMAIN)
2433  ereport(ERROR,
2434  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2435  errmsg("\"%s\" is not a domain",
2436  NameStr(pg_type_tuple->typname))));
2437 }
int errhint(const char *fmt,...)
Definition: elog.c:1316
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261

References ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, NameStr, OBJECT_DOMAIN, and InternalGrant::objtype.

Referenced by ExecGrantStmt_oids().

◆ ExecGrantStmt_oids()

static void ExecGrantStmt_oids ( InternalGrant istmt)
static

Definition at line 592 of file aclchk.c.

593 {
594  switch (istmt->objtype)
595  {
596  case OBJECT_TABLE:
597  case OBJECT_SEQUENCE:
598  ExecGrant_Relation(istmt);
599  break;
600  case OBJECT_DATABASE:
601  ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
602  break;
603  case OBJECT_DOMAIN:
604  case OBJECT_TYPE:
606  break;
607  case OBJECT_FDW:
608  ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
609  break;
611  ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
612  break;
613  case OBJECT_FUNCTION:
614  case OBJECT_PROCEDURE:
615  case OBJECT_ROUTINE:
616  ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
617  break;
618  case OBJECT_LANGUAGE:
620  break;
621  case OBJECT_LARGEOBJECT:
622  ExecGrant_Largeobject(istmt);
623  break;
624  case OBJECT_SCHEMA:
625  ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
626  break;
627  case OBJECT_TABLESPACE:
628  ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
629  break;
631  ExecGrant_Parameter(istmt);
632  break;
633  default:
634  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
635  (int) istmt->objtype);
636  }
637 
638  /*
639  * Pass the info to event triggers about the just-executed GRANT. Note
640  * that we prefer to do it after actually executing it, because that gives
641  * the functions a chance to adjust the istmt with privileges actually
642  * granted.
643  */
646 }
#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:2418
static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs, void(*object_check)(InternalGrant *istmt, HeapTuple tuple))
Definition: aclchk.c:2131
static void ExecGrant_Largeobject(InternalGrant *istmt)
Definition: aclchk.c:2282
static void ExecGrant_Parameter(InternalGrant *istmt)
Definition: aclchk.c:2440
static void ExecGrant_Relation(InternalGrant *istmt)
Definition: aclchk.c:1803
static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
Definition: aclchk.c:2266
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 382 of file aclchk.c.

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

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

1616 {
1617  AttrNumber curr_att;
1618 
1619  Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
1620  for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
1621  curr_att <= classForm->relnatts;
1622  curr_att++)
1623  {
1624  HeapTuple attTuple;
1625  bool isdropped;
1626 
1627  if (curr_att == InvalidAttrNumber)
1628  continue;
1629 
1630  /* Views don't have any system columns at all */
1631  if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
1632  continue;
1633 
1634  attTuple = SearchSysCache2(ATTNUM,
1635  ObjectIdGetDatum(table_oid),
1636  Int16GetDatum(curr_att));
1637  if (!HeapTupleIsValid(attTuple))
1638  elog(ERROR, "cache lookup failed for attribute %d of relation %u",
1639  curr_att, table_oid);
1640 
1641  isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
1642 
1643  ReleaseSysCache(attTuple);
1644 
1645  /* ignore dropped columns */
1646  if (isdropped)
1647  continue;
1648 
1649  col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
1650  }
1651 }
#define InvalidAttrNumber
Definition: attnum.h:23
Assert(fmt[strlen(fmt) - 1] !='\n')

References Assert(), ATTNUM, 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 1579 of file aclchk.c.

1583 {
1584  ListCell *cell;
1585 
1586  foreach(cell, colnames)
1587  {
1588  char *colname = strVal(lfirst(cell));
1590 
1591  attnum = get_attnum(table_oid, colname);
1592  if (attnum == InvalidAttrNumber)
1593  ereport(ERROR,
1594  (errcode(ERRCODE_UNDEFINED_COLUMN),
1595  errmsg("column \"%s\" of relation \"%s\" does not exist",
1596  colname, get_rel_name(table_oid))));
1598  if (attnum <= 0 || attnum >= num_col_privileges)
1599  elog(ERROR, "column number out of range"); /* safety check */
1600  col_privileges[attnum] |= this_privileges;
1601  }
1602 }
AttrNumber get_attnum(Oid relid, const char *attname)
Definition: lsyscache.c:857
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1910
#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 4096 of file aclchk.c.

4097 {
4098  Acl *result = NULL;
4099  HeapTuple tuple;
4100 
4102  ObjectIdGetDatum(roleId),
4103  ObjectIdGetDatum(nsp_oid),
4104  CharGetDatum(objtype));
4105 
4106  if (HeapTupleIsValid(tuple))
4107  {
4108  Datum aclDatum;
4109  bool isNull;
4110 
4111  aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
4112  Anum_pg_default_acl_defaclacl,
4113  &isNull);
4114  if (!isNull)
4115  result = DatumGetAclPCopy(aclDatum);
4116  ReleaseSysCache(tuple);
4117  }
4118 
4119  return result;
4120 }
static Datum CharGetDatum(char X)
Definition: postgres.h:122
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:840
@ DEFACLROLENSPOBJ
Definition: syscache.h:56

References CharGetDatum(), DatumGetAclPCopy, DEFACLROLENSPOBJ, 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 4131 of file aclchk.c.

4132 {
4133  Acl *result;
4134  Acl *glob_acl;
4135  Acl *schema_acl;
4136  Acl *def_acl;
4137  char defaclobjtype;
4138 
4139  /*
4140  * Use NULL during bootstrap, since pg_default_acl probably isn't there
4141  * yet.
4142  */
4144  return NULL;
4145 
4146  /* Check if object type is supported in pg_default_acl */
4147  switch (objtype)
4148  {
4149  case OBJECT_TABLE:
4150  defaclobjtype = DEFACLOBJ_RELATION;
4151  break;
4152 
4153  case OBJECT_SEQUENCE:
4154  defaclobjtype = DEFACLOBJ_SEQUENCE;
4155  break;
4156 
4157  case OBJECT_FUNCTION:
4158  defaclobjtype = DEFACLOBJ_FUNCTION;
4159  break;
4160 
4161  case OBJECT_TYPE:
4162  defaclobjtype = DEFACLOBJ_TYPE;
4163  break;
4164 
4165  case OBJECT_SCHEMA:
4166  defaclobjtype = DEFACLOBJ_NAMESPACE;
4167  break;
4168 
4169  default:
4170  return NULL;
4171  }
4172 
4173  /* Look up the relevant pg_default_acl entries */
4174  glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
4175  schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
4176 
4177  /* Quick out if neither entry exists */
4178  if (glob_acl == NULL && schema_acl == NULL)
4179  return NULL;
4180 
4181  /* We need to know the hard-wired default value, too */
4182  def_acl = acldefault(objtype, ownerId);
4183 
4184  /* If there's no global entry, substitute the hard-wired default */
4185  if (glob_acl == NULL)
4186  glob_acl = def_acl;
4187 
4188  /* Merge in any per-schema privileges */
4189  result = aclmerge(glob_acl, schema_acl, ownerId);
4190 
4191  /*
4192  * For efficiency, we want to return NULL if the result equals default.
4193  * This requires sorting both arrays to get an accurate comparison.
4194  */
4195  aclitemsort(result);
4196  aclitemsort(def_acl);
4197  if (aclequal(result, def_acl))
4198  result = NULL;
4199 
4200  return result;
4201 }
void aclitemsort(Acl *acl)
Definition: acl.c:522
Acl * aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
Definition: acl.c:478
static Acl * get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
Definition: aclchk.c:4096
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:405
#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 928 of file aclchk.c.

929 {
930  List *relations = NIL;
931  ScanKeyData key[2];
932  Relation rel;
933  TableScanDesc scan;
934  HeapTuple tuple;
935 
936  ScanKeyInit(&key[0],
937  Anum_pg_class_relnamespace,
938  BTEqualStrategyNumber, F_OIDEQ,
939  ObjectIdGetDatum(namespaceId));
940  ScanKeyInit(&key[1],
941  Anum_pg_class_relkind,
942  BTEqualStrategyNumber, F_CHAREQ,
943  CharGetDatum(relkind));
944 
945  rel = table_open(RelationRelationId, AccessShareLock);
946  scan = table_beginscan_catalog(rel, 2, key);
947 
948  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
949  {
950  Oid oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
951 
952  relations = lappend_oid(relations, oid);
953  }
954 
955  table_endscan(scan);
957 
958  return relations;
959 }
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition: heapam.c:1093
#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:1011

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

4073 {
4074  bool result = false;
4075  HeapTuple utup;
4076 
4077  /* Superusers bypass all permission checking. */
4078  if (superuser_arg(roleid))
4079  return true;
4080 
4081  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4082  if (HeapTupleIsValid(utup))
4083  {
4084  result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
4085  ReleaseSysCache(utup);
4086  }
4087  return result;
4088 }
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
@ AUTHOID
Definition: syscache.h:45

References AUTHOID, 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 4053 of file aclchk.c.

4054 {
4055  bool result = false;
4056  HeapTuple utup;
4057 
4058  /* Superusers bypass all permission checking. */
4059  if (superuser_arg(roleid))
4060  return true;
4061 
4062  utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
4063  if (HeapTupleIsValid(utup))
4064  {
4065  result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
4066  ReleaseSysCache(utup);
4067  }
4068  return result;
4069 }
bool rolcreaterole
Definition: pg_authid.h:37

References AUTHOID, 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 172 of file aclchk.c.

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

◆ object_aclcheck()

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

Definition at line 3775 of file aclchk.c.

3776 {
3777  if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0)
3778  return ACLCHECK_OK;
3779  else
3780  return ACLCHECK_NO_PRIV;
3781 }
@ ACLMASK_ANY
Definition: acl.h:177
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3069
static PgChecksumMode mode
Definition: pg_checksums.c:65

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

Referenced by AggregateCreate(), AlterExtensionNamespace(), AlterForeignServerOwner_internal(), AlterObjectNamespace_internal(), AlterObjectOwner_internal(), AlterObjectRename_internal(), AlterPublicationOwner_internal(), AlterSchemaOwner_internal(), AlterSubscriptionOwner_internal(), AlterTableMoveAll(), AlterTypeOwner(), ATExecAddColumn(), 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(), has_database_privilege_id_id(), has_database_privilege_id_name(), has_database_privilege_name(), has_database_privilege_name_id(), has_database_privilege_name_name(), has_foreign_data_wrapper_privilege_id(), has_foreign_data_wrapper_privilege_id_id(), has_foreign_data_wrapper_privilege_id_name(), has_foreign_data_wrapper_privilege_name(), has_foreign_data_wrapper_privilege_name_id(), has_foreign_data_wrapper_privilege_name_name(), has_function_privilege_id(), has_function_privilege_id_id(), has_function_privilege_id_name(), has_function_privilege_name(), has_function_privilege_name_id(), has_function_privilege_name_name(), has_language_privilege_id(), has_language_privilege_id_id(), has_language_privilege_id_name(), has_language_privilege_name(), has_language_privilege_name_id(), has_language_privilege_name_name(), has_schema_privilege_id(), has_schema_privilege_id_id(), has_schema_privilege_id_name(), has_schema_privilege_name(), has_schema_privilege_name_id(), has_schema_privilege_name_name(), has_server_privilege_id(), has_server_privilege_id_id(), has_server_privilege_id_name(), has_server_privilege_name(), has_server_privilege_name_id(), has_server_privilege_name_name(), has_tablespace_privilege_id(), has_tablespace_privilege_id_id(), has_tablespace_privilege_id_name(), has_tablespace_privilege_name(), has_tablespace_privilege_name_id(), has_tablespace_privilege_name_name(), has_type_privilege_id(), has_type_privilege_id_id(), has_type_privilege_id_name(), has_type_privilege_name(), has_type_privilege_name_id(), 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(), pg_namespace_aclmask(), PrepareTempTablespaces(), RangeVarCallbackForAlterRelation(), RangeVarGetAndCheckCreationNamespace(), recomputeNamespacePath(), ReindexMultipleInternal(), RenameSchema(), transformTableLikeClause(), user_mapping_ddl_aclcheck(), ValidateJoinEstimator(), and ValidateRestrictionEstimator().

◆ object_aclmask()

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

Definition at line 3069 of file aclchk.c.

3071 {
3072  int cacheid;
3073  AclMode result;
3074  HeapTuple tuple;
3075  Datum aclDatum;
3076  bool isNull;
3077  Acl *acl;
3078  Oid ownerId;
3079 
3080  /* Special cases */
3081  switch (classid)
3082  {
3083  case NamespaceRelationId:
3084  return pg_namespace_aclmask(objectid, roleid, mask, how);
3085  case TypeRelationId:
3086  return pg_type_aclmask(objectid, roleid, mask, how);
3087  }
3088 
3089  /* Even more special cases */
3090  Assert(classid != RelationRelationId); /* should use pg_class_acl* */
3091  Assert(classid != LargeObjectMetadataRelationId); /* should use
3092  * pg_largeobject_acl* */
3093 
3094  /* Superusers bypass all permission checking. */
3095  if (superuser_arg(roleid))
3096  return mask;
3097 
3098  /*
3099  * Get the objects's ACL from its catalog
3100  */
3101 
3102  cacheid = get_object_catcache_oid(classid);
3103 
3104  tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3105  if (!HeapTupleIsValid(tuple))
3106  ereport(ERROR,
3107  (errcode(ERRCODE_UNDEFINED_DATABASE),
3108  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
3109 
3110  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3111  tuple,
3112  get_object_attnum_owner(classid)));
3113 
3114  aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
3115  &isNull);
3116  if (isNull)
3117  {
3118  /* No ACL, so build default ACL */
3119  acl = acldefault(get_object_type(classid, objectid), ownerId);
3120  aclDatum = (Datum) 0;
3121  }
3122  else
3123  {
3124  /* detoast ACL if necessary */
3125  acl = DatumGetAclP(aclDatum);
3126  }
3127 
3128  result = aclmask(acl, roleid, ownerId, mask, how);
3129 
3130  /* if we have a detoasted copy, free it */
3131  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3132  pfree(acl);
3133 
3134  ReleaseSysCache(tuple);
3135 
3136  return result;
3137 }
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1359
#define DatumGetAclP(X)
Definition: acl.h:120
static AclMode pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3698
static AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3606
char * Pointer
Definition: c.h:467
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(), pg_type_aclmask(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), SysCacheGetAttr(), and SysCacheGetAttrNotNull().

Referenced by object_aclcheck(), and pg_aclmask().

◆ object_ownercheck()

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

Definition at line 3976 of file aclchk.c.

3977 {
3978  int cacheid;
3979  Oid ownerId;
3980 
3981  /* Superusers bypass all permission checking. */
3982  if (superuser_arg(roleid))
3983  return true;
3984 
3985  cacheid = get_object_catcache_oid(classid);
3986  if (cacheid != -1)
3987  {
3988  HeapTuple tuple;
3989 
3990  tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
3991  if (!HeapTupleIsValid(tuple))
3992  ereport(ERROR,
3993  (errcode(ERRCODE_UNDEFINED_OBJECT),
3994  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
3995 
3996  ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
3997  tuple,
3998  get_object_attnum_owner(classid)));
3999  ReleaseSysCache(tuple);
4000  }
4001  else
4002  {
4003  /* for catalogs without an appropriate syscache */
4004 
4005  Relation rel;
4006  ScanKeyData entry[1];
4007  SysScanDesc scan;
4008  HeapTuple tuple;
4009  bool isnull;
4010 
4011  rel = table_open(classid, AccessShareLock);
4012 
4013  ScanKeyInit(&entry[0],
4014  get_object_attnum_oid(classid),
4015  BTEqualStrategyNumber, F_OIDEQ,
4016  ObjectIdGetDatum(objectid));
4017 
4018  scan = systable_beginscan(rel,
4019  get_object_oid_index(classid), true,
4020  NULL, 1, entry);
4021 
4022  tuple = systable_getnext(scan);
4023  if (!HeapTupleIsValid(tuple))
4024  ereport(ERROR,
4025  (errcode(ERRCODE_UNDEFINED_OBJECT),
4026  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
4027 
4028  ownerId = DatumGetObjectId(heap_getattr(tuple,
4029  get_object_attnum_owner(classid),
4030  RelationGetDescr(rel),
4031  &isnull));
4032  Assert(!isnull);
4033 
4034  systable_endscan(scan);
4036  }
4037 
4038  return has_privs_of_role(roleid, ownerId);
4039 }
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(), user_mapping_ddl_aclcheck(), and vacuum_is_permitted_for_relation().

◆ objectNamesToOids()

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

Definition at line 659 of file aclchk.c.

660 {
661  List *objects = NIL;
662  ListCell *cell;
663 
664  Assert(objnames != NIL);
665 
666  switch (objtype)
667  {
668  case OBJECT_TABLE:
669  case OBJECT_SEQUENCE:
670  foreach(cell, objnames)
671  {
672  RangeVar *relvar = (RangeVar *) lfirst(cell);
673  Oid relOid;
674 
675  relOid = RangeVarGetRelid(relvar, NoLock, false);
676  objects = lappend_oid(objects, relOid);
677  }
678  break;
679  case OBJECT_DATABASE:
680  foreach(cell, objnames)
681  {
682  char *dbname = strVal(lfirst(cell));
683  Oid dbid;
684 
685  dbid = get_database_oid(dbname, false);
686  objects = lappend_oid(objects, dbid);
687  }
688  break;
689  case OBJECT_DOMAIN:
690  case OBJECT_TYPE:
691  foreach(cell, objnames)
692  {
693  List *typname = (List *) lfirst(cell);
694  Oid oid;
695 
697  objects = lappend_oid(objects, oid);
698  }
699  break;
700  case OBJECT_FUNCTION:
701  foreach(cell, objnames)
702  {
703  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
704  Oid funcid;
705 
706  funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
707  objects = lappend_oid(objects, funcid);
708  }
709  break;
710  case OBJECT_LANGUAGE:
711  foreach(cell, objnames)
712  {
713  char *langname = strVal(lfirst(cell));
714  Oid oid;
715 
716  oid = get_language_oid(langname, false);
717  objects = lappend_oid(objects, oid);
718  }
719  break;
720  case OBJECT_LARGEOBJECT:
721  foreach(cell, objnames)
722  {
723  Oid lobjOid = oidparse(lfirst(cell));
724 
725  if (!LargeObjectExists(lobjOid))
726  ereport(ERROR,
727  (errcode(ERRCODE_UNDEFINED_OBJECT),
728  errmsg("large object %u does not exist",
729  lobjOid)));
730 
731  objects = lappend_oid(objects, lobjOid);
732  }
733  break;
734  case OBJECT_SCHEMA:
735  foreach(cell, objnames)
736  {
737  char *nspname = strVal(lfirst(cell));
738  Oid oid;
739 
740  oid = get_namespace_oid(nspname, false);
741  objects = lappend_oid(objects, oid);
742  }
743  break;
744  case OBJECT_PROCEDURE:
745  foreach(cell, objnames)
746  {
747  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
748  Oid procid;
749 
750  procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
751  objects = lappend_oid(objects, procid);
752  }
753  break;
754  case OBJECT_ROUTINE:
755  foreach(cell, objnames)
756  {
757  ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
758  Oid routid;
759 
760  routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
761  objects = lappend_oid(objects, routid);
762  }
763  break;
764  case OBJECT_TABLESPACE:
765  foreach(cell, objnames)
766  {
767  char *spcname = strVal(lfirst(cell));
768  Oid spcoid;
769 
770  spcoid = get_tablespace_oid(spcname, false);
771  objects = lappend_oid(objects, spcoid);
772  }
773  break;
774  case OBJECT_FDW:
775  foreach(cell, objnames)
776  {
777  char *fdwname = strVal(lfirst(cell));
778  Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
779 
780  objects = lappend_oid(objects, fdwid);
781  }
782  break;
784  foreach(cell, objnames)
785  {
786  char *srvname = strVal(lfirst(cell));
787  Oid srvid = get_foreign_server_oid(srvname, false);
788 
789  objects = lappend_oid(objects, srvid);
790  }
791  break;
793  foreach(cell, objnames)
794  {
795  /*
796  * In this code we represent a GUC by the OID of its entry in
797  * pg_parameter_acl, which we have to manufacture here if it
798  * doesn't exist yet. (That's a hack for sure, but it avoids
799  * messing with all the GRANT/REVOKE infrastructure that
800  * expects to use OIDs for object identities.) However, if
801  * this is a REVOKE, we can instead just ignore any GUCs that
802  * don't have such an entry, as they must not have any
803  * privileges needing removal.
804  */
805  char *parameter = strVal(lfirst(cell));
806  Oid parameterId = ParameterAclLookup(parameter, true);
807 
808  if (!OidIsValid(parameterId) && is_grant)
809  {
810  parameterId = ParameterAclCreate(parameter);
811 
812  /*
813  * Prevent error when processing duplicate objects, and
814  * make this new entry visible so that ExecGrant_Parameter
815  * can update it.
816  */
818  }
819  if (OidIsValid(parameterId))
820  objects = lappend_oid(objects, parameterId);
821  }
822  break;
823  default:
824  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
825  (int) objtype);
826  }
827 
828  return objects;
829 }
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1432
#define OidIsValid(objectId)
Definition: c.h:759
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:2976
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:690
Oid get_foreign_data_wrapper_oid(const char *fdwname, bool missing_ok)
Definition: foreign.c:667
#define NoLock
Definition: lockdefs.h:34
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:459
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3086
#define RangeVarGetRelid(relation, lockmode, missing_ok)
Definition: namespace.h:79
Oid oidparse(Node *node)
Definition: oid.c:234
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2205
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
bool LargeObjectExists(Oid loid)
Oid ParameterAclLookup(const char *parameter, bool missing_ok)
Oid ParameterAclCreate(const char *parameter)
NameData typname
Definition: pg_type.h:41
Oid get_language_oid(const char *langname, bool missing_ok)
Definition: proclang.c:228
char * dbname
Definition: streamutil.c:51

References Assert(), CommandCounterIncrement(), dbname, elog(), ereport, errcode(), errmsg(), ERROR, get_database_oid(), get_foreign_data_wrapper_oid(), get_foreign_server_oid(), get_language_oid(), get_namespace_oid(), get_tablespace_oid(), lappend_oid(), LargeObjectExists(), lfirst, LookupFuncWithArgs(), makeTypeNameFromNameList(), NIL, NoLock, 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, OidIsValid, oidparse(), ParameterAclCreate(), ParameterAclLookup(), RangeVarGetRelid, strVal, typenameTypeId(), and typname.

Referenced by ExecuteGrantStmt().

◆ objectsInSchemaToOids()

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

Definition at line 839 of file aclchk.c.

840 {
841  List *objects = NIL;
842  ListCell *cell;
843 
844  foreach(cell, nspnames)
845  {
846  char *nspname = strVal(lfirst(cell));
847  Oid namespaceId;
848  List *objs;
849 
850  namespaceId = LookupExplicitNamespace(nspname, false);
851 
852  switch (objtype)
853  {
854  case OBJECT_TABLE:
855  objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
856  objects = list_concat(objects, objs);
857  objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
858  objects = list_concat(objects, objs);
859  objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
860  objects = list_concat(objects, objs);
861  objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
862  objects = list_concat(objects, objs);
863  objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
864  objects = list_concat(objects, objs);
865  break;
866  case OBJECT_SEQUENCE:
867  objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
868  objects = list_concat(objects, objs);
869  break;
870  case OBJECT_FUNCTION:
871  case OBJECT_PROCEDURE:
872  case OBJECT_ROUTINE:
873  {
874  ScanKeyData key[2];
875  int keycount;
876  Relation rel;
877  TableScanDesc scan;
878  HeapTuple tuple;
879 
880  keycount = 0;
881  ScanKeyInit(&key[keycount++],
882  Anum_pg_proc_pronamespace,
883  BTEqualStrategyNumber, F_OIDEQ,
884  ObjectIdGetDatum(namespaceId));
885 
886  if (objtype == OBJECT_FUNCTION)
887  /* includes aggregates and window functions */
888  ScanKeyInit(&key[keycount++],
889  Anum_pg_proc_prokind,
890  BTEqualStrategyNumber, F_CHARNE,
891  CharGetDatum(PROKIND_PROCEDURE));
892  else if (objtype == OBJECT_PROCEDURE)
893  ScanKeyInit(&key[keycount++],
894  Anum_pg_proc_prokind,
895  BTEqualStrategyNumber, F_CHAREQ,
896  CharGetDatum(PROKIND_PROCEDURE));
897 
898  rel = table_open(ProcedureRelationId, AccessShareLock);
899  scan = table_beginscan_catalog(rel, keycount, key);
900 
901  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
902  {
903  Oid oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
904 
905  objects = lappend_oid(objects, oid);
906  }
907 
908  table_endscan(scan);
910  }
911  break;
912  default:
913  /* should not happen */
914  elog(ERROR, "unrecognized GrantStmt.objtype: %d",
915  (int) objtype);
916  }
917  }
918 
919  return objects;
920 }
static List * getRelationsInNamespace(Oid namespaceId, char relkind)
Definition: aclchk.c:928
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2936
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 3004 of file aclchk.c.

3006 {
3007  switch (objtype)
3008  {
3009  case OBJECT_COLUMN:
3010  return
3011  pg_class_aclmask(object_oid, roleid, mask, how) |
3012  pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
3013  case OBJECT_TABLE:
3014  case OBJECT_SEQUENCE:
3015  return pg_class_aclmask(object_oid, roleid, mask, how);
3016  case OBJECT_DATABASE:
3017  return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
3018  case OBJECT_FUNCTION:
3019  return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
3020  case OBJECT_LANGUAGE:
3021  return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
3022  case OBJECT_LARGEOBJECT:
3023  return pg_largeobject_aclmask_snapshot(object_oid, roleid,
3024  mask, how, NULL);
3025  case OBJECT_PARAMETER_ACL:
3026  return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
3027  case OBJECT_SCHEMA:
3028  return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
3029  case OBJECT_STATISTIC_EXT:
3030  elog(ERROR, "grantable rights not supported for statistics objects");
3031  /* not reached, but keep compiler quiet */
3032  return ACL_NO_RIGHTS;
3033  case OBJECT_TABLESPACE:
3034  return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
3035  case OBJECT_FDW:
3036  return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
3037  case OBJECT_FOREIGN_SERVER:
3038  return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
3039  case OBJECT_EVENT_TRIGGER:
3040  elog(ERROR, "grantable rights not supported for event triggers");
3041  /* not reached, but keep compiler quiet */
3042  return ACL_NO_RIGHTS;
3043  case OBJECT_TYPE:
3044  return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
3045  default:
3046  elog(ERROR, "unrecognized object type: %d",
3047  (int) objtype);
3048  /* not reached, but keep compiler quiet */
3049  return ACL_NO_RIGHTS;
3050  }
3051 }
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid, AclMode mask, AclMaskHow how, Snapshot snapshot)
Definition: aclchk.c:3533
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3148
static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3474
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3267

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

3796 {
3797  return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
3798 }
AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3808

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

3840 {
3841  AclResult result;
3842  HeapTuple classTuple;
3843  Form_pg_class classForm;
3844  AttrNumber nattrs;
3845  AttrNumber curr_att;
3846 
3847  /*
3848  * Must fetch pg_class row to check number of attributes. As in
3849  * pg_attribute_aclmask, we prefer to return "no privileges" instead of
3850  * throwing an error if we get any unexpected lookup errors.
3851  */
3852  classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
3853  if (!HeapTupleIsValid(classTuple))
3854  return ACLCHECK_NO_PRIV;
3855  classForm = (Form_pg_class) GETSTRUCT(classTuple);
3856 
3857  nattrs = classForm->relnatts;
3858 
3859  ReleaseSysCache(classTuple);
3860 
3861  /*
3862  * Initialize result in case there are no non-dropped columns. We want to
3863  * report failure in such cases for either value of 'how'.
3864  */
3865  result = ACLCHECK_NO_PRIV;
3866 
3867  for (curr_att = 1; curr_att <= nattrs; curr_att++)
3868  {
3869  HeapTuple attTuple;
3870  AclMode attmask;
3871 
3872  attTuple = SearchSysCache2(ATTNUM,
3873  ObjectIdGetDatum(table_oid),
3874  Int16GetDatum(curr_att));
3875  if (!HeapTupleIsValid(attTuple))
3876  continue;
3877 
3878  /* ignore dropped columns */
3879  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
3880  {
3881  ReleaseSysCache(attTuple);
3882  continue;
3883  }
3884 
3885  /*
3886  * Here we hard-wire knowledge that the default ACL for a column
3887  * grants no privileges, so that we can fall out quickly in the very
3888  * common case where attacl is null.
3889  */
3890  if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
3891  attmask = 0;
3892  else
3893  attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
3894  mode, ACLMASK_ANY);
3895 
3896  ReleaseSysCache(attTuple);
3897 
3898  if (attmask != 0)
3899  {
3900  result = ACLCHECK_OK;
3901  if (how == ACLMASK_ANY)
3902  break; /* succeed on any success */
3903  }
3904  else
3905  {
3906  result = ACLCHECK_NO_PRIV;
3907  if (how == ACLMASK_ALL)
3908  break; /* fail on any failure */
3909  }
3910  }
3911 
3912  return result;
3913 }
AclResult
Definition: acl.h:182
@ ACLMASK_ALL
Definition: acl.h:176
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:359

References ACLCHECK_NO_PRIV, ACLCHECK_OK, ACLMASK_ALL, ACLMASK_ANY, ATTNUM, GETSTRUCT, heap_attisnull(), HeapTupleIsValid, Int16GetDatum(), mode, ObjectIdGetDatum(), pg_attribute_aclmask(), ReleaseSysCache(), RELOID, SearchSysCache1(), and SearchSysCache2().

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

◆ pg_attribute_aclcheck_ext()

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

Definition at line 3808 of file aclchk.c.

3810 {
3811  if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
3812  ACLMASK_ANY, is_missing) != 0)
3813  return ACLCHECK_OK;
3814  else
3815  return ACLCHECK_NO_PRIV;
3816 }
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3162

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

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

References attnum, and pg_attribute_aclmask_ext().

Referenced by pg_aclmask(), and pg_attribute_aclcheck_all().

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

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

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

Referenced by pg_attribute_aclcheck_ext(), and pg_attribute_aclmask().

◆ pg_class_aclcheck()

AclResult pg_class_aclcheck ( Oid  table_oid,
Oid  roleid,
AclMode  mode 
)

Definition at line 3923 of file aclchk.c.

3924 {
3925  return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
3926 }
AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid, AclMode mode, bool *is_missing)
Definition: aclchk.c:3935

References mode, and pg_class_aclcheck_ext().

Referenced by BuildIndexValueDescription(), checkFkeyPermissions(), cluster_is_permitted_for_relation(), CreateTriggerFiringOn(), currtid_internal(), currval_oid(), do_setval(), examine_simple_variable(), examine_variable(), ExecBuildSlotPartitionKeyDescription(), ExecBuildSlotValueDescription(), get_rel_from_relname(), has_any_column_privilege_id(), has_any_column_privilege_id_id(), has_any_column_privilege_id_name(), has_any_column_privilege_name(), has_any_column_privilege_name_id(), has_any_column_privilege_name_name(), has_partition_ancestor_privs(), has_sequence_privilege_id(), has_sequence_privilege_id_id(), has_sequence_privilege_id_name(), has_sequence_privilege_name(), has_sequence_privilege_name_id(), has_sequence_privilege_name_name(), has_table_privilege_id(), has_table_privilege_id_id(), has_table_privilege_id_name(), has_table_privilege_name(), has_table_privilege_name_id(), has_table_privilege_name_name(), lastval(), LockTableAclCheck(), LogicalRepSyncTableStart(), nextval_internal(), pg_prewarm(), pg_sequence_last_value(), pg_sequence_parameters(), pgrowlocks(), RangeVarCallbackForReindexIndex(), RangeVarCallbackMaintainsTable(), ReindexMultipleTables(), ri_ReportViolation(), statext_is_compatible_clause(), TargetPrivilegesCheck(), transformTableLikeClause(), truncate_check_perms(), and vacuum_is_permitted_for_relation().

◆ pg_class_aclcheck_ext()

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

Definition at line 3935 of file aclchk.c.

3937 {
3938  if (pg_class_aclmask_ext(table_oid, roleid, mode,
3939  ACLMASK_ANY, is_missing) != 0)
3940  return ACLCHECK_OK;
3941  else
3942  return ACLCHECK_NO_PRIV;
3943 }
static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how, bool *is_missing)
Definition: aclchk.c:3280

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

Referenced by column_privilege_check(), and pg_class_aclcheck().

◆ pg_class_aclmask()

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

Definition at line 3267 of file aclchk.c.

3269 {
3270  return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
3271 }

References pg_class_aclmask_ext().

Referenced by ExecCheckOneRelPerms(), and pg_aclmask().

◆ pg_class_aclmask_ext()

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

Definition at line 3280 of file aclchk.c.

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

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(), RELOID, 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 3962 of file aclchk.c.

3964 {
3965  if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
3966  ACLMASK_ANY, snapshot) != 0)
3967  return ACLCHECK_OK;
3968  else
3969  return ACLCHECK_NO_PRIV;
3970 }

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

Referenced by be_lo_put(), and inv_open().

◆ pg_largeobject_aclmask_snapshot()

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

Definition at line 3533 of file aclchk.c.

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

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

Referenced by pg_aclmask(), and pg_largeobject_aclcheck_snapshot().

◆ pg_namespace_aclmask()

static AclMode pg_namespace_aclmask ( Oid  nsp_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3606 of file aclchk.c.

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

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, NAMESPACEOID, object_aclcheck(), OBJECT_SCHEMA, ObjectIdGetDatum(), pfree(), ReleaseSysCache(), SearchSysCache1(), superuser_arg(), and SysCacheGetAttr().

Referenced by object_aclmask().

◆ pg_parameter_acl_aclmask()

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

Definition at line 3474 of file aclchk.c.

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

References acldefault(), aclmask(), DatumGetAclP, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, HeapTupleIsValid, OBJECT_PARAMETER_ACL, ObjectIdGetDatum(), PARAMETERACLOID, 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 3950 of file aclchk.c.

3951 {
3952  if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
3953  return ACLCHECK_OK;
3954  else
3955  return ACLCHECK_NO_PRIV;
3956 }
static AclMode pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3410
const char * name
Definition: encode.c:571

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

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

◆ pg_parameter_aclmask()

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

Definition at line 3410 of file aclchk.c.

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

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

Referenced by pg_parameter_aclcheck().

◆ pg_type_aclmask()

static AclMode pg_type_aclmask ( Oid  type_oid,
Oid  roleid,
AclMode  mask,
AclMaskHow  how 
)
static

Definition at line 3698 of file aclchk.c.

3699 {
3700  AclMode result;
3701  HeapTuple tuple;
3702  Datum aclDatum;
3703  bool isNull;
3704  Acl *acl;
3705  Oid ownerId;
3706 
3707  Form_pg_type typeForm;
3708 
3709  /* Bypass permission checks for superusers */
3710  if (superuser_arg(roleid))
3711  return mask;
3712 
3713  /*
3714  * Must get the type's tuple from pg_type
3715  */
3716  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
3717  if (!HeapTupleIsValid(tuple))
3718  ereport(ERROR,
3719  (errcode(ERRCODE_UNDEFINED_OBJECT),
3720  errmsg("type with OID %u does not exist",
3721  type_oid)));
3722  typeForm = (Form_pg_type) GETSTRUCT(tuple);
3723 
3724  /*
3725  * "True" array types don't manage permissions of their own; consult the
3726  * element type instead.
3727  */
3728  if (IsTrueArrayType(typeForm))
3729  {
3730  Oid elttype_oid = typeForm->typelem;
3731 
3732  ReleaseSysCache(tuple);
3733 
3734  tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
3735  /* this case is not a user-facing error, so elog not ereport */
3736  if (!HeapTupleIsValid(tuple))
3737  elog(ERROR, "cache lookup failed for type %u", elttype_oid);
3738  typeForm = (Form_pg_type) GETSTRUCT(tuple);
3739  }
3740 
3741  /*
3742  * Now get the type's owner and ACL from the tuple
3743  */
3744  ownerId = typeForm->typowner;
3745 
3746  aclDatum = SysCacheGetAttr(TYPEOID, tuple,
3747  Anum_pg_type_typacl, &isNull);
3748  if (isNull)
3749  {
3750  /* No ACL, so build default ACL */
3751  acl = acldefault(OBJECT_TYPE, ownerId);
3752  aclDatum = (Datum) 0;
3753  }
3754  else
3755  {
3756  /* detoast rel's ACL if necessary */
3757  acl = DatumGetAclP(aclDatum);
3758  }
3759 
3760  result = aclmask(acl, roleid, ownerId, mask, how);
3761 
3762  /* if we have a detoasted copy, free it */
3763  if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
3764  pfree(acl);
3765 
3766  ReleaseSysCache(tuple);
3767 
3768  return result;
3769 }
@ TYPEOID
Definition: syscache.h:114

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

Referenced by object_aclmask().

◆ privilege_to_string()

static const char * privilege_to_string ( AclMode  privilege)
static

Definition at line 2626 of file aclchk.c.

2627 {
2628  switch (privilege)
2629  {
2630  case ACL_INSERT:
2631  return "INSERT";
2632  case ACL_SELECT:
2633  return "SELECT";
2634  case ACL_UPDATE:
2635  return "UPDATE";
2636  case ACL_DELETE:
2637  return "DELETE";
2638  case ACL_TRUNCATE:
2639  return "TRUNCATE";
2640  case ACL_REFERENCES:
2641  return "REFERENCES";
2642  case ACL_TRIGGER:
2643  return "TRIGGER";
2644  case ACL_EXECUTE:
2645  return "EXECUTE";
2646  case ACL_USAGE:
2647  return "USAGE";
2648  case ACL_CREATE:
2649  return "CREATE";
2650  case ACL_CREATE_TEMP:
2651  return "TEMP";
2652  case ACL_CONNECT:
2653  return "CONNECT";
2654  case ACL_SET:
2655  return "SET";
2656  case ACL_ALTER_SYSTEM:
2657  return "ALTER SYSTEM";
2658  case ACL_MAINTAIN:
2659  return "MAINTAIN";
2660  default:
2661  elog(ERROR, "unrecognized privilege: %d", (int) privilege);
2662  }
2663  return NULL; /* appease compiler */
2664 }
#define ACL_SET
Definition: parsenodes.h:95
#define ACL_CONNECT
Definition: parsenodes.h:94
#define ACL_ALTER_SYSTEM
Definition: parsenodes.h:96
#define ACL_REFERENCES
Definition: parsenodes.h:88
#define ACL_EXECUTE
Definition: parsenodes.h:90
#define ACL_CREATE
Definition: parsenodes.h:92
#define ACL_TRIGGER
Definition: parsenodes.h:89

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

4209 {
4210  int nmembers;
4211  Oid *members;
4212 
4213  /* Nothing to do if ACL is defaulted */
4214  if (acl == NULL)
4215  return;
4216 
4217  /* Extract roles mentioned in ACL */
4218  nmembers = aclmembers(acl, &members);
4219 
4220  /* Update the shared dependency ACL info */
4221  updateAclDependencies(classId, objectId, objsubId,
4222  ownerId,
4223  0, NULL,
4224  nmembers, members);
4225 }

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

4481 {
4482  /*
4483  * Generally, we only record the initial privileges when an extension is
4484  * being created, but because we don't actually use CREATE EXTENSION
4485  * during binary upgrades with pg_upgrade, there is a variable to let us
4486  * know that the GRANT and REVOKE statements being issued, while this
4487  * variable is true, are for the initial privileges of the extension
4488  * object and therefore we need to record them.
4489  */
4491  return;
4492 
4493  recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
4494 }
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
Definition: aclchk.c:4509
bool binary_upgrade_record_init_privs
Definition: aclchk.c:105
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 4509 of file aclchk.c.

4510 {
4511  Relation relation;
4512  ScanKeyData key[3];
4513  SysScanDesc scan;
4514  HeapTuple tuple;
4515  HeapTuple oldtuple;
4516 
4517  relation = table_open(InitPrivsRelationId, RowExclusiveLock);
4518 
4519  ScanKeyInit(&key[0],
4520  Anum_pg_init_privs_objoid,
4521  BTEqualStrategyNumber, F_OIDEQ,
4522  ObjectIdGetDatum(objoid));
4523  ScanKeyInit(&key[1],
4524  Anum_pg_init_privs_classoid,
4525  BTEqualStrategyNumber, F_OIDEQ,
4526  ObjectIdGetDatum(classoid));
4527  ScanKeyInit(&key[2],
4528  Anum_pg_init_privs_objsubid,
4529  BTEqualStrategyNumber, F_INT4EQ,
4530  Int32GetDatum(objsubid));
4531 
4532  scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
4533  NULL, 3, key);
4534 
4535  /* There should exist only one entry or none. */
4536  oldtuple = systable_getnext(scan);
4537 
4538  /* If we find an entry, update it with the latest ACL. */
4539  if (HeapTupleIsValid(oldtuple))
4540  {
4541  Datum values[Natts_pg_init_privs] = {0};
4542  bool nulls[Natts_pg_init_privs] = {0};
4543  bool replace[Natts_pg_init_privs] = {0};
4544 
4545  /* If we have a new ACL to set, then update the row with it. */
4546  if (new_acl)
4547  {
4548  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4549  replace[Anum_pg_init_privs_initprivs - 1] = true;
4550 
4551  oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
4552  values, nulls, replace);
4553 
4554  CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
4555  }
4556  else
4557  {
4558  /* new_acl is NULL, so delete the entry we found. */
4559  CatalogTupleDelete(relation, &oldtuple->t_self);
4560  }
4561  }
4562  else
4563  {
4564  Datum values[Natts_pg_init_privs] = {0};
4565  bool nulls[Natts_pg_init_privs] = {0};
4566 
4567  /*
4568  * Only add a new entry if the new ACL is non-NULL.
4569  *
4570  * If we are passed in a NULL ACL and no entry exists, we can just
4571  * fall through and do nothing.
4572  */
4573  if (new_acl)
4574  {
4575  /* No entry found, so add it. */
4576  values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
4577  values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
4578  values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
4579 
4580  /* This function only handles initial privileges of extensions */
4581  values[Anum_pg_init_privs_privtype - 1] =
4583 
4584  values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
4585 
4586  tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
4587 
4588  CatalogTupleInsert(relation, tuple);
4589  }
4590  }
4591 
4592  systable_endscan(scan);
4593 
4594  /* prevent error when processing objects multiple times */
4596 
4597  table_close(relation, RowExclusiveLock);
4598 }
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
@ INITPRIVS_EXTENSION
Definition: pg_init_privs.h:80
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

References BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), CommandCounterIncrement(), heap_form_tuple(), 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(), and values.

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

◆ recordExtObjInitPriv()

void recordExtObjInitPriv ( Oid  objoid,
Oid  classoid 
)

Definition at line 4234 of file aclchk.c.

4235 {
4236  /*
4237  * pg_class / pg_attribute
4238  *
4239  * If this is a relation then we need to see if there are any sub-objects
4240  * (eg: columns) for it and, if so, be sure to call
4241  * recordExtensionInitPrivWorker() for each one.
4242  */
4243  if (classoid == RelationRelationId)
4244  {
4245  Form_pg_class pg_class_tuple;
4246  Datum aclDatum;
4247  bool isNull;
4248  HeapTuple tuple;
4249 
4250  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4251  if (!HeapTupleIsValid(tuple))
4252  elog(ERROR, "cache lookup failed for relation %u", objoid);
4253  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4254 
4255  /*
4256  * Indexes don't have permissions, neither do the pg_class rows for
4257  * composite types. (These cases are unreachable given the
4258  * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
4259  */
4260  if (pg_class_tuple->relkind == RELKIND_INDEX ||
4261  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4262  pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4263  {
4264  ReleaseSysCache(tuple);
4265  return;
4266  }
4267 
4268  /*
4269  * If this isn't a sequence then it's possibly going to have
4270  * column-level ACLs associated with it.
4271  */
4272  if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4273  {
4274  AttrNumber curr_att;
4275  AttrNumber nattrs = pg_class_tuple->relnatts;
4276 
4277  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4278  {
4279  HeapTuple attTuple;
4280  Datum attaclDatum;
4281 
4282  attTuple = SearchSysCache2(ATTNUM,
4283  ObjectIdGetDatum(objoid),
4284  Int16GetDatum(curr_att));
4285 
4286  if (!HeapTupleIsValid(attTuple))
4287  continue;
4288 
4289  /* ignore dropped columns */
4290  if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
4291  {
4292  ReleaseSysCache(attTuple);
4293  continue;
4294  }
4295 
4296  attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
4297  Anum_pg_attribute_attacl,
4298  &isNull);
4299 
4300  /* no need to do anything for a NULL ACL */
4301  if (isNull)
4302  {
4303  ReleaseSysCache(attTuple);
4304  continue;
4305  }
4306 
4307  recordExtensionInitPrivWorker(objoid, classoid, curr_att,
4308  DatumGetAclP(attaclDatum));
4309 
4310  ReleaseSysCache(attTuple);
4311  }
4312  }
4313 
4314  aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
4315  &isNull);
4316 
4317  /* Add the record, if any, for the top-level object */
4318  if (!isNull)
4319  recordExtensionInitPrivWorker(objoid, classoid, 0,
4320  DatumGetAclP(aclDatum));
4321 
4322  ReleaseSysCache(tuple);
4323  }
4324  /* pg_largeobject_metadata */
4325  else if (classoid == LargeObjectMetadataRelationId)
4326  {
4327  Datum aclDatum;
4328  bool isNull;
4329  HeapTuple tuple;
4330  ScanKeyData entry[1];
4331  SysScanDesc scan;
4332  Relation relation;
4333 
4334  /*
4335  * Note: this is dead code, given that we don't allow large objects to
4336  * be made extension members. But it seems worth carrying in case
4337  * some future caller of this function has need for it.
4338  */
4339  relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
4340 
4341  /* There's no syscache for pg_largeobject_metadata */
4342  ScanKeyInit(&entry[0],
4343  Anum_pg_largeobject_metadata_oid,
4344  BTEqualStrategyNumber, F_OIDEQ,
4345  ObjectIdGetDatum(objoid));
4346 
4347  scan = systable_beginscan(relation,
4348  LargeObjectMetadataOidIndexId, true,
4349  NULL, 1, entry);
4350 
4351  tuple = systable_getnext(scan);
4352  if (!HeapTupleIsValid(tuple))
4353  elog(ERROR, "could not find tuple for large object %u", objoid);
4354 
4355  aclDatum = heap_getattr(tuple,
4356  Anum_pg_largeobject_metadata_lomacl,
4357  RelationGetDescr(relation), &isNull);
4358 
4359  /* Add the record, if any, for the top-level object */
4360  if (!isNull)
4361  recordExtensionInitPrivWorker(objoid, classoid, 0,
4362  DatumGetAclP(aclDatum));
4363 
4364  systable_endscan(scan);
4365  }
4366  /* This will error on unsupported classoid. */
4367  else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
4368  {
4369  Datum aclDatum;
4370  bool isNull;
4371  HeapTuple tuple;
4372 
4373  tuple = SearchSysCache1(get_object_catcache_oid(classoid),
4374  ObjectIdGetDatum(objoid));
4375  if (!HeapTupleIsValid(tuple))
4376  elog(ERROR, "cache lookup failed for %s %u",
4377  get_object_class_descr(classoid), objoid);
4378 
4379  aclDatum = SysCacheGetAttr(get_object_catcache_oid(classoid), tuple,
4380  get_object_attnum_acl(classoid),
4381  &isNull);
4382 
4383  /* Add the record, if any, for the top-level object */
4384  if (!isNull)
4385  recordExtensionInitPrivWorker(objoid, classoid, 0,
4386  DatumGetAclP(aclDatum));
4387 
4388  ReleaseSysCache(tuple);
4389  }
4390 }

References ATTNUM, 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(), RELOID, RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SearchSysCache2(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), and table_open().

Referenced by ExecAlterExtensionContentsStmt().

◆ removeExtObjInitPriv()

void removeExtObjInitPriv ( Oid  objoid,
Oid  classoid 
)

Definition at line 4397 of file aclchk.c.

4398 {
4399  /*
4400  * If this is a relation then we need to see if there are any sub-objects
4401  * (eg: columns) for it and, if so, be sure to call
4402  * recordExtensionInitPrivWorker() for each one.
4403  */
4404  if (classoid == RelationRelationId)
4405  {
4406  Form_pg_class pg_class_tuple;
4407  HeapTuple tuple;
4408 
4409  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
4410  if (!HeapTupleIsValid(tuple))
4411  elog(ERROR, "cache lookup failed for relation %u", objoid);
4412  pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
4413 
4414  /*
4415  * Indexes don't have permissions, neither do the pg_class rows for
4416  * composite types. (These cases are unreachable given the
4417  * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
4418  */
4419  if (pg_class_tuple->relkind == RELKIND_INDEX ||
4420  pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
4421  pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
4422  {
4423  ReleaseSysCache(tuple);
4424  return;
4425  }
4426 
4427  /*
4428  * If this isn't a sequence then it's possibly going to have
4429  * column-level ACLs associated with it.
4430  */
4431  if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
4432  {
4433  AttrNumber curr_att;
4434  AttrNumber nattrs = pg_class_tuple->relnatts;
4435 
4436  for (curr_att = 1; curr_att <= nattrs; curr_att++)
4437  {
4438  HeapTuple attTuple;
4439 
4440  attTuple = SearchSysCache2(ATTNUM,
4441  ObjectIdGetDatum(objoid),
4442  Int16GetDatum(curr_att));
4443 
4444  if (!HeapTupleIsValid(attTuple))
4445  continue;
4446 
4447  /* when removing, remove all entries, even dropped columns */
4448 
4449  recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
4450 
4451  ReleaseSysCache(attTuple);
4452  }
4453  }
4454 
4455  ReleaseSysCache(tuple);
4456  }
4457 
4458  /* Remove the record, if any, for the top-level object */
4459  recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
4460 }

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

Referenced by ExecAlterExtensionContentsStmt().

◆ RemoveRoleFromObjectACL()

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

Definition at line 1444 of file aclchk.c.

1445 {
1446  if (classid == DefaultAclRelationId)
1447  {
1448  InternalDefaultACL iacls;
1449  Form_pg_default_acl pg_default_acl_tuple;
1450  Relation rel;
1451  ScanKeyData skey[1];
1452  SysScanDesc scan;
1453  HeapTuple tuple;
1454 
1455  /* first fetch info needed by SetDefaultACL */
1456  rel = table_open(DefaultAclRelationId, AccessShareLock);
1457 
1458  ScanKeyInit(&skey[0],
1459  Anum_pg_default_acl_oid,
1460  BTEqualStrategyNumber, F_OIDEQ,
1461  ObjectIdGetDatum(objid));
1462 
1463  scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
1464  NULL, 1, skey);
1465 
1466  tuple = systable_getnext(scan);
1467 
1468  if (!HeapTupleIsValid(tuple))
1469  elog(ERROR, "could not find tuple for default ACL %u", objid);
1470 
1471  pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
1472 
1473  iacls.roleid = pg_default_acl_tuple->defaclrole;
1474  iacls.nspid = pg_default_acl_tuple->defaclnamespace;
1475 
1476  switch (pg_default_acl_tuple->defaclobjtype)
1477  {
1478  case DEFACLOBJ_RELATION:
1479  iacls.objtype = OBJECT_TABLE;
1480  break;
1481  case DEFACLOBJ_SEQUENCE:
1482  iacls.objtype = OBJECT_SEQUENCE;
1483  break;
1484  case DEFACLOBJ_FUNCTION:
1485  iacls.objtype = OBJECT_FUNCTION;
1486  break;
1487  case DEFACLOBJ_TYPE:
1488  iacls.objtype = OBJECT_TYPE;
1489  break;
1490  case DEFACLOBJ_NAMESPACE:
1491  iacls.objtype = OBJECT_SCHEMA;
1492  break;
1493  default:
1494  /* Shouldn't get here */
1495  elog(ERROR, "unexpected default ACL type: %d",
1496  (int) pg_default_acl_tuple->defaclobjtype);
1497  break;
1498  }
1499 
1500  systable_endscan(scan);
1502 
1503  iacls.is_grant = false;
1504  iacls.all_privs = true;
1505  iacls.privileges = ACL_NO_RIGHTS;
1506  iacls.grantees = list_make1_oid(roleid);
1507  iacls.grant_option = false;
1508  iacls.behavior = DROP_CASCADE;
1509 
1510  /* Do it */
1511  SetDefaultACL(&iacls);
1512  }
1513  else
1514  {
1515  InternalGrant istmt;
1516 
1517  switch (classid)
1518  {
1519  case RelationRelationId:
1520  /* it's OK to use TABLE for a sequence */
1521  istmt.objtype = OBJECT_TABLE;
1522  break;
1523  case DatabaseRelationId:
1524  istmt.objtype = OBJECT_DATABASE;
1525  break;
1526  case TypeRelationId:
1527  istmt.objtype = OBJECT_TYPE;
1528  break;
1529  case ProcedureRelationId:
1530  istmt.objtype = OBJECT_ROUTINE;
1531  break;
1532  case LanguageRelationId:
1533  istmt.objtype = OBJECT_LANGUAGE;
1534  break;
1535  case LargeObjectRelationId:
1536  istmt.objtype = OBJECT_LARGEOBJECT;
1537  break;
1538  case NamespaceRelationId:
1539  istmt.objtype = OBJECT_SCHEMA;
1540  break;
1541  case TableSpaceRelationId:
1542  istmt.objtype = OBJECT_TABLESPACE;
1543  break;
1544  case ForeignServerRelationId:
1546  break;
1547  case ForeignDataWrapperRelationId:
1548  istmt.objtype = OBJECT_FDW;
1549  break;
1550  case ParameterAclRelationId:
1551  istmt.objtype = OBJECT_PARAMETER_ACL;
1552  break;
1553  default:
1554  elog(ERROR, "unexpected object class %u", classid);
1555  break;
1556  }
1557  istmt.is_grant = false;
1558  istmt.objects = list_make1_oid(objid);
1559  istmt.all_privs = true;
1560  istmt.privileges = ACL_NO_RIGHTS;
1561  istmt.col_privs = NIL;
1562  istmt.grantees = list_make1_oid(roleid);
1563  istmt.grant_option = false;
1564  istmt.behavior = DROP_CASCADE;
1565 
1566  ExecGrantStmt_oids(&istmt);
1567  }
1568 }
static void SetDefaultACL(InternalDefaultACL *iacls)
Definition: aclchk.c:1193
@ DROP_CASCADE
Definition: parsenodes.h:2156
FormData_pg_default_acl * Form_pg_default_acl
#define list_make1_oid(x1)
Definition: pg_list.h:242

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

Referenced by shdepDropOwned().

◆ restrict_and_check_grant()

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

Definition at line 231 of file aclchk.c.

235 {
236  AclMode this_privileges;
237  AclMode whole_mask;
238 
239  switch (objtype)
240  {
241  case OBJECT_COLUMN:
242  whole_mask = ACL_ALL_RIGHTS_COLUMN;
243  break;
244  case OBJECT_TABLE:
245  whole_mask = ACL_ALL_RIGHTS_RELATION;
246  break;
247  case OBJECT_SEQUENCE:
248  whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
249  break;
250  case OBJECT_DATABASE:
251  whole_mask = ACL_ALL_RIGHTS_DATABASE;
252  break;
253  case OBJECT_FUNCTION:
254  whole_mask = ACL_ALL_RIGHTS_FUNCTION;
255  break;
256  case OBJECT_LANGUAGE:
257  whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
258  break;
259  case OBJECT_LARGEOBJECT:
260  whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
261  break;
262  case OBJECT_SCHEMA:
263  whole_mask = ACL_ALL_RIGHTS_SCHEMA;
264  break;
265  case OBJECT_TABLESPACE:
266  whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
267  break;
268  case OBJECT_FDW:
269  whole_mask = ACL_ALL_RIGHTS_FDW;
270  break;
272  whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
273  break;
275  elog(ERROR, "grantable rights not supported for event triggers");
276  /* not reached, but keep compiler quiet */
277  return ACL_NO_RIGHTS;
278  case OBJECT_TYPE:
279  whole_mask = ACL_ALL_RIGHTS_TYPE;
280  break;
282  whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
283  break;
284  default:
285  elog(ERROR, "unrecognized object type: %d", objtype);
286  /* not reached, but keep compiler quiet */
287  return ACL_NO_RIGHTS;
288  }
289 
290  /*
291  * If we found no grant options, consider whether to issue a hard error.
292  * Per spec, having any privilege at all on the object will get you by
293  * here.
294  */
295  if (avail_goptions == ACL_NO_RIGHTS)
296  {
297  if (pg_aclmask(objtype, objectId, att_number, grantorId,
298  whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),