LCOV - code coverage report
Current view: top level - src/backend/catalog - aclchk.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1536 1887 81.4 %
Date: 2024-07-27 03:11:23 Functions: 56 59 94.9 %
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-2024, 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             :  *    The xxx_aclmask() functions in this file are wrappers around
      17             :  *    acl.c's aclmask() function; see that for basic usage information.
      18             :  *    The wrapper functions add object-type-specific lookup capability.
      19             :  *    Generally, they will throw error if the object doesn't exist.
      20             :  *
      21             :  *    The xxx_aclmask_ext() functions add the ability to not throw
      22             :  *    error if the object doesn't exist.  If their "is_missing" argument
      23             :  *    isn't NULL, then when the object isn't found they will set
      24             :  *    *is_missing = true and return zero (no privileges) instead of
      25             :  *    throwing an error.  Caller must initialize *is_missing = false.
      26             :  *
      27             :  *    The xxx_aclcheck() functions are simplified wrappers around the
      28             :  *    corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
      29             :  *    if any of the privileges specified in "mode" are held, and otherwise
      30             :  *    a suitable error code (in practice, always ACLCHECK_NO_PRIV).
      31             :  *    Again, they will throw error if the object doesn't exist.
      32             :  *
      33             :  *    The xxx_aclcheck_ext() functions add the ability to not throw
      34             :  *    error if the object doesn't exist.  Their "is_missing" argument
      35             :  *    works similarly to the xxx_aclmask_ext() functions.
      36             :  *
      37             :  *-------------------------------------------------------------------------
      38             :  */
      39             : #include "postgres.h"
      40             : 
      41             : #include "access/genam.h"
      42             : #include "access/heapam.h"
      43             : #include "access/htup_details.h"
      44             : #include "access/sysattr.h"
      45             : #include "access/tableam.h"
      46             : #include "access/xact.h"
      47             : #include "catalog/binary_upgrade.h"
      48             : #include "catalog/catalog.h"
      49             : #include "catalog/dependency.h"
      50             : #include "catalog/indexing.h"
      51             : #include "catalog/objectaccess.h"
      52             : #include "catalog/pg_authid.h"
      53             : #include "catalog/pg_class.h"
      54             : #include "catalog/pg_database.h"
      55             : #include "catalog/pg_default_acl.h"
      56             : #include "catalog/pg_foreign_data_wrapper.h"
      57             : #include "catalog/pg_foreign_server.h"
      58             : #include "catalog/pg_init_privs.h"
      59             : #include "catalog/pg_language.h"
      60             : #include "catalog/pg_largeobject.h"
      61             : #include "catalog/pg_largeobject_metadata.h"
      62             : #include "catalog/pg_namespace.h"
      63             : #include "catalog/pg_parameter_acl.h"
      64             : #include "catalog/pg_proc.h"
      65             : #include "catalog/pg_tablespace.h"
      66             : #include "catalog/pg_type.h"
      67             : #include "commands/dbcommands.h"
      68             : #include "commands/defrem.h"
      69             : #include "commands/event_trigger.h"
      70             : #include "commands/extension.h"
      71             : #include "commands/proclang.h"
      72             : #include "commands/tablespace.h"
      73             : #include "foreign/foreign.h"
      74             : #include "miscadmin.h"
      75             : #include "nodes/makefuncs.h"
      76             : #include "parser/parse_func.h"
      77             : #include "parser/parse_type.h"
      78             : #include "utils/acl.h"
      79             : #include "utils/aclchk_internal.h"
      80             : #include "utils/builtins.h"
      81             : #include "utils/fmgroids.h"
      82             : #include "utils/guc.h"
      83             : #include "utils/lsyscache.h"
      84             : #include "utils/rel.h"
      85             : #include "utils/syscache.h"
      86             : 
      87             : /*
      88             :  * Internal format used by ALTER DEFAULT PRIVILEGES.
      89             :  */
      90             : typedef struct
      91             : {
      92             :     Oid         roleid;         /* owning role */
      93             :     Oid         nspid;          /* namespace, or InvalidOid if none */
      94             :     /* remaining fields are same as in InternalGrant: */
      95             :     bool        is_grant;
      96             :     ObjectType  objtype;
      97             :     bool        all_privs;
      98             :     AclMode     privileges;
      99             :     List       *grantees;
     100             :     bool        grant_option;
     101             :     DropBehavior behavior;
     102             : } InternalDefaultACL;
     103             : 
     104             : /*
     105             :  * When performing a binary-upgrade, pg_dump will call a function to set
     106             :  * this variable to let us know that we need to populate the pg_init_privs
     107             :  * table for the GRANT/REVOKE commands while this variable is set to true.
     108             :  */
     109             : bool        binary_upgrade_record_init_privs = false;
     110             : 
     111             : static void ExecGrantStmt_oids(InternalGrant *istmt);
     112             : static void ExecGrant_Relation(InternalGrant *istmt);
     113             : static void ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
     114             :                              void (*object_check) (InternalGrant *istmt, HeapTuple tuple));
     115             : static void ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple);
     116             : static void ExecGrant_Largeobject(InternalGrant *istmt);
     117             : static void ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple);
     118             : static void ExecGrant_Parameter(InternalGrant *istmt);
     119             : 
     120             : static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
     121             : static void SetDefaultACL(InternalDefaultACL *iacls);
     122             : 
     123             : static List *objectNamesToOids(ObjectType objtype, List *objnames,
     124             :                                bool is_grant);
     125             : static List *objectsInSchemaToOids(ObjectType objtype, List *nspnames);
     126             : static List *getRelationsInNamespace(Oid namespaceId, char relkind);
     127             : static void expand_col_privileges(List *colnames, Oid table_oid,
     128             :                                   AclMode this_privileges,
     129             :                                   AclMode *col_privileges,
     130             :                                   int num_col_privileges);
     131             : static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
     132             :                                       AclMode this_privileges,
     133             :                                       AclMode *col_privileges,
     134             :                                       int num_col_privileges);
     135             : static AclMode string_to_privilege(const char *privname);
     136             : static const char *privilege_to_string(AclMode privilege);
     137             : static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
     138             :                                         bool all_privs, AclMode privileges,
     139             :                                         Oid objectId, Oid grantorId,
     140             :                                         ObjectType objtype, const char *objname,
     141             :                                         AttrNumber att_number, const char *colname);
     142             : static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
     143             :                           Oid roleid, AclMode mask, AclMaskHow how);
     144             : static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
     145             :                               AclMode mask, AclMaskHow how);
     146             : static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
     147             :                                   AclMode mask, AclMaskHow how,
     148             :                                   bool *is_missing);
     149             : static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
     150             :                                     Oid roleid, AclMode mask, AclMaskHow how);
     151             : static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
     152             :                                         Oid roleid, AclMode mask,
     153             :                                         AclMaskHow how, bool *is_missing);
     154             : static AclMode pg_class_aclmask_ext(Oid table_oid, Oid roleid,
     155             :                                     AclMode mask, AclMaskHow how,
     156             :                                     bool *is_missing);
     157             : static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
     158             :                                         AclMode mask, AclMaskHow how);
     159             : static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
     160             :                                                AclMode mask, AclMaskHow how, Snapshot snapshot);
     161             : static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
     162             :                                         AclMode mask, AclMaskHow how,
     163             :                                         bool *is_missing);
     164             : static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
     165             :                                    AclMode mask, AclMaskHow how,
     166             :                                    bool *is_missing);
     167             : static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
     168             :                                     Acl *new_acl);
     169             : static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
     170             :                                           Acl *new_acl);
     171             : 
     172             : 
     173             : /*
     174             :  * If is_grant is true, adds the given privileges for the list of
     175             :  * grantees to the existing old_acl.  If is_grant is false, the
     176             :  * privileges for the given grantees are removed from old_acl.
     177             :  *
     178             :  * NB: the original old_acl is pfree'd.
     179             :  */
     180             : static Acl *
     181       68870 : merge_acl_with_grant(Acl *old_acl, bool is_grant,
     182             :                      bool grant_option, DropBehavior behavior,
     183             :                      List *grantees, AclMode privileges,
     184             :                      Oid grantorId, Oid ownerId)
     185             : {
     186             :     unsigned    modechg;
     187             :     ListCell   *j;
     188             :     Acl        *new_acl;
     189             : 
     190       68870 :     modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
     191             : 
     192       68870 :     new_acl = old_acl;
     193             : 
     194      137854 :     foreach(j, grantees)
     195             :     {
     196             :         AclItem     aclitem;
     197             :         Acl        *newer_acl;
     198             : 
     199       68996 :         aclitem.ai_grantee = lfirst_oid(j);
     200             : 
     201             :         /*
     202             :          * Grant options can only be granted to individual roles, not PUBLIC.
     203             :          * The reason is that if a user would re-grant a privilege that he
     204             :          * held through PUBLIC, and later the user is removed, the situation
     205             :          * is impossible to clean up.
     206             :          */
     207       68996 :         if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
     208           0 :             ereport(ERROR,
     209             :                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     210             :                      errmsg("grant options can only be granted to roles")));
     211             : 
     212       68996 :         aclitem.ai_grantor = grantorId;
     213             : 
     214             :         /*
     215             :          * The asymmetry in the conditions here comes from the spec.  In
     216             :          * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
     217             :          * to grant both the basic privilege and its grant option. But in
     218             :          * REVOKE, plain revoke revokes both the basic privilege and its grant
     219             :          * option, while REVOKE GRANT OPTION revokes only the option.
     220             :          */
     221       68996 :         ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
     222             :                                    (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
     223             :                                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
     224             : 
     225       68996 :         newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
     226             : 
     227             :         /* avoid memory leak when there are many grantees */
     228       68984 :         pfree(new_acl);
     229       68984 :         new_acl = newer_acl;
     230             :     }
     231             : 
     232       68858 :     return new_acl;
     233             : }
     234             : 
     235             : /*
     236             :  * Restrict the privileges to what we can actually grant, and emit
     237             :  * the standards-mandated warning and error messages.
     238             :  */
     239             : static AclMode
     240       68682 : restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
     241             :                          AclMode privileges, Oid objectId, Oid grantorId,
     242             :                          ObjectType objtype, const char *objname,
     243             :                          AttrNumber att_number, const char *colname)
     244             : {
     245             :     AclMode     this_privileges;
     246             :     AclMode     whole_mask;
     247             : 
     248       68682 :     switch (objtype)
     249             :     {
     250       44438 :         case OBJECT_COLUMN:
     251       44438 :             whole_mask = ACL_ALL_RIGHTS_COLUMN;
     252       44438 :             break;
     253       16226 :         case OBJECT_TABLE:
     254       16226 :             whole_mask = ACL_ALL_RIGHTS_RELATION;
     255       16226 :             break;
     256         174 :         case OBJECT_SEQUENCE:
     257         174 :             whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
     258         174 :             break;
     259         288 :         case OBJECT_DATABASE:
     260         288 :             whole_mask = ACL_ALL_RIGHTS_DATABASE;
     261         288 :             break;
     262        6566 :         case OBJECT_FUNCTION:
     263        6566 :             whole_mask = ACL_ALL_RIGHTS_FUNCTION;
     264        6566 :             break;
     265          36 :         case OBJECT_LANGUAGE:
     266          36 :             whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
     267          36 :             break;
     268          80 :         case OBJECT_LARGEOBJECT:
     269          80 :             whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
     270          80 :             break;
     271         430 :         case OBJECT_SCHEMA:
     272         430 :             whole_mask = ACL_ALL_RIGHTS_SCHEMA;
     273         430 :             break;
     274           0 :         case OBJECT_TABLESPACE:
     275           0 :             whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
     276           0 :             break;
     277          94 :         case OBJECT_FDW:
     278          94 :             whole_mask = ACL_ALL_RIGHTS_FDW;
     279          94 :             break;
     280          90 :         case OBJECT_FOREIGN_SERVER:
     281          90 :             whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     282          90 :             break;
     283           0 :         case OBJECT_EVENT_TRIGGER:
     284           0 :             elog(ERROR, "grantable rights not supported for event triggers");
     285             :             /* not reached, but keep compiler quiet */
     286             :             return ACL_NO_RIGHTS;
     287         126 :         case OBJECT_TYPE:
     288         126 :             whole_mask = ACL_ALL_RIGHTS_TYPE;
     289         126 :             break;
     290         134 :         case OBJECT_PARAMETER_ACL:
     291         134 :             whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL;
     292         134 :             break;
     293           0 :         default:
     294           0 :             elog(ERROR, "unrecognized object type: %d", objtype);
     295             :             /* not reached, but keep compiler quiet */
     296             :             return ACL_NO_RIGHTS;
     297             :     }
     298             : 
     299             :     /*
     300             :      * If we found no grant options, consider whether to issue a hard error.
     301             :      * Per spec, having any privilege at all on the object will get you by
     302             :      * here.
     303             :      */
     304       68682 :     if (avail_goptions == ACL_NO_RIGHTS)
     305             :     {
     306          66 :         if (pg_aclmask(objtype, objectId, att_number, grantorId,
     307          66 :                        whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
     308             :                        ACLMASK_ANY) == ACL_NO_RIGHTS)
     309             :         {
     310          30 :             if (objtype == OBJECT_COLUMN && colname)
     311           0 :                 aclcheck_error_col(ACLCHECK_NO_PRIV, objtype, objname, colname);
     312             :             else
     313          30 :                 aclcheck_error(ACLCHECK_NO_PRIV, objtype, objname);
     314             :         }
     315             :     }
     316             : 
     317             :     /*
     318             :      * Restrict the operation to what we can actually grant or revoke, and
     319             :      * issue a warning if appropriate.  (For REVOKE this isn't quite what the
     320             :      * spec says to do: the spec seems to want a warning only if no privilege
     321             :      * bits actually change in the ACL. In practice that behavior seems much
     322             :      * too noisy, as well as inconsistent with the GRANT case.)
     323             :      */
     324       68652 :     this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
     325       68652 :     if (is_grant)
     326             :     {
     327       14340 :         if (this_privileges == 0)
     328             :         {
     329          30 :             if (objtype == OBJECT_COLUMN && colname)
     330           0 :                 ereport(WARNING,
     331             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     332             :                          errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
     333             :                                 colname, objname)));
     334             :             else
     335          30 :                 ereport(WARNING,
     336             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     337             :                          errmsg("no privileges were granted for \"%s\"",
     338             :                                 objname)));
     339             :         }
     340       14310 :         else if (!all_privs && this_privileges != privileges)
     341             :         {
     342           0 :             if (objtype == OBJECT_COLUMN && colname)
     343           0 :                 ereport(WARNING,
     344             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     345             :                          errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
     346             :                                 colname, objname)));
     347             :             else
     348           0 :                 ereport(WARNING,
     349             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
     350             :                          errmsg("not all privileges were granted for \"%s\"",
     351             :                                 objname)));
     352             :         }
     353             :     }
     354             :     else
     355             :     {
     356       54312 :         if (this_privileges == 0)
     357             :         {
     358           6 :             if (objtype == OBJECT_COLUMN && colname)
     359           0 :                 ereport(WARNING,
     360             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     361             :                          errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
     362             :                                 colname, objname)));
     363             :             else
     364           6 :                 ereport(WARNING,
     365             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     366             :                          errmsg("no privileges could be revoked for \"%s\"",
     367             :                                 objname)));
     368             :         }
     369       54306 :         else if (!all_privs && this_privileges != privileges)
     370             :         {
     371           0 :             if (objtype == OBJECT_COLUMN && colname)
     372           0 :                 ereport(WARNING,
     373             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     374             :                          errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
     375             :                                 colname, objname)));
     376             :             else
     377           0 :                 ereport(WARNING,
     378             :                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
     379             :                          errmsg("not all privileges could be revoked for \"%s\"",
     380             :                                 objname)));
     381             :         }
     382             :     }
     383             : 
     384       68652 :     return this_privileges;
     385             : }
     386             : 
     387             : /*
     388             :  * Called to execute the utility commands GRANT and REVOKE
     389             :  */
     390             : void
     391       24274 : ExecuteGrantStmt(GrantStmt *stmt)
     392             : {
     393             :     InternalGrant istmt;
     394             :     ListCell   *cell;
     395             :     const char *errormsg;
     396             :     AclMode     all_privileges;
     397             : 
     398       24274 :     if (stmt->grantor)
     399             :     {
     400             :         Oid         grantor;
     401             : 
     402          18 :         grantor = get_rolespec_oid(stmt->grantor, false);
     403             : 
     404             :         /*
     405             :          * Currently, this clause is only for SQL compatibility, not very
     406             :          * interesting otherwise.
     407             :          */
     408          18 :         if (grantor != GetUserId())
     409           6 :             ereport(ERROR,
     410             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     411             :                      errmsg("grantor must be current user")));
     412             :     }
     413             : 
     414             :     /*
     415             :      * Turn the regular GrantStmt into the InternalGrant form.
     416             :      */
     417       24268 :     istmt.is_grant = stmt->is_grant;
     418       24268 :     istmt.objtype = stmt->objtype;
     419             : 
     420             :     /* Collect the OIDs of the target objects */
     421       24268 :     switch (stmt->targtype)
     422             :     {
     423       24238 :         case ACL_TARGET_OBJECT:
     424       48450 :             istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects,
     425       24238 :                                               stmt->is_grant);
     426       24212 :             break;
     427          30 :         case ACL_TARGET_ALL_IN_SCHEMA:
     428          30 :             istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
     429          30 :             break;
     430             :             /* ACL_TARGET_DEFAULTS should not be seen here */
     431           0 :         default:
     432           0 :             elog(ERROR, "unrecognized GrantStmt.targtype: %d",
     433             :                  (int) stmt->targtype);
     434             :     }
     435             : 
     436             :     /* all_privs to be filled below */
     437             :     /* privileges to be filled below */
     438       24242 :     istmt.col_privs = NIL;      /* may get filled below */
     439       24242 :     istmt.grantees = NIL;       /* filled below */
     440       24242 :     istmt.grant_option = stmt->grant_option;
     441       24242 :     istmt.behavior = stmt->behavior;
     442             : 
     443             :     /*
     444             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
     445             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
     446             :      * there shouldn't be any additional work needed to support this case.
     447             :      */
     448       48574 :     foreach(cell, stmt->grantees)
     449             :     {
     450       24338 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
     451             :         Oid         grantee_uid;
     452             : 
     453       24338 :         switch (grantee->roletype)
     454             :         {
     455       20714 :             case ROLESPEC_PUBLIC:
     456       20714 :                 grantee_uid = ACL_ID_PUBLIC;
     457       20714 :                 break;
     458        3624 :             default:
     459        3624 :                 grantee_uid = get_rolespec_oid(grantee, false);
     460        3618 :                 break;
     461             :         }
     462       24332 :         istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
     463             :     }
     464             : 
     465             :     /*
     466             :      * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
     467             :      * bitmask.  Note: objtype can't be OBJECT_COLUMN.
     468             :      */
     469       24236 :     switch (stmt->objtype)
     470             :     {
     471       16616 :         case OBJECT_TABLE:
     472             : 
     473             :             /*
     474             :              * Because this might be a sequence, we test both relation and
     475             :              * sequence bits, and later do a more limited test when we know
     476             :              * the object type.
     477             :              */
     478       16616 :             all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
     479       16616 :             errormsg = gettext_noop("invalid privilege type %s for relation");
     480       16616 :             break;
     481          22 :         case OBJECT_SEQUENCE:
     482          22 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
     483          22 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
     484          22 :             break;
     485         278 :         case OBJECT_DATABASE:
     486         278 :             all_privileges = ACL_ALL_RIGHTS_DATABASE;
     487         278 :             errormsg = gettext_noop("invalid privilege type %s for database");
     488         278 :             break;
     489          26 :         case OBJECT_DOMAIN:
     490          26 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     491          26 :             errormsg = gettext_noop("invalid privilege type %s for domain");
     492          26 :             break;
     493        6450 :         case OBJECT_FUNCTION:
     494        6450 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     495        6450 :             errormsg = gettext_noop("invalid privilege type %s for function");
     496        6450 :             break;
     497          42 :         case OBJECT_LANGUAGE:
     498          42 :             all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
     499          42 :             errormsg = gettext_noop("invalid privilege type %s for language");
     500          42 :             break;
     501          62 :         case OBJECT_LARGEOBJECT:
     502          62 :             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
     503          62 :             errormsg = gettext_noop("invalid privilege type %s for large object");
     504          62 :             break;
     505         334 :         case OBJECT_SCHEMA:
     506         334 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
     507         334 :             errormsg = gettext_noop("invalid privilege type %s for schema");
     508         334 :             break;
     509          48 :         case OBJECT_PROCEDURE:
     510          48 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     511          48 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
     512          48 :             break;
     513           6 :         case OBJECT_ROUTINE:
     514           6 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
     515           6 :             errormsg = gettext_noop("invalid privilege type %s for routine");
     516           6 :             break;
     517           0 :         case OBJECT_TABLESPACE:
     518           0 :             all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
     519           0 :             errormsg = gettext_noop("invalid privilege type %s for tablespace");
     520           0 :             break;
     521         112 :         case OBJECT_TYPE:
     522         112 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
     523         112 :             errormsg = gettext_noop("invalid privilege type %s for type");
     524         112 :             break;
     525          92 :         case OBJECT_FDW:
     526          92 :             all_privileges = ACL_ALL_RIGHTS_FDW;
     527          92 :             errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
     528          92 :             break;
     529          76 :         case OBJECT_FOREIGN_SERVER:
     530          76 :             all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
     531          76 :             errormsg = gettext_noop("invalid privilege type %s for foreign server");
     532          76 :             break;
     533          72 :         case OBJECT_PARAMETER_ACL:
     534          72 :             all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
     535          72 :             errormsg = gettext_noop("invalid privilege type %s for parameter");
     536          72 :             break;
     537           0 :         default:
     538           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     539             :                  (int) stmt->objtype);
     540             :             /* keep compiler quiet */
     541             :             all_privileges = ACL_NO_RIGHTS;
     542             :             errormsg = NULL;
     543             :     }
     544             : 
     545       24236 :     if (stmt->privileges == NIL)
     546             :     {
     547        2086 :         istmt.all_privs = true;
     548             : 
     549             :         /*
     550             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
     551             :          * depending on the object type
     552             :          */
     553        2086 :         istmt.privileges = ACL_NO_RIGHTS;
     554             :     }
     555             :     else
     556             :     {
     557       22150 :         istmt.all_privs = false;
     558       22150 :         istmt.privileges = ACL_NO_RIGHTS;
     559             : 
     560       44706 :         foreach(cell, stmt->privileges)
     561             :         {
     562       22580 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
     563             :             AclMode     priv;
     564             : 
     565             :             /*
     566             :              * If it's a column-level specification, we just set it aside in
     567             :              * col_privs for the moment; but insist it's for a relation.
     568             :              */
     569       22580 :             if (privnode->cols)
     570             :             {
     571         416 :                 if (stmt->objtype != OBJECT_TABLE)
     572           0 :                     ereport(ERROR,
     573             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     574             :                              errmsg("column privileges are only valid for relations")));
     575         416 :                 istmt.col_privs = lappend(istmt.col_privs, privnode);
     576         416 :                 continue;
     577             :             }
     578             : 
     579       22164 :             if (privnode->priv_name == NULL) /* parser mistake? */
     580           0 :                 elog(ERROR, "AccessPriv node must specify privilege or columns");
     581       22164 :             priv = string_to_privilege(privnode->priv_name);
     582             : 
     583       22164 :             if (priv & ~((AclMode) all_privileges))
     584          24 :                 ereport(ERROR,
     585             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
     586             :                          errmsg(errormsg, privilege_to_string(priv))));
     587             : 
     588       22140 :             istmt.privileges |= priv;
     589             :         }
     590             :     }
     591             : 
     592       24212 :     ExecGrantStmt_oids(&istmt);
     593       24142 : }
     594             : 
     595             : /*
     596             :  * ExecGrantStmt_oids
     597             :  *
     598             :  * Internal entry point for granting and revoking privileges.
     599             :  */
     600             : static void
     601       24438 : ExecGrantStmt_oids(InternalGrant *istmt)
     602             : {
     603       24438 :     switch (istmt->objtype)
     604             :     {
     605       16738 :         case OBJECT_TABLE:
     606             :         case OBJECT_SEQUENCE:
     607       16738 :             ExecGrant_Relation(istmt);
     608       16728 :             break;
     609         288 :         case OBJECT_DATABASE:
     610         288 :             ExecGrant_common(istmt, DatabaseRelationId, ACL_ALL_RIGHTS_DATABASE, NULL);
     611         288 :             break;
     612         144 :         case OBJECT_DOMAIN:
     613             :         case OBJECT_TYPE:
     614         144 :             ExecGrant_common(istmt, TypeRelationId, ACL_ALL_RIGHTS_TYPE, ExecGrant_Type_check);
     615         120 :             break;
     616          94 :         case OBJECT_FDW:
     617          94 :             ExecGrant_common(istmt, ForeignDataWrapperRelationId, ACL_ALL_RIGHTS_FDW, NULL);
     618          76 :             break;
     619          90 :         case OBJECT_FOREIGN_SERVER:
     620          90 :             ExecGrant_common(istmt, ForeignServerRelationId, ACL_ALL_RIGHTS_FOREIGN_SERVER, NULL);
     621          78 :             break;
     622        6524 :         case OBJECT_FUNCTION:
     623             :         case OBJECT_PROCEDURE:
     624             :         case OBJECT_ROUTINE:
     625        6524 :             ExecGrant_common(istmt, ProcedureRelationId, ACL_ALL_RIGHTS_FUNCTION, NULL);
     626        6524 :             break;
     627          42 :         case OBJECT_LANGUAGE:
     628          42 :             ExecGrant_common(istmt, LanguageRelationId, ACL_ALL_RIGHTS_LANGUAGE, ExecGrant_Language_check);
     629          36 :             break;
     630          74 :         case OBJECT_LARGEOBJECT:
     631          74 :             ExecGrant_Largeobject(istmt);
     632          74 :             break;
     633         348 :         case OBJECT_SCHEMA:
     634         348 :             ExecGrant_common(istmt, NamespaceRelationId, ACL_ALL_RIGHTS_SCHEMA, NULL);
     635         348 :             break;
     636           0 :         case OBJECT_TABLESPACE:
     637           0 :             ExecGrant_common(istmt, TableSpaceRelationId, ACL_ALL_RIGHTS_TABLESPACE, NULL);
     638           0 :             break;
     639          96 :         case OBJECT_PARAMETER_ACL:
     640          96 :             ExecGrant_Parameter(istmt);
     641          96 :             break;
     642           0 :         default:
     643           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     644             :                  (int) istmt->objtype);
     645             :     }
     646             : 
     647             :     /*
     648             :      * Pass the info to event triggers about the just-executed GRANT.  Note
     649             :      * that we prefer to do it after actually executing it, because that gives
     650             :      * the functions a chance to adjust the istmt with privileges actually
     651             :      * granted.
     652             :      */
     653       24368 :     if (EventTriggerSupportsObjectType(istmt->objtype))
     654       23984 :         EventTriggerCollectGrant(istmt);
     655       24368 : }
     656             : 
     657             : /*
     658             :  * objectNamesToOids
     659             :  *
     660             :  * Turn a list of object names of a given type into an Oid list.
     661             :  *
     662             :  * XXX: This function doesn't take any sort of locks on the objects whose
     663             :  * names it looks up.  In the face of concurrent DDL, we might easily latch
     664             :  * onto an old version of an object, causing the GRANT or REVOKE statement
     665             :  * to fail.
     666             :  */
     667             : static List *
     668       24238 : objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
     669             : {
     670       24238 :     List       *objects = NIL;
     671             :     ListCell   *cell;
     672             : 
     673             :     Assert(objnames != NIL);
     674             : 
     675       24238 :     switch (objtype)
     676             :     {
     677       16626 :         case OBJECT_TABLE:
     678             :         case OBJECT_SEQUENCE:
     679       33306 :             foreach(cell, objnames)
     680             :             {
     681       16680 :                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
     682             :                 Oid         relOid;
     683             : 
     684       16680 :                 relOid = RangeVarGetRelid(relvar, NoLock, false);
     685       16680 :                 objects = lappend_oid(objects, relOid);
     686             :             }
     687       16626 :             break;
     688         278 :         case OBJECT_DATABASE:
     689         556 :             foreach(cell, objnames)
     690             :             {
     691         278 :                 char       *dbname = strVal(lfirst(cell));
     692             :                 Oid         dbid;
     693             : 
     694         278 :                 dbid = get_database_oid(dbname, false);
     695         278 :                 objects = lappend_oid(objects, dbid);
     696             :             }
     697         278 :             break;
     698         138 :         case OBJECT_DOMAIN:
     699             :         case OBJECT_TYPE:
     700         276 :             foreach(cell, objnames)
     701             :             {
     702         138 :                 List       *typname = (List *) lfirst(cell);
     703             :                 Oid         oid;
     704             : 
     705         138 :                 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
     706         138 :                 objects = lappend_oid(objects, oid);
     707             :             }
     708         138 :             break;
     709        6456 :         case OBJECT_FUNCTION:
     710       12924 :             foreach(cell, objnames)
     711             :             {
     712        6480 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     713             :                 Oid         funcid;
     714             : 
     715        6480 :                 funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
     716        6468 :                 objects = lappend_oid(objects, funcid);
     717             :             }
     718        6444 :             break;
     719          42 :         case OBJECT_LANGUAGE:
     720          84 :             foreach(cell, objnames)
     721             :             {
     722          42 :                 char       *langname = strVal(lfirst(cell));
     723             :                 Oid         oid;
     724             : 
     725          42 :                 oid = get_language_oid(langname, false);
     726          42 :                 objects = lappend_oid(objects, oid);
     727             :             }
     728          42 :             break;
     729          80 :         case OBJECT_LARGEOBJECT:
     730         154 :             foreach(cell, objnames)
     731             :             {
     732          86 :                 Oid         lobjOid = oidparse(lfirst(cell));
     733             : 
     734          86 :                 if (!LargeObjectExists(lobjOid))
     735          12 :                     ereport(ERROR,
     736             :                             (errcode(ERRCODE_UNDEFINED_OBJECT),
     737             :                              errmsg("large object %u does not exist",
     738             :                                     lobjOid)));
     739             : 
     740          74 :                 objects = lappend_oid(objects, lobjOid);
     741             :             }
     742          68 :             break;
     743         334 :         case OBJECT_SCHEMA:
     744         750 :             foreach(cell, objnames)
     745             :             {
     746         416 :                 char       *nspname = strVal(lfirst(cell));
     747             :                 Oid         oid;
     748             : 
     749         416 :                 oid = get_namespace_oid(nspname, false);
     750         416 :                 objects = lappend_oid(objects, oid);
     751             :             }
     752         334 :             break;
     753          42 :         case OBJECT_PROCEDURE:
     754          84 :             foreach(cell, objnames)
     755             :             {
     756          42 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     757             :                 Oid         procid;
     758             : 
     759          42 :                 procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
     760          42 :                 objects = lappend_oid(objects, procid);
     761             :             }
     762          42 :             break;
     763           0 :         case OBJECT_ROUTINE:
     764           0 :             foreach(cell, objnames)
     765             :             {
     766           0 :                 ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
     767             :                 Oid         routid;
     768             : 
     769           0 :                 routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
     770           0 :                 objects = lappend_oid(objects, routid);
     771             :             }
     772           0 :             break;
     773           0 :         case OBJECT_TABLESPACE:
     774           0 :             foreach(cell, objnames)
     775             :             {
     776           0 :                 char       *spcname = strVal(lfirst(cell));
     777             :                 Oid         spcoid;
     778             : 
     779           0 :                 spcoid = get_tablespace_oid(spcname, false);
     780           0 :                 objects = lappend_oid(objects, spcoid);
     781             :             }
     782           0 :             break;
     783          92 :         case OBJECT_FDW:
     784         184 :             foreach(cell, objnames)
     785             :             {
     786          92 :                 char       *fdwname = strVal(lfirst(cell));
     787          92 :                 Oid         fdwid = get_foreign_data_wrapper_oid(fdwname, false);
     788             : 
     789          92 :                 objects = lappend_oid(objects, fdwid);
     790             :             }
     791          92 :             break;
     792          76 :         case OBJECT_FOREIGN_SERVER:
     793         152 :             foreach(cell, objnames)
     794             :             {
     795          76 :                 char       *srvname = strVal(lfirst(cell));
     796          76 :                 Oid         srvid = get_foreign_server_oid(srvname, false);
     797             : 
     798          76 :                 objects = lappend_oid(objects, srvid);
     799             :             }
     800          76 :             break;
     801          74 :         case OBJECT_PARAMETER_ACL:
     802         196 :             foreach(cell, objnames)
     803             :             {
     804             :                 /*
     805             :                  * In this code we represent a GUC by the OID of its entry in
     806             :                  * pg_parameter_acl, which we have to manufacture here if it
     807             :                  * doesn't exist yet.  (That's a hack for sure, but it avoids
     808             :                  * messing with all the GRANT/REVOKE infrastructure that
     809             :                  * expects to use OIDs for object identities.)  However, if
     810             :                  * this is a REVOKE, we can instead just ignore any GUCs that
     811             :                  * don't have such an entry, as they must not have any
     812             :                  * privileges needing removal.
     813             :                  */
     814         124 :                 char       *parameter = strVal(lfirst(cell));
     815         124 :                 Oid         parameterId = ParameterAclLookup(parameter, true);
     816             : 
     817         124 :                 if (!OidIsValid(parameterId) && is_grant)
     818             :                 {
     819          68 :                     parameterId = ParameterAclCreate(parameter);
     820             : 
     821             :                     /*
     822             :                      * Prevent error when processing duplicate objects, and
     823             :                      * make this new entry visible so that ExecGrant_Parameter
     824             :                      * can update it.
     825             :                      */
     826          66 :                     CommandCounterIncrement();
     827             :                 }
     828         122 :                 if (OidIsValid(parameterId))
     829         110 :                     objects = lappend_oid(objects, parameterId);
     830             :             }
     831          72 :             break;
     832           0 :         default:
     833           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     834             :                  (int) objtype);
     835             :     }
     836             : 
     837       24212 :     return objects;
     838             : }
     839             : 
     840             : /*
     841             :  * objectsInSchemaToOids
     842             :  *
     843             :  * Find all objects of a given type in specified schemas, and make a list
     844             :  * of their Oids.  We check USAGE privilege on the schemas, but there is
     845             :  * no privilege checking on the individual objects here.
     846             :  */
     847             : static List *
     848          30 : objectsInSchemaToOids(ObjectType objtype, List *nspnames)
     849             : {
     850          30 :     List       *objects = NIL;
     851             :     ListCell   *cell;
     852             : 
     853          60 :     foreach(cell, nspnames)
     854             :     {
     855          30 :         char       *nspname = strVal(lfirst(cell));
     856             :         Oid         namespaceId;
     857             :         List       *objs;
     858             : 
     859          30 :         namespaceId = LookupExplicitNamespace(nspname, false);
     860             : 
     861          30 :         switch (objtype)
     862             :         {
     863          12 :             case OBJECT_TABLE:
     864          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
     865          12 :                 objects = list_concat(objects, objs);
     866          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
     867          12 :                 objects = list_concat(objects, objs);
     868          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
     869          12 :                 objects = list_concat(objects, objs);
     870          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
     871          12 :                 objects = list_concat(objects, objs);
     872          12 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_PARTITIONED_TABLE);
     873          12 :                 objects = list_concat(objects, objs);
     874          12 :                 break;
     875           0 :             case OBJECT_SEQUENCE:
     876           0 :                 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
     877           0 :                 objects = list_concat(objects, objs);
     878           0 :                 break;
     879          18 :             case OBJECT_FUNCTION:
     880             :             case OBJECT_PROCEDURE:
     881             :             case OBJECT_ROUTINE:
     882             :                 {
     883             :                     ScanKeyData key[2];
     884             :                     int         keycount;
     885             :                     Relation    rel;
     886             :                     TableScanDesc scan;
     887             :                     HeapTuple   tuple;
     888             : 
     889          18 :                     keycount = 0;
     890          18 :                     ScanKeyInit(&key[keycount++],
     891             :                                 Anum_pg_proc_pronamespace,
     892             :                                 BTEqualStrategyNumber, F_OIDEQ,
     893             :                                 ObjectIdGetDatum(namespaceId));
     894             : 
     895          18 :                     if (objtype == OBJECT_FUNCTION)
     896             :                         /* includes aggregates and window functions */
     897           6 :                         ScanKeyInit(&key[keycount++],
     898             :                                     Anum_pg_proc_prokind,
     899             :                                     BTEqualStrategyNumber, F_CHARNE,
     900             :                                     CharGetDatum(PROKIND_PROCEDURE));
     901          12 :                     else if (objtype == OBJECT_PROCEDURE)
     902           6 :                         ScanKeyInit(&key[keycount++],
     903             :                                     Anum_pg_proc_prokind,
     904             :                                     BTEqualStrategyNumber, F_CHAREQ,
     905             :                                     CharGetDatum(PROKIND_PROCEDURE));
     906             : 
     907          18 :                     rel = table_open(ProcedureRelationId, AccessShareLock);
     908          18 :                     scan = table_beginscan_catalog(rel, keycount, key);
     909             : 
     910          54 :                     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     911             :                     {
     912          36 :                         Oid         oid = ((Form_pg_proc) GETSTRUCT(tuple))->oid;
     913             : 
     914          36 :                         objects = lappend_oid(objects, oid);
     915             :                     }
     916             : 
     917          18 :                     table_endscan(scan);
     918          18 :                     table_close(rel, AccessShareLock);
     919             :                 }
     920          18 :                 break;
     921           0 :             default:
     922             :                 /* should not happen */
     923           0 :                 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
     924             :                      (int) objtype);
     925             :         }
     926             :     }
     927             : 
     928          30 :     return objects;
     929             : }
     930             : 
     931             : /*
     932             :  * getRelationsInNamespace
     933             :  *
     934             :  * Return Oid list of relations in given namespace filtered by relation kind
     935             :  */
     936             : static List *
     937          60 : getRelationsInNamespace(Oid namespaceId, char relkind)
     938             : {
     939          60 :     List       *relations = NIL;
     940             :     ScanKeyData key[2];
     941             :     Relation    rel;
     942             :     TableScanDesc scan;
     943             :     HeapTuple   tuple;
     944             : 
     945          60 :     ScanKeyInit(&key[0],
     946             :                 Anum_pg_class_relnamespace,
     947             :                 BTEqualStrategyNumber, F_OIDEQ,
     948             :                 ObjectIdGetDatum(namespaceId));
     949          60 :     ScanKeyInit(&key[1],
     950             :                 Anum_pg_class_relkind,
     951             :                 BTEqualStrategyNumber, F_CHAREQ,
     952             :                 CharGetDatum(relkind));
     953             : 
     954          60 :     rel = table_open(RelationRelationId, AccessShareLock);
     955          60 :     scan = table_beginscan_catalog(rel, 2, key);
     956             : 
     957          84 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     958             :     {
     959          24 :         Oid         oid = ((Form_pg_class) GETSTRUCT(tuple))->oid;
     960             : 
     961          24 :         relations = lappend_oid(relations, oid);
     962             :     }
     963             : 
     964          60 :     table_endscan(scan);
     965          60 :     table_close(rel, AccessShareLock);
     966             : 
     967          60 :     return relations;
     968             : }
     969             : 
     970             : 
     971             : /*
     972             :  * ALTER DEFAULT PRIVILEGES statement
     973             :  */
     974             : void
     975         160 : ExecAlterDefaultPrivilegesStmt(ParseState *pstate, AlterDefaultPrivilegesStmt *stmt)
     976             : {
     977         160 :     GrantStmt  *action = stmt->action;
     978             :     InternalDefaultACL iacls;
     979             :     ListCell   *cell;
     980         160 :     List       *rolespecs = NIL;
     981         160 :     List       *nspnames = NIL;
     982         160 :     DefElem    *drolespecs = NULL;
     983         160 :     DefElem    *dnspnames = NULL;
     984             :     AclMode     all_privileges;
     985             :     const char *errormsg;
     986             : 
     987             :     /* Deconstruct the "options" part of the statement */
     988         282 :     foreach(cell, stmt->options)
     989             :     {
     990         122 :         DefElem    *defel = (DefElem *) lfirst(cell);
     991             : 
     992         122 :         if (strcmp(defel->defname, "schemas") == 0)
     993             :         {
     994          54 :             if (dnspnames)
     995           0 :                 errorConflictingDefElem(defel, pstate);
     996          54 :             dnspnames = defel;
     997             :         }
     998          68 :         else if (strcmp(defel->defname, "roles") == 0)
     999             :         {
    1000          68 :             if (drolespecs)
    1001           0 :                 errorConflictingDefElem(defel, pstate);
    1002          68 :             drolespecs = defel;
    1003             :         }
    1004             :         else
    1005           0 :             elog(ERROR, "option \"%s\" not recognized", defel->defname);
    1006             :     }
    1007             : 
    1008         160 :     if (dnspnames)
    1009          54 :         nspnames = (List *) dnspnames->arg;
    1010         160 :     if (drolespecs)
    1011          68 :         rolespecs = (List *) drolespecs->arg;
    1012             : 
    1013             :     /* Prepare the InternalDefaultACL representation of the statement */
    1014             :     /* roleid to be filled below */
    1015             :     /* nspid to be filled in SetDefaultACLsInSchemas */
    1016         160 :     iacls.is_grant = action->is_grant;
    1017         160 :     iacls.objtype = action->objtype;
    1018             :     /* all_privs to be filled below */
    1019             :     /* privileges to be filled below */
    1020         160 :     iacls.grantees = NIL;       /* filled below */
    1021         160 :     iacls.grant_option = action->grant_option;
    1022         160 :     iacls.behavior = action->behavior;
    1023             : 
    1024             :     /*
    1025             :      * Convert the RoleSpec list into an Oid list.  Note that at this point we
    1026             :      * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
    1027             :      * there shouldn't be any additional work needed to support this case.
    1028             :      */
    1029         326 :     foreach(cell, action->grantees)
    1030             :     {
    1031         166 :         RoleSpec   *grantee = (RoleSpec *) lfirst(cell);
    1032             :         Oid         grantee_uid;
    1033             : 
    1034         166 :         switch (grantee->roletype)
    1035             :         {
    1036          40 :             case ROLESPEC_PUBLIC:
    1037          40 :                 grantee_uid = ACL_ID_PUBLIC;
    1038          40 :                 break;
    1039         126 :             default:
    1040         126 :                 grantee_uid = get_rolespec_oid(grantee, false);
    1041         126 :                 break;
    1042             :         }
    1043         166 :         iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
    1044             :     }
    1045             : 
    1046             :     /*
    1047             :      * Convert action->privileges, a list of privilege strings, into an
    1048             :      * AclMode bitmask.
    1049             :      */
    1050         160 :     switch (action->objtype)
    1051             :     {
    1052          78 :         case OBJECT_TABLE:
    1053          78 :             all_privileges = ACL_ALL_RIGHTS_RELATION;
    1054          78 :             errormsg = gettext_noop("invalid privilege type %s for relation");
    1055          78 :             break;
    1056           6 :         case OBJECT_SEQUENCE:
    1057           6 :             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1058           6 :             errormsg = gettext_noop("invalid privilege type %s for sequence");
    1059           6 :             break;
    1060          22 :         case OBJECT_FUNCTION:
    1061          22 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1062          22 :             errormsg = gettext_noop("invalid privilege type %s for function");
    1063          22 :             break;
    1064           0 :         case OBJECT_PROCEDURE:
    1065           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1066           0 :             errormsg = gettext_noop("invalid privilege type %s for procedure");
    1067           0 :             break;
    1068           0 :         case OBJECT_ROUTINE:
    1069           0 :             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1070           0 :             errormsg = gettext_noop("invalid privilege type %s for routine");
    1071           0 :             break;
    1072          18 :         case OBJECT_TYPE:
    1073          18 :             all_privileges = ACL_ALL_RIGHTS_TYPE;
    1074          18 :             errormsg = gettext_noop("invalid privilege type %s for type");
    1075          18 :             break;
    1076          36 :         case OBJECT_SCHEMA:
    1077          36 :             all_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1078          36 :             errormsg = gettext_noop("invalid privilege type %s for schema");
    1079          36 :             break;
    1080           0 :         default:
    1081           0 :             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
    1082             :                  (int) action->objtype);
    1083             :             /* keep compiler quiet */
    1084             :             all_privileges = ACL_NO_RIGHTS;
    1085             :             errormsg = NULL;
    1086             :     }
    1087             : 
    1088         160 :     if (action->privileges == NIL)
    1089             :     {
    1090          56 :         iacls.all_privs = true;
    1091             : 
    1092             :         /*
    1093             :          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
    1094             :          * depending on the object type
    1095             :          */
    1096          56 :         iacls.privileges = ACL_NO_RIGHTS;
    1097             :     }
    1098             :     else
    1099             :     {
    1100         104 :         iacls.all_privs = false;
    1101         104 :         iacls.privileges = ACL_NO_RIGHTS;
    1102             : 
    1103         208 :         foreach(cell, action->privileges)
    1104             :         {
    1105         104 :             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
    1106             :             AclMode     priv;
    1107             : 
    1108         104 :             if (privnode->cols)
    1109           0 :                 ereport(ERROR,
    1110             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1111             :                          errmsg("default privileges cannot be set for columns")));
    1112             : 
    1113         104 :             if (privnode->priv_name == NULL) /* parser mistake? */
    1114           0 :                 elog(ERROR, "AccessPriv node must specify privilege");
    1115         104 :             priv = string_to_privilege(privnode->priv_name);
    1116             : 
    1117         104 :             if (priv & ~((AclMode) all_privileges))
    1118           0 :                 ereport(ERROR,
    1119             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1120             :                          errmsg(errormsg, privilege_to_string(priv))));
    1121             : 
    1122         104 :             iacls.privileges |= priv;
    1123             :         }
    1124             :     }
    1125             : 
    1126         160 :     if (rolespecs == NIL)
    1127             :     {
    1128             :         /* Set permissions for myself */
    1129          92 :         iacls.roleid = GetUserId();
    1130             : 
    1131          92 :         SetDefaultACLsInSchemas(&iacls, nspnames);
    1132             :     }
    1133             :     else
    1134             :     {
    1135             :         /* Look up the role OIDs and do permissions checks */
    1136             :         ListCell   *rolecell;
    1137             : 
    1138         136 :         foreach(rolecell, rolespecs)
    1139             :         {
    1140          68 :             RoleSpec   *rolespec = lfirst(rolecell);
    1141             : 
    1142          68 :             iacls.roleid = get_rolespec_oid(rolespec, false);
    1143             : 
    1144          68 :             if (!has_privs_of_role(GetUserId(), iacls.roleid))
    1145           0 :                 ereport(ERROR,
    1146             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    1147             :                          errmsg("permission denied to change default privileges")));
    1148             : 
    1149          68 :             SetDefaultACLsInSchemas(&iacls, nspnames);
    1150             :         }
    1151             :     }
    1152         154 : }
    1153             : 
    1154             : /*
    1155             :  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
    1156             :  *
    1157             :  * All fields of *iacls except nspid were filled already
    1158             :  */
    1159             : static void
    1160         160 : SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
    1161             : {
    1162         160 :     if (nspnames == NIL)
    1163             :     {
    1164             :         /* Set database-wide permissions if no schema was specified */
    1165         106 :         iacls->nspid = InvalidOid;
    1166             : 
    1167         106 :         SetDefaultACL(iacls);
    1168             :     }
    1169             :     else
    1170             :     {
    1171             :         /* Look up the schema OIDs and set permissions for each one */
    1172             :         ListCell   *nspcell;
    1173             : 
    1174         108 :         foreach(nspcell, nspnames)
    1175             :         {
    1176          60 :             char       *nspname = strVal(lfirst(nspcell));
    1177             : 
    1178          60 :             iacls->nspid = get_namespace_oid(nspname, false);
    1179             : 
    1180             :             /*
    1181             :              * We used to insist that the target role have CREATE privileges
    1182             :              * on the schema, since without that it wouldn't be able to create
    1183             :              * an object for which these default privileges would apply.
    1184             :              * However, this check proved to be more confusing than helpful,
    1185             :              * and it also caused certain database states to not be
    1186             :              * dumpable/restorable, since revoking CREATE doesn't cause
    1187             :              * default privileges for the schema to go away.  So now, we just
    1188             :              * allow the ALTER; if the user lacks CREATE he'll find out when
    1189             :              * he tries to create an object.
    1190             :              */
    1191             : 
    1192          60 :             SetDefaultACL(iacls);
    1193             :         }
    1194             :     }
    1195         154 : }
    1196             : 
    1197             : 
    1198             : /*
    1199             :  * Create or update a pg_default_acl entry
    1200             :  */
    1201             : static void
    1202         196 : SetDefaultACL(InternalDefaultACL *iacls)
    1203             : {
    1204         196 :     AclMode     this_privileges = iacls->privileges;
    1205             :     char        objtype;
    1206             :     Relation    rel;
    1207             :     HeapTuple   tuple;
    1208             :     bool        isNew;
    1209             :     Acl        *def_acl;
    1210             :     Acl        *old_acl;
    1211             :     Acl        *new_acl;
    1212             :     HeapTuple   newtuple;
    1213             :     int         noldmembers;
    1214             :     int         nnewmembers;
    1215             :     Oid        *oldmembers;
    1216             :     Oid        *newmembers;
    1217             : 
    1218         196 :     rel = table_open(DefaultAclRelationId, RowExclusiveLock);
    1219             : 
    1220             :     /*
    1221             :      * The default for a global entry is the hard-wired default ACL for the
    1222             :      * particular object type.  The default for non-global entries is an empty
    1223             :      * ACL.  This must be so because global entries replace the hard-wired
    1224             :      * defaults, while others are added on.
    1225             :      */
    1226         196 :     if (!OidIsValid(iacls->nspid))
    1227         136 :         def_acl = acldefault(iacls->objtype, iacls->roleid);
    1228             :     else
    1229          60 :         def_acl = make_empty_acl();
    1230             : 
    1231             :     /*
    1232             :      * Convert ACL object type to pg_default_acl object type and handle
    1233             :      * all_privs option
    1234             :      */
    1235         196 :     switch (iacls->objtype)
    1236             :     {
    1237          90 :         case OBJECT_TABLE:
    1238          90 :             objtype = DEFACLOBJ_RELATION;
    1239          90 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1240          26 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1241          90 :             break;
    1242             : 
    1243          12 :         case OBJECT_SEQUENCE:
    1244          12 :             objtype = DEFACLOBJ_SEQUENCE;
    1245          12 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1246          12 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1247          12 :             break;
    1248             : 
    1249          28 :         case OBJECT_FUNCTION:
    1250          28 :             objtype = DEFACLOBJ_FUNCTION;
    1251          28 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1252          12 :                 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
    1253          28 :             break;
    1254             : 
    1255          24 :         case OBJECT_TYPE:
    1256          24 :             objtype = DEFACLOBJ_TYPE;
    1257          24 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1258          12 :                 this_privileges = ACL_ALL_RIGHTS_TYPE;
    1259          24 :             break;
    1260             : 
    1261          42 :         case OBJECT_SCHEMA:
    1262          42 :             if (OidIsValid(iacls->nspid))
    1263           6 :                 ereport(ERROR,
    1264             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1265             :                          errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
    1266          36 :             objtype = DEFACLOBJ_NAMESPACE;
    1267          36 :             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
    1268          24 :                 this_privileges = ACL_ALL_RIGHTS_SCHEMA;
    1269          36 :             break;
    1270             : 
    1271           0 :         default:
    1272           0 :             elog(ERROR, "unrecognized object type: %d",
    1273             :                  (int) iacls->objtype);
    1274             :             objtype = 0;        /* keep compiler quiet */
    1275             :             break;
    1276             :     }
    1277             : 
    1278             :     /* Search for existing row for this object type in catalog */
    1279         190 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    1280             :                             ObjectIdGetDatum(iacls->roleid),
    1281             :                             ObjectIdGetDatum(iacls->nspid),
    1282             :                             CharGetDatum(objtype));
    1283             : 
    1284         190 :     if (HeapTupleIsValid(tuple))
    1285             :     {
    1286             :         Datum       aclDatum;
    1287             :         bool        isNull;
    1288             : 
    1289          72 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    1290             :                                    Anum_pg_default_acl_defaclacl,
    1291             :                                    &isNull);
    1292          72 :         if (!isNull)
    1293          72 :             old_acl = DatumGetAclPCopy(aclDatum);
    1294             :         else
    1295           0 :             old_acl = NULL;     /* this case shouldn't happen, probably */
    1296          72 :         isNew = false;
    1297             :     }
    1298             :     else
    1299             :     {
    1300         118 :         old_acl = NULL;
    1301         118 :         isNew = true;
    1302             :     }
    1303             : 
    1304         190 :     if (old_acl != NULL)
    1305             :     {
    1306             :         /*
    1307             :          * We need the members of both old and new ACLs so we can correct the
    1308             :          * shared dependency information.  Collect data before
    1309             :          * merge_acl_with_grant throws away old_acl.
    1310             :          */
    1311          72 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1312             :     }
    1313             :     else
    1314             :     {
    1315             :         /* If no or null entry, start with the default ACL value */
    1316         118 :         old_acl = aclcopy(def_acl);
    1317             :         /* There are no old member roles according to the catalogs */
    1318         118 :         noldmembers = 0;
    1319         118 :         oldmembers = NULL;
    1320             :     }
    1321             : 
    1322             :     /*
    1323             :      * Generate new ACL.  Grantor of rights is always the same as the target
    1324             :      * role.
    1325             :      */
    1326         190 :     new_acl = merge_acl_with_grant(old_acl,
    1327         190 :                                    iacls->is_grant,
    1328         190 :                                    iacls->grant_option,
    1329             :                                    iacls->behavior,
    1330             :                                    iacls->grantees,
    1331             :                                    this_privileges,
    1332             :                                    iacls->roleid,
    1333             :                                    iacls->roleid);
    1334             : 
    1335             :     /*
    1336             :      * If the result is the same as the default value, we do not need an
    1337             :      * explicit pg_default_acl entry, and should in fact remove the entry if
    1338             :      * it exists.  Must sort both arrays to compare properly.
    1339             :      */
    1340         190 :     aclitemsort(new_acl);
    1341         190 :     aclitemsort(def_acl);
    1342         190 :     if (aclequal(new_acl, def_acl))
    1343             :     {
    1344             :         /* delete old entry, if indeed there is one */
    1345          56 :         if (!isNew)
    1346             :         {
    1347             :             ObjectAddress myself;
    1348             : 
    1349             :             /*
    1350             :              * The dependency machinery will take care of removing all
    1351             :              * associated dependency entries.  We use DROP_RESTRICT since
    1352             :              * there shouldn't be anything depending on this entry.
    1353             :              */
    1354          54 :             myself.classId = DefaultAclRelationId;
    1355          54 :             myself.objectId = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1356          54 :             myself.objectSubId = 0;
    1357             : 
    1358          54 :             performDeletion(&myself, DROP_RESTRICT, 0);
    1359             :         }
    1360             :     }
    1361             :     else
    1362             :     {
    1363         134 :         Datum       values[Natts_pg_default_acl] = {0};
    1364         134 :         bool        nulls[Natts_pg_default_acl] = {0};
    1365         134 :         bool        replaces[Natts_pg_default_acl] = {0};
    1366             :         Oid         defAclOid;
    1367             : 
    1368         134 :         if (isNew)
    1369             :         {
    1370             :             /* insert new entry */
    1371         116 :             defAclOid = GetNewOidWithIndex(rel, DefaultAclOidIndexId,
    1372             :                                            Anum_pg_default_acl_oid);
    1373         116 :             values[Anum_pg_default_acl_oid - 1] = ObjectIdGetDatum(defAclOid);
    1374         116 :             values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
    1375         116 :             values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
    1376         116 :             values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
    1377         116 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1378             : 
    1379         116 :             newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
    1380         116 :             CatalogTupleInsert(rel, newtuple);
    1381             :         }
    1382             :         else
    1383             :         {
    1384          18 :             defAclOid = ((Form_pg_default_acl) GETSTRUCT(tuple))->oid;
    1385             : 
    1386             :             /* update existing entry */
    1387          18 :             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
    1388          18 :             replaces[Anum_pg_default_acl_defaclacl - 1] = true;
    1389             : 
    1390          18 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
    1391             :                                          values, nulls, replaces);
    1392          18 :             CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    1393             :         }
    1394             : 
    1395             :         /* these dependencies don't change in an update */
    1396         134 :         if (isNew)
    1397             :         {
    1398             :             /* dependency on role */
    1399         116 :             recordDependencyOnOwner(DefaultAclRelationId, defAclOid,
    1400             :                                     iacls->roleid);
    1401             : 
    1402             :             /* dependency on namespace */
    1403         116 :             if (OidIsValid(iacls->nspid))
    1404             :             {
    1405             :                 ObjectAddress myself,
    1406             :                             referenced;
    1407             : 
    1408          34 :                 myself.classId = DefaultAclRelationId;
    1409          34 :                 myself.objectId = defAclOid;
    1410          34 :                 myself.objectSubId = 0;
    1411             : 
    1412          34 :                 referenced.classId = NamespaceRelationId;
    1413          34 :                 referenced.objectId = iacls->nspid;
    1414          34 :                 referenced.objectSubId = 0;
    1415             : 
    1416          34 :                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
    1417             :             }
    1418             :         }
    1419             : 
    1420             :         /*
    1421             :          * Update the shared dependency ACL info
    1422             :          */
    1423         134 :         nnewmembers = aclmembers(new_acl, &newmembers);
    1424             : 
    1425         134 :         updateAclDependencies(DefaultAclRelationId,
    1426             :                               defAclOid, 0,
    1427             :                               iacls->roleid,
    1428             :                               noldmembers, oldmembers,
    1429             :                               nnewmembers, newmembers);
    1430             : 
    1431         134 :         if (isNew)
    1432         116 :             InvokeObjectPostCreateHook(DefaultAclRelationId, defAclOid, 0);
    1433             :         else
    1434          18 :             InvokeObjectPostAlterHook(DefaultAclRelationId, defAclOid, 0);
    1435             :     }
    1436             : 
    1437         190 :     if (HeapTupleIsValid(tuple))
    1438          72 :         ReleaseSysCache(tuple);
    1439             : 
    1440         190 :     table_close(rel, RowExclusiveLock);
    1441             : 
    1442             :     /* prevent error when processing duplicate objects */
    1443         190 :     CommandCounterIncrement();
    1444         190 : }
    1445             : 
    1446             : 
    1447             : /*
    1448             :  * RemoveRoleFromObjectACL
    1449             :  *
    1450             :  * Used by shdepDropOwned to remove mentions of a role in ACLs.
    1451             :  *
    1452             :  * Notice that this doesn't accept an objsubid parameter, which is a bit bogus
    1453             :  * since the pg_shdepend record that caused us to call it certainly had one.
    1454             :  * If, for example, pg_shdepend records the existence of a permission on
    1455             :  * mytable.mycol, this function will effectively issue a REVOKE ALL ON TABLE
    1456             :  * mytable.  That gets the job done because (per SQL spec) such a REVOKE also
    1457             :  * revokes per-column permissions.  We could not recreate a situation where
    1458             :  * the role has table-level but not column-level permissions; but it's okay
    1459             :  * (for now anyway) because this is only used when we're dropping the role
    1460             :  * and so all its permissions everywhere must go away.  At worst it's a bit
    1461             :  * inefficient if the role has column permissions on several columns of the
    1462             :  * same table.
    1463             :  */
    1464             : void
    1465         256 : RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
    1466             : {
    1467         256 :     if (classid == DefaultAclRelationId)
    1468             :     {
    1469             :         InternalDefaultACL iacls;
    1470             :         Form_pg_default_acl pg_default_acl_tuple;
    1471             :         Relation    rel;
    1472             :         ScanKeyData skey[1];
    1473             :         SysScanDesc scan;
    1474             :         HeapTuple   tuple;
    1475             : 
    1476             :         /* first fetch info needed by SetDefaultACL */
    1477          30 :         rel = table_open(DefaultAclRelationId, AccessShareLock);
    1478             : 
    1479          30 :         ScanKeyInit(&skey[0],
    1480             :                     Anum_pg_default_acl_oid,
    1481             :                     BTEqualStrategyNumber, F_OIDEQ,
    1482             :                     ObjectIdGetDatum(objid));
    1483             : 
    1484          30 :         scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
    1485             :                                   NULL, 1, skey);
    1486             : 
    1487          30 :         tuple = systable_getnext(scan);
    1488             : 
    1489          30 :         if (!HeapTupleIsValid(tuple))
    1490           0 :             elog(ERROR, "could not find tuple for default ACL %u", objid);
    1491             : 
    1492          30 :         pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
    1493             : 
    1494          30 :         iacls.roleid = pg_default_acl_tuple->defaclrole;
    1495          30 :         iacls.nspid = pg_default_acl_tuple->defaclnamespace;
    1496             : 
    1497          30 :         switch (pg_default_acl_tuple->defaclobjtype)
    1498             :         {
    1499           6 :             case DEFACLOBJ_RELATION:
    1500           6 :                 iacls.objtype = OBJECT_TABLE;
    1501           6 :                 break;
    1502           6 :             case DEFACLOBJ_SEQUENCE:
    1503           6 :                 iacls.objtype = OBJECT_SEQUENCE;
    1504           6 :                 break;
    1505           6 :             case DEFACLOBJ_FUNCTION:
    1506           6 :                 iacls.objtype = OBJECT_FUNCTION;
    1507           6 :                 break;
    1508           6 :             case DEFACLOBJ_TYPE:
    1509           6 :                 iacls.objtype = OBJECT_TYPE;
    1510           6 :                 break;
    1511           6 :             case DEFACLOBJ_NAMESPACE:
    1512           6 :                 iacls.objtype = OBJECT_SCHEMA;
    1513           6 :                 break;
    1514           0 :             default:
    1515             :                 /* Shouldn't get here */
    1516           0 :                 elog(ERROR, "unexpected default ACL type: %d",
    1517             :                      (int) pg_default_acl_tuple->defaclobjtype);
    1518             :                 break;
    1519             :         }
    1520             : 
    1521          30 :         systable_endscan(scan);
    1522          30 :         table_close(rel, AccessShareLock);
    1523             : 
    1524          30 :         iacls.is_grant = false;
    1525          30 :         iacls.all_privs = true;
    1526          30 :         iacls.privileges = ACL_NO_RIGHTS;
    1527          30 :         iacls.grantees = list_make1_oid(roleid);
    1528          30 :         iacls.grant_option = false;
    1529          30 :         iacls.behavior = DROP_CASCADE;
    1530             : 
    1531             :         /* Do it */
    1532          30 :         SetDefaultACL(&iacls);
    1533             :     }
    1534             :     else
    1535             :     {
    1536             :         InternalGrant istmt;
    1537             : 
    1538         226 :         switch (classid)
    1539             :         {
    1540         100 :             case RelationRelationId:
    1541             :                 /* it's OK to use TABLE for a sequence */
    1542         100 :                 istmt.objtype = OBJECT_TABLE;
    1543         100 :                 break;
    1544          10 :             case DatabaseRelationId:
    1545          10 :                 istmt.objtype = OBJECT_DATABASE;
    1546          10 :                 break;
    1547           6 :             case TypeRelationId:
    1548           6 :                 istmt.objtype = OBJECT_TYPE;
    1549           6 :                 break;
    1550          38 :             case ProcedureRelationId:
    1551          38 :                 istmt.objtype = OBJECT_ROUTINE;
    1552          38 :                 break;
    1553           0 :             case LanguageRelationId:
    1554           0 :                 istmt.objtype = OBJECT_LANGUAGE;
    1555           0 :                 break;
    1556          18 :             case LargeObjectRelationId:
    1557          18 :                 istmt.objtype = OBJECT_LARGEOBJECT;
    1558          18 :                 break;
    1559          14 :             case NamespaceRelationId:
    1560          14 :                 istmt.objtype = OBJECT_SCHEMA;
    1561          14 :                 break;
    1562           0 :             case TableSpaceRelationId:
    1563           0 :                 istmt.objtype = OBJECT_TABLESPACE;
    1564           0 :                 break;
    1565          14 :             case ForeignServerRelationId:
    1566          14 :                 istmt.objtype = OBJECT_FOREIGN_SERVER;
    1567          14 :                 break;
    1568           2 :             case ForeignDataWrapperRelationId:
    1569           2 :                 istmt.objtype = OBJECT_FDW;
    1570           2 :                 break;
    1571          24 :             case ParameterAclRelationId:
    1572          24 :                 istmt.objtype = OBJECT_PARAMETER_ACL;
    1573          24 :                 break;
    1574           0 :             default:
    1575           0 :                 elog(ERROR, "unexpected object class %u", classid);
    1576             :                 break;
    1577             :         }
    1578         226 :         istmt.is_grant = false;
    1579         226 :         istmt.objects = list_make1_oid(objid);
    1580         226 :         istmt.all_privs = true;
    1581         226 :         istmt.privileges = ACL_NO_RIGHTS;
    1582         226 :         istmt.col_privs = NIL;
    1583         226 :         istmt.grantees = list_make1_oid(roleid);
    1584         226 :         istmt.grant_option = false;
    1585         226 :         istmt.behavior = DROP_CASCADE;
    1586             : 
    1587         226 :         ExecGrantStmt_oids(&istmt);
    1588             :     }
    1589         256 : }
    1590             : 
    1591             : 
    1592             : /*
    1593             :  * expand_col_privileges
    1594             :  *
    1595             :  * OR the specified privilege(s) into per-column array entries for each
    1596             :  * specified attribute.  The per-column array is indexed starting at
    1597             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1598             :  */
    1599             : static void
    1600         416 : expand_col_privileges(List *colnames, Oid table_oid,
    1601             :                       AclMode this_privileges,
    1602             :                       AclMode *col_privileges,
    1603             :                       int num_col_privileges)
    1604             : {
    1605             :     ListCell   *cell;
    1606             : 
    1607        2322 :     foreach(cell, colnames)
    1608             :     {
    1609        1906 :         char       *colname = strVal(lfirst(cell));
    1610             :         AttrNumber  attnum;
    1611             : 
    1612        1906 :         attnum = get_attnum(table_oid, colname);
    1613        1906 :         if (attnum == InvalidAttrNumber)
    1614           0 :             ereport(ERROR,
    1615             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    1616             :                      errmsg("column \"%s\" of relation \"%s\" does not exist",
    1617             :                             colname, get_rel_name(table_oid))));
    1618        1906 :         attnum -= FirstLowInvalidHeapAttributeNumber;
    1619        1906 :         if (attnum <= 0 || attnum >= num_col_privileges)
    1620           0 :             elog(ERROR, "column number out of range");    /* safety check */
    1621        1906 :         col_privileges[attnum] |= this_privileges;
    1622             :     }
    1623         416 : }
    1624             : 
    1625             : /*
    1626             :  * expand_all_col_privileges
    1627             :  *
    1628             :  * OR the specified privilege(s) into per-column array entries for each valid
    1629             :  * attribute of a relation.  The per-column array is indexed starting at
    1630             :  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
    1631             :  */
    1632             : static void
    1633        5930 : expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
    1634             :                           AclMode this_privileges,
    1635             :                           AclMode *col_privileges,
    1636             :                           int num_col_privileges)
    1637             : {
    1638             :     AttrNumber  curr_att;
    1639             : 
    1640             :     Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
    1641        5930 :     for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
    1642       58284 :          curr_att <= classForm->relnatts;
    1643       52354 :          curr_att++)
    1644             :     {
    1645             :         HeapTuple   attTuple;
    1646             :         bool        isdropped;
    1647             : 
    1648       52354 :         if (curr_att == InvalidAttrNumber)
    1649        5930 :             continue;
    1650             : 
    1651             :         /* Views don't have any system columns at all */
    1652       46424 :         if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
    1653        3816 :             continue;
    1654             : 
    1655       42608 :         attTuple = SearchSysCache2(ATTNUM,
    1656             :                                    ObjectIdGetDatum(table_oid),
    1657             :                                    Int16GetDatum(curr_att));
    1658       42608 :         if (!HeapTupleIsValid(attTuple))
    1659           0 :             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1660             :                  curr_att, table_oid);
    1661             : 
    1662       42608 :         isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
    1663             : 
    1664       42608 :         ReleaseSysCache(attTuple);
    1665             : 
    1666             :         /* ignore dropped columns */
    1667       42608 :         if (isdropped)
    1668           6 :             continue;
    1669             : 
    1670       42602 :         col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
    1671             :     }
    1672        5930 : }
    1673             : 
    1674             : /*
    1675             :  *  This processes attributes, but expects to be called from
    1676             :  *  ExecGrant_Relation, not directly from ExecuteGrantStmt.
    1677             :  */
    1678             : static void
    1679       44438 : ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
    1680             :                     AttrNumber attnum, Oid ownerId, AclMode col_privileges,
    1681             :                     Relation attRelation, const Acl *old_rel_acl)
    1682             : {
    1683             :     HeapTuple   attr_tuple;
    1684             :     Form_pg_attribute pg_attribute_tuple;
    1685             :     Acl        *old_acl;
    1686             :     Acl        *new_acl;
    1687             :     Acl        *merged_acl;
    1688             :     Datum       aclDatum;
    1689             :     bool        isNull;
    1690             :     Oid         grantorId;
    1691             :     AclMode     avail_goptions;
    1692             :     bool        need_update;
    1693             :     HeapTuple   newtuple;
    1694       44438 :     Datum       values[Natts_pg_attribute] = {0};
    1695       44438 :     bool        nulls[Natts_pg_attribute] = {0};
    1696       44438 :     bool        replaces[Natts_pg_attribute] = {0};
    1697             :     int         noldmembers;
    1698             :     int         nnewmembers;
    1699             :     Oid        *oldmembers;
    1700             :     Oid        *newmembers;
    1701             : 
    1702       44438 :     attr_tuple = SearchSysCache2(ATTNUM,
    1703             :                                  ObjectIdGetDatum(relOid),
    1704             :                                  Int16GetDatum(attnum));
    1705       44438 :     if (!HeapTupleIsValid(attr_tuple))
    1706           0 :         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
    1707             :              attnum, relOid);
    1708       44438 :     pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
    1709             : 
    1710             :     /*
    1711             :      * Get working copy of existing ACL. If there's no ACL, substitute the
    1712             :      * proper default.
    1713             :      */
    1714       44438 :     aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
    1715             :                                &isNull);
    1716       44438 :     if (isNull)
    1717             :     {
    1718       44128 :         old_acl = acldefault(OBJECT_COLUMN, ownerId);
    1719             :         /* There are no old member roles according to the catalogs */
    1720       44128 :         noldmembers = 0;
    1721       44128 :         oldmembers = NULL;
    1722             :     }
    1723             :     else
    1724             :     {
    1725         310 :         old_acl = DatumGetAclPCopy(aclDatum);
    1726             :         /* Get the roles mentioned in the existing ACL */
    1727         310 :         noldmembers = aclmembers(old_acl, &oldmembers);
    1728             :     }
    1729             : 
    1730             :     /*
    1731             :      * In select_best_grantor we should consider existing table-level ACL bits
    1732             :      * as well as the per-column ACL.  Build a new ACL that is their
    1733             :      * concatenation.  (This is a bit cheap and dirty compared to merging them
    1734             :      * properly with no duplications, but it's all we need here.)
    1735             :      */
    1736       44438 :     merged_acl = aclconcat(old_rel_acl, old_acl);
    1737             : 
    1738             :     /* Determine ID to do the grant as, and available grant options */
    1739       44438 :     select_best_grantor(GetUserId(), col_privileges,
    1740             :                         merged_acl, ownerId,
    1741             :                         &grantorId, &avail_goptions);
    1742             : 
    1743       44438 :     pfree(merged_acl);
    1744             : 
    1745             :     /*
    1746             :      * Restrict the privileges to what we can actually grant, and emit the
    1747             :      * standards-mandated warning and error messages.  Note: we don't track
    1748             :      * whether the user actually used the ALL PRIVILEGES(columns) syntax for
    1749             :      * each column; we just approximate it by whether all the possible
    1750             :      * privileges are specified now.  Since the all_privs flag only determines
    1751             :      * whether a warning is issued, this seems close enough.
    1752             :      */
    1753             :     col_privileges =
    1754       44438 :         restrict_and_check_grant(istmt->is_grant, avail_goptions,
    1755             :                                  (col_privileges == ACL_ALL_RIGHTS_COLUMN),
    1756             :                                  col_privileges,
    1757             :                                  relOid, grantorId, OBJECT_COLUMN,
    1758             :                                  relname, attnum,
    1759       44438 :                                  NameStr(pg_attribute_tuple->attname));
    1760             : 
    1761             :     /*
    1762             :      * Generate new ACL.
    1763             :      */
    1764       44438 :     new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    1765       44438 :                                    istmt->grant_option,
    1766             :                                    istmt->behavior, istmt->grantees,
    1767             :                                    col_privileges, grantorId,
    1768             :                                    ownerId);
    1769             : 
    1770             :     /*
    1771             :      * We need the members of both old and new ACLs so we can correct the
    1772             :      * shared dependency information.
    1773             :      */
    1774       44438 :     nnewmembers = aclmembers(new_acl, &newmembers);
    1775             : 
    1776             :     /* finished building new ACL value, now insert it */
    1777             : 
    1778             :     /*
    1779             :      * If the updated ACL is empty, we can set attacl to null, and maybe even
    1780             :      * avoid an update of the pg_attribute row.  This is worth testing because
    1781             :      * we'll come through here multiple times for any relation-level REVOKE,
    1782             :      * even if there were never any column GRANTs.  Note we are assuming that
    1783             :      * the "default" ACL state for columns is empty.
    1784             :      */
    1785       44438 :     if (ACL_NUM(new_acl) > 0)
    1786             :     {
    1787        1930 :         values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
    1788        1930 :         need_update = true;
    1789             :     }
    1790             :     else
    1791             :     {
    1792       42508 :         nulls[Anum_pg_attribute_attacl - 1] = true;
    1793       42508 :         need_update = !isNull;
    1794             :     }
    1795       44438 :     replaces[Anum_pg_attribute_attacl - 1] = true;
    1796             : 
    1797       44438 :     if (need_update)
    1798             :     {
    1799        2026 :         newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
    1800             :                                      values, nulls, replaces);
    1801             : 
    1802        2026 :         CatalogTupleUpdate(attRelation, &newtuple->t_self, newtuple);
    1803             : 
    1804             :         /* Update initial privileges for extensions */
    1805        2026 :         recordExtensionInitPriv(relOid, RelationRelationId, attnum,
    1806        2026 :                                 ACL_NUM(new_acl) > 0 ? new_acl : NULL);
    1807             : 
    1808             :         /* Update the shared dependency ACL info */
    1809        2026 :         updateAclDependencies(RelationRelationId, relOid, attnum,
    1810             :                               ownerId,
    1811             :                               noldmembers, oldmembers,
    1812             :                               nnewmembers, newmembers);
    1813             :     }
    1814             : 
    1815       44438 :     pfree(new_acl);
    1816             : 
    1817       44438 :     ReleaseSysCache(attr_tuple);
    1818       44438 : }
    1819             : 
    1820             : /*
    1821             :  *  This processes both sequences and non-sequences.
    1822             :  */
    1823             : static void
    1824       16738 : ExecGrant_Relation(InternalGrant *istmt)
    1825             : {
    1826             :     Relation    relation;
    1827             :     Relation    attRelation;
    1828             :     ListCell   *cell;
    1829             : 
    1830       16738 :     relation = table_open(RelationRelationId, RowExclusiveLock);
    1831       16738 :     attRelation = table_open(AttributeRelationId, RowExclusiveLock);
    1832             : 
    1833       33532 :     foreach(cell, istmt->objects)
    1834             :     {
    1835       16804 :         Oid         relOid = lfirst_oid(cell);
    1836             :         Datum       aclDatum;
    1837             :         Form_pg_class pg_class_tuple;
    1838             :         bool        isNull;
    1839             :         AclMode     this_privileges;
    1840             :         AclMode    *col_privileges;
    1841             :         int         num_col_privileges;
    1842             :         bool        have_col_privileges;
    1843             :         Acl        *old_acl;
    1844             :         Acl        *old_rel_acl;
    1845             :         int         noldmembers;
    1846             :         Oid        *oldmembers;
    1847             :         Oid         ownerId;
    1848             :         HeapTuple   tuple;
    1849             :         ListCell   *cell_colprivs;
    1850             : 
    1851       16804 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
    1852       16804 :         if (!HeapTupleIsValid(tuple))
    1853           0 :             elog(ERROR, "cache lookup failed for relation %u", relOid);
    1854       16804 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    1855             : 
    1856             :         /* Not sensible to grant on an index */
    1857       16804 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    1858       16804 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
    1859           0 :             ereport(ERROR,
    1860             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1861             :                      errmsg("\"%s\" is an index",
    1862             :                             NameStr(pg_class_tuple->relname))));
    1863             : 
    1864             :         /* Composite types aren't tables either */
    1865       16804 :         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    1866           0 :             ereport(ERROR,
    1867             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1868             :                      errmsg("\"%s\" is a composite type",
    1869             :                             NameStr(pg_class_tuple->relname))));
    1870             : 
    1871             :         /* Used GRANT SEQUENCE on a non-sequence? */
    1872       16804 :         if (istmt->objtype == OBJECT_SEQUENCE &&
    1873          22 :             pg_class_tuple->relkind != RELKIND_SEQUENCE)
    1874           0 :             ereport(ERROR,
    1875             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1876             :                      errmsg("\"%s\" is not a sequence",
    1877             :                             NameStr(pg_class_tuple->relname))));
    1878             : 
    1879             :         /* Adjust the default permissions based on object type */
    1880       16804 :         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    1881             :         {
    1882        1580 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1883          80 :                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
    1884             :             else
    1885        1500 :                 this_privileges = ACL_ALL_RIGHTS_RELATION;
    1886             :         }
    1887             :         else
    1888       15224 :             this_privileges = istmt->privileges;
    1889             : 
    1890             :         /*
    1891             :          * The GRANT TABLE syntax can be used for sequences and non-sequences,
    1892             :          * so we have to look at the relkind to determine the supported
    1893             :          * permissions.  The OR of table and sequence permissions were already
    1894             :          * checked.
    1895             :          */
    1896       16804 :         if (istmt->objtype == OBJECT_TABLE)
    1897             :         {
    1898       16782 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
    1899             :             {
    1900             :                 /*
    1901             :                  * For backward compatibility, just throw a warning for
    1902             :                  * invalid sequence permissions when using the non-sequence
    1903             :                  * GRANT syntax.
    1904             :                  */
    1905         152 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
    1906             :                 {
    1907             :                     /*
    1908             :                      * Mention the object name because the user needs to know
    1909             :                      * which operations succeeded.  This is required because
    1910             :                      * WARNING allows the command to continue.
    1911             :                      */
    1912           0 :                     ereport(WARNING,
    1913             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1914             :                              errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
    1915             :                                     NameStr(pg_class_tuple->relname))));
    1916           0 :                     this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
    1917             :                 }
    1918             :             }
    1919             :             else
    1920             :             {
    1921       16630 :                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
    1922             :                 {
    1923             :                     /*
    1924             :                      * USAGE is the only permission supported by sequences but
    1925             :                      * not by non-sequences.  Don't mention the object name
    1926             :                      * because we didn't in the combined TABLE | SEQUENCE
    1927             :                      * check.
    1928             :                      */
    1929           0 :                     ereport(ERROR,
    1930             :                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    1931             :                              errmsg("invalid privilege type %s for table",
    1932             :                                     "USAGE")));
    1933             :                 }
    1934             :             }
    1935             :         }
    1936             : 
    1937             :         /*
    1938             :          * Set up array in which we'll accumulate any column privilege bits
    1939             :          * that need modification.  The array is indexed such that entry [0]
    1940             :          * corresponds to FirstLowInvalidHeapAttributeNumber.
    1941             :          */
    1942       16804 :         num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
    1943       16804 :         col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
    1944       16804 :         have_col_privileges = false;
    1945             : 
    1946             :         /*
    1947             :          * If we are revoking relation privileges that are also column
    1948             :          * privileges, we must implicitly revoke them from each column too,
    1949             :          * per SQL spec.  (We don't need to implicitly add column privileges
    1950             :          * during GRANT because the permissions-checking code always checks
    1951             :          * both relation and per-column privileges.)
    1952             :          */
    1953       16804 :         if (!istmt->is_grant &&
    1954        5988 :             (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
    1955             :         {
    1956        5930 :             expand_all_col_privileges(relOid, pg_class_tuple,
    1957             :                                       this_privileges & ACL_ALL_RIGHTS_COLUMN,
    1958             :                                       col_privileges,
    1959             :                                       num_col_privileges);
    1960        5930 :             have_col_privileges = true;
    1961             :         }
    1962             : 
    1963             :         /*
    1964             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    1965             :          * substitute the proper default.
    1966             :          */
    1967       16804 :         ownerId = pg_class_tuple->relowner;
    1968       16804 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    1969             :                                    &isNull);
    1970       16804 :         if (isNull)
    1971             :         {
    1972        6902 :             switch (pg_class_tuple->relkind)
    1973             :             {
    1974          92 :                 case RELKIND_SEQUENCE:
    1975          92 :                     old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
    1976          92 :                     break;
    1977        6810 :                 default:
    1978        6810 :                     old_acl = acldefault(OBJECT_TABLE, ownerId);
    1979        6810 :                     break;
    1980             :             }
    1981             :             /* There are no old member roles according to the catalogs */
    1982        6902 :             noldmembers = 0;
    1983        6902 :             oldmembers = NULL;
    1984             :         }
    1985             :         else
    1986             :         {
    1987        9902 :             old_acl = DatumGetAclPCopy(aclDatum);
    1988             :             /* Get the roles mentioned in the existing ACL */
    1989        9902 :             noldmembers = aclmembers(old_acl, &oldmembers);
    1990             :         }
    1991             : 
    1992             :         /* Need an extra copy of original rel ACL for column handling */
    1993       16804 :         old_rel_acl = aclcopy(old_acl);
    1994             : 
    1995             :         /*
    1996             :          * Handle relation-level privileges, if any were specified
    1997             :          */
    1998       16804 :         if (this_privileges != ACL_NO_RIGHTS)
    1999             :         {
    2000             :             AclMode     avail_goptions;
    2001             :             Acl        *new_acl;
    2002             :             Oid         grantorId;
    2003             :             HeapTuple   newtuple;
    2004       16400 :             Datum       values[Natts_pg_class] = {0};
    2005       16400 :             bool        nulls[Natts_pg_class] = {0};
    2006       16400 :             bool        replaces[Natts_pg_class] = {0};
    2007             :             int         nnewmembers;
    2008             :             Oid        *newmembers;
    2009             :             ObjectType  objtype;
    2010             : 
    2011             :             /* Determine ID to do the grant as, and available grant options */
    2012       16400 :             select_best_grantor(GetUserId(), this_privileges,
    2013             :                                 old_acl, ownerId,
    2014             :                                 &grantorId, &avail_goptions);
    2015             : 
    2016       16400 :             switch (pg_class_tuple->relkind)
    2017             :             {
    2018         174 :                 case RELKIND_SEQUENCE:
    2019         174 :                     objtype = OBJECT_SEQUENCE;
    2020         174 :                     break;
    2021       16226 :                 default:
    2022       16226 :                     objtype = OBJECT_TABLE;
    2023       16226 :                     break;
    2024             :             }
    2025             : 
    2026             :             /*
    2027             :              * Restrict the privileges to what we can actually grant, and emit
    2028             :              * the standards-mandated warning and error messages.
    2029             :              */
    2030             :             this_privileges =
    2031       16400 :                 restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2032       16400 :                                          istmt->all_privs, this_privileges,
    2033             :                                          relOid, grantorId, objtype,
    2034       16400 :                                          NameStr(pg_class_tuple->relname),
    2035             :                                          0, NULL);
    2036             : 
    2037             :             /*
    2038             :              * Generate new ACL.
    2039             :              */
    2040       16400 :             new_acl = merge_acl_with_grant(old_acl,
    2041       16400 :                                            istmt->is_grant,
    2042       16400 :                                            istmt->grant_option,
    2043             :                                            istmt->behavior,
    2044             :                                            istmt->grantees,
    2045             :                                            this_privileges,
    2046             :                                            grantorId,
    2047             :                                            ownerId);
    2048             : 
    2049             :             /*
    2050             :              * We need the members of both old and new ACLs so we can correct
    2051             :              * the shared dependency information.
    2052             :              */
    2053       16394 :             nnewmembers = aclmembers(new_acl, &newmembers);
    2054             : 
    2055             :             /* finished building new ACL value, now insert it */
    2056       16394 :             replaces[Anum_pg_class_relacl - 1] = true;
    2057       16394 :             values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
    2058             : 
    2059       16394 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2060             :                                          values, nulls, replaces);
    2061             : 
    2062       16394 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2063             : 
    2064             :             /* Update initial privileges for extensions */
    2065       16390 :             recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl);
    2066             : 
    2067             :             /* Update the shared dependency ACL info */
    2068       16390 :             updateAclDependencies(RelationRelationId, relOid, 0,
    2069             :                                   ownerId,
    2070             :                                   noldmembers, oldmembers,
    2071             :                                   nnewmembers, newmembers);
    2072             : 
    2073       16390 :             pfree(new_acl);
    2074             :         }
    2075             : 
    2076             :         /*
    2077             :          * Handle column-level privileges, if any were specified or implied.
    2078             :          * We first expand the user-specified column privileges into the
    2079             :          * array, and then iterate over all nonempty array entries.
    2080             :          */
    2081       17210 :         foreach(cell_colprivs, istmt->col_privs)
    2082             :         {
    2083         416 :             AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
    2084             : 
    2085         416 :             if (col_privs->priv_name == NULL)
    2086          18 :                 this_privileges = ACL_ALL_RIGHTS_COLUMN;
    2087             :             else
    2088         398 :                 this_privileges = string_to_privilege(col_privs->priv_name);
    2089             : 
    2090         416 :             if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
    2091           0 :                 ereport(ERROR,
    2092             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2093             :                          errmsg("invalid privilege type %s for column",
    2094             :                                 privilege_to_string(this_privileges))));
    2095             : 
    2096         416 :             if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
    2097           0 :                 this_privileges & ~((AclMode) ACL_SELECT))
    2098             :             {
    2099             :                 /*
    2100             :                  * The only column privilege allowed on sequences is SELECT.
    2101             :                  * This is a warning not error because we do it that way for
    2102             :                  * relation-level privileges.
    2103             :                  */
    2104           0 :                 ereport(WARNING,
    2105             :                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2106             :                          errmsg("sequence \"%s\" only supports SELECT column privileges",
    2107             :                                 NameStr(pg_class_tuple->relname))));
    2108             : 
    2109           0 :                 this_privileges &= (AclMode) ACL_SELECT;
    2110             :             }
    2111             : 
    2112         416 :             expand_col_privileges(col_privs->cols, relOid,
    2113             :                                   this_privileges,
    2114             :                                   col_privileges,
    2115             :                                   num_col_privileges);
    2116         416 :             have_col_privileges = true;
    2117             :         }
    2118             : 
    2119       16794 :         if (have_col_privileges)
    2120             :         {
    2121             :             AttrNumber  i;
    2122             : 
    2123       70502 :             for (i = 0; i < num_col_privileges; i++)
    2124             :             {
    2125       64178 :                 if (col_privileges[i] == ACL_NO_RIGHTS)
    2126       19740 :                     continue;
    2127       44438 :                 ExecGrant_Attribute(istmt,
    2128             :                                     relOid,
    2129       44438 :                                     NameStr(pg_class_tuple->relname),
    2130       44438 :                                     i + FirstLowInvalidHeapAttributeNumber,
    2131             :                                     ownerId,
    2132       44438 :                                     col_privileges[i],
    2133             :                                     attRelation,
    2134             :                                     old_rel_acl);
    2135             :             }
    2136             :         }
    2137             : 
    2138       16794 :         pfree(old_rel_acl);
    2139       16794 :         pfree(col_privileges);
    2140             : 
    2141       16794 :         ReleaseSysCache(tuple);
    2142             : 
    2143             :         /* prevent error when processing duplicate objects */
    2144       16794 :         CommandCounterIncrement();
    2145             :     }
    2146             : 
    2147       16728 :     table_close(attRelation, RowExclusiveLock);
    2148       16728 :     table_close(relation, RowExclusiveLock);
    2149       16728 : }
    2150             : 
    2151             : static void
    2152        7530 : ExecGrant_common(InternalGrant *istmt, Oid classid, AclMode default_privs,
    2153             :                  void (*object_check) (InternalGrant *istmt, HeapTuple tuple))
    2154             : {
    2155             :     int         cacheid;
    2156             :     Relation    relation;
    2157             :     ListCell   *cell;
    2158             : 
    2159        7530 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2160         688 :         istmt->privileges = default_privs;
    2161             : 
    2162        7530 :     cacheid = get_object_catcache_oid(classid);
    2163             : 
    2164        7530 :     relation = table_open(classid, RowExclusiveLock);
    2165             : 
    2166       15124 :     foreach(cell, istmt->objects)
    2167             :     {
    2168        7654 :         Oid         objectid = lfirst_oid(cell);
    2169             :         Datum       aclDatum;
    2170             :         Datum       nameDatum;
    2171             :         bool        isNull;
    2172             :         AclMode     avail_goptions;
    2173             :         AclMode     this_privileges;
    2174             :         Acl        *old_acl;
    2175             :         Acl        *new_acl;
    2176             :         Oid         grantorId;
    2177             :         Oid         ownerId;
    2178             :         HeapTuple   tuple;
    2179             :         HeapTuple   newtuple;
    2180        7654 :         Datum      *values = palloc0_array(Datum, RelationGetDescr(relation)->natts);
    2181        7654 :         bool       *nulls = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2182        7654 :         bool       *replaces = palloc0_array(bool, RelationGetDescr(relation)->natts);
    2183             :         int         noldmembers;
    2184             :         int         nnewmembers;
    2185             :         Oid        *oldmembers;
    2186             :         Oid        *newmembers;
    2187             : 
    2188        7654 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    2189        7654 :         if (!HeapTupleIsValid(tuple))
    2190           0 :             elog(ERROR, "cache lookup failed for %s %u", get_object_class_descr(classid), objectid);
    2191             : 
    2192             :         /*
    2193             :          * Additional object-type-specific checks
    2194             :          */
    2195        7654 :         if (object_check)
    2196         186 :             object_check(istmt, tuple);
    2197             : 
    2198             :         /*
    2199             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2200             :          * substitute the proper default.
    2201             :          */
    2202        7630 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    2203             :                                                           tuple,
    2204        7630 :                                                           get_object_attnum_owner(classid)));
    2205        7630 :         aclDatum = SysCacheGetAttr(cacheid,
    2206             :                                    tuple,
    2207        7630 :                                    get_object_attnum_acl(classid),
    2208             :                                    &isNull);
    2209        7630 :         if (isNull)
    2210             :         {
    2211        5894 :             old_acl = acldefault(get_object_type(classid, objectid), ownerId);
    2212             :             /* There are no old member roles according to the catalogs */
    2213        5894 :             noldmembers = 0;
    2214        5894 :             oldmembers = NULL;
    2215             :         }
    2216             :         else
    2217             :         {
    2218        1736 :             old_acl = DatumGetAclPCopy(aclDatum);
    2219             :             /* Get the roles mentioned in the existing ACL */
    2220        1736 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2221             :         }
    2222             : 
    2223             :         /* Determine ID to do the grant as, and available grant options */
    2224        7630 :         select_best_grantor(GetUserId(), istmt->privileges,
    2225             :                             old_acl, ownerId,
    2226             :                             &grantorId, &avail_goptions);
    2227             : 
    2228        7630 :         nameDatum = SysCacheGetAttrNotNull(cacheid, tuple,
    2229        7630 :                                            get_object_attnum_name(classid));
    2230             : 
    2231             :         /*
    2232             :          * Restrict the privileges to what we can actually grant, and emit the
    2233             :          * standards-mandated warning and error messages.
    2234             :          */
    2235             :         this_privileges =
    2236       15260 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2237        7630 :                                      istmt->all_privs, istmt->privileges,
    2238             :                                      objectid, grantorId, get_object_type(classid, objectid),
    2239        7630 :                                      NameStr(*DatumGetName(nameDatum)),
    2240             :                                      0, NULL);
    2241             : 
    2242             :         /*
    2243             :          * Generate new ACL.
    2244             :          */
    2245        7600 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2246        7600 :                                        istmt->grant_option, istmt->behavior,
    2247             :                                        istmt->grantees, this_privileges,
    2248             :                                        grantorId, ownerId);
    2249             : 
    2250             :         /*
    2251             :          * We need the members of both old and new ACLs so we can correct the
    2252             :          * shared dependency information.
    2253             :          */
    2254        7594 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2255             : 
    2256             :         /* finished building new ACL value, now insert it */
    2257        7594 :         replaces[get_object_attnum_acl(classid) - 1] = true;
    2258        7594 :         values[get_object_attnum_acl(classid) - 1] = PointerGetDatum(new_acl);
    2259             : 
    2260        7594 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
    2261             :                                      nulls, replaces);
    2262             : 
    2263        7594 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2264             : 
    2265             :         /* Update initial privileges for extensions */
    2266        7594 :         recordExtensionInitPriv(objectid, classid, 0, new_acl);
    2267             : 
    2268             :         /* Update the shared dependency ACL info */
    2269        7594 :         updateAclDependencies(classid,
    2270             :                               objectid, 0,
    2271             :                               ownerId,
    2272             :                               noldmembers, oldmembers,
    2273             :                               nnewmembers, newmembers);
    2274             : 
    2275        7594 :         ReleaseSysCache(tuple);
    2276             : 
    2277        7594 :         pfree(new_acl);
    2278             : 
    2279             :         /* prevent error when processing duplicate objects */
    2280        7594 :         CommandCounterIncrement();
    2281             :     }
    2282             : 
    2283        7470 :     table_close(relation, RowExclusiveLock);
    2284        7470 : }
    2285             : 
    2286             : static void
    2287          42 : ExecGrant_Language_check(InternalGrant *istmt, HeapTuple tuple)
    2288             : {
    2289             :     Form_pg_language pg_language_tuple;
    2290             : 
    2291          42 :     pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
    2292             : 
    2293          42 :     if (!pg_language_tuple->lanpltrusted)
    2294           6 :         ereport(ERROR,
    2295             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2296             :                  errmsg("language \"%s\" is not trusted",
    2297             :                         NameStr(pg_language_tuple->lanname)),
    2298             :                  errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
    2299             :                            "because only superusers can use untrusted languages.")));
    2300          36 : }
    2301             : 
    2302             : static void
    2303          74 : ExecGrant_Largeobject(InternalGrant *istmt)
    2304             : {
    2305             :     Relation    relation;
    2306             :     ListCell   *cell;
    2307             : 
    2308          74 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2309          44 :         istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
    2310             : 
    2311          74 :     relation = table_open(LargeObjectMetadataRelationId,
    2312             :                           RowExclusiveLock);
    2313             : 
    2314         154 :     foreach(cell, istmt->objects)
    2315             :     {
    2316          80 :         Oid         loid = lfirst_oid(cell);
    2317             :         Form_pg_largeobject_metadata form_lo_meta;
    2318             :         char        loname[NAMEDATALEN];
    2319             :         Datum       aclDatum;
    2320             :         bool        isNull;
    2321             :         AclMode     avail_goptions;
    2322             :         AclMode     this_privileges;
    2323             :         Acl        *old_acl;
    2324             :         Acl        *new_acl;
    2325             :         Oid         grantorId;
    2326             :         Oid         ownerId;
    2327             :         HeapTuple   newtuple;
    2328          80 :         Datum       values[Natts_pg_largeobject_metadata] = {0};
    2329          80 :         bool        nulls[Natts_pg_largeobject_metadata] = {0};
    2330          80 :         bool        replaces[Natts_pg_largeobject_metadata] = {0};
    2331             :         int         noldmembers;
    2332             :         int         nnewmembers;
    2333             :         Oid        *oldmembers;
    2334             :         Oid        *newmembers;
    2335             :         ScanKeyData entry[1];
    2336             :         SysScanDesc scan;
    2337             :         HeapTuple   tuple;
    2338             : 
    2339             :         /* There's no syscache for pg_largeobject_metadata */
    2340          80 :         ScanKeyInit(&entry[0],
    2341             :                     Anum_pg_largeobject_metadata_oid,
    2342             :                     BTEqualStrategyNumber, F_OIDEQ,
    2343             :                     ObjectIdGetDatum(loid));
    2344             : 
    2345          80 :         scan = systable_beginscan(relation,
    2346             :                                   LargeObjectMetadataOidIndexId, true,
    2347             :                                   NULL, 1, entry);
    2348             : 
    2349          80 :         tuple = systable_getnext(scan);
    2350          80 :         if (!HeapTupleIsValid(tuple))
    2351           0 :             elog(ERROR, "could not find tuple for large object %u", loid);
    2352             : 
    2353          80 :         form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
    2354             : 
    2355             :         /*
    2356             :          * Get owner ID and working copy of existing ACL. If there's no ACL,
    2357             :          * substitute the proper default.
    2358             :          */
    2359          80 :         ownerId = form_lo_meta->lomowner;
    2360          80 :         aclDatum = heap_getattr(tuple,
    2361             :                                 Anum_pg_largeobject_metadata_lomacl,
    2362             :                                 RelationGetDescr(relation), &isNull);
    2363          80 :         if (isNull)
    2364             :         {
    2365          44 :             old_acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    2366             :             /* There are no old member roles according to the catalogs */
    2367          44 :             noldmembers = 0;
    2368          44 :             oldmembers = NULL;
    2369             :         }
    2370             :         else
    2371             :         {
    2372          36 :             old_acl = DatumGetAclPCopy(aclDatum);
    2373             :             /* Get the roles mentioned in the existing ACL */
    2374          36 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2375             :         }
    2376             : 
    2377             :         /* Determine ID to do the grant as, and available grant options */
    2378          80 :         select_best_grantor(GetUserId(), istmt->privileges,
    2379             :                             old_acl, ownerId,
    2380             :                             &grantorId, &avail_goptions);
    2381             : 
    2382             :         /*
    2383             :          * Restrict the privileges to what we can actually grant, and emit the
    2384             :          * standards-mandated warning and error messages.
    2385             :          */
    2386          80 :         snprintf(loname, sizeof(loname), "large object %u", loid);
    2387             :         this_privileges =
    2388          80 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2389          80 :                                      istmt->all_privs, istmt->privileges,
    2390             :                                      loid, grantorId, OBJECT_LARGEOBJECT,
    2391             :                                      loname, 0, NULL);
    2392             : 
    2393             :         /*
    2394             :          * Generate new ACL.
    2395             :          */
    2396          80 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2397          80 :                                        istmt->grant_option, istmt->behavior,
    2398             :                                        istmt->grantees, this_privileges,
    2399             :                                        grantorId, ownerId);
    2400             : 
    2401             :         /*
    2402             :          * We need the members of both old and new ACLs so we can correct the
    2403             :          * shared dependency information.
    2404             :          */
    2405          80 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2406             : 
    2407             :         /* finished building new ACL value, now insert it */
    2408          80 :         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
    2409             :         values[Anum_pg_largeobject_metadata_lomacl - 1]
    2410          80 :             = PointerGetDatum(new_acl);
    2411             : 
    2412          80 :         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2413             :                                      values, nulls, replaces);
    2414             : 
    2415          80 :         CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2416             : 
    2417             :         /* Update initial privileges for extensions */
    2418          80 :         recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl);
    2419             : 
    2420             :         /* Update the shared dependency ACL info */
    2421          80 :         updateAclDependencies(LargeObjectRelationId,
    2422             :                               form_lo_meta->oid, 0,
    2423             :                               ownerId,
    2424             :                               noldmembers, oldmembers,
    2425             :                               nnewmembers, newmembers);
    2426             : 
    2427          80 :         systable_endscan(scan);
    2428             : 
    2429          80 :         pfree(new_acl);
    2430             : 
    2431             :         /* prevent error when processing duplicate objects */
    2432          80 :         CommandCounterIncrement();
    2433             :     }
    2434             : 
    2435          74 :     table_close(relation, RowExclusiveLock);
    2436          74 : }
    2437             : 
    2438             : static void
    2439         144 : ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
    2440             : {
    2441             :     Form_pg_type pg_type_tuple;
    2442             : 
    2443         144 :     pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
    2444             : 
    2445             :     /* Disallow GRANT on dependent types */
    2446         144 :     if (IsTrueArrayType(pg_type_tuple))
    2447           6 :         ereport(ERROR,
    2448             :                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2449             :                  errmsg("cannot set privileges of array types"),
    2450             :                  errhint("Set the privileges of the element type instead.")));
    2451         138 :     if (pg_type_tuple->typtype == TYPTYPE_MULTIRANGE)
    2452           6 :         ereport(ERROR,
    2453             :                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
    2454             :                  errmsg("cannot set privileges of multirange types"),
    2455             :                  errhint("Set the privileges of the range type instead.")));
    2456             : 
    2457             :     /* Used GRANT DOMAIN on a non-domain? */
    2458         132 :     if (istmt->objtype == OBJECT_DOMAIN &&
    2459          26 :         pg_type_tuple->typtype != TYPTYPE_DOMAIN)
    2460           6 :         ereport(ERROR,
    2461             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2462             :                  errmsg("\"%s\" is not a domain",
    2463             :                         NameStr(pg_type_tuple->typname))));
    2464         126 : }
    2465             : 
    2466             : static void
    2467          96 : ExecGrant_Parameter(InternalGrant *istmt)
    2468             : {
    2469             :     Relation    relation;
    2470             :     ListCell   *cell;
    2471             : 
    2472          96 :     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
    2473          42 :         istmt->privileges = ACL_ALL_RIGHTS_PARAMETER_ACL;
    2474             : 
    2475          96 :     relation = table_open(ParameterAclRelationId, RowExclusiveLock);
    2476             : 
    2477         230 :     foreach(cell, istmt->objects)
    2478             :     {
    2479         134 :         Oid         parameterId = lfirst_oid(cell);
    2480             :         Datum       nameDatum;
    2481             :         const char *parname;
    2482             :         Datum       aclDatum;
    2483             :         bool        isNull;
    2484             :         AclMode     avail_goptions;
    2485             :         AclMode     this_privileges;
    2486             :         Acl        *old_acl;
    2487             :         Acl        *new_acl;
    2488             :         Oid         grantorId;
    2489             :         Oid         ownerId;
    2490             :         HeapTuple   tuple;
    2491             :         int         noldmembers;
    2492             :         int         nnewmembers;
    2493             :         Oid        *oldmembers;
    2494             :         Oid        *newmembers;
    2495             : 
    2496         134 :         tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(parameterId));
    2497         134 :         if (!HeapTupleIsValid(tuple))
    2498           0 :             elog(ERROR, "cache lookup failed for parameter ACL %u",
    2499             :                  parameterId);
    2500             : 
    2501             :         /* We'll need the GUC's name */
    2502         134 :         nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tuple,
    2503             :                                            Anum_pg_parameter_acl_parname);
    2504         134 :         parname = TextDatumGetCString(nameDatum);
    2505             : 
    2506             :         /* Treat all parameters as belonging to the bootstrap superuser. */
    2507         134 :         ownerId = BOOTSTRAP_SUPERUSERID;
    2508             : 
    2509             :         /*
    2510             :          * Get working copy of existing ACL. If there's no ACL, substitute the
    2511             :          * proper default.
    2512             :          */
    2513         134 :         aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    2514             :                                    Anum_pg_parameter_acl_paracl,
    2515             :                                    &isNull);
    2516             : 
    2517         134 :         if (isNull)
    2518             :         {
    2519          66 :             old_acl = acldefault(istmt->objtype, ownerId);
    2520             :             /* There are no old member roles according to the catalogs */
    2521          66 :             noldmembers = 0;
    2522          66 :             oldmembers = NULL;
    2523             :         }
    2524             :         else
    2525             :         {
    2526          68 :             old_acl = DatumGetAclPCopy(aclDatum);
    2527             :             /* Get the roles mentioned in the existing ACL */
    2528          68 :             noldmembers = aclmembers(old_acl, &oldmembers);
    2529             :         }
    2530             : 
    2531             :         /* Determine ID to do the grant as, and available grant options */
    2532         134 :         select_best_grantor(GetUserId(), istmt->privileges,
    2533             :                             old_acl, ownerId,
    2534             :                             &grantorId, &avail_goptions);
    2535             : 
    2536             :         /*
    2537             :          * Restrict the privileges to what we can actually grant, and emit the
    2538             :          * standards-mandated warning and error messages.
    2539             :          */
    2540             :         this_privileges =
    2541         134 :             restrict_and_check_grant(istmt->is_grant, avail_goptions,
    2542         134 :                                      istmt->all_privs, istmt->privileges,
    2543             :                                      parameterId, grantorId,
    2544             :                                      OBJECT_PARAMETER_ACL,
    2545             :                                      parname,
    2546             :                                      0, NULL);
    2547             : 
    2548             :         /*
    2549             :          * Generate new ACL.
    2550             :          */
    2551         134 :         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
    2552         134 :                                        istmt->grant_option, istmt->behavior,
    2553             :                                        istmt->grantees, this_privileges,
    2554             :                                        grantorId, ownerId);
    2555             : 
    2556             :         /*
    2557             :          * We need the members of both old and new ACLs so we can correct the
    2558             :          * shared dependency information.
    2559             :          */
    2560         134 :         nnewmembers = aclmembers(new_acl, &newmembers);
    2561             : 
    2562             :         /*
    2563             :          * If the new ACL is equal to the default, we don't need the catalog
    2564             :          * entry any longer.  Delete it rather than updating it, to avoid
    2565             :          * leaving a degenerate entry.
    2566             :          */
    2567         134 :         if (aclequal(new_acl, acldefault(istmt->objtype, ownerId)))
    2568             :         {
    2569          58 :             CatalogTupleDelete(relation, &tuple->t_self);
    2570             :         }
    2571             :         else
    2572             :         {
    2573             :             /* finished building new ACL value, now insert it */
    2574             :             HeapTuple   newtuple;
    2575          76 :             Datum       values[Natts_pg_parameter_acl] = {0};
    2576          76 :             bool        nulls[Natts_pg_parameter_acl] = {0};
    2577          76 :             bool        replaces[Natts_pg_parameter_acl] = {0};
    2578             : 
    2579          76 :             replaces[Anum_pg_parameter_acl_paracl - 1] = true;
    2580          76 :             values[Anum_pg_parameter_acl_paracl - 1] = PointerGetDatum(new_acl);
    2581             : 
    2582          76 :             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
    2583             :                                          values, nulls, replaces);
    2584             : 
    2585          76 :             CatalogTupleUpdate(relation, &newtuple->t_self, newtuple);
    2586             :         }
    2587             : 
    2588             :         /* Update initial privileges for extensions */
    2589         134 :         recordExtensionInitPriv(parameterId, ParameterAclRelationId, 0,
    2590             :                                 new_acl);
    2591             : 
    2592             :         /* Update the shared dependency ACL info */
    2593         134 :         updateAclDependencies(ParameterAclRelationId, parameterId, 0,
    2594             :                               ownerId,
    2595             :                               noldmembers, oldmembers,
    2596             :                               nnewmembers, newmembers);
    2597             : 
    2598         134 :         ReleaseSysCache(tuple);
    2599         134 :         pfree(new_acl);
    2600             : 
    2601             :         /* prevent error when processing duplicate objects */
    2602         134 :         CommandCounterIncrement();
    2603             :     }
    2604             : 
    2605          96 :     table_close(relation, RowExclusiveLock);
    2606          96 : }
    2607             : 
    2608             : 
    2609             : static AclMode
    2610       22666 : string_to_privilege(const char *privname)
    2611             : {
    2612       22666 :     if (strcmp(privname, "insert") == 0)
    2613         222 :         return ACL_INSERT;
    2614       22444 :     if (strcmp(privname, "select") == 0)
    2615       14740 :         return ACL_SELECT;
    2616        7704 :     if (strcmp(privname, "update") == 0)
    2617         322 :         return ACL_UPDATE;
    2618        7382 :     if (strcmp(privname, "delete") == 0)
    2619         114 :         return ACL_DELETE;
    2620        7268 :     if (strcmp(privname, "truncate") == 0)
    2621          34 :         return ACL_TRUNCATE;
    2622        7234 :     if (strcmp(privname, "references") == 0)
    2623          14 :         return ACL_REFERENCES;
    2624        7220 :     if (strcmp(privname, "trigger") == 0)
    2625           8 :         return ACL_TRIGGER;
    2626        7212 :     if (strcmp(privname, "execute") == 0)
    2627        6076 :         return ACL_EXECUTE;
    2628        1136 :     if (strcmp(privname, "usage") == 0)
    2629         608 :         return ACL_USAGE;
    2630         528 :     if (strcmp(privname, "create") == 0)
    2631         250 :         return ACL_CREATE;
    2632         278 :     if (strcmp(privname, "temporary") == 0)
    2633         158 :         return ACL_CREATE_TEMP;
    2634         120 :     if (strcmp(privname, "temp") == 0)
    2635           2 :         return ACL_CREATE_TEMP;
    2636         118 :     if (strcmp(privname, "connect") == 0)
    2637          14 :         return ACL_CONNECT;
    2638         104 :     if (strcmp(privname, "set") == 0)
    2639          48 :         return ACL_SET;
    2640          56 :     if (strcmp(privname, "alter system") == 0)
    2641          24 :         return ACL_ALTER_SYSTEM;
    2642          32 :     if (strcmp(privname, "maintain") == 0)
    2643          32 :         return ACL_MAINTAIN;
    2644           0 :     if (strcmp(privname, "rule") == 0)
    2645           0 :         return 0;               /* ignore old RULE privileges */
    2646           0 :     ereport(ERROR,
    2647             :             (errcode(ERRCODE_SYNTAX_ERROR),
    2648             :              errmsg("unrecognized privilege type \"%s\"", privname)));
    2649             :     return 0;                   /* appease compiler */
    2650             : }
    2651             : 
    2652             : static const char *
    2653          24 : privilege_to_string(AclMode privilege)
    2654             : {
    2655          24 :     switch (privilege)
    2656             :     {
    2657           6 :         case ACL_INSERT:
    2658           6 :             return "INSERT";
    2659           0 :         case ACL_SELECT:
    2660           0 :             return "SELECT";
    2661           0 :         case ACL_UPDATE:
    2662           0 :             return "UPDATE";
    2663           0 :         case ACL_DELETE:
    2664           0 :             return "DELETE";
    2665           0 :         case ACL_TRUNCATE:
    2666           0 :             return "TRUNCATE";
    2667           0 :         case ACL_REFERENCES:
    2668           0 :             return "REFERENCES";
    2669           0 :         case ACL_TRIGGER:
    2670           0 :             return "TRIGGER";
    2671           0 :         case ACL_EXECUTE:
    2672           0 :             return "EXECUTE";
    2673          18 :         case ACL_USAGE:
    2674          18 :             return "USAGE";
    2675           0 :         case ACL_CREATE:
    2676           0 :             return "CREATE";
    2677           0 :         case ACL_CREATE_TEMP:
    2678           0 :             return "TEMP";
    2679           0 :         case ACL_CONNECT:
    2680           0 :             return "CONNECT";
    2681           0 :         case ACL_SET:
    2682           0 :             return "SET";
    2683           0 :         case ACL_ALTER_SYSTEM:
    2684           0 :             return "ALTER SYSTEM";
    2685           0 :         case ACL_MAINTAIN:
    2686           0 :             return "MAINTAIN";
    2687           0 :         default:
    2688           0 :             elog(ERROR, "unrecognized privilege: %d", (int) privilege);
    2689             :     }
    2690             :     return NULL;                /* appease compiler */
    2691             : }
    2692             : 
    2693             : /*
    2694             :  * Standardized reporting of aclcheck permissions failures.
    2695             :  *
    2696             :  * Note: we do not double-quote the %s's below, because many callers
    2697             :  * supply strings that might be already quoted.
    2698             :  */
    2699             : void
    2700        2638 : aclcheck_error(AclResult aclerr, ObjectType objtype,
    2701             :                const char *objectname)
    2702             : {
    2703        2638 :     switch (aclerr)
    2704             :     {
    2705           0 :         case ACLCHECK_OK:
    2706             :             /* no error, so return to caller */
    2707           0 :             break;
    2708        2094 :         case ACLCHECK_NO_PRIV:
    2709             :             {
    2710        2094 :                 const char *msg = "???";
    2711             : 
    2712             :                 switch (objtype)
    2713             :                 {
    2714           6 :                     case OBJECT_AGGREGATE:
    2715           6 :                         msg = gettext_noop("permission denied for aggregate %s");
    2716           6 :                         break;
    2717           0 :                     case OBJECT_COLLATION:
    2718           0 :                         msg = gettext_noop("permission denied for collation %s");
    2719           0 :                         break;
    2720           0 :                     case OBJECT_COLUMN:
    2721           0 :                         msg = gettext_noop("permission denied for column %s");
    2722           0 :                         break;
    2723           0 :                     case OBJECT_CONVERSION:
    2724           0 :                         msg = gettext_noop("permission denied for conversion %s");
    2725           0 :                         break;
    2726          18 :                     case OBJECT_DATABASE:
    2727          18 :                         msg = gettext_noop("permission denied for database %s");
    2728          18 :                         break;
    2729           0 :                     case OBJECT_DOMAIN:
    2730           0 :                         msg = gettext_noop("permission denied for domain %s");
    2731           0 :                         break;
    2732           0 :                     case OBJECT_EVENT_TRIGGER:
    2733           0 :                         msg = gettext_noop("permission denied for event trigger %s");
    2734           0 :                         break;
    2735           0 :                     case OBJECT_EXTENSION:
    2736           0 :                         msg = gettext_noop("permission denied for extension %s");
    2737           0 :                         break;
    2738          44 :                     case OBJECT_FDW:
    2739          44 :                         msg = gettext_noop("permission denied for foreign-data wrapper %s");
    2740          44 :                         break;
    2741          20 :                     case OBJECT_FOREIGN_SERVER:
    2742          20 :                         msg = gettext_noop("permission denied for foreign server %s");
    2743          20 :                         break;
    2744           2 :                     case OBJECT_FOREIGN_TABLE:
    2745           2 :                         msg = gettext_noop("permission denied for foreign table %s");
    2746           2 :                         break;
    2747          90 :                     case OBJECT_FUNCTION:
    2748          90 :                         msg = gettext_noop("permission denied for function %s");
    2749          90 :                         break;
    2750          12 :                     case OBJECT_INDEX:
    2751          12 :                         msg = gettext_noop("permission denied for index %s");
    2752          12 :                         break;
    2753           8 :                     case OBJECT_LANGUAGE:
    2754           8 :                         msg = gettext_noop("permission denied for language %s");
    2755           8 :                         break;
    2756           0 :                     case OBJECT_LARGEOBJECT:
    2757           0 :                         msg = gettext_noop("permission denied for large object %s");
    2758           0 :                         break;
    2759           6 :                     case OBJECT_MATVIEW:
    2760           6 :                         msg = gettext_noop("permission denied for materialized view %s");
    2761           6 :                         break;
    2762           0 :                     case OBJECT_OPCLASS:
    2763           0 :                         msg = gettext_noop("permission denied for operator class %s");
    2764           0 :                         break;
    2765           0 :                     case OBJECT_OPERATOR:
    2766           0 :                         msg = gettext_noop("permission denied for operator %s");
    2767           0 :                         break;
    2768           0 :                     case OBJECT_OPFAMILY:
    2769           0 :                         msg = gettext_noop("permission denied for operator family %s");
    2770           0 :                         break;
    2771           0 :                     case OBJECT_PARAMETER_ACL:
    2772           0 :                         msg = gettext_noop("permission denied for parameter %s");
    2773           0 :                         break;
    2774           0 :                     case OBJECT_POLICY:
    2775           0 :                         msg = gettext_noop("permission denied for policy %s");
    2776           0 :                         break;
    2777          12 :                     case OBJECT_PROCEDURE:
    2778          12 :                         msg = gettext_noop("permission denied for procedure %s");
    2779          12 :                         break;
    2780           0 :                     case OBJECT_PUBLICATION:
    2781           0 :                         msg = gettext_noop("permission denied for publication %s");
    2782           0 :                         break;
    2783           0 :                     case OBJECT_ROUTINE:
    2784           0 :                         msg = gettext_noop("permission denied for routine %s");
    2785           0 :                         break;
    2786          14 :                     case OBJECT_SCHEMA:
    2787          14 :                         msg = gettext_noop("permission denied for schema %s");
    2788          14 :                         break;
    2789           0 :                     case OBJECT_SEQUENCE:
    2790           0 :                         msg = gettext_noop("permission denied for sequence %s");
    2791           0 :                         break;
    2792           0 :                     case OBJECT_STATISTIC_EXT:
    2793           0 :                         msg = gettext_noop("permission denied for statistics object %s");
    2794           0 :                         break;
    2795           0 :                     case OBJECT_SUBSCRIPTION:
    2796           0 :                         msg = gettext_noop("permission denied for subscription %s");
    2797           0 :                         break;
    2798        1338 :                     case OBJECT_TABLE:
    2799        1338 :                         msg = gettext_noop("permission denied for table %s");
    2800        1338 :                         break;
    2801          18 :                     case OBJECT_TABLESPACE:
    2802          18 :                         msg = gettext_noop("permission denied for tablespace %s");
    2803          18 :                         break;
    2804           0 :                     case OBJECT_TSCONFIGURATION:
    2805           0 :                         msg = gettext_noop("permission denied for text search configuration %s");
    2806           0 :                         break;
    2807           0 :                     case OBJECT_TSDICTIONARY:
    2808           0 :                         msg = gettext_noop("permission denied for text search dictionary %s");
    2809           0 :                         break;
    2810         120 :                     case OBJECT_TYPE:
    2811         120 :                         msg = gettext_noop("permission denied for type %s");
    2812         120 :                         break;
    2813         386 :                     case OBJECT_VIEW:
    2814         386 :                         msg = gettext_noop("permission denied for view %s");
    2815         386 :                         break;
    2816             :                         /* these currently aren't used */
    2817           0 :                     case OBJECT_ACCESS_METHOD:
    2818             :                     case OBJECT_AMOP:
    2819             :                     case OBJECT_AMPROC:
    2820             :                     case OBJECT_ATTRIBUTE:
    2821             :                     case OBJECT_CAST:
    2822             :                     case OBJECT_DEFAULT:
    2823             :                     case OBJECT_DEFACL:
    2824             :                     case OBJECT_DOMCONSTRAINT:
    2825             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2826             :                     case OBJECT_PUBLICATION_REL:
    2827             :                     case OBJECT_ROLE:
    2828             :                     case OBJECT_RULE:
    2829             :                     case OBJECT_TABCONSTRAINT:
    2830             :                     case OBJECT_TRANSFORM:
    2831             :                     case OBJECT_TRIGGER:
    2832             :                     case OBJECT_TSPARSER:
    2833             :                     case OBJECT_TSTEMPLATE:
    2834             :                     case OBJECT_USER_MAPPING:
    2835           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2836             :                 }
    2837             : 
    2838        2094 :                 ereport(ERROR,
    2839             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2840             :                          errmsg(msg, objectname)));
    2841             :                 break;
    2842             :             }
    2843         544 :         case ACLCHECK_NOT_OWNER:
    2844             :             {
    2845         544 :                 const char *msg = "???";
    2846             : 
    2847             :                 switch (objtype)
    2848             :                 {
    2849           6 :                     case OBJECT_AGGREGATE:
    2850           6 :                         msg = gettext_noop("must be owner of aggregate %s");
    2851           6 :                         break;
    2852           0 :                     case OBJECT_COLLATION:
    2853           0 :                         msg = gettext_noop("must be owner of collation %s");
    2854           0 :                         break;
    2855          18 :                     case OBJECT_CONVERSION:
    2856          18 :                         msg = gettext_noop("must be owner of conversion %s");
    2857          18 :                         break;
    2858           0 :                     case OBJECT_DATABASE:
    2859           0 :                         msg = gettext_noop("must be owner of database %s");
    2860           0 :                         break;
    2861           0 :                     case OBJECT_DOMAIN:
    2862           0 :                         msg = gettext_noop("must be owner of domain %s");
    2863           0 :                         break;
    2864           0 :                     case OBJECT_EVENT_TRIGGER:
    2865           0 :                         msg = gettext_noop("must be owner of event trigger %s");
    2866           0 :                         break;
    2867           0 :                     case OBJECT_EXTENSION:
    2868           0 :                         msg = gettext_noop("must be owner of extension %s");
    2869           0 :                         break;
    2870          18 :                     case OBJECT_FDW:
    2871          18 :                         msg = gettext_noop("must be owner of foreign-data wrapper %s");
    2872          18 :                         break;
    2873         114 :                     case OBJECT_FOREIGN_SERVER:
    2874         114 :                         msg = gettext_noop("must be owner of foreign server %s");
    2875         114 :                         break;
    2876           0 :                     case OBJECT_FOREIGN_TABLE:
    2877           0 :                         msg = gettext_noop("must be owner of foreign table %s");
    2878           0 :                         break;
    2879          42 :                     case OBJECT_FUNCTION:
    2880          42 :                         msg = gettext_noop("must be owner of function %s");
    2881          42 :                         break;
    2882          24 :                     case OBJECT_INDEX:
    2883          24 :                         msg = gettext_noop("must be owner of index %s");
    2884          24 :                         break;
    2885          12 :                     case OBJECT_LANGUAGE:
    2886          12 :                         msg = gettext_noop("must be owner of language %s");
    2887          12 :                         break;
    2888           0 :                     case OBJECT_LARGEOBJECT:
    2889           0 :                         msg = gettext_noop("must be owner of large object %s");
    2890           0 :                         break;
    2891           0 :                     case OBJECT_MATVIEW:
    2892           0 :                         msg = gettext_noop("must be owner of materialized view %s");
    2893           0 :                         break;
    2894          18 :                     case OBJECT_OPCLASS:
    2895          18 :                         msg = gettext_noop("must be owner of operator class %s");
    2896          18 :                         break;
    2897          18 :                     case OBJECT_OPERATOR:
    2898          18 :                         msg = gettext_noop("must be owner of operator %s");
    2899          18 :                         break;
    2900          18 :                     case OBJECT_OPFAMILY:
    2901          18 :                         msg = gettext_noop("must be owner of operator family %s");
    2902          18 :                         break;
    2903           6 :                     case OBJECT_PROCEDURE:
    2904           6 :                         msg = gettext_noop("must be owner of procedure %s");
    2905           6 :                         break;
    2906           6 :                     case OBJECT_PUBLICATION:
    2907           6 :                         msg = gettext_noop("must be owner of publication %s");
    2908           6 :                         break;
    2909           0 :                     case OBJECT_ROUTINE:
    2910           0 :                         msg = gettext_noop("must be owner of routine %s");
    2911           0 :                         break;
    2912           6 :                     case OBJECT_SEQUENCE:
    2913           6 :                         msg = gettext_noop("must be owner of sequence %s");
    2914           6 :                         break;
    2915           6 :                     case OBJECT_SUBSCRIPTION:
    2916           6 :                         msg = gettext_noop("must be owner of subscription %s");
    2917           6 :                         break;
    2918         100 :                     case OBJECT_TABLE:
    2919         100 :                         msg = gettext_noop("must be owner of table %s");
    2920         100 :                         break;
    2921           6 :                     case OBJECT_TYPE:
    2922           6 :                         msg = gettext_noop("must be owner of type %s");
    2923           6 :                         break;
    2924          18 :                     case OBJECT_VIEW:
    2925          18 :                         msg = gettext_noop("must be owner of view %s");
    2926          18 :                         break;
    2927          18 :                     case OBJECT_SCHEMA:
    2928          18 :                         msg = gettext_noop("must be owner of schema %s");
    2929          18 :                         break;
    2930          36 :                     case OBJECT_STATISTIC_EXT:
    2931          36 :                         msg = gettext_noop("must be owner of statistics object %s");
    2932          36 :                         break;
    2933           0 :                     case OBJECT_TABLESPACE:
    2934           0 :                         msg = gettext_noop("must be owner of tablespace %s");
    2935           0 :                         break;
    2936          18 :                     case OBJECT_TSCONFIGURATION:
    2937          18 :                         msg = gettext_noop("must be owner of text search configuration %s");
    2938          18 :                         break;
    2939          18 :                     case OBJECT_TSDICTIONARY:
    2940          18 :                         msg = gettext_noop("must be owner of text search dictionary %s");
    2941          18 :                         break;
    2942             : 
    2943             :                         /*
    2944             :                          * Special cases: For these, the error message talks
    2945             :                          * about "relation", because that's where the
    2946             :                          * ownership is attached.  See also
    2947             :                          * check_object_ownership().
    2948             :                          */
    2949          18 :                     case OBJECT_COLUMN:
    2950             :                     case OBJECT_POLICY:
    2951             :                     case OBJECT_RULE:
    2952             :                     case OBJECT_TABCONSTRAINT:
    2953             :                     case OBJECT_TRIGGER:
    2954          18 :                         msg = gettext_noop("must be owner of relation %s");
    2955          18 :                         break;
    2956             :                         /* these currently aren't used */
    2957           0 :                     case OBJECT_ACCESS_METHOD:
    2958             :                     case OBJECT_AMOP:
    2959             :                     case OBJECT_AMPROC:
    2960             :                     case OBJECT_ATTRIBUTE:
    2961             :                     case OBJECT_CAST:
    2962             :                     case OBJECT_DEFAULT:
    2963             :                     case OBJECT_DEFACL:
    2964             :                     case OBJECT_DOMCONSTRAINT:
    2965             :                     case OBJECT_PARAMETER_ACL:
    2966             :                     case OBJECT_PUBLICATION_NAMESPACE:
    2967             :                     case OBJECT_PUBLICATION_REL:
    2968             :                     case OBJECT_ROLE:
    2969             :                     case OBJECT_TRANSFORM:
    2970             :                     case OBJECT_TSPARSER:
    2971             :                     case OBJECT_TSTEMPLATE:
    2972             :                     case OBJECT_USER_MAPPING:
    2973           0 :                         elog(ERROR, "unsupported object type: %d", objtype);
    2974             :                 }
    2975             : 
    2976         544 :                 ereport(ERROR,
    2977             :                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    2978             :                          errmsg(msg, objectname)));
    2979             :                 break;
    2980             :             }
    2981           0 :         default:
    2982           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    2983             :             break;
    2984             :     }
    2985           0 : }
    2986             : 
    2987             : 
    2988             : void
    2989           0 : aclcheck_error_col(AclResult aclerr, ObjectType objtype,
    2990             :                    const char *objectname, const char *colname)
    2991             : {
    2992           0 :     switch (aclerr)
    2993             :     {
    2994           0 :         case ACLCHECK_OK:
    2995             :             /* no error, so return to caller */
    2996           0 :             break;
    2997           0 :         case ACLCHECK_NO_PRIV:
    2998           0 :             ereport(ERROR,
    2999             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
    3000             :                      errmsg("permission denied for column \"%s\" of relation \"%s\"",
    3001             :                             colname, objectname)));
    3002             :             break;
    3003           0 :         case ACLCHECK_NOT_OWNER:
    3004             :             /* relation msg is OK since columns don't have separate owners */
    3005           0 :             aclcheck_error(aclerr, objtype, objectname);
    3006           0 :             break;
    3007           0 :         default:
    3008           0 :             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
    3009             :             break;
    3010             :     }
    3011           0 : }
    3012             : 
    3013             : 
    3014             : /*
    3015             :  * Special common handling for types: use element type instead of array type,
    3016             :  * and format nicely
    3017             :  */
    3018             : void
    3019         120 : aclcheck_error_type(AclResult aclerr, Oid typeOid)
    3020             : {
    3021         120 :     Oid         element_type = get_element_type(typeOid);
    3022             : 
    3023         120 :     aclcheck_error(aclerr, OBJECT_TYPE, format_type_be(element_type ? element_type : typeOid));
    3024           0 : }
    3025             : 
    3026             : 
    3027             : /*
    3028             :  * Relay for the various pg_*_mask routines depending on object kind
    3029             :  */
    3030             : static AclMode
    3031          66 : pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
    3032             :            AclMode mask, AclMaskHow how)
    3033             : {
    3034          66 :     switch (objtype)
    3035             :     {
    3036           0 :         case OBJECT_COLUMN:
    3037             :             return
    3038           0 :                 pg_class_aclmask(object_oid, roleid, mask, how) |
    3039           0 :                 pg_attribute_aclmask(object_oid, attnum, roleid, mask, how);
    3040          12 :         case OBJECT_TABLE:
    3041             :         case OBJECT_SEQUENCE:
    3042          12 :             return pg_class_aclmask(object_oid, roleid, mask, how);
    3043           0 :         case OBJECT_DATABASE:
    3044           0 :             return object_aclmask(DatabaseRelationId, object_oid, roleid, mask, how);
    3045           0 :         case OBJECT_FUNCTION:
    3046           0 :             return object_aclmask(ProcedureRelationId, object_oid, roleid, mask, how);
    3047           6 :         case OBJECT_LANGUAGE:
    3048           6 :             return object_aclmask(LanguageRelationId, object_oid, roleid, mask, how);
    3049           0 :         case OBJECT_LARGEOBJECT:
    3050           0 :             return pg_largeobject_aclmask_snapshot(object_oid, roleid,
    3051             :                                                    mask, how, NULL);
    3052           0 :         case OBJECT_PARAMETER_ACL:
    3053           0 :             return pg_parameter_acl_aclmask(object_oid, roleid, mask, how);
    3054           0 :         case OBJECT_SCHEMA:
    3055           0 :             return object_aclmask(NamespaceRelationId, object_oid, roleid, mask, how);
    3056           0 :         case OBJECT_STATISTIC_EXT:
    3057           0 :             elog(ERROR, "grantable rights not supported for statistics objects");
    3058             :             /* not reached, but keep compiler quiet */
    3059             :             return ACL_NO_RIGHTS;
    3060           0 :         case OBJECT_TABLESPACE:
    3061           0 :             return object_aclmask(TableSpaceRelationId, object_oid, roleid, mask, how);
    3062          18 :         case OBJECT_FDW:
    3063          18 :             return object_aclmask(ForeignDataWrapperRelationId, object_oid, roleid, mask, how);
    3064          18 :         case OBJECT_FOREIGN_SERVER:
    3065          18 :             return object_aclmask(ForeignServerRelationId, object_oid, roleid, mask, how);
    3066           0 :         case OBJECT_EVENT_TRIGGER:
    3067           0 :             elog(ERROR, "grantable rights not supported for event triggers");
    3068             :             /* not reached, but keep compiler quiet */
    3069             :             return ACL_NO_RIGHTS;
    3070          12 :         case OBJECT_TYPE:
    3071          12 :             return object_aclmask(TypeRelationId, object_oid, roleid, mask, how);
    3072           0 :         default:
    3073           0 :             elog(ERROR, "unrecognized object type: %d",
    3074             :                  (int) objtype);
    3075             :             /* not reached, but keep compiler quiet */
    3076             :             return ACL_NO_RIGHTS;
    3077             :     }
    3078             : }
    3079             : 
    3080             : 
    3081             : /* ****************************************************************
    3082             :  * Exported routines for examining a user's privileges for various objects
    3083             :  *
    3084             :  * See aclmask() for a description of the common API for these functions.
    3085             :  *
    3086             :  * Note: we give lookup failure the full ereport treatment because the
    3087             :  * has_xxx_privilege() family of functions allow users to pass any random
    3088             :  * OID to these functions.
    3089             :  * ****************************************************************
    3090             :  */
    3091             : 
    3092             : /*
    3093             :  * Generic routine for examining a user's privileges for an object
    3094             :  */
    3095             : static AclMode
    3096          54 : object_aclmask(Oid classid, Oid objectid, Oid roleid,
    3097             :                AclMode mask, AclMaskHow how)
    3098             : {
    3099          54 :     return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
    3100             : }
    3101             : 
    3102             : /*
    3103             :  * Generic routine for examining a user's privileges for an object,
    3104             :  * with is_missing
    3105             :  */
    3106             : static AclMode
    3107     2832646 : object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
    3108             :                    AclMode mask, AclMaskHow how,
    3109             :                    bool *is_missing)
    3110             : {
    3111             :     int         cacheid;
    3112             :     AclMode     result;
    3113             :     HeapTuple   tuple;
    3114             :     Datum       aclDatum;
    3115             :     bool        isNull;
    3116             :     Acl        *acl;
    3117             :     Oid         ownerId;
    3118             : 
    3119             :     /* Special cases */
    3120     2832646 :     switch (classid)
    3121             :     {
    3122      797266 :         case NamespaceRelationId:
    3123      797266 :             return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
    3124             :                                             is_missing);
    3125      290314 :         case TypeRelationId:
    3126      290314 :             return pg_type_aclmask_ext(objectid, roleid, mask, how,
    3127             :                                        is_missing);
    3128             :     }
    3129             : 
    3130             :     /* Even more special cases */
    3131             :     Assert(classid != RelationRelationId);  /* should use pg_class_acl* */
    3132             :     Assert(classid != LargeObjectMetadataRelationId);   /* should use
    3133             :                                                          * pg_largeobject_acl* */
    3134             : 
    3135             :     /* Superusers bypass all permission checking. */
    3136     1745066 :     if (superuser_arg(roleid))
    3137     1706868 :         return mask;
    3138             : 
    3139             :     /*
    3140             :      * Get the object's ACL from its catalog
    3141             :      */
    3142             : 
    3143       38198 :     cacheid = get_object_catcache_oid(classid);
    3144             : 
    3145       38198 :     tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    3146       38198 :     if (!HeapTupleIsValid(tuple))
    3147             :     {
    3148           0 :         if (is_missing != NULL)
    3149             :         {
    3150             :             /* return "no privileges" instead of throwing an error */
    3151           0 :             *is_missing = true;
    3152           0 :             return 0;
    3153             :         }
    3154             :         else
    3155           0 :             ereport(ERROR,
    3156             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    3157             :                      errmsg("%s with OID %u does not exist",
    3158             :                             get_object_class_descr(classid), objectid)));
    3159             :     }
    3160             : 
    3161       38198 :     ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    3162             :                                                       tuple,
    3163       38198 :                                                       get_object_attnum_owner(classid)));
    3164             : 
    3165       38198 :     aclDatum = SysCacheGetAttr(cacheid, tuple, get_object_attnum_acl(classid),
    3166             :                                &isNull);
    3167       38198 :     if (isNull)
    3168             :     {
    3169             :         /* No ACL, so build default ACL */
    3170       35702 :         acl = acldefault(get_object_type(classid, objectid), ownerId);
    3171       35702 :         aclDatum = (Datum) 0;
    3172             :     }
    3173             :     else
    3174             :     {
    3175             :         /* detoast ACL if necessary */
    3176        2496 :         acl = DatumGetAclP(aclDatum);
    3177             :     }
    3178             : 
    3179       38198 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3180             : 
    3181             :     /* if we have a detoasted copy, free it */
    3182       38198 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3183       38198 :         pfree(acl);
    3184             : 
    3185       38198 :     ReleaseSysCache(tuple);
    3186             : 
    3187       38198 :     return result;
    3188             : }
    3189             : 
    3190             : /*
    3191             :  * Routine for examining a user's privileges for a column
    3192             :  *
    3193             :  * Note: this considers only privileges granted specifically on the column.
    3194             :  * It is caller's responsibility to take relation-level privileges into account
    3195             :  * as appropriate.  (For the same reason, we have no special case for
    3196             :  * superuser-ness here.)
    3197             :  */
    3198             : static AclMode
    3199           0 : pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
    3200             :                      AclMode mask, AclMaskHow how)
    3201             : {
    3202           0 :     return pg_attribute_aclmask_ext(table_oid, attnum, roleid,
    3203             :                                     mask, how, NULL);
    3204             : }
    3205             : 
    3206             : /*
    3207             :  * Routine for examining a user's privileges for a column, with is_missing
    3208             :  */
    3209             : static AclMode
    3210        5268 : pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
    3211             :                          AclMode mask, AclMaskHow how, bool *is_missing)
    3212             : {
    3213             :     AclMode     result;
    3214             :     HeapTuple   classTuple;
    3215             :     HeapTuple   attTuple;
    3216             :     Form_pg_class classForm;
    3217             :     Form_pg_attribute attributeForm;
    3218             :     Datum       aclDatum;
    3219             :     bool        isNull;
    3220             :     Acl        *acl;
    3221             :     Oid         ownerId;
    3222             : 
    3223             :     /*
    3224             :      * First, get the column's ACL from its pg_attribute entry
    3225             :      */
    3226        5268 :     attTuple = SearchSysCache2(ATTNUM,
    3227             :                                ObjectIdGetDatum(table_oid),
    3228             :                                Int16GetDatum(attnum));
    3229        5268 :     if (!HeapTupleIsValid(attTuple))
    3230             :     {
    3231          30 :         if (is_missing != NULL)
    3232             :         {
    3233             :             /* return "no privileges" instead of throwing an error */
    3234          30 :             *is_missing = true;
    3235          30 :             return 0;
    3236             :         }
    3237             :         else
    3238           0 :             ereport(ERROR,
    3239             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    3240             :                      errmsg("attribute %d of relation with OID %u does not exist",
    3241             :                             attnum, table_oid)));
    3242             :     }
    3243             : 
    3244        5238 :     attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
    3245             : 
    3246             :     /* Check dropped columns, too */
    3247        5238 :     if (attributeForm->attisdropped)
    3248             :     {
    3249          12 :         if (is_missing != NULL)
    3250             :         {
    3251             :             /* return "no privileges" instead of throwing an error */
    3252          12 :             *is_missing = true;
    3253          12 :             ReleaseSysCache(attTuple);
    3254          12 :             return 0;
    3255             :         }
    3256             :         else
    3257           0 :             ereport(ERROR,
    3258             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    3259             :                      errmsg("attribute %d of relation with OID %u does not exist",
    3260             :                             attnum, table_oid)));
    3261             :     }
    3262             : 
    3263        5226 :     aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
    3264             :                                &isNull);
    3265             : 
    3266             :     /*
    3267             :      * Here we hard-wire knowledge that the default ACL for a column grants no
    3268             :      * privileges, so that we can fall out quickly in the very common case
    3269             :      * where attacl is null.
    3270             :      */
    3271        5226 :     if (isNull)
    3272             :     {
    3273        2732 :         ReleaseSysCache(attTuple);
    3274        2732 :         return 0;
    3275             :     }
    3276             : 
    3277             :     /*
    3278             :      * Must get the relation's ownerId from pg_class.  Since we already found
    3279             :      * a pg_attribute entry, the only likely reason for this to fail is that a
    3280             :      * concurrent DROP of the relation committed since then (which could only
    3281             :      * happen if we don't have lock on the relation).  Treat that similarly to
    3282             :      * not finding the attribute entry.
    3283             :      */
    3284        2494 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3285        2494 :     if (!HeapTupleIsValid(classTuple))
    3286             :     {
    3287           0 :         ReleaseSysCache(attTuple);
    3288           0 :         if (is_missing != NULL)
    3289             :         {
    3290             :             /* return "no privileges" instead of throwing an error */
    3291           0 :             *is_missing = true;
    3292           0 :             return 0;
    3293             :         }
    3294             :         else
    3295           0 :             ereport(ERROR,
    3296             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3297             :                      errmsg("relation with OID %u does not exist",
    3298             :                             table_oid)));
    3299             :     }
    3300        2494 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    3301             : 
    3302        2494 :     ownerId = classForm->relowner;
    3303             : 
    3304        2494 :     ReleaseSysCache(classTuple);
    3305             : 
    3306             :     /* detoast column's ACL if necessary */
    3307        2494 :     acl = DatumGetAclP(aclDatum);
    3308             : 
    3309        2494 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3310             : 
    3311             :     /* if we have a detoasted copy, free it */
    3312        2494 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3313        2494 :         pfree(acl);
    3314             : 
    3315        2494 :     ReleaseSysCache(attTuple);
    3316             : 
    3317        2494 :     return result;
    3318             : }
    3319             : 
    3320             : /*
    3321             :  * Exported routine for examining a user's privileges for a table
    3322             :  */
    3323             : AclMode
    3324      496282 : pg_class_aclmask(Oid table_oid, Oid roleid,
    3325             :                  AclMode mask, AclMaskHow how)
    3326             : {
    3327      496282 :     return pg_class_aclmask_ext(table_oid, roleid, mask, how, NULL);
    3328             : }
    3329             : 
    3330             : /*
    3331             :  * Routine for examining a user's privileges for a table, with is_missing
    3332             :  */
    3333             : static AclMode
    3334     2370990 : pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
    3335             :                      AclMaskHow how, bool *is_missing)
    3336             : {
    3337             :     AclMode     result;
    3338             :     HeapTuple   tuple;
    3339             :     Form_pg_class classForm;
    3340             :     Datum       aclDatum;
    3341             :     bool        isNull;
    3342             :     Acl        *acl;
    3343             :     Oid         ownerId;
    3344             : 
    3345             :     /*
    3346             :      * Must get the relation's tuple from pg_class
    3347             :      */
    3348     2370990 :     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3349     2370990 :     if (!HeapTupleIsValid(tuple))
    3350             :     {
    3351           8 :         if (is_missing != NULL)
    3352             :         {
    3353             :             /* return "no privileges" instead of throwing an error */
    3354           8 :             *is_missing = true;
    3355           8 :             return 0;
    3356             :         }
    3357             :         else
    3358           0 :             ereport(ERROR,
    3359             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3360             :                      errmsg("relation with OID %u does not exist",
    3361             :                             table_oid)));
    3362             :     }
    3363             : 
    3364     2370982 :     classForm = (Form_pg_class) GETSTRUCT(tuple);
    3365             : 
    3366             :     /*
    3367             :      * Deny anyone permission to update a system catalog unless
    3368             :      * pg_authid.rolsuper is set.
    3369             :      *
    3370             :      * As of 7.4 we have some updatable system views; those shouldn't be
    3371             :      * protected in this way.  Assume the view rules can take care of
    3372             :      * themselves.  ACL_USAGE is if we ever have system sequences.
    3373             :      */
    3374     3013344 :     if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
    3375      642362 :         IsSystemClass(table_oid, classForm) &&
    3376        4714 :         classForm->relkind != RELKIND_VIEW &&
    3377        4714 :         !superuser_arg(roleid))
    3378          70 :         mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
    3379             : 
    3380             :     /*
    3381             :      * Otherwise, superusers bypass all permission-checking.
    3382             :      */
    3383     2370982 :     if (superuser_arg(roleid))
    3384             :     {
    3385     2339282 :         ReleaseSysCache(tuple);
    3386     2339282 :         return mask;
    3387             :     }
    3388             : 
    3389             :     /*
    3390             :      * Normal case: get the relation's ACL from pg_class
    3391             :      */
    3392       31700 :     ownerId = classForm->relowner;
    3393             : 
    3394       31700 :     aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    3395             :                                &isNull);
    3396       31700 :     if (isNull)
    3397             :     {
    3398             :         /* No ACL, so build default ACL */
    3399        5902 :         switch (classForm->relkind)
    3400             :         {
    3401          36 :             case RELKIND_SEQUENCE:
    3402          36 :                 acl = acldefault(OBJECT_SEQUENCE, ownerId);
    3403          36 :                 break;
    3404        5866 :             default:
    3405        5866 :                 acl = acldefault(OBJECT_TABLE, ownerId);
    3406        5866 :                 break;
    3407             :         }
    3408        5902 :         aclDatum = (Datum) 0;
    3409             :     }
    3410             :     else
    3411             :     {
    3412             :         /* detoast rel's ACL if necessary */
    3413       25798 :         acl = DatumGetAclP(aclDatum);
    3414             :     }
    3415             : 
    3416       31700 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3417             : 
    3418             :     /* if we have a detoasted copy, free it */
    3419       31700 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3420       31700 :         pfree(acl);
    3421             : 
    3422       31700 :     ReleaseSysCache(tuple);
    3423             : 
    3424             :     /*
    3425             :      * Check if ACL_SELECT is being checked and, if so, and not set already as
    3426             :      * part of the result, then check if the user is a member of the
    3427             :      * pg_read_all_data role, which allows read access to all relations.
    3428             :      */
    3429       33646 :     if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
    3430        1946 :         has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
    3431          12 :         result |= ACL_SELECT;
    3432             : 
    3433             :     /*
    3434             :      * Check if ACL_INSERT, ACL_UPDATE, or ACL_DELETE is being checked and, if
    3435             :      * so, and not set already as part of the result, then check if the user
    3436             :      * is a member of the pg_write_all_data role, which allows
    3437             :      * INSERT/UPDATE/DELETE access to all relations (except system catalogs,
    3438             :      * which requires superuser, see above).
    3439             :      */
    3440       31700 :     if (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE) &&
    3441        7288 :         !(result & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
    3442        1674 :         has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
    3443          18 :         result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
    3444             : 
    3445             :     /*
    3446             :      * Check if ACL_MAINTAIN is being checked and, if so, and not already set
    3447             :      * as part of the result, then check if the user is a member of the
    3448             :      * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
    3449             :      * MATERIALIZED VIEW, and REINDEX on all relations.
    3450             :      */
    3451       31700 :     if (mask & ACL_MAINTAIN &&
    3452        1882 :         !(result & ACL_MAINTAIN) &&
    3453         670 :         has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
    3454          66 :         result |= ACL_MAINTAIN;
    3455             : 
    3456       31700 :     return result;
    3457             : }
    3458             : 
    3459             : /*
    3460             :  * Routine for examining a user's privileges for a configuration
    3461             :  * parameter (GUC), identified by GUC name.
    3462             :  */
    3463             : static AclMode
    3464         160 : pg_parameter_aclmask(const char *name, Oid roleid, AclMode mask, AclMaskHow how)
    3465             : {
    3466             :     AclMode     result;
    3467             :     char       *parname;
    3468             :     text       *partext;
    3469             :     HeapTuple   tuple;
    3470             : 
    3471             :     /* Superusers bypass all permission checking. */
    3472         160 :     if (superuser_arg(roleid))
    3473           2 :         return mask;
    3474             : 
    3475             :     /* Convert name to the form it should have in pg_parameter_acl... */
    3476         158 :     parname = convert_GUC_name_for_parameter_acl(name);
    3477         158 :     partext = cstring_to_text(parname);
    3478             : 
    3479             :     /* ... and look it up */
    3480         158 :     tuple = SearchSysCache1(PARAMETERACLNAME, PointerGetDatum(partext));
    3481             : 
    3482         158 :     if (!HeapTupleIsValid(tuple))
    3483             :     {
    3484             :         /* If no entry, GUC has no permissions for non-superusers */
    3485          70 :         result = ACL_NO_RIGHTS;
    3486             :     }
    3487             :     else
    3488             :     {
    3489             :         Datum       aclDatum;
    3490             :         bool        isNull;
    3491             :         Acl        *acl;
    3492             : 
    3493          88 :         aclDatum = SysCacheGetAttr(PARAMETERACLNAME, tuple,
    3494             :                                    Anum_pg_parameter_acl_paracl,
    3495             :                                    &isNull);
    3496          88 :         if (isNull)
    3497             :         {
    3498             :             /* No ACL, so build default ACL */
    3499           0 :             acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3500           0 :             aclDatum = (Datum) 0;
    3501             :         }
    3502             :         else
    3503             :         {
    3504             :             /* detoast ACL if necessary */
    3505          88 :             acl = DatumGetAclP(aclDatum);
    3506             :         }
    3507             : 
    3508          88 :         result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3509             : 
    3510             :         /* if we have a detoasted copy, free it */
    3511          88 :         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3512          88 :             pfree(acl);
    3513             : 
    3514          88 :         ReleaseSysCache(tuple);
    3515             :     }
    3516             : 
    3517         158 :     pfree(parname);
    3518         158 :     pfree(partext);
    3519             : 
    3520         158 :     return result;
    3521             : }
    3522             : 
    3523             : /*
    3524             :  * Routine for examining a user's privileges for a configuration
    3525             :  * parameter (GUC), identified by the OID of its pg_parameter_acl entry.
    3526             :  */
    3527             : static AclMode
    3528           0 : pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid, AclMode mask, AclMaskHow how)
    3529             : {
    3530             :     AclMode     result;
    3531             :     HeapTuple   tuple;
    3532             :     Datum       aclDatum;
    3533             :     bool        isNull;
    3534             :     Acl        *acl;
    3535             : 
    3536             :     /* Superusers bypass all permission checking. */
    3537           0 :     if (superuser_arg(roleid))
    3538           0 :         return mask;
    3539             : 
    3540             :     /* Get the ACL from pg_parameter_acl */
    3541           0 :     tuple = SearchSysCache1(PARAMETERACLOID, ObjectIdGetDatum(acl_oid));
    3542           0 :     if (!HeapTupleIsValid(tuple))
    3543           0 :         ereport(ERROR,
    3544             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3545             :                  errmsg("parameter ACL with OID %u does not exist",
    3546             :                         acl_oid)));
    3547             : 
    3548           0 :     aclDatum = SysCacheGetAttr(PARAMETERACLOID, tuple,
    3549             :                                Anum_pg_parameter_acl_paracl,
    3550             :                                &isNull);
    3551           0 :     if (isNull)
    3552             :     {
    3553             :         /* No ACL, so build default ACL */
    3554           0 :         acl = acldefault(OBJECT_PARAMETER_ACL, BOOTSTRAP_SUPERUSERID);
    3555           0 :         aclDatum = (Datum) 0;
    3556             :     }
    3557             :     else
    3558             :     {
    3559             :         /* detoast ACL if necessary */
    3560           0 :         acl = DatumGetAclP(aclDatum);
    3561             :     }
    3562             : 
    3563           0 :     result = aclmask(acl, roleid, BOOTSTRAP_SUPERUSERID, mask, how);
    3564             : 
    3565             :     /* if we have a detoasted copy, free it */
    3566           0 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3567           0 :         pfree(acl);
    3568             : 
    3569           0 :     ReleaseSysCache(tuple);
    3570             : 
    3571           0 :     return result;
    3572             : }
    3573             : 
    3574             : /*
    3575             :  * Routine for examining a user's privileges for a largeobject
    3576             :  *
    3577             :  * When a large object is opened for reading, it is opened relative to the
    3578             :  * caller's snapshot, but when it is opened for writing, a current
    3579             :  * MVCC snapshot will be used.  See doc/src/sgml/lobj.sgml.  This function
    3580             :  * takes a snapshot argument so that the permissions check can be made
    3581             :  * relative to the same snapshot that will be used to read the underlying
    3582             :  * data.  The caller will actually pass NULL for an instantaneous MVCC
    3583             :  * snapshot, since all we do with the snapshot argument is pass it through
    3584             :  * to systable_beginscan().
    3585             :  */
    3586             : static AclMode
    3587         560 : pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
    3588             :                                 AclMode mask, AclMaskHow how,
    3589             :                                 Snapshot snapshot)
    3590             : {
    3591             :     AclMode     result;
    3592             :     Relation    pg_lo_meta;
    3593             :     ScanKeyData entry[1];
    3594             :     SysScanDesc scan;
    3595             :     HeapTuple   tuple;
    3596             :     Datum       aclDatum;
    3597             :     bool        isNull;
    3598             :     Acl        *acl;
    3599             :     Oid         ownerId;
    3600             : 
    3601             :     /* Superusers bypass all permission checking. */
    3602         560 :     if (superuser_arg(roleid))
    3603         410 :         return mask;
    3604             : 
    3605             :     /*
    3606             :      * Get the largeobject's ACL from pg_largeobject_metadata
    3607             :      */
    3608         150 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
    3609             :                             AccessShareLock);
    3610             : 
    3611         150 :     ScanKeyInit(&entry[0],
    3612             :                 Anum_pg_largeobject_metadata_oid,
    3613             :                 BTEqualStrategyNumber, F_OIDEQ,
    3614             :                 ObjectIdGetDatum(lobj_oid));
    3615             : 
    3616         150 :     scan = systable_beginscan(pg_lo_meta,
    3617             :                               LargeObjectMetadataOidIndexId, true,
    3618             :                               snapshot, 1, entry);
    3619             : 
    3620         150 :     tuple = systable_getnext(scan);
    3621         150 :     if (!HeapTupleIsValid(tuple))
    3622           0 :         ereport(ERROR,
    3623             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    3624             :                  errmsg("large object %u does not exist", lobj_oid)));
    3625             : 
    3626         150 :     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
    3627             : 
    3628         150 :     aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
    3629             :                             RelationGetDescr(pg_lo_meta), &isNull);
    3630             : 
    3631         150 :     if (isNull)
    3632             :     {
    3633             :         /* No ACL, so build default ACL */
    3634          36 :         acl = acldefault(OBJECT_LARGEOBJECT, ownerId);
    3635          36 :         aclDatum = (Datum) 0;
    3636             :     }
    3637             :     else
    3638             :     {
    3639             :         /* detoast ACL if necessary */
    3640         114 :         acl = DatumGetAclP(aclDatum);
    3641             :     }
    3642             : 
    3643         150 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3644             : 
    3645             :     /* if we have a detoasted copy, free it */
    3646         150 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3647         150 :         pfree(acl);
    3648             : 
    3649         150 :     systable_endscan(scan);
    3650             : 
    3651         150 :     table_close(pg_lo_meta, AccessShareLock);
    3652             : 
    3653         150 :     return result;
    3654             : }
    3655             : 
    3656             : /*
    3657             :  * Routine for examining a user's privileges for a namespace, with is_missing
    3658             :  */
    3659             : static AclMode
    3660      797266 : pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
    3661             :                          AclMode mask, AclMaskHow how,
    3662             :                          bool *is_missing)
    3663             : {
    3664             :     AclMode     result;
    3665             :     HeapTuple   tuple;
    3666             :     Datum       aclDatum;
    3667             :     bool        isNull;
    3668             :     Acl        *acl;
    3669             :     Oid         ownerId;
    3670             : 
    3671             :     /* Superusers bypass all permission checking. */
    3672      797266 :     if (superuser_arg(roleid))
    3673      781274 :         return mask;
    3674             : 
    3675             :     /*
    3676             :      * If we have been assigned this namespace as a temp namespace, check to
    3677             :      * make sure we have CREATE TEMP permission on the database, and if so act
    3678             :      * as though we have all standard (but not GRANT OPTION) permissions on
    3679             :      * the namespace.  If we don't have CREATE TEMP, act as though we have
    3680             :      * only USAGE (and not CREATE) rights.
    3681             :      *
    3682             :      * This may seem redundant given the check in InitTempTableNamespace, but
    3683             :      * it really isn't since current user ID may have changed since then. The
    3684             :      * upshot of this behavior is that a SECURITY DEFINER function can create
    3685             :      * temp tables that can then be accessed (if permission is granted) by
    3686             :      * code in the same session that doesn't have permissions to create temp
    3687             :      * tables.
    3688             :      *
    3689             :      * XXX Would it be safe to ereport a special error message as
    3690             :      * InitTempTableNamespace does?  Returning zero here means we'll get a
    3691             :      * generic "permission denied for schema pg_temp_N" message, which is not
    3692             :      * remarkably user-friendly.
    3693             :      */
    3694       15992 :     if (isTempNamespace(nsp_oid))
    3695             :     {
    3696         280 :         if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
    3697             :                                 ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
    3698         280 :             return mask & ACL_ALL_RIGHTS_SCHEMA;
    3699             :         else
    3700           0 :             return mask & ACL_USAGE;
    3701             :     }
    3702             : 
    3703             :     /*
    3704             :      * Get the schema's ACL from pg_namespace
    3705             :      */
    3706       15712 :     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
    3707       15712 :     if (!HeapTupleIsValid(tuple))
    3708             :     {
    3709           0 :         if (is_missing != NULL)
    3710             :         {
    3711             :             /* return "no privileges" instead of throwing an error */
    3712           0 :             *is_missing = true;
    3713           0 :             return 0;
    3714             :         }
    3715             :         else
    3716           0 :             ereport(ERROR,
    3717             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
    3718             :                      errmsg("schema with OID %u does not exist", nsp_oid)));
    3719             :     }
    3720             : 
    3721       15712 :     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
    3722             : 
    3723       15712 :     aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
    3724             :                                &isNull);
    3725       15712 :     if (isNull)
    3726             :     {
    3727             :         /* No ACL, so build default ACL */
    3728         280 :         acl = acldefault(OBJECT_SCHEMA, ownerId);
    3729         280 :         aclDatum = (Datum) 0;
    3730             :     }
    3731             :     else
    3732             :     {
    3733             :         /* detoast ACL if necessary */
    3734       15432 :         acl = DatumGetAclP(aclDatum);
    3735             :     }
    3736             : 
    3737       15712 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3738             : 
    3739             :     /* if we have a detoasted copy, free it */
    3740       15712 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3741       15712 :         pfree(acl);
    3742             : 
    3743       15712 :     ReleaseSysCache(tuple);
    3744             : 
    3745             :     /*
    3746             :      * Check if ACL_USAGE is being checked and, if so, and not set already as
    3747             :      * part of the result, then check if the user is a member of the
    3748             :      * pg_read_all_data or pg_write_all_data roles, which allow usage access
    3749             :      * to all schemas.
    3750             :      */
    3751       15752 :     if (mask & ACL_USAGE && !(result & ACL_USAGE) &&
    3752          74 :         (has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA) ||
    3753          34 :          has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA)))
    3754          14 :         result |= ACL_USAGE;
    3755       15712 :     return result;
    3756             : }
    3757             : 
    3758             : /*
    3759             :  * Routine for examining a user's privileges for a type, with is_missing
    3760             :  */
    3761             : static AclMode
    3762      290314 : pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
    3763             :                     bool *is_missing)
    3764             : {
    3765             :     AclMode     result;
    3766             :     HeapTuple   tuple;
    3767             :     Form_pg_type typeForm;
    3768             :     Datum       aclDatum;
    3769             :     bool        isNull;
    3770             :     Acl        *acl;
    3771             :     Oid         ownerId;
    3772             : 
    3773             :     /* Bypass permission checks for superusers */
    3774      290314 :     if (superuser_arg(roleid))
    3775      286018 :         return mask;
    3776             : 
    3777             :     /*
    3778             :      * Must get the type's tuple from pg_type
    3779             :      */
    3780        4296 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
    3781        4296 :     if (!HeapTupleIsValid(tuple))
    3782             :     {
    3783           0 :         if (is_missing != NULL)
    3784             :         {
    3785             :             /* return "no privileges" instead of throwing an error */
    3786           0 :             *is_missing = true;
    3787           0 :             return 0;
    3788             :         }
    3789             :         else
    3790           0 :             ereport(ERROR,
    3791             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    3792             :                      errmsg("type with OID %u does not exist",
    3793             :                             type_oid)));
    3794             :     }
    3795        4296 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3796             : 
    3797             :     /*
    3798             :      * "True" array types don't manage permissions of their own; consult the
    3799             :      * element type instead.
    3800             :      */
    3801        4296 :     if (IsTrueArrayType(typeForm))
    3802             :     {
    3803          48 :         Oid         elttype_oid = typeForm->typelem;
    3804             : 
    3805          48 :         ReleaseSysCache(tuple);
    3806             : 
    3807          48 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
    3808          48 :         if (!HeapTupleIsValid(tuple))
    3809             :         {
    3810           0 :             if (is_missing != NULL)
    3811             :             {
    3812             :                 /* return "no privileges" instead of throwing an error */
    3813           0 :                 *is_missing = true;
    3814           0 :                 return 0;
    3815             :             }
    3816             :             else
    3817           0 :                 ereport(ERROR,
    3818             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    3819             :                          errmsg("type with OID %u does not exist",
    3820             :                                 elttype_oid)));
    3821             :         }
    3822          48 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3823             :     }
    3824             : 
    3825             :     /*
    3826             :      * Likewise, multirange types don't manage their own permissions; consult
    3827             :      * the associated range type.  (Note we must do this after the array step
    3828             :      * to get the right answer for arrays of multiranges.)
    3829             :      */
    3830        4296 :     if (typeForm->typtype == TYPTYPE_MULTIRANGE)
    3831             :     {
    3832          12 :         Oid         rangetype = get_multirange_range(typeForm->oid);
    3833             : 
    3834          12 :         ReleaseSysCache(tuple);
    3835             : 
    3836          12 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rangetype));
    3837          12 :         if (!HeapTupleIsValid(tuple))
    3838             :         {
    3839           0 :             if (is_missing != NULL)
    3840             :             {
    3841             :                 /* return "no privileges" instead of throwing an error */
    3842           0 :                 *is_missing = true;
    3843           0 :                 return 0;
    3844             :             }
    3845             :             else
    3846           0 :                 ereport(ERROR,
    3847             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    3848             :                          errmsg("type with OID %u does not exist",
    3849             :                                 rangetype)));
    3850             :         }
    3851          12 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
    3852             :     }
    3853             : 
    3854             :     /*
    3855             :      * Now get the type's owner and ACL from the tuple
    3856             :      */
    3857        4296 :     ownerId = typeForm->typowner;
    3858             : 
    3859        4296 :     aclDatum = SysCacheGetAttr(TYPEOID, tuple,
    3860             :                                Anum_pg_type_typacl, &isNull);
    3861        4296 :     if (isNull)
    3862             :     {
    3863             :         /* No ACL, so build default ACL */
    3864        4062 :         acl = acldefault(OBJECT_TYPE, ownerId);
    3865        4062 :         aclDatum = (Datum) 0;
    3866             :     }
    3867             :     else
    3868             :     {
    3869             :         /* detoast rel's ACL if necessary */
    3870         234 :         acl = DatumGetAclP(aclDatum);
    3871             :     }
    3872             : 
    3873        4296 :     result = aclmask(acl, roleid, ownerId, mask, how);
    3874             : 
    3875             :     /* if we have a detoasted copy, free it */
    3876        4296 :     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
    3877        4296 :         pfree(acl);
    3878             : 
    3879        4296 :     ReleaseSysCache(tuple);
    3880             : 
    3881        4296 :     return result;
    3882             : }
    3883             : 
    3884             : /*
    3885             :  * Exported generic routine for checking a user's access privileges to an object
    3886             :  */
    3887             : AclResult
    3888     2832204 : object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
    3889             : {
    3890     2832204 :     return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
    3891             : }
    3892             : 
    3893             : /*
    3894             :  * Exported generic routine for checking a user's access privileges to an
    3895             :  * object, with is_missing
    3896             :  */
    3897             : AclResult
    3898     2832592 : object_aclcheck_ext(Oid classid, Oid objectid,
    3899             :                     Oid roleid, AclMode mode,
    3900             :                     bool *is_missing)
    3901             : {
    3902     2832592 :     if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
    3903             :                            is_missing) != 0)
    3904     2832048 :         return ACLCHECK_OK;
    3905             :     else
    3906         544 :         return ACLCHECK_NO_PRIV;
    3907             : }
    3908             : 
    3909             : /*
    3910             :  * Exported routine for checking a user's access privileges to a column
    3911             :  *
    3912             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    3913             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    3914             :  * ACLCHECK_NO_PRIV).
    3915             :  *
    3916             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3917             :  * column are considered here.
    3918             :  */
    3919             : AclResult
    3920        3538 : pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
    3921             :                       Oid roleid, AclMode mode)
    3922             : {
    3923        3538 :     return pg_attribute_aclcheck_ext(table_oid, attnum, roleid, mode, NULL);
    3924             : }
    3925             : 
    3926             : 
    3927             : /*
    3928             :  * Exported routine for checking a user's access privileges to a column,
    3929             :  * with is_missing
    3930             :  */
    3931             : AclResult
    3932        5268 : pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
    3933             :                           Oid roleid, AclMode mode, bool *is_missing)
    3934             : {
    3935        5268 :     if (pg_attribute_aclmask_ext(table_oid, attnum, roleid, mode,
    3936             :                                  ACLMASK_ANY, is_missing) != 0)
    3937        1960 :         return ACLCHECK_OK;
    3938             :     else
    3939        3308 :         return ACLCHECK_NO_PRIV;
    3940             : }
    3941             : 
    3942             : /*
    3943             :  * Exported routine for checking a user's access privileges to any/all columns
    3944             :  *
    3945             :  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
    3946             :  * privileges identified by 'mode' on any non-dropped column in the relation;
    3947             :  * otherwise returns a suitable error code (in practice, always
    3948             :  * ACLCHECK_NO_PRIV).
    3949             :  *
    3950             :  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
    3951             :  * privileges identified by 'mode' on each non-dropped column in the relation
    3952             :  * (and there must be at least one such column); otherwise returns a suitable
    3953             :  * error code (in practice, always ACLCHECK_NO_PRIV).
    3954             :  *
    3955             :  * As with pg_attribute_aclmask, only privileges granted directly on the
    3956             :  * column(s) are considered here.
    3957             :  *
    3958             :  * Note: system columns are not considered here; there are cases where that
    3959             :  * might be appropriate but there are also cases where it wouldn't.
    3960             :  */
    3961             : AclResult
    3962         162 : pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
    3963             :                           AclMaskHow how)
    3964             : {
    3965         162 :     return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
    3966             : }
    3967             : 
    3968             : /*
    3969             :  * Exported routine for checking a user's access privileges to any/all columns,
    3970             :  * with is_missing
    3971             :  */
    3972             : AclResult
    3973         162 : pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
    3974             :                               AclMode mode, AclMaskHow how,
    3975             :                               bool *is_missing)
    3976             : {
    3977             :     AclResult   result;
    3978             :     HeapTuple   classTuple;
    3979             :     Form_pg_class classForm;
    3980             :     Oid         ownerId;
    3981             :     AttrNumber  nattrs;
    3982             :     AttrNumber  curr_att;
    3983             : 
    3984             :     /*
    3985             :      * Must fetch pg_class row to get owner ID and number of attributes.
    3986             :      */
    3987         162 :     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
    3988         162 :     if (!HeapTupleIsValid(classTuple))
    3989             :     {
    3990           0 :         if (is_missing != NULL)
    3991             :         {
    3992             :             /* return "no privileges" instead of throwing an error */
    3993           0 :             *is_missing = true;
    3994           0 :             return ACLCHECK_NO_PRIV;
    3995             :         }
    3996             :         else
    3997           0 :             ereport(ERROR,
    3998             :                     (errcode(ERRCODE_UNDEFINED_TABLE),
    3999             :                      errmsg("relation with OID %u does not exist",
    4000             :                             table_oid)));
    4001             :     }
    4002         162 :     classForm = (Form_pg_class) GETSTRUCT(classTuple);
    4003             : 
    4004         162 :     ownerId = classForm->relowner;
    4005         162 :     nattrs = classForm->relnatts;
    4006             : 
    4007         162 :     ReleaseSysCache(classTuple);
    4008             : 
    4009             :     /*
    4010             :      * Initialize result in case there are no non-dropped columns.  We want to
    4011             :      * report failure in such cases for either value of 'how'.
    4012             :      */
    4013         162 :     result = ACLCHECK_NO_PRIV;
    4014             : 
    4015         414 :     for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4016             :     {
    4017             :         HeapTuple   attTuple;
    4018             :         Datum       aclDatum;
    4019             :         bool        isNull;
    4020             :         Acl        *acl;
    4021             :         AclMode     attmask;
    4022             : 
    4023         330 :         attTuple = SearchSysCache2(ATTNUM,
    4024             :                                    ObjectIdGetDatum(table_oid),
    4025             :                                    Int16GetDatum(curr_att));
    4026             : 
    4027             :         /*
    4028             :          * Lookup failure probably indicates that the table was just dropped,
    4029             :          * but we'll treat it the same as a dropped column rather than
    4030             :          * throwing error.
    4031             :          */
    4032         330 :         if (!HeapTupleIsValid(attTuple))
    4033          18 :             continue;
    4034             : 
    4035             :         /* ignore dropped columns */
    4036         330 :         if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    4037             :         {
    4038          18 :             ReleaseSysCache(attTuple);
    4039          18 :             continue;
    4040             :         }
    4041             : 
    4042         312 :         aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
    4043             :                                    &isNull);
    4044             : 
    4045             :         /*
    4046             :          * Here we hard-wire knowledge that the default ACL for a column
    4047             :          * grants no privileges, so that we can fall out quickly in the very
    4048             :          * common case where attacl is null.
    4049             :          */
    4050         312 :         if (isNull)
    4051         156 :             attmask = 0;
    4052             :         else
    4053             :         {
    4054             :             /* detoast column's ACL if necessary */
    4055         156 :             acl = DatumGetAclP(aclDatum);
    4056             : 
    4057         156 :             attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
    4058             : 
    4059             :             /* if we have a detoasted copy, free it */
    4060         156 :             if ((Pointer) acl != DatumGetPointer(aclDatum))
    4061         156 :                 pfree(acl);
    4062             :         }
    4063             : 
    4064         312 :         ReleaseSysCache(attTuple);
    4065             : 
    4066         312 :         if (attmask != 0)
    4067             :         {
    4068         138 :             result = ACLCHECK_OK;
    4069         138 :             if (how == ACLMASK_ANY)
    4070          78 :                 break;          /* succeed on any success */
    4071             :         }
    4072             :         else
    4073             :         {
    4074         174 :             result = ACLCHECK_NO_PRIV;
    4075         174 :             if (how == ACLMASK_ALL)
    4076          36 :                 break;          /* fail on any failure */
    4077             :         }
    4078             :     }
    4079             : 
    4080         162 :     return result;
    4081             : }
    4082             : 
    4083             : /*
    4084             :  * Exported routine for checking a user's access privileges to a table
    4085             :  *
    4086             :  * Returns ACLCHECK_OK if the user has any of the privileges identified by
    4087             :  * 'mode'; otherwise returns a suitable error code (in practice, always
    4088             :  * ACLCHECK_NO_PRIV).
    4089             :  */
    4090             : AclResult
    4091     1872856 : pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
    4092             : {
    4093     1872856 :     return pg_class_aclcheck_ext(table_oid, roleid, mode, NULL);
    4094             : }
    4095             : 
    4096             : /*
    4097             :  * Exported routine for checking a user's access privileges to a table,
    4098             :  * with is_missing
    4099             :  */
    4100             : AclResult
    4101     1874708 : pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
    4102             :                       AclMode mode, bool *is_missing)
    4103             : {
    4104     1874708 :     if (pg_class_aclmask_ext(table_oid, roleid, mode,
    4105             :                              ACLMASK_ANY, is_missing) != 0)
    4106     1873558 :         return ACLCHECK_OK;
    4107             :     else
    4108        1150 :         return ACLCHECK_NO_PRIV;
    4109             : }
    4110             : 
    4111             : /*
    4112             :  * Exported routine for checking a user's access privileges to a configuration
    4113             :  * parameter (GUC), identified by GUC name.
    4114             :  */
    4115             : AclResult
    4116         160 : pg_parameter_aclcheck(const char *name, Oid roleid, AclMode mode)
    4117             : {
    4118         160 :     if (pg_parameter_aclmask(name, roleid, mode, ACLMASK_ANY) != 0)
    4119          68 :         return ACLCHECK_OK;
    4120             :     else
    4121          92 :         return ACLCHECK_NO_PRIV;
    4122             : }
    4123             : 
    4124             : /*
    4125             :  * Exported routine for checking a user's access privileges to a largeobject
    4126             :  */
    4127             : AclResult
    4128         560 : pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
    4129             :                                  Snapshot snapshot)
    4130             : {
    4131         560 :     if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
    4132             :                                         ACLMASK_ANY, snapshot) != 0)
    4133         506 :         return ACLCHECK_OK;
    4134             :     else
    4135          54 :         return ACLCHECK_NO_PRIV;
    4136             : }
    4137             : 
    4138             : /*
    4139             :  * Generic ownership check for an object
    4140             :  */
    4141             : bool
    4142      216458 : object_ownercheck(Oid classid, Oid objectid, Oid roleid)
    4143             : {
    4144             :     int         cacheid;
    4145             :     Oid         ownerId;
    4146             : 
    4147             :     /* Superusers bypass all permission checking. */
    4148      216458 :     if (superuser_arg(roleid))
    4149      208646 :         return true;
    4150             : 
    4151             :     /* For large objects, the catalog to consult is pg_largeobject_metadata */
    4152        7812 :     if (classid == LargeObjectRelationId)
    4153          24 :         classid = LargeObjectMetadataRelationId;
    4154             : 
    4155        7812 :     cacheid = get_object_catcache_oid(classid);
    4156        7812 :     if (cacheid != -1)
    4157             :     {
    4158             :         /* we can get the object's tuple from the syscache */
    4159             :         HeapTuple   tuple;
    4160             : 
    4161        7784 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
    4162        7784 :         if (!HeapTupleIsValid(tuple))
    4163           0 :             ereport(ERROR,
    4164             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    4165             :                      errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
    4166             : 
    4167        7784 :         ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    4168             :                                                           tuple,
    4169        7784 :                                                           get_object_attnum_owner(classid)));
    4170        7784 :         ReleaseSysCache(tuple);
    4171             :     }
    4172             :     else
    4173             :     {
    4174             :         /* for catalogs without an appropriate syscache */
    4175             :         Relation    rel;
    4176             :         ScanKeyData entry[1];
    4177             :         SysScanDesc scan;
    4178             :         HeapTuple   tuple;
    4179             :         bool        isnull;
    4180             : 
    4181          28 :         rel = table_open(classid, AccessShareLock);
    4182             : 
    4183          56 :         ScanKeyInit(&entry[0],
    4184          28 :                     get_object_attnum_oid(classid),
    4185             :                     BTEqualStrategyNumber, F_OIDEQ,
    4186             :                     ObjectIdGetDatum(objectid));
    4187             : 
    4188          28 :         scan = systable_beginscan(rel,
    4189             :                                   get_object_oid_index(classid), true,
    4190             :                                   NULL, 1, entry);
    4191             : 
    4192          28 :         tuple = systable_getnext(scan);
    4193          28 :         if (!HeapTupleIsValid(tuple))
    4194           0 :             ereport(ERROR,
    4195             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    4196             :                      errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
    4197             : 
    4198          28 :         ownerId = DatumGetObjectId(heap_getattr(tuple,
    4199          28 :                                                 get_object_attnum_owner(classid),
    4200             :                                                 RelationGetDescr(rel),
    4201             :                                                 &isnull));
    4202             :         Assert(!isnull);
    4203             : 
    4204          28 :         systable_endscan(scan);
    4205          28 :         table_close(rel, AccessShareLock);
    4206             :     }
    4207             : 
    4208        7812 :     return has_privs_of_role(roleid, ownerId);
    4209             : }
    4210             : 
    4211             : /*
    4212             :  * Check whether specified role has CREATEROLE privilege (or is a superuser)
    4213             :  *
    4214             :  * Note: roles do not have owners per se; instead we use this test in
    4215             :  * places where an ownership-like permissions test is needed for a role.
    4216             :  * Be sure to apply it to the role trying to do the operation, not the
    4217             :  * role being operated on!  Also note that this generally should not be
    4218             :  * considered enough privilege if the target role is a superuser.
    4219             :  * (We don't handle that consideration here because we want to give a
    4220             :  * separate error message for such cases, so the caller has to deal with it.)
    4221             :  */
    4222             : bool
    4223        2372 : has_createrole_privilege(Oid roleid)
    4224             : {
    4225        2372 :     bool        result = false;
    4226             :     HeapTuple   utup;
    4227             : 
    4228             :     /* Superusers bypass all permission checking. */
    4229        2372 :     if (superuser_arg(roleid))
    4230        1854 :         return true;
    4231             : 
    4232         518 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4233         518 :     if (HeapTupleIsValid(utup))
    4234             :     {
    4235         518 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
    4236         518 :         ReleaseSysCache(utup);
    4237             :     }
    4238         518 :     return result;
    4239             : }
    4240             : 
    4241             : bool
    4242        4490 : has_bypassrls_privilege(Oid roleid)
    4243             : {
    4244        4490 :     bool        result = false;
    4245             :     HeapTuple   utup;
    4246             : 
    4247             :     /* Superusers bypass all permission checking. */
    4248        4490 :     if (superuser_arg(roleid))
    4249        1360 :         return true;
    4250             : 
    4251        3130 :     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
    4252        3130 :     if (HeapTupleIsValid(utup))
    4253             :     {
    4254        3130 :         result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
    4255        3130 :         ReleaseSysCache(utup);
    4256             :     }
    4257        3130 :     return result;
    4258             : }
    4259             : 
    4260             : /*
    4261             :  * Fetch pg_default_acl entry for given role, namespace and object type
    4262             :  * (object type must be given in pg_default_acl's encoding).
    4263             :  * Returns NULL if no such entry.
    4264             :  */
    4265             : static Acl *
    4266      139640 : get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
    4267             : {
    4268      139640 :     Acl        *result = NULL;
    4269             :     HeapTuple   tuple;
    4270             : 
    4271      139640 :     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
    4272             :                             ObjectIdGetDatum(roleId),
    4273             :                             ObjectIdGetDatum(nsp_oid),
    4274             :                             CharGetDatum(objtype));
    4275             : 
    4276      139640 :     if (HeapTupleIsValid(tuple))
    4277             :     {
    4278             :         Datum       aclDatum;
    4279             :         bool        isNull;
    4280             : 
    4281         228 :         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
    4282             :                                    Anum_pg_default_acl_defaclacl,
    4283             :                                    &isNull);
    4284         228 :         if (!isNull)
    4285         228 :             result = DatumGetAclPCopy(aclDatum);
    4286         228 :         ReleaseSysCache(tuple);
    4287             :     }
    4288             : 
    4289      139640 :     return result;
    4290             : }
    4291             : 
    4292             : /*
    4293             :  * Get default permissions for newly created object within given schema
    4294             :  *
    4295             :  * Returns NULL if built-in system defaults should be used.
    4296             :  *
    4297             :  * If the result is not NULL, caller must call recordDependencyOnNewAcl
    4298             :  * once the OID of the new object is known.
    4299             :  */
    4300             : Acl *
    4301       69820 : get_user_default_acl(ObjectType objtype, Oid ownerId, Oid nsp_oid)
    4302             : {
    4303             :     Acl        *result;
    4304             :     Acl        *glob_acl;
    4305             :     Acl        *schema_acl;
    4306             :     Acl        *def_acl;
    4307             :     char        defaclobjtype;
    4308             : 
    4309             :     /*
    4310             :      * Use NULL during bootstrap, since pg_default_acl probably isn't there
    4311             :      * yet.
    4312             :      */
    4313       69820 :     if (IsBootstrapProcessingMode())
    4314           0 :         return NULL;
    4315             : 
    4316             :     /* Check if object type is supported in pg_default_acl */
    4317       69820 :     switch (objtype)
    4318             :     {
    4319       49966 :         case OBJECT_TABLE:
    4320       49966 :             defaclobjtype = DEFACLOBJ_RELATION;
    4321       49966 :             break;
    4322             : 
    4323        1664 :         case OBJECT_SEQUENCE:
    4324        1664 :             defaclobjtype = DEFACLOBJ_SEQUENCE;
    4325        1664 :             break;
    4326             : 
    4327       14634 :         case OBJECT_FUNCTION:
    4328       14634 :             defaclobjtype = DEFACLOBJ_FUNCTION;
    4329       14634 :             break;
    4330             : 
    4331        2610 :         case OBJECT_TYPE:
    4332        2610 :             defaclobjtype = DEFACLOBJ_TYPE;
    4333        2610 :             break;
    4334             : 
    4335         946 :         case OBJECT_SCHEMA:
    4336         946 :             defaclobjtype = DEFACLOBJ_NAMESPACE;
    4337         946 :             break;
    4338             : 
    4339           0 :         default:
    4340           0 :             return NULL;
    4341             :     }
    4342             : 
    4343             :     /* Look up the relevant pg_default_acl entries */
    4344       69820 :     glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
    4345       69820 :     schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
    4346             : 
    4347             :     /* Quick out if neither entry exists */
    4348       69820 :     if (glob_acl == NULL && schema_acl == NULL)
    4349       69628 :         return NULL;
    4350             : 
    4351             :     /* We need to know the hard-wired default value, too */
    4352         192 :     def_acl = acldefault(objtype, ownerId);
    4353             : 
    4354             :     /* If there's no global entry, substitute the hard-wired default */
    4355         192 :     if (glob_acl == NULL)
    4356          18 :         glob_acl = def_acl;
    4357             : 
    4358             :     /* Merge in any per-schema privileges */
    4359         192 :     result = aclmerge(glob_acl, schema_acl, ownerId);
    4360             : 
    4361             :     /*
    4362             :      * For efficiency, we want to return NULL if the result equals default.
    4363             :      * This requires sorting both arrays to get an accurate comparison.
    4364             :      */
    4365         192 :     aclitemsort(result);
    4366         192 :     aclitemsort(def_acl);
    4367         192 :     if (aclequal(result, def_acl))
    4368          24 :         result = NULL;
    4369             : 
    4370         192 :     return result;
    4371             : }
    4372             : 
    4373             : /*
    4374             :  * Record dependencies on roles mentioned in a new object's ACL.
    4375             :  */
    4376             : void
    4377       72864 : recordDependencyOnNewAcl(Oid classId, Oid objectId, int32 objsubId,
    4378             :                          Oid ownerId, Acl *acl)
    4379             : {
    4380             :     int         nmembers;
    4381             :     Oid        *members;
    4382             : 
    4383             :     /* Nothing to do if ACL is defaulted */
    4384       72864 :     if (acl == NULL)
    4385       72696 :         return;
    4386             : 
    4387             :     /* Extract roles mentioned in ACL */
    4388         168 :     nmembers = aclmembers(acl, &members);
    4389             : 
    4390             :     /* Update the shared dependency ACL info */
    4391         168 :     updateAclDependencies(classId, objectId, objsubId,
    4392             :                           ownerId,
    4393             :                           0, NULL,
    4394             :                           nmembers, members);
    4395             : }
    4396             : 
    4397             : /*
    4398             :  * Record initial privileges for the top-level object passed in.
    4399             :  *
    4400             :  * For the object passed in, this will record its ACL (if any) and the ACLs of
    4401             :  * any sub-objects (eg: columns) into pg_init_privs.
    4402             :  */
    4403             : void
    4404          96 : recordExtObjInitPriv(Oid objoid, Oid classoid)
    4405             : {
    4406             :     /*
    4407             :      * pg_class / pg_attribute
    4408             :      *
    4409             :      * If this is a relation then we need to see if there are any sub-objects
    4410             :      * (eg: columns) for it and, if so, be sure to call
    4411             :      * recordExtensionInitPrivWorker() for each one.
    4412             :      */
    4413          96 :     if (classoid == RelationRelationId)
    4414             :     {
    4415             :         Form_pg_class pg_class_tuple;
    4416             :         Datum       aclDatum;
    4417             :         bool        isNull;
    4418             :         HeapTuple   tuple;
    4419             : 
    4420          16 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4421          16 :         if (!HeapTupleIsValid(tuple))
    4422           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4423          16 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    4424             : 
    4425             :         /*
    4426             :          * Indexes don't have permissions, neither do the pg_class rows for
    4427             :          * composite types.  (These cases are unreachable given the
    4428             :          * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
    4429             :          */
    4430          16 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4431          16 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4432          16 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4433             :         {
    4434           0 :             ReleaseSysCache(tuple);
    4435           0 :             return;
    4436             :         }
    4437             : 
    4438             :         /*
    4439             :          * If this isn't a sequence then it's possibly going to have
    4440             :          * column-level ACLs associated with it.
    4441             :          */
    4442          16 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4443             :         {
    4444             :             AttrNumber  curr_att;
    4445          14 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4446             : 
    4447          38 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4448             :             {
    4449             :                 HeapTuple   attTuple;
    4450             :                 Datum       attaclDatum;
    4451             : 
    4452          24 :                 attTuple = SearchSysCache2(ATTNUM,
    4453             :                                            ObjectIdGetDatum(objoid),
    4454             :                                            Int16GetDatum(curr_att));
    4455             : 
    4456          24 :                 if (!HeapTupleIsValid(attTuple))
    4457           0 :                     continue;
    4458             : 
    4459             :                 /* ignore dropped columns */
    4460          24 :                 if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
    4461             :                 {
    4462           2 :                     ReleaseSysCache(attTuple);
    4463           2 :                     continue;
    4464             :                 }
    4465             : 
    4466          22 :                 attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
    4467             :                                               Anum_pg_attribute_attacl,
    4468             :                                               &isNull);
    4469             : 
    4470             :                 /* no need to do anything for a NULL ACL */
    4471          22 :                 if (isNull)
    4472             :                 {
    4473          18 :                     ReleaseSysCache(attTuple);
    4474          18 :                     continue;
    4475             :                 }
    4476             : 
    4477           4 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att,
    4478           4 :                                               DatumGetAclP(attaclDatum));
    4479             : 
    4480           4 :                 ReleaseSysCache(attTuple);
    4481             :             }
    4482             :         }
    4483             : 
    4484          16 :         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
    4485             :                                    &isNull);
    4486             : 
    4487             :         /* Add the record, if any, for the top-level object */
    4488          16 :         if (!isNull)
    4489           8 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4490           8 :                                           DatumGetAclP(aclDatum));
    4491             : 
    4492          16 :         ReleaseSysCache(tuple);
    4493             :     }
    4494          80 :     else if (classoid == LargeObjectRelationId)
    4495             :     {
    4496             :         /* For large objects, we must consult pg_largeobject_metadata */
    4497             :         Datum       aclDatum;
    4498             :         bool        isNull;
    4499             :         HeapTuple   tuple;
    4500             :         ScanKeyData entry[1];
    4501             :         SysScanDesc scan;
    4502             :         Relation    relation;
    4503             : 
    4504             :         /*
    4505             :          * Note: this is dead code, given that we don't allow large objects to
    4506             :          * be made extension members.  But it seems worth carrying in case
    4507             :          * some future caller of this function has need for it.
    4508             :          */
    4509           0 :         relation = table_open(LargeObjectMetadataRelationId, RowExclusiveLock);
    4510             : 
    4511             :         /* There's no syscache for pg_largeobject_metadata */
    4512           0 :         ScanKeyInit(&entry[0],
    4513             :                     Anum_pg_largeobject_metadata_oid,
    4514             :                     BTEqualStrategyNumber, F_OIDEQ,
    4515             :                     ObjectIdGetDatum(objoid));
    4516             : 
    4517           0 :         scan = systable_beginscan(relation,
    4518             :                                   LargeObjectMetadataOidIndexId, true,
    4519             :                                   NULL, 1, entry);
    4520             : 
    4521           0 :         tuple = systable_getnext(scan);
    4522           0 :         if (!HeapTupleIsValid(tuple))
    4523           0 :             elog(ERROR, "could not find tuple for large object %u", objoid);
    4524             : 
    4525           0 :         aclDatum = heap_getattr(tuple,
    4526             :                                 Anum_pg_largeobject_metadata_lomacl,
    4527             :                                 RelationGetDescr(relation), &isNull);
    4528             : 
    4529             :         /* Add the record, if any, for the top-level object */
    4530           0 :         if (!isNull)
    4531           0 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4532           0 :                                           DatumGetAclP(aclDatum));
    4533             : 
    4534           0 :         systable_endscan(scan);
    4535             :     }
    4536             :     /* This will error on unsupported classoid. */
    4537          80 :     else if (get_object_attnum_acl(classoid) != InvalidAttrNumber)
    4538             :     {
    4539             :         int         cacheid;
    4540             :         Datum       aclDatum;
    4541             :         bool        isNull;
    4542             :         HeapTuple   tuple;
    4543             : 
    4544          58 :         cacheid = get_object_catcache_oid(classoid);
    4545          58 :         tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objoid));
    4546          58 :         if (!HeapTupleIsValid(tuple))
    4547           0 :             elog(ERROR, "cache lookup failed for %s %u",
    4548             :                  get_object_class_descr(classoid), objoid);
    4549             : 
    4550          58 :         aclDatum = SysCacheGetAttr(cacheid, tuple,
    4551          58 :                                    get_object_attnum_acl(classoid),
    4552             :                                    &isNull);
    4553             : 
    4554             :         /* Add the record, if any, for the top-level object */
    4555          58 :         if (!isNull)
    4556          10 :             recordExtensionInitPrivWorker(objoid, classoid, 0,
    4557          10 :                                           DatumGetAclP(aclDatum));
    4558             : 
    4559          58 :         ReleaseSysCache(tuple);
    4560             :     }
    4561             : }
    4562             : 
    4563             : /*
    4564             :  * For the object passed in, remove its ACL and the ACLs of any object subIds
    4565             :  * from pg_init_privs (via recordExtensionInitPrivWorker()).
    4566             :  */
    4567             : void
    4568         228 : removeExtObjInitPriv(Oid objoid, Oid classoid)
    4569             : {
    4570             :     /*
    4571             :      * If this is a relation then we need to see if there are any sub-objects
    4572             :      * (eg: columns) for it and, if so, be sure to call
    4573             :      * recordExtensionInitPrivWorker() for each one.
    4574             :      */
    4575         228 :     if (classoid == RelationRelationId)
    4576             :     {
    4577             :         Form_pg_class pg_class_tuple;
    4578             :         HeapTuple   tuple;
    4579             : 
    4580          40 :         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
    4581          40 :         if (!HeapTupleIsValid(tuple))
    4582           0 :             elog(ERROR, "cache lookup failed for relation %u", objoid);
    4583          40 :         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
    4584             : 
    4585             :         /*
    4586             :          * Indexes don't have permissions, neither do the pg_class rows for
    4587             :          * composite types.  (These cases are unreachable given the
    4588             :          * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
    4589             :          */
    4590          40 :         if (pg_class_tuple->relkind == RELKIND_INDEX ||
    4591          40 :             pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
    4592          40 :             pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
    4593             :         {
    4594           0 :             ReleaseSysCache(tuple);
    4595           0 :             return;
    4596             :         }
    4597             : 
    4598             :         /*
    4599             :          * If this isn't a sequence then it's possibly going to have
    4600             :          * column-level ACLs associated with it.
    4601             :          */
    4602          40 :         if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
    4603             :         {
    4604             :             AttrNumber  curr_att;
    4605          40 :             AttrNumber  nattrs = pg_class_tuple->relnatts;
    4606             : 
    4607         938 :             for (curr_att = 1; curr_att <= nattrs; curr_att++)
    4608             :             {
    4609             :                 HeapTuple   attTuple;
    4610             : 
    4611         898 :                 attTuple = SearchSysCache2(ATTNUM,
    4612             :                                            ObjectIdGetDatum(objoid),
    4613             :                                            Int16GetDatum(curr_att));
    4614             : 
    4615         898 :                 if (!HeapTupleIsValid(attTuple))
    4616           0 :                     continue;
    4617             : 
    4618             :                 /* when removing, remove all entries, even dropped columns */
    4619             : 
    4620         898 :                 recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
    4621             : 
    4622         898 :                 ReleaseSysCache(attTuple);
    4623             :             }
    4624             :         }
    4625             : 
    4626          40 :         ReleaseSysCache(tuple);
    4627             :     }
    4628             : 
    4629             :     /* Remove the record, if any, for the top-level object */
    4630         228 :     recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
    4631             : }
    4632             : 
    4633             : /*
    4634             :  * Record initial ACL for an extension object
    4635             :  *
    4636             :  * Can be called at any time, we check if 'creating_extension' is set and, if
    4637             :  * not, exit immediately.
    4638             :  *
    4639             :  * Pass in the object OID, the OID of the class (the OID of the table which
    4640             :  * the object is defined in) and the 'sub' id of the object (objsubid), if
    4641             :  * any.  If there is no 'sub' id (they are currently only used for columns of
    4642             :  * tables) then pass in '0'.  Finally, pass in the complete ACL to store.
    4643             :  *
    4644             :  * If an ACL already exists for this object/sub-object then we will replace
    4645             :  * it with what is passed in.
    4646             :  *
    4647             :  * Passing in NULL for 'new_acl' will result in the entry for the object being
    4648             :  * removed, if one is found.
    4649             :  */
    4650             : static void
    4651       26224 : recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
    4652             : {
    4653             :     /*
    4654             :      * Generally, we only record the initial privileges when an extension is
    4655             :      * being created, but because we don't actually use CREATE EXTENSION
    4656             :      * during binary upgrades with pg_upgrade, there is a variable to let us
    4657             :      * know that the GRANT and REVOKE statements being issued, while this
    4658             :      * variable is true, are for the initial privileges of the extension
    4659             :      * object and therefore we need to record them.
    4660             :      */
    4661       26224 :     if (!creating_extension && !binary_upgrade_record_init_privs)
    4662       25568 :         return;
    4663             : 
    4664         656 :     recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
    4665             : }
    4666             : 
    4667             : /*
    4668             :  * Record initial ACL for an extension object, worker.
    4669             :  *
    4670             :  * This will perform a wholesale replacement of the entire ACL for the object
    4671             :  * passed in, therefore be sure to pass in the complete new ACL to use.
    4672             :  *
    4673             :  * Generally speaking, do *not* use this function directly but instead use
    4674             :  * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
    4675             :  * This function does *not* check if 'creating_extension' is set as it is also
    4676             :  * used when an object is added to or removed from an extension via ALTER
    4677             :  * EXTENSION ... ADD/DROP.
    4678             :  */
    4679             : static void
    4680        1804 : recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
    4681             :                               Acl *new_acl)
    4682             : {
    4683             :     Relation    relation;
    4684             :     ScanKeyData key[3];
    4685             :     SysScanDesc scan;
    4686             :     HeapTuple   tuple;
    4687             :     HeapTuple   oldtuple;
    4688             :     int         noldmembers;
    4689             :     int         nnewmembers;
    4690             :     Oid        *oldmembers;
    4691             :     Oid        *newmembers;
    4692             : 
    4693             :     /* We'll need the role membership of the new ACL. */
    4694        1804 :     nnewmembers = aclmembers(new_acl, &newmembers);
    4695             : 
    4696             :     /* Search pg_init_privs for an existing entry. */
    4697        1804 :     relation = table_open(InitPrivsRelationId, RowExclusiveLock);
    4698             : 
    4699        1804 :     ScanKeyInit(&key[0],
    4700             :                 Anum_pg_init_privs_objoid,
    4701             :                 BTEqualStrategyNumber, F_OIDEQ,
    4702             :                 ObjectIdGetDatum(objoid));
    4703        1804 :     ScanKeyInit(&key[1],
    4704             :                 Anum_pg_init_privs_classoid,
    4705             :                 BTEqualStrategyNumber, F_OIDEQ,
    4706             :                 ObjectIdGetDatum(classoid));
    4707        1804 :     ScanKeyInit(&key[2],
    4708             :                 Anum_pg_init_privs_objsubid,
    4709             :                 BTEqualStrategyNumber, F_INT4EQ,
    4710             :                 Int32GetDatum(objsubid));
    4711             : 
    4712        1804 :     scan = systable_beginscan(relation, InitPrivsObjIndexId, true,
    4713             :                               NULL, 3, key);
    4714             : 
    4715             :     /* There should exist only one entry or none. */
    4716        1804 :     oldtuple = systable_getnext(scan);
    4717             : 
    4718             :     /* If we find an entry, update it with the latest ACL. */
    4719        1804 :     if (HeapTupleIsValid(oldtuple))
    4720             :     {
    4721         212 :         Datum       values[Natts_pg_init_privs] = {0};
    4722         212 :         bool        nulls[Natts_pg_init_privs] = {0};
    4723         212 :         bool        replace[Natts_pg_init_privs] = {0};
    4724             :         Datum       oldAclDatum;
    4725             :         bool        isNull;
    4726             :         Acl        *old_acl;
    4727             : 
    4728             :         /* Update pg_shdepend for roles mentioned in the old/new ACLs. */
    4729         212 :         oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4730             :                                    RelationGetDescr(relation), &isNull);
    4731             :         Assert(!isNull);
    4732         212 :         old_acl = DatumGetAclP(oldAclDatum);
    4733         212 :         noldmembers = aclmembers(old_acl, &oldmembers);
    4734             : 
    4735         212 :         updateInitAclDependencies(classoid, objoid, objsubid,
    4736             :                                   noldmembers, oldmembers,
    4737             :                                   nnewmembers, newmembers);
    4738             : 
    4739             :         /* If we have a new ACL to set, then update the row with it. */
    4740         212 :         if (new_acl && ACL_NUM(new_acl) != 0)
    4741             :         {
    4742         146 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4743         146 :             replace[Anum_pg_init_privs_initprivs - 1] = true;
    4744             : 
    4745         146 :             oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation),
    4746             :                                          values, nulls, replace);
    4747             : 
    4748         146 :             CatalogTupleUpdate(relation, &oldtuple->t_self, oldtuple);
    4749             :         }
    4750             :         else
    4751             :         {
    4752             :             /* new_acl is NULL/empty, so delete the entry we found. */
    4753          66 :             CatalogTupleDelete(relation, &oldtuple->t_self);
    4754             :         }
    4755             :     }
    4756             :     else
    4757             :     {
    4758        1592 :         Datum       values[Natts_pg_init_privs] = {0};
    4759        1592 :         bool        nulls[Natts_pg_init_privs] = {0};
    4760             : 
    4761             :         /*
    4762             :          * Only add a new entry if the new ACL is non-NULL.
    4763             :          *
    4764             :          * If we are passed in a NULL ACL and no entry exists, we can just
    4765             :          * fall through and do nothing.
    4766             :          */
    4767        1592 :         if (new_acl && ACL_NUM(new_acl) != 0)
    4768             :         {
    4769             :             /* No entry found, so add it. */
    4770         526 :             values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
    4771         526 :             values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
    4772         526 :             values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
    4773             : 
    4774             :             /* This function only handles initial privileges of extensions */
    4775         526 :             values[Anum_pg_init_privs_privtype - 1] =
    4776         526 :                 CharGetDatum(INITPRIVS_EXTENSION);
    4777             : 
    4778         526 :             values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4779             : 
    4780         526 :             tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
    4781             : 
    4782         526 :             CatalogTupleInsert(relation, tuple);
    4783             : 
    4784             :             /* Update pg_shdepend, too. */
    4785         526 :             noldmembers = 0;
    4786         526 :             oldmembers = NULL;
    4787             : 
    4788         526 :             updateInitAclDependencies(classoid, objoid, objsubid,
    4789             :                                       noldmembers, oldmembers,
    4790             :                                       nnewmembers, newmembers);
    4791             :         }
    4792             :     }
    4793             : 
    4794        1804 :     systable_endscan(scan);
    4795             : 
    4796             :     /* prevent error when processing objects multiple times */
    4797        1804 :     CommandCounterIncrement();
    4798             : 
    4799        1804 :     table_close(relation, RowExclusiveLock);
    4800        1804 : }
    4801             : 
    4802             : /*
    4803             :  * ReplaceRoleInInitPriv
    4804             :  *
    4805             :  * Used by shdepReassignOwned to replace mentions of a role in pg_init_privs.
    4806             :  */
    4807             : void
    4808          24 : ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid,
    4809             :                       Oid classid, Oid objid, int32 objsubid)
    4810             : {
    4811             :     Relation    rel;
    4812             :     ScanKeyData key[3];
    4813             :     SysScanDesc scan;
    4814             :     HeapTuple   oldtuple;
    4815             :     Datum       oldAclDatum;
    4816             :     bool        isNull;
    4817             :     Acl        *old_acl;
    4818             :     Acl        *new_acl;
    4819             :     HeapTuple   newtuple;
    4820             :     int         noldmembers;
    4821             :     int         nnewmembers;
    4822             :     Oid        *oldmembers;
    4823             :     Oid        *newmembers;
    4824             : 
    4825             :     /* Search for existing pg_init_privs entry for the target object. */
    4826          24 :     rel = table_open(InitPrivsRelationId, RowExclusiveLock);
    4827             : 
    4828          24 :     ScanKeyInit(&key[0],
    4829             :                 Anum_pg_init_privs_objoid,
    4830             :                 BTEqualStrategyNumber, F_OIDEQ,
    4831             :                 ObjectIdGetDatum(objid));
    4832          24 :     ScanKeyInit(&key[1],
    4833             :                 Anum_pg_init_privs_classoid,
    4834             :                 BTEqualStrategyNumber, F_OIDEQ,
    4835             :                 ObjectIdGetDatum(classid));
    4836          24 :     ScanKeyInit(&key[2],
    4837             :                 Anum_pg_init_privs_objsubid,
    4838             :                 BTEqualStrategyNumber, F_INT4EQ,
    4839             :                 Int32GetDatum(objsubid));
    4840             : 
    4841          24 :     scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
    4842             :                               NULL, 3, key);
    4843             : 
    4844             :     /* There should exist only one entry or none. */
    4845          24 :     oldtuple = systable_getnext(scan);
    4846             : 
    4847          24 :     if (!HeapTupleIsValid(oldtuple))
    4848             :     {
    4849             :         /*
    4850             :          * Hmm, why are we here if there's no entry?  But pack up and go away
    4851             :          * quietly.
    4852             :          */
    4853           0 :         systable_endscan(scan);
    4854           0 :         table_close(rel, RowExclusiveLock);
    4855           0 :         return;
    4856             :     }
    4857             : 
    4858             :     /* Get a writable copy of the existing ACL. */
    4859          24 :     oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4860             :                                RelationGetDescr(rel), &isNull);
    4861             :     Assert(!isNull);
    4862          24 :     old_acl = DatumGetAclPCopy(oldAclDatum);
    4863             : 
    4864             :     /*
    4865             :      * Generate new ACL.  This usage of aclnewowner is a bit off-label when
    4866             :      * oldroleid isn't the owner; but it does the job fine.
    4867             :      */
    4868          24 :     new_acl = aclnewowner(old_acl, oldroleid, newroleid);
    4869             : 
    4870             :     /*
    4871             :      * If we end with an empty ACL, delete the pg_init_privs entry.  (That
    4872             :      * probably can't happen here, but we may as well cover the case.)
    4873             :      */
    4874          24 :     if (new_acl == NULL || ACL_NUM(new_acl) == 0)
    4875             :     {
    4876           0 :         CatalogTupleDelete(rel, &oldtuple->t_self);
    4877             :     }
    4878             :     else
    4879             :     {
    4880          24 :         Datum       values[Natts_pg_init_privs] = {0};
    4881          24 :         bool        nulls[Natts_pg_init_privs] = {0};
    4882          24 :         bool        replaces[Natts_pg_init_privs] = {0};
    4883             : 
    4884             :         /* Update existing entry. */
    4885          24 :         values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    4886          24 :         replaces[Anum_pg_init_privs_initprivs - 1] = true;
    4887             : 
    4888          24 :         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
    4889             :                                      values, nulls, replaces);
    4890          24 :         CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    4891             :     }
    4892             : 
    4893             :     /*
    4894             :      * Update the shared dependency ACL info.
    4895             :      */
    4896          24 :     noldmembers = aclmembers(old_acl, &oldmembers);
    4897          24 :     nnewmembers = aclmembers(new_acl, &newmembers);
    4898             : 
    4899          24 :     updateInitAclDependencies(classid, objid, objsubid,
    4900             :                               noldmembers, oldmembers,
    4901             :                               nnewmembers, newmembers);
    4902             : 
    4903          24 :     systable_endscan(scan);
    4904             : 
    4905             :     /* prevent error when processing objects multiple times */
    4906          24 :     CommandCounterIncrement();
    4907             : 
    4908          24 :     table_close(rel, RowExclusiveLock);
    4909             : }
    4910             : 
    4911             : /*
    4912             :  * RemoveRoleFromInitPriv
    4913             :  *
    4914             :  * Used by shdepDropOwned to remove mentions of a role in pg_init_privs.
    4915             :  */
    4916             : void
    4917          28 : RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
    4918             : {
    4919             :     Relation    rel;
    4920             :     ScanKeyData key[3];
    4921             :     SysScanDesc scan;
    4922             :     HeapTuple   oldtuple;
    4923             :     int         cacheid;
    4924             :     HeapTuple   objtuple;
    4925             :     Oid         ownerId;
    4926             :     Datum       oldAclDatum;
    4927             :     bool        isNull;
    4928             :     Acl        *old_acl;
    4929             :     Acl        *new_acl;
    4930             :     HeapTuple   newtuple;
    4931             :     int         noldmembers;
    4932             :     int         nnewmembers;
    4933             :     Oid        *oldmembers;
    4934             :     Oid        *newmembers;
    4935             : 
    4936             :     /* Search for existing pg_init_privs entry for the target object. */
    4937          28 :     rel = table_open(InitPrivsRelationId, RowExclusiveLock);
    4938             : 
    4939          28 :     ScanKeyInit(&key[0],
    4940             :                 Anum_pg_init_privs_objoid,
    4941             :                 BTEqualStrategyNumber, F_OIDEQ,
    4942             :                 ObjectIdGetDatum(objid));
    4943          28 :     ScanKeyInit(&key[1],
    4944             :                 Anum_pg_init_privs_classoid,
    4945             :                 BTEqualStrategyNumber, F_OIDEQ,
    4946             :                 ObjectIdGetDatum(classid));
    4947          28 :     ScanKeyInit(&key[2],
    4948             :                 Anum_pg_init_privs_objsubid,
    4949             :                 BTEqualStrategyNumber, F_INT4EQ,
    4950             :                 Int32GetDatum(objsubid));
    4951             : 
    4952          28 :     scan = systable_beginscan(rel, InitPrivsObjIndexId, true,
    4953             :                               NULL, 3, key);
    4954             : 
    4955             :     /* There should exist only one entry or none. */
    4956          28 :     oldtuple = systable_getnext(scan);
    4957             : 
    4958          28 :     if (!HeapTupleIsValid(oldtuple))
    4959             :     {
    4960             :         /*
    4961             :          * Hmm, why are we here if there's no entry?  But pack up and go away
    4962             :          * quietly.
    4963             :          */
    4964           0 :         systable_endscan(scan);
    4965           0 :         table_close(rel, RowExclusiveLock);
    4966           0 :         return;
    4967             :     }
    4968             : 
    4969             :     /* Get a writable copy of the existing ACL. */
    4970          28 :     oldAclDatum = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs,
    4971             :                                RelationGetDescr(rel), &isNull);
    4972             :     Assert(!isNull);
    4973          28 :     old_acl = DatumGetAclPCopy(oldAclDatum);
    4974             : 
    4975             :     /*
    4976             :      * We need the members of both old and new ACLs so we can correct the
    4977             :      * shared dependency information.  Collect data before
    4978             :      * merge_acl_with_grant throws away old_acl.
    4979             :      */
    4980          28 :     noldmembers = aclmembers(old_acl, &oldmembers);
    4981             : 
    4982             :     /* Must find out the owner's OID the hard way. */
    4983          28 :     cacheid = get_object_catcache_oid(classid);
    4984          28 :     objtuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objid));
    4985          28 :     if (!HeapTupleIsValid(objtuple))
    4986           0 :         elog(ERROR, "cache lookup failed for %s %u",
    4987             :              get_object_class_descr(classid), objid);
    4988             : 
    4989          28 :     ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
    4990             :                                                       objtuple,
    4991          28 :                                                       get_object_attnum_owner(classid)));
    4992          28 :     ReleaseSysCache(objtuple);
    4993             : 
    4994             :     /*
    4995             :      * Generate new ACL.  Grantor of rights is always the same as the owner.
    4996             :      */
    4997          28 :     if (old_acl != NULL)
    4998          28 :         new_acl = merge_acl_with_grant(old_acl,
    4999             :                                        false,   /* is_grant */
    5000             :                                        false,   /* grant_option */
    5001             :                                        DROP_RESTRICT,
    5002          28 :                                        list_make1_oid(roleid),
    5003             :                                        ACLITEM_ALL_PRIV_BITS,
    5004             :                                        ownerId,
    5005             :                                        ownerId);
    5006             :     else
    5007           0 :         new_acl = NULL;         /* this case shouldn't happen, probably */
    5008             : 
    5009             :     /* If we end with an empty ACL, delete the pg_init_privs entry. */
    5010          28 :     if (new_acl == NULL || ACL_NUM(new_acl) == 0)
    5011             :     {
    5012           0 :         CatalogTupleDelete(rel, &oldtuple->t_self);
    5013             :     }
    5014             :     else
    5015             :     {
    5016          28 :         Datum       values[Natts_pg_init_privs] = {0};
    5017          28 :         bool        nulls[Natts_pg_init_privs] = {0};
    5018          28 :         bool        replaces[Natts_pg_init_privs] = {0};
    5019             : 
    5020             :         /* Update existing entry. */
    5021          28 :         values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl);
    5022          28 :         replaces[Anum_pg_init_privs_initprivs - 1] = true;
    5023             : 
    5024          28 :         newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(rel),
    5025             :                                      values, nulls, replaces);
    5026          28 :         CatalogTupleUpdate(rel, &newtuple->t_self, newtuple);
    5027             :     }
    5028             : 
    5029             :     /*
    5030             :      * Update the shared dependency ACL info.
    5031             :      */
    5032          28 :     nnewmembers = aclmembers(new_acl, &newmembers);
    5033             : 
    5034          28 :     updateInitAclDependencies(classid, objid, objsubid,
    5035             :                               noldmembers, oldmembers,
    5036             :                               nnewmembers, newmembers);
    5037             : 
    5038          28 :     systable_endscan(scan);
    5039             : 
    5040             :     /* prevent error when processing objects multiple times */
    5041          28 :     CommandCounterIncrement();
    5042             : 
    5043          28 :     table_close(rel, RowExclusiveLock);
    5044             : }

Generated by: LCOV version 1.14