Header And Logo

PostgreSQL
| The world's most advanced open source database.

aclchk.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * aclchk.c
00004  *    Routines to check access control permissions.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/catalog/aclchk.c
00012  *
00013  * NOTES
00014  *    See acl.h.
00015  *
00016  *-------------------------------------------------------------------------
00017  */
00018 #include "postgres.h"
00019 
00020 #include "access/genam.h"
00021 #include "access/heapam.h"
00022 #include "access/htup_details.h"
00023 #include "access/sysattr.h"
00024 #include "access/xact.h"
00025 #include "catalog/catalog.h"
00026 #include "catalog/dependency.h"
00027 #include "catalog/indexing.h"
00028 #include "catalog/objectaccess.h"
00029 #include "catalog/pg_authid.h"
00030 #include "catalog/pg_collation.h"
00031 #include "catalog/pg_conversion.h"
00032 #include "catalog/pg_database.h"
00033 #include "catalog/pg_default_acl.h"
00034 #include "catalog/pg_event_trigger.h"
00035 #include "catalog/pg_extension.h"
00036 #include "catalog/pg_foreign_data_wrapper.h"
00037 #include "catalog/pg_foreign_server.h"
00038 #include "catalog/pg_language.h"
00039 #include "catalog/pg_largeobject.h"
00040 #include "catalog/pg_largeobject_metadata.h"
00041 #include "catalog/pg_namespace.h"
00042 #include "catalog/pg_opclass.h"
00043 #include "catalog/pg_operator.h"
00044 #include "catalog/pg_opfamily.h"
00045 #include "catalog/pg_proc.h"
00046 #include "catalog/pg_tablespace.h"
00047 #include "catalog/pg_type.h"
00048 #include "catalog/pg_ts_config.h"
00049 #include "catalog/pg_ts_dict.h"
00050 #include "commands/dbcommands.h"
00051 #include "commands/proclang.h"
00052 #include "commands/tablespace.h"
00053 #include "foreign/foreign.h"
00054 #include "miscadmin.h"
00055 #include "nodes/makefuncs.h"
00056 #include "parser/parse_func.h"
00057 #include "parser/parse_type.h"
00058 #include "utils/acl.h"
00059 #include "utils/builtins.h"
00060 #include "utils/fmgroids.h"
00061 #include "utils/lsyscache.h"
00062 #include "utils/rel.h"
00063 #include "utils/syscache.h"
00064 #include "utils/tqual.h"
00065 
00066 
00067 /*
00068  * The information about one Grant/Revoke statement, in internal format: object
00069  * and grantees names have been turned into Oids, the privilege list is an
00070  * AclMode bitmask.  If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
00071  * all_privs is true, 'privileges' will be internally set to the right kind of
00072  * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
00073  * InternalGrant struct!)
00074  *
00075  * Note: 'all_privs' and 'privileges' represent object-level privileges only.
00076  * There might also be column-level privilege specifications, which are
00077  * represented in col_privs (this is a list of untransformed AccessPriv nodes).
00078  * Column privileges are only valid for objtype ACL_OBJECT_RELATION.
00079  */
00080 typedef struct
00081 {
00082     bool        is_grant;
00083     GrantObjectType objtype;
00084     List       *objects;
00085     bool        all_privs;
00086     AclMode     privileges;
00087     List       *col_privs;
00088     List       *grantees;
00089     bool        grant_option;
00090     DropBehavior behavior;
00091 } InternalGrant;
00092 
00093 /*
00094  * Internal format used by ALTER DEFAULT PRIVILEGES.
00095  */
00096 typedef struct
00097 {
00098     Oid         roleid;         /* owning role */
00099     Oid         nspid;          /* namespace, or InvalidOid if none */
00100     /* remaining fields are same as in InternalGrant: */
00101     bool        is_grant;
00102     GrantObjectType objtype;
00103     bool        all_privs;
00104     AclMode     privileges;
00105     List       *grantees;
00106     bool        grant_option;
00107     DropBehavior behavior;
00108 } InternalDefaultACL;
00109 
00110 
00111 static void ExecGrantStmt_oids(InternalGrant *istmt);
00112 static void ExecGrant_Relation(InternalGrant *grantStmt);
00113 static void ExecGrant_Database(InternalGrant *grantStmt);
00114 static void ExecGrant_Fdw(InternalGrant *grantStmt);
00115 static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
00116 static void ExecGrant_Function(InternalGrant *grantStmt);
00117 static void ExecGrant_Language(InternalGrant *grantStmt);
00118 static void ExecGrant_Largeobject(InternalGrant *grantStmt);
00119 static void ExecGrant_Namespace(InternalGrant *grantStmt);
00120 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
00121 static void ExecGrant_Type(InternalGrant *grantStmt);
00122 
00123 static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
00124 static void SetDefaultACL(InternalDefaultACL *iacls);
00125 
00126 static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
00127 static List *objectsInSchemaToOids(GrantObjectType objtype, List *nspnames);
00128 static List *getRelationsInNamespace(Oid namespaceId, char relkind);
00129 static void expand_col_privileges(List *colnames, Oid table_oid,
00130                       AclMode this_privileges,
00131                       AclMode *col_privileges,
00132                       int num_col_privileges);
00133 static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
00134                           AclMode this_privileges,
00135                           AclMode *col_privileges,
00136                           int num_col_privileges);
00137 static AclMode string_to_privilege(const char *privname);
00138 static const char *privilege_to_string(AclMode privilege);
00139 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
00140                          bool all_privs, AclMode privileges,
00141                          Oid objectId, Oid grantorId,
00142                          AclObjectKind objkind, const char *objname,
00143                          AttrNumber att_number, const char *colname);
00144 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
00145            Oid roleid, AclMode mask, AclMaskHow how);
00146 
00147 
00148 #ifdef ACLDEBUG
00149 static void
00150 dumpacl(Acl *acl)
00151 {
00152     int         i;
00153     AclItem    *aip;
00154 
00155     elog(DEBUG2, "acl size = %d, # acls = %d",
00156          ACL_SIZE(acl), ACL_NUM(acl));
00157     aip = ACL_DAT(acl);
00158     for (i = 0; i < ACL_NUM(acl); ++i)
00159         elog(DEBUG2, "  acl[%d]: %s", i,
00160              DatumGetCString(DirectFunctionCall1(aclitemout,
00161                                                  PointerGetDatum(aip + i))));
00162 }
00163 #endif   /* ACLDEBUG */
00164 
00165 
00166 /*
00167  * If is_grant is true, adds the given privileges for the list of
00168  * grantees to the existing old_acl.  If is_grant is false, the
00169  * privileges for the given grantees are removed from old_acl.
00170  *
00171  * NB: the original old_acl is pfree'd.
00172  */
00173 static Acl *
00174 merge_acl_with_grant(Acl *old_acl, bool is_grant,
00175                      bool grant_option, DropBehavior behavior,
00176                      List *grantees, AclMode privileges,
00177                      Oid grantorId, Oid ownerId)
00178 {
00179     unsigned    modechg;
00180     ListCell   *j;
00181     Acl        *new_acl;
00182 
00183     modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
00184 
00185 #ifdef ACLDEBUG
00186     dumpacl(old_acl);
00187 #endif
00188     new_acl = old_acl;
00189 
00190     foreach(j, grantees)
00191     {
00192         AclItem     aclitem;
00193         Acl        *newer_acl;
00194 
00195         aclitem.ai_grantee = lfirst_oid(j);
00196 
00197         /*
00198          * Grant options can only be granted to individual roles, not PUBLIC.
00199          * The reason is that if a user would re-grant a privilege that he
00200          * held through PUBLIC, and later the user is removed, the situation
00201          * is impossible to clean up.
00202          */
00203         if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
00204             ereport(ERROR,
00205                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
00206                      errmsg("grant options can only be granted to roles")));
00207 
00208         aclitem.ai_grantor = grantorId;
00209 
00210         /*
00211          * The asymmetry in the conditions here comes from the spec.  In
00212          * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
00213          * to grant both the basic privilege and its grant option. But in
00214          * REVOKE, plain revoke revokes both the basic privilege and its grant
00215          * option, while REVOKE GRANT OPTION revokes only the option.
00216          */
00217         ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
00218                     (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
00219                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
00220 
00221         newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
00222 
00223         /* avoid memory leak when there are many grantees */
00224         pfree(new_acl);
00225         new_acl = newer_acl;
00226 
00227 #ifdef ACLDEBUG
00228         dumpacl(new_acl);
00229 #endif
00230     }
00231 
00232     return new_acl;
00233 }
00234 
00235 /*
00236  * Restrict the privileges to what we can actually grant, and emit
00237  * the standards-mandated warning and error messages.
00238  */
00239 static AclMode
00240 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
00241                          AclMode privileges, Oid objectId, Oid grantorId,
00242                          AclObjectKind objkind, const char *objname,
00243                          AttrNumber att_number, const char *colname)
00244 {
00245     AclMode     this_privileges;
00246     AclMode     whole_mask;
00247 
00248     switch (objkind)
00249     {
00250         case ACL_KIND_COLUMN:
00251             whole_mask = ACL_ALL_RIGHTS_COLUMN;
00252             break;
00253         case ACL_KIND_CLASS:
00254             whole_mask = ACL_ALL_RIGHTS_RELATION;
00255             break;
00256         case ACL_KIND_SEQUENCE:
00257             whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
00258             break;
00259         case ACL_KIND_DATABASE:
00260             whole_mask = ACL_ALL_RIGHTS_DATABASE;
00261             break;
00262         case ACL_KIND_PROC:
00263             whole_mask = ACL_ALL_RIGHTS_FUNCTION;
00264             break;
00265         case ACL_KIND_LANGUAGE:
00266             whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
00267             break;
00268         case ACL_KIND_LARGEOBJECT:
00269             whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
00270             break;
00271         case ACL_KIND_NAMESPACE:
00272             whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
00273             break;
00274         case ACL_KIND_TABLESPACE:
00275             whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
00276             break;
00277         case ACL_KIND_FDW:
00278             whole_mask = ACL_ALL_RIGHTS_FDW;
00279             break;
00280         case ACL_KIND_FOREIGN_SERVER:
00281             whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
00282             break;
00283         case ACL_KIND_EVENT_TRIGGER:
00284             elog(ERROR, "grantable rights not supported for event triggers");
00285             /* not reached, but keep compiler quiet */
00286             return ACL_NO_RIGHTS;
00287         case ACL_KIND_TYPE:
00288             whole_mask = ACL_ALL_RIGHTS_TYPE;
00289             break;
00290         default:
00291             elog(ERROR, "unrecognized object kind: %d", objkind);
00292             /* not reached, but keep compiler quiet */
00293             return ACL_NO_RIGHTS;
00294     }
00295 
00296     /*
00297      * If we found no grant options, consider whether to issue a hard error.
00298      * Per spec, having any privilege at all on the object will get you by
00299      * here.
00300      */
00301     if (avail_goptions == ACL_NO_RIGHTS)
00302     {
00303         if (pg_aclmask(objkind, objectId, att_number, grantorId,
00304                        whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
00305                        ACLMASK_ANY) == ACL_NO_RIGHTS)
00306         {
00307             if (objkind == ACL_KIND_COLUMN && colname)
00308                 aclcheck_error_col(ACLCHECK_NO_PRIV, objkind, objname, colname);
00309             else
00310                 aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
00311         }
00312     }
00313 
00314     /*
00315      * Restrict the operation to what we can actually grant or revoke, and
00316      * issue a warning if appropriate.  (For REVOKE this isn't quite what the
00317      * spec says to do: the spec seems to want a warning only if no privilege
00318      * bits actually change in the ACL. In practice that behavior seems much
00319      * too noisy, as well as inconsistent with the GRANT case.)
00320      */
00321     this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
00322     if (is_grant)
00323     {
00324         if (this_privileges == 0)
00325         {
00326             if (objkind == ACL_KIND_COLUMN && colname)
00327                 ereport(WARNING,
00328                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
00329                          errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
00330                                 colname, objname)));
00331             else
00332                 ereport(WARNING,
00333                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
00334                          errmsg("no privileges were granted for \"%s\"",
00335                                 objname)));
00336         }
00337         else if (!all_privs && this_privileges != privileges)
00338         {
00339             if (objkind == ACL_KIND_COLUMN && colname)
00340                 ereport(WARNING,
00341                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
00342                          errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
00343                                 colname, objname)));
00344             else
00345                 ereport(WARNING,
00346                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
00347                          errmsg("not all privileges were granted for \"%s\"",
00348                                 objname)));
00349         }
00350     }
00351     else
00352     {
00353         if (this_privileges == 0)
00354         {
00355             if (objkind == ACL_KIND_COLUMN && colname)
00356                 ereport(WARNING,
00357                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
00358                          errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
00359                                 colname, objname)));
00360             else
00361                 ereport(WARNING,
00362                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
00363                          errmsg("no privileges could be revoked for \"%s\"",
00364                                 objname)));
00365         }
00366         else if (!all_privs && this_privileges != privileges)
00367         {
00368             if (objkind == ACL_KIND_COLUMN && colname)
00369                 ereport(WARNING,
00370                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
00371                          errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
00372                                 colname, objname)));
00373             else
00374                 ereport(WARNING,
00375                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
00376                      errmsg("not all privileges could be revoked for \"%s\"",
00377                             objname)));
00378         }
00379     }
00380 
00381     return this_privileges;
00382 }
00383 
00384 /*
00385  * Called to execute the utility commands GRANT and REVOKE
00386  */
00387 void
00388 ExecuteGrantStmt(GrantStmt *stmt)
00389 {
00390     InternalGrant istmt;
00391     ListCell   *cell;
00392     const char *errormsg;
00393     AclMode     all_privileges;
00394 
00395     /*
00396      * Turn the regular GrantStmt into the InternalGrant form.
00397      */
00398     istmt.is_grant = stmt->is_grant;
00399     istmt.objtype = stmt->objtype;
00400 
00401     /* Collect the OIDs of the target objects */
00402     switch (stmt->targtype)
00403     {
00404         case ACL_TARGET_OBJECT:
00405             istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
00406             break;
00407         case ACL_TARGET_ALL_IN_SCHEMA:
00408             istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
00409             break;
00410             /* ACL_TARGET_DEFAULTS should not be seen here */
00411         default:
00412             elog(ERROR, "unrecognized GrantStmt.targtype: %d",
00413                  (int) stmt->targtype);
00414     }
00415 
00416     /* all_privs to be filled below */
00417     /* privileges to be filled below */
00418     istmt.col_privs = NIL;      /* may get filled below */
00419     istmt.grantees = NIL;       /* filled below */
00420     istmt.grant_option = stmt->grant_option;
00421     istmt.behavior = stmt->behavior;
00422 
00423     /*
00424      * Convert the PrivGrantee list into an Oid list.  Note that at this point
00425      * we insert an ACL_ID_PUBLIC into the list if an empty role name is
00426      * detected (which is what the grammar uses if PUBLIC is found), so
00427      * downstream there shouldn't be any additional work needed to support
00428      * this case.
00429      */
00430     foreach(cell, stmt->grantees)
00431     {
00432         PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
00433 
00434         if (grantee->rolname == NULL)
00435             istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
00436         else
00437             istmt.grantees =
00438                 lappend_oid(istmt.grantees,
00439                             get_role_oid(grantee->rolname, false));
00440     }
00441 
00442     /*
00443      * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
00444      * bitmask.  Note: objtype can't be ACL_OBJECT_COLUMN.
00445      */
00446     switch (stmt->objtype)
00447     {
00448             /*
00449              * Because this might be a sequence, we test both relation and
00450              * sequence bits, and later do a more limited test when we know
00451              * the object type.
00452              */
00453         case ACL_OBJECT_RELATION:
00454             all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
00455             errormsg = gettext_noop("invalid privilege type %s for relation");
00456             break;
00457         case ACL_OBJECT_SEQUENCE:
00458             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
00459             errormsg = gettext_noop("invalid privilege type %s for sequence");
00460             break;
00461         case ACL_OBJECT_DATABASE:
00462             all_privileges = ACL_ALL_RIGHTS_DATABASE;
00463             errormsg = gettext_noop("invalid privilege type %s for database");
00464             break;
00465         case ACL_OBJECT_DOMAIN:
00466             all_privileges = ACL_ALL_RIGHTS_TYPE;
00467             errormsg = gettext_noop("invalid privilege type %s for domain");
00468             break;
00469         case ACL_OBJECT_FUNCTION:
00470             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
00471             errormsg = gettext_noop("invalid privilege type %s for function");
00472             break;
00473         case ACL_OBJECT_LANGUAGE:
00474             all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
00475             errormsg = gettext_noop("invalid privilege type %s for language");
00476             break;
00477         case ACL_OBJECT_LARGEOBJECT:
00478             all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
00479             errormsg = gettext_noop("invalid privilege type %s for large object");
00480             break;
00481         case ACL_OBJECT_NAMESPACE:
00482             all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
00483             errormsg = gettext_noop("invalid privilege type %s for schema");
00484             break;
00485         case ACL_OBJECT_TABLESPACE:
00486             all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
00487             errormsg = gettext_noop("invalid privilege type %s for tablespace");
00488             break;
00489         case ACL_OBJECT_TYPE:
00490             all_privileges = ACL_ALL_RIGHTS_TYPE;
00491             errormsg = gettext_noop("invalid privilege type %s for type");
00492             break;
00493         case ACL_OBJECT_FDW:
00494             all_privileges = ACL_ALL_RIGHTS_FDW;
00495             errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
00496             break;
00497         case ACL_OBJECT_FOREIGN_SERVER:
00498             all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
00499             errormsg = gettext_noop("invalid privilege type %s for foreign server");
00500             break;
00501         default:
00502             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
00503                  (int) stmt->objtype);
00504             /* keep compiler quiet */
00505             all_privileges = ACL_NO_RIGHTS;
00506             errormsg = NULL;
00507     }
00508 
00509     if (stmt->privileges == NIL)
00510     {
00511         istmt.all_privs = true;
00512 
00513         /*
00514          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
00515          * depending on the object type
00516          */
00517         istmt.privileges = ACL_NO_RIGHTS;
00518     }
00519     else
00520     {
00521         istmt.all_privs = false;
00522         istmt.privileges = ACL_NO_RIGHTS;
00523 
00524         foreach(cell, stmt->privileges)
00525         {
00526             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
00527             AclMode     priv;
00528 
00529             /*
00530              * If it's a column-level specification, we just set it aside in
00531              * col_privs for the moment; but insist it's for a relation.
00532              */
00533             if (privnode->cols)
00534             {
00535                 if (stmt->objtype != ACL_OBJECT_RELATION)
00536                     ereport(ERROR,
00537                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
00538                              errmsg("column privileges are only valid for relations")));
00539                 istmt.col_privs = lappend(istmt.col_privs, privnode);
00540                 continue;
00541             }
00542 
00543             if (privnode->priv_name == NULL)    /* parser mistake? */
00544                 elog(ERROR, "AccessPriv node must specify privilege or columns");
00545             priv = string_to_privilege(privnode->priv_name);
00546 
00547             if (priv & ~((AclMode) all_privileges))
00548                 ereport(ERROR,
00549                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
00550                          errmsg(errormsg, privilege_to_string(priv))));
00551 
00552             istmt.privileges |= priv;
00553         }
00554     }
00555 
00556     ExecGrantStmt_oids(&istmt);
00557 }
00558 
00559 /*
00560  * ExecGrantStmt_oids
00561  *
00562  * Internal entry point for granting and revoking privileges.
00563  */
00564 static void
00565 ExecGrantStmt_oids(InternalGrant *istmt)
00566 {
00567     switch (istmt->objtype)
00568     {
00569         case ACL_OBJECT_RELATION:
00570         case ACL_OBJECT_SEQUENCE:
00571             ExecGrant_Relation(istmt);
00572             break;
00573         case ACL_OBJECT_DATABASE:
00574             ExecGrant_Database(istmt);
00575             break;
00576         case ACL_OBJECT_DOMAIN:
00577         case ACL_OBJECT_TYPE:
00578             ExecGrant_Type(istmt);
00579             break;
00580         case ACL_OBJECT_FDW:
00581             ExecGrant_Fdw(istmt);
00582             break;
00583         case ACL_OBJECT_FOREIGN_SERVER:
00584             ExecGrant_ForeignServer(istmt);
00585             break;
00586         case ACL_OBJECT_FUNCTION:
00587             ExecGrant_Function(istmt);
00588             break;
00589         case ACL_OBJECT_LANGUAGE:
00590             ExecGrant_Language(istmt);
00591             break;
00592         case ACL_OBJECT_LARGEOBJECT:
00593             ExecGrant_Largeobject(istmt);
00594             break;
00595         case ACL_OBJECT_NAMESPACE:
00596             ExecGrant_Namespace(istmt);
00597             break;
00598         case ACL_OBJECT_TABLESPACE:
00599             ExecGrant_Tablespace(istmt);
00600             break;
00601         default:
00602             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
00603                  (int) istmt->objtype);
00604     }
00605 }
00606 
00607 /*
00608  * objectNamesToOids
00609  *
00610  * Turn a list of object names of a given type into an Oid list.
00611  *
00612  * XXX: This function doesn't take any sort of locks on the objects whose
00613  * names it looks up.  In the face of concurrent DDL, we might easily latch
00614  * onto an old version of an object, causing the GRANT or REVOKE statement
00615  * to fail.
00616  */
00617 static List *
00618 objectNamesToOids(GrantObjectType objtype, List *objnames)
00619 {
00620     List       *objects = NIL;
00621     ListCell   *cell;
00622 
00623     Assert(objnames != NIL);
00624 
00625     switch (objtype)
00626     {
00627         case ACL_OBJECT_RELATION:
00628         case ACL_OBJECT_SEQUENCE:
00629             foreach(cell, objnames)
00630             {
00631                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
00632                 Oid         relOid;
00633 
00634                 relOid = RangeVarGetRelid(relvar, NoLock, false);
00635                 objects = lappend_oid(objects, relOid);
00636             }
00637             break;
00638         case ACL_OBJECT_DATABASE:
00639             foreach(cell, objnames)
00640             {
00641                 char       *dbname = strVal(lfirst(cell));
00642                 Oid         dbid;
00643 
00644                 dbid = get_database_oid(dbname, false);
00645                 objects = lappend_oid(objects, dbid);
00646             }
00647             break;
00648         case ACL_OBJECT_DOMAIN:
00649         case ACL_OBJECT_TYPE:
00650             foreach(cell, objnames)
00651             {
00652                 List       *typname = (List *) lfirst(cell);
00653                 Oid         oid;
00654 
00655                 oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
00656                 objects = lappend_oid(objects, oid);
00657             }
00658             break;
00659         case ACL_OBJECT_FUNCTION:
00660             foreach(cell, objnames)
00661             {
00662                 FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
00663                 Oid         funcid;
00664 
00665                 funcid = LookupFuncNameTypeNames(func->funcname,
00666                                                  func->funcargs, false);
00667                 objects = lappend_oid(objects, funcid);
00668             }
00669             break;
00670         case ACL_OBJECT_LANGUAGE:
00671             foreach(cell, objnames)
00672             {
00673                 char       *langname = strVal(lfirst(cell));
00674                 Oid         oid;
00675 
00676                 oid = get_language_oid(langname, false);
00677                 objects = lappend_oid(objects, oid);
00678             }
00679             break;
00680         case ACL_OBJECT_LARGEOBJECT:
00681             foreach(cell, objnames)
00682             {
00683                 Oid         lobjOid = oidparse(lfirst(cell));
00684 
00685                 if (!LargeObjectExists(lobjOid))
00686                     ereport(ERROR,
00687                             (errcode(ERRCODE_UNDEFINED_OBJECT),
00688                              errmsg("large object %u does not exist",
00689                                     lobjOid)));
00690 
00691                 objects = lappend_oid(objects, lobjOid);
00692             }
00693             break;
00694         case ACL_OBJECT_NAMESPACE:
00695             foreach(cell, objnames)
00696             {
00697                 char       *nspname = strVal(lfirst(cell));
00698                 Oid         oid;
00699 
00700                 oid = get_namespace_oid(nspname, false);
00701                 objects = lappend_oid(objects, oid);
00702             }
00703             break;
00704         case ACL_OBJECT_TABLESPACE:
00705             foreach(cell, objnames)
00706             {
00707                 char       *spcname = strVal(lfirst(cell));
00708                 Oid         spcoid;
00709 
00710                 spcoid = get_tablespace_oid(spcname, false);
00711                 objects = lappend_oid(objects, spcoid);
00712             }
00713             break;
00714         case ACL_OBJECT_FDW:
00715             foreach(cell, objnames)
00716             {
00717                 char       *fdwname = strVal(lfirst(cell));
00718                 Oid         fdwid = get_foreign_data_wrapper_oid(fdwname, false);
00719 
00720                 objects = lappend_oid(objects, fdwid);
00721             }
00722             break;
00723         case ACL_OBJECT_FOREIGN_SERVER:
00724             foreach(cell, objnames)
00725             {
00726                 char       *srvname = strVal(lfirst(cell));
00727                 Oid         srvid = get_foreign_server_oid(srvname, false);
00728 
00729                 objects = lappend_oid(objects, srvid);
00730             }
00731             break;
00732         default:
00733             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
00734                  (int) objtype);
00735     }
00736 
00737     return objects;
00738 }
00739 
00740 /*
00741  * objectsInSchemaToOids
00742  *
00743  * Find all objects of a given type in specified schemas, and make a list
00744  * of their Oids.  We check USAGE privilege on the schemas, but there is
00745  * no privilege checking on the individual objects here.
00746  */
00747 static List *
00748 objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
00749 {
00750     List       *objects = NIL;
00751     ListCell   *cell;
00752 
00753     foreach(cell, nspnames)
00754     {
00755         char       *nspname = strVal(lfirst(cell));
00756         Oid         namespaceId;
00757         List       *objs;
00758 
00759         namespaceId = LookupExplicitNamespace(nspname, false);
00760 
00761         switch (objtype)
00762         {
00763             case ACL_OBJECT_RELATION:
00764                 /* Process regular tables, views and foreign tables */
00765                 objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
00766                 objects = list_concat(objects, objs);
00767                 objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
00768                 objects = list_concat(objects, objs);
00769                 objs = getRelationsInNamespace(namespaceId, RELKIND_MATVIEW);
00770                 objects = list_concat(objects, objs);
00771                 objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
00772                 objects = list_concat(objects, objs);
00773                 break;
00774             case ACL_OBJECT_SEQUENCE:
00775                 objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
00776                 objects = list_concat(objects, objs);
00777                 break;
00778             case ACL_OBJECT_FUNCTION:
00779                 {
00780                     ScanKeyData key[1];
00781                     Relation    rel;
00782                     HeapScanDesc scan;
00783                     HeapTuple   tuple;
00784 
00785                     ScanKeyInit(&key[0],
00786                                 Anum_pg_proc_pronamespace,
00787                                 BTEqualStrategyNumber, F_OIDEQ,
00788                                 ObjectIdGetDatum(namespaceId));
00789 
00790                     rel = heap_open(ProcedureRelationId, AccessShareLock);
00791                     scan = heap_beginscan(rel, SnapshotNow, 1, key);
00792 
00793                     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00794                     {
00795                         objects = lappend_oid(objects, HeapTupleGetOid(tuple));
00796                     }
00797 
00798                     heap_endscan(scan);
00799                     heap_close(rel, AccessShareLock);
00800                 }
00801                 break;
00802             default:
00803                 /* should not happen */
00804                 elog(ERROR, "unrecognized GrantStmt.objtype: %d",
00805                      (int) objtype);
00806         }
00807     }
00808 
00809     return objects;
00810 }
00811 
00812 /*
00813  * getRelationsInNamespace
00814  *
00815  * Return Oid list of relations in given namespace filtered by relation kind
00816  */
00817 static List *
00818 getRelationsInNamespace(Oid namespaceId, char relkind)
00819 {
00820     List       *relations = NIL;
00821     ScanKeyData key[2];
00822     Relation    rel;
00823     HeapScanDesc scan;
00824     HeapTuple   tuple;
00825 
00826     ScanKeyInit(&key[0],
00827                 Anum_pg_class_relnamespace,
00828                 BTEqualStrategyNumber, F_OIDEQ,
00829                 ObjectIdGetDatum(namespaceId));
00830     ScanKeyInit(&key[1],
00831                 Anum_pg_class_relkind,
00832                 BTEqualStrategyNumber, F_CHAREQ,
00833                 CharGetDatum(relkind));
00834 
00835     rel = heap_open(RelationRelationId, AccessShareLock);
00836     scan = heap_beginscan(rel, SnapshotNow, 2, key);
00837 
00838     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00839     {
00840         relations = lappend_oid(relations, HeapTupleGetOid(tuple));
00841     }
00842 
00843     heap_endscan(scan);
00844     heap_close(rel, AccessShareLock);
00845 
00846     return relations;
00847 }
00848 
00849 
00850 /*
00851  * ALTER DEFAULT PRIVILEGES statement
00852  */
00853 void
00854 ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
00855 {
00856     GrantStmt  *action = stmt->action;
00857     InternalDefaultACL iacls;
00858     ListCell   *cell;
00859     List       *rolenames = NIL;
00860     List       *nspnames = NIL;
00861     DefElem    *drolenames = NULL;
00862     DefElem    *dnspnames = NULL;
00863     AclMode     all_privileges;
00864     const char *errormsg;
00865 
00866     /* Deconstruct the "options" part of the statement */
00867     foreach(cell, stmt->options)
00868     {
00869         DefElem    *defel = (DefElem *) lfirst(cell);
00870 
00871         if (strcmp(defel->defname, "schemas") == 0)
00872         {
00873             if (dnspnames)
00874                 ereport(ERROR,
00875                         (errcode(ERRCODE_SYNTAX_ERROR),
00876                          errmsg("conflicting or redundant options")));
00877             dnspnames = defel;
00878         }
00879         else if (strcmp(defel->defname, "roles") == 0)
00880         {
00881             if (drolenames)
00882                 ereport(ERROR,
00883                         (errcode(ERRCODE_SYNTAX_ERROR),
00884                          errmsg("conflicting or redundant options")));
00885             drolenames = defel;
00886         }
00887         else
00888             elog(ERROR, "option \"%s\" not recognized", defel->defname);
00889     }
00890 
00891     if (dnspnames)
00892         nspnames = (List *) dnspnames->arg;
00893     if (drolenames)
00894         rolenames = (List *) drolenames->arg;
00895 
00896     /* Prepare the InternalDefaultACL representation of the statement */
00897     /* roleid to be filled below */
00898     /* nspid to be filled in SetDefaultACLsInSchemas */
00899     iacls.is_grant = action->is_grant;
00900     iacls.objtype = action->objtype;
00901     /* all_privs to be filled below */
00902     /* privileges to be filled below */
00903     iacls.grantees = NIL;       /* filled below */
00904     iacls.grant_option = action->grant_option;
00905     iacls.behavior = action->behavior;
00906 
00907     /*
00908      * Convert the PrivGrantee list into an Oid list.  Note that at this point
00909      * we insert an ACL_ID_PUBLIC into the list if an empty role name is
00910      * detected (which is what the grammar uses if PUBLIC is found), so
00911      * downstream there shouldn't be any additional work needed to support
00912      * this case.
00913      */
00914     foreach(cell, action->grantees)
00915     {
00916         PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
00917 
00918         if (grantee->rolname == NULL)
00919             iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
00920         else
00921             iacls.grantees =
00922                 lappend_oid(iacls.grantees,
00923                             get_role_oid(grantee->rolname, false));
00924     }
00925 
00926     /*
00927      * Convert action->privileges, a list of privilege strings, into an
00928      * AclMode bitmask.
00929      */
00930     switch (action->objtype)
00931     {
00932         case ACL_OBJECT_RELATION:
00933             all_privileges = ACL_ALL_RIGHTS_RELATION;
00934             errormsg = gettext_noop("invalid privilege type %s for relation");
00935             break;
00936         case ACL_OBJECT_SEQUENCE:
00937             all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
00938             errormsg = gettext_noop("invalid privilege type %s for sequence");
00939             break;
00940         case ACL_OBJECT_FUNCTION:
00941             all_privileges = ACL_ALL_RIGHTS_FUNCTION;
00942             errormsg = gettext_noop("invalid privilege type %s for function");
00943             break;
00944         case ACL_OBJECT_TYPE:
00945             all_privileges = ACL_ALL_RIGHTS_TYPE;
00946             errormsg = gettext_noop("invalid privilege type %s for type");
00947             break;
00948         default:
00949             elog(ERROR, "unrecognized GrantStmt.objtype: %d",
00950                  (int) action->objtype);
00951             /* keep compiler quiet */
00952             all_privileges = ACL_NO_RIGHTS;
00953             errormsg = NULL;
00954     }
00955 
00956     if (action->privileges == NIL)
00957     {
00958         iacls.all_privs = true;
00959 
00960         /*
00961          * will be turned into ACL_ALL_RIGHTS_* by the internal routines
00962          * depending on the object type
00963          */
00964         iacls.privileges = ACL_NO_RIGHTS;
00965     }
00966     else
00967     {
00968         iacls.all_privs = false;
00969         iacls.privileges = ACL_NO_RIGHTS;
00970 
00971         foreach(cell, action->privileges)
00972         {
00973             AccessPriv *privnode = (AccessPriv *) lfirst(cell);
00974             AclMode     priv;
00975 
00976             if (privnode->cols)
00977                 ereport(ERROR,
00978                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
00979                     errmsg("default privileges cannot be set for columns")));
00980 
00981             if (privnode->priv_name == NULL)    /* parser mistake? */
00982                 elog(ERROR, "AccessPriv node must specify privilege");
00983             priv = string_to_privilege(privnode->priv_name);
00984 
00985             if (priv & ~((AclMode) all_privileges))
00986                 ereport(ERROR,
00987                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
00988                          errmsg(errormsg, privilege_to_string(priv))));
00989 
00990             iacls.privileges |= priv;
00991         }
00992     }
00993 
00994     if (rolenames == NIL)
00995     {
00996         /* Set permissions for myself */
00997         iacls.roleid = GetUserId();
00998 
00999         SetDefaultACLsInSchemas(&iacls, nspnames);
01000     }
01001     else
01002     {
01003         /* Look up the role OIDs and do permissions checks */
01004         ListCell   *rolecell;
01005 
01006         foreach(rolecell, rolenames)
01007         {
01008             char       *rolename = strVal(lfirst(rolecell));
01009 
01010             iacls.roleid = get_role_oid(rolename, false);
01011 
01012             /*
01013              * We insist that calling user be a member of each target role. If
01014              * he has that, he could become that role anyway via SET ROLE, so
01015              * FOR ROLE is just a syntactic convenience and doesn't give any
01016              * special privileges.
01017              */
01018             check_is_member_of_role(GetUserId(), iacls.roleid);
01019 
01020             SetDefaultACLsInSchemas(&iacls, nspnames);
01021         }
01022     }
01023 }
01024 
01025 /*
01026  * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
01027  *
01028  * All fields of *iacls except nspid were filled already
01029  */
01030 static void
01031 SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
01032 {
01033     if (nspnames == NIL)
01034     {
01035         /* Set database-wide permissions if no schema was specified */
01036         iacls->nspid = InvalidOid;
01037 
01038         SetDefaultACL(iacls);
01039     }
01040     else
01041     {
01042         /* Look up the schema OIDs and do permissions checks */
01043         ListCell   *nspcell;
01044 
01045         foreach(nspcell, nspnames)
01046         {
01047             char       *nspname = strVal(lfirst(nspcell));
01048             AclResult   aclresult;
01049 
01050             /*
01051              * Note that we must do the permissions check against the target
01052              * role not the calling user.  We require CREATE privileges, since
01053              * without CREATE you won't be able to do anything using the
01054              * default privs anyway.
01055              */
01056             iacls->nspid = get_namespace_oid(nspname, false);
01057 
01058             aclresult = pg_namespace_aclcheck(iacls->nspid, iacls->roleid,
01059                                               ACL_CREATE);
01060             if (aclresult != ACLCHECK_OK)
01061                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
01062                                nspname);
01063 
01064             SetDefaultACL(iacls);
01065         }
01066     }
01067 }
01068 
01069 
01070 /*
01071  * Create or update a pg_default_acl entry
01072  */
01073 static void
01074 SetDefaultACL(InternalDefaultACL *iacls)
01075 {
01076     AclMode     this_privileges = iacls->privileges;
01077     char        objtype;
01078     Relation    rel;
01079     HeapTuple   tuple;
01080     bool        isNew;
01081     Acl        *def_acl;
01082     Acl        *old_acl;
01083     Acl        *new_acl;
01084     HeapTuple   newtuple;
01085     Datum       values[Natts_pg_default_acl];
01086     bool        nulls[Natts_pg_default_acl];
01087     bool        replaces[Natts_pg_default_acl];
01088     int         noldmembers;
01089     int         nnewmembers;
01090     Oid        *oldmembers;
01091     Oid        *newmembers;
01092 
01093     rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
01094 
01095     /*
01096      * The default for a global entry is the hard-wired default ACL for the
01097      * particular object type.  The default for non-global entries is an empty
01098      * ACL.  This must be so because global entries replace the hard-wired
01099      * defaults, while others are added on.
01100      */
01101     if (!OidIsValid(iacls->nspid))
01102         def_acl = acldefault(iacls->objtype, iacls->roleid);
01103     else
01104         def_acl = make_empty_acl();
01105 
01106     /*
01107      * Convert ACL object type to pg_default_acl object type and handle
01108      * all_privs option
01109      */
01110     switch (iacls->objtype)
01111     {
01112         case ACL_OBJECT_RELATION:
01113             objtype = DEFACLOBJ_RELATION;
01114             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
01115                 this_privileges = ACL_ALL_RIGHTS_RELATION;
01116             break;
01117 
01118         case ACL_OBJECT_SEQUENCE:
01119             objtype = DEFACLOBJ_SEQUENCE;
01120             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
01121                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
01122             break;
01123 
01124         case ACL_OBJECT_FUNCTION:
01125             objtype = DEFACLOBJ_FUNCTION;
01126             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
01127                 this_privileges = ACL_ALL_RIGHTS_FUNCTION;
01128             break;
01129 
01130         case ACL_OBJECT_TYPE:
01131             objtype = DEFACLOBJ_TYPE;
01132             if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
01133                 this_privileges = ACL_ALL_RIGHTS_TYPE;
01134             break;
01135 
01136         default:
01137             elog(ERROR, "unrecognized objtype: %d",
01138                  (int) iacls->objtype);
01139             objtype = 0;        /* keep compiler quiet */
01140             break;
01141     }
01142 
01143     /* Search for existing row for this object type in catalog */
01144     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
01145                             ObjectIdGetDatum(iacls->roleid),
01146                             ObjectIdGetDatum(iacls->nspid),
01147                             CharGetDatum(objtype));
01148 
01149     if (HeapTupleIsValid(tuple))
01150     {
01151         Datum       aclDatum;
01152         bool        isNull;
01153 
01154         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
01155                                    Anum_pg_default_acl_defaclacl,
01156                                    &isNull);
01157         if (!isNull)
01158             old_acl = DatumGetAclPCopy(aclDatum);
01159         else
01160             old_acl = NULL;     /* this case shouldn't happen, probably */
01161         isNew = false;
01162     }
01163     else
01164     {
01165         old_acl = NULL;
01166         isNew = true;
01167     }
01168 
01169     if (old_acl != NULL)
01170     {
01171         /*
01172          * We need the members of both old and new ACLs so we can correct the
01173          * shared dependency information.  Collect data before
01174          * merge_acl_with_grant throws away old_acl.
01175          */
01176         noldmembers = aclmembers(old_acl, &oldmembers);
01177     }
01178     else
01179     {
01180         /* If no or null entry, start with the default ACL value */
01181         old_acl = aclcopy(def_acl);
01182         /* There are no old member roles according to the catalogs */
01183         noldmembers = 0;
01184         oldmembers = NULL;
01185     }
01186 
01187     /*
01188      * Generate new ACL.  Grantor of rights is always the same as the target
01189      * role.
01190      */
01191     new_acl = merge_acl_with_grant(old_acl,
01192                                    iacls->is_grant,
01193                                    iacls->grant_option,
01194                                    iacls->behavior,
01195                                    iacls->grantees,
01196                                    this_privileges,
01197                                    iacls->roleid,
01198                                    iacls->roleid);
01199 
01200     /*
01201      * If the result is the same as the default value, we do not need an
01202      * explicit pg_default_acl entry, and should in fact remove the entry if
01203      * it exists.  Must sort both arrays to compare properly.
01204      */
01205     aclitemsort(new_acl);
01206     aclitemsort(def_acl);
01207     if (aclequal(new_acl, def_acl))
01208     {
01209         /* delete old entry, if indeed there is one */
01210         if (!isNew)
01211         {
01212             ObjectAddress myself;
01213 
01214             /*
01215              * The dependency machinery will take care of removing all
01216              * associated dependency entries.  We use DROP_RESTRICT since
01217              * there shouldn't be anything depending on this entry.
01218              */
01219             myself.classId = DefaultAclRelationId;
01220             myself.objectId = HeapTupleGetOid(tuple);
01221             myself.objectSubId = 0;
01222 
01223             performDeletion(&myself, DROP_RESTRICT, 0);
01224         }
01225     }
01226     else
01227     {
01228         /* Prepare to insert or update pg_default_acl entry */
01229         MemSet(values, 0, sizeof(values));
01230         MemSet(nulls, false, sizeof(nulls));
01231         MemSet(replaces, false, sizeof(replaces));
01232 
01233         if (isNew)
01234         {
01235             /* insert new entry */
01236             values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
01237             values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
01238             values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
01239             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
01240 
01241             newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
01242             simple_heap_insert(rel, newtuple);
01243         }
01244         else
01245         {
01246             /* update existing entry */
01247             values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
01248             replaces[Anum_pg_default_acl_defaclacl - 1] = true;
01249 
01250             newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
01251                                          values, nulls, replaces);
01252             simple_heap_update(rel, &newtuple->t_self, newtuple);
01253         }
01254 
01255         /* keep the catalog indexes up to date */
01256         CatalogUpdateIndexes(rel, newtuple);
01257 
01258         /* these dependencies don't change in an update */
01259         if (isNew)
01260         {
01261             /* dependency on role */
01262             recordDependencyOnOwner(DefaultAclRelationId,
01263                                     HeapTupleGetOid(newtuple),
01264                                     iacls->roleid);
01265 
01266             /* dependency on namespace */
01267             if (OidIsValid(iacls->nspid))
01268             {
01269                 ObjectAddress myself,
01270                             referenced;
01271 
01272                 myself.classId = DefaultAclRelationId;
01273                 myself.objectId = HeapTupleGetOid(newtuple);
01274                 myself.objectSubId = 0;
01275 
01276                 referenced.classId = NamespaceRelationId;
01277                 referenced.objectId = iacls->nspid;
01278                 referenced.objectSubId = 0;
01279 
01280                 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
01281             }
01282         }
01283 
01284         /*
01285          * Update the shared dependency ACL info
01286          */
01287         nnewmembers = aclmembers(new_acl, &newmembers);
01288 
01289         updateAclDependencies(DefaultAclRelationId,
01290                               HeapTupleGetOid(newtuple), 0,
01291                               iacls->roleid,
01292                               noldmembers, oldmembers,
01293                               nnewmembers, newmembers);
01294 
01295         if (isNew)
01296             InvokeObjectPostCreateHook(DefaultAclRelationId,
01297                                        HeapTupleGetOid(newtuple), 0);
01298         else
01299             InvokeObjectPostAlterHook(DefaultAclRelationId,
01300                                       HeapTupleGetOid(newtuple), 0);
01301     }
01302 
01303     if (HeapTupleIsValid(tuple))
01304         ReleaseSysCache(tuple);
01305 
01306     heap_close(rel, RowExclusiveLock);
01307 }
01308 
01309 
01310 /*
01311  * RemoveRoleFromObjectACL
01312  *
01313  * Used by shdepDropOwned to remove mentions of a role in ACLs
01314  */
01315 void
01316 RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
01317 {
01318     if (classid == DefaultAclRelationId)
01319     {
01320         InternalDefaultACL iacls;
01321         Form_pg_default_acl pg_default_acl_tuple;
01322         Relation    rel;
01323         ScanKeyData skey[1];
01324         SysScanDesc scan;
01325         HeapTuple   tuple;
01326 
01327         /* first fetch info needed by SetDefaultACL */
01328         rel = heap_open(DefaultAclRelationId, AccessShareLock);
01329 
01330         ScanKeyInit(&skey[0],
01331                     ObjectIdAttributeNumber,
01332                     BTEqualStrategyNumber, F_OIDEQ,
01333                     ObjectIdGetDatum(objid));
01334 
01335         scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
01336                                   SnapshotNow, 1, skey);
01337 
01338         tuple = systable_getnext(scan);
01339 
01340         if (!HeapTupleIsValid(tuple))
01341             elog(ERROR, "could not find tuple for default ACL %u", objid);
01342 
01343         pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
01344 
01345         iacls.roleid = pg_default_acl_tuple->defaclrole;
01346         iacls.nspid = pg_default_acl_tuple->defaclnamespace;
01347 
01348         switch (pg_default_acl_tuple->defaclobjtype)
01349         {
01350             case DEFACLOBJ_RELATION:
01351                 iacls.objtype = ACL_OBJECT_RELATION;
01352                 break;
01353             case DEFACLOBJ_SEQUENCE:
01354                 iacls.objtype = ACL_OBJECT_SEQUENCE;
01355                 break;
01356             case DEFACLOBJ_FUNCTION:
01357                 iacls.objtype = ACL_OBJECT_FUNCTION;
01358                 break;
01359             case DEFACLOBJ_TYPE:
01360                 iacls.objtype = ACL_OBJECT_TYPE;
01361                 break;
01362             default:
01363                 /* Shouldn't get here */
01364                 elog(ERROR, "unexpected default ACL type: %d",
01365                      (int) pg_default_acl_tuple->defaclobjtype);
01366                 break;
01367         }
01368 
01369         systable_endscan(scan);
01370         heap_close(rel, AccessShareLock);
01371 
01372         iacls.is_grant = false;
01373         iacls.all_privs = true;
01374         iacls.privileges = ACL_NO_RIGHTS;
01375         iacls.grantees = list_make1_oid(roleid);
01376         iacls.grant_option = false;
01377         iacls.behavior = DROP_CASCADE;
01378 
01379         /* Do it */
01380         SetDefaultACL(&iacls);
01381     }
01382     else
01383     {
01384         InternalGrant istmt;
01385 
01386         switch (classid)
01387         {
01388             case RelationRelationId:
01389                 /* it's OK to use RELATION for a sequence */
01390                 istmt.objtype = ACL_OBJECT_RELATION;
01391                 break;
01392             case DatabaseRelationId:
01393                 istmt.objtype = ACL_OBJECT_DATABASE;
01394                 break;
01395             case TypeRelationId:
01396                 istmt.objtype = ACL_OBJECT_TYPE;
01397                 break;
01398             case ProcedureRelationId:
01399                 istmt.objtype = ACL_OBJECT_FUNCTION;
01400                 break;
01401             case LanguageRelationId:
01402                 istmt.objtype = ACL_OBJECT_LANGUAGE;
01403                 break;
01404             case LargeObjectRelationId:
01405                 istmt.objtype = ACL_OBJECT_LARGEOBJECT;
01406                 break;
01407             case NamespaceRelationId:
01408                 istmt.objtype = ACL_OBJECT_NAMESPACE;
01409                 break;
01410             case TableSpaceRelationId:
01411                 istmt.objtype = ACL_OBJECT_TABLESPACE;
01412                 break;
01413             case ForeignServerRelationId:
01414                 istmt.objtype = ACL_OBJECT_FOREIGN_SERVER;
01415                 break;
01416             case ForeignDataWrapperRelationId:
01417                 istmt.objtype = ACL_OBJECT_FDW;
01418                 break;
01419             default:
01420                 elog(ERROR, "unexpected object class %u", classid);
01421                 break;
01422         }
01423         istmt.is_grant = false;
01424         istmt.objects = list_make1_oid(objid);
01425         istmt.all_privs = true;
01426         istmt.privileges = ACL_NO_RIGHTS;
01427         istmt.col_privs = NIL;
01428         istmt.grantees = list_make1_oid(roleid);
01429         istmt.grant_option = false;
01430         istmt.behavior = DROP_CASCADE;
01431 
01432         ExecGrantStmt_oids(&istmt);
01433     }
01434 }
01435 
01436 
01437 /*
01438  * Remove a pg_default_acl entry
01439  */
01440 void
01441 RemoveDefaultACLById(Oid defaclOid)
01442 {
01443     Relation    rel;
01444     ScanKeyData skey[1];
01445     SysScanDesc scan;
01446     HeapTuple   tuple;
01447 
01448     rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
01449 
01450     ScanKeyInit(&skey[0],
01451                 ObjectIdAttributeNumber,
01452                 BTEqualStrategyNumber, F_OIDEQ,
01453                 ObjectIdGetDatum(defaclOid));
01454 
01455     scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
01456                               SnapshotNow, 1, skey);
01457 
01458     tuple = systable_getnext(scan);
01459 
01460     if (!HeapTupleIsValid(tuple))
01461         elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
01462 
01463     simple_heap_delete(rel, &tuple->t_self);
01464 
01465     systable_endscan(scan);
01466     heap_close(rel, RowExclusiveLock);
01467 }
01468 
01469 
01470 /*
01471  * expand_col_privileges
01472  *
01473  * OR the specified privilege(s) into per-column array entries for each
01474  * specified attribute.  The per-column array is indexed starting at
01475  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
01476  */
01477 static void
01478 expand_col_privileges(List *colnames, Oid table_oid,
01479                       AclMode this_privileges,
01480                       AclMode *col_privileges,
01481                       int num_col_privileges)
01482 {
01483     ListCell   *cell;
01484 
01485     foreach(cell, colnames)
01486     {
01487         char       *colname = strVal(lfirst(cell));
01488         AttrNumber  attnum;
01489 
01490         attnum = get_attnum(table_oid, colname);
01491         if (attnum == InvalidAttrNumber)
01492             ereport(ERROR,
01493                     (errcode(ERRCODE_UNDEFINED_COLUMN),
01494                      errmsg("column \"%s\" of relation \"%s\" does not exist",
01495                             colname, get_rel_name(table_oid))));
01496         attnum -= FirstLowInvalidHeapAttributeNumber;
01497         if (attnum <= 0 || attnum >= num_col_privileges)
01498             elog(ERROR, "column number out of range");  /* safety check */
01499         col_privileges[attnum] |= this_privileges;
01500     }
01501 }
01502 
01503 /*
01504  * expand_all_col_privileges
01505  *
01506  * OR the specified privilege(s) into per-column array entries for each valid
01507  * attribute of a relation.  The per-column array is indexed starting at
01508  * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
01509  */
01510 static void
01511 expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
01512                           AclMode this_privileges,
01513                           AclMode *col_privileges,
01514                           int num_col_privileges)
01515 {
01516     AttrNumber  curr_att;
01517 
01518     Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
01519     for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
01520          curr_att <= classForm->relnatts;
01521          curr_att++)
01522     {
01523         HeapTuple   attTuple;
01524         bool        isdropped;
01525 
01526         if (curr_att == InvalidAttrNumber)
01527             continue;
01528 
01529         /* Skip OID column if it doesn't exist */
01530         if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids)
01531             continue;
01532 
01533         /* Views don't have any system columns at all */
01534         if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
01535             continue;
01536 
01537         attTuple = SearchSysCache2(ATTNUM,
01538                                    ObjectIdGetDatum(table_oid),
01539                                    Int16GetDatum(curr_att));
01540         if (!HeapTupleIsValid(attTuple))
01541             elog(ERROR, "cache lookup failed for attribute %d of relation %u",
01542                  curr_att, table_oid);
01543 
01544         isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
01545 
01546         ReleaseSysCache(attTuple);
01547 
01548         /* ignore dropped columns */
01549         if (isdropped)
01550             continue;
01551 
01552         col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
01553     }
01554 }
01555 
01556 /*
01557  *  This processes attributes, but expects to be called from
01558  *  ExecGrant_Relation, not directly from ExecGrantStmt.
01559  */
01560 static void
01561 ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
01562                     AttrNumber attnum, Oid ownerId, AclMode col_privileges,
01563                     Relation attRelation, const Acl *old_rel_acl)
01564 {
01565     HeapTuple   attr_tuple;
01566     Form_pg_attribute pg_attribute_tuple;
01567     Acl        *old_acl;
01568     Acl        *new_acl;
01569     Acl        *merged_acl;
01570     Datum       aclDatum;
01571     bool        isNull;
01572     Oid         grantorId;
01573     AclMode     avail_goptions;
01574     bool        need_update;
01575     HeapTuple   newtuple;
01576     Datum       values[Natts_pg_attribute];
01577     bool        nulls[Natts_pg_attribute];
01578     bool        replaces[Natts_pg_attribute];
01579     int         noldmembers;
01580     int         nnewmembers;
01581     Oid        *oldmembers;
01582     Oid        *newmembers;
01583 
01584     attr_tuple = SearchSysCache2(ATTNUM,
01585                                  ObjectIdGetDatum(relOid),
01586                                  Int16GetDatum(attnum));
01587     if (!HeapTupleIsValid(attr_tuple))
01588         elog(ERROR, "cache lookup failed for attribute %d of relation %u",
01589              attnum, relOid);
01590     pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
01591 
01592     /*
01593      * Get working copy of existing ACL. If there's no ACL, substitute the
01594      * proper default.
01595      */
01596     aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
01597                                &isNull);
01598     if (isNull)
01599     {
01600         old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId);
01601         /* There are no old member roles according to the catalogs */
01602         noldmembers = 0;
01603         oldmembers = NULL;
01604     }
01605     else
01606     {
01607         old_acl = DatumGetAclPCopy(aclDatum);
01608         /* Get the roles mentioned in the existing ACL */
01609         noldmembers = aclmembers(old_acl, &oldmembers);
01610     }
01611 
01612     /*
01613      * In select_best_grantor we should consider existing table-level ACL bits
01614      * as well as the per-column ACL.  Build a new ACL that is their
01615      * concatenation.  (This is a bit cheap and dirty compared to merging them
01616      * properly with no duplications, but it's all we need here.)
01617      */
01618     merged_acl = aclconcat(old_rel_acl, old_acl);
01619 
01620     /* Determine ID to do the grant as, and available grant options */
01621     select_best_grantor(GetUserId(), col_privileges,
01622                         merged_acl, ownerId,
01623                         &grantorId, &avail_goptions);
01624 
01625     pfree(merged_acl);
01626 
01627     /*
01628      * Restrict the privileges to what we can actually grant, and emit the
01629      * standards-mandated warning and error messages.  Note: we don't track
01630      * whether the user actually used the ALL PRIVILEGES(columns) syntax for
01631      * each column; we just approximate it by whether all the possible
01632      * privileges are specified now.  Since the all_privs flag only determines
01633      * whether a warning is issued, this seems close enough.
01634      */
01635     col_privileges =
01636         restrict_and_check_grant(istmt->is_grant, avail_goptions,
01637                                  (col_privileges == ACL_ALL_RIGHTS_COLUMN),
01638                                  col_privileges,
01639                                  relOid, grantorId, ACL_KIND_COLUMN,
01640                                  relname, attnum,
01641                                  NameStr(pg_attribute_tuple->attname));
01642 
01643     /*
01644      * Generate new ACL.
01645      */
01646     new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
01647                                    istmt->grant_option,
01648                                    istmt->behavior, istmt->grantees,
01649                                    col_privileges, grantorId,
01650                                    ownerId);
01651 
01652     /*
01653      * We need the members of both old and new ACLs so we can correct the
01654      * shared dependency information.
01655      */
01656     nnewmembers = aclmembers(new_acl, &newmembers);
01657 
01658     /* finished building new ACL value, now insert it */
01659     MemSet(values, 0, sizeof(values));
01660     MemSet(nulls, false, sizeof(nulls));
01661     MemSet(replaces, false, sizeof(replaces));
01662 
01663     /*
01664      * If the updated ACL is empty, we can set attacl to null, and maybe even
01665      * avoid an update of the pg_attribute row.  This is worth testing because
01666      * we'll come through here multiple times for any relation-level REVOKE,
01667      * even if there were never any column GRANTs.  Note we are assuming that
01668      * the "default" ACL state for columns is empty.
01669      */
01670     if (ACL_NUM(new_acl) > 0)
01671     {
01672         values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
01673         need_update = true;
01674     }
01675     else
01676     {
01677         nulls[Anum_pg_attribute_attacl - 1] = true;
01678         need_update = !isNull;
01679     }
01680     replaces[Anum_pg_attribute_attacl - 1] = true;
01681 
01682     if (need_update)
01683     {
01684         newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
01685                                      values, nulls, replaces);
01686 
01687         simple_heap_update(attRelation, &newtuple->t_self, newtuple);
01688 
01689         /* keep the catalog indexes up to date */
01690         CatalogUpdateIndexes(attRelation, newtuple);
01691 
01692         /* Update the shared dependency ACL info */
01693         updateAclDependencies(RelationRelationId, relOid, attnum,
01694                               ownerId,
01695                               noldmembers, oldmembers,
01696                               nnewmembers, newmembers);
01697     }
01698 
01699     pfree(new_acl);
01700 
01701     ReleaseSysCache(attr_tuple);
01702 }
01703 
01704 /*
01705  *  This processes both sequences and non-sequences.
01706  */
01707 static void
01708 ExecGrant_Relation(InternalGrant *istmt)
01709 {
01710     Relation    relation;
01711     Relation    attRelation;
01712     ListCell   *cell;
01713 
01714     relation = heap_open(RelationRelationId, RowExclusiveLock);
01715     attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
01716 
01717     foreach(cell, istmt->objects)
01718     {
01719         Oid         relOid = lfirst_oid(cell);
01720         Datum       aclDatum;
01721         Form_pg_class pg_class_tuple;
01722         bool        isNull;
01723         AclMode     this_privileges;
01724         AclMode    *col_privileges;
01725         int         num_col_privileges;
01726         bool        have_col_privileges;
01727         Acl        *old_acl;
01728         Acl        *old_rel_acl;
01729         int         noldmembers;
01730         Oid        *oldmembers;
01731         Oid         ownerId;
01732         HeapTuple   tuple;
01733         ListCell   *cell_colprivs;
01734 
01735         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
01736         if (!HeapTupleIsValid(tuple))
01737             elog(ERROR, "cache lookup failed for relation %u", relOid);
01738         pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
01739 
01740         /* Not sensible to grant on an index */
01741         if (pg_class_tuple->relkind == RELKIND_INDEX)
01742             ereport(ERROR,
01743                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01744                      errmsg("\"%s\" is an index",
01745                             NameStr(pg_class_tuple->relname))));
01746 
01747         /* Composite types aren't tables either */
01748         if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
01749             ereport(ERROR,
01750                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01751                      errmsg("\"%s\" is a composite type",
01752                             NameStr(pg_class_tuple->relname))));
01753 
01754         /* Used GRANT SEQUENCE on a non-sequence? */
01755         if (istmt->objtype == ACL_OBJECT_SEQUENCE &&
01756             pg_class_tuple->relkind != RELKIND_SEQUENCE)
01757             ereport(ERROR,
01758                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01759                      errmsg("\"%s\" is not a sequence",
01760                             NameStr(pg_class_tuple->relname))));
01761 
01762         /* Adjust the default permissions based on object type */
01763         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
01764         {
01765             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
01766                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
01767             else
01768                 this_privileges = ACL_ALL_RIGHTS_RELATION;
01769         }
01770         else
01771             this_privileges = istmt->privileges;
01772 
01773         /*
01774          * The GRANT TABLE syntax can be used for sequences and non-sequences,
01775          * so we have to look at the relkind to determine the supported
01776          * permissions.  The OR of table and sequence permissions were already
01777          * checked.
01778          */
01779         if (istmt->objtype == ACL_OBJECT_RELATION)
01780         {
01781             if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
01782             {
01783                 /*
01784                  * For backward compatibility, just throw a warning for
01785                  * invalid sequence permissions when using the non-sequence
01786                  * GRANT syntax.
01787                  */
01788                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
01789                 {
01790                     /*
01791                      * Mention the object name because the user needs to know
01792                      * which operations succeeded.  This is required because
01793                      * WARNING allows the command to continue.
01794                      */
01795                     ereport(WARNING,
01796                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
01797                              errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
01798                                     NameStr(pg_class_tuple->relname))));
01799                     this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
01800                 }
01801             }
01802             else
01803             {
01804                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
01805                 {
01806                     /*
01807                      * USAGE is the only permission supported by sequences but
01808                      * not by non-sequences.  Don't mention the object name
01809                      * because we didn't in the combined TABLE | SEQUENCE
01810                      * check.
01811                      */
01812                     ereport(ERROR,
01813                             (errcode(ERRCODE_INVALID_GRANT_OPERATION),
01814                           errmsg("invalid privilege type USAGE for table")));
01815                 }
01816             }
01817         }
01818 
01819         /*
01820          * Set up array in which we'll accumulate any column privilege bits
01821          * that need modification.  The array is indexed such that entry [0]
01822          * corresponds to FirstLowInvalidHeapAttributeNumber.
01823          */
01824         num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
01825         col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
01826         have_col_privileges = false;
01827 
01828         /*
01829          * If we are revoking relation privileges that are also column
01830          * privileges, we must implicitly revoke them from each column too,
01831          * per SQL spec.  (We don't need to implicitly add column privileges
01832          * during GRANT because the permissions-checking code always checks
01833          * both relation and per-column privileges.)
01834          */
01835         if (!istmt->is_grant &&
01836             (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
01837         {
01838             expand_all_col_privileges(relOid, pg_class_tuple,
01839                                       this_privileges & ACL_ALL_RIGHTS_COLUMN,
01840                                       col_privileges,
01841                                       num_col_privileges);
01842             have_col_privileges = true;
01843         }
01844 
01845         /*
01846          * Get owner ID and working copy of existing ACL. If there's no ACL,
01847          * substitute the proper default.
01848          */
01849         ownerId = pg_class_tuple->relowner;
01850         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
01851                                    &isNull);
01852         if (isNull)
01853         {
01854             switch (pg_class_tuple->relkind)
01855             {
01856                 case RELKIND_SEQUENCE:
01857                     old_acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);
01858                     break;
01859                 default:
01860                     old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);
01861                     break;
01862             }
01863             /* There are no old member roles according to the catalogs */
01864             noldmembers = 0;
01865             oldmembers = NULL;
01866         }
01867         else
01868         {
01869             old_acl = DatumGetAclPCopy(aclDatum);
01870             /* Get the roles mentioned in the existing ACL */
01871             noldmembers = aclmembers(old_acl, &oldmembers);
01872         }
01873 
01874         /* Need an extra copy of original rel ACL for column handling */
01875         old_rel_acl = aclcopy(old_acl);
01876 
01877         /*
01878          * Handle relation-level privileges, if any were specified
01879          */
01880         if (this_privileges != ACL_NO_RIGHTS)
01881         {
01882             AclMode     avail_goptions;
01883             Acl        *new_acl;
01884             Oid         grantorId;
01885             HeapTuple   newtuple;
01886             Datum       values[Natts_pg_class];
01887             bool        nulls[Natts_pg_class];
01888             bool        replaces[Natts_pg_class];
01889             int         nnewmembers;
01890             Oid        *newmembers;
01891             AclObjectKind aclkind;
01892 
01893             /* Determine ID to do the grant as, and available grant options */
01894             select_best_grantor(GetUserId(), this_privileges,
01895                                 old_acl, ownerId,
01896                                 &grantorId, &avail_goptions);
01897 
01898             switch (pg_class_tuple->relkind)
01899             {
01900                 case RELKIND_SEQUENCE:
01901                     aclkind = ACL_KIND_SEQUENCE;
01902                     break;
01903                 default:
01904                     aclkind = ACL_KIND_CLASS;
01905                     break;
01906             }
01907 
01908             /*
01909              * Restrict the privileges to what we can actually grant, and emit
01910              * the standards-mandated warning and error messages.
01911              */
01912             this_privileges =
01913                 restrict_and_check_grant(istmt->is_grant, avail_goptions,
01914                                          istmt->all_privs, this_privileges,
01915                                          relOid, grantorId, aclkind,
01916                                          NameStr(pg_class_tuple->relname),
01917                                          0, NULL);
01918 
01919             /*
01920              * Generate new ACL.
01921              */
01922             new_acl = merge_acl_with_grant(old_acl,
01923                                            istmt->is_grant,
01924                                            istmt->grant_option,
01925                                            istmt->behavior,
01926                                            istmt->grantees,
01927                                            this_privileges,
01928                                            grantorId,
01929                                            ownerId);
01930 
01931             /*
01932              * We need the members of both old and new ACLs so we can correct
01933              * the shared dependency information.
01934              */
01935             nnewmembers = aclmembers(new_acl, &newmembers);
01936 
01937             /* finished building new ACL value, now insert it */
01938             MemSet(values, 0, sizeof(values));
01939             MemSet(nulls, false, sizeof(nulls));
01940             MemSet(replaces, false, sizeof(replaces));
01941 
01942             replaces[Anum_pg_class_relacl - 1] = true;
01943             values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
01944 
01945             newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
01946                                          values, nulls, replaces);
01947 
01948             simple_heap_update(relation, &newtuple->t_self, newtuple);
01949 
01950             /* keep the catalog indexes up to date */
01951             CatalogUpdateIndexes(relation, newtuple);
01952 
01953             /* Update the shared dependency ACL info */
01954             updateAclDependencies(RelationRelationId, relOid, 0,
01955                                   ownerId,
01956                                   noldmembers, oldmembers,
01957                                   nnewmembers, newmembers);
01958 
01959             pfree(new_acl);
01960         }
01961 
01962         /*
01963          * Handle column-level privileges, if any were specified or implied.
01964          * We first expand the user-specified column privileges into the
01965          * array, and then iterate over all nonempty array entries.
01966          */
01967         foreach(cell_colprivs, istmt->col_privs)
01968         {
01969             AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
01970 
01971             if (col_privs->priv_name == NULL)
01972                 this_privileges = ACL_ALL_RIGHTS_COLUMN;
01973             else
01974                 this_privileges = string_to_privilege(col_privs->priv_name);
01975 
01976             if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
01977                 ereport(ERROR,
01978                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
01979                          errmsg("invalid privilege type %s for column",
01980                                 privilege_to_string(this_privileges))));
01981 
01982             if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
01983                 this_privileges & ~((AclMode) ACL_SELECT))
01984             {
01985                 /*
01986                  * The only column privilege allowed on sequences is SELECT.
01987                  * This is a warning not error because we do it that way for
01988                  * relation-level privileges.
01989                  */
01990                 ereport(WARNING,
01991                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
01992                          errmsg("sequence \"%s\" only supports SELECT column privileges",
01993                                 NameStr(pg_class_tuple->relname))));
01994 
01995                 this_privileges &= (AclMode) ACL_SELECT;
01996             }
01997 
01998             expand_col_privileges(col_privs->cols, relOid,
01999                                   this_privileges,
02000                                   col_privileges,
02001                                   num_col_privileges);
02002             have_col_privileges = true;
02003         }
02004 
02005         if (have_col_privileges)
02006         {
02007             AttrNumber  i;
02008 
02009             for (i = 0; i < num_col_privileges; i++)
02010             {
02011                 if (col_privileges[i] == ACL_NO_RIGHTS)
02012                     continue;
02013                 ExecGrant_Attribute(istmt,
02014                                     relOid,
02015                                     NameStr(pg_class_tuple->relname),
02016                                     i + FirstLowInvalidHeapAttributeNumber,
02017                                     ownerId,
02018                                     col_privileges[i],
02019                                     attRelation,
02020                                     old_rel_acl);
02021             }
02022         }
02023 
02024         pfree(old_rel_acl);
02025         pfree(col_privileges);
02026 
02027         ReleaseSysCache(tuple);
02028 
02029         /* prevent error when processing duplicate objects */
02030         CommandCounterIncrement();
02031     }
02032 
02033     heap_close(attRelation, RowExclusiveLock);
02034     heap_close(relation, RowExclusiveLock);
02035 }
02036 
02037 static void
02038 ExecGrant_Database(InternalGrant *istmt)
02039 {
02040     Relation    relation;
02041     ListCell   *cell;
02042 
02043     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02044         istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
02045 
02046     relation = heap_open(DatabaseRelationId, RowExclusiveLock);
02047 
02048     foreach(cell, istmt->objects)
02049     {
02050         Oid         datId = lfirst_oid(cell);
02051         Form_pg_database pg_database_tuple;
02052         Datum       aclDatum;
02053         bool        isNull;
02054         AclMode     avail_goptions;
02055         AclMode     this_privileges;
02056         Acl        *old_acl;
02057         Acl        *new_acl;
02058         Oid         grantorId;
02059         Oid         ownerId;
02060         HeapTuple   newtuple;
02061         Datum       values[Natts_pg_database];
02062         bool        nulls[Natts_pg_database];
02063         bool        replaces[Natts_pg_database];
02064         int         noldmembers;
02065         int         nnewmembers;
02066         Oid        *oldmembers;
02067         Oid        *newmembers;
02068         HeapTuple   tuple;
02069 
02070         tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
02071         if (!HeapTupleIsValid(tuple))
02072             elog(ERROR, "cache lookup failed for database %u", datId);
02073 
02074         pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
02075 
02076         /*
02077          * Get owner ID and working copy of existing ACL. If there's no ACL,
02078          * substitute the proper default.
02079          */
02080         ownerId = pg_database_tuple->datdba;
02081         aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
02082                                 RelationGetDescr(relation), &isNull);
02083         if (isNull)
02084         {
02085             old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
02086             /* There are no old member roles according to the catalogs */
02087             noldmembers = 0;
02088             oldmembers = NULL;
02089         }
02090         else
02091         {
02092             old_acl = DatumGetAclPCopy(aclDatum);
02093             /* Get the roles mentioned in the existing ACL */
02094             noldmembers = aclmembers(old_acl, &oldmembers);
02095         }
02096 
02097         /* Determine ID to do the grant as, and available grant options */
02098         select_best_grantor(GetUserId(), istmt->privileges,
02099                             old_acl, ownerId,
02100                             &grantorId, &avail_goptions);
02101 
02102         /*
02103          * Restrict the privileges to what we can actually grant, and emit the
02104          * standards-mandated warning and error messages.
02105          */
02106         this_privileges =
02107             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02108                                      istmt->all_privs, istmt->privileges,
02109                                      datId, grantorId, ACL_KIND_DATABASE,
02110                                      NameStr(pg_database_tuple->datname),
02111                                      0, NULL);
02112 
02113         /*
02114          * Generate new ACL.
02115          */
02116         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02117                                        istmt->grant_option, istmt->behavior,
02118                                        istmt->grantees, this_privileges,
02119                                        grantorId, ownerId);
02120 
02121         /*
02122          * We need the members of both old and new ACLs so we can correct the
02123          * shared dependency information.
02124          */
02125         nnewmembers = aclmembers(new_acl, &newmembers);
02126 
02127         /* finished building new ACL value, now insert it */
02128         MemSet(values, 0, sizeof(values));
02129         MemSet(nulls, false, sizeof(nulls));
02130         MemSet(replaces, false, sizeof(replaces));
02131 
02132         replaces[Anum_pg_database_datacl - 1] = true;
02133         values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
02134 
02135         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02136                                      nulls, replaces);
02137 
02138         simple_heap_update(relation, &newtuple->t_self, newtuple);
02139 
02140         /* keep the catalog indexes up to date */
02141         CatalogUpdateIndexes(relation, newtuple);
02142 
02143         /* Update the shared dependency ACL info */
02144         updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
02145                               ownerId,
02146                               noldmembers, oldmembers,
02147                               nnewmembers, newmembers);
02148 
02149         ReleaseSysCache(tuple);
02150 
02151         pfree(new_acl);
02152 
02153         /* prevent error when processing duplicate objects */
02154         CommandCounterIncrement();
02155     }
02156 
02157     heap_close(relation, RowExclusiveLock);
02158 }
02159 
02160 static void
02161 ExecGrant_Fdw(InternalGrant *istmt)
02162 {
02163     Relation    relation;
02164     ListCell   *cell;
02165 
02166     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02167         istmt->privileges = ACL_ALL_RIGHTS_FDW;
02168 
02169     relation = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
02170 
02171     foreach(cell, istmt->objects)
02172     {
02173         Oid         fdwid = lfirst_oid(cell);
02174         Form_pg_foreign_data_wrapper pg_fdw_tuple;
02175         Datum       aclDatum;
02176         bool        isNull;
02177         AclMode     avail_goptions;
02178         AclMode     this_privileges;
02179         Acl        *old_acl;
02180         Acl        *new_acl;
02181         Oid         grantorId;
02182         Oid         ownerId;
02183         HeapTuple   tuple;
02184         HeapTuple   newtuple;
02185         Datum       values[Natts_pg_foreign_data_wrapper];
02186         bool        nulls[Natts_pg_foreign_data_wrapper];
02187         bool        replaces[Natts_pg_foreign_data_wrapper];
02188         int         noldmembers;
02189         int         nnewmembers;
02190         Oid        *oldmembers;
02191         Oid        *newmembers;
02192 
02193         tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
02194                                 ObjectIdGetDatum(fdwid));
02195         if (!HeapTupleIsValid(tuple))
02196             elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
02197 
02198         pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
02199 
02200         /*
02201          * Get owner ID and working copy of existing ACL. If there's no ACL,
02202          * substitute the proper default.
02203          */
02204         ownerId = pg_fdw_tuple->fdwowner;
02205         aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
02206                                    Anum_pg_foreign_data_wrapper_fdwacl,
02207                                    &isNull);
02208         if (isNull)
02209         {
02210             old_acl = acldefault(ACL_OBJECT_FDW, ownerId);
02211             /* There are no old member roles according to the catalogs */
02212             noldmembers = 0;
02213             oldmembers = NULL;
02214         }
02215         else
02216         {
02217             old_acl = DatumGetAclPCopy(aclDatum);
02218             /* Get the roles mentioned in the existing ACL */
02219             noldmembers = aclmembers(old_acl, &oldmembers);
02220         }
02221 
02222         /* Determine ID to do the grant as, and available grant options */
02223         select_best_grantor(GetUserId(), istmt->privileges,
02224                             old_acl, ownerId,
02225                             &grantorId, &avail_goptions);
02226 
02227         /*
02228          * Restrict the privileges to what we can actually grant, and emit the
02229          * standards-mandated warning and error messages.
02230          */
02231         this_privileges =
02232             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02233                                      istmt->all_privs, istmt->privileges,
02234                                      fdwid, grantorId, ACL_KIND_FDW,
02235                                      NameStr(pg_fdw_tuple->fdwname),
02236                                      0, NULL);
02237 
02238         /*
02239          * Generate new ACL.
02240          */
02241         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02242                                        istmt->grant_option, istmt->behavior,
02243                                        istmt->grantees, this_privileges,
02244                                        grantorId, ownerId);
02245 
02246         /*
02247          * We need the members of both old and new ACLs so we can correct the
02248          * shared dependency information.
02249          */
02250         nnewmembers = aclmembers(new_acl, &newmembers);
02251 
02252         /* finished building new ACL value, now insert it */
02253         MemSet(values, 0, sizeof(values));
02254         MemSet(nulls, false, sizeof(nulls));
02255         MemSet(replaces, false, sizeof(replaces));
02256 
02257         replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
02258         values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
02259 
02260         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02261                                      nulls, replaces);
02262 
02263         simple_heap_update(relation, &newtuple->t_self, newtuple);
02264 
02265         /* keep the catalog indexes up to date */
02266         CatalogUpdateIndexes(relation, newtuple);
02267 
02268         /* Update the shared dependency ACL info */
02269         updateAclDependencies(ForeignDataWrapperRelationId,
02270                               HeapTupleGetOid(tuple), 0,
02271                               ownerId,
02272                               noldmembers, oldmembers,
02273                               nnewmembers, newmembers);
02274 
02275         ReleaseSysCache(tuple);
02276 
02277         pfree(new_acl);
02278 
02279         /* prevent error when processing duplicate objects */
02280         CommandCounterIncrement();
02281     }
02282 
02283     heap_close(relation, RowExclusiveLock);
02284 }
02285 
02286 static void
02287 ExecGrant_ForeignServer(InternalGrant *istmt)
02288 {
02289     Relation    relation;
02290     ListCell   *cell;
02291 
02292     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02293         istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
02294 
02295     relation = heap_open(ForeignServerRelationId, RowExclusiveLock);
02296 
02297     foreach(cell, istmt->objects)
02298     {
02299         Oid         srvid = lfirst_oid(cell);
02300         Form_pg_foreign_server pg_server_tuple;
02301         Datum       aclDatum;
02302         bool        isNull;
02303         AclMode     avail_goptions;
02304         AclMode     this_privileges;
02305         Acl        *old_acl;
02306         Acl        *new_acl;
02307         Oid         grantorId;
02308         Oid         ownerId;
02309         HeapTuple   tuple;
02310         HeapTuple   newtuple;
02311         Datum       values[Natts_pg_foreign_server];
02312         bool        nulls[Natts_pg_foreign_server];
02313         bool        replaces[Natts_pg_foreign_server];
02314         int         noldmembers;
02315         int         nnewmembers;
02316         Oid        *oldmembers;
02317         Oid        *newmembers;
02318 
02319         tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
02320         if (!HeapTupleIsValid(tuple))
02321             elog(ERROR, "cache lookup failed for foreign server %u", srvid);
02322 
02323         pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
02324 
02325         /*
02326          * Get owner ID and working copy of existing ACL. If there's no ACL,
02327          * substitute the proper default.
02328          */
02329         ownerId = pg_server_tuple->srvowner;
02330         aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
02331                                    Anum_pg_foreign_server_srvacl,
02332                                    &isNull);
02333         if (isNull)
02334         {
02335             old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
02336             /* There are no old member roles according to the catalogs */
02337             noldmembers = 0;
02338             oldmembers = NULL;
02339         }
02340         else
02341         {
02342             old_acl = DatumGetAclPCopy(aclDatum);
02343             /* Get the roles mentioned in the existing ACL */
02344             noldmembers = aclmembers(old_acl, &oldmembers);
02345         }
02346 
02347         /* Determine ID to do the grant as, and available grant options */
02348         select_best_grantor(GetUserId(), istmt->privileges,
02349                             old_acl, ownerId,
02350                             &grantorId, &avail_goptions);
02351 
02352         /*
02353          * Restrict the privileges to what we can actually grant, and emit the
02354          * standards-mandated warning and error messages.
02355          */
02356         this_privileges =
02357             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02358                                      istmt->all_privs, istmt->privileges,
02359                                    srvid, grantorId, ACL_KIND_FOREIGN_SERVER,
02360                                      NameStr(pg_server_tuple->srvname),
02361                                      0, NULL);
02362 
02363         /*
02364          * Generate new ACL.
02365          */
02366         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02367                                        istmt->grant_option, istmt->behavior,
02368                                        istmt->grantees, this_privileges,
02369                                        grantorId, ownerId);
02370 
02371         /*
02372          * We need the members of both old and new ACLs so we can correct the
02373          * shared dependency information.
02374          */
02375         nnewmembers = aclmembers(new_acl, &newmembers);
02376 
02377         /* finished building new ACL value, now insert it */
02378         MemSet(values, 0, sizeof(values));
02379         MemSet(nulls, false, sizeof(nulls));
02380         MemSet(replaces, false, sizeof(replaces));
02381 
02382         replaces[Anum_pg_foreign_server_srvacl - 1] = true;
02383         values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
02384 
02385         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02386                                      nulls, replaces);
02387 
02388         simple_heap_update(relation, &newtuple->t_self, newtuple);
02389 
02390         /* keep the catalog indexes up to date */
02391         CatalogUpdateIndexes(relation, newtuple);
02392 
02393         /* Update the shared dependency ACL info */
02394         updateAclDependencies(ForeignServerRelationId,
02395                               HeapTupleGetOid(tuple), 0,
02396                               ownerId,
02397                               noldmembers, oldmembers,
02398                               nnewmembers, newmembers);
02399 
02400         ReleaseSysCache(tuple);
02401 
02402         pfree(new_acl);
02403 
02404         /* prevent error when processing duplicate objects */
02405         CommandCounterIncrement();
02406     }
02407 
02408     heap_close(relation, RowExclusiveLock);
02409 }
02410 
02411 static void
02412 ExecGrant_Function(InternalGrant *istmt)
02413 {
02414     Relation    relation;
02415     ListCell   *cell;
02416 
02417     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02418         istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
02419 
02420     relation = heap_open(ProcedureRelationId, RowExclusiveLock);
02421 
02422     foreach(cell, istmt->objects)
02423     {
02424         Oid         funcId = lfirst_oid(cell);
02425         Form_pg_proc pg_proc_tuple;
02426         Datum       aclDatum;
02427         bool        isNull;
02428         AclMode     avail_goptions;
02429         AclMode     this_privileges;
02430         Acl        *old_acl;
02431         Acl        *new_acl;
02432         Oid         grantorId;
02433         Oid         ownerId;
02434         HeapTuple   tuple;
02435         HeapTuple   newtuple;
02436         Datum       values[Natts_pg_proc];
02437         bool        nulls[Natts_pg_proc];
02438         bool        replaces[Natts_pg_proc];
02439         int         noldmembers;
02440         int         nnewmembers;
02441         Oid        *oldmembers;
02442         Oid        *newmembers;
02443 
02444         tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
02445         if (!HeapTupleIsValid(tuple))
02446             elog(ERROR, "cache lookup failed for function %u", funcId);
02447 
02448         pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
02449 
02450         /*
02451          * Get owner ID and working copy of existing ACL. If there's no ACL,
02452          * substitute the proper default.
02453          */
02454         ownerId = pg_proc_tuple->proowner;
02455         aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
02456                                    &isNull);
02457         if (isNull)
02458         {
02459             old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
02460             /* There are no old member roles according to the catalogs */
02461             noldmembers = 0;
02462             oldmembers = NULL;
02463         }
02464         else
02465         {
02466             old_acl = DatumGetAclPCopy(aclDatum);
02467             /* Get the roles mentioned in the existing ACL */
02468             noldmembers = aclmembers(old_acl, &oldmembers);
02469         }
02470 
02471         /* Determine ID to do the grant as, and available grant options */
02472         select_best_grantor(GetUserId(), istmt->privileges,
02473                             old_acl, ownerId,
02474                             &grantorId, &avail_goptions);
02475 
02476         /*
02477          * Restrict the privileges to what we can actually grant, and emit the
02478          * standards-mandated warning and error messages.
02479          */
02480         this_privileges =
02481             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02482                                      istmt->all_privs, istmt->privileges,
02483                                      funcId, grantorId, ACL_KIND_PROC,
02484                                      NameStr(pg_proc_tuple->proname),
02485                                      0, NULL);
02486 
02487         /*
02488          * Generate new ACL.
02489          */
02490         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02491                                        istmt->grant_option, istmt->behavior,
02492                                        istmt->grantees, this_privileges,
02493                                        grantorId, ownerId);
02494 
02495         /*
02496          * We need the members of both old and new ACLs so we can correct the
02497          * shared dependency information.
02498          */
02499         nnewmembers = aclmembers(new_acl, &newmembers);
02500 
02501         /* finished building new ACL value, now insert it */
02502         MemSet(values, 0, sizeof(values));
02503         MemSet(nulls, false, sizeof(nulls));
02504         MemSet(replaces, false, sizeof(replaces));
02505 
02506         replaces[Anum_pg_proc_proacl - 1] = true;
02507         values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
02508 
02509         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02510                                      nulls, replaces);
02511 
02512         simple_heap_update(relation, &newtuple->t_self, newtuple);
02513 
02514         /* keep the catalog indexes up to date */
02515         CatalogUpdateIndexes(relation, newtuple);
02516 
02517         /* Update the shared dependency ACL info */
02518         updateAclDependencies(ProcedureRelationId, funcId, 0,
02519                               ownerId,
02520                               noldmembers, oldmembers,
02521                               nnewmembers, newmembers);
02522 
02523         ReleaseSysCache(tuple);
02524 
02525         pfree(new_acl);
02526 
02527         /* prevent error when processing duplicate objects */
02528         CommandCounterIncrement();
02529     }
02530 
02531     heap_close(relation, RowExclusiveLock);
02532 }
02533 
02534 static void
02535 ExecGrant_Language(InternalGrant *istmt)
02536 {
02537     Relation    relation;
02538     ListCell   *cell;
02539 
02540     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02541         istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
02542 
02543     relation = heap_open(LanguageRelationId, RowExclusiveLock);
02544 
02545     foreach(cell, istmt->objects)
02546     {
02547         Oid         langId = lfirst_oid(cell);
02548         Form_pg_language pg_language_tuple;
02549         Datum       aclDatum;
02550         bool        isNull;
02551         AclMode     avail_goptions;
02552         AclMode     this_privileges;
02553         Acl        *old_acl;
02554         Acl        *new_acl;
02555         Oid         grantorId;
02556         Oid         ownerId;
02557         HeapTuple   tuple;
02558         HeapTuple   newtuple;
02559         Datum       values[Natts_pg_language];
02560         bool        nulls[Natts_pg_language];
02561         bool        replaces[Natts_pg_language];
02562         int         noldmembers;
02563         int         nnewmembers;
02564         Oid        *oldmembers;
02565         Oid        *newmembers;
02566 
02567         tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
02568         if (!HeapTupleIsValid(tuple))
02569             elog(ERROR, "cache lookup failed for language %u", langId);
02570 
02571         pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
02572 
02573         if (!pg_language_tuple->lanpltrusted)
02574             ereport(ERROR,
02575                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
02576                      errmsg("language \"%s\" is not trusted",
02577                             NameStr(pg_language_tuple->lanname)),
02578                    errhint("Only superusers can use untrusted languages.")));
02579 
02580         /*
02581          * Get owner ID and working copy of existing ACL. If there's no ACL,
02582          * substitute the proper default.
02583          */
02584         ownerId = pg_language_tuple->lanowner;
02585         aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
02586                                    &isNull);
02587         if (isNull)
02588         {
02589             old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
02590             /* There are no old member roles according to the catalogs */
02591             noldmembers = 0;
02592             oldmembers = NULL;
02593         }
02594         else
02595         {
02596             old_acl = DatumGetAclPCopy(aclDatum);
02597             /* Get the roles mentioned in the existing ACL */
02598             noldmembers = aclmembers(old_acl, &oldmembers);
02599         }
02600 
02601         /* Determine ID to do the grant as, and available grant options */
02602         select_best_grantor(GetUserId(), istmt->privileges,
02603                             old_acl, ownerId,
02604                             &grantorId, &avail_goptions);
02605 
02606         /*
02607          * Restrict the privileges to what we can actually grant, and emit the
02608          * standards-mandated warning and error messages.
02609          */
02610         this_privileges =
02611             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02612                                      istmt->all_privs, istmt->privileges,
02613                                      langId, grantorId, ACL_KIND_LANGUAGE,
02614                                      NameStr(pg_language_tuple->lanname),
02615                                      0, NULL);
02616 
02617         /*
02618          * Generate new ACL.
02619          */
02620         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02621                                        istmt->grant_option, istmt->behavior,
02622                                        istmt->grantees, this_privileges,
02623                                        grantorId, ownerId);
02624 
02625         /*
02626          * We need the members of both old and new ACLs so we can correct the
02627          * shared dependency information.
02628          */
02629         nnewmembers = aclmembers(new_acl, &newmembers);
02630 
02631         /* finished building new ACL value, now insert it */
02632         MemSet(values, 0, sizeof(values));
02633         MemSet(nulls, false, sizeof(nulls));
02634         MemSet(replaces, false, sizeof(replaces));
02635 
02636         replaces[Anum_pg_language_lanacl - 1] = true;
02637         values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
02638 
02639         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02640                                      nulls, replaces);
02641 
02642         simple_heap_update(relation, &newtuple->t_self, newtuple);
02643 
02644         /* keep the catalog indexes up to date */
02645         CatalogUpdateIndexes(relation, newtuple);
02646 
02647         /* Update the shared dependency ACL info */
02648         updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
02649                               ownerId,
02650                               noldmembers, oldmembers,
02651                               nnewmembers, newmembers);
02652 
02653         ReleaseSysCache(tuple);
02654 
02655         pfree(new_acl);
02656 
02657         /* prevent error when processing duplicate objects */
02658         CommandCounterIncrement();
02659     }
02660 
02661     heap_close(relation, RowExclusiveLock);
02662 }
02663 
02664 static void
02665 ExecGrant_Largeobject(InternalGrant *istmt)
02666 {
02667     Relation    relation;
02668     ListCell   *cell;
02669 
02670     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02671         istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
02672 
02673     relation = heap_open(LargeObjectMetadataRelationId,
02674                          RowExclusiveLock);
02675 
02676     foreach(cell, istmt->objects)
02677     {
02678         Oid         loid = lfirst_oid(cell);
02679         Form_pg_largeobject_metadata form_lo_meta;
02680         char        loname[NAMEDATALEN];
02681         Datum       aclDatum;
02682         bool        isNull;
02683         AclMode     avail_goptions;
02684         AclMode     this_privileges;
02685         Acl        *old_acl;
02686         Acl        *new_acl;
02687         Oid         grantorId;
02688         Oid         ownerId;
02689         HeapTuple   newtuple;
02690         Datum       values[Natts_pg_largeobject_metadata];
02691         bool        nulls[Natts_pg_largeobject_metadata];
02692         bool        replaces[Natts_pg_largeobject_metadata];
02693         int         noldmembers;
02694         int         nnewmembers;
02695         Oid        *oldmembers;
02696         Oid        *newmembers;
02697         ScanKeyData entry[1];
02698         SysScanDesc scan;
02699         HeapTuple   tuple;
02700 
02701         /* There's no syscache for pg_largeobject_metadata */
02702         ScanKeyInit(&entry[0],
02703                     ObjectIdAttributeNumber,
02704                     BTEqualStrategyNumber, F_OIDEQ,
02705                     ObjectIdGetDatum(loid));
02706 
02707         scan = systable_beginscan(relation,
02708                                   LargeObjectMetadataOidIndexId, true,
02709                                   SnapshotNow, 1, entry);
02710 
02711         tuple = systable_getnext(scan);
02712         if (!HeapTupleIsValid(tuple))
02713             elog(ERROR, "cache lookup failed for large object %u", loid);
02714 
02715         form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
02716 
02717         /*
02718          * Get owner ID and working copy of existing ACL. If there's no ACL,
02719          * substitute the proper default.
02720          */
02721         ownerId = form_lo_meta->lomowner;
02722         aclDatum = heap_getattr(tuple,
02723                                 Anum_pg_largeobject_metadata_lomacl,
02724                                 RelationGetDescr(relation), &isNull);
02725         if (isNull)
02726         {
02727             old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
02728             /* There are no old member roles according to the catalogs */
02729             noldmembers = 0;
02730             oldmembers = NULL;
02731         }
02732         else
02733         {
02734             old_acl = DatumGetAclPCopy(aclDatum);
02735             /* Get the roles mentioned in the existing ACL */
02736             noldmembers = aclmembers(old_acl, &oldmembers);
02737         }
02738 
02739         /* Determine ID to do the grant as, and available grant options */
02740         select_best_grantor(GetUserId(), istmt->privileges,
02741                             old_acl, ownerId,
02742                             &grantorId, &avail_goptions);
02743 
02744         /*
02745          * Restrict the privileges to what we can actually grant, and emit the
02746          * standards-mandated warning and error messages.
02747          */
02748         snprintf(loname, sizeof(loname), "large object %u", loid);
02749         this_privileges =
02750             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02751                                      istmt->all_privs, istmt->privileges,
02752                                      loid, grantorId, ACL_KIND_LARGEOBJECT,
02753                                      loname, 0, NULL);
02754 
02755         /*
02756          * Generate new ACL.
02757          */
02758         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02759                                        istmt->grant_option, istmt->behavior,
02760                                        istmt->grantees, this_privileges,
02761                                        grantorId, ownerId);
02762 
02763         /*
02764          * We need the members of both old and new ACLs so we can correct the
02765          * shared dependency information.
02766          */
02767         nnewmembers = aclmembers(new_acl, &newmembers);
02768 
02769         /* finished building new ACL value, now insert it */
02770         MemSet(values, 0, sizeof(values));
02771         MemSet(nulls, false, sizeof(nulls));
02772         MemSet(replaces, false, sizeof(replaces));
02773 
02774         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
02775         values[Anum_pg_largeobject_metadata_lomacl - 1]
02776             = PointerGetDatum(new_acl);
02777 
02778         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
02779                                      values, nulls, replaces);
02780 
02781         simple_heap_update(relation, &newtuple->t_self, newtuple);
02782 
02783         /* keep the catalog indexes up to date */
02784         CatalogUpdateIndexes(relation, newtuple);
02785 
02786         /* Update the shared dependency ACL info */
02787         updateAclDependencies(LargeObjectRelationId,
02788                               HeapTupleGetOid(tuple), 0,
02789                               ownerId,
02790                               noldmembers, oldmembers,
02791                               nnewmembers, newmembers);
02792 
02793         systable_endscan(scan);
02794 
02795         pfree(new_acl);
02796 
02797         /* prevent error when processing duplicate objects */
02798         CommandCounterIncrement();
02799     }
02800 
02801     heap_close(relation, RowExclusiveLock);
02802 }
02803 
02804 static void
02805 ExecGrant_Namespace(InternalGrant *istmt)
02806 {
02807     Relation    relation;
02808     ListCell   *cell;
02809 
02810     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02811         istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
02812 
02813     relation = heap_open(NamespaceRelationId, RowExclusiveLock);
02814 
02815     foreach(cell, istmt->objects)
02816     {
02817         Oid         nspid = lfirst_oid(cell);
02818         Form_pg_namespace pg_namespace_tuple;
02819         Datum       aclDatum;
02820         bool        isNull;
02821         AclMode     avail_goptions;
02822         AclMode     this_privileges;
02823         Acl        *old_acl;
02824         Acl        *new_acl;
02825         Oid         grantorId;
02826         Oid         ownerId;
02827         HeapTuple   tuple;
02828         HeapTuple   newtuple;
02829         Datum       values[Natts_pg_namespace];
02830         bool        nulls[Natts_pg_namespace];
02831         bool        replaces[Natts_pg_namespace];
02832         int         noldmembers;
02833         int         nnewmembers;
02834         Oid        *oldmembers;
02835         Oid        *newmembers;
02836 
02837         tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
02838         if (!HeapTupleIsValid(tuple))
02839             elog(ERROR, "cache lookup failed for namespace %u", nspid);
02840 
02841         pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
02842 
02843         /*
02844          * Get owner ID and working copy of existing ACL. If there's no ACL,
02845          * substitute the proper default.
02846          */
02847         ownerId = pg_namespace_tuple->nspowner;
02848         aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
02849                                    Anum_pg_namespace_nspacl,
02850                                    &isNull);
02851         if (isNull)
02852         {
02853             old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
02854             /* There are no old member roles according to the catalogs */
02855             noldmembers = 0;
02856             oldmembers = NULL;
02857         }
02858         else
02859         {
02860             old_acl = DatumGetAclPCopy(aclDatum);
02861             /* Get the roles mentioned in the existing ACL */
02862             noldmembers = aclmembers(old_acl, &oldmembers);
02863         }
02864 
02865         /* Determine ID to do the grant as, and available grant options */
02866         select_best_grantor(GetUserId(), istmt->privileges,
02867                             old_acl, ownerId,
02868                             &grantorId, &avail_goptions);
02869 
02870         /*
02871          * Restrict the privileges to what we can actually grant, and emit the
02872          * standards-mandated warning and error messages.
02873          */
02874         this_privileges =
02875             restrict_and_check_grant(istmt->is_grant, avail_goptions,
02876                                      istmt->all_privs, istmt->privileges,
02877                                      nspid, grantorId, ACL_KIND_NAMESPACE,
02878                                      NameStr(pg_namespace_tuple->nspname),
02879                                      0, NULL);
02880 
02881         /*
02882          * Generate new ACL.
02883          */
02884         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
02885                                        istmt->grant_option, istmt->behavior,
02886                                        istmt->grantees, this_privileges,
02887                                        grantorId, ownerId);
02888 
02889         /*
02890          * We need the members of both old and new ACLs so we can correct the
02891          * shared dependency information.
02892          */
02893         nnewmembers = aclmembers(new_acl, &newmembers);
02894 
02895         /* finished building new ACL value, now insert it */
02896         MemSet(values, 0, sizeof(values));
02897         MemSet(nulls, false, sizeof(nulls));
02898         MemSet(replaces, false, sizeof(replaces));
02899 
02900         replaces[Anum_pg_namespace_nspacl - 1] = true;
02901         values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
02902 
02903         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
02904                                      nulls, replaces);
02905 
02906         simple_heap_update(relation, &newtuple->t_self, newtuple);
02907 
02908         /* keep the catalog indexes up to date */
02909         CatalogUpdateIndexes(relation, newtuple);
02910 
02911         /* Update the shared dependency ACL info */
02912         updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
02913                               ownerId,
02914                               noldmembers, oldmembers,
02915                               nnewmembers, newmembers);
02916 
02917         ReleaseSysCache(tuple);
02918 
02919         pfree(new_acl);
02920 
02921         /* prevent error when processing duplicate objects */
02922         CommandCounterIncrement();
02923     }
02924 
02925     heap_close(relation, RowExclusiveLock);
02926 }
02927 
02928 static void
02929 ExecGrant_Tablespace(InternalGrant *istmt)
02930 {
02931     Relation    relation;
02932     ListCell   *cell;
02933 
02934     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
02935         istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
02936 
02937     relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
02938 
02939     foreach(cell, istmt->objects)
02940     {
02941         Oid         tblId = lfirst_oid(cell);
02942         Form_pg_tablespace pg_tablespace_tuple;
02943         Datum       aclDatum;
02944         bool        isNull;
02945         AclMode     avail_goptions;
02946         AclMode     this_privileges;
02947         Acl        *old_acl;
02948         Acl        *new_acl;
02949         Oid         grantorId;
02950         Oid         ownerId;
02951         HeapTuple   newtuple;
02952         Datum       values[Natts_pg_tablespace];
02953         bool        nulls[Natts_pg_tablespace];
02954         bool        replaces[Natts_pg_tablespace];
02955         int         noldmembers;
02956         int         nnewmembers;
02957         Oid        *oldmembers;
02958         Oid        *newmembers;
02959         HeapTuple   tuple;
02960 
02961         /* Search syscache for pg_tablespace */
02962         tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
02963         if (!HeapTupleIsValid(tuple))
02964             elog(ERROR, "cache lookup failed for tablespace %u", tblId);
02965 
02966         pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
02967 
02968         /*
02969          * Get owner ID and working copy of existing ACL. If there's no ACL,
02970          * substitute the proper default.
02971          */
02972         ownerId = pg_tablespace_tuple->spcowner;
02973         aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
02974                                 RelationGetDescr(relation), &isNull);
02975         if (isNull)
02976         {
02977             old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
02978             /* There are no old member roles according to the catalogs */
02979             noldmembers = 0;
02980             oldmembers = NULL;
02981         }
02982         else
02983         {
02984             old_acl = DatumGetAclPCopy(aclDatum);
02985             /* Get the roles mentioned in the existing ACL */
02986             noldmembers = aclmembers(old_acl, &oldmembers);
02987         }
02988 
02989         /* Determine ID to do the grant as, and available grant options */
02990         select_best_grantor(GetUserId(), istmt->privileges,
02991                             old_acl, ownerId,
02992                             &grantorId, &avail_goptions);
02993 
02994         /*
02995          * Restrict the privileges to what we can actually grant, and emit the
02996          * standards-mandated warning and error messages.
02997          */
02998         this_privileges =
02999             restrict_and_check_grant(istmt->is_grant, avail_goptions,
03000                                      istmt->all_privs, istmt->privileges,
03001                                      tblId, grantorId, ACL_KIND_TABLESPACE,
03002                                      NameStr(pg_tablespace_tuple->spcname),
03003                                      0, NULL);
03004 
03005         /*
03006          * Generate new ACL.
03007          */
03008         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
03009                                        istmt->grant_option, istmt->behavior,
03010                                        istmt->grantees, this_privileges,
03011                                        grantorId, ownerId);
03012 
03013         /*
03014          * We need the members of both old and new ACLs so we can correct the
03015          * shared dependency information.
03016          */
03017         nnewmembers = aclmembers(new_acl, &newmembers);
03018 
03019         /* finished building new ACL value, now insert it */
03020         MemSet(values, 0, sizeof(values));
03021         MemSet(nulls, false, sizeof(nulls));
03022         MemSet(replaces, false, sizeof(replaces));
03023 
03024         replaces[Anum_pg_tablespace_spcacl - 1] = true;
03025         values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
03026 
03027         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
03028                                      nulls, replaces);
03029 
03030         simple_heap_update(relation, &newtuple->t_self, newtuple);
03031 
03032         /* keep the catalog indexes up to date */
03033         CatalogUpdateIndexes(relation, newtuple);
03034 
03035         /* Update the shared dependency ACL info */
03036         updateAclDependencies(TableSpaceRelationId, tblId, 0,
03037                               ownerId,
03038                               noldmembers, oldmembers,
03039                               nnewmembers, newmembers);
03040 
03041         ReleaseSysCache(tuple);
03042         pfree(new_acl);
03043 
03044         /* prevent error when processing duplicate objects */
03045         CommandCounterIncrement();
03046     }
03047 
03048     heap_close(relation, RowExclusiveLock);
03049 }
03050 
03051 static void
03052 ExecGrant_Type(InternalGrant *istmt)
03053 {
03054     Relation    relation;
03055     ListCell   *cell;
03056 
03057     if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
03058         istmt->privileges = ACL_ALL_RIGHTS_TYPE;
03059 
03060     relation = heap_open(TypeRelationId, RowExclusiveLock);
03061 
03062     foreach(cell, istmt->objects)
03063     {
03064         Oid         typId = lfirst_oid(cell);
03065         Form_pg_type pg_type_tuple;
03066         Datum       aclDatum;
03067         bool        isNull;
03068         AclMode     avail_goptions;
03069         AclMode     this_privileges;
03070         Acl        *old_acl;
03071         Acl        *new_acl;
03072         Oid         grantorId;
03073         Oid         ownerId;
03074         HeapTuple   newtuple;
03075         Datum       values[Natts_pg_type];
03076         bool        nulls[Natts_pg_type];
03077         bool        replaces[Natts_pg_type];
03078         int         noldmembers;
03079         int         nnewmembers;
03080         Oid        *oldmembers;
03081         Oid        *newmembers;
03082         HeapTuple   tuple;
03083 
03084         /* Search syscache for pg_type */
03085         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typId));
03086         if (!HeapTupleIsValid(tuple))
03087             elog(ERROR, "cache lookup failed for type %u", typId);
03088 
03089         pg_type_tuple = (Form_pg_type) GETSTRUCT(tuple);
03090 
03091         if (pg_type_tuple->typelem != 0 && pg_type_tuple->typlen == -1)
03092             ereport(ERROR,
03093                     (errcode(ERRCODE_INVALID_GRANT_OPERATION),
03094                      errmsg("cannot set privileges of array types"),
03095                 errhint("Set the privileges of the element type instead.")));
03096 
03097         /* Used GRANT DOMAIN on a non-domain? */
03098         if (istmt->objtype == ACL_OBJECT_DOMAIN &&
03099             pg_type_tuple->typtype != TYPTYPE_DOMAIN)
03100             ereport(ERROR,
03101                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
03102                      errmsg("\"%s\" is not a domain",
03103                             NameStr(pg_type_tuple->typname))));
03104 
03105         /*
03106          * Get owner ID and working copy of existing ACL. If there's no ACL,
03107          * substitute the proper default.
03108          */
03109         ownerId = pg_type_tuple->typowner;
03110         aclDatum = heap_getattr(tuple, Anum_pg_type_typacl,
03111                                 RelationGetDescr(relation), &isNull);
03112         if (isNull)
03113         {
03114             old_acl = acldefault(istmt->objtype, ownerId);
03115             /* There are no old member roles according to the catalogs */
03116             noldmembers = 0;
03117             oldmembers = NULL;
03118         }
03119         else
03120         {
03121             old_acl = DatumGetAclPCopy(aclDatum);
03122             /* Get the roles mentioned in the existing ACL */
03123             noldmembers = aclmembers(old_acl, &oldmembers);
03124         }
03125 
03126         /* Determine ID to do the grant as, and available grant options */
03127         select_best_grantor(GetUserId(), istmt->privileges,
03128                             old_acl, ownerId,
03129                             &grantorId, &avail_goptions);
03130 
03131         /*
03132          * Restrict the privileges to what we can actually grant, and emit the
03133          * standards-mandated warning and error messages.
03134          */
03135         this_privileges =
03136             restrict_and_check_grant(istmt->is_grant, avail_goptions,
03137                                      istmt->all_privs, istmt->privileges,
03138                                      typId, grantorId, ACL_KIND_TYPE,
03139                                      NameStr(pg_type_tuple->typname),
03140                                      0, NULL);
03141 
03142         /*
03143          * Generate new ACL.
03144          */
03145         new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
03146                                        istmt->grant_option, istmt->behavior,
03147                                        istmt->grantees, this_privileges,
03148                                        grantorId, ownerId);
03149 
03150         /*
03151          * We need the members of both old and new ACLs so we can correct the
03152          * shared dependency information.
03153          */
03154         nnewmembers = aclmembers(new_acl, &newmembers);
03155 
03156         /* finished building new ACL value, now insert it */
03157         MemSet(values, 0, sizeof(values));
03158         MemSet(nulls, false, sizeof(nulls));
03159         MemSet(replaces, false, sizeof(replaces));
03160 
03161         replaces[Anum_pg_type_typacl - 1] = true;
03162         values[Anum_pg_type_typacl - 1] = PointerGetDatum(new_acl);
03163 
03164         newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
03165                                      nulls, replaces);
03166 
03167         simple_heap_update(relation, &newtuple->t_self, newtuple);
03168 
03169         /* keep the catalog indexes up to date */
03170         CatalogUpdateIndexes(relation, newtuple);
03171 
03172         /* Update the shared dependency ACL info */
03173         updateAclDependencies(TypeRelationId, typId, 0,
03174                               ownerId,
03175                               noldmembers, oldmembers,
03176                               nnewmembers, newmembers);
03177 
03178         ReleaseSysCache(tuple);
03179         pfree(new_acl);
03180 
03181         /* prevent error when processing duplicate objects */
03182         CommandCounterIncrement();
03183     }
03184 
03185     heap_close(relation, RowExclusiveLock);
03186 }
03187 
03188 
03189 static AclMode
03190 string_to_privilege(const char *privname)
03191 {
03192     if (strcmp(privname, "insert") == 0)
03193         return ACL_INSERT;
03194     if (strcmp(privname, "select") == 0)
03195         return ACL_SELECT;
03196     if (strcmp(privname, "update") == 0)
03197         return ACL_UPDATE;
03198     if (strcmp(privname, "delete") == 0)
03199         return ACL_DELETE;
03200     if (strcmp(privname, "truncate") == 0)
03201         return ACL_TRUNCATE;
03202     if (strcmp(privname, "references") == 0)
03203         return ACL_REFERENCES;
03204     if (strcmp(privname, "trigger") == 0)
03205         return ACL_TRIGGER;
03206     if (strcmp(privname, "execute") == 0)
03207         return ACL_EXECUTE;
03208     if (strcmp(privname, "usage") == 0)
03209         return ACL_USAGE;
03210     if (strcmp(privname, "create") == 0)
03211         return ACL_CREATE;
03212     if (strcmp(privname, "temporary") == 0)
03213         return ACL_CREATE_TEMP;
03214     if (strcmp(privname, "temp") == 0)
03215         return ACL_CREATE_TEMP;
03216     if (strcmp(privname, "connect") == 0)
03217         return ACL_CONNECT;
03218     if (strcmp(privname, "rule") == 0)
03219         return 0;               /* ignore old RULE privileges */
03220     ereport(ERROR,
03221             (errcode(ERRCODE_SYNTAX_ERROR),
03222              errmsg("unrecognized privilege type \"%s\"", privname)));
03223     return 0;                   /* appease compiler */
03224 }
03225 
03226 static const char *
03227 privilege_to_string(AclMode privilege)
03228 {
03229     switch (privilege)
03230     {
03231         case ACL_INSERT:
03232             return "INSERT";
03233         case ACL_SELECT:
03234             return "SELECT";
03235         case ACL_UPDATE:
03236             return "UPDATE";
03237         case ACL_DELETE:
03238             return "DELETE";
03239         case ACL_TRUNCATE:
03240             return "TRUNCATE";
03241         case ACL_REFERENCES:
03242             return "REFERENCES";
03243         case ACL_TRIGGER:
03244             return "TRIGGER";
03245         case ACL_EXECUTE:
03246             return "EXECUTE";
03247         case ACL_USAGE:
03248             return "USAGE";
03249         case ACL_CREATE:
03250             return "CREATE";
03251         case ACL_CREATE_TEMP:
03252             return "TEMP";
03253         case ACL_CONNECT:
03254             return "CONNECT";
03255         default:
03256             elog(ERROR, "unrecognized privilege: %d", (int) privilege);
03257     }
03258     return NULL;                /* appease compiler */
03259 }
03260 
03261 /*
03262  * Standardized reporting of aclcheck permissions failures.
03263  *
03264  * Note: we do not double-quote the %s's below, because many callers
03265  * supply strings that might be already quoted.
03266  */
03267 
03268 static const char *const no_priv_msg[MAX_ACL_KIND] =
03269 {
03270     /* ACL_KIND_COLUMN */
03271     gettext_noop("permission denied for column %s"),
03272     /* ACL_KIND_CLASS */
03273     gettext_noop("permission denied for relation %s"),
03274     /* ACL_KIND_SEQUENCE */
03275     gettext_noop("permission denied for sequence %s"),
03276     /* ACL_KIND_DATABASE */
03277     gettext_noop("permission denied for database %s"),
03278     /* ACL_KIND_PROC */
03279     gettext_noop("permission denied for function %s"),
03280     /* ACL_KIND_OPER */
03281     gettext_noop("permission denied for operator %s"),
03282     /* ACL_KIND_TYPE */
03283     gettext_noop("permission denied for type %s"),
03284     /* ACL_KIND_LANGUAGE */
03285     gettext_noop("permission denied for language %s"),
03286     /* ACL_KIND_LARGEOBJECT */
03287     gettext_noop("permission denied for large object %s"),
03288     /* ACL_KIND_NAMESPACE */
03289     gettext_noop("permission denied for schema %s"),
03290     /* ACL_KIND_OPCLASS */
03291     gettext_noop("permission denied for operator class %s"),
03292     /* ACL_KIND_OPFAMILY */
03293     gettext_noop("permission denied for operator family %s"),
03294     /* ACL_KIND_COLLATION */
03295     gettext_noop("permission denied for collation %s"),
03296     /* ACL_KIND_CONVERSION */
03297     gettext_noop("permission denied for conversion %s"),
03298     /* ACL_KIND_TABLESPACE */
03299     gettext_noop("permission denied for tablespace %s"),
03300     /* ACL_KIND_TSDICTIONARY */
03301     gettext_noop("permission denied for text search dictionary %s"),
03302     /* ACL_KIND_TSCONFIGURATION */
03303     gettext_noop("permission denied for text search configuration %s"),
03304     /* ACL_KIND_FDW */
03305     gettext_noop("permission denied for foreign-data wrapper %s"),
03306     /* ACL_KIND_FOREIGN_SERVER */
03307     gettext_noop("permission denied for foreign server %s"),
03308     /* ACL_KIND_EVENT_TRIGGER */
03309     gettext_noop("permission denied for event trigger %s"),
03310     /* ACL_KIND_EXTENSION */
03311     gettext_noop("permission denied for extension %s"),
03312 };
03313 
03314 static const char *const not_owner_msg[MAX_ACL_KIND] =
03315 {
03316     /* ACL_KIND_COLUMN */
03317     gettext_noop("must be owner of relation %s"),
03318     /* ACL_KIND_CLASS */
03319     gettext_noop("must be owner of relation %s"),
03320     /* ACL_KIND_SEQUENCE */
03321     gettext_noop("must be owner of sequence %s"),
03322     /* ACL_KIND_DATABASE */
03323     gettext_noop("must be owner of database %s"),
03324     /* ACL_KIND_PROC */
03325     gettext_noop("must be owner of function %s"),
03326     /* ACL_KIND_OPER */
03327     gettext_noop("must be owner of operator %s"),
03328     /* ACL_KIND_TYPE */
03329     gettext_noop("must be owner of type %s"),
03330     /* ACL_KIND_LANGUAGE */
03331     gettext_noop("must be owner of language %s"),
03332     /* ACL_KIND_LARGEOBJECT */
03333     gettext_noop("must be owner of large object %s"),
03334     /* ACL_KIND_NAMESPACE */
03335     gettext_noop("must be owner of schema %s"),
03336     /* ACL_KIND_OPCLASS */
03337     gettext_noop("must be owner of operator class %s"),
03338     /* ACL_KIND_OPFAMILY */
03339     gettext_noop("must be owner of operator family %s"),
03340     /* ACL_KIND_COLLATION */
03341     gettext_noop("must be owner of collation %s"),
03342     /* ACL_KIND_CONVERSION */
03343     gettext_noop("must be owner of conversion %s"),
03344     /* ACL_KIND_TABLESPACE */
03345     gettext_noop("must be owner of tablespace %s"),
03346     /* ACL_KIND_TSDICTIONARY */
03347     gettext_noop("must be owner of text search dictionary %s"),
03348     /* ACL_KIND_TSCONFIGURATION */
03349     gettext_noop("must be owner of text search configuration %s"),
03350     /* ACL_KIND_FDW */
03351     gettext_noop("must be owner of foreign-data wrapper %s"),
03352     /* ACL_KIND_FOREIGN_SERVER */
03353     gettext_noop("must be owner of foreign server %s"),
03354     /* ACL_KIND_EVENT_TRIGGER */
03355     gettext_noop("must be owner of event trigger %s"),
03356     /* ACL_KIND_EXTENSION */
03357     gettext_noop("must be owner of extension %s"),
03358 };
03359 
03360 
03361 void
03362 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
03363                const char *objectname)
03364 {
03365     switch (aclerr)
03366     {
03367         case ACLCHECK_OK:
03368             /* no error, so return to caller */
03369             break;
03370         case ACLCHECK_NO_PRIV:
03371             ereport(ERROR,
03372                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03373                      errmsg(no_priv_msg[objectkind], objectname)));
03374             break;
03375         case ACLCHECK_NOT_OWNER:
03376             ereport(ERROR,
03377                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03378                      errmsg(not_owner_msg[objectkind], objectname)));
03379             break;
03380         default:
03381             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
03382             break;
03383     }
03384 }
03385 
03386 
03387 void
03388 aclcheck_error_col(AclResult aclerr, AclObjectKind objectkind,
03389                    const char *objectname, const char *colname)
03390 {
03391     switch (aclerr)
03392     {
03393         case ACLCHECK_OK:
03394             /* no error, so return to caller */
03395             break;
03396         case ACLCHECK_NO_PRIV:
03397             ereport(ERROR,
03398                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03399              errmsg("permission denied for column \"%s\" of relation \"%s\"",
03400                     colname, objectname)));
03401             break;
03402         case ACLCHECK_NOT_OWNER:
03403             /* relation msg is OK since columns don't have separate owners */
03404             ereport(ERROR,
03405                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
03406                      errmsg(not_owner_msg[objectkind], objectname)));
03407             break;
03408         default:
03409             elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
03410             break;
03411     }
03412 }
03413 
03414 
03415 /*
03416  * Special common handling for types: use element type instead of array type,
03417  * and format nicely
03418  */
03419 void
03420 aclcheck_error_type(AclResult aclerr, Oid typeOid)
03421 {
03422     Oid element_type = get_element_type(typeOid);
03423 
03424     aclcheck_error(aclerr, ACL_KIND_TYPE, format_type_be(element_type ? element_type : typeOid));
03425 }
03426 
03427 
03428 /* Check if given user has rolcatupdate privilege according to pg_authid */
03429 static bool
03430 has_rolcatupdate(Oid roleid)
03431 {
03432     bool        rolcatupdate;
03433     HeapTuple   tuple;
03434 
03435     tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
03436     if (!HeapTupleIsValid(tuple))
03437         ereport(ERROR,
03438                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03439                  errmsg("role with OID %u does not exist", roleid)));
03440 
03441     rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
03442 
03443     ReleaseSysCache(tuple);
03444 
03445     return rolcatupdate;
03446 }
03447 
03448 /*
03449  * Relay for the various pg_*_mask routines depending on object kind
03450  */
03451 static AclMode
03452 pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
03453            AclMode mask, AclMaskHow how)
03454 {
03455     switch (objkind)
03456     {
03457         case ACL_KIND_COLUMN:
03458             return
03459                 pg_class_aclmask(table_oid, roleid, mask, how) |
03460                 pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
03461         case ACL_KIND_CLASS:
03462         case ACL_KIND_SEQUENCE:
03463             return pg_class_aclmask(table_oid, roleid, mask, how);
03464         case ACL_KIND_DATABASE:
03465             return pg_database_aclmask(table_oid, roleid, mask, how);
03466         case ACL_KIND_PROC:
03467             return pg_proc_aclmask(table_oid, roleid, mask, how);
03468         case ACL_KIND_LANGUAGE:
03469             return pg_language_aclmask(table_oid, roleid, mask, how);
03470         case ACL_KIND_LARGEOBJECT:
03471             return pg_largeobject_aclmask_snapshot(table_oid, roleid,
03472                                                    mask, how, SnapshotNow);
03473         case ACL_KIND_NAMESPACE:
03474             return pg_namespace_aclmask(table_oid, roleid, mask, how);
03475         case ACL_KIND_TABLESPACE:
03476             return pg_tablespace_aclmask(table_oid, roleid, mask, how);
03477         case ACL_KIND_FDW:
03478             return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
03479         case ACL_KIND_FOREIGN_SERVER:
03480             return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
03481         case ACL_KIND_EVENT_TRIGGER:
03482             elog(ERROR, "grantable rights not supported for event triggers");
03483             /* not reached, but keep compiler quiet */
03484             return ACL_NO_RIGHTS;
03485         case ACL_KIND_TYPE:
03486             return pg_type_aclmask(table_oid, roleid, mask, how);
03487         default:
03488             elog(ERROR, "unrecognized objkind: %d",
03489                  (int) objkind);
03490             /* not reached, but keep compiler quiet */
03491             return ACL_NO_RIGHTS;
03492     }
03493 }
03494 
03495 
03496 /* ****************************************************************
03497  * Exported routines for examining a user's privileges for various objects
03498  *
03499  * See aclmask() for a description of the common API for these functions.
03500  *
03501  * Note: we give lookup failure the full ereport treatment because the
03502  * has_xxx_privilege() family of functions allow users to pass any random
03503  * OID to these functions.
03504  * ****************************************************************
03505  */
03506 
03507 /*
03508  * Exported routine for examining a user's privileges for a column
03509  *
03510  * Note: this considers only privileges granted specifically on the column.
03511  * It is caller's responsibility to take relation-level privileges into account
03512  * as appropriate.  (For the same reason, we have no special case for
03513  * superuser-ness here.)
03514  */
03515 AclMode
03516 pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
03517                      AclMode mask, AclMaskHow how)
03518 {
03519     AclMode     result;
03520     HeapTuple   classTuple;
03521     HeapTuple   attTuple;
03522     Form_pg_class classForm;
03523     Form_pg_attribute attributeForm;
03524     Datum       aclDatum;
03525     bool        isNull;
03526     Acl        *acl;
03527     Oid         ownerId;
03528 
03529     /*
03530      * First, get the column's ACL from its pg_attribute entry
03531      */
03532     attTuple = SearchSysCache2(ATTNUM,
03533                                ObjectIdGetDatum(table_oid),
03534                                Int16GetDatum(attnum));
03535     if (!HeapTupleIsValid(attTuple))
03536         ereport(ERROR,
03537                 (errcode(ERRCODE_UNDEFINED_COLUMN),
03538                  errmsg("attribute %d of relation with OID %u does not exist",
03539                         attnum, table_oid)));
03540     attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
03541 
03542     /* Throw error on dropped columns, too */
03543     if (attributeForm->attisdropped)
03544         ereport(ERROR,
03545                 (errcode(ERRCODE_UNDEFINED_COLUMN),
03546                  errmsg("attribute %d of relation with OID %u does not exist",
03547                         attnum, table_oid)));
03548 
03549     aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
03550                                &isNull);
03551 
03552     /*
03553      * Here we hard-wire knowledge that the default ACL for a column grants no
03554      * privileges, so that we can fall out quickly in the very common case
03555      * where attacl is null.
03556      */
03557     if (isNull)
03558     {
03559         ReleaseSysCache(attTuple);
03560         return 0;
03561     }
03562 
03563     /*
03564      * Must get the relation's ownerId from pg_class.  Since we already found
03565      * a pg_attribute entry, the only likely reason for this to fail is that a
03566      * concurrent DROP of the relation committed since then (which could only
03567      * happen if we don't have lock on the relation).  We prefer to report "no
03568      * privileges" rather than failing in such a case, so as to avoid unwanted
03569      * failures in has_column_privilege() tests.
03570      */
03571     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
03572     if (!HeapTupleIsValid(classTuple))
03573     {
03574         ReleaseSysCache(attTuple);
03575         return 0;
03576     }
03577     classForm = (Form_pg_class) GETSTRUCT(classTuple);
03578 
03579     ownerId = classForm->relowner;
03580 
03581     ReleaseSysCache(classTuple);
03582 
03583     /* detoast column's ACL if necessary */
03584     acl = DatumGetAclP(aclDatum);
03585 
03586     result = aclmask(acl, roleid, ownerId, mask, how);
03587 
03588     /* if we have a detoasted copy, free it */
03589     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03590         pfree(acl);
03591 
03592     ReleaseSysCache(attTuple);
03593 
03594     return result;
03595 }
03596 
03597 /*
03598  * Exported routine for examining a user's privileges for a table
03599  */
03600 AclMode
03601 pg_class_aclmask(Oid table_oid, Oid roleid,
03602                  AclMode mask, AclMaskHow how)
03603 {
03604     AclMode     result;
03605     HeapTuple   tuple;
03606     Form_pg_class classForm;
03607     Datum       aclDatum;
03608     bool        isNull;
03609     Acl        *acl;
03610     Oid         ownerId;
03611 
03612     /*
03613      * Must get the relation's tuple from pg_class
03614      */
03615     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
03616     if (!HeapTupleIsValid(tuple))
03617         ereport(ERROR,
03618                 (errcode(ERRCODE_UNDEFINED_TABLE),
03619                  errmsg("relation with OID %u does not exist",
03620                         table_oid)));
03621     classForm = (Form_pg_class) GETSTRUCT(tuple);
03622 
03623     /*
03624      * Deny anyone permission to update a system catalog unless
03625      * pg_authid.rolcatupdate is set.   (This is to let superusers protect
03626      * themselves from themselves.)  Also allow it if allowSystemTableMods.
03627      *
03628      * As of 7.4 we have some updatable system views; those shouldn't be
03629      * protected in this way.  Assume the view rules can take care of
03630      * themselves.  ACL_USAGE is if we ever have system sequences.
03631      */
03632     if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
03633         IsSystemClass(classForm) &&
03634         classForm->relkind != RELKIND_VIEW &&
03635         !has_rolcatupdate(roleid) &&
03636         !allowSystemTableMods)
03637     {
03638 #ifdef ACLDEBUG
03639         elog(DEBUG2, "permission denied for system catalog update");
03640 #endif
03641         mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
03642     }
03643 
03644     /*
03645      * Otherwise, superusers bypass all permission-checking.
03646      */
03647     if (superuser_arg(roleid))
03648     {
03649 #ifdef ACLDEBUG
03650         elog(DEBUG2, "OID %u is superuser, home free", roleid);
03651 #endif
03652         ReleaseSysCache(tuple);
03653         return mask;
03654     }
03655 
03656     /*
03657      * Normal case: get the relation's ACL from pg_class
03658      */
03659     ownerId = classForm->relowner;
03660 
03661     aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
03662                                &isNull);
03663     if (isNull)
03664     {
03665         /* No ACL, so build default ACL */
03666         switch (classForm->relkind)
03667         {
03668             case RELKIND_SEQUENCE:
03669                 acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);
03670                 break;
03671             default:
03672                 acl = acldefault(ACL_OBJECT_RELATION, ownerId);
03673                 break;
03674         }
03675         aclDatum = (Datum) 0;
03676     }
03677     else
03678     {
03679         /* detoast rel's ACL if necessary */
03680         acl = DatumGetAclP(aclDatum);
03681     }
03682 
03683     result = aclmask(acl, roleid, ownerId, mask, how);
03684 
03685     /* if we have a detoasted copy, free it */
03686     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03687         pfree(acl);
03688 
03689     ReleaseSysCache(tuple);
03690 
03691     return result;
03692 }
03693 
03694 /*
03695  * Exported routine for examining a user's privileges for a database
03696  */
03697 AclMode
03698 pg_database_aclmask(Oid db_oid, Oid roleid,
03699                     AclMode mask, AclMaskHow how)
03700 {
03701     AclMode     result;
03702     HeapTuple   tuple;
03703     Datum       aclDatum;
03704     bool        isNull;
03705     Acl        *acl;
03706     Oid         ownerId;
03707 
03708     /* Superusers bypass all permission checking. */
03709     if (superuser_arg(roleid))
03710         return mask;
03711 
03712     /*
03713      * Get the database's ACL from pg_database
03714      */
03715     tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
03716     if (!HeapTupleIsValid(tuple))
03717         ereport(ERROR,
03718                 (errcode(ERRCODE_UNDEFINED_DATABASE),
03719                  errmsg("database with OID %u does not exist", db_oid)));
03720 
03721     ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
03722 
03723     aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
03724                                &isNull);
03725     if (isNull)
03726     {
03727         /* No ACL, so build default ACL */
03728         acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
03729         aclDatum = (Datum) 0;
03730     }
03731     else
03732     {
03733         /* detoast ACL if necessary */
03734         acl = DatumGetAclP(aclDatum);
03735     }
03736 
03737     result = aclmask(acl, roleid, ownerId, mask, how);
03738 
03739     /* if we have a detoasted copy, free it */
03740     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03741         pfree(acl);
03742 
03743     ReleaseSysCache(tuple);
03744 
03745     return result;
03746 }
03747 
03748 /*
03749  * Exported routine for examining a user's privileges for a function
03750  */
03751 AclMode
03752 pg_proc_aclmask(Oid proc_oid, Oid roleid,
03753                 AclMode mask, AclMaskHow how)
03754 {
03755     AclMode     result;
03756     HeapTuple   tuple;
03757     Datum       aclDatum;
03758     bool        isNull;
03759     Acl        *acl;
03760     Oid         ownerId;
03761 
03762     /* Superusers bypass all permission checking. */
03763     if (superuser_arg(roleid))
03764         return mask;
03765 
03766     /*
03767      * Get the function's ACL from pg_proc
03768      */
03769     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
03770     if (!HeapTupleIsValid(tuple))
03771         ereport(ERROR,
03772                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
03773                  errmsg("function with OID %u does not exist", proc_oid)));
03774 
03775     ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
03776 
03777     aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
03778                                &isNull);
03779     if (isNull)
03780     {
03781         /* No ACL, so build default ACL */
03782         acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
03783         aclDatum = (Datum) 0;
03784     }
03785     else
03786     {
03787         /* detoast ACL if necessary */
03788         acl = DatumGetAclP(aclDatum);
03789     }
03790 
03791     result = aclmask(acl, roleid, ownerId, mask, how);
03792 
03793     /* if we have a detoasted copy, free it */
03794     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03795         pfree(acl);
03796 
03797     ReleaseSysCache(tuple);
03798 
03799     return result;
03800 }
03801 
03802 /*
03803  * Exported routine for examining a user's privileges for a language
03804  */
03805 AclMode
03806 pg_language_aclmask(Oid lang_oid, Oid roleid,
03807                     AclMode mask, AclMaskHow how)
03808 {
03809     AclMode     result;
03810     HeapTuple   tuple;
03811     Datum       aclDatum;
03812     bool        isNull;
03813     Acl        *acl;
03814     Oid         ownerId;
03815 
03816     /* Superusers bypass all permission checking. */
03817     if (superuser_arg(roleid))
03818         return mask;
03819 
03820     /*
03821      * Get the language's ACL from pg_language
03822      */
03823     tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
03824     if (!HeapTupleIsValid(tuple))
03825         ereport(ERROR,
03826                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03827                  errmsg("language with OID %u does not exist", lang_oid)));
03828 
03829     ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
03830 
03831     aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
03832                                &isNull);
03833     if (isNull)
03834     {
03835         /* No ACL, so build default ACL */
03836         acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
03837         aclDatum = (Datum) 0;
03838     }
03839     else
03840     {
03841         /* detoast ACL if necessary */
03842         acl = DatumGetAclP(aclDatum);
03843     }
03844 
03845     result = aclmask(acl, roleid, ownerId, mask, how);
03846 
03847     /* if we have a detoasted copy, free it */
03848     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03849         pfree(acl);
03850 
03851     ReleaseSysCache(tuple);
03852 
03853     return result;
03854 }
03855 
03856 /*
03857  * Exported routine for examining a user's privileges for a largeobject
03858  *
03859  * When a large object is opened for reading, it is opened relative to the
03860  * caller's snapshot, but when it is opened for writing, it is always relative
03861  * to SnapshotNow, as documented in doc/src/sgml/lobj.sgml.  This function
03862  * takes a snapshot argument so that the permissions check can be made relative
03863  * to the same snapshot that will be used to read the underlying data.
03864  */
03865 AclMode
03866 pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
03867                                 AclMode mask, AclMaskHow how,
03868                                 Snapshot snapshot)
03869 {
03870     AclMode     result;
03871     Relation    pg_lo_meta;
03872     ScanKeyData entry[1];
03873     SysScanDesc scan;
03874     HeapTuple   tuple;
03875     Datum       aclDatum;
03876     bool        isNull;
03877     Acl        *acl;
03878     Oid         ownerId;
03879 
03880     /* Superusers bypass all permission checking. */
03881     if (superuser_arg(roleid))
03882         return mask;
03883 
03884     /*
03885      * Get the largeobject's ACL from pg_language_metadata
03886      */
03887     pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
03888                            AccessShareLock);
03889 
03890     ScanKeyInit(&entry[0],
03891                 ObjectIdAttributeNumber,
03892                 BTEqualStrategyNumber, F_OIDEQ,
03893                 ObjectIdGetDatum(lobj_oid));
03894 
03895     scan = systable_beginscan(pg_lo_meta,
03896                               LargeObjectMetadataOidIndexId, true,
03897                               snapshot, 1, entry);
03898 
03899     tuple = systable_getnext(scan);
03900     if (!HeapTupleIsValid(tuple))
03901         ereport(ERROR,
03902                 (errcode(ERRCODE_UNDEFINED_OBJECT),
03903                  errmsg("large object %u does not exist", lobj_oid)));
03904 
03905     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
03906 
03907     aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
03908                             RelationGetDescr(pg_lo_meta), &isNull);
03909 
03910     if (isNull)
03911     {
03912         /* No ACL, so build default ACL */
03913         acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
03914         aclDatum = (Datum) 0;
03915     }
03916     else
03917     {
03918         /* detoast ACL if necessary */
03919         acl = DatumGetAclP(aclDatum);
03920     }
03921 
03922     result = aclmask(acl, roleid, ownerId, mask, how);
03923 
03924     /* if we have a detoasted copy, free it */
03925     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
03926         pfree(acl);
03927 
03928     systable_endscan(scan);
03929 
03930     heap_close(pg_lo_meta, AccessShareLock);
03931 
03932     return result;
03933 }
03934 
03935 /*
03936  * Exported routine for examining a user's privileges for a namespace
03937  */
03938 AclMode
03939 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
03940                      AclMode mask, AclMaskHow how)
03941 {
03942     AclMode     result;
03943     HeapTuple   tuple;
03944     Datum       aclDatum;
03945     bool        isNull;
03946     Acl        *acl;
03947     Oid         ownerId;
03948 
03949     /* Superusers bypass all permission checking. */
03950     if (superuser_arg(roleid))
03951         return mask;
03952 
03953     /*
03954      * If we have been assigned this namespace as a temp namespace, check to
03955      * make sure we have CREATE TEMP permission on the database, and if so act
03956      * as though we have all standard (but not GRANT OPTION) permissions on
03957      * the namespace.  If we don't have CREATE TEMP, act as though we have
03958      * only USAGE (and not CREATE) rights.
03959      *
03960      * This may seem redundant given the check in InitTempTableNamespace, but
03961      * it really isn't since current user ID may have changed since then. The
03962      * upshot of this behavior is that a SECURITY DEFINER function can create
03963      * temp tables that can then be accessed (if permission is granted) by
03964      * code in the same session that doesn't have permissions to create temp
03965      * tables.
03966      *
03967      * XXX Would it be safe to ereport a special error message as
03968      * InitTempTableNamespace does?  Returning zero here means we'll get a
03969      * generic "permission denied for schema pg_temp_N" message, which is not
03970      * remarkably user-friendly.
03971      */
03972     if (isTempNamespace(nsp_oid))
03973     {
03974         if (pg_database_aclcheck(MyDatabaseId, roleid,
03975                                  ACL_CREATE_TEMP) == ACLCHECK_OK)
03976             return mask & ACL_ALL_RIGHTS_NAMESPACE;
03977         else
03978             return mask & ACL_USAGE;
03979     }
03980 
03981     /*
03982      * Get the schema's ACL from pg_namespace
03983      */
03984     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
03985     if (!HeapTupleIsValid(tuple))
03986         ereport(ERROR,
03987                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
03988                  errmsg("schema with OID %u does not exist", nsp_oid)));
03989 
03990     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
03991 
03992     aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
03993                                &isNull);
03994     if (isNull)
03995     {
03996         /* No ACL, so build default ACL */
03997         acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
03998         aclDatum = (Datum) 0;
03999     }
04000     else
04001     {
04002         /* detoast ACL if necessary */
04003         acl = DatumGetAclP(aclDatum);
04004     }
04005 
04006     result = aclmask(acl, roleid, ownerId, mask, how);
04007 
04008     /* if we have a detoasted copy, free it */
04009     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
04010         pfree(acl);
04011 
04012     ReleaseSysCache(tuple);
04013 
04014     return result;
04015 }
04016 
04017 /*
04018  * Exported routine for examining a user's privileges for a tablespace
04019  */
04020 AclMode
04021 pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
04022                       AclMode mask, AclMaskHow how)
04023 {
04024     AclMode     result;
04025     HeapTuple   tuple;
04026     Datum       aclDatum;
04027     bool        isNull;
04028     Acl        *acl;
04029     Oid         ownerId;
04030 
04031     /* Superusers bypass all permission checking. */
04032     if (superuser_arg(roleid))
04033         return mask;
04034 
04035     /*
04036      * Get the tablespace's ACL from pg_tablespace
04037      */
04038     tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
04039     if (!HeapTupleIsValid(tuple))
04040         ereport(ERROR,
04041                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04042                  errmsg("tablespace with OID %u does not exist", spc_oid)));
04043 
04044     ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
04045 
04046     aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
04047                                Anum_pg_tablespace_spcacl,
04048                                &isNull);
04049 
04050     if (isNull)
04051     {
04052         /* No ACL, so build default ACL */
04053         acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
04054         aclDatum = (Datum) 0;
04055     }
04056     else
04057     {
04058         /* detoast ACL if necessary */
04059         acl = DatumGetAclP(aclDatum);
04060     }
04061 
04062     result = aclmask(acl, roleid, ownerId, mask, how);
04063 
04064     /* if we have a detoasted copy, free it */
04065     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
04066         pfree(acl);
04067 
04068     ReleaseSysCache(tuple);
04069 
04070     return result;
04071 }
04072 
04073 /*
04074  * Exported routine for examining a user's privileges for a foreign
04075  * data wrapper
04076  */
04077 AclMode
04078 pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
04079                                 AclMode mask, AclMaskHow how)
04080 {
04081     AclMode     result;
04082     HeapTuple   tuple;
04083     Datum       aclDatum;
04084     bool        isNull;
04085     Acl        *acl;
04086     Oid         ownerId;
04087 
04088     Form_pg_foreign_data_wrapper fdwForm;
04089 
04090     /* Bypass permission checks for superusers */
04091     if (superuser_arg(roleid))
04092         return mask;
04093 
04094     /*
04095      * Must get the FDW's tuple from pg_foreign_data_wrapper
04096      */
04097     tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
04098     if (!HeapTupleIsValid(tuple))
04099         ereport(ERROR,
04100                 (errmsg("foreign-data wrapper with OID %u does not exist",
04101                         fdw_oid)));
04102     fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
04103 
04104     /*
04105      * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
04106      */
04107     ownerId = fdwForm->fdwowner;
04108 
04109     aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
04110                                Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
04111     if (isNull)
04112     {
04113         /* No ACL, so build default ACL */
04114         acl = acldefault(ACL_OBJECT_FDW, ownerId);
04115         aclDatum = (Datum) 0;
04116     }
04117     else
04118     {
04119         /* detoast rel's ACL if necessary */
04120         acl = DatumGetAclP(aclDatum);
04121     }
04122 
04123     result = aclmask(acl, roleid, ownerId, mask, how);
04124 
04125     /* if we have a detoasted copy, free it */
04126     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
04127         pfree(acl);
04128 
04129     ReleaseSysCache(tuple);
04130 
04131     return result;
04132 }
04133 
04134 /*
04135  * Exported routine for examining a user's privileges for a foreign
04136  * server.
04137  */
04138 AclMode
04139 pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
04140                           AclMode mask, AclMaskHow how)
04141 {
04142     AclMode     result;
04143     HeapTuple   tuple;
04144     Datum       aclDatum;
04145     bool        isNull;
04146     Acl        *acl;
04147     Oid         ownerId;
04148 
04149     Form_pg_foreign_server srvForm;
04150 
04151     /* Bypass permission checks for superusers */
04152     if (superuser_arg(roleid))
04153         return mask;
04154 
04155     /*
04156      * Must get the FDW's tuple from pg_foreign_data_wrapper
04157      */
04158     tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
04159     if (!HeapTupleIsValid(tuple))
04160         ereport(ERROR,
04161                 (errmsg("foreign server with OID %u does not exist",
04162                         srv_oid)));
04163     srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
04164 
04165     /*
04166      * Normal case: get the foreign server's ACL from pg_foreign_server
04167      */
04168     ownerId = srvForm->srvowner;
04169 
04170     aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
04171                                Anum_pg_foreign_server_srvacl, &isNull);
04172     if (isNull)
04173     {
04174         /* No ACL, so build default ACL */
04175         acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
04176         aclDatum = (Datum) 0;
04177     }
04178     else
04179     {
04180         /* detoast rel's ACL if necessary */
04181         acl = DatumGetAclP(aclDatum);
04182     }
04183 
04184     result = aclmask(acl, roleid, ownerId, mask, how);
04185 
04186     /* if we have a detoasted copy, free it */
04187     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
04188         pfree(acl);
04189 
04190     ReleaseSysCache(tuple);
04191 
04192     return result;
04193 }
04194 
04195 /*
04196  * Exported routine for examining a user's privileges for a type.
04197  */
04198 AclMode
04199 pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
04200 {
04201     AclMode     result;
04202     HeapTuple   tuple;
04203     Datum       aclDatum;
04204     bool        isNull;
04205     Acl        *acl;
04206     Oid         ownerId;
04207 
04208     Form_pg_type typeForm;
04209 
04210     /* Bypass permission checks for superusers */
04211     if (superuser_arg(roleid))
04212         return mask;
04213 
04214     /*
04215      * Must get the type's tuple from pg_type
04216      */
04217     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
04218     if (!HeapTupleIsValid(tuple))
04219         ereport(ERROR,
04220                 (errmsg("type with OID %u does not exist",
04221                         type_oid)));
04222     typeForm = (Form_pg_type) GETSTRUCT(tuple);
04223 
04224     /* "True" array types don't manage permissions of their own */
04225     if (typeForm->typelem != 0 && typeForm->typlen == -1)
04226     {
04227         Oid         elttype_oid = typeForm->typelem;
04228 
04229         ReleaseSysCache(tuple);
04230 
04231         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
04232         if (!HeapTupleIsValid(tuple))
04233             ereport(ERROR,
04234                     (errmsg("type with OID %u does not exist",
04235                             type_oid)));
04236         typeForm = (Form_pg_type) GETSTRUCT(tuple);
04237     }
04238 
04239     /*
04240      * Normal case: get the type's ACL from pg_type
04241      */
04242     ownerId = typeForm->typowner;
04243 
04244     aclDatum = SysCacheGetAttr(TYPEOID, tuple,
04245                                Anum_pg_type_typacl, &isNull);
04246     if (isNull)
04247     {
04248         /* No ACL, so build default ACL */
04249         acl = acldefault(ACL_OBJECT_TYPE, ownerId);
04250         aclDatum = (Datum) 0;
04251     }
04252     else
04253     {
04254         /* detoast rel's ACL if necessary */
04255         acl = DatumGetAclP(aclDatum);
04256     }
04257 
04258     result = aclmask(acl, roleid, ownerId, mask, how);
04259 
04260     /* if we have a detoasted copy, free it */
04261     if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
04262         pfree(acl);
04263 
04264     ReleaseSysCache(tuple);
04265 
04266     return result;
04267 }
04268 
04269 /*
04270  * Exported routine for checking a user's access privileges to a column
04271  *
04272  * Returns ACLCHECK_OK if the user has any of the privileges identified by
04273  * 'mode'; otherwise returns a suitable error code (in practice, always
04274  * ACLCHECK_NO_PRIV).
04275  *
04276  * As with pg_attribute_aclmask, only privileges granted directly on the
04277  * column are considered here.
04278  */
04279 AclResult
04280 pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
04281                       Oid roleid, AclMode mode)
04282 {
04283     if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
04284         return ACLCHECK_OK;
04285     else
04286         return ACLCHECK_NO_PRIV;
04287 }
04288 
04289 /*
04290  * Exported routine for checking a user's access privileges to any/all columns
04291  *
04292  * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
04293  * privileges identified by 'mode' on any non-dropped column in the relation;
04294  * otherwise returns a suitable error code (in practice, always
04295  * ACLCHECK_NO_PRIV).
04296  *
04297  * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
04298  * privileges identified by 'mode' on each non-dropped column in the relation
04299  * (and there must be at least one such column); otherwise returns a suitable
04300  * error code (in practice, always ACLCHECK_NO_PRIV).
04301  *
04302  * As with pg_attribute_aclmask, only privileges granted directly on the
04303  * column(s) are considered here.
04304  *
04305  * Note: system columns are not considered here; there are cases where that
04306  * might be appropriate but there are also cases where it wouldn't.
04307  */
04308 AclResult
04309 pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
04310                           AclMaskHow how)
04311 {
04312     AclResult   result;
04313     HeapTuple   classTuple;
04314     Form_pg_class classForm;
04315     AttrNumber  nattrs;
04316     AttrNumber  curr_att;
04317 
04318     /*
04319      * Must fetch pg_class row to check number of attributes.  As in
04320      * pg_attribute_aclmask, we prefer to return "no privileges" instead of
04321      * throwing an error if we get any unexpected lookup errors.
04322      */
04323     classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
04324     if (!HeapTupleIsValid(classTuple))
04325         return ACLCHECK_NO_PRIV;
04326     classForm = (Form_pg_class) GETSTRUCT(classTuple);
04327 
04328     nattrs = classForm->relnatts;
04329 
04330     ReleaseSysCache(classTuple);
04331 
04332     /*
04333      * Initialize result in case there are no non-dropped columns.  We want to
04334      * report failure in such cases for either value of 'how'.
04335      */
04336     result = ACLCHECK_NO_PRIV;
04337 
04338     for (curr_att = 1; curr_att <= nattrs; curr_att++)
04339     {
04340         HeapTuple   attTuple;
04341         AclMode     attmask;
04342 
04343         attTuple = SearchSysCache2(ATTNUM,
04344                                    ObjectIdGetDatum(table_oid),
04345                                    Int16GetDatum(curr_att));
04346         if (!HeapTupleIsValid(attTuple))
04347             continue;
04348 
04349         /* ignore dropped columns */
04350         if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
04351         {
04352             ReleaseSysCache(attTuple);
04353             continue;
04354         }
04355 
04356         /*
04357          * Here we hard-wire knowledge that the default ACL for a column
04358          * grants no privileges, so that we can fall out quickly in the very
04359          * common case where attacl is null.
04360          */
04361         if (heap_attisnull(attTuple, Anum_pg_attribute_attacl))
04362             attmask = 0;
04363         else
04364             attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
04365                                            mode, ACLMASK_ANY);
04366 
04367         ReleaseSysCache(attTuple);
04368 
04369         if (attmask != 0)
04370         {
04371             result = ACLCHECK_OK;
04372             if (how == ACLMASK_ANY)
04373                 break;          /* succeed on any success */
04374         }
04375         else
04376         {
04377             result = ACLCHECK_NO_PRIV;
04378             if (how == ACLMASK_ALL)
04379                 break;          /* fail on any failure */
04380         }
04381     }
04382 
04383     return result;
04384 }
04385 
04386 /*
04387  * Exported routine for checking a user's access privileges to a table
04388  *
04389  * Returns ACLCHECK_OK if the user has any of the privileges identified by
04390  * 'mode'; otherwise returns a suitable error code (in practice, always
04391  * ACLCHECK_NO_PRIV).
04392  */
04393 AclResult
04394 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
04395 {
04396     if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
04397         return ACLCHECK_OK;
04398     else
04399         return ACLCHECK_NO_PRIV;
04400 }
04401 
04402 /*
04403  * Exported routine for checking a user's access privileges to a database
04404  */
04405 AclResult
04406 pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
04407 {
04408     if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
04409         return ACLCHECK_OK;
04410     else
04411         return ACLCHECK_NO_PRIV;
04412 }
04413 
04414 /*
04415  * Exported routine for checking a user's access privileges to a function
04416  */
04417 AclResult
04418 pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
04419 {
04420     if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
04421         return ACLCHECK_OK;
04422     else
04423         return ACLCHECK_NO_PRIV;
04424 }
04425 
04426 /*
04427  * Exported routine for checking a user's access privileges to a language
04428  */
04429 AclResult
04430 pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
04431 {
04432     if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
04433         return ACLCHECK_OK;
04434     else
04435         return ACLCHECK_NO_PRIV;
04436 }
04437 
04438 /*
04439  * Exported routine for checking a user's access privileges to a largeobject
04440  */
04441 AclResult
04442 pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
04443                                  Snapshot snapshot)
04444 {
04445     if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
04446                                         ACLMASK_ANY, snapshot) != 0)
04447         return ACLCHECK_OK;
04448     else
04449         return ACLCHECK_NO_PRIV;
04450 }
04451 
04452 /*
04453  * Exported routine for checking a user's access privileges to a namespace
04454  */
04455 AclResult
04456 pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
04457 {
04458     if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
04459         return ACLCHECK_OK;
04460     else
04461         return ACLCHECK_NO_PRIV;
04462 }
04463 
04464 /*
04465  * Exported routine for checking a user's access privileges to a tablespace
04466  */
04467 AclResult
04468 pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
04469 {
04470     if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
04471         return ACLCHECK_OK;
04472     else
04473         return ACLCHECK_NO_PRIV;
04474 }
04475 
04476 /*
04477  * Exported routine for checking a user's access privileges to a foreign
04478  * data wrapper
04479  */
04480 AclResult
04481 pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
04482 {
04483     if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
04484         return ACLCHECK_OK;
04485     else
04486         return ACLCHECK_NO_PRIV;
04487 }
04488 
04489 /*
04490  * Exported routine for checking a user's access privileges to a foreign
04491  * server
04492  */
04493 AclResult
04494 pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
04495 {
04496     if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
04497         return ACLCHECK_OK;
04498     else
04499         return ACLCHECK_NO_PRIV;
04500 }
04501 
04502 /*
04503  * Exported routine for checking a user's access privileges to a type
04504  */
04505 AclResult
04506 pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
04507 {
04508     if (pg_type_aclmask(type_oid, roleid, mode, ACLMASK_ANY) != 0)
04509         return ACLCHECK_OK;
04510     else
04511         return ACLCHECK_NO_PRIV;
04512 }
04513 
04514 /*
04515  * Ownership check for a relation (specified by OID).
04516  */
04517 bool
04518 pg_class_ownercheck(Oid class_oid, Oid roleid)
04519 {
04520     HeapTuple   tuple;
04521     Oid         ownerId;
04522 
04523     /* Superusers bypass all permission checking. */
04524     if (superuser_arg(roleid))
04525         return true;
04526 
04527     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
04528     if (!HeapTupleIsValid(tuple))
04529         ereport(ERROR,
04530                 (errcode(ERRCODE_UNDEFINED_TABLE),
04531                  errmsg("relation with OID %u does not exist", class_oid)));
04532 
04533     ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
04534 
04535     ReleaseSysCache(tuple);
04536 
04537     return has_privs_of_role(roleid, ownerId);
04538 }
04539 
04540 /*
04541  * Ownership check for a type (specified by OID).
04542  */
04543 bool
04544 pg_type_ownercheck(Oid type_oid, Oid roleid)
04545 {
04546     HeapTuple   tuple;
04547     Oid         ownerId;
04548 
04549     /* Superusers bypass all permission checking. */
04550     if (superuser_arg(roleid))
04551         return true;
04552 
04553     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
04554     if (!HeapTupleIsValid(tuple))
04555         ereport(ERROR,
04556                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04557                  errmsg("type with OID %u does not exist", type_oid)));
04558 
04559     ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
04560 
04561     ReleaseSysCache(tuple);
04562 
04563     return has_privs_of_role(roleid, ownerId);
04564 }
04565 
04566 /*
04567  * Ownership check for an operator (specified by OID).
04568  */
04569 bool
04570 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
04571 {
04572     HeapTuple   tuple;
04573     Oid         ownerId;
04574 
04575     /* Superusers bypass all permission checking. */
04576     if (superuser_arg(roleid))
04577         return true;
04578 
04579     tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
04580     if (!HeapTupleIsValid(tuple))
04581         ereport(ERROR,
04582                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
04583                  errmsg("operator with OID %u does not exist", oper_oid)));
04584 
04585     ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
04586 
04587     ReleaseSysCache(tuple);
04588 
04589     return has_privs_of_role(roleid, ownerId);
04590 }
04591 
04592 /*
04593  * Ownership check for a function (specified by OID).
04594  */
04595 bool
04596 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
04597 {
04598     HeapTuple   tuple;
04599     Oid         ownerId;
04600 
04601     /* Superusers bypass all permission checking. */
04602     if (superuser_arg(roleid))
04603         return true;
04604 
04605     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
04606     if (!HeapTupleIsValid(tuple))
04607         ereport(ERROR,
04608                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
04609                  errmsg("function with OID %u does not exist", proc_oid)));
04610 
04611     ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
04612 
04613     ReleaseSysCache(tuple);
04614 
04615     return has_privs_of_role(roleid, ownerId);
04616 }
04617 
04618 /*
04619  * Ownership check for a procedural language (specified by OID)
04620  */
04621 bool
04622 pg_language_ownercheck(Oid lan_oid, Oid roleid)
04623 {
04624     HeapTuple   tuple;
04625     Oid         ownerId;
04626 
04627     /* Superusers bypass all permission checking. */
04628     if (superuser_arg(roleid))
04629         return true;
04630 
04631     tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
04632     if (!HeapTupleIsValid(tuple))
04633         ereport(ERROR,
04634                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
04635                  errmsg("language with OID %u does not exist", lan_oid)));
04636 
04637     ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
04638 
04639     ReleaseSysCache(tuple);
04640 
04641     return has_privs_of_role(roleid, ownerId);
04642 }
04643 
04644 /*
04645  * Ownership check for a largeobject (specified by OID)
04646  *
04647  * This is only used for operations like ALTER LARGE OBJECT that are always
04648  * relative to SnapshotNow.
04649  */
04650 bool
04651 pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
04652 {
04653     Relation    pg_lo_meta;
04654     ScanKeyData entry[1];
04655     SysScanDesc scan;
04656     HeapTuple   tuple;
04657     Oid         ownerId;
04658 
04659     /* Superusers bypass all permission checking. */
04660     if (superuser_arg(roleid))
04661         return true;
04662 
04663     /* There's no syscache for pg_largeobject_metadata */
04664     pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
04665                            AccessShareLock);
04666 
04667     ScanKeyInit(&entry[0],
04668                 ObjectIdAttributeNumber,
04669                 BTEqualStrategyNumber, F_OIDEQ,
04670                 ObjectIdGetDatum(lobj_oid));
04671 
04672     scan = systable_beginscan(pg_lo_meta,
04673                               LargeObjectMetadataOidIndexId, true,
04674                               SnapshotNow, 1, entry);
04675 
04676     tuple = systable_getnext(scan);
04677     if (!HeapTupleIsValid(tuple))
04678         ereport(ERROR,
04679                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04680                  errmsg("large object %u does not exist", lobj_oid)));
04681 
04682     ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
04683 
04684     systable_endscan(scan);
04685     heap_close(pg_lo_meta, AccessShareLock);
04686 
04687     return has_privs_of_role(roleid, ownerId);
04688 }
04689 
04690 /*
04691  * Ownership check for a namespace (specified by OID).
04692  */
04693 bool
04694 pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
04695 {
04696     HeapTuple   tuple;
04697     Oid         ownerId;
04698 
04699     /* Superusers bypass all permission checking. */
04700     if (superuser_arg(roleid))
04701         return true;
04702 
04703     tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
04704     if (!HeapTupleIsValid(tuple))
04705         ereport(ERROR,
04706                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
04707                  errmsg("schema with OID %u does not exist", nsp_oid)));
04708 
04709     ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
04710 
04711     ReleaseSysCache(tuple);
04712 
04713     return has_privs_of_role(roleid, ownerId);
04714 }
04715 
04716 /*
04717  * Ownership check for a tablespace (specified by OID).
04718  */
04719 bool
04720 pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
04721 {
04722     HeapTuple   spctuple;
04723     Oid         spcowner;
04724 
04725     /* Superusers bypass all permission checking. */
04726     if (superuser_arg(roleid))
04727         return true;
04728 
04729     /* Search syscache for pg_tablespace */
04730     spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
04731     if (!HeapTupleIsValid(spctuple))
04732         ereport(ERROR,
04733                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04734                  errmsg("tablespace with OID %u does not exist", spc_oid)));
04735 
04736     spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
04737 
04738     ReleaseSysCache(spctuple);
04739 
04740     return has_privs_of_role(roleid, spcowner);
04741 }
04742 
04743 /*
04744  * Ownership check for an operator class (specified by OID).
04745  */
04746 bool
04747 pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
04748 {
04749     HeapTuple   tuple;
04750     Oid         ownerId;
04751 
04752     /* Superusers bypass all permission checking. */
04753     if (superuser_arg(roleid))
04754         return true;
04755 
04756     tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
04757     if (!HeapTupleIsValid(tuple))
04758         ereport(ERROR,
04759                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04760                  errmsg("operator class with OID %u does not exist",
04761                         opc_oid)));
04762 
04763     ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
04764 
04765     ReleaseSysCache(tuple);
04766 
04767     return has_privs_of_role(roleid, ownerId);
04768 }
04769 
04770 /*
04771  * Ownership check for an operator family (specified by OID).
04772  */
04773 bool
04774 pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
04775 {
04776     HeapTuple   tuple;
04777     Oid         ownerId;
04778 
04779     /* Superusers bypass all permission checking. */
04780     if (superuser_arg(roleid))
04781         return true;
04782 
04783     tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
04784     if (!HeapTupleIsValid(tuple))
04785         ereport(ERROR,
04786                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04787                  errmsg("operator family with OID %u does not exist",
04788                         opf_oid)));
04789 
04790     ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
04791 
04792     ReleaseSysCache(tuple);
04793 
04794     return has_privs_of_role(roleid, ownerId);
04795 }
04796 
04797 /*
04798  * Ownership check for a text search dictionary (specified by OID).
04799  */
04800 bool
04801 pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
04802 {
04803     HeapTuple   tuple;
04804     Oid         ownerId;
04805 
04806     /* Superusers bypass all permission checking. */
04807     if (superuser_arg(roleid))
04808         return true;
04809 
04810     tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
04811     if (!HeapTupleIsValid(tuple))
04812         ereport(ERROR,
04813                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04814                  errmsg("text search dictionary with OID %u does not exist",
04815                         dict_oid)));
04816 
04817     ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
04818 
04819     ReleaseSysCache(tuple);
04820 
04821     return has_privs_of_role(roleid, ownerId);
04822 }
04823 
04824 /*
04825  * Ownership check for a text search configuration (specified by OID).
04826  */
04827 bool
04828 pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
04829 {
04830     HeapTuple   tuple;
04831     Oid         ownerId;
04832 
04833     /* Superusers bypass all permission checking. */
04834     if (superuser_arg(roleid))
04835         return true;
04836 
04837     tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
04838     if (!HeapTupleIsValid(tuple))
04839         ereport(ERROR,
04840                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04841                errmsg("text search configuration with OID %u does not exist",
04842                       cfg_oid)));
04843 
04844     ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
04845 
04846     ReleaseSysCache(tuple);
04847 
04848     return has_privs_of_role(roleid, ownerId);
04849 }
04850 
04851 /*
04852  * Ownership check for a foreign-data wrapper (specified by OID).
04853  */
04854 bool
04855 pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
04856 {
04857     HeapTuple   tuple;
04858     Oid         ownerId;
04859 
04860     /* Superusers bypass all permission checking. */
04861     if (superuser_arg(roleid))
04862         return true;
04863 
04864     tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
04865     if (!HeapTupleIsValid(tuple))
04866         ereport(ERROR,
04867                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04868                  errmsg("foreign-data wrapper with OID %u does not exist",
04869                         srv_oid)));
04870 
04871     ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
04872 
04873     ReleaseSysCache(tuple);
04874 
04875     return has_privs_of_role(roleid, ownerId);
04876 }
04877 
04878 /*
04879  * Ownership check for a foreign server (specified by OID).
04880  */
04881 bool
04882 pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
04883 {
04884     HeapTuple   tuple;
04885     Oid         ownerId;
04886 
04887     /* Superusers bypass all permission checking. */
04888     if (superuser_arg(roleid))
04889         return true;
04890 
04891     tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
04892     if (!HeapTupleIsValid(tuple))
04893         ereport(ERROR,
04894                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04895                  errmsg("foreign server with OID %u does not exist",
04896                         srv_oid)));
04897 
04898     ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
04899 
04900     ReleaseSysCache(tuple);
04901 
04902     return has_privs_of_role(roleid, ownerId);
04903 }
04904 
04905 /*
04906  * Ownership check for an event trigger (specified by OID).
04907  */
04908 bool
04909 pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
04910 {
04911     HeapTuple   tuple;
04912     Oid         ownerId;
04913 
04914     /* Superusers bypass all permission checking. */
04915     if (superuser_arg(roleid))
04916         return true;
04917 
04918     tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
04919     if (!HeapTupleIsValid(tuple))
04920         ereport(ERROR,
04921                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04922                  errmsg("event trigger with OID %u does not exist",
04923                         et_oid)));
04924 
04925     ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
04926 
04927     ReleaseSysCache(tuple);
04928 
04929     return has_privs_of_role(roleid, ownerId);
04930 }
04931 
04932 /*
04933  * Ownership check for a database (specified by OID).
04934  */
04935 bool
04936 pg_database_ownercheck(Oid db_oid, Oid roleid)
04937 {
04938     HeapTuple   tuple;
04939     Oid         dba;
04940 
04941     /* Superusers bypass all permission checking. */
04942     if (superuser_arg(roleid))
04943         return true;
04944 
04945     tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
04946     if (!HeapTupleIsValid(tuple))
04947         ereport(ERROR,
04948                 (errcode(ERRCODE_UNDEFINED_DATABASE),
04949                  errmsg("database with OID %u does not exist", db_oid)));
04950 
04951     dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
04952 
04953     ReleaseSysCache(tuple);
04954 
04955     return has_privs_of_role(roleid, dba);
04956 }
04957 
04958 /*
04959  * Ownership check for a collation (specified by OID).
04960  */
04961 bool
04962 pg_collation_ownercheck(Oid coll_oid, Oid roleid)
04963 {
04964     HeapTuple   tuple;
04965     Oid         ownerId;
04966 
04967     /* Superusers bypass all permission checking. */
04968     if (superuser_arg(roleid))
04969         return true;
04970 
04971     tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
04972     if (!HeapTupleIsValid(tuple))
04973         ereport(ERROR,
04974                 (errcode(ERRCODE_UNDEFINED_OBJECT),
04975                  errmsg("collation with OID %u does not exist", coll_oid)));
04976 
04977     ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
04978 
04979     ReleaseSysCache(tuple);
04980 
04981     return has_privs_of_role(roleid, ownerId);
04982 }
04983 
04984 /*
04985  * Ownership check for a conversion (specified by OID).
04986  */
04987 bool
04988 pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
04989 {
04990     HeapTuple   tuple;
04991     Oid         ownerId;
04992 
04993     /* Superusers bypass all permission checking. */
04994     if (superuser_arg(roleid))
04995         return true;
04996 
04997     tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
04998     if (!HeapTupleIsValid(tuple))
04999         ereport(ERROR,
05000                 (errcode(ERRCODE_UNDEFINED_OBJECT),
05001                  errmsg("conversion with OID %u does not exist", conv_oid)));
05002 
05003     ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
05004 
05005     ReleaseSysCache(tuple);
05006 
05007     return has_privs_of_role(roleid, ownerId);
05008 }
05009 
05010 /*
05011  * Ownership check for an extension (specified by OID).
05012  */
05013 bool
05014 pg_extension_ownercheck(Oid ext_oid, Oid roleid)
05015 {
05016     Relation    pg_extension;
05017     ScanKeyData entry[1];
05018     SysScanDesc scan;
05019     HeapTuple   tuple;
05020     Oid         ownerId;
05021 
05022     /* Superusers bypass all permission checking. */
05023     if (superuser_arg(roleid))
05024         return true;
05025 
05026     /* There's no syscache for pg_extension, so do it the hard way */
05027     pg_extension = heap_open(ExtensionRelationId, AccessShareLock);
05028 
05029     ScanKeyInit(&entry[0],
05030                 ObjectIdAttributeNumber,
05031                 BTEqualStrategyNumber, F_OIDEQ,
05032                 ObjectIdGetDatum(ext_oid));
05033 
05034     scan = systable_beginscan(pg_extension,
05035                               ExtensionOidIndexId, true,
05036                               SnapshotNow, 1, entry);
05037 
05038     tuple = systable_getnext(scan);
05039     if (!HeapTupleIsValid(tuple))
05040         ereport(ERROR,
05041                 (errcode(ERRCODE_UNDEFINED_OBJECT),
05042                  errmsg("extension with OID %u does not exist", ext_oid)));
05043 
05044     ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
05045 
05046     systable_endscan(scan);
05047     heap_close(pg_extension, AccessShareLock);
05048 
05049     return has_privs_of_role(roleid, ownerId);
05050 }
05051 
05052 /*
05053  * Check whether specified role has CREATEROLE privilege (or is a superuser)
05054  *
05055  * Note: roles do not have owners per se; instead we use this test in
05056  * places where an ownership-like permissions test is needed for a role.
05057  * Be sure to apply it to the role trying to do the operation, not the
05058  * role being operated on!  Also note that this generally should not be
05059  * considered enough privilege if the target role is a superuser.
05060  * (We don't handle that consideration here because we want to give a
05061  * separate error message for such cases, so the caller has to deal with it.)
05062  */
05063 bool
05064 has_createrole_privilege(Oid roleid)
05065 {
05066     bool        result = false;
05067     HeapTuple   utup;
05068 
05069     /* Superusers bypass all permission checking. */
05070     if (superuser_arg(roleid))
05071         return true;
05072 
05073     utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
05074     if (HeapTupleIsValid(utup))
05075     {
05076         result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
05077         ReleaseSysCache(utup);
05078     }
05079     return result;
05080 }
05081 
05082 /*
05083  * Fetch pg_default_acl entry for given role, namespace and object type
05084  * (object type must be given in pg_default_acl's encoding).
05085  * Returns NULL if no such entry.
05086  */
05087 static Acl *
05088 get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
05089 {
05090     Acl        *result = NULL;
05091     HeapTuple   tuple;
05092 
05093     tuple = SearchSysCache3(DEFACLROLENSPOBJ,
05094                             ObjectIdGetDatum(roleId),
05095                             ObjectIdGetDatum(nsp_oid),
05096                             CharGetDatum(objtype));
05097 
05098     if (HeapTupleIsValid(tuple))
05099     {
05100         Datum       aclDatum;
05101         bool        isNull;
05102 
05103         aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
05104                                    Anum_pg_default_acl_defaclacl,
05105                                    &isNull);
05106         if (!isNull)
05107             result = DatumGetAclPCopy(aclDatum);
05108         ReleaseSysCache(tuple);
05109     }
05110 
05111     return result;
05112 }
05113 
05114 /*
05115  * Get default permissions for newly created object within given schema
05116  *
05117  * Returns NULL if built-in system defaults should be used
05118  */
05119 Acl *
05120 get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
05121 {
05122     Acl        *result;
05123     Acl        *glob_acl;
05124     Acl        *schema_acl;
05125     Acl        *def_acl;
05126     char        defaclobjtype;
05127 
05128     /*
05129      * Use NULL during bootstrap, since pg_default_acl probably isn't there
05130      * yet.
05131      */
05132     if (IsBootstrapProcessingMode())
05133         return NULL;
05134 
05135     /* Check if object type is supported in pg_default_acl */
05136     switch (objtype)
05137     {
05138         case ACL_OBJECT_RELATION:
05139             defaclobjtype = DEFACLOBJ_RELATION;
05140             break;
05141 
05142         case ACL_OBJECT_SEQUENCE:
05143             defaclobjtype = DEFACLOBJ_SEQUENCE;
05144             break;
05145 
05146         case ACL_OBJECT_FUNCTION:
05147             defaclobjtype = DEFACLOBJ_FUNCTION;
05148             break;
05149 
05150         case ACL_OBJECT_TYPE:
05151             defaclobjtype = DEFACLOBJ_TYPE;
05152             break;
05153 
05154         default:
05155             return NULL;
05156     }
05157 
05158     /* Look up the relevant pg_default_acl entries */
05159     glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
05160     schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
05161 
05162     /* Quick out if neither entry exists */
05163     if (glob_acl == NULL && schema_acl == NULL)
05164         return NULL;
05165 
05166     /* We need to know the hard-wired default value, too */
05167     def_acl = acldefault(objtype, ownerId);
05168 
05169     /* If there's no global entry, substitute the hard-wired default */
05170     if (glob_acl == NULL)
05171         glob_acl = def_acl;
05172 
05173     /* Merge in any per-schema privileges */
05174     result = aclmerge(glob_acl, schema_acl, ownerId);
05175 
05176     /*
05177      * For efficiency, we want to return NULL if the result equals default.
05178      * This requires sorting both arrays to get an accurate comparison.
05179      */
05180     aclitemsort(result);
05181     aclitemsort(def_acl);
05182     if (aclequal(result, def_acl))
05183         result = NULL;
05184 
05185     return result;
05186 }