LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 1436 1767 81.3 %
Date: 2023-05-30 17:15:13 Functions: 52 54 96.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * aclchk.c
       4             :  *    Routines to check access control permissions.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/catalog/aclchk.c
      12             :  *
      13             :  * NOTES
      14             :  *    See acl.h.
      15             :  *
      16             :  *-------------------------------------------------------------------------
      17             :  */
      18             : #include "postgres.h"
      19             : 
      20             : #include "access/genam.h"
      21             : #include "access/heapam.h"
      22             : #include "access/htup_details.h"
      23             : #include "access/sysattr.h"
      24             : #include "access/tableam.h"
      25             : #include "access/xact.h"
      26             : #include "catalog/binary_upgrade.h"
      27             : #include "catalog/catalog.h"
      28             : #include "catalog/dependency.h"
      29             : #include "catalog/indexing.h"
      30             : #include "catalog/objectaccess.h"
      31             : #include "catalog/pg_aggregate.h"
      32             : #include "catalog/pg_am.h"
      33             : #include "catalog/pg_authid.h"
      34             : #include "catalog/pg_cast.h"
      35             : #include "catalog/pg_class.h"
      36             : #include "catalog/pg_collation.h"
      37             : #include "catalog/pg_conversion.h"
      38             : #include "catalog/pg_database.h"
      39             : #include "catalog/pg_default_acl.h"
      40             : #include "catalog/pg_event_trigger.h"
      41             : #include "catalog/pg_extension.h"
      42             : #include "catalog/pg_foreign_data_wrapper.h"
      43             : #include "catalog/pg_foreign_server.h"
      44             : #include "catalog/pg_init_privs.h"
      45             : #include "catalog/pg_language.h"
      46             : #include "catalog/pg_largeobject.h"
      47             : #include "catalog/pg_largeobject_metadata.h"
      48             : #include "catalog/pg_namespace.h"
      49             : #include "catalog/pg_opclass.h"
      50             : #include "catalog/pg_operator.h"
      51             : #include "catalog/pg_opfamily.h"
      52             : #include "catalog/pg_parameter_acl.h"
      53             : #include "catalog/pg_proc.h"
      54             : #include "catalog/pg_statistic_ext.h"
      55             : #include "catalog/pg_subscription.h"
      56             : #include "catalog/pg_tablespace.h"
      57             : #include "catalog/pg_transform.h"
      58             : #include "catalog/pg_ts_config.h"
      59             : #include "catalog/pg_ts_dict.h"
      60             : #include "catalog/pg_ts_parser.h"
      61             : #include "catalog/pg_ts_template.h"
      62             : #include "catalog/pg_type.h"
      63             : #include "commands/dbcommands.h"
      64             : #include "commands/defrem.h"
      65             : #include "commands/event_trigger.h"
      66             : #include "commands/extension.h"
      67             : #include "commands/proclang.h"
      68             : #include "commands/tablespace.h"
      69             : #include "foreign/foreign.h"
      70             : #include "miscadmin.h"
      71             : #include "nodes/makefuncs.h"
      72             : #include "parser/parse_func.h"
      73             : #include "parser/parse_type.h"
      74             : #include "utils/acl.h"
      75             : #include "utils/aclchk_internal.h"
      76             : #include "utils/builtins.h"
      77             : #include "utils/fmgroids.h"
      78             : #include "utils/guc.h"
      79             : #include "utils/lsyscache.h"
      80             : #include "utils/rel.h"
      81             : #include "utils/syscache.h"
      82             : 
      83             : /*
      84             :  * Internal format used by ALTER DEFAULT PRIVILEGES.
      85             :  */
      86             : typedef struct
      87             : {
      88             :     Oid         roleid;         /* owning role */
      89             :     Oid         nspid;          /* namespace, or InvalidOid if none */
      90             :     /* remaining fields are same as in InternalGrant: */
      91             :     bool        is_grant;
      92             :     ObjectType  objtype;
      93             :     bool        all_privs;
      94             :     AclMode     privileges;
      95             :     List       *grantees;
      96             :     bool        grant_option;
      97             :     DropBehavior behavior;
      98             : } InternalDefaultACL;
      99             : 
     100             : /*
     101             :  * When performing a binary-upgrade, pg_dump will call a function to set
     102             :  * this variable to let us know that we need to populate the pg_init_privs
     103             :  * table for the GRANT/REVOKE commands while this variable is set to true.
     104             :  */
     105             : bool        binary_upgrade_record_init_privs = false;
     106             : 
     107             : static void ExecGrantStmt_oids(InternalGrant *istmt);
     108             : static void ExecGrant_Relation(InternalGrant *istmt);
     109             : static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
     110             :                              void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
     111             : static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
     112             : static void ExecGrant_Largeobject(InternalGrant *istmt);
     113             : static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
     114             : static void ExecGrant_Parameter(InternalGrant *istmt);
     115             : 
     116             : static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
     117             : static void SetDefaultACL(InternalDefaultACL *iacls);
     118             : 
     119             : static List *objectNamesToOids(ObjectType objtype, List *objnames,
     120             :                                bool is_grant);
     121             : static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
     122             : static List *getRelationsInNamespace(Oid namespaceId, char relkind);
     123             : static void expand_col_privileges(List *colnames, Oid table_oid,
     124             :                                   AclMode this_privileges,
     125             :                                   AclMode *col_privileges,
     126             :                                   int num_col_privileges);
     127             : static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
     128             :                                       AclMode this_privileges,
     129             :                                       AclMode *col_privileges,
     130             :                                       int num_col_privileges);
     131             : static AclMode string_to_privilege(const char *privname);
     132             : static const char *privilege_to_string(AclMode privilege);
     133             : static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
     134             :                                         bool all_privs, AclMode privileges,
     135             :                                         Oid objectId, Oid grantorId,
     136             :                                         ObjectType objtype, const char *objname,
     137             :                                         AttrNumber att_number, const char *colname);
     138             : static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
     139             :                           Oid roleid, AclMode mask, AclMaskHow how);
     140             : static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
     141             :                               AclMode mask, AclMaskHow how);
     142             : static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
     143             :                                     Oid roleid, AclMode mask, AclMaskHow how);
     144             : static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
     145             :                                         Oid roleid, AclMode mask,
     146             :                                         AclMaskHow how, bool *is_missing);
     147             : static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
     148             :                                     AclMode mask, AclMaskHow how,
     149             :                                     bool *is_missing);
     150             : static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
     151             :                                         AclMode mask, AclMaskHow how);
     152             : static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
     153             :                                                AclMode mask, AclMaskHow how, Snapshot snapshot);
     154             : static AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
     155             :                                     AclMode mask, AclMaskHow how);
     156             : static AclMode pg_type_aclmask(Oid type_oid, Oid roleid,
     157             :                                AclMode mask, AclMaskHow how);
     158             : static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
     159             :                                     Acl *new_acl);
     160             : static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
     161             :                                           Acl *new_acl);
     162             : 
     163             : 
     164             : /*
     165             :  * If is_grant is true, adds the given privileges for the list of
     166             :  * grantees to the existing old_acl.  If is_grant is false, the
     167             :  * privileges for the given grantees are removed from old_acl.
     168             :  *
     169             :  * NB: the original old_acl is pfree'd.
     170             :  */
     171             : static Acl *
     172      208208 : merge_acl_with_grant(Acl *old_acl, bool is_grant,
     173             :                      bool grant_option, DropBehavior behavior,
     174             :                      List *grantees, AclMode privileges,
     175             :                      Oid grantorId, Oid ownerId)
     176             : {
     177             :     unsigned    modechg;
     178             :     ListCell   *j;
     179             :     Acl        *new_acl;
     180             : 
     181      208208 :     modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
     182             : 
     183      208208 :     new_acl = old_acl;
     184             : 
     185      416500 :     foreach(j, grantees)
     186             :     {
     187             :         AclItem     aclitem;
     188             :         Acl        *newer_acl;
     189             : 
     190      208304 :         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      208304 :         if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
     199           0 :             ereport(ERROR,
     200             :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     201             :                      errmsg("grant options can only be granted to roles")));
     202             : 
     203      208304 :         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             :          */
     212      208304 :         ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
     213             :                                    (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
     214             :                                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
     215             : 
     216      208304 :         newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
     217             : 
     218             :         /* avoid memory leak when there are many grantees */
     219      208292 :         pfree(new_acl);
     220      208292 :         new_acl = newer_acl;
     221             :     }
     222             : 
     223      208196 :     return new_acl;
     224             : }
     225             : 
     226             : /*
     227             :  * Restrict the privileges to what we can actually grant, and emit
     228             :  * the standards-mandated warning and error messages.
     229             :  */
     230             : static AclMode
     231      208048 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
     232             :                          AclMode privileges, Oid objectId, Oid grantorId,
     233             :                          ObjectType objtype, const char *objname,
     234             :                          AttrNumber att_number, const char *colname)
     235             : {
     236             :     AclMode     this_privileges;
     237             :     AclMode     whole_mask;
     238             : 
     239      208048 :     switch (objtype)
     240             :     {
     241      111076 :         case OBJECT_COLUMN:
     242      111076 :             whole_mask = ACL_ALL_RIGHTS_COLUMN;
     243      111076 :             break;
     244       48904 :         case OBJECT_TABLE:
     245       48904 :             whole_mask = ACL_ALL_RIGHTS_RELATION;
     246       48904 :             break;
     247         152 :         case OBJECT_SEQUENCE:
     248         152 :             whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
     249         152 :             break;
     250        1322 :         case OBJECT_DATABASE:
     251        1322 :             whole_mask = ACL_ALL_RIGHTS_DATABASE;
     252        1322 :             break;
     253       44124 :         case OBJECT_FUNCTION:
     254       44124 :             whole_mask = ACL_ALL_RIGHTS_FUNCTION;
     255       44124 :             break;
     256          36 :         case OBJECT_LANGUAGE:
     257          36 :             whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
     258          36 :             break;
     259          80 :         case OBJECT_LARGEOBJECT:
     260          80 :             whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
     261          80 :             break;
     262        1944 :         case OBJECT_SCHEMA:
     263        1944 :             whole_mask = ACL_ALL_RIGHTS_SCHEMA;
     264        1944 :             break;
     265           0 :         case OBJECT_TABLESPACE:
     266           0 :             whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
     267           0 :             break;
     268          94 :         case OBJECT_FDW:
     269          94 :             whole_mask = ACL_ALL_RIGHTS_FDW;
     270          94 :             break;
     271          88 :         case OBJECT_FOREIGN_SERVER:
     272          88 :             whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     273          88 :             break;
     274           0 :         case OBJECT_EVENT_TRIGGER:
     275           0 :             elog(ERROR, "grantable rights not supported for event triggers");
     276             :             /* not reached, but keep compiler quiet */
     277             :             return ACL_NO_RIGHTS;
     278          94 :         case OBJECT_TYPE:
     279          94 :             whole_mask = ACL_ALL_RIGHTS_TYPE;
     280          94 :             break;
     281         134 :         case OBJECT_PARAMETER_ACL:
     282         134 :             whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
     283         134 :             break;
     284           0 :         default:
     285           0 :             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      208048 :     if (avail_goptions == ACL_NO_RIGHTS)
     296             :     {
     297          66 :         if (pg_aclmask(objtype, objectId, att_number, grantorId,
     298          66 :                        whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
     299             :                        ACLMASK_ANY) == ACL_NO_RIGHTS)
     300             :         {
     301          30 :             if (objtype == OBJECT_COLUMN && colname)
     302           0 :                 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
     303             :             else
     304          30 :                 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
     305             :         }
     306             :     }
     307             : 
     308             :     /*
     309             :      * Restrict the operation to what we can actually grant or revoke, and
     310             :      * issue a warning if appropriate.  (For REVOKE this isn't quite what the
     311             :      * spec says to do: the spec seems to want a warning only if no privilege
     312             :      * bits actually change in the ACL. In practice that behavior seems much
     313             :      * too noisy, as well as inconsistent with the GRANT case.)
     314             :      */
     315      208018 :     this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
     316      208018 :     if (is_grant)
     317             :     {
     318       59012 :         if (this_privileges == 0)
     319             :         {
     320          30 :             if (objtype == OBJECT_COLUMN && colname)
     321           0 :                 ereport(WARNING,
     322             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     323             :                          errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
     324             :                                 colname, objname)));
     325             :             else
     326          30 :                 ereport(WARNING,
     327             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     328             :                          errmsg("no privileges were granted for \"%s\"",
     329             :                                 objname)));
     330             :         }
     331       58982 :         else if (!all_privs && this_privileges != privileges)
     332             :         {
     333           0 :             if (objtype == OBJECT_COLUMN && colname)
     334           0 :                 ereport(WARNING,
     335             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     336             :                          errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
     337             :                                 colname, objname)));
     338             :             else
     339           0 :                 ereport(WARNING,
     340             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     341             :                          errmsg("not all privileges were granted for \"%s\"",
     342             :                                 objname)));
     343             :         }
     344             :     }
     345             :     else
     346             :     {
     347      149006 :         if (this_privileges == 0)
     348             :         {
     349           6 :             if (objtype == OBJECT_COLUMN && colname)
     350           0 :                 ereport(WARNING,
     351             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     352             :                          errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
     353             :                                 colname, objname)));
     354             :             else
     355           6 :                 ereport(WARNING,
     356             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     357             :                          errmsg("no privileges could be revoked for \"%s\"",
     358             :                                 objname)));
     359             :         }
     360      149000 :         else if (!all_privs && this_privileges != privileges)
     361             :         {
     362           0 :             if (objtype == OBJECT_COLUMN && colname)
     363           0 :                 ereport(WARNING,
     364             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     365             :                          errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
     366             :                                 colname, objname)));
     367             :             else
     368           0 :                 ereport(WARNING,
     369             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     370             :                          errmsg("not all privileges could be revoked for \"%s\"",
     371             :                                 objname)));
     372             :         }
     373             :     }
     374             : 
     375      208018 :     return this_privileges;
     376             : }
     377             : 
     378             : /*
     379             :  * Called to execute the utility commands GRANT and REVOKE
     380             :  */
     381             : void
     382       97032 : ExecuteGrantStmt(GrantStmt *stmt)
     383             : {
     384             :     InternalGrant istmt;
     385             :     ListCell   *cell;
     386             :     const char *errormsg;
     387             :     AclMode     all_privileges;
     388             : 
     389       97032 :     if (stmt->grantor)
     390             :     {
     391             :         Oid         grantor;
     392             : 
     393          18 :         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          18 :         if (grantor != GetUserId())
     400           6 :             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       97026 :     istmt.is_grant = stmt->is_grant;
     409       97026 :     istmt.objtype = stmt->objtype;
     410             : 
     411             :     /* Collect the OIDs of the target objects */
     412       97026 :     switch (stmt->targtype)
     413             :     {
     414       96996 :         case ACL_TARGET_OBJECT:
     415      193966 :             istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
     416       96996 :                                               stmt->is_grant);
     417       96970 :             break;
     418          30 :         case ACL_TARGET_ALL_IN_SCHEMA:
     419          30 :             istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
     420          30 :             break;
     421             :             /* ACL_TARGET_DEFAULTS should not be seen here */
     422           0 :         default:
     423           0 :             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       97000 :     istmt.col_privs = NIL;      /* may get filled below */
     430       97000 :     istmt.grantees = NIL;       /* filled below */
     431       97000 :     istmt.grant_option = stmt->grant_option;
     432       97000 :     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      194060 :     foreach(cell, stmt->grantees)
     440             :     {
     441       97066 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     442             :         Oid         grantee_uid;
     443             : 
     444       97066 :         switch (grantee->roletype)
     445             :         {
     446       87452 :             case ROLESPEC_PUBLIC:
     447       87452 :                 grantee_uid = ACL_ID_PUBLIC;
     448       87452 :                 break;
     449        9614 :             default:
     450        9614 :                 grantee_uid = get_rolespec_oid(grantee, false);
     451        9608 :                 break;
     452             :         }
     453       97060 :         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       96994 :     switch (stmt->objtype)
     461             :     {
     462       49824 :         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             :              */
     469       49824 :             all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
     470       49824 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     471       49824 :             break;
     472          12 :         case OBJECT_SEQUENCE:
     473          12 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
     474          12 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
     475          12 :             break;
     476        1312 :         case OBJECT_DATABASE:
     477        1312 :             all_privileges = ACL_ALL_RIGHTS_DATABASE;
     478        1312 :             errormsg = gettext_noop("invalid privilege type %s for database");
     479        1312 :             break;
     480          20 :         case OBJECT_DOMAIN:
     481          20 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     482          20 :             errormsg = gettext_noop("invalid privilege type %s for domain");
     483          20 :             break;
     484       44024 :         case OBJECT_FUNCTION:
     485       44024 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     486       44024 :             errormsg = gettext_noop("invalid privilege type %s for function");
     487       44024 :             break;
     488          42 :         case OBJECT_LANGUAGE:
     489          42 :             all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
     490          42 :             errormsg = gettext_noop("invalid privilege type %s for language");
     491          42 :             break;
     492          62 :         case OBJECT_LARGEOBJECT:
     493          62 :             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
     494          62 :             errormsg = gettext_noop("invalid privilege type %s for large object");
     495          62 :             break;
     496        1324 :         case OBJECT_SCHEMA:
     497        1324 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
     498        1324 :             errormsg = gettext_noop("invalid privilege type %s for schema");
     499        1324 :             break;
     500          42 :         case OBJECT_PROCEDURE:
     501          42 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     502          42 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
     503          42 :             break;
     504           6 :         case OBJECT_ROUTINE:
     505           6 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     506           6 :             errormsg = gettext_noop("invalid privilege type %s for routine");
     507           6 :             break;
     508           0 :         case OBJECT_TABLESPACE:
     509           0 :             all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
     510           0 :             errormsg = gettext_noop("invalid privilege type %s for tablespace");
     511           0 :             break;
     512          86 :         case OBJECT_TYPE:
     513          86 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     514          86 :             errormsg = gettext_noop("invalid privilege type %s for type");
     515          86 :             break;
     516          92 :         case OBJECT_FDW:
     517          92 :             all_privileges = ACL_ALL_RIGHTS_FDW;
     518          92 :             errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
     519          92 :             break;
     520          76 :         case OBJECT_FOREIGN_SERVER:
     521          76 :             all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     522          76 :             errormsg = gettext_noop("invalid privilege type %s for foreign server");
     523          76 :             break;
     524          72 :         case OBJECT_PARAMETER_ACL:
     525          72 :             all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
     526          72 :             errormsg = gettext_noop("invalid privilege type %s for parameter");
     527          72 :             break;
     528           0 :         default:
     529           0 :             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       96994 :     if (stmt->privileges == NIL)
     537             :     {
     538        9244 :         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        9244 :         istmt.privileges = ACL_NO_RIGHTS;
     545             :     }
     546             :     else
     547             :     {
     548       87750 :         istmt.all_privs = false;
     549       87750 :         istmt.privileges = ACL_NO_RIGHTS;
     550             : 
     551      177480 :         foreach(cell, stmt->privileges)
     552             :         {
     553       89754 :             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       89754 :             if (privnode->cols)
     561             :             {
     562         934 :                 if (stmt->objtype != OBJECT_TABLE)
     563           0 :                     ereport(ERROR,
     564             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     565             :                              errmsg("column privileges are only valid for relations")));
     566         934 :                 istmt.col_privs = lappend(istmt.col_privs, privnode);
     567         934 :                 continue;
     568             :             }
     569             : 
     570       88820 :             if (privnode->priv_name == NULL) /* parser mistake? */
     571           0 :                 elog(ERROR, "AccessPriv node must specify privilege or columns");
     572       88820 :             priv = string_to_privilege(privnode->priv_name);
     573             : 
     574       88820 :             if (priv & ~((AclMode) all_privileges))
     575          24 :                 ereport(ERROR,
     576             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     577             :                          errmsg(errormsg, privilege_to_string(priv))));
     578             : 
     579       88796 :             istmt.privileges |= priv;
     580             :         }
     581             :     }
     582             : 
     583       96970 :     ExecGrantStmt_oids(&istmt);
     584       96910 : }
     585             : 
     586             : /*
     587             :  * ExecGrantStmt_oids
     588             :  *
     589             :  * Internal entry point for granting and revoking privileges.
     590             :  */
     591             : static void
     592       97152 : ExecGrantStmt_oids(InternalGrant *istmt)
     593             : {
     594       97152 :     switch (istmt->objtype)
     595             :     {
     596       49912 :         case OBJECT_TABLE:
     597             :         case OBJECT_SEQUENCE:
     598       49912 :             ExecGrant_Relation(istmt);
     599       49906 :             break;
     600        1322 :         case OBJECT_DATABASE:
     601        1322 :             ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
     602        1322 :             break;
     603         106 :         case OBJECT_DOMAIN:
     604             :         case OBJECT_TYPE:
     605         106 :             ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
     606          88 :             break;
     607          94 :         case OBJECT_FDW:
     608          94 :             ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
     609          76 :             break;
     610          88 :         case OBJECT_FOREIGN_SERVER:
     611          88 :             ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
     612          76 :             break;
     613       44082 :         case OBJECT_FUNCTION:
     614             :         case OBJECT_PROCEDURE:
     615             :         case OBJECT_ROUTINE:
     616       44082 :             ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
     617       44082 :             break;
     618          42 :         case OBJECT_LANGUAGE:
     619          42 :             ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
     620          36 :             break;
     621          74 :         case OBJECT_LARGEOBJECT:
     622          74 :             ExecGrant_Largeobject(istmt);
     623          74 :             break;
     624        1336 :         case OBJECT_SCHEMA:
     625        1336 :             ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
     626        1336 :             break;
     627           0 :         case OBJECT_TABLESPACE:
     628           0 :             ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
     629           0 :             break;
     630          96 :         case OBJECT_PARAMETER_ACL:
     631          96 :             ExecGrant_Parameter(istmt);
     632          96 :             break;
     633           0 :         default:
     634           0 :             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             :      */
     644       97092 :     if (EventTriggerSupportsObjectType(istmt->objtype))
     645       95674 :         EventTriggerCollectGrant(istmt);
     646       97092 : }
     647             : 
     648             : /*
     649             :  * objectNamesToOids
     650             :  *
     651             :  * Turn a list of object names of a given type into an Oid list.
     652             :  *
     653             :  * XXX: This function doesn't take any sort of locks on the objects whose
     654             :  * names it looks up.  In the face of concurrent DDL, we might easily latch
     655             :  * onto an old version of an object, causing the GRANT or REVOKE statement
     656             :  * to fail.
     657             :  */
     658             : static List *
     659       96996 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
     660             : {
     661       96996 :     List       *objects = NIL;
     662             :     ListCell   *cell;
     663             : 
     664             :     Assert(objnames != NIL);
     665             : 
     666       96996 :     switch (objtype)
     667             :     {
     668       49824 :         case OBJECT_TABLE:
     669             :         case OBJECT_SEQUENCE:
     670       99702 :             foreach(cell, objnames)
     671             :             {
     672       49878 :                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
     673             :                 Oid         relOid;
     674             : 
     675       49878 :                 relOid = RangeVarGetRelid(relvar, NoLock, false);
     676       49878 :                 objects = lappend_oid(objects, relOid);
     677             :             }
     678       49824 :             break;
     679        1312 :         case OBJECT_DATABASE:
     680        2624 :             foreach(cell, objnames)
     681             :             {
     682        1312 :                 char       *dbname = strVal(lfirst(cell));
     683             :                 Oid         dbid;
     684             : 
     685        1312 :                 dbid = get_database_oid(dbname, false);
     686        1312 :                 objects = lappend_oid(objects, dbid);
     687             :             }
     688        1312 :             break;
     689         106 :         case OBJECT_DOMAIN:
     690             :         case OBJECT_TYPE:
     691         212 :             foreach(cell, objnames)
     692             :             {
     693         106 :                 List       *typname = (List *) lfirst(cell);
     694             :                 Oid         oid;
     695             : 
     696         106 :                 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
     697         106 :                 objects = lappend_oid(objects, oid);
     698             :             }
     699         106 :             break;
     700       44030 :         case OBJECT_FUNCTION:
     701       88072 :             foreach(cell, objnames)
     702             :             {
     703       44054 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     704             :                 Oid         funcid;
     705             : 
     706       44054 :                 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
     707       44042 :                 objects = lappend_oid(objects, funcid);
     708             :             }
     709       44018 :             break;
     710          42 :         case OBJECT_LANGUAGE:
     711          84 :             foreach(cell, objnames)
     712             :             {
     713          42 :                 char       *langname = strVal(lfirst(cell));
     714             :                 Oid         oid;
     715             : 
     716          42 :                 oid = get_language_oid(langname, false);
     717          42 :                 objects = lappend_oid(objects, oid);
     718             :             }
     719          42 :             break;
     720          80 :         case OBJECT_LARGEOBJECT:
     721         154 :             foreach(cell, objnames)
     722             :             {
     723          86 :                 Oid         lobjOid = oidparse(lfirst(cell));
     724             : 
     725          86 :                 if (!LargeObjectExists(lobjOid))
     726          12 :                     ereport(ERROR,
     727             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
     728             :                              errmsg("large object %u does not exist",
     729             :                                     lobjOid)));
     730             : 
     731          74 :                 objects = lappend_oid(objects, lobjOid);
     732             :             }
     733          68 :             break;
     734        1324 :         case OBJECT_SCHEMA:
     735        3256 :             foreach(cell, objnames)
     736             :             {
     737        1932 :                 char       *nspname = strVal(lfirst(cell));
     738             :                 Oid         oid;
     739             : 
     740        1932 :                 oid = get_namespace_oid(nspname, false);
     741        1932 :                 objects = lappend_oid(objects, oid);
     742             :             }
     743        1324 :             break;
     744          36 :         case OBJECT_PROCEDURE:
     745          72 :             foreach(cell, objnames)
     746             :             {
     747          36 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     748             :                 Oid         procid;
     749             : 
     750          36 :                 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
     751          36 :                 objects = lappend_oid(objects, procid);
     752             :             }
     753          36 :             break;
     754           0 :         case OBJECT_ROUTINE:
     755           0 :             foreach(cell, objnames)
     756             :             {
     757           0 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     758             :                 Oid         routid;
     759             : 
     760           0 :                 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
     761           0 :                 objects = lappend_oid(objects, routid);
     762             :             }
     763           0 :             break;
     764           0 :         case OBJECT_TABLESPACE:
     765           0 :             foreach(cell, objnames)
     766             :             {
     767           0 :                 char       *spcname = strVal(lfirst(cell));
     768             :                 Oid         spcoid;
     769             : 
     770           0 :                 spcoid = get_tablespace_oid(spcname, false);
     771           0 :                 objects = lappend_oid(objects, spcoid);
     772             :             }
     773           0 :             break;
     774          92 :         case OBJECT_FDW:
     775         184 :             foreach(cell, objnames)
     776             :             {
     777          92 :                 char       *fdwname = strVal(lfirst(cell));
     778          92 :                 Oid         fdwid = get_foreign_data_wrapper_oid(fdwname, false);
     779             : 
     780          92 :                 objects = lappend_oid(objects, fdwid);
     781             :             }
     782          92 :             break;
     783          76 :         case OBJECT_FOREIGN_SERVER:
     784         152 :             foreach(cell, objnames)
     785             :             {
     786          76 :                 char       *srvname = strVal(lfirst(cell));
     787          76 :                 Oid         srvid = get_foreign_server_oid(srvname, false);
     788             : 
     789          76 :                 objects = lappend_oid(objects, srvid);
     790             :             }
     791          76 :             break;
     792          74 :         case OBJECT_PARAMETER_ACL:
     793         196 :             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         124 :                 char       *parameter = strVal(lfirst(cell));
     806         124 :                 Oid         parameterId = ParameterAclLookup(parameter, true);
     807             : 
     808         124 :                 if (!OidIsValid(parameterId) && is_grant)
     809             :                 {
     810          68 :                     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             :                      */
     817          66 :                     CommandCounterIncrement();
     818             :                 }
     819         122 :                 if (OidIsValid(parameterId))
     820         110 :                     objects = lappend_oid(objects, parameterId);
     821             :             }
     822          72 :             break;
     823           0 :         default:
     824           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     825             :                  (int) objtype);
     826             :     }
     827             : 
     828       96970 :     return objects;
     829             : }
     830             : 
     831             : /*
     832             :  * objectsInSchemaToOids
     833             :  *
     834             :  * Find all objects of a given type in specified schemas, and make a list
     835             :  * of their Oids.  We check USAGE privilege on the schemas, but there is
     836             :  * no privilege checking on the individual objects here.
     837             :  */
     838             : static List *
     839          30 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
     840             : {
     841          30 :     List       *objects = NIL;
     842             :     ListCell   *cell;
     843             : 
     844          60 :     foreach(cell, nspnames)
     845             :     {
     846          30 :         char       *nspname = strVal(lfirst(cell));
     847             :         Oid         namespaceId;
     848             :         List       *objs;
     849             : 
     850          30 :         namespaceId = LookupExplicitNamespace(nspname, false);
     851             : 
     852          30 :         switch (objtype)
     853             :         {
     854          12 :             case OBJECT_TABLE:
     855          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
     856          12 :                 objects = list_concat(objects, objs);
     857          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
     858          12 :                 objects = list_concat(objects, objs);
     859          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
     860          12 :                 objects = list_concat(objects, objs);
     861          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
     862          12 :                 objects = list_concat(objects, objs);
     863          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
     864          12 :                 objects = list_concat(objects, objs);
     865          12 :                 break;
     866           0 :             case OBJECT_SEQUENCE:
     867           0 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
     868           0 :                 objects = list_concat(objects, objs);
     869           0 :                 break;
     870          18 :             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          18 :                     keycount = 0;
     881          18 :                     ScanKeyInit(&key[keycount++],
     882             :                                 Anum_pg_proc_pronamespace,
     883             :                                 BTEqualStrategyNumber, F_OIDEQ,
     884             :                                 ObjectIdGetDatum(namespaceId));
     885             : 
     886          18 :                     if (objtype == OBJECT_FUNCTION)
     887             :                         /* includes aggregates and window functions */
     888           6 :                         ScanKeyInit(&key[keycount++],
     889             :                                     Anum_pg_proc_prokind,
     890             :                                     BTEqualStrategyNumber, F_CHARNE,
     891             :                                     CharGetDatum(PROKIND_PROCEDURE));
     892          12 :                     else if (objtype == OBJECT_PROCEDURE)
     893           6 :                         ScanKeyInit(&key[keycount++],
     894             :                                     Anum_pg_proc_prokind,
     895             :                                     BTEqualStrategyNumber, F_CHAREQ,
     896             :                                     CharGetDatum(PROKIND_PROCEDURE));
     897             : 
     898          18 :                     rel = table_open(ProcedureRelationId, AccessShareLock);
     899          18 :                     scan = table_beginscan_catalog(rel, keycount, key);
     900             : 
     901          54 :                     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     902             :                     {
     903          36 :                         Oid         oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
     904             : 
     905          36 :                         objects = lappend_oid(objects, oid);
     906             :                     }
     907             : 
     908          18 :                     table_endscan(scan);
     909          18 :                     table_close(rel, AccessShareLock);
     910             :                 }
     911          18 :                 break;
     912           0 :             default:
     913             :                 /* should not happen */
     914           0 :                 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     915             :                      (int) objtype);
     916             :         }
     917             :     }
     918             : 
     919          30 :     return objects;
     920             : }
     921             : 
     922             : /*
     923             :  * getRelationsInNamespace
     924             :  *
     925             :  * Return Oid list of relations in given namespace filtered by relation kind
     926             :  */
     927             : static List *
     928          60 : getRelationsInNamespace(Oid namespaceId, char relkind)
     929             : {
     930          60 :     List       *relations = NIL;
     931             :     ScanKeyData key[2];
     932             :     Relation    rel;
     933             :     TableScanDesc scan;
     934             :     HeapTuple   tuple;
     935             : 
     936          60 :     ScanKeyInit(&key[0],
     937             :                 Anum_pg_class_relnamespace,
     938             :                 BTEqualStrategyNumber, F_OIDEQ,
     939             :                 ObjectIdGetDatum(namespaceId));
     940          60 :     ScanKeyInit(&key[1],
     941             :                 Anum_pg_class_relkind,
     942             :                 BTEqualStrategyNumber, F_CHAREQ,
     943             :                 CharGetDatum(relkind));
     944             : 
     945          60 :     rel = table_open(RelationRelationId, AccessShareLock);
     946          60 :     scan = table_beginscan_catalog(rel, 2, key);
     947             : 
     948          84 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     949             :     {
     950          24 :         Oid         oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
     951             : 
     952          24 :         relations = lappend_oid(relations, oid);
     953             :     }
     954             : 
     955          60 :     table_endscan(scan);
     956          60 :     table_close(rel, AccessShareLock);
     957             : 
     958          60 :     return relations;
     959             : }
     960             : 
     961             : 
     962             : /*
     963             :  * ALTER DEFAULT PRIVILEGES statement
     964             :  */
     965             : void
     966         160 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
     967             : {
     968         160 :     GrantStmt  *action = stmt->action;
     969             :     InternalDefaultACL iacls;
     970             :     ListCell   *cell;
     971         160 :     List       *rolespecs = NIL;
     972         160 :     List       *nspnames = NIL;
     973         160 :     DefElem    *drolespecs = NULL;
     974         160 :     DefElem    *dnspnames = NULL;
     975             :     AclMode     all_privileges;
     976             :     const char *errormsg;
     977             : 
     978             :     /* Deconstruct the "options" part of the statement */
     979         282 :     foreach(cell, stmt->options)
     980             :     {
     981         122 :         DefElem    *defel = (DefElem *) lfirst(cell);
     982             : 
     983         122 :         if (strcmp(defel->defname, "schemas") == 0)
     984             :         {
     985          54 :             if (dnspnames)
     986           0 :                 errorConflictingDefElem(defel, pstate);
     987          54 :             dnspnames = defel;
     988             :         }
     989          68 :         else if (strcmp(defel->defname, "roles") == 0)
     990             :         {
     991          68 :             if (drolespecs)
     992           0 :                 errorConflictingDefElem(defel, pstate);
     993          68 :             drolespecs = defel;
     994             :         }
     995             :         else
     996           0 :             elog(ERROR, "option \"%s\" not recognized", defel->defname);
     997             :     }
     998             : 
     999         160 :     if (dnspnames)
    1000          54 :         nspnames = (List *) dnspnames->arg;
    1001         160 :     if (drolespecs)
    1002          68 :         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         160 :     iacls.is_grant = action->is_grant;
    1008         160 :     iacls.objtype = action->objtype;
    1009             :     /* all_privs to be filled below */
    1010             :     /* privileges to be filled below */
    1011         160 :     iacls.grantees = NIL;       /* filled below */
    1012         160 :     iacls.grant_option = action->grant_option;
    1013         160 :     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         326 :     foreach(cell, action->grantees)
    1021             :     {
    1022         166 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
    1023             :         Oid         grantee_uid;
    1024             : 
    1025         166 :         switch (grantee->roletype)
    1026             :         {
    1027          40 :             case ROLESPEC_PUBLIC:
    1028          40 :                 grantee_uid = ACL_ID_PUBLIC;
    1029          40 :                 break;
    1030         126 :             default:
    1031         126 :                 grantee_uid = get_rolespec_oid(grantee, false);
    1032         126 :                 break;
    1033             :         }
    1034         166 :         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         160 :     switch (action->objtype)
    1042             :     {
    1043          78 :         case OBJECT_TABLE:
    1044          78 :             all_privileges = ACL_ALL_RIGHTS_RELATION;
    1045          78 :             errormsg = gettext_noop("invalid privilege type %s for relation");
    1046          78 :             break;
    1047           6 :         case OBJECT_SEQUENCE:
    1048           6 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1049           6 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
    1050           6 :             break;
    1051          22 :         case OBJECT_FUNCTION:
    1052          22 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1053          22 :             errormsg = gettext_noop("invalid privilege type %s for function");
    1054          22 :             break;
    1055           0 :         case OBJECT_PROCEDURE:
    1056           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1057           0 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
    1058           0 :             break;
    1059           0 :         case OBJECT_ROUTINE:
    1060           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1061           0 :             errormsg = gettext_noop("invalid privilege type %s for routine");
    1062           0 :             break;
    1063          18 :         case OBJECT_TYPE:
    1064          18 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
    1065          18 :             errormsg = gettext_noop("invalid privilege type %s for type");
    1066          18 :             break;
    1067          36 :         case OBJECT_SCHEMA:
    1068          36 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1069          36 :             errormsg = gettext_noop("invalid privilege type %s for schema");
    1070          36 :             break;
    1071           0 :         default:
    1072           0 :             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         160 :     if (action->privileges == NIL)
    1080             :     {
    1081          56 :         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          56 :         iacls.privileges = ACL_NO_RIGHTS;
    1088             :     }
    1089             :     else
    1090             :     {
    1091         104 :         iacls.all_privs = false;
    1092         104 :         iacls.privileges = ACL_NO_RIGHTS;
    1093             : 
    1094         208 :         foreach(cell, action->privileges)
    1095             :         {
    1096         104 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
    1097             :             AclMode     priv;
    1098             : 
    1099         104 :             if (privnode->cols)
    1100           0 :                 ereport(ERROR,
    1101             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1102             :                          errmsg("default privileges cannot be set for columns")));
    1103             : 
    1104         104 :             if (privnode->priv_name == NULL) /* parser mistake? */
    1105           0 :                 elog(ERROR, "AccessPriv node must specify privilege");
    1106         104 :             priv = string_to_privilege(privnode->priv_name);
    1107             : 
    1108         104 :             if (priv & ~((AclMode) all_privileges))
    1109           0 :                 ereport(ERROR,
    1110             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1111             :                          errmsg(errormsg, privilege_to_string(priv))));
    1112             : 
    1113         104 :             iacls.privileges |= priv;
    1114             :         }
    1115             :     }
    1116             : 
    1117         160 :     if (rolespecs == NIL)
    1118             :     {
    1119             :         /* Set permissions for myself */
    1120          92 :         iacls.roleid = GetUserId();
    1121             : 
    1122          92 :         SetDefaultACLsInSchemas(&iacls, nspnames);
    1123             :     }
    1124             :     else
    1125             :     {
    1126             :         /* Look up the role OIDs and do permissions checks */
    1127             :         ListCell   *rolecell;
    1128             : 
    1129         136 :         foreach(rolecell, rolespecs)
    1130             :         {
    1131          68 :             RoleSpec   *rolespec = lfirst(rolecell);
    1132             : 
    1133          68 :             iacls.roleid = get_rolespec_oid(rolespec, false);
    1134             : 
    1135          68 :             if (!has_privs_of_role(GetUserId(), iacls.roleid))
    1136           0 :                 ereport(ERROR,
    1137             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1138             :                          errmsg("permission denied to change default privileges")));
    1139             : 
    1140          68 :             SetDefaultACLsInSchemas(&iacls, nspnames);
    1141             :         }
    1142             :     }
    1143         154 : }
    1144             : 
    1145             : /*
    1146             :  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
    1147             :  *
    1148             :  * All fields of *iacls except nspid were filled already
    1149             :  */
    1150             : static void
    1151         160 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
    1152             : {
    1153         160 :     if (nspnames == NIL)
    1154             :     {
    1155             :         /* Set database-wide permissions if no schema was specified */
    1156         106 :         iacls->nspid = InvalidOid;
    1157             : 
    1158         106 :         SetDefaultACL(iacls);
    1159             :     }
    1160             :     else
    1161             :     {
    1162             :         /* Look up the schema OIDs and set permissions for each one */
    1163             :         ListCell   *nspcell;
    1164             : 
    1165         108 :         foreach(nspcell, nspnames)
    1166             :         {
    1167          60 :             char       *nspname = strVal(lfirst(nspcell));
    1168             : 
    1169          60 :             iacls->nspid = get_namespace_oid(nspname, false);
    1170             : 
    1171             :             /*
    1172             :              * We used to insist that the target role have CREATE privileges
    1173             :              * on the schema, since without that it wouldn't be able to create
    1174             :              * an object for which these default privileges would apply.
    1175             :              * However, this check proved to be more confusing than helpful,
    1176             :              * and it also caused certain database states to not be
    1177             :              * dumpable/restorable, since revoking CREATE doesn't cause
    1178             :              * default privileges for the schema to go away.  So now, we just
    1179             :              * allow the ALTER; if the user lacks CREATE he'll find out when
    1180             :              * he tries to create an object.
    1181             :              */
    1182             : 
    1183          60 :             SetDefaultACL(iacls);
    1184             :         }
    1185             :     }
    1186         154 : }
    1187             : 
    1188             : 
    1189             : /*
    1190             :  * Create or update a pg_default_acl entry
    1191             :  */
    1192             : static void
    1193         196 : SetDefaultACL(InternalDefaultACL *iacls)
    1194             : {
    1195         196 :     AclMode     this_privileges = iacls->privileges;
    1196             :     char        objtype;
    1197             :     Relation    rel;
    1198             :     HeapTuple   tuple;
    1199             :     bool        isNew;
    1200             :     Acl        *def_acl;
    1201             :     Acl        *old_acl;
    1202             :     Acl        *new_acl;
    1203             :     HeapTuple   newtuple;
    1204             :     int         noldmembers;
    1205             :     int         nnewmembers;
    1206             :     Oid        *oldmembers;
    1207             :     Oid        *newmembers;
    1208             : 
    1209         196 :     rel = table_open(DefaultAclRelationId, RowExclusiveLock);
    1210             : 
    1211             :     /*
    1212             :      * The default for a global entry is the hard-wired default ACL for the
    1213             :      * particular object type.  The default for non-global entries is an empty
    1214             :      * ACL.  This must be so because global entries replace the hard-wired
    1215             :      * defaults, while others are added on.
    1216             :      */
    1217         196 :     if (!OidIsValid(iacls->nspid))
    1218         136 :         def_acl = acldefault(iacls->objtype, iacls->roleid);
    1219             :     else
    1220          60 :         def_acl = make_empty_acl();
    1221             : 
    1222             :     /*
    1223             :      * Convert ACL object type to pg_default_acl object type and handle
    1224             :      * all_privs option
    1225             :      */
    1226         196 :     switch (iacls->objtype)
    1227             :     {
    1228          90 :         case OBJECT_TABLE:
    1229          90 :             objtype = DEFACLOBJ_RELATION;
    1230          90 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1231          26 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1232          90 :             break;
    1233             : 
    1234          12 :         case OBJECT_SEQUENCE:
    1235          12 :             objtype = DEFACLOBJ_SEQUENCE;
    1236          12 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1237          12 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1238          12 :             break;
    1239             : 
    1240          28 :         case OBJECT_FUNCTION:
    1241          28 :             objtype = DEFACLOBJ_FUNCTION;
    1242          28 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1243          12 :                 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1244          28 :             break;
    1245             : 
    1246          24 :         case OBJECT_TYPE:
    1247          24 :             objtype = DEFACLOBJ_TYPE;
    1248          24 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1249          12 :                 this_privileges = ACL_ALL_RIGHTS_TYPE;
    1250          24 :             break;
    1251             : 
    1252          42 :         case OBJECT_SCHEMA:
    1253          42 :             if (OidIsValid(iacls->nspid))
    1254           6 :                 ereport(ERROR,
    1255             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1256             :                          errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
    1257          36 :             objtype = DEFACLOBJ_NAMESPACE;
    1258          36 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1259          24 :                 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1260          36 :             break;
    1261             : 
    1262           0 :         default:
    1263           0 :             elog(ERROR, "unrecognized object type: %d",
    1264             :                  (int) iacls->objtype);
    1265             :             objtype = 0;        /* keep compiler quiet */
    1266             :             break;
    1267             :     }
    1268             : 
    1269             :     /* Search for existing row for this object type in catalog */
    1270         190 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    1271             :                             ObjectIdGetDatum(iacls->roleid),
    1272             :                             ObjectIdGetDatum(iacls->nspid),
    1273             :                             CharGetDatum(objtype));
    1274             : 
    1275         190 :     if (HeapTupleIsValid(tuple))
    1276             :     {
    1277             :         Datum       aclDatum;
    1278             :         bool        isNull;
    1279             : 
    1280          72 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    1281             :                                    Anum_pg_default_acl_defaclacl,
    1282             :                                    &isNull);
    1283          72 :         if (!isNull)
    1284          72 :             old_acl = DatumGetAclPCopy(aclDatum);
    1285             :         else
    1286           0 :             old_acl = NULL;     /* this case shouldn't happen, probably */
    1287          72 :         isNew = false;
    1288             :     }
    1289             :     else
    1290             :     {
    1291         118 :         old_acl = NULL;
    1292         118 :         isNew = true;
    1293             :     }
    1294             : 
    1295         190 :     if (old_acl != NULL)
    1296             :     {
    1297             :         /*
    1298             :          * We need the members of both old and new ACLs so we can correct the
    1299             :          * shared dependency information.  Collect data before
    1300             :          * merge_acl_with_grant throws away old_acl.
    1301             :          */
    1302          72 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1303             :     }
    1304             :     else
    1305             :     {
    1306             :         /* If no or null entry, start with the default ACL value */
    1307         118 :         old_acl = aclcopy(def_acl);
    1308             :         /* There are no old member roles according to the catalogs */
    1309         118 :         noldmembers = 0;
    1310         118 :         oldmembers = NULL;
    1311             :     }
    1312             : 
    1313             :     /*
    1314             :      * Generate new ACL.  Grantor of rights is always the same as the target
    1315             :      * role.
    1316             :      */
    1317         190 :     new_acl = merge_acl_with_grant(old_acl,
    1318         190 :                                    iacls->is_grant,
    1319         190 :                                    iacls->grant_option,
    1320             :                                    iacls->behavior,
    1321             :                                    iacls->grantees,
    1322             :                                    this_privileges,
    1323             :                                    iacls->roleid,
    1324             :                                    iacls->roleid);
    1325             : 
    1326             :     /*
    1327             :      * If the result is the same as the default value, we do not need an
    1328             :      * explicit pg_default_acl entry, and should in fact remove the entry if
    1329             :      * it exists.  Must sort both arrays to compare properly.
    1330             :      */
    1331         190 :     aclitemsort(new_acl);
    1332         190 :     aclitemsort(def_acl);
    1333         190 :     if (aclequal(new_acl, def_acl))
    1334             :     {
    1335             :         /* delete old entry, if indeed there is one */
    1336          56 :         if (!isNew)
    1337             :         {
    1338             :             ObjectAddress myself;
    1339             : 
    1340             :             /*
    1341             :              * The dependency machinery will take care of removing all
    1342             :              * associated dependency entries.  We use DROP_RESTRICT since
    1343             :              * there shouldn't be anything depending on this entry.
    1344             :              */
    1345          54 :             myself.classId = DefaultAclRelationId;
    1346          54 :             myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1347          54 :             myself.objectSubId = 0;
    1348             : 
    1349          54 :             performDeletion(&myself, DROP_RESTRICT, 0);
    1350             :         }
    1351             :     }
    1352             :     else
    1353             :     {
    1354         134 :         Datum       values[Natts_pg_default_acl] = {0};
    1355         134 :         bool        nulls[Natts_pg_default_acl] = {0};
    1356         134 :         bool        replaces[Natts_pg_default_acl] = {0};
    1357             :         Oid         defAclOid;
    1358             : 
    1359         134 :         if (isNew)
    1360             :         {
    1361             :             /* insert new entry */
    1362         116 :             defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
    1363             :                                            Anum_pg_default_acl_oid);
    1364         116 :             values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
    1365         116 :             values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
    1366         116 :             values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
    1367         116 :             values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
    1368         116 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1369             : 
    1370         116 :             newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
    1371         116 :             CatalogTupleInsert(rel, newtuple);
    1372             :         }
    1373             :         else
    1374             :         {
    1375          18 :             defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1376             : 
    1377             :             /* update existing entry */
    1378          18 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1379          18 :             replaces[Anum_pg_default_acl_defaclacl - 1] = true;
    1380             : 
    1381          18 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
    1382             :                                          values, nulls, replaces);
    1383          18 :             CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    1384             :         }
    1385             : 
    1386             :         /* these dependencies don't change in an update */
    1387         134 :         if (isNew)
    1388             :         {
    1389             :             /* dependency on role */
    1390         116 :             recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
    1391             :                                     iacls->roleid);
    1392             : 
    1393             :             /* dependency on namespace */
    1394         116 :             if (OidIsValid(iacls->nspid))
    1395             :             {
    1396             :                 ObjectAddress myself,
    1397             :                             referenced;
    1398             : 
    1399          34 :                 myself.classId = DefaultAclRelationId;
    1400          34 :                 myself.objectId = defAclOid;
    1401          34 :                 myself.objectSubId = 0;
    1402             : 
    1403          34 :                 referenced.classId = NamespaceRelationId;
    1404          34 :                 referenced.objectId = iacls->nspid;
    1405          34 :                 referenced.objectSubId = 0;
    1406             : 
    1407          34 :                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
    1408             :             }
    1409             :         }
    1410             : 
    1411             :         /*
    1412             :          * Update the shared dependency ACL info
    1413             :          */
    1414         134 :         nnewmembers = aclmembers(new_acl, &newmembers);
    1415             : 
    1416         134 :         updateAclDependencies(DefaultAclRelationId,
    1417             :                               defAclOid, 0,
    1418             :                               iacls->roleid,
    1419             :                               noldmembers, oldmembers,
    1420             :                               nnewmembers, newmembers);
    1421             : 
    1422         134 :         if (isNew)
    1423         116 :             InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
    1424             :         else
    1425          18 :             InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
    1426             :     }
    1427             : 
    1428         190 :     if (HeapTupleIsValid(tuple))
    1429          72 :         ReleaseSysCache(tuple);
    1430             : 
    1431         190 :     table_close(rel, RowExclusiveLock);
    1432             : 
    1433             :     /* prevent error when processing duplicate objects */
    1434         190 :     CommandCounterIncrement();
    1435         190 : }
    1436             : 
    1437             : 
    1438             : /*
    1439             :  * RemoveRoleFromObjectACL
    1440             :  *
    1441             :  * Used by shdepDropOwned to remove mentions of a role in ACLs
    1442             :  */
    1443             : void
    1444         212 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
    1445             : {
    1446         212 :     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          30 :         rel = table_open(DefaultAclRelationId, AccessShareLock);
    1457             : 
    1458          30 :         ScanKeyInit(&skey[0],
    1459             :                     Anum_pg_default_acl_oid,
    1460             :                     BTEqualStrategyNumber, F_OIDEQ,
    1461             :                     ObjectIdGetDatum(objid));
    1462             : 
    1463          30 :         scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
    1464             :                                   NULL, 1, skey);
    1465             : 
    1466          30 :         tuple = systable_getnext(scan);
    1467             : 
    1468          30 :         if (!HeapTupleIsValid(tuple))
    1469           0 :             elog(ERROR, "could not find tuple for default ACL %u", objid);
    1470             : 
    1471          30 :         pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
    1472             : 
    1473          30 :         iacls.roleid = pg_default_acl_tuple->defaclrole;
    1474          30 :         iacls.nspid = pg_default_acl_tuple->defaclnamespace;
    1475             : 
    1476          30 :         switch (pg_default_acl_tuple->defaclobjtype)
    1477             :         {
    1478           6 :             case DEFACLOBJ_RELATION:
    1479           6 :                 iacls.objtype = OBJECT_TABLE;
    1480           6 :                 break;
    1481           6 :             case DEFACLOBJ_SEQUENCE:
    1482           6 :                 iacls.objtype = OBJECT_SEQUENCE;
    1483           6 :                 break;
    1484           6 :             case DEFACLOBJ_FUNCTION:
    1485           6 :                 iacls.objtype = OBJECT_FUNCTION;
    1486           6 :                 break;
    1487           6 :             case DEFACLOBJ_TYPE:
    1488           6 :                 iacls.objtype = OBJECT_TYPE;
    1489           6 :                 break;
    1490           6 :             case DEFACLOBJ_NAMESPACE:
    1491           6 :                 iacls.objtype = OBJECT_SCHEMA;
    1492           6 :                 break;
    1493           0 :             default:
    1494             :                 /* Shouldn't get here */
    1495           0 :                 elog(ERROR, "unexpected default ACL type: %d",
    1496             :                      (int) pg_default_acl_tuple->defaclobjtype);
    1497             :                 break;
    1498             :         }
    1499             : 
    1500          30 :         systable_endscan(scan);
    1501          30 :         table_close(rel, AccessShareLock);
    1502             : 
    1503          30 :         iacls.is_grant = false;
    1504          30 :         iacls.all_privs = true;
    1505          30 :         iacls.privileges = ACL_NO_RIGHTS;
    1506          30 :         iacls.grantees = list_make1_oid(roleid);
    1507          30 :         iacls.grant_option = false;
    1508          30 :         iacls.behavior = DROP_CASCADE;
    1509             : 
    1510             :         /* Do it */
    1511          30 :         SetDefaultACL(&iacls);
    1512             :     }
    1513             :     else
    1514             :     {
    1515             :         InternalGrant istmt;
    1516             : 
    1517         182 :         switch (classid)
    1518             :         {
    1519          76 :             case RelationRelationId:
    1520             :                 /* it's OK to use TABLE for a sequence */
    1521          76 :                 istmt.objtype = OBJECT_TABLE;
    1522          76 :                 break;
    1523          10 :             case DatabaseRelationId:
    1524          10 :                 istmt.objtype = OBJECT_DATABASE;
    1525          10 :                 break;
    1526           0 :             case TypeRelationId:
    1527           0 :                 istmt.objtype = OBJECT_TYPE;
    1528           0 :                 break;
    1529          28 :             case ProcedureRelationId:
    1530          28 :                 istmt.objtype = OBJECT_ROUTINE;
    1531          28 :                 break;
    1532           0 :             case LanguageRelationId:
    1533           0 :                 istmt.objtype = OBJECT_LANGUAGE;
    1534           0 :                 break;
    1535          18 :             case LargeObjectRelationId:
    1536          18 :                 istmt.objtype = OBJECT_LARGEOBJECT;
    1537          18 :                 break;
    1538          12 :             case NamespaceRelationId:
    1539          12 :                 istmt.objtype = OBJECT_SCHEMA;
    1540          12 :                 break;
    1541           0 :             case TableSpaceRelationId:
    1542           0 :                 istmt.objtype = OBJECT_TABLESPACE;
    1543           0 :                 break;
    1544          12 :             case ForeignServerRelationId:
    1545          12 :                 istmt.objtype = OBJECT_FOREIGN_SERVER;
    1546          12 :                 break;
    1547           2 :             case ForeignDataWrapperRelationId:
    1548           2 :                 istmt.objtype = OBJECT_FDW;
    1549           2 :                 break;
    1550          24 :             case ParameterAclRelationId:
    1551          24 :                 istmt.objtype = OBJECT_PARAMETER_ACL;
    1552          24 :                 break;
    1553           0 :             default:
    1554           0 :                 elog(ERROR, "unexpected object class %u", classid);
    1555             :                 break;
    1556             :         }
    1557         182 :         istmt.is_grant = false;
    1558         182 :         istmt.objects = list_make1_oid(objid);
    1559         182 :         istmt.all_privs = true;
    1560         182 :         istmt.privileges = ACL_NO_RIGHTS;
    1561         182 :         istmt.col_privs = NIL;
    1562         182 :         istmt.grantees = list_make1_oid(roleid);
    1563         182 :         istmt.grant_option = false;
    1564         182 :         istmt.behavior = DROP_CASCADE;
    1565             : 
    1566         182 :         ExecGrantStmt_oids(&istmt);
    1567             :     }
    1568         212 : }
    1569             : 
    1570             : 
    1571             : /*
    1572             :  * expand_col_privileges
    1573             :  *
    1574             :  * OR the specified privilege(s) into per-column array entries for each
    1575             :  * specified attribute.  The per-column array is indexed starting at
    1576             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1577             :  */
    1578             : static void
    1579         934 : expand_col_privileges(List *colnames, Oid table_oid,
    1580             :                       AclMode this_privileges,
    1581             :                       AclMode *col_privileges,
    1582             :                       int num_col_privileges)
    1583             : {
    1584             :     ListCell   *cell;
    1585             : 
    1586       11172 :     foreach(cell, colnames)
    1587             :     {
    1588       10238 :         char       *colname = strVal(lfirst(cell));
    1589             :         AttrNumber  attnum;
    1590             : 
    1591       10238 :         attnum = get_attnum(table_oid, colname);
    1592       10238 :         if (attnum == InvalidAttrNumber)
    1593           0 :             ereport(ERROR,
    1594             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1595             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    1596             :                             colname, get_rel_name(table_oid))));
    1597       10238 :         attnum -= FirstLowInvalidHeapAttributeNumber;
    1598       10238 :         if (attnum <= 0 || attnum >= num_col_privileges)
    1599           0 :             elog(ERROR, "column number out of range");    /* safety check */
    1600       10238 :         col_privileges[attnum] |= this_privileges;
    1601             :     }
    1602         934 : }
    1603             : 
    1604             : /*
    1605             :  * expand_all_col_privileges
    1606             :  *
    1607             :  * OR the specified privilege(s) into per-column array entries for each valid
    1608             :  * attribute of a relation.  The per-column array is indexed starting at
    1609             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1610             :  */
    1611             : static void
    1612        8856 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
    1613             :                           AclMode this_privileges,
    1614             :                           AclMode *col_privileges,
    1615             :                           int num_col_privileges)
    1616             : {
    1617             :     AttrNumber  curr_att;
    1618             : 
    1619             :     Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
    1620        8856 :     for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
    1621      147662 :          curr_att <= classForm->relnatts;
    1622      138806 :          curr_att++)
    1623             :     {
    1624             :         HeapTuple   attTuple;
    1625             :         bool        isdropped;
    1626             : 
    1627      138806 :         if (curr_att == InvalidAttrNumber)
    1628        8856 :             continue;
    1629             : 
    1630             :         /* Views don't have any system columns at all */
    1631      129950 :         if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
    1632       29064 :             continue;
    1633             : 
    1634      100886 :         attTuple = SearchSysCache2(ATTNUM,
    1635             :                                    ObjectIdGetDatum(table_oid),
    1636             :                                    Int16GetDatum(curr_att));
    1637      100886 :         if (!HeapTupleIsValid(attTuple))
    1638           0 :             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1639             :                  curr_att, table_oid);
    1640             : 
    1641      100886 :         isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
    1642             : 
    1643      100886 :         ReleaseSysCache(attTuple);
    1644             : 
    1645             :         /* ignore dropped columns */
    1646      100886 :         if (isdropped)
    1647           6 :             continue;
    1648             : 
    1649      100880 :         col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
    1650             :     }
    1651        8856 : }
    1652             : 
    1653             : /*
    1654             :  *  This processes attributes, but expects to be called from
    1655             :  *  ExecGrant_Relation, not directly from ExecuteGrantStmt.
    1656             :  */
    1657             : static void
    1658      111076 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
    1659             :                     AttrNumber attnum, Oid ownerId, AclMode col_privileges,
    1660             :                     Relation attRelation, const Acl *old_rel_acl)
    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      111076 :     Datum       values[Natts_pg_attribute] = {0};
    1674      111076 :     bool        nulls[Natts_pg_attribute] = {0};
    1675      111076 :     bool        replaces[Natts_pg_attribute] = {0};
    1676             :     int         noldmembers;
    1677             :     int         nnewmembers;
    1678             :     Oid        *oldmembers;
    1679             :     Oid        *newmembers;
    1680             : 
    1681      111076 :     attr_tuple = SearchSysCache2(ATTNUM,
    1682             :                                  ObjectIdGetDatum(relOid),
    1683             :                                  Int16GetDatum(attnum));
    1684      111076 :     if (!HeapTupleIsValid(attr_tuple))
    1685           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1686             :              attnum, relOid);
    1687      111076 :     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      111076 :     aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
    1694             :                                &isNull);
    1695      111076 :     if (isNull)
    1696             :     {
    1697      110774 :         old_acl = acldefault(OBJECT_COLUMN, ownerId);
    1698             :         /* There are no old member roles according to the catalogs */
    1699      110774 :         noldmembers = 0;
    1700      110774 :         oldmembers = NULL;
    1701             :     }
    1702             :     else
    1703             :     {
    1704         302 :         old_acl = DatumGetAclPCopy(aclDatum);
    1705             :         /* Get the roles mentioned in the existing ACL */
    1706         302 :         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      111076 :     merged_acl = aclconcat(old_rel_acl, old_acl);
    1716             : 
    1717             :     /* Determine ID to do the grant as, and available grant options */
    1718      111076 :     select_best_grantor(GetUserId(), col_privileges,
    1719             :                         merged_acl, ownerId,
    1720             :                         &grantorId, &avail_goptions);
    1721             : 
    1722      111076 :     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      111076 :         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      111076 :                                  NameStr(pg_attribute_tuple->attname));
    1739             : 
    1740             :     /*
    1741             :      * Generate new ACL.
    1742             :      */
    1743      111076 :     new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    1744      111076 :                                    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      111076 :     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      111076 :     if (ACL_NUM(new_acl) > 0)
    1765             :     {
    1766       10260 :         values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
    1767       10260 :         need_update = true;
    1768             :     }
    1769             :     else
    1770             :     {
    1771      100816 :         nulls[Anum_pg_attribute_attacl - 1] = true;
    1772      100816 :         need_update = !isNull;
    1773             :     }
    1774      111076 :     replaces[Anum_pg_attribute_attacl - 1] = true;
    1775             : 
    1776      111076 :     if (need_update)
    1777             :     {
    1778       10352 :         newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
    1779             :                                      values, nulls, replaces);
    1780             : 
    1781       10352 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
    1782             : 
    1783             :         /* Update initial privileges for extensions */
    1784       10352 :         recordExtensionInitPriv(relOid, RelationRelationId, attnum,
    1785       10352 :                                 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
    1786             : 
    1787             :         /* Update the shared dependency ACL info */
    1788       10352 :         updateAclDependencies(RelationRelationId, relOid, attnum,
    1789             :                               ownerId,
    1790             :                               noldmembers, oldmembers,
    1791             :                               nnewmembers, newmembers);
    1792             :     }
    1793             : 
    1794      111076 :     pfree(new_acl);
    1795             : 
    1796      111076 :     ReleaseSysCache(attr_tuple);
    1797      111076 : }
    1798             : 
    1799             : /*
    1800             :  *  This processes both sequences and non-sequences.
    1801             :  */
    1802             : static void
    1803       49912 : ExecGrant_Relation(InternalGrant *istmt)
    1804             : {
    1805             :     Relation    relation;
    1806             :     Relation    attRelation;
    1807             :     ListCell   *cell;
    1808             : 
    1809       49912 :     relation = table_open(RelationRelationId, RowExclusiveLock);
    1810       49912 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
    1811             : 
    1812       99884 :     foreach(cell, istmt->objects)
    1813             :     {
    1814       49978 :         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       49978 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
    1831       49978 :         if (!HeapTupleIsValid(tuple))
    1832           0 :             elog(ERROR, "cache lookup failed for relation %u", relOid);
    1833       49978 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    1834             : 
    1835             :         /* Not sensible to grant on an index */
    1836       49978 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    1837       49978 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    1838           0 :             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       49978 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    1845           0 :             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       49978 :         if (istmt->objtype == OBJECT_SEQUENCE &&
    1852          12 :             pg_class_tuple->relkind != RELKIND_SEQUENCE)
    1853           0 :             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       49978 :         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    1860             :         {
    1861        8910 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1862          70 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1863             :             else
    1864        8840 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1865             :         }
    1866             :         else
    1867       41068 :             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       49978 :         if (istmt->objtype == OBJECT_TABLE)
    1876             :         {
    1877       49966 :             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         140 :                 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           0 :                     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           0 :                     this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
    1896             :                 }
    1897             :             }
    1898             :             else
    1899             :             {
    1900       49826 :                 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           0 :                     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       49978 :         num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
    1922       49978 :         col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
    1923       49978 :         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       49978 :         if (!istmt->is_grant &&
    1933        8912 :             (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
    1934             :         {
    1935        8856 :             expand_all_col_privileges(relOid, pg_class_tuple,
    1936             :                                       this_privileges & ACL_ALL_RIGHTS_COLUMN,
    1937             :                                       col_privileges,
    1938             :                                       num_col_privileges);
    1939        8856 :             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       49978 :         ownerId = pg_class_tuple->relowner;
    1947       49978 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    1948             :                                    &isNull);
    1949       49978 :         if (isNull)
    1950             :         {
    1951       46808 :             switch (pg_class_tuple->relkind)
    1952             :             {
    1953          80 :                 case RELKIND_SEQUENCE:
    1954          80 :                     old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
    1955          80 :                     break;
    1956       46728 :                 default:
    1957       46728 :                     old_acl = acldefault(OBJECT_TABLE, ownerId);
    1958       46728 :                     break;
    1959             :             }
    1960             :             /* There are no old member roles according to the catalogs */
    1961       46808 :             noldmembers = 0;
    1962       46808 :             oldmembers = NULL;
    1963             :         }
    1964             :         else
    1965             :         {
    1966        3170 :             old_acl = DatumGetAclPCopy(aclDatum);
    1967             :             /* Get the roles mentioned in the existing ACL */
    1968        3170 :             noldmembers = aclmembers(old_acl, &oldmembers);
    1969             :         }
    1970             : 
    1971             :         /* Need an extra copy of original rel ACL for column handling */
    1972       49978 :         old_rel_acl = aclcopy(old_acl);
    1973             : 
    1974             :         /*
    1975             :          * Handle relation-level privileges, if any were specified
    1976             :          */
    1977       49978 :         if (this_privileges != ACL_NO_RIGHTS)
    1978             :         {
    1979             :             AclMode     avail_goptions;
    1980             :             Acl        *new_acl;
    1981             :             Oid         grantorId;
    1982             :             HeapTuple   newtuple;
    1983       49056 :             Datum       values[Natts_pg_class] = {0};
    1984       49056 :             bool        nulls[Natts_pg_class] = {0};
    1985       49056 :             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       49056 :             select_best_grantor(GetUserId(), this_privileges,
    1992             :                                 old_acl, ownerId,
    1993             :                                 &grantorId, &avail_goptions);
    1994             : 
    1995       49056 :             switch (pg_class_tuple->relkind)
    1996             :             {
    1997         152 :                 case RELKIND_SEQUENCE:
    1998         152 :                     objtype = OBJECT_SEQUENCE;
    1999         152 :                     break;
    2000       48904 :                 default:
    2001       48904 :                     objtype = OBJECT_TABLE;
    2002       48904 :                     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       49056 :                 restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2011       49056 :                                          istmt->all_privs, this_privileges,
    2012             :                                          relOid, grantorId, objtype,
    2013       49056 :                                          NameStr(pg_class_tuple->relname),
    2014             :                                          0, NULL);
    2015             : 
    2016             :             /*
    2017             :              * Generate new ACL.
    2018             :              */
    2019       49056 :             new_acl = merge_acl_with_grant(old_acl,
    2020       49056 :                                            istmt->is_grant,
    2021       49056 :                                            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       49050 :             nnewmembers = aclmembers(new_acl, &newmembers);
    2033             : 
    2034             :             /* finished building new ACL value, now insert it */
    2035       49050 :             replaces[Anum_pg_class_relacl - 1] = true;
    2036       49050 :             values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
    2037             : 
    2038       49050 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2039             :                                          values, nulls, replaces);
    2040             : 
    2041       49050 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2042             : 
    2043             :             /* Update initial privileges for extensions */
    2044       49050 :             recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
    2045             : 
    2046             :             /* Update the shared dependency ACL info */
    2047       49050 :             updateAclDependencies(RelationRelationId, relOid, 0,
    2048             :                                   ownerId,
    2049             :                                   noldmembers, oldmembers,
    2050             :                                   nnewmembers, newmembers);
    2051             : 
    2052       49050 :             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       50906 :         foreach(cell_colprivs, istmt->col_privs)
    2061             :         {
    2062         934 :             AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
    2063             : 
    2064         934 :             if (col_privs->priv_name == NULL)
    2065          18 :                 this_privileges = ACL_ALL_RIGHTS_COLUMN;
    2066             :             else
    2067         916 :                 this_privileges = string_to_privilege(col_privs->priv_name);
    2068             : 
    2069         934 :             if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
    2070           0 :                 ereport(ERROR,
    2071             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2072             :                          errmsg("invalid privilege type %s for column",
    2073             :                                 privilege_to_string(this_privileges))));
    2074             : 
    2075         934 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
    2076           0 :                 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           0 :                 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           0 :                 this_privileges &= (AclMode) ACL_SELECT;
    2089             :             }
    2090             : 
    2091         934 :             expand_col_privileges(col_privs->cols, relOid,
    2092             :                                   this_privileges,
    2093             :                                   col_privileges,
    2094             :                                   num_col_privileges);
    2095         934 :             have_col_privileges = true;
    2096             :         }
    2097             : 
    2098       49972 :         if (have_col_privileges)
    2099             :         {
    2100             :             AttrNumber  i;
    2101             : 
    2102      176354 :             for (i = 0; i < num_col_privileges; i++)
    2103             :             {
    2104      166582 :                 if (col_privileges[i] == ACL_NO_RIGHTS)
    2105       55506 :                     continue;
    2106      111076 :                 ExecGrant_Attribute(istmt,
    2107             :                                     relOid,
    2108      111076 :                                     NameStr(pg_class_tuple->relname),
    2109      111076 :                                     i + FirstLowInvalidHeapAttributeNumber,
    2110             :                                     ownerId,
    2111      111076 :                                     col_privileges[i],
    2112             :                                     attRelation,
    2113             :                                     old_rel_acl);
    2114             :             }
    2115             :         }
    2116             : 
    2117       49972 :         pfree(old_rel_acl);
    2118       49972 :         pfree(col_privileges);
    2119             : 
    2120       49972 :         ReleaseSysCache(tuple);
    2121             : 
    2122             :         /* prevent error when processing duplicate objects */
    2123       49972 :         CommandCounterIncrement();
    2124             :     }
    2125             : 
    2126       49906 :     table_close(attRelation, RowExclusiveLock);
    2127       49906 :     table_close(relation, RowExclusiveLock);
    2128       49906 : }
    2129             : 
    2130             : static void
    2131       47070 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
    2132             :                  void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
    2133             : {
    2134             :     int         cacheid;
    2135             :     Relation    relation;
    2136             :     ListCell   *cell;
    2137             : 
    2138       47070 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2139         472 :         istmt->privileges = default_privs;
    2140             : 
    2141       47070 :     cacheid = get_object_catcache_oid(classid);
    2142             : 
    2143       47070 :     relation = table_open(classid, RowExclusiveLock);
    2144             : 
    2145       94736 :     foreach(cell, istmt->objects)
    2146             :     {
    2147       47720 :         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       47720 :         Datum      *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
    2160       47720 :         bool       *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2161       47720 :         bool       *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2162             :         int         noldmembers;
    2163             :         int         nnewmembers;
    2164             :         Oid        *oldmembers;
    2165             :         Oid        *newmembers;
    2166             : 
    2167       47720 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    2168       47720 :         if (!HeapTupleIsValid(tuple))
    2169           0 :             elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
    2170             : 
    2171             :         /*
    2172             :          * Additional object-type-specific checks
    2173             :          */
    2174       47720 :         if (object_check)
    2175         148 :             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       47702 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    2182             :                                                           tuple,
    2183       47702 :                                                           get_object_attnum_owner(classid)));
    2184       47702 :         aclDatum = SysCacheGetAttr(cacheid,
    2185             :                                    tuple,
    2186       47702 :                                    get_object_attnum_acl(classid),
    2187             :                                    &isNull);
    2188       47702 :         if (isNull)
    2189             :         {
    2190       40964 :             old_acl = acldefault(get_object_type(classid, objectid), ownerId);
    2191             :             /* There are no old member roles according to the catalogs */
    2192       40964 :             noldmembers = 0;
    2193       40964 :             oldmembers = NULL;
    2194             :         }
    2195             :         else
    2196             :         {
    2197        6738 :             old_acl = DatumGetAclPCopy(aclDatum);
    2198             :             /* Get the roles mentioned in the existing ACL */
    2199        6738 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2200             :         }
    2201             : 
    2202             :         /* Determine ID to do the grant as, and available grant options */
    2203       47702 :         select_best_grantor(GetUserId(), istmt->privileges,
    2204             :                             old_acl, ownerId,
    2205             :                             &grantorId, &avail_goptions);
    2206             : 
    2207       47702 :         nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
    2208       47702 :                                            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       95404 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2216       47702 :                                      istmt->all_privs, istmt->privileges,
    2217             :                                      objectid, grantorId, get_object_type(classid, objectid),
    2218       47702 :                                      NameStr(*DatumGetName(nameDatum)),
    2219             :                                      0, NULL);
    2220             : 
    2221             :         /*
    2222             :          * Generate new ACL.
    2223             :          */
    2224       47672 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2225       47672 :                                        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       47666 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2234             : 
    2235             :         /* finished building new ACL value, now insert it */
    2236       47666 :         replaces[get_object_attnum_acl(classid) - 1] = true;
    2237       47666 :         values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
    2238             : 
    2239       47666 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2240             :                                      nulls, replaces);
    2241             : 
    2242       47666 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2243             : 
    2244             :         /* Update initial privileges for extensions */
    2245       47666 :         recordExtensionInitPriv(objectid, classid, 0, new_acl);
    2246             : 
    2247             :         /* Update the shared dependency ACL info */
    2248       47666 :         updateAclDependencies(classid,
    2249             :                               objectid, 0,
    2250             :                               ownerId,
    2251             :                               noldmembers, oldmembers,
    2252             :                               nnewmembers, newmembers);
    2253             : 
    2254       47666 :         ReleaseSysCache(tuple);
    2255             : 
    2256       47666 :         pfree(new_acl);
    2257             : 
    2258             :         /* prevent error when processing duplicate objects */
    2259       47666 :         CommandCounterIncrement();
    2260             :     }
    2261             : 
    2262       47016 :     table_close(relation, RowExclusiveLock);
    2263       47016 : }
    2264             : 
    2265             : static void
    2266          42 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
    2267             : {
    2268             :     Form_pg_language pg_language_tuple;
    2269             : 
    2270          42 :     pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
    2271             : 
    2272          42 :     if (!pg_language_tuple->lanpltrusted)
    2273           6 :         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          36 : }
    2280             : 
    2281             : static void
    2282          74 : ExecGrant_Largeobject(InternalGrant *istmt)
    2283             : {
    2284             :     Relation    relation;
    2285             :     ListCell   *cell;
    2286             : 
    2287          74 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2288          44 :         istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    2289             : 
    2290          74 :     relation = table_open(LargeObjectMetadataRelationId,
    2291             :                           RowExclusiveLock);
    2292             : 
    2293         154 :     foreach(cell, istmt->objects)
    2294             :     {
    2295          80 :         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          80 :         Datum       values[Natts_pg_largeobject_metadata] = {0};
    2308          80 :         bool        nulls[Natts_pg_largeobject_metadata] = {0};
    2309          80 :         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          80 :         ScanKeyInit(&entry[0],
    2320             :                     Anum_pg_largeobject_metadata_oid,
    2321             :                     BTEqualStrategyNumber, F_OIDEQ,
    2322             :                     ObjectIdGetDatum(loid));
    2323             : 
    2324          80 :         scan = systable_beginscan(relation,
    2325             :                                   LargeObjectMetadataOidIndexId, true,
    2326             :                                   NULL, 1, entry);
    2327             : 
    2328          80 :         tuple = systable_getnext(scan);
    2329          80 :         if (!HeapTupleIsValid(tuple))
    2330           0 :             elog(ERROR, "could not find tuple for large object %u", loid);
    2331             : 
    2332          80 :         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          80 :         ownerId = form_lo_meta->lomowner;
    2339          80 :         aclDatum = heap_getattr(tuple,
    2340             :                                 Anum_pg_largeobject_metadata_lomacl,
    2341             :                                 RelationGetDescr(relation), &isNull);
    2342          80 :         if (isNull)
    2343             :         {
    2344          44 :             old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    2345             :             /* There are no old member roles according to the catalogs */
    2346          44 :             noldmembers = 0;
    2347          44 :             oldmembers = NULL;
    2348             :         }
    2349             :         else
    2350             :         {
    2351          36 :             old_acl = DatumGetAclPCopy(aclDatum);
    2352             :             /* Get the roles mentioned in the existing ACL */
    2353          36 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2354             :         }
    2355             : 
    2356             :         /* Determine ID to do the grant as, and available grant options */
    2357          80 :         select_best_grantor(GetUserId(), istmt->privileges,
    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          80 :         snprintf(loname, sizeof(loname), "large object %u", loid);
    2366             :         this_privileges =
    2367          80 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2368          80 :                                      istmt->all_privs, istmt->privileges,
    2369             :                                      loid, grantorId, OBJECT_LARGEOBJECT,
    2370             :                                      loname, 0, NULL);
    2371             : 
    2372             :         /*
    2373             :          * Generate new ACL.
    2374             :          */
    2375          80 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2376          80 :                                        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          80 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2385             : 
    2386             :         /* finished building new ACL value, now insert it */
    2387          80 :         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
    2388             :         values[Anum_pg_largeobject_metadata_lomacl - 1]
    2389          80 :             = PointerGetDatum(new_acl);
    2390             : 
    2391          80 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2392             :                                      values, nulls, replaces);
    2393             : 
    2394          80 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2395             : 
    2396             :         /* Update initial privileges for extensions */
    2397          80 :         recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
    2398             : 
    2399             :         /* Update the shared dependency ACL info */
    2400          80 :         updateAclDependencies(LargeObjectRelationId,
    2401             :                               form_lo_meta->oid, 0,
    2402             :                               ownerId,
    2403             :                               noldmembers, oldmembers,
    2404             :                               nnewmembers, newmembers);
    2405             : 
    2406          80 :         systable_endscan(scan);
    2407             : 
    2408          80 :         pfree(new_acl);
    2409             : 
    2410             :         /* prevent error when processing duplicate objects */
    2411          80 :         CommandCounterIncrement();
    2412             :     }
    2413             : 
    2414          74 :     table_close(relation, RowExclusiveLock);
    2415          74 : }
    2416             : 
    2417             : static void
    2418         106 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
    2419             : {
    2420             :     Form_pg_type pg_type_tuple;
    2421             : 
    2422         106 :     pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
    2423             : 
    2424         106 :     if (IsTrueArrayType(pg_type_tuple))
    2425           6 :         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         100 :     if (istmt->objtype == OBJECT_DOMAIN &&
    2432          20 :         pg_type_tuple->typtype != TYPTYPE_DOMAIN)
    2433           6 :         ereport(ERROR,
    2434             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2435             :                  errmsg("\"%s\" is not a domain",
    2436             :                         NameStr(pg_type_tuple->typname))));
    2437          94 : }
    2438             : 
    2439             : static void
    2440          96 : ExecGrant_Parameter(InternalGrant *istmt)
    2441             : {
    2442             :     Relation    relation;
    2443             :     ListCell   *cell;
    2444             : 
    2445          96 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2446          42 :         istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
    2447             : 
    2448          96 :     relation = table_open(ParameterAclRelationId, RowExclusiveLock);
    2449             : 
    2450         230 :     foreach(cell, istmt->objects)
    2451             :     {
    2452         134 :         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         134 :         tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
    2470         134 :         if (!HeapTupleIsValid(tuple))
    2471           0 :             elog(ERROR, "cache lookup failed for parameter ACL %u",
    2472             :                  parameterId);
    2473             : 
    2474             :         /* We'll need the GUC's name */
    2475         134 :         nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
    2476             :                                            Anum_pg_parameter_acl_parname);
    2477         134 :         parname = TextDatumGetCString(nameDatum);
    2478             : 
    2479             :         /* Treat all parameters as belonging to the bootstrap superuser. */
    2480         134 :         ownerId = BOOTSTRAP_SUPERUSERID;
    2481             : 
    2482             :         /*
    2483             :          * Get working copy of existing ACL. If there's no ACL, substitute the
    2484             :          * proper default.
    2485             :          */
    2486         134 :         aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    2487             :                                    Anum_pg_parameter_acl_paracl,
    2488             :                                    &isNull);
    2489             : 
    2490         134 :         if (isNull)
    2491             :         {
    2492          66 :             old_acl = acldefault(istmt->objtype, ownerId);
    2493             :             /* There are no old member roles according to the catalogs */
    2494          66 :             noldmembers = 0;
    2495          66 :             oldmembers = NULL;
    2496             :         }
    2497             :         else
    2498             :         {
    2499          68 :             old_acl = DatumGetAclPCopy(aclDatum);
    2500             :             /* Get the roles mentioned in the existing ACL */
    2501          68 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2502             :         }
    2503             : 
    2504             :         /* Determine ID to do the grant as, and available grant options */
    2505         134 :         select_best_grantor(GetUserId(), istmt->privileges,
    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         134 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2515         134 :                                      istmt->all_privs, istmt->privileges,
    2516             :                                      parameterId, grantorId,
    2517             :                                      OBJECT_PARAMETER_ACL,
    2518             :                                      parname,
    2519             :                                      0, NULL);
    2520             : 
    2521             :         /*
    2522             :          * Generate new ACL.
    2523             :          */
    2524         134 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2525         134 :                                        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         134 :         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         134 :         if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
    2541             :         {
    2542          58 :             CatalogTupleDelete(relation, &tuple->t_self);
    2543             :         }
    2544             :         else
    2545             :         {
    2546             :             /* finished building new ACL value, now insert it */
    2547             :             HeapTuple   newtuple;
    2548          76 :             Datum       values[Natts_pg_parameter_acl] = {0};
    2549          76 :             bool        nulls[Natts_pg_parameter_acl] = {0};
    2550          76 :             bool        replaces[Natts_pg_parameter_acl] = {0};
    2551             : 
    2552          76 :             replaces[Anum_pg_parameter_acl_paracl - 1] = true;
    2553          76 :             values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
    2554             : 
    2555          76 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2556             :                                          values, nulls, replaces);
    2557             : 
    2558          76 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2559             :         }
    2560             : 
    2561             :         /* Update initial privileges for extensions */
    2562         134 :         recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
    2563             :                                 new_acl);
    2564             : 
    2565             :         /* Update the shared dependency ACL info */
    2566         134 :         updateAclDependencies(ParameterAclRelationId, parameterId, 0,
    2567             :                               ownerId,
    2568             :                               noldmembers, oldmembers,
    2569             :                               nnewmembers, newmembers);
    2570             : 
    2571         134 :         ReleaseSysCache(tuple);
    2572         134 :         pfree(new_acl);
    2573             : 
    2574             :         /* prevent error when processing duplicate objects */
    2575         134 :         CommandCounterIncrement();
    2576             :     }
    2577             : 
    2578          96 :     table_close(relation, RowExclusiveLock);
    2579          96 : }
    2580             : 
    2581             : 
    2582             : static AclMode
    2583       89840 : string_to_privilege(const char *privname)
    2584             : {
    2585       89840 :     if (strcmp(privname, "insert") == 0)
    2586         222 :         return ACL_INSERT;
    2587       89618 :     if (strcmp(privname, "select") == 0)
    2588       40588 :         return ACL_SELECT;
    2589       49030 :     if (strcmp(privname, "update") == 0)
    2590         848 :         return ACL_UPDATE;
    2591       48182 :     if (strcmp(privname, "delete") == 0)
    2592         114 :         return ACL_DELETE;
    2593       48068 :     if (strcmp(privname, "truncate") == 0)
    2594          34 :         return ACL_TRUNCATE;
    2595       48034 :     if (strcmp(privname, "references") == 0)
    2596          14 :         return ACL_REFERENCES;
    2597       48020 :     if (strcmp(privname, "trigger") == 0)
    2598           8 :         return ACL_TRIGGER;
    2599       48012 :     if (strcmp(privname, "execute") == 0)
    2600       43766 :         return ACL_EXECUTE;
    2601        4246 :     if (strcmp(privname, "usage") == 0)
    2602        1634 :         return ACL_USAGE;
    2603        2612 :     if (strcmp(privname, "create") == 0)
    2604        1296 :         return ACL_CREATE;
    2605        1316 :     if (strcmp(privname, "temporary") == 0)
    2606        1206 :         return ACL_CREATE_TEMP;
    2607         110 :     if (strcmp(privname, "temp") == 0)
    2608           0 :         return ACL_CREATE_TEMP;
    2609         110 :     if (strcmp(privname, "connect") == 0)
    2610           6 :         return ACL_CONNECT;
    2611         104 :     if (strcmp(privname, "set") == 0)
    2612          48 :         return ACL_SET;
    2613          56 :     if (strcmp(privname, "alter system") == 0)
    2614          24 :         return ACL_ALTER_SYSTEM;
    2615          32 :     if (strcmp(privname, "maintain") == 0)
    2616          32 :         return ACL_MAINTAIN;
    2617           0 :     if (strcmp(privname, "rule") == 0)
    2618           0 :         return 0;               /* ignore old RULE privileges */
    2619           0 :     ereport(ERROR,
    2620             :             (errcode(ERRCODE_SYNTAX_ERROR),
    2621             :              errmsg("unrecognized privilege type \"%s\"", privname)));
    2622             :     return 0;                   /* appease compiler */
    2623             : }
    2624             : 
    2625             : static const char *
    2626          24 : privilege_to_string(AclMode privilege)
    2627             : {
    2628          24 :     switch (privilege)
    2629             :     {
    2630           6 :         case ACL_INSERT:
    2631           6 :             return "INSERT";
    2632           0 :         case ACL_SELECT:
    2633           0 :             return "SELECT";
    2634           0 :         case ACL_UPDATE:
    2635           0 :             return "UPDATE";
    2636           0 :         case ACL_DELETE:
    2637           0 :             return "DELETE";
    2638           0 :         case ACL_TRUNCATE:
    2639           0 :             return "TRUNCATE";
    2640           0 :         case ACL_REFERENCES:
    2641           0 :             return "REFERENCES";
    2642           0 :         case ACL_TRIGGER:
    2643           0 :             return "TRIGGER";
    2644           0 :         case ACL_EXECUTE:
    2645           0 :             return "EXECUTE";
    2646          18 :         case ACL_USAGE:
    2647          18 :             return "USAGE";
    2648           0 :         case ACL_CREATE:
    2649           0 :             return "CREATE";
    2650           0 :         case ACL_CREATE_TEMP:
    2651           0 :             return "TEMP";
    2652           0 :         case ACL_CONNECT:
    2653           0 :             return "CONNECT";
    2654           0 :         case ACL_SET:
    2655           0 :             return "SET";
    2656           0 :         case ACL_ALTER_SYSTEM:
    2657           0 :             return "ALTER SYSTEM";
    2658           0 :         case ACL_MAINTAIN:
    2659           0 :             return "MAINTAIN";
    2660           0 :         default:
    2661           0 :             elog(ERROR, "unrecognized privilege: %d", (int) privilege);
    2662             :     }
    2663             :     return NULL;                /* appease compiler */
    2664             : }
    2665             : 
    2666             : /*
    2667             :  * Standardized reporting of aclcheck permissions failures.
    2668             :  *
    2669             :  * Note: we do not double-quote the %s's below, because many callers
    2670             :  * supply strings that might be already quoted.
    2671             :  */
    2672             : void
    2673        2330 : aclcheck_error(AclResult aclerr, ObjectType objtype,
    2674             :                const char *objectname)
    2675             : {
    2676        2330 :     switch (aclerr)
    2677             :     {
    2678           0 :         case ACLCHECK_OK:
    2679             :             /* no error, so return to caller */
    2680           0 :             break;
    2681        1786 :         case ACLCHECK_NO_PRIV:
    2682             :             {
    2683        1786 :                 const char *msg = "???";
    2684             : 
    2685             :                 switch (objtype)
    2686             :                 {
    2687           6 :                     case OBJECT_AGGREGATE:
    2688           6 :                         msg = gettext_noop("permission denied for aggregate %s");
    2689           6 :                         break;
    2690           0 :                     case OBJECT_COLLATION:
    2691           0 :                         msg = gettext_noop("permission denied for collation %s");
    2692           0 :                         break;
    2693           0 :                     case OBJECT_COLUMN:
    2694           0 :                         msg = gettext_noop("permission denied for column %s");
    2695           0 :                         break;
    2696           0 :                     case OBJECT_CONVERSION:
    2697           0 :                         msg = gettext_noop("permission denied for conversion %s");
    2698           0 :                         break;
    2699          18 :                     case OBJECT_DATABASE:
    2700          18 :                         msg = gettext_noop("permission denied for database %s");
    2701          18 :                         break;
    2702           0 :                     case OBJECT_DOMAIN:
    2703           0 :                         msg = gettext_noop("permission denied for domain %s");
    2704           0 :                         break;
    2705           0 :                     case OBJECT_EVENT_TRIGGER:
    2706           0 :                         msg = gettext_noop("permission denied for event trigger %s");
    2707           0 :                         break;
    2708           0 :                     case OBJECT_EXTENSION:
    2709           0 :                         msg = gettext_noop("permission denied for extension %s");
    2710           0 :                         break;
    2711          44 :                     case OBJECT_FDW:
    2712          44 :                         msg = gettext_noop("permission denied for foreign-data wrapper %s");
    2713          44 :                         break;
    2714          20 :                     case OBJECT_FOREIGN_SERVER:
    2715          20 :                         msg = gettext_noop("permission denied for foreign server %s");
    2716          20 :                         break;
    2717           2 :                     case OBJECT_FOREIGN_TABLE:
    2718           2 :                         msg = gettext_noop("permission denied for foreign table %s");
    2719           2 :                         break;
    2720         100 :                     case OBJECT_FUNCTION:
    2721         100 :                         msg = gettext_noop("permission denied for function %s");
    2722         100 :                         break;
    2723           0 :                     case OBJECT_INDEX:
    2724           0 :                         msg = gettext_noop("permission denied for index %s");
    2725           0 :                         break;
    2726           8 :                     case OBJECT_LANGUAGE:
    2727           8 :                         msg = gettext_noop("permission denied for language %s");
    2728           8 :                         break;
    2729           0 :                     case OBJECT_LARGEOBJECT:
    2730           0 :                         msg = gettext_noop("permission denied for large object %s");
    2731           0 :                         break;
    2732           0 :                     case OBJECT_MATVIEW:
    2733           0 :                         msg = gettext_noop("permission denied for materialized view %s");
    2734           0 :                         break;
    2735           0 :                     case OBJECT_OPCLASS:
    2736           0 :                         msg = gettext_noop("permission denied for operator class %s");
    2737           0 :                         break;
    2738           0 :                     case OBJECT_OPERATOR:
    2739           0 :                         msg = gettext_noop("permission denied for operator %s");
    2740           0 :                         break;
    2741           0 :                     case OBJECT_OPFAMILY:
    2742           0 :                         msg = gettext_noop("permission denied for operator family %s");
    2743           0 :                         break;
    2744           0 :                     case OBJECT_PARAMETER_ACL:
    2745           0 :                         msg = gettext_noop("permission denied for parameter %s");
    2746           0 :                         break;
    2747           0 :                     case OBJECT_POLICY:
    2748           0 :                         msg = gettext_noop("permission denied for policy %s");
    2749           0 :                         break;
    2750          12 :                     case OBJECT_PROCEDURE:
    2751          12 :                         msg = gettext_noop("permission denied for procedure %s");
    2752          12 :                         break;
    2753           0 :                     case OBJECT_PUBLICATION:
    2754           0 :                         msg = gettext_noop("permission denied for publication %s");
    2755           0 :                         break;
    2756           0 :                     case OBJECT_ROUTINE:
    2757           0 :                         msg = gettext_noop("permission denied for routine %s");
    2758           0 :                         break;
    2759          14 :                     case OBJECT_SCHEMA:
    2760          14 :                         msg = gettext_noop("permission denied for schema %s");
    2761          14 :                         break;
    2762           0 :                     case OBJECT_SEQUENCE:
    2763           0 :                         msg = gettext_noop("permission denied for sequence %s");
    2764           0 :                         break;
    2765           0 :                     case OBJECT_STATISTIC_EXT:
    2766           0 :                         msg = gettext_noop("permission denied for statistics object %s");
    2767           0 :                         break;
    2768           0 :                     case OBJECT_SUBSCRIPTION:
    2769           0 :                         msg = gettext_noop("permission denied for subscription %s");
    2770           0 :                         break;
    2771        1164 :                     case OBJECT_TABLE:
    2772        1164 :                         msg = gettext_noop("permission denied for table %s");
    2773        1164 :                         break;
    2774          18 :                     case OBJECT_TABLESPACE:
    2775          18 :                         msg = gettext_noop("permission denied for tablespace %s");
    2776          18 :                         break;
    2777           0 :                     case OBJECT_TSCONFIGURATION:
    2778           0 :                         msg = gettext_noop("permission denied for text search configuration %s");
    2779           0 :                         break;
    2780           0 :                     case OBJECT_TSDICTIONARY:
    2781           0 :                         msg = gettext_noop("permission denied for text search dictionary %s");
    2782           0 :                         break;
    2783         114 :                     case OBJECT_TYPE:
    2784         114 :                         msg = gettext_noop("permission denied for type %s");
    2785         114 :                         break;
    2786         266 :                     case OBJECT_VIEW:
    2787         266 :                         msg = gettext_noop("permission denied for view %s");
    2788         266 :                         break;
    2789             :                         /* these currently aren't used */
    2790           0 :                     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:
    2798             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2799             :                     case OBJECT_PUBLICATION_REL:
    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           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2809             :                 }
    2810             : 
    2811        1786 :                 ereport(ERROR,
    2812             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2813             :                          errmsg(msg, objectname)));
    2814             :                 break;
    2815             :             }
    2816         544 :         case ACLCHECK_NOT_OWNER:
    2817             :             {
    2818         544 :                 const char *msg = "???";
    2819             : 
    2820             :                 switch (objtype)
    2821             :                 {
    2822           6 :                     case OBJECT_AGGREGATE:
    2823           6 :                         msg = gettext_noop("must be owner of aggregate %s");
    2824           6 :                         break;
    2825           0 :                     case OBJECT_COLLATION:
    2826           0 :                         msg = gettext_noop("must be owner of collation %s");
    2827           0 :                         break;
    2828          18 :                     case OBJECT_CONVERSION:
    2829          18 :                         msg = gettext_noop("must be owner of conversion %s");
    2830          18 :                         break;
    2831           0 :                     case OBJECT_DATABASE:
    2832           0 :                         msg = gettext_noop("must be owner of database %s");
    2833           0 :                         break;
    2834           0 :                     case OBJECT_DOMAIN:
    2835           0 :                         msg = gettext_noop("must be owner of domain %s");
    2836           0 :                         break;
    2837           0 :                     case OBJECT_EVENT_TRIGGER:
    2838           0 :                         msg = gettext_noop("must be owner of event trigger %s");
    2839           0 :                         break;
    2840           0 :                     case OBJECT_EXTENSION:
    2841           0 :                         msg = gettext_noop("must be owner of extension %s");
    2842           0 :                         break;
    2843          18 :                     case OBJECT_FDW:
    2844          18 :                         msg = gettext_noop("must be owner of foreign-data wrapper %s");
    2845          18 :                         break;
    2846         114 :                     case OBJECT_FOREIGN_SERVER:
    2847         114 :                         msg = gettext_noop("must be owner of foreign server %s");
    2848         114 :                         break;
    2849           0 :                     case OBJECT_FOREIGN_TABLE:
    2850           0 :                         msg = gettext_noop("must be owner of foreign table %s");
    2851           0 :                         break;
    2852          42 :                     case OBJECT_FUNCTION:
    2853          42 :                         msg = gettext_noop("must be owner of function %s");
    2854          42 :                         break;
    2855          36 :                     case OBJECT_INDEX:
    2856          36 :                         msg = gettext_noop("must be owner of index %s");
    2857          36 :                         break;
    2858          12 :                     case OBJECT_LANGUAGE:
    2859          12 :                         msg = gettext_noop("must be owner of language %s");
    2860          12 :                         break;
    2861           0 :                     case OBJECT_LARGEOBJECT:
    2862           0 :                         msg = gettext_noop("must be owner of large object %s");
    2863           0 :                         break;
    2864           0 :                     case OBJECT_MATVIEW:
    2865           0 :                         msg = gettext_noop("must be owner of materialized view %s");
    2866           0 :                         break;
    2867          18 :                     case OBJECT_OPCLASS:
    2868          18 :                         msg = gettext_noop("must be owner of operator class %s");
    2869          18 :                         break;
    2870          18 :                     case OBJECT_OPERATOR:
    2871          18 :                         msg = gettext_noop("must be owner of operator %s");
    2872          18 :                         break;
    2873          18 :                     case OBJECT_OPFAMILY:
    2874          18 :                         msg = gettext_noop("must be owner of operator family %s");
    2875          18 :                         break;
    2876           6 :                     case OBJECT_PROCEDURE:
    2877           6 :                         msg = gettext_noop("must be owner of procedure %s");
    2878           6 :                         break;
    2879           6 :                     case OBJECT_PUBLICATION:
    2880           6 :                         msg = gettext_noop("must be owner of publication %s");
    2881           6 :                         break;
    2882           0 :                     case OBJECT_ROUTINE:
    2883           0 :                         msg = gettext_noop("must be owner of routine %s");
    2884           0 :                         break;
    2885           6 :                     case OBJECT_SEQUENCE:
    2886           6 :                         msg = gettext_noop("must be owner of sequence %s");
    2887           6 :                         break;
    2888           6 :                     case OBJECT_SUBSCRIPTION:
    2889           6 :                         msg = gettext_noop("must be owner of subscription %s");
    2890           6 :                         break;
    2891          88 :                     case OBJECT_TABLE:
    2892          88 :                         msg = gettext_noop("must be owner of table %s");
    2893          88 :                         break;
    2894           6 :                     case OBJECT_TYPE:
    2895           6 :                         msg = gettext_noop("must be owner of type %s");
    2896           6 :                         break;
    2897          18 :                     case OBJECT_VIEW:
    2898          18 :                         msg = gettext_noop("must be owner of view %s");
    2899          18 :                         break;
    2900          18 :                     case OBJECT_SCHEMA:
    2901          18 :                         msg = gettext_noop("must be owner of schema %s");
    2902          18 :                         break;
    2903          36 :                     case OBJECT_STATISTIC_EXT:
    2904          36 :                         msg = gettext_noop("must be owner of statistics object %s");
    2905          36 :                         break;
    2906           0 :                     case OBJECT_TABLESPACE:
    2907           0 :                         msg = gettext_noop("must be owner of tablespace %s");
    2908           0 :                         break;
    2909          18 :                     case OBJECT_TSCONFIGURATION:
    2910          18 :                         msg = gettext_noop("must be owner of text search configuration %s");
    2911          18 :                         break;
    2912          18 :                     case OBJECT_TSDICTIONARY:
    2913          18 :                         msg = gettext_noop("must be owner of text search dictionary %s");
    2914          18 :                         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          18 :                     case OBJECT_COLUMN:
    2923             :                     case OBJECT_POLICY:
    2924             :                     case OBJECT_RULE:
    2925             :                     case OBJECT_TABCONSTRAINT:
    2926             :                     case OBJECT_TRIGGER:
    2927          18 :                         msg = gettext_noop("must be owner of relation %s");
    2928          18 :                         break;
    2929             :                         /* these currently aren't used */
    2930           0 :                     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:
    2939             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2940             :                     case OBJECT_PUBLICATION_REL:
    2941             :                     case OBJECT_ROLE:
    2942             :                     case OBJECT_TRANSFORM:
    2943             :                     case OBJECT_TSPARSER:
    2944             :                     case OBJECT_TSTEMPLATE:
    2945             :                     case OBJECT_USER_MAPPING:
    2946           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2947             :                 }
    2948             : 
    2949         544 :                 ereport(ERROR,
    2950             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2951             :                          errmsg(msg, objectname)));
    2952             :                 break;
    2953             :             }
    2954           0 :         default:
    2955           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    2956             :             break;
    2957             :     }
    2958           0 : }
    2959             : 
    2960             : 
    2961             : void
    2962           0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
    2963             :                    const char *objectname, const char *colname)
    2964             : {
    2965           0 :     switch (aclerr)
    2966             :     {
    2967           0 :         case ACLCHECK_OK:
    2968             :             /* no error, so return to caller */
    2969           0 :             break;
    2970           0 :         case ACLCHECK_NO_PRIV:
    2971           0 :             ereport(ERROR,
    2972             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2973             :                      errmsg("permission denied for column \"%s\" of relation \"%s\"",
    2974             :                             colname, objectname)));
    2975             :             break;
    2976           0 :         case ACLCHECK_NOT_OWNER:
    2977             :             /* relation msg is OK since columns don't have separate owners */
    2978           0 :             aclcheck_error(aclerr, objtype, objectname);
    2979           0 :             break;
    2980           0 :         default:
    2981           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    2982             :             break;
    2983             :     }
    2984           0 : }
    2985             : 
    2986             : 
    2987             : /*
    2988             :  * Special common handling for types: use element type instead of array type,
    2989             :  * and format nicely
    2990             :  */
    2991             : void
    2992         114 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
    2993             : {
    2994         114 :     Oid         element_type = get_element_type(typeOid);
    2995             : 
    2996         114 :     aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
    2997           0 : }
    2998             : 
    2999             : 
    3000             : /*
    3001             :  * Relay for the various pg_*_mask routines depending on object kind
    3002             :  */
    3003             : static AclMode
    3004          66 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
    3005             :            AclMode mask, AclMaskHow how)
    3006             : {
    3007          66 :     switch (objtype)
    3008             :     {
    3009           0 :         case OBJECT_COLUMN:
    3010             :             return
    3011           0 :                 pg_class_aclmask(object_oid, roleid, mask, how) |
    3012           0 :                 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
    3013          12 :         case OBJECT_TABLE:
    3014             :         case OBJECT_SEQUENCE:
    3015          12 :             return pg_class_aclmask(object_oid, roleid, mask, how);
    3016           0 :         case OBJECT_DATABASE:
    3017           0 :             return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
    3018           0 :         case OBJECT_FUNCTION:
    3019           0 :             return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
    3020           6 :         case OBJECT_LANGUAGE:
    3021           6 :             return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
    3022           0 :         case OBJECT_LARGEOBJECT:
    3023           0 :             return pg_largeobject_aclmask_snapshot(object_oid, roleid,
    3024             :                                                    mask, how, NULL);
    3025           0 :         case OBJECT_PARAMETER_ACL:
    3026           0 :             return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
    3027           0 :         case OBJECT_SCHEMA:
    3028           0 :             return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
    3029           0 :         case OBJECT_STATISTIC_EXT:
    3030           0 :             elog(ERROR, "grantable rights not supported for statistics objects");
    3031             :             /* not reached, but keep compiler quiet */
    3032             :             return ACL_NO_RIGHTS;
    3033           0 :         case OBJECT_TABLESPACE:
    3034           0 :             return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
    3035          18 :         case OBJECT_FDW:
    3036          18 :             return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
    3037          18 :         case OBJECT_FOREIGN_SERVER:
    3038          18 :             return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
    3039           0 :         case OBJECT_EVENT_TRIGGER:
    3040           0 :             elog(ERROR, "grantable rights not supported for event triggers");
    3041             :             /* not reached, but keep compiler quiet */
    3042             :             return ACL_NO_RIGHTS;
    3043          12 :         case OBJECT_TYPE:
    3044          12 :             return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
    3045           0 :         default:
    3046           0 :             elog(ERROR, "unrecognized object type: %d",
    3047             :                  (int) objtype);
    3048             :             /* not reached, but keep compiler quiet */
    3049             :             return ACL_NO_RIGHTS;
    3050             :     }
    3051             : }
    3052             : 
    3053             : 
    3054             : /* ****************************************************************
    3055             :  * Exported routines for examining a user's privileges for various objects
    3056             :  *
    3057             :  * See aclmask() for a description of the common API for these functions.
    3058             :  *
    3059             :  * Note: we give lookup failure the full ereport treatment because the
    3060             :  * has_xxx_privilege() family of functions allow users to pass any random
    3061             :  * OID to these functions.
    3062             :  * ****************************************************************
    3063             :  */
    3064             : 
    3065             : /*
    3066             :  * Generic routine for examining a user's privileges for an object
    3067             :  */
    3068             : static AclMode
    3069     3918240 : object_aclmask(Oid classid, Oid objectid, Oid roleid,
    3070             :                AclMode mask, AclMaskHow how)
    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     3918240 :     switch (classid)
    3082             :     {
    3083     1024406 :         case NamespaceRelationId:
    3084     1024406 :             return pg_namespace_aclmask(objectid, roleid, mask, how);
    3085     1230842 :         case TypeRelationId:
    3086     1230842 :             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     1662992 :     if (superuser_arg(roleid))
    3096     1631180 :         return mask;
    3097             : 
    3098             :     /*
    3099             :      * Get the objects's ACL from its catalog
    3100             :      */
    3101             : 
    3102       31812 :     cacheid = get_object_catcache_oid(classid);
    3103             : 
    3104       31812 :     tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    3105       31812 :     if (!HeapTupleIsValid(tuple))
    3106           0 :         ereport(ERROR,
    3107             :                 (errcode(ERRCODE_UNDEFINED_DATABASE),
    3108             :                  errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
    3109             : 
    3110       31812 :     ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    3111             :                                                       tuple,
    3112       31812 :                                                       get_object_attnum_owner(classid)));
    3113             : 
    3114       31812 :     aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
    3115             :                                &isNull);
    3116       31812 :     if (isNull)
    3117             :     {
    3118             :         /* No ACL, so build default ACL */
    3119       29370 :         acl = acldefault(get_object_type(classid, objectid), ownerId);
    3120       29370 :         aclDatum = (Datum) 0;
    3121             :     }
    3122             :     else
    3123             :     {
    3124             :         /* detoast ACL if necessary */
    3125        2442 :         acl = DatumGetAclP(aclDatum);
    3126             :     }
    3127             : 
    3128       31812 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3129             : 
    3130             :     /* if we have a detoasted copy, free it */
    3131       31812 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3132       31812 :         pfree(acl);
    3133             : 
    3134       31812 :     ReleaseSysCache(tuple);
    3135             : 
    3136       31812 :     return result;
    3137             : }
    3138             : 
    3139             : /*
    3140             :  * Routine for examining a user's privileges for a column
    3141             :  *
    3142             :  * Note: this considers only privileges granted specifically on the column.
    3143             :  * It is caller's responsibility to take relation-level privileges into account
    3144             :  * as appropriate.  (For the same reason, we have no special case for
    3145             :  * superuser-ness here.)
    3146             :  */
    3147             : static AclMode
    3148         180 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
    3149             :                      AclMode mask, AclMaskHow how)
    3150             : {
    3151         180 :     return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
    3152             :                                     mask, how, NULL);
    3153             : }
    3154             : 
    3155             : /*
    3156             :  * Routine for examining a user's privileges for a column
    3157             :  *
    3158             :  * Does the bulk of the work for pg_attribute_aclmask(), and allows other
    3159             :  * callers to avoid the missing attribute ERROR when is_missing is non-NULL.
    3160             :  */
    3161             : static AclMode
    3162        5576 : pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
    3163             :                          AclMode mask, AclMaskHow how, bool *is_missing)
    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        5576 :     attTuple = SearchSysCache2(ATTNUM,
    3179             :                                ObjectIdGetDatum(table_oid),
    3180             :                                Int16GetDatum(attnum));
    3181        5576 :     if (!HeapTupleIsValid(attTuple))
    3182             :     {
    3183          30 :         if (is_missing != NULL)
    3184             :         {
    3185             :             /* return "no privileges" instead of throwing an error */
    3186          30 :             *is_missing = true;
    3187          30 :             return 0;
    3188             :         }
    3189             :         else
    3190           0 :             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        5546 :     attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
    3197             : 
    3198             :     /* Check dropped columns, too */
    3199        5546 :     if (attributeForm->attisdropped)
    3200             :     {
    3201          12 :         if (is_missing != NULL)
    3202             :         {
    3203             :             /* return "no privileges" instead of throwing an error */
    3204          12 :             *is_missing = true;
    3205          12 :             ReleaseSysCache(attTuple);
    3206          12 :             return 0;
    3207             :         }
    3208             :         else
    3209           0 :             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        5534 :     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        5534 :     if (isNull)
    3224             :     {
    3225        3078 :         ReleaseSysCache(attTuple);
    3226        3078 :         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        2456 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3238        2456 :     if (!HeapTupleIsValid(classTuple))
    3239             :     {
    3240           0 :         ReleaseSysCache(attTuple);
    3241           0 :         return 0;
    3242             :     }
    3243        2456 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3244             : 
    3245        2456 :     ownerId = classForm->relowner;
    3246             : 
    3247        2456 :     ReleaseSysCache(classTuple);
    3248             : 
    3249             :     /* detoast column's ACL if necessary */
    3250        2456 :     acl = DatumGetAclP(aclDatum);
    3251             : 
    3252        2456 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3253             : 
    3254             :     /* if we have a detoasted copy, free it */
    3255        2456 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3256        2456 :         pfree(acl);
    3257             : 
    3258        2456 :     ReleaseSysCache(attTuple);
    3259             : 
    3260        2456 :     return result;
    3261             : }
    3262             : 
    3263             : /*
    3264             :  * Exported routine for examining a user's privileges for a table
    3265             :  */
    3266             : AclMode
    3267      479544 : pg_class_aclmask(Oid table_oid, Oid roleid,
    3268             :                  AclMode mask, AclMaskHow how)
    3269             : {
    3270      479544 :     return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
    3271             : }
    3272             : 
    3273             : /*
    3274             :  * Routine for examining a user's privileges for a table
    3275             :  *
    3276             :  * Does the bulk of the work for pg_class_aclmask(), and allows other
    3277             :  * callers to avoid the missing relation ERROR when is_missing is non-NULL.
    3278             :  */
    3279             : static AclMode
    3280     2147168 : pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
    3281             :                      AclMaskHow how, bool *is_missing)
    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     2147168 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3295     2147168 :     if (!HeapTupleIsValid(tuple))
    3296             :     {
    3297           0 :         if (is_missing != NULL)
    3298             :         {
    3299             :             /* return "no privileges" instead of throwing an error */
    3300           0 :             *is_missing = true;
    3301           0 :             return 0;
    3302             :         }
    3303             :         else
    3304           0 :             ereport(ERROR,
    3305             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3306             :                      errmsg("relation with OID %u does not exist",
    3307             :                             table_oid)));
    3308             :     }
    3309             : 
    3310     2147168 :     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     2804520 :     if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
    3321      657352 :         IsSystemClass(table_oid, classForm) &&
    3322       11470 :         classForm->relkind != RELKIND_VIEW &&
    3323       11470 :         !superuser_arg(roleid))
    3324          70 :         mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
    3325             : 
    3326             :     /*
    3327             :      * Otherwise, superusers bypass all permission-checking.
    3328             :      */
    3329     2147168 :     if (superuser_arg(roleid))
    3330             :     {
    3331     2119476 :         ReleaseSysCache(tuple);
    3332     2119476 :         return mask;
    3333             :     }
    3334             : 
    3335             :     /*
    3336             :      * Normal case: get the relation's ACL from pg_class
    3337             :      */
    3338       27692 :     ownerId = classForm->relowner;
    3339             : 
    3340       27692 :     aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    3341             :                                &isNull);
    3342       27692 :     if (isNull)
    3343             :     {
    3344             :         /* No ACL, so build default ACL */
    3345        5858 :         switch (classForm->relkind)
    3346             :         {
    3347          36 :             case RELKIND_SEQUENCE:
    3348          36 :                 acl = acldefault(OBJECT_SEQUENCE, ownerId);
    3349          36 :                 break;
    3350        5822 :             default:
    3351        5822 :                 acl = acldefault(OBJECT_TABLE, ownerId);
    3352        5822 :                 break;
    3353             :         }
    3354        5858 :         aclDatum = (Datum) 0;
    3355             :     }
    3356             :     else
    3357             :     {
    3358             :         /* detoast rel's ACL if necessary */
    3359       21834 :         acl = DatumGetAclP(aclDatum);
    3360             :     }
    3361             : 
    3362       27692 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3363             : 
    3364             :     /* if we have a detoasted copy, free it */
    3365       27692 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3366       27692 :         pfree(acl);
    3367             : 
    3368       27692 :     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       29588 :     if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
    3376        1896 :         has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
    3377          12 :         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       27692 :     if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
    3387        5970 :         !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
    3388        1242 :         has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
    3389          18 :         result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
    3390             : 
    3391             :     /*
    3392             :      * Check if ACL_MAINTAIN is being checked and, if so, and not already set
    3393             :      * as part of the result, then check if the user is a member of the
    3394             :      * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
    3395             :      * MATERIALIZED VIEW, and REINDEX on all relations.
    3396             :      */
    3397       27692 :     if (mask & ACL_MAINTAIN &&
    3398        2476 :         !(result & ACL_MAINTAIN) &&
    3399         862 :         has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
    3400          66 :         result |= ACL_MAINTAIN;
    3401             : 
    3402       27692 :     return result;
    3403             : }
    3404             : 
    3405             : /*
    3406             :  * Routine for examining a user's privileges for a configuration
    3407             :  * parameter (GUC), identified by GUC name.
    3408             :  */
    3409             : static AclMode
    3410         158 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
    3411             : {
    3412             :     AclMode     result;
    3413             :     char       *parname;
    3414             :     text       *partext;
    3415             :     HeapTuple   tuple;
    3416             : 
    3417             :     /* Superusers bypass all permission checking. */
    3418         158 :     if (superuser_arg(roleid))
    3419           2 :         return mask;
    3420             : 
    3421             :     /* Convert name to the form it should have in pg_parameter_acl... */
    3422         156 :     parname = convert_GUC_name_for_parameter_acl(name);
    3423         156 :     partext = cstring_to_text(parname);
    3424             : 
    3425             :     /* ... and look it up */
    3426         156 :     tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
    3427             : 
    3428         156 :     if (!HeapTupleIsValid(tuple))
    3429             :     {
    3430             :         /* If no entry, GUC has no permissions for non-superusers */
    3431          68 :         result = ACL_NO_RIGHTS;
    3432             :     }
    3433             :     else
    3434             :     {
    3435             :         Datum       aclDatum;
    3436             :         bool        isNull;
    3437             :         Acl        *acl;
    3438             : 
    3439          88 :         aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
    3440             :                                    Anum_pg_parameter_acl_paracl,
    3441             :                                    &isNull);
    3442          88 :         if (isNull)
    3443             :         {
    3444             :             /* No ACL, so build default ACL */
    3445           0 :             acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3446           0 :             aclDatum = (Datum) 0;
    3447             :         }
    3448             :         else
    3449             :         {
    3450             :             /* detoast ACL if necessary */
    3451          88 :             acl = DatumGetAclP(aclDatum);
    3452             :         }
    3453             : 
    3454          88 :         result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3455             : 
    3456             :         /* if we have a detoasted copy, free it */
    3457          88 :         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3458          88 :             pfree(acl);
    3459             : 
    3460          88 :         ReleaseSysCache(tuple);
    3461             :     }
    3462             : 
    3463         156 :     pfree(parname);
    3464         156 :     pfree(partext);
    3465             : 
    3466         156 :     return result;
    3467             : }
    3468             : 
    3469             : /*
    3470             :  * Routine for examining a user's privileges for a configuration
    3471             :  * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
    3472             :  */
    3473             : static AclMode
    3474           0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
    3475             : {
    3476             :     AclMode     result;
    3477             :     HeapTuple   tuple;
    3478             :     Datum       aclDatum;
    3479             :     bool        isNull;
    3480             :     Acl        *acl;
    3481             : 
    3482             :     /* Superusers bypass all permission checking. */
    3483           0 :     if (superuser_arg(roleid))
    3484           0 :         return mask;
    3485             : 
    3486             :     /* Get the ACL from pg_parameter_acl */
    3487           0 :     tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
    3488           0 :     if (!HeapTupleIsValid(tuple))
    3489           0 :         ereport(ERROR,
    3490             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3491             :                  errmsg("parameter ACL with OID %u does not exist",
    3492             :                         acl_oid)));
    3493             : 
    3494           0 :     aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    3495             :                                Anum_pg_parameter_acl_paracl,
    3496             :                                &isNull);
    3497           0 :     if (isNull)
    3498             :     {
    3499             :         /* No ACL, so build default ACL */
    3500           0 :         acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3501           0 :         aclDatum = (Datum) 0;
    3502             :     }
    3503             :     else
    3504             :     {
    3505             :         /* detoast ACL if necessary */
    3506           0 :         acl = DatumGetAclP(aclDatum);
    3507             :     }
    3508             : 
    3509           0 :     result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3510             : 
    3511             :     /* if we have a detoasted copy, free it */
    3512           0 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3513           0 :         pfree(acl);
    3514             : 
    3515           0 :     ReleaseSysCache(tuple);
    3516             : 
    3517           0 :     return result;
    3518             : }
    3519             : 
    3520             : /*
    3521             :  * Routine for examining a user's privileges for a largeobject
    3522             :  *
    3523             :  * When a large object is opened for reading, it is opened relative to the
    3524             :  * caller's snapshot, but when it is opened for writing, a current
    3525             :  * MVCC snapshot will be used.  See doc/src/sgml/lobj.sgml.  This function
    3526             :  * takes a snapshot argument so that the permissions check can be made
    3527             :  * relative to the same snapshot that will be used to read the underlying
    3528             :  * data.  The caller will actually pass NULL for an instantaneous MVCC
    3529             :  * snapshot, since all we do with the snapshot argument is pass it through
    3530             :  * to systable_beginscan().
    3531             :  */
    3532             : static AclMode
    3533         572 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
    3534             :                                 AclMode mask, AclMaskHow how,
    3535             :                                 Snapshot snapshot)
    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         572 :     if (superuser_arg(roleid))
    3549         422 :         return mask;
    3550             : 
    3551             :     /*
    3552             :      * Get the largeobject's ACL from pg_largeobject_metadata
    3553             :      */
    3554         150 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
    3555             :                             AccessShareLock);
    3556             : 
    3557         150 :     ScanKeyInit(&entry[0],
    3558             :                 Anum_pg_largeobject_metadata_oid,
    3559             :                 BTEqualStrategyNumber, F_OIDEQ,
    3560             :                 ObjectIdGetDatum(lobj_oid));
    3561             : 
    3562         150 :     scan = systable_beginscan(pg_lo_meta,
    3563             :                               LargeObjectMetadataOidIndexId, true,
    3564             :                               snapshot, 1, entry);
    3565             : 
    3566         150 :     tuple = systable_getnext(scan);
    3567         150 :     if (!HeapTupleIsValid(tuple))
    3568           0 :         ereport(ERROR,
    3569             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3570             :                  errmsg("large object %u does not exist", lobj_oid)));
    3571             : 
    3572         150 :     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
    3573             : 
    3574         150 :     aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
    3575             :                             RelationGetDescr(pg_lo_meta), &isNull);
    3576             : 
    3577         150 :     if (isNull)
    3578             :     {
    3579             :         /* No ACL, so build default ACL */
    3580          36 :         acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    3581          36 :         aclDatum = (Datum) 0;
    3582             :     }
    3583             :     else
    3584             :     {
    3585             :         /* detoast ACL if necessary */
    3586         114 :         acl = DatumGetAclP(aclDatum);
    3587             :     }
    3588             : 
    3589         150 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3590             : 
    3591             :     /* if we have a detoasted copy, free it */
    3592         150 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3593         150 :         pfree(acl);
    3594             : 
    3595         150 :     systable_endscan(scan);
    3596             : 
    3597         150 :     table_close(pg_lo_meta, AccessShareLock);
    3598             : 
    3599         150 :     return result;
    3600             : }
    3601             : 
    3602             : /*
    3603             :  * Routine for examining a user's privileges for a namespace
    3604             :  */
    3605             : static AclMode
    3606     1024406 : pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
    3607             :                      AclMode mask, AclMaskHow how)
    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     1024406 :     if (superuser_arg(roleid))
    3618     1009258 :         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       15148 :     if (isTempNamespace(nsp_oid))
    3640             :     {
    3641         186 :         if (object_aclcheck(DatabaseRelationId, MyDatabaseId, roleid,
    3642             :                             ACL_CREATE_TEMP) == ACLCHECK_OK)
    3643         186 :             return mask & ACL_ALL_RIGHTS_SCHEMA;
    3644             :         else
    3645           0 :             return mask & ACL_USAGE;
    3646             :     }
    3647             : 
    3648             :     /*
    3649             :      * Get the schema's ACL from pg_namespace
    3650             :      */
    3651       14962 :     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
    3652       14962 :     if (!HeapTupleIsValid(tuple))
    3653           0 :         ereport(ERROR,
    3654             :                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
    3655             :                  errmsg("schema with OID %u does not exist", nsp_oid)));
    3656             : 
    3657       14962 :     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
    3658             : 
    3659       14962 :     aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
    3660             :                                &isNull);
    3661       14962 :     if (isNull)
    3662             :     {
    3663             :         /* No ACL, so build default ACL */
    3664         276 :         acl = acldefault(OBJECT_SCHEMA, ownerId);
    3665         276 :         aclDatum = (Datum) 0;
    3666             :     }
    3667             :     else
    3668             :     {
    3669             :         /* detoast ACL if necessary */
    3670       14686 :         acl = DatumGetAclP(aclDatum);
    3671             :     }
    3672             : 
    3673       14962 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3674             : 
    3675             :     /* if we have a detoasted copy, free it */
    3676       14962 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3677       14962 :         pfree(acl);
    3678             : 
    3679       14962 :     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       15000 :     if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
    3688          70 :         (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
    3689          32 :          has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
    3690          12 :         result |= ACL_USAGE;
    3691       14962 :     return result;
    3692             : }
    3693             : 
    3694             : /*
    3695             :  * Routine for examining a user's privileges for a type.
    3696             :  */
    3697             : static AclMode
    3698     1230842 : pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
    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     1230842 :     if (superuser_arg(roleid))
    3711     1226828 :         return mask;
    3712             : 
    3713             :     /*
    3714             :      * Must get the type's tuple from pg_type
    3715             :      */
    3716        4014 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
    3717        4014 :     if (!HeapTupleIsValid(tuple))
    3718           0 :         ereport(ERROR,
    3719             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3720             :                  errmsg("type with OID %u does not exist",
    3721             :                         type_oid)));
    3722        4014 :     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        4014 :     if (IsTrueArrayType(typeForm))
    3729             :     {
    3730          36 :         Oid         elttype_oid = typeForm->typelem;
    3731             : 
    3732          36 :         ReleaseSysCache(tuple);
    3733             : 
    3734          36 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
    3735             :         /* this case is not a user-facing error, so elog not ereport */
    3736          36 :         if (!HeapTupleIsValid(tuple))
    3737           0 :             elog(ERROR, "cache lookup failed for type %u", elttype_oid);
    3738          36 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3739             :     }
    3740             : 
    3741             :     /*
    3742             :      * Now get the type's owner and ACL from the tuple
    3743             :      */
    3744        4014 :     ownerId = typeForm->typowner;
    3745             : 
    3746        4014 :     aclDatum = SysCacheGetAttr(TYPEOID, tuple,
    3747             :                                Anum_pg_type_typacl, &isNull);
    3748        4014 :     if (isNull)
    3749             :     {
    3750             :         /* No ACL, so build default ACL */
    3751        3792 :         acl = acldefault(OBJECT_TYPE, ownerId);
    3752        3792 :         aclDatum = (Datum) 0;
    3753             :     }
    3754             :     else
    3755             :     {
    3756             :         /* detoast rel's ACL if necessary */
    3757         222 :         acl = DatumGetAclP(aclDatum);
    3758             :     }
    3759             : 
    3760        4014 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3761             : 
    3762             :     /* if we have a detoasted copy, free it */
    3763        4014 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3764        4014 :         pfree(acl);
    3765             : 
    3766        4014 :     ReleaseSysCache(tuple);
    3767             : 
    3768        4014 :     return result;
    3769             : }
    3770             : 
    3771             : /*
    3772             :  * Exported generic routine for checking a user's access privileges to an object
    3773             :  */
    3774             : AclResult
    3775     3918186 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
    3776             : {
    3777     3918186 :     if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0)
    3778     3917644 :         return ACLCHECK_OK;
    3779             :     else
    3780         542 :         return ACLCHECK_NO_PRIV;
    3781             : }
    3782             : 
    3783             : /*
    3784             :  * Exported routine for checking a user's access privileges to a column
    3785             :  *
    3786             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    3787             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    3788             :  * ACLCHECK_NO_PRIV).
    3789             :  *
    3790             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3791             :  * column are considered here.
    3792             :  */
    3793             : AclResult
    3794        3152 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
    3795             :                       Oid roleid, AclMode mode)
    3796             : {
    3797        3152 :     return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
    3798             : }
    3799             : 
    3800             : 
    3801             : /*
    3802             :  * Exported routine for checking a user's access privileges to a column
    3803             :  *
    3804             :  * Does the bulk of the work for pg_attribute_aclcheck(), and allows other
    3805             :  * callers to avoid the missing attribute ERROR when is_missing is non-NULL.
    3806             :  */
    3807             : AclResult
    3808        5396 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
    3809             :                           Oid roleid, AclMode mode, bool *is_missing)
    3810             : {
    3811        5396 :     if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
    3812             :                                  ACLMASK_ANY, is_missing) != 0)
    3813        1808 :         return ACLCHECK_OK;
    3814             :     else
    3815        3588 :         return ACLCHECK_NO_PRIV;
    3816             : }
    3817             : 
    3818             : /*
    3819             :  * Exported routine for checking a user's access privileges to any/all columns
    3820             :  *
    3821             :  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
    3822             :  * privileges identified by 'mode' on any non-dropped column in the relation;
    3823             :  * otherwise returns a suitable error code (in practice, always
    3824             :  * ACLCHECK_NO_PRIV).
    3825             :  *
    3826             :  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
    3827             :  * privileges identified by 'mode' on each non-dropped column in the relation
    3828             :  * (and there must be at least one such column); otherwise returns a suitable
    3829             :  * error code (in practice, always ACLCHECK_NO_PRIV).
    3830             :  *
    3831             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3832             :  * column(s) are considered here.
    3833             :  *
    3834             :  * Note: system columns are not considered here; there are cases where that
    3835             :  * might be appropriate but there are also cases where it wouldn't.
    3836             :  */
    3837             : AclResult
    3838         168 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
    3839             :                           AclMaskHow how)
    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         168 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3853         168 :     if (!HeapTupleIsValid(classTuple))
    3854           0 :         return ACLCHECK_NO_PRIV;
    3855         168 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3856             : 
    3857         168 :     nattrs = classForm->relnatts;
    3858             : 
    3859         168 :     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         168 :     result = ACLCHECK_NO_PRIV;
    3866             : 
    3867         432 :     for (curr_att = 1; curr_att <= nattrs; curr_att++)
    3868             :     {
    3869             :         HeapTuple   attTuple;
    3870             :         AclMode     attmask;
    3871             : 
    3872         342 :         attTuple = SearchSysCache2(ATTNUM,
    3873             :                                    ObjectIdGetDatum(table_oid),
    3874             :                                    Int16GetDatum(curr_att));
    3875         342 :         if (!HeapTupleIsValid(attTuple))
    3876           0 :             continue;
    3877             : 
    3878             :         /* ignore dropped columns */
    3879         342 :         if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    3880             :         {
    3881          18 :             ReleaseSysCache(attTuple);
    3882          18 :             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         324 :         if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
    3891         144 :             attmask = 0;
    3892             :         else
    3893         180 :             attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
    3894             :                                            mode, ACLMASK_ANY);
    3895             : 
    3896         324 :         ReleaseSysCache(attTuple);
    3897             : 
    3898         324 :         if (attmask != 0)
    3899             :         {
    3900         162 :             result = ACLCHECK_OK;
    3901         162 :             if (how == ACLMASK_ANY)
    3902          42 :                 break;          /* succeed on any success */
    3903             :         }
    3904             :         else
    3905             :         {
    3906         162 :             result = ACLCHECK_NO_PRIV;
    3907         162 :             if (how == ACLMASK_ALL)
    3908          36 :                 break;          /* fail on any failure */
    3909             :         }
    3910             :     }
    3911             : 
    3912         168 :     return result;
    3913             : }
    3914             : 
    3915             : /*
    3916             :  * Exported routine for checking a user's access privileges to a table
    3917             :  *
    3918             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    3919             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    3920             :  * ACLCHECK_NO_PRIV).
    3921             :  */
    3922             : AclResult
    3923     1665434 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
    3924             : {
    3925     1665434 :     return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
    3926             : }
    3927             : 
    3928             : /*
    3929             :  * Exported routine for checking a user's access privileges to a table
    3930             :  *
    3931             :  * Does the bulk of the work for pg_class_aclcheck(), and allows other
    3932             :  * callers to avoid the missing relation ERROR when is_missing is non-NULL.
    3933             :  */
    3934             : AclResult
    3935     1667624 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
    3936             :                       AclMode mode, bool *is_missing)
    3937             : {
    3938     1667624 :     if (pg_class_aclmask_ext(table_oid, roleid, mode,
    3939             :                              ACLMASK_ANY, is_missing) != 0)
    3940     1666290 :         return ACLCHECK_OK;
    3941             :     else
    3942        1334 :         return ACLCHECK_NO_PRIV;
    3943             : }
    3944             : 
    3945             : /*
    3946             :  * Exported routine for checking a user's access privileges to a configuration
    3947             :  * parameter (GUC), identified by GUC name.
    3948             :  */
    3949             : AclResult
    3950         158 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
    3951             : {
    3952         158 :     if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
    3953          68 :         return ACLCHECK_OK;
    3954             :     else
    3955          90 :         return ACLCHECK_NO_PRIV;
    3956             : }
    3957             : 
    3958             : /*
    3959             :  * Exported routine for checking a user's access privileges to a largeobject
    3960             :  */
    3961             : AclResult
    3962         572 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
    3963             :                                  Snapshot snapshot)
    3964             : {
    3965         572 :     if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
    3966             :                                         ACLMASK_ANY, snapshot) != 0)
    3967         518 :         return ACLCHECK_OK;
    3968             :     else
    3969          54 :         return ACLCHECK_NO_PRIV;
    3970             : }
    3971             : 
    3972             : /*
    3973             :  * Generic ownership check for an object
    3974             :  */
    3975             : bool
    3976      644632 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
    3977             : {
    3978             :     int         cacheid;
    3979             :     Oid         ownerId;
    3980             : 
    3981             :     /* Superusers bypass all permission checking. */
    3982      644632 :     if (superuser_arg(roleid))
    3983      637236 :         return true;
    3984             : 
    3985        7396 :     cacheid = get_object_catcache_oid(classid);
    3986        7396 :     if (cacheid != -1)
    3987             :     {
    3988             :         HeapTuple   tuple;
    3989             : 
    3990        7374 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    3991        7374 :         if (!HeapTupleIsValid(tuple))
    3992           0 :             ereport(ERROR,
    3993             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    3994             :                      errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
    3995             : 
    3996        7374 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    3997             :                                                           tuple,
    3998        7374 :                                                           get_object_attnum_owner(classid)));
    3999        7374 :         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          22 :         rel = table_open(classid, AccessShareLock);
    4012             : 
    4013          44 :         ScanKeyInit(&entry[0],
    4014          22 :                     get_object_attnum_oid(classid),
    4015             :                     BTEqualStrategyNumber, F_OIDEQ,
    4016             :                     ObjectIdGetDatum(objectid));
    4017             : 
    4018          22 :         scan = systable_beginscan(rel,
    4019             :                                   get_object_oid_index(classid), true,
    4020             :                                   NULL, 1, entry);
    4021             : 
    4022          22 :         tuple = systable_getnext(scan);
    4023          22 :         if (!HeapTupleIsValid(tuple))
    4024           0 :             ereport(ERROR,
    4025             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    4026             :                      errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
    4027             : 
    4028          22 :         ownerId = DatumGetObjectId(heap_getattr(tuple,
    4029          22 :                                                 get_object_attnum_owner(classid),
    4030             :                                                 RelationGetDescr(rel),
    4031             :                                                 &isnull));
    4032             :         Assert(!isnull);
    4033             : 
    4034          22 :         systable_endscan(scan);
    4035          22 :         table_close(rel, AccessShareLock);
    4036             :     }
    4037             : 
    4038        7396 :     return has_privs_of_role(roleid, ownerId);
    4039             : }
    4040             : 
    4041             : /*
    4042             :  * Check whether specified role has CREATEROLE privilege (or is a superuser)
    4043             :  *
    4044             :  * Note: roles do not have owners per se; instead we use this test in
    4045             :  * places where an ownership-like permissions test is needed for a role.
    4046             :  * Be sure to apply it to the role trying to do the operation, not the
    4047             :  * role being operated on!  Also note that this generally should not be
    4048             :  * considered enough privilege if the target role is a superuser.
    4049             :  * (We don't handle that consideration here because we want to give a
    4050             :  * separate error message for such cases, so the caller has to deal with it.)
    4051             :  */
    4052             : bool
    4053        2268 : has_createrole_privilege(Oid roleid)
    4054             : {
    4055        2268 :     bool        result = false;
    4056             :     HeapTuple   utup;
    4057             : 
    4058             :     /* Superusers bypass all permission checking. */
    4059        2268 :     if (superuser_arg(roleid))
    4060        1750 :         return true;
    4061             : 
    4062         518 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4063         518 :     if (HeapTupleIsValid(utup))
    4064             :     {
    4065         518 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
    4066         518 :         ReleaseSysCache(utup);
    4067             :     }
    4068         518 :     return result;
    4069             : }
    4070             : 
    4071             : bool
    4072        4238 : has_bypassrls_privilege(Oid roleid)
    4073             : {
    4074        4238 :     bool        result = false;
    4075             :     HeapTuple   utup;
    4076             : 
    4077             :     /* Superusers bypass all permission checking. */
    4078        4238 :     if (superuser_arg(roleid))
    4079        1346 :         return true;
    4080             : 
    4081        2892 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4082        2892 :     if (HeapTupleIsValid(utup))
    4083             :     {
    4084        2892 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
    4085        2892 :         ReleaseSysCache(utup);
    4086             :     }
    4087        2892 :     return result;
    4088             : }
    4089             : 
    4090             : /*
    4091             :  * Fetch pg_default_acl entry for given role, namespace and object type
    4092             :  * (object type must be given in pg_default_acl's encoding).
    4093             :  * Returns NULL if no such entry.
    4094             :  */
    4095             : static Acl *
    4096      306548 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
    4097             : {
    4098      306548 :     Acl        *result = NULL;
    4099             :     HeapTuple   tuple;
    4100             : 
    4101      306548 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    4102             :                             ObjectIdGetDatum(roleId),
    4103             :                             ObjectIdGetDatum(nsp_oid),
    4104             :                             CharGetDatum(objtype));
    4105             : 
    4106      306548 :     if (HeapTupleIsValid(tuple))
    4107             :     {
    4108             :         Datum       aclDatum;
    4109             :         bool        isNull;
    4110             : 
    4111         228 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    4112             :                                    Anum_pg_default_acl_defaclacl,
    4113             :                                    &isNull);
    4114         228 :         if (!isNull)
    4115         228 :             result = DatumGetAclPCopy(aclDatum);
    4116         228 :         ReleaseSysCache(tuple);
    4117             :     }
    4118             : 
    4119      306548 :     return result;
    4120             : }
    4121             : 
    4122             : /*
    4123             :  * Get default permissions for newly created object within given schema
    4124             :  *
    4125             :  * Returns NULL if built-in system defaults should be used.
    4126             :  *
    4127             :  * If the result is not NULL, caller must call recordDependencyOnNewAcl
    4128             :  * once the OID of the new object is known.
    4129             :  */
    4130             : Acl *
    4131      153274 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
    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             :      */
    4143      153274 :     if (IsBootstrapProcessingMode())
    4144           0 :         return NULL;
    4145             : 
    4146             :     /* Check if object type is supported in pg_default_acl */
    4147      153274 :     switch (objtype)
    4148             :     {
    4149      122770 :         case OBJECT_TABLE:
    4150      122770 :             defaclobjtype = DEFACLOBJ_RELATION;
    4151      122770 :             break;
    4152             : 
    4153        1500 :         case OBJECT_SEQUENCE:
    4154        1500 :             defaclobjtype = DEFACLOBJ_SEQUENCE;
    4155        1500 :             break;
    4156             : 
    4157       22468 :         case OBJECT_FUNCTION:
    4158       22468 :             defaclobjtype = DEFACLOBJ_FUNCTION;
    4159       22468 :             break;
    4160             : 
    4161        5130 :         case OBJECT_TYPE:
    4162        5130 :             defaclobjtype = DEFACLOBJ_TYPE;
    4163        5130 :             break;
    4164             : 
    4165        1406 :         case OBJECT_SCHEMA:
    4166        1406 :             defaclobjtype = DEFACLOBJ_NAMESPACE;
    4167        1406 :             break;
    4168             : 
    4169           0 :         default:
    4170           0 :             return NULL;
    4171             :     }
    4172             : 
    4173             :     /* Look up the relevant pg_default_acl entries */
    4174      153274 :     glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
    4175      153274 :     schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
    4176             : 
    4177             :     /* Quick out if neither entry exists */
    4178      153274 :     if (glob_acl == NULL && schema_acl == NULL)
    4179      153082 :         return NULL;
    4180             : 
    4181             :     /* We need to know the hard-wired default value, too */
    4182         192 :     def_acl = acldefault(objtype, ownerId);
    4183             : 
    4184             :     /* If there's no global entry, substitute the hard-wired default */
    4185         192 :     if (glob_acl == NULL)
    4186          18 :         glob_acl = def_acl;
    4187             : 
    4188             :     /* Merge in any per-schema privileges */
    4189         192 :     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         192 :     aclitemsort(result);
    4196         192 :     aclitemsort(def_acl);
    4197         192 :     if (aclequal(result, def_acl))
    4198          24 :         result = NULL;
    4199             : 
    4200         192 :     return result;
    4201             : }
    4202             : 
    4203             : /*
    4204             :  * Record dependencies on roles mentioned in a new object's ACL.
    4205             :  */
    4206             : void
    4207      155310 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
    4208             :                          Oid ownerId, Acl *acl)
    4209             : {
    4210             :     int         nmembers;
    4211             :     Oid        *members;
    4212             : 
    4213             :     /* Nothing to do if ACL is defaulted */
    4214      155310 :     if (acl == NULL)
    4215      155142 :         return;
    4216             : 
    4217             :     /* Extract roles mentioned in ACL */
    4218         168 :     nmembers = aclmembers(acl, &members);
    4219             : 
    4220             :     /* Update the shared dependency ACL info */
    4221         168 :     updateAclDependencies(classId, objectId, objsubId,
    4222             :                           ownerId,
    4223             :                           0, NULL,
    4224             :                           nmembers, members);
    4225             : }
    4226             : 
    4227             : /*
    4228             :  * Record initial privileges for the top-level object passed in.
    4229             :  *
    4230             :  * For the object passed in, this will record its ACL (if any) and the ACLs of
    4231             :  * any sub-objects (eg: columns) into pg_init_privs.
    4232             :  */
    4233             : void
    4234          56 : recordExtObjInitPriv(Oid objoid, Oid classoid)
    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          56 :     if (classoid == RelationRelationId)
    4244             :     {
    4245             :         Form_pg_class pg_class_tuple;
    4246             :         Datum       aclDatum;
    4247             :         bool        isNull;
    4248             :         HeapTuple   tuple;
    4249             : 
    4250          14 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4251          14 :         if (!HeapTupleIsValid(tuple))
    4252           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4253          14 :         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          14 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4261          14 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4262          14 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4263             :         {
    4264           0 :             ReleaseSysCache(tuple);
    4265           0 :             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          14 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4273             :         {
    4274             :             AttrNumber  curr_att;
    4275          12 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4276             : 
    4277          32 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4278             :             {
    4279             :                 HeapTuple   attTuple;
    4280             :                 Datum       attaclDatum;
    4281             : 
    4282          20 :                 attTuple = SearchSysCache2(ATTNUM,
    4283             :                                            ObjectIdGetDatum(objoid),
    4284             :                                            Int16GetDatum(curr_att));
    4285             : 
    4286          20 :                 if (!HeapTupleIsValid(attTuple))
    4287           0 :                     continue;
    4288             : 
    4289             :                 /* ignore dropped columns */
    4290          20 :                 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    4291             :                 {
    4292           2 :                     ReleaseSysCache(attTuple);
    4293           2 :                     continue;
    4294             :                 }
    4295             : 
    4296          18 :                 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
    4297             :                                               Anum_pg_attribute_attacl,
    4298             :                                               &isNull);
    4299             : 
    4300             :                 /* no need to do anything for a NULL ACL */
    4301          18 :                 if (isNull)
    4302             :                 {
    4303          14 :                     ReleaseSysCache(attTuple);
    4304          14 :                     continue;
    4305             :                 }
    4306             : 
    4307           4 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
    4308           4 :                                               DatumGetAclP(attaclDatum));
    4309             : 
    4310           4 :                 ReleaseSysCache(attTuple);
    4311             :             }
    4312             :         }
    4313             : 
    4314          14 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    4315             :                                    &isNull);
    4316             : 
    4317             :         /* Add the record, if any, for the top-level object */
    4318          14 :         if (!isNull)
    4319           8 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4320           8 :                                           DatumGetAclP(aclDatum));
    4321             : 
    4322          14 :         ReleaseSysCache(tuple);
    4323             :     }
    4324             :     /* pg_largeobject_metadata */
    4325          42 :     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           0 :         relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
    4340             : 
    4341             :         /* There's no syscache for pg_largeobject_metadata */
    4342           0 :         ScanKeyInit(&entry[0],
    4343             :                     Anum_pg_largeobject_metadata_oid,
    4344             :                     BTEqualStrategyNumber, F_OIDEQ,
    4345             :                     ObjectIdGetDatum(objoid));
    4346             : 
    4347           0 :         scan = systable_beginscan(relation,
    4348             :                                   LargeObjectMetadataOidIndexId, true,
    4349             :                                   NULL, 1, entry);
    4350             : 
    4351           0 :         tuple = systable_getnext(scan);
    4352           0 :         if (!HeapTupleIsValid(tuple))
    4353           0 :             elog(ERROR, "could not find tuple for large object %u", objoid);
    4354             : 
    4355           0 :         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           0 :         if (!isNull)
    4361           0 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4362           0 :                                           DatumGetAclP(aclDatum));
    4363             : 
    4364           0 :         systable_endscan(scan);
    4365             :     }
    4366             :     /* This will error on unsupported classoid. */
    4367          42 :     else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
    4368             :     {
    4369             :         Datum       aclDatum;
    4370             :         bool        isNull;
    4371             :         HeapTuple   tuple;
    4372             : 
    4373          20 :         tuple = SearchSysCache1(get_object_catcache_oid(classoid),
    4374             :                                 ObjectIdGetDatum(objoid));
    4375          20 :         if (!HeapTupleIsValid(tuple))
    4376           0 :             elog(ERROR, "cache lookup failed for %s %u",
    4377             :                  get_object_class_descr(classoid), objoid);
    4378             : 
    4379          20 :         aclDatum = SysCacheGetAttr(get_object_catcache_oid(classoid), tuple,
    4380          20 :                                    get_object_attnum_acl(classoid),
    4381             :                                    &isNull);
    4382             : 
    4383             :         /* Add the record, if any, for the top-level object */
    4384          20 :         if (!isNull)
    4385          10 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4386          10 :                                           DatumGetAclP(aclDatum));
    4387             : 
    4388          20 :         ReleaseSysCache(tuple);
    4389             :     }
    4390             : }
    4391             : 
    4392             : /*
    4393             :  * For the object passed in, remove its ACL and the ACLs of any object subIds
    4394             :  * from pg_init_privs (via recordExtensionInitPrivWorker()).
    4395             :  */
    4396             : void
    4397         120 : removeExtObjInitPriv(Oid objoid, Oid classoid)
    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         120 :     if (classoid == RelationRelationId)
    4405             :     {
    4406             :         Form_pg_class pg_class_tuple;
    4407             :         HeapTuple   tuple;
    4408             : 
    4409          32 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4410          32 :         if (!HeapTupleIsValid(tuple))
    4411           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4412          32 :         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          32 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4420          32 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4421          32 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4422             :         {
    4423           0 :             ReleaseSysCache(tuple);
    4424           0 :             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          32 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4432             :         {
    4433             :             AttrNumber  curr_att;
    4434          32 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4435             : 
    4436         750 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4437             :             {
    4438             :                 HeapTuple   attTuple;
    4439             : 
    4440         718 :                 attTuple = SearchSysCache2(ATTNUM,
    4441             :                                            ObjectIdGetDatum(objoid),
    4442             :                                            Int16GetDatum(curr_att));
    4443             : 
    4444         718 :                 if (!HeapTupleIsValid(attTuple))
    4445           0 :                     continue;
    4446             : 
    4447             :                 /* when removing, remove all entries, even dropped columns */
    4448             : 
    4449         718 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
    4450             : 
    4451         718 :                 ReleaseSysCache(attTuple);
    4452             :             }
    4453             :         }
    4454             : 
    4455          32 :         ReleaseSysCache(tuple);
    4456             :     }
    4457             : 
    4458             :     /* Remove the record, if any, for the top-level object */
    4459         120 :     recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
    4460             : }
    4461             : 
    4462             : /*
    4463             :  * Record initial ACL for an extension object
    4464             :  *
    4465             :  * Can be called at any time, we check if 'creating_extension' is set and, if
    4466             :  * not, exit immediately.
    4467             :  *
    4468             :  * Pass in the object OID, the OID of the class (the OID of the table which
    4469             :  * the object is defined in) and the 'sub' id of the object (objsubid), if
    4470             :  * any.  If there is no 'sub' id (they are currently only used for columns of
    4471             :  * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
    4472             :  *
    4473             :  * If an ACL already exists for this object/sub-object then we will replace
    4474             :  * it with what is passed in.
    4475             :  *
    4476             :  * Passing in NULL for 'new_acl' will result in the entry for the object being
    4477             :  * removed, if one is found.
    4478             :  */
    4479             : static void
    4480      107282 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    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             :      */
    4490      107282 :     if (!creating_extension && !binary_upgrade_record_init_privs)
    4491      106828 :         return;
    4492             : 
    4493         454 :     recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
    4494             : }
    4495             : 
    4496             : /*
    4497             :  * Record initial ACL for an extension object, worker.
    4498             :  *
    4499             :  * This will perform a wholesale replacement of the entire ACL for the object
    4500             :  * passed in, therefore be sure to pass in the complete new ACL to use.
    4501             :  *
    4502             :  * Generally speaking, do *not* use this function directly but instead use
    4503             :  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
    4504             :  * This function does *not* check if 'creating_extension' is set as it is also
    4505             :  * used when an object is added to or removed from an extension via ALTER
    4506             :  * EXTENSION ... ADD/DROP.
    4507             :  */
    4508             : static void
    4509        1314 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    4510             : {
    4511             :     Relation    relation;
    4512             :     ScanKeyData key[3];
    4513             :     SysScanDesc scan;
    4514             :     HeapTuple   tuple;
    4515             :     HeapTuple   oldtuple;
    4516             : 
    4517        1314 :     relation = table_open(InitPrivsRelationId, RowExclusiveLock);
    4518             : 
    4519        1314 :     ScanKeyInit(&key[0],
    4520             :                 Anum_pg_init_privs_objoid,
    4521             :                 BTEqualStrategyNumber, F_OIDEQ,
    4522             :                 ObjectIdGetDatum(objoid));
    4523        1314 :     ScanKeyInit(&key[1],
    4524             :                 Anum_pg_init_privs_classoid,
    4525             :                 BTEqualStrategyNumber, F_OIDEQ,
    4526             :                 ObjectIdGetDatum(classoid));
    4527        1314 :     ScanKeyInit(&key[2],
    4528             :                 Anum_pg_init_privs_objsubid,
    4529             :                 BTEqualStrategyNumber, F_INT4EQ,
    4530             :                 Int32GetDatum(objsubid));
    4531             : 
    4532        1314 :     scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
    4533             :                               NULL, 3, key);
    4534             : 
    4535             :     /* There should exist only one entry or none. */
    4536        1314 :     oldtuple = systable_getnext(scan);
    4537             : 
    4538             :     /* If we find an entry, update it with the latest ACL. */
    4539        1314 :     if (HeapTupleIsValid(oldtuple))
    4540             :     {
    4541         170 :         Datum       values[Natts_pg_init_privs] = {0};
    4542         170 :         bool        nulls[Natts_pg_init_privs] = {0};
    4543         170 :         bool        replace[Natts_pg_init_privs] = {0};
    4544             : 
    4545             :         /* If we have a new ACL to set, then update the row with it. */
    4546         170 :         if (new_acl)
    4547             :         {
    4548         114 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4549         114 :             replace[Anum_pg_init_privs_initprivs - 1] = true;
    4550             : 
    4551         114 :             oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
    4552             :                                          values, nulls, replace);
    4553             : 
    4554         114 :             CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
    4555             :         }
    4556             :         else
    4557             :         {
    4558             :             /* new_acl is NULL, so delete the entry we found. */
    4559          56 :             CatalogTupleDelete(relation, &oldtuple->t_self);
    4560             :         }
    4561             :     }
    4562             :     else
    4563             :     {
    4564        1144 :         Datum       values[Natts_pg_init_privs] = {0};
    4565        1144 :         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        1144 :         if (new_acl)
    4574             :         {
    4575             :             /* No entry found, so add it. */
    4576         358 :             values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
    4577         358 :             values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
    4578         358 :             values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
    4579             : 
    4580             :             /* This function only handles initial privileges of extensions */
    4581         358 :             values[Anum_pg_init_privs_privtype - 1] =
    4582         358 :                 CharGetDatum(INITPRIVS_EXTENSION);
    4583             : 
    4584         358 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4585             : 
    4586         358 :             tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
    4587             : 
    4588         358 :             CatalogTupleInsert(relation, tuple);
    4589             :         }
    4590             :     }
    4591             : 
    4592        1314 :     systable_endscan(scan);
    4593             : 
    4594             :     /* prevent error when processing objects multiple times */
    4595        1314 :     CommandCounterIncrement();
    4596             : 
    4597        1314 :     table_close(relation, RowExclusiveLock);
    4598        1314 : }

Generated by: LCOV version 1.14