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

Generated by: LCOV version 1.14