]> granicus.if.org Git - postgresql/blob - src/backend/catalog/aclchk.c
5497869d8bdd66462287775da583717962d3dba1
[postgresql] / src / backend / catalog / aclchk.c
1 /*-------------------------------------------------------------------------
2  *
3  * aclchk.c
4  *        Routines to check access control permissions.
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.133 2006/11/16 14:41:49 petere Exp $
12  *
13  * NOTES
14  *        See acl.h.
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/xact.h"
23 #include "catalog/catalog.h"
24 #include "catalog/dependency.h"
25 #include "catalog/indexing.h"
26 #include "catalog/pg_authid.h"
27 #include "catalog/pg_conversion.h"
28 #include "catalog/pg_database.h"
29 #include "catalog/pg_language.h"
30 #include "catalog/pg_namespace.h"
31 #include "catalog/pg_opclass.h"
32 #include "catalog/pg_operator.h"
33 #include "catalog/pg_proc.h"
34 #include "catalog/pg_tablespace.h"
35 #include "catalog/pg_type.h"
36 #include "commands/dbcommands.h"
37 #include "miscadmin.h"
38 #include "parser/parse_func.h"
39 #include "utils/acl.h"
40 #include "utils/fmgroids.h"
41 #include "utils/lsyscache.h"
42 #include "utils/syscache.h"
43
44
45 static void ExecGrant_Relation(InternalGrant *grantStmt);
46 static void ExecGrant_Database(InternalGrant *grantStmt);
47 static void ExecGrant_Function(InternalGrant *grantStmt);
48 static void ExecGrant_Language(InternalGrant *grantStmt);
49 static void ExecGrant_Namespace(InternalGrant *grantStmt);
50 static void ExecGrant_Tablespace(InternalGrant *grantStmt);
51
52 static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
53 static AclMode string_to_privilege(const char *privname);
54 static const char *privilege_to_string(AclMode privilege);
55 static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
56                                                  bool all_privs, AclMode privileges,
57                                                  Oid objectId, Oid grantorId,
58                                                  AclObjectKind objkind, char *objname);
59 static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
60                    AclMode mask, AclMaskHow how);
61
62
63 #ifdef ACLDEBUG
64 static void
65 dumpacl(Acl *acl)
66 {
67         int                     i;
68         AclItem    *aip;
69
70         elog(DEBUG2, "acl size = %d, # acls = %d",
71                  ACL_SIZE(acl), ACL_NUM(acl));
72         aip = ACL_DAT(acl);
73         for (i = 0; i < ACL_NUM(acl); ++i)
74                 elog(DEBUG2, "  acl[%d]: %s", i,
75                          DatumGetCString(DirectFunctionCall1(aclitemout,
76                                                                                                  PointerGetDatum(aip + i))));
77 }
78 #endif   /* ACLDEBUG */
79
80
81 /*
82  * If is_grant is true, adds the given privileges for the list of
83  * grantees to the existing old_acl.  If is_grant is false, the
84  * privileges for the given grantees are removed from old_acl.
85  *
86  * NB: the original old_acl is pfree'd.
87  */
88 static Acl *
89 merge_acl_with_grant(Acl *old_acl, bool is_grant,
90                                          bool grant_option, DropBehavior behavior,
91                                          List *grantees, AclMode privileges,
92                                          Oid grantorId, Oid ownerId)
93 {
94         unsigned        modechg;
95         ListCell   *j;
96         Acl                *new_acl;
97
98         modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
99
100 #ifdef ACLDEBUG
101         dumpacl(old_acl);
102 #endif
103         new_acl = old_acl;
104
105         foreach(j, grantees)
106         {
107                 AclItem aclitem;
108                 Acl                *newer_acl;
109
110                 aclitem.        ai_grantee = lfirst_oid(j);
111
112                 /*
113                  * Grant options can only be granted to individual roles, not PUBLIC.
114                  * The reason is that if a user would re-grant a privilege that he
115                  * held through PUBLIC, and later the user is removed, the situation
116                  * is impossible to clean up.
117                  */
118                 if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
119                         ereport(ERROR,
120                                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
121                                          errmsg("grant options can only be granted to roles")));
122
123                 aclitem.        ai_grantor = grantorId;
124
125                 /*
126                  * The asymmetry in the conditions here comes from the spec.  In
127                  * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
128                  * to grant both the basic privilege and its grant option. But in
129                  * REVOKE, plain revoke revokes both the basic privilege and its grant
130                  * option, while REVOKE GRANT OPTION revokes only the option.
131                  */
132                 ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
133                                         (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
134                                    (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
135
136                 newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
137
138                 /* avoid memory leak when there are many grantees */
139                 pfree(new_acl);
140                 new_acl = newer_acl;
141
142 #ifdef ACLDEBUG
143                 dumpacl(new_acl);
144 #endif
145         }
146
147         return new_acl;
148 }
149
150 /*
151  * Restrict the privileges to what we can actually grant, and emit
152  * the standards-mandated warning and error messages.
153  */
154 static AclMode
155 restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
156                                                  AclMode privileges, Oid objectId, Oid grantorId,
157                                                  AclObjectKind objkind, char *objname)
158 {
159         AclMode         this_privileges;
160         AclMode         whole_mask;
161
162         switch (objkind)
163         {
164                 case ACL_KIND_CLASS:
165                         whole_mask = ACL_ALL_RIGHTS_RELATION;
166                         break;
167                 case ACL_KIND_SEQUENCE:
168                         whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
169                         break;
170                 case ACL_KIND_DATABASE:
171                         whole_mask = ACL_ALL_RIGHTS_DATABASE;
172                         break;
173                 case ACL_KIND_PROC:
174                         whole_mask = ACL_ALL_RIGHTS_FUNCTION;
175                         break;
176                 case ACL_KIND_LANGUAGE:
177                         whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
178                         break;
179                 case ACL_KIND_NAMESPACE:
180                         whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
181                         break;
182                 case ACL_KIND_TABLESPACE:
183                         whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
184                         break;
185                 default:
186                         elog(ERROR, "unrecognized object kind: %d", objkind);
187                         /* not reached, but keep compiler quiet */
188                         return ACL_NO_RIGHTS;
189         }
190
191         /*
192          * If we found no grant options, consider whether to issue a hard error.
193          * Per spec, having any privilege at all on the object will get you by
194          * here.
195          */
196         if (avail_goptions == ACL_NO_RIGHTS)
197         {
198                 if (pg_aclmask(objkind, objectId, grantorId,
199                                            whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
200                                            ACLMASK_ANY) == ACL_NO_RIGHTS)
201                         aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
202         }
203
204         /*
205          * Restrict the operation to what we can actually grant or revoke, and
206          * issue a warning if appropriate.      (For REVOKE this isn't quite what the
207          * spec says to do: the spec seems to want a warning only if no privilege
208          * bits actually change in the ACL. In practice that behavior seems much
209          * too noisy, as well as inconsistent with the GRANT case.)
210          */
211         this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
212         if (is_grant)
213         {
214                 if (this_privileges == 0)
215                         ereport(WARNING,
216                                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
217                                   errmsg("no privileges were granted for \"%s\"", objname)));
218                 else if (!all_privs && this_privileges != privileges)
219                         ereport(WARNING,
220                                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
221                          errmsg("not all privileges were granted for \"%s\"", objname)));
222         }
223         else
224         {
225                 if (this_privileges == 0)
226                         ereport(WARNING,
227                                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
228                           errmsg("no privileges could be revoked for \"%s\"", objname)));
229                 else if (!all_privs && this_privileges != privileges)
230                         ereport(WARNING,
231                                         (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
232                                          errmsg("not all privileges could be revoked for \"%s\"", objname)));
233         }
234
235         return this_privileges;
236 }
237
238 /*
239  * Called to execute the utility commands GRANT and REVOKE
240  */
241 void
242 ExecuteGrantStmt(GrantStmt *stmt)
243 {
244         InternalGrant istmt;
245         ListCell   *cell;
246         char       *errormsg;
247         AclMode         all_privileges;
248
249         /*
250          * Turn the regular GrantStmt into the InternalGrant form.
251          */
252         istmt.is_grant = stmt->is_grant;
253         istmt.objtype = stmt->objtype;
254         istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
255         /* all_privs to be filled below */
256         /* privileges to be filled below */
257         istmt.grantees = NIL;
258         /* filled below */
259         istmt.grant_option = stmt->grant_option;
260         istmt.behavior = stmt->behavior;
261
262
263         /*
264          * Convert the PrivGrantee list into an Oid list.  Note that at this point
265          * we insert an ACL_ID_PUBLIC into the list if an empty role name is
266          * detected (which is what the grammar uses if PUBLIC is found), so
267          * downstream there shouldn't be any additional work needed to support
268          * this case.
269          */
270         foreach(cell, stmt->grantees)
271         {
272                 PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
273
274                 if (grantee->rolname == NULL)
275                         istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
276                 else
277                         istmt.grantees =
278                                 lappend_oid(istmt.grantees,
279                                                         get_roleid_checked(grantee->rolname));
280         }
281
282         /*
283          * Convert stmt->privileges, a textual list, into an AclMode bitmask.
284          */
285         switch (stmt->objtype)
286         {
287                         /*
288                          * Because this might be a sequence, we test both relation and
289                          * sequence bits, and later do a more limited test when we know
290                          * the object type.
291                          */
292                 case ACL_OBJECT_RELATION:
293                         all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
294                         errormsg = _("invalid privilege type %s for relation");
295                         break;
296                 case ACL_OBJECT_SEQUENCE:
297                         all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
298                         errormsg = _("invalid privilege type %s for sequence");
299                         break;
300                 case ACL_OBJECT_DATABASE:
301                         all_privileges = ACL_ALL_RIGHTS_DATABASE;
302                         errormsg = _("invalid privilege type %s for database");
303                         break;
304                 case ACL_OBJECT_FUNCTION:
305                         all_privileges = ACL_ALL_RIGHTS_FUNCTION;
306                         errormsg = _("invalid privilege type %s for function");
307                         break;
308                 case ACL_OBJECT_LANGUAGE:
309                         all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
310                         errormsg = _("invalid privilege type %s for language");
311                         break;
312                 case ACL_OBJECT_NAMESPACE:
313                         all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
314                         errormsg = _("invalid privilege type %s for schema");
315                         break;
316                 case ACL_OBJECT_TABLESPACE:
317                         all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
318                         errormsg = _("invalid privilege type %s for tablespace");
319                         break;
320                 default:
321                         /* keep compiler quiet */
322                         all_privileges = ACL_NO_RIGHTS;
323                         errormsg = NULL;
324                         elog(ERROR, "unrecognized GrantStmt.objtype: %d",
325                                  (int) stmt->objtype);
326         }
327
328         if (stmt->privileges == NIL)
329         {
330                 istmt.all_privs = true;
331
332                 /*
333                  * will be turned into ACL_ALL_RIGHTS_* by the internal routines
334                  * depending on the object type
335                  */
336                 istmt.privileges = ACL_NO_RIGHTS;
337         }
338         else
339         {
340                 istmt.all_privs = false;
341                 istmt.privileges = ACL_NO_RIGHTS;
342
343                 foreach(cell, stmt->privileges)
344                 {
345                         char       *privname = strVal(lfirst(cell));
346                         AclMode         priv = string_to_privilege(privname);
347
348                         if (priv & ~((AclMode) all_privileges))
349                                 ereport(ERROR,
350                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
351                                                  errmsg(errormsg,
352                                                                 privilege_to_string(priv))));
353
354                         istmt.privileges |= priv;
355                 }
356         }
357
358         ExecGrantStmt_oids(&istmt);
359 }
360
361 /*
362  * ExecGrantStmt_oids
363  *
364  * "Internal" entrypoint for granting and revoking privileges.
365  */
366 void
367 ExecGrantStmt_oids(InternalGrant *istmt)
368 {
369         switch (istmt->objtype)
370         {
371                 case ACL_OBJECT_RELATION:
372                 case ACL_OBJECT_SEQUENCE:
373                         ExecGrant_Relation(istmt);
374                         break;
375                 case ACL_OBJECT_DATABASE:
376                         ExecGrant_Database(istmt);
377                         break;
378                 case ACL_OBJECT_FUNCTION:
379                         ExecGrant_Function(istmt);
380                         break;
381                 case ACL_OBJECT_LANGUAGE:
382                         ExecGrant_Language(istmt);
383                         break;
384                 case ACL_OBJECT_NAMESPACE:
385                         ExecGrant_Namespace(istmt);
386                         break;
387                 case ACL_OBJECT_TABLESPACE:
388                         ExecGrant_Tablespace(istmt);
389                         break;
390                 default:
391                         elog(ERROR, "unrecognized GrantStmt.objtype: %d",
392                                  (int) istmt->objtype);
393         }
394 }
395
396 /*
397  * objectNamesToOids
398  *
399  * Turn a list of object names of a given type into an Oid list.
400  */
401 static List *
402 objectNamesToOids(GrantObjectType objtype, List *objnames)
403 {
404         List       *objects = NIL;
405         ListCell   *cell;
406
407         Assert(objnames != NIL);
408
409         switch (objtype)
410         {
411                 case ACL_OBJECT_RELATION:
412                 case ACL_OBJECT_SEQUENCE:
413                         foreach(cell, objnames)
414                         {
415                                 RangeVar   *relvar = (RangeVar *) lfirst(cell);
416                                 Oid                     relOid;
417
418                                 relOid = RangeVarGetRelid(relvar, false);
419                                 objects = lappend_oid(objects, relOid);
420                         }
421                         break;
422                 case ACL_OBJECT_DATABASE:
423                         foreach(cell, objnames)
424                         {
425                                 char       *dbname = strVal(lfirst(cell));
426                                 Oid                     dbid;
427
428                                 dbid = get_database_oid(dbname);
429                                 if (!OidIsValid(dbid))
430                                         ereport(ERROR,
431                                                         (errcode(ERRCODE_UNDEFINED_DATABASE),
432                                                          errmsg("database \"%s\" does not exist",
433                                                                         dbname)));
434                                 objects = lappend_oid(objects, dbid);
435                         }
436                         break;
437                 case ACL_OBJECT_FUNCTION:
438                         foreach(cell, objnames)
439                         {
440                                 FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
441                                 Oid                     funcid;
442
443                                 funcid = LookupFuncNameTypeNames(func->funcname,
444                                                                                                  func->funcargs, false);
445                                 objects = lappend_oid(objects, funcid);
446                         }
447                         break;
448                 case ACL_OBJECT_LANGUAGE:
449                         foreach(cell, objnames)
450                         {
451                                 char       *langname = strVal(lfirst(cell));
452                                 HeapTuple       tuple;
453
454                                 tuple = SearchSysCache(LANGNAME,
455                                                                            PointerGetDatum(langname),
456                                                                            0, 0, 0);
457                                 if (!HeapTupleIsValid(tuple))
458                                         ereport(ERROR,
459                                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
460                                                          errmsg("language \"%s\" does not exist",
461                                                                         langname)));
462
463                                 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
464
465                                 ReleaseSysCache(tuple);
466                         }
467                         break;
468                 case ACL_OBJECT_NAMESPACE:
469                         foreach(cell, objnames)
470                         {
471                                 char       *nspname = strVal(lfirst(cell));
472                                 HeapTuple       tuple;
473
474                                 tuple = SearchSysCache(NAMESPACENAME,
475                                                                            CStringGetDatum(nspname),
476                                                                            0, 0, 0);
477                                 if (!HeapTupleIsValid(tuple))
478                                         ereport(ERROR,
479                                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
480                                                          errmsg("schema \"%s\" does not exist",
481                                                                         nspname)));
482
483                                 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
484
485                                 ReleaseSysCache(tuple);
486                         }
487                         break;
488                 case ACL_OBJECT_TABLESPACE:
489                         foreach(cell, objnames)
490                         {
491                                 char       *spcname = strVal(lfirst(cell));
492                                 ScanKeyData entry[1];
493                                 HeapScanDesc scan;
494                                 HeapTuple       tuple;
495                                 Relation        relation;
496
497                                 relation = heap_open(TableSpaceRelationId, AccessShareLock);
498
499                                 ScanKeyInit(&entry[0],
500                                                         Anum_pg_tablespace_spcname,
501                                                         BTEqualStrategyNumber, F_NAMEEQ,
502                                                         CStringGetDatum(spcname));
503
504                                 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
505                                 tuple = heap_getnext(scan, ForwardScanDirection);
506                                 if (!HeapTupleIsValid(tuple))
507                                         ereport(ERROR,
508                                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
509                                            errmsg("tablespace \"%s\" does not exist", spcname)));
510
511                                 objects = lappend_oid(objects, HeapTupleGetOid(tuple));
512
513                                 heap_endscan(scan);
514
515                                 heap_close(relation, AccessShareLock);
516                         }
517                         break;
518                 default:
519                         elog(ERROR, "unrecognized GrantStmt.objtype: %d",
520                                  (int) objtype);
521         }
522
523         return objects;
524 }
525
526 /*
527  *      This processes both sequences and non-sequences.
528  */
529 static void
530 ExecGrant_Relation(InternalGrant *istmt)
531 {
532         Relation        relation;
533         ListCell   *cell;
534
535         relation = heap_open(RelationRelationId, RowExclusiveLock);
536
537         foreach(cell, istmt->objects)
538         {
539                 Oid                     relOid = lfirst_oid(cell);
540                 Datum           aclDatum;
541                 Form_pg_class pg_class_tuple;
542                 bool            isNull;
543                 AclMode         avail_goptions;
544                 AclMode         this_privileges;
545                 Acl                *old_acl;
546                 Acl                *new_acl;
547                 Oid                     grantorId;
548                 Oid                     ownerId;
549                 HeapTuple       tuple;
550                 HeapTuple       newtuple;
551                 Datum           values[Natts_pg_class];
552                 char            nulls[Natts_pg_class];
553                 char            replaces[Natts_pg_class];
554                 int                     noldmembers;
555                 int                     nnewmembers;
556                 Oid                *oldmembers;
557                 Oid                *newmembers;
558
559                 tuple = SearchSysCache(RELOID,
560                                                            ObjectIdGetDatum(relOid),
561                                                            0, 0, 0);
562                 if (!HeapTupleIsValid(tuple))
563                         elog(ERROR, "cache lookup failed for relation %u", relOid);
564                 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
565
566                 /* Not sensible to grant on an index */
567                 if (pg_class_tuple->relkind == RELKIND_INDEX)
568                         ereport(ERROR,
569                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
570                                          errmsg("\"%s\" is an index",
571                                                         NameStr(pg_class_tuple->relname))));
572
573                 /* Composite types aren't tables either */
574                 if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
575                         ereport(ERROR,
576                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
577                                          errmsg("\"%s\" is a composite type",
578                                                         NameStr(pg_class_tuple->relname))));
579
580                 /* Used GRANT SEQUENCE on a non-sequence? */
581                 if (istmt->objtype == ACL_OBJECT_SEQUENCE &&
582                         pg_class_tuple->relkind != RELKIND_SEQUENCE)
583                         ereport(ERROR,
584                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
585                                          errmsg("\"%s\" is not a sequence",
586                                                         NameStr(pg_class_tuple->relname))));
587
588                 /* Adjust the default permissions based on whether it is a sequence */
589                 if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
590                 {
591                         if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
592                                 this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
593                         else
594                                 this_privileges = ACL_ALL_RIGHTS_RELATION;
595                 }
596                 else
597                         this_privileges = istmt->privileges;
598
599                 /*
600                  * The GRANT TABLE syntax can be used for sequences and non-sequences,
601                  * so we have to look at the relkind to determine the supported
602                  * permissions.  The OR of table and sequence permissions were already
603                  * checked.
604                  */
605                 if (istmt->objtype == ACL_OBJECT_RELATION)
606                 {
607                         if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
608                         {
609                                 /*
610                                  * For backward compatibility, throw just a warning for
611                                  * invalid sequence permissions when using the non-sequence
612                                  * GRANT syntax is used.
613                                  */
614                                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
615                                 {
616                                         /*
617                                          * Mention the object name because the user needs to know
618                                          * which operations succeeded.  This is required because
619                                          * WARNING allows the command to continue.
620                                          */
621                                         ereport(WARNING,
622                                                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
623                                                          errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE",
624                                                                         NameStr(pg_class_tuple->relname))));
625                                         this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
626                                 }
627                         }
628                         else
629                         {
630                                 if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
631
632                                         /*
633                                          * USAGE is the only permission supported by sequences but
634                                          * not by non-sequences.  Don't mention the object name
635                                          * because we didn't in the combined TABLE | SEQUENCE
636                                          * check.
637                                          */
638                                         ereport(ERROR,
639                                                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
640                                                   errmsg("invalid privilege type USAGE for table")));
641                         }
642                 }
643
644                 /*
645                  * Get owner ID and working copy of existing ACL. If there's no ACL,
646                  * substitute the proper default.
647                  */
648                 ownerId = pg_class_tuple->relowner;
649                 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
650                                                                    &isNull);
651                 if (isNull)
652                         old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ?
653                                                                  ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
654                                                                  ownerId);
655                 else
656                         old_acl = DatumGetAclPCopy(aclDatum);
657
658                 /* Determine ID to do the grant as, and available grant options */
659                 select_best_grantor(GetUserId(), this_privileges,
660                                                         old_acl, ownerId,
661                                                         &grantorId, &avail_goptions);
662
663                 /*
664                  * Restrict the privileges to what we can actually grant, and emit the
665                  * standards-mandated warning and error messages.
666                  */
667                 this_privileges =
668                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
669                                                                          istmt->all_privs, this_privileges,
670                                                                          relOid, grantorId,
671                                                                   pg_class_tuple->relkind == RELKIND_SEQUENCE
672                                                                          ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS,
673                                                                          NameStr(pg_class_tuple->relname));
674
675                 /*
676                  * Generate new ACL.
677                  *
678                  * We need the members of both old and new ACLs so we can correct the
679                  * shared dependency information.
680                  */
681                 noldmembers = aclmembers(old_acl, &oldmembers);
682
683                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
684                                                                            istmt->grant_option, istmt->behavior,
685                                                                            istmt->grantees, this_privileges,
686                                                                            grantorId, ownerId);
687
688                 nnewmembers = aclmembers(new_acl, &newmembers);
689
690                 /* finished building new ACL value, now insert it */
691                 MemSet(values, 0, sizeof(values));
692                 MemSet(nulls, ' ', sizeof(nulls));
693                 MemSet(replaces, ' ', sizeof(replaces));
694
695                 replaces[Anum_pg_class_relacl - 1] = 'r';
696                 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
697
698                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
699
700                 simple_heap_update(relation, &newtuple->t_self, newtuple);
701
702                 /* keep the catalog indexes up to date */
703                 CatalogUpdateIndexes(relation, newtuple);
704
705                 /* Update the shared dependency ACL info */
706                 updateAclDependencies(RelationRelationId, relOid,
707                                                           ownerId, istmt->is_grant,
708                                                           noldmembers, oldmembers,
709                                                           nnewmembers, newmembers);
710
711                 ReleaseSysCache(tuple);
712
713                 pfree(new_acl);
714
715                 /* prevent error when processing duplicate objects */
716                 CommandCounterIncrement();
717         }
718
719         heap_close(relation, RowExclusiveLock);
720 }
721
722 static void
723 ExecGrant_Database(InternalGrant *istmt)
724 {
725         Relation        relation;
726         ListCell   *cell;
727
728         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
729                 istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
730
731         relation = heap_open(DatabaseRelationId, RowExclusiveLock);
732
733         foreach(cell, istmt->objects)
734         {
735                 Oid                     datId = lfirst_oid(cell);
736                 Form_pg_database pg_database_tuple;
737                 Datum           aclDatum;
738                 bool            isNull;
739                 AclMode         avail_goptions;
740                 AclMode         this_privileges;
741                 Acl                *old_acl;
742                 Acl                *new_acl;
743                 Oid                     grantorId;
744                 Oid                     ownerId;
745                 HeapTuple       newtuple;
746                 Datum           values[Natts_pg_database];
747                 char            nulls[Natts_pg_database];
748                 char            replaces[Natts_pg_database];
749                 int                     noldmembers;
750                 int                     nnewmembers;
751                 Oid                *oldmembers;
752                 Oid                *newmembers;
753                 HeapTuple       tuple;
754
755                 tuple = SearchSysCache(DATABASEOID,
756                                                            ObjectIdGetDatum(datId),
757                                                            0, 0, 0);
758                 if (!HeapTupleIsValid(tuple))
759                         elog(ERROR, "cache lookup failed for database %u", datId);
760
761                 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
762
763                 /*
764                  * Get owner ID and working copy of existing ACL. If there's no ACL,
765                  * substitute the proper default.
766                  */
767                 ownerId = pg_database_tuple->datdba;
768                 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
769                                                                 RelationGetDescr(relation), &isNull);
770                 if (isNull)
771                         old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
772                 else
773                         old_acl = DatumGetAclPCopy(aclDatum);
774
775                 /* Determine ID to do the grant as, and available grant options */
776                 select_best_grantor(GetUserId(), istmt->privileges,
777                                                         old_acl, ownerId,
778                                                         &grantorId, &avail_goptions);
779
780                 /*
781                  * Restrict the privileges to what we can actually grant, and emit the
782                  * standards-mandated warning and error messages.
783                  */
784                 this_privileges =
785                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
786                                                                          istmt->all_privs, istmt->privileges,
787                                                                          datId, grantorId, ACL_KIND_DATABASE,
788                                                                          NameStr(pg_database_tuple->datname));
789
790                 /*
791                  * Generate new ACL.
792                  *
793                  * We need the members of both old and new ACLs so we can correct the
794                  * shared dependency information.
795                  */
796                 noldmembers = aclmembers(old_acl, &oldmembers);
797
798                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
799                                                                            istmt->grant_option, istmt->behavior,
800                                                                            istmt->grantees, this_privileges,
801                                                                            grantorId, ownerId);
802
803                 nnewmembers = aclmembers(new_acl, &newmembers);
804
805                 /* finished building new ACL value, now insert it */
806                 MemSet(values, 0, sizeof(values));
807                 MemSet(nulls, ' ', sizeof(nulls));
808                 MemSet(replaces, ' ', sizeof(replaces));
809
810                 replaces[Anum_pg_database_datacl - 1] = 'r';
811                 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
812
813                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
814                                                                         nulls, replaces);
815
816                 simple_heap_update(relation, &newtuple->t_self, newtuple);
817
818                 /* keep the catalog indexes up to date */
819                 CatalogUpdateIndexes(relation, newtuple);
820
821                 /* Update the shared dependency ACL info */
822                 updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
823                                                           ownerId, istmt->is_grant,
824                                                           noldmembers, oldmembers,
825                                                           nnewmembers, newmembers);
826
827                 ReleaseSysCache(tuple);
828
829                 pfree(new_acl);
830
831                 /* prevent error when processing duplicate objects */
832                 CommandCounterIncrement();
833         }
834
835         heap_close(relation, RowExclusiveLock);
836 }
837
838 static void
839 ExecGrant_Function(InternalGrant *istmt)
840 {
841         Relation        relation;
842         ListCell   *cell;
843
844         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
845                 istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
846
847         relation = heap_open(ProcedureRelationId, RowExclusiveLock);
848
849         foreach(cell, istmt->objects)
850         {
851                 Oid                     funcId = lfirst_oid(cell);
852                 Form_pg_proc pg_proc_tuple;
853                 Datum           aclDatum;
854                 bool            isNull;
855                 AclMode         avail_goptions;
856                 AclMode         this_privileges;
857                 Acl                *old_acl;
858                 Acl                *new_acl;
859                 Oid                     grantorId;
860                 Oid                     ownerId;
861                 HeapTuple       tuple;
862                 HeapTuple       newtuple;
863                 Datum           values[Natts_pg_proc];
864                 char            nulls[Natts_pg_proc];
865                 char            replaces[Natts_pg_proc];
866                 int                     noldmembers;
867                 int                     nnewmembers;
868                 Oid                *oldmembers;
869                 Oid                *newmembers;
870
871                 tuple = SearchSysCache(PROCOID,
872                                                            ObjectIdGetDatum(funcId),
873                                                            0, 0, 0);
874                 if (!HeapTupleIsValid(tuple))
875                         elog(ERROR, "cache lookup failed for function %u", funcId);
876
877                 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
878
879                 /*
880                  * Get owner ID and working copy of existing ACL. If there's no ACL,
881                  * substitute the proper default.
882                  */
883                 ownerId = pg_proc_tuple->proowner;
884                 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
885                                                                    &isNull);
886                 if (isNull)
887                         old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
888                 else
889                         old_acl = DatumGetAclPCopy(aclDatum);
890
891                 /* Determine ID to do the grant as, and available grant options */
892                 select_best_grantor(GetUserId(), istmt->privileges,
893                                                         old_acl, ownerId,
894                                                         &grantorId, &avail_goptions);
895
896                 /*
897                  * Restrict the privileges to what we can actually grant, and emit the
898                  * standards-mandated warning and error messages.
899                  */
900                 this_privileges =
901                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
902                                                                          istmt->all_privs, istmt->privileges,
903                                                                          funcId, grantorId, ACL_KIND_PROC,
904                                                                          NameStr(pg_proc_tuple->proname));
905
906                 /*
907                  * Generate new ACL.
908                  *
909                  * We need the members of both old and new ACLs so we can correct the
910                  * shared dependency information.
911                  */
912                 noldmembers = aclmembers(old_acl, &oldmembers);
913
914                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
915                                                                            istmt->grant_option, istmt->behavior,
916                                                                            istmt->grantees, this_privileges,
917                                                                            grantorId, ownerId);
918
919                 nnewmembers = aclmembers(new_acl, &newmembers);
920
921                 /* finished building new ACL value, now insert it */
922                 MemSet(values, 0, sizeof(values));
923                 MemSet(nulls, ' ', sizeof(nulls));
924                 MemSet(replaces, ' ', sizeof(replaces));
925
926                 replaces[Anum_pg_proc_proacl - 1] = 'r';
927                 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
928
929                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
930                                                                         nulls, replaces);
931
932                 simple_heap_update(relation, &newtuple->t_self, newtuple);
933
934                 /* keep the catalog indexes up to date */
935                 CatalogUpdateIndexes(relation, newtuple);
936
937                 /* Update the shared dependency ACL info */
938                 updateAclDependencies(ProcedureRelationId, funcId,
939                                                           ownerId, istmt->is_grant,
940                                                           noldmembers, oldmembers,
941                                                           nnewmembers, newmembers);
942
943                 ReleaseSysCache(tuple);
944
945                 pfree(new_acl);
946
947                 /* prevent error when processing duplicate objects */
948                 CommandCounterIncrement();
949         }
950
951         heap_close(relation, RowExclusiveLock);
952 }
953
954 static void
955 ExecGrant_Language(InternalGrant *istmt)
956 {
957         Relation        relation;
958         ListCell   *cell;
959
960         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
961                 istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
962
963         relation = heap_open(LanguageRelationId, RowExclusiveLock);
964
965         foreach(cell, istmt->objects)
966         {
967                 Oid                     langId = lfirst_oid(cell);
968                 Form_pg_language pg_language_tuple;
969                 Datum           aclDatum;
970                 bool            isNull;
971                 AclMode         avail_goptions;
972                 AclMode         this_privileges;
973                 Acl                *old_acl;
974                 Acl                *new_acl;
975                 Oid                     grantorId;
976                 Oid                     ownerId;
977                 HeapTuple       tuple;
978                 HeapTuple       newtuple;
979                 Datum           values[Natts_pg_language];
980                 char            nulls[Natts_pg_language];
981                 char            replaces[Natts_pg_language];
982                 int                     noldmembers;
983                 int                     nnewmembers;
984                 Oid                *oldmembers;
985                 Oid                *newmembers;
986
987                 tuple = SearchSysCache(LANGOID,
988                                                            ObjectIdGetDatum(langId),
989                                                            0, 0, 0);
990                 if (!HeapTupleIsValid(tuple))
991                         elog(ERROR, "cache lookup failed for language %u", langId);
992
993                 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
994
995                 if (!pg_language_tuple->lanpltrusted)
996                         ereport(ERROR,
997                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
998                                          errmsg("language \"%s\" is not trusted",
999                                                         NameStr(pg_language_tuple->lanname)),
1000                                    errhint("Only superusers may use untrusted languages.")));
1001
1002                 /*
1003                  * Get owner ID and working copy of existing ACL. If there's no ACL,
1004                  * substitute the proper default.
1005                  *
1006                  * Note: for now, languages are treated as owned by the bootstrap
1007                  * user. We should add an owner column to pg_language instead.
1008                  */
1009                 ownerId = BOOTSTRAP_SUPERUSERID;
1010                 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
1011                                                                    &isNull);
1012                 if (isNull)
1013                         old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
1014                 else
1015                         old_acl = DatumGetAclPCopy(aclDatum);
1016
1017                 /* Determine ID to do the grant as, and available grant options */
1018                 select_best_grantor(GetUserId(), istmt->privileges,
1019                                                         old_acl, ownerId,
1020                                                         &grantorId, &avail_goptions);
1021
1022                 /*
1023                  * Restrict the privileges to what we can actually grant, and emit the
1024                  * standards-mandated warning and error messages.
1025                  */
1026                 this_privileges =
1027                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
1028                                                                          istmt->all_privs, istmt->privileges,
1029                                                                          langId, grantorId, ACL_KIND_LANGUAGE,
1030                                                                          NameStr(pg_language_tuple->lanname));
1031
1032                 /*
1033                  * Generate new ACL.
1034                  *
1035                  * We need the members of both old and new ACLs so we can correct the
1036                  * shared dependency information.
1037                  */
1038                 noldmembers = aclmembers(old_acl, &oldmembers);
1039
1040                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1041                                                                            istmt->grant_option, istmt->behavior,
1042                                                                            istmt->grantees, this_privileges,
1043                                                                            grantorId, ownerId);
1044
1045                 nnewmembers = aclmembers(new_acl, &newmembers);
1046
1047                 /* finished building new ACL value, now insert it */
1048                 MemSet(values, 0, sizeof(values));
1049                 MemSet(nulls, ' ', sizeof(nulls));
1050                 MemSet(replaces, ' ', sizeof(replaces));
1051
1052                 replaces[Anum_pg_language_lanacl - 1] = 'r';
1053                 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
1054
1055                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1056                                                                         nulls, replaces);
1057
1058                 simple_heap_update(relation, &newtuple->t_self, newtuple);
1059
1060                 /* keep the catalog indexes up to date */
1061                 CatalogUpdateIndexes(relation, newtuple);
1062
1063                 /* Update the shared dependency ACL info */
1064                 updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
1065                                                           ownerId, istmt->is_grant,
1066                                                           noldmembers, oldmembers,
1067                                                           nnewmembers, newmembers);
1068
1069                 ReleaseSysCache(tuple);
1070
1071                 pfree(new_acl);
1072
1073                 /* prevent error when processing duplicate objects */
1074                 CommandCounterIncrement();
1075         }
1076
1077         heap_close(relation, RowExclusiveLock);
1078 }
1079
1080 static void
1081 ExecGrant_Namespace(InternalGrant *istmt)
1082 {
1083         Relation        relation;
1084         ListCell   *cell;
1085
1086         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1087                 istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
1088
1089         relation = heap_open(NamespaceRelationId, RowExclusiveLock);
1090
1091         foreach(cell, istmt->objects)
1092         {
1093                 Oid                     nspid = lfirst_oid(cell);
1094                 Form_pg_namespace pg_namespace_tuple;
1095                 Datum           aclDatum;
1096                 bool            isNull;
1097                 AclMode         avail_goptions;
1098                 AclMode         this_privileges;
1099                 Acl                *old_acl;
1100                 Acl                *new_acl;
1101                 Oid                     grantorId;
1102                 Oid                     ownerId;
1103                 HeapTuple       tuple;
1104                 HeapTuple       newtuple;
1105                 Datum           values[Natts_pg_namespace];
1106                 char            nulls[Natts_pg_namespace];
1107                 char            replaces[Natts_pg_namespace];
1108                 int                     noldmembers;
1109                 int                     nnewmembers;
1110                 Oid                *oldmembers;
1111                 Oid                *newmembers;
1112
1113                 tuple = SearchSysCache(NAMESPACEOID,
1114                                                            ObjectIdGetDatum(nspid),
1115                                                            0, 0, 0);
1116                 if (!HeapTupleIsValid(tuple))
1117                         elog(ERROR, "cache lookup failed for namespace %u", nspid);
1118
1119                 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
1120
1121                 /*
1122                  * Get owner ID and working copy of existing ACL. If there's no ACL,
1123                  * substitute the proper default.
1124                  */
1125                 ownerId = pg_namespace_tuple->nspowner;
1126                 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
1127                                                                    Anum_pg_namespace_nspacl,
1128                                                                    &isNull);
1129                 if (isNull)
1130                         old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1131                 else
1132                         old_acl = DatumGetAclPCopy(aclDatum);
1133
1134                 /* Determine ID to do the grant as, and available grant options */
1135                 select_best_grantor(GetUserId(), istmt->privileges,
1136                                                         old_acl, ownerId,
1137                                                         &grantorId, &avail_goptions);
1138
1139                 /*
1140                  * Restrict the privileges to what we can actually grant, and emit the
1141                  * standards-mandated warning and error messages.
1142                  */
1143                 this_privileges =
1144                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
1145                                                                          istmt->all_privs, istmt->privileges,
1146                                                                          nspid, grantorId, ACL_KIND_NAMESPACE,
1147                                                                          NameStr(pg_namespace_tuple->nspname));
1148
1149                 /*
1150                  * Generate new ACL.
1151                  *
1152                  * We need the members of both old and new ACLs so we can correct the
1153                  * shared dependency information.
1154                  */
1155                 noldmembers = aclmembers(old_acl, &oldmembers);
1156
1157                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1158                                                                            istmt->grant_option, istmt->behavior,
1159                                                                            istmt->grantees, this_privileges,
1160                                                                            grantorId, ownerId);
1161
1162                 nnewmembers = aclmembers(new_acl, &newmembers);
1163
1164                 /* finished building new ACL value, now insert it */
1165                 MemSet(values, 0, sizeof(values));
1166                 MemSet(nulls, ' ', sizeof(nulls));
1167                 MemSet(replaces, ' ', sizeof(replaces));
1168
1169                 replaces[Anum_pg_namespace_nspacl - 1] = 'r';
1170                 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
1171
1172                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1173                                                                         nulls, replaces);
1174
1175                 simple_heap_update(relation, &newtuple->t_self, newtuple);
1176
1177                 /* keep the catalog indexes up to date */
1178                 CatalogUpdateIndexes(relation, newtuple);
1179
1180                 /* Update the shared dependency ACL info */
1181                 updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
1182                                                           ownerId, istmt->is_grant,
1183                                                           noldmembers, oldmembers,
1184                                                           nnewmembers, newmembers);
1185
1186                 ReleaseSysCache(tuple);
1187
1188                 pfree(new_acl);
1189
1190                 /* prevent error when processing duplicate objects */
1191                 CommandCounterIncrement();
1192         }
1193
1194         heap_close(relation, RowExclusiveLock);
1195 }
1196
1197 static void
1198 ExecGrant_Tablespace(InternalGrant *istmt)
1199 {
1200         Relation        relation;
1201         ListCell   *cell;
1202
1203         if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
1204                 istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
1205
1206         relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
1207
1208         foreach(cell, istmt->objects)
1209         {
1210                 Oid                     tblId = lfirst_oid(cell);
1211                 Form_pg_tablespace pg_tablespace_tuple;
1212                 Datum           aclDatum;
1213                 bool            isNull;
1214                 AclMode         avail_goptions;
1215                 AclMode         this_privileges;
1216                 Acl                *old_acl;
1217                 Acl                *new_acl;
1218                 Oid                     grantorId;
1219                 Oid                     ownerId;
1220                 HeapTuple       newtuple;
1221                 Datum           values[Natts_pg_tablespace];
1222                 char            nulls[Natts_pg_tablespace];
1223                 char            replaces[Natts_pg_tablespace];
1224                 int                     noldmembers;
1225                 int                     nnewmembers;
1226                 Oid                *oldmembers;
1227                 Oid                *newmembers;
1228                 ScanKeyData entry[1];
1229                 SysScanDesc scan;
1230                 HeapTuple       tuple;
1231
1232                 /* There's no syscache for pg_tablespace, so must look the hard way */
1233                 ScanKeyInit(&entry[0],
1234                                         ObjectIdAttributeNumber,
1235                                         BTEqualStrategyNumber, F_OIDEQ,
1236                                         ObjectIdGetDatum(tblId));
1237                 scan = systable_beginscan(relation, TablespaceOidIndexId, true,
1238                                                                   SnapshotNow, 1, entry);
1239                 tuple = systable_getnext(scan);
1240                 if (!HeapTupleIsValid(tuple))
1241                         elog(ERROR, "cache lookup failed for tablespace %u", tblId);
1242
1243                 pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
1244
1245                 /*
1246                  * Get owner ID and working copy of existing ACL. If there's no ACL,
1247                  * substitute the proper default.
1248                  */
1249                 ownerId = pg_tablespace_tuple->spcowner;
1250                 aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1251                                                                 RelationGetDescr(relation), &isNull);
1252                 if (isNull)
1253                         old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1254                 else
1255                         old_acl = DatumGetAclPCopy(aclDatum);
1256
1257                 /* Determine ID to do the grant as, and available grant options */
1258                 select_best_grantor(GetUserId(), istmt->privileges,
1259                                                         old_acl, ownerId,
1260                                                         &grantorId, &avail_goptions);
1261
1262                 /*
1263                  * Restrict the privileges to what we can actually grant, and emit the
1264                  * standards-mandated warning and error messages.
1265                  */
1266                 this_privileges =
1267                         restrict_and_check_grant(istmt->is_grant, avail_goptions,
1268                                                                          istmt->all_privs, istmt->privileges,
1269                                                                          tblId, grantorId, ACL_KIND_TABLESPACE,
1270                                                                          NameStr(pg_tablespace_tuple->spcname));
1271
1272                 /*
1273                  * Generate new ACL.
1274                  *
1275                  * We need the members of both old and new ACLs so we can correct the
1276                  * shared dependency information.
1277                  */
1278                 noldmembers = aclmembers(old_acl, &oldmembers);
1279
1280                 new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
1281                                                                            istmt->grant_option, istmt->behavior,
1282                                                                            istmt->grantees, this_privileges,
1283                                                                            grantorId, ownerId);
1284
1285                 nnewmembers = aclmembers(new_acl, &newmembers);
1286
1287                 /* finished building new ACL value, now insert it */
1288                 MemSet(values, 0, sizeof(values));
1289                 MemSet(nulls, ' ', sizeof(nulls));
1290                 MemSet(replaces, ' ', sizeof(replaces));
1291
1292                 replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
1293                 values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
1294
1295                 newtuple = heap_modifytuple(tuple, RelationGetDescr(relation), values,
1296                                                                         nulls, replaces);
1297
1298                 simple_heap_update(relation, &newtuple->t_self, newtuple);
1299
1300                 /* keep the catalog indexes up to date */
1301                 CatalogUpdateIndexes(relation, newtuple);
1302
1303                 /* Update the shared dependency ACL info */
1304                 updateAclDependencies(TableSpaceRelationId, tblId,
1305                                                           ownerId, istmt->is_grant,
1306                                                           noldmembers, oldmembers,
1307                                                           nnewmembers, newmembers);
1308
1309                 systable_endscan(scan);
1310
1311                 pfree(new_acl);
1312
1313                 /* prevent error when processing duplicate objects */
1314                 CommandCounterIncrement();
1315         }
1316
1317         heap_close(relation, RowExclusiveLock);
1318 }
1319
1320
1321 static AclMode
1322 string_to_privilege(const char *privname)
1323 {
1324         if (strcmp(privname, "insert") == 0)
1325                 return ACL_INSERT;
1326         if (strcmp(privname, "select") == 0)
1327                 return ACL_SELECT;
1328         if (strcmp(privname, "update") == 0)
1329                 return ACL_UPDATE;
1330         if (strcmp(privname, "delete") == 0)
1331                 return ACL_DELETE;
1332         if (strcmp(privname, "references") == 0)
1333                 return ACL_REFERENCES;
1334         if (strcmp(privname, "trigger") == 0)
1335                 return ACL_TRIGGER;
1336         if (strcmp(privname, "execute") == 0)
1337                 return ACL_EXECUTE;
1338         if (strcmp(privname, "usage") == 0)
1339                 return ACL_USAGE;
1340         if (strcmp(privname, "create") == 0)
1341                 return ACL_CREATE;
1342         if (strcmp(privname, "temporary") == 0)
1343                 return ACL_CREATE_TEMP;
1344         if (strcmp(privname, "temp") == 0)
1345                 return ACL_CREATE_TEMP;
1346         if (strcmp(privname, "connect") == 0)
1347                 return ACL_CONNECT;
1348         if (strcmp(privname, "rule") == 0)
1349                 return 0;                               /* ignore old RULE privileges */
1350         ereport(ERROR,
1351                         (errcode(ERRCODE_SYNTAX_ERROR),
1352                          errmsg("unrecognized privilege type \"%s\"", privname)));
1353         return 0;                                       /* appease compiler */
1354 }
1355
1356 static const char *
1357 privilege_to_string(AclMode privilege)
1358 {
1359         switch (privilege)
1360         {
1361                 case ACL_INSERT:
1362                         return "INSERT";
1363                 case ACL_SELECT:
1364                         return "SELECT";
1365                 case ACL_UPDATE:
1366                         return "UPDATE";
1367                 case ACL_DELETE:
1368                         return "DELETE";
1369                 case ACL_REFERENCES:
1370                         return "REFERENCES";
1371                 case ACL_TRIGGER:
1372                         return "TRIGGER";
1373                 case ACL_EXECUTE:
1374                         return "EXECUTE";
1375                 case ACL_USAGE:
1376                         return "USAGE";
1377                 case ACL_CREATE:
1378                         return "CREATE";
1379                 case ACL_CREATE_TEMP:
1380                         return "TEMP";
1381                 case ACL_CONNECT:
1382                         return "CONNECT";
1383                 default:
1384                         elog(ERROR, "unrecognized privilege: %d", (int) privilege);
1385         }
1386         return NULL;                            /* appease compiler */
1387 }
1388
1389 /*
1390  * Standardized reporting of aclcheck permissions failures.
1391  *
1392  * Note: we do not double-quote the %s's below, because many callers
1393  * supply strings that might be already quoted.
1394  */
1395
1396 static const char *const no_priv_msg[MAX_ACL_KIND] =
1397 {
1398         /* ACL_KIND_CLASS */
1399         gettext_noop("permission denied for relation %s"),
1400         /* ACL_KIND_SEQUENCE */
1401         gettext_noop("permission denied for sequence %s"),
1402         /* ACL_KIND_DATABASE */
1403         gettext_noop("permission denied for database %s"),
1404         /* ACL_KIND_PROC */
1405         gettext_noop("permission denied for function %s"),
1406         /* ACL_KIND_OPER */
1407         gettext_noop("permission denied for operator %s"),
1408         /* ACL_KIND_TYPE */
1409         gettext_noop("permission denied for type %s"),
1410         /* ACL_KIND_LANGUAGE */
1411         gettext_noop("permission denied for language %s"),
1412         /* ACL_KIND_NAMESPACE */
1413         gettext_noop("permission denied for schema %s"),
1414         /* ACL_KIND_OPCLASS */
1415         gettext_noop("permission denied for operator class %s"),
1416         /* ACL_KIND_CONVERSION */
1417         gettext_noop("permission denied for conversion %s"),
1418         /* ACL_KIND_TABLESPACE */
1419         gettext_noop("permission denied for tablespace %s")
1420 };
1421
1422 static const char *const not_owner_msg[MAX_ACL_KIND] =
1423 {
1424         /* ACL_KIND_CLASS */
1425         gettext_noop("must be owner of relation %s"),
1426         /* ACL_KIND_SEQUENCE */
1427         gettext_noop("must be owner of sequence %s"),
1428         /* ACL_KIND_DATABASE */
1429         gettext_noop("must be owner of database %s"),
1430         /* ACL_KIND_PROC */
1431         gettext_noop("must be owner of function %s"),
1432         /* ACL_KIND_OPER */
1433         gettext_noop("must be owner of operator %s"),
1434         /* ACL_KIND_TYPE */
1435         gettext_noop("must be owner of type %s"),
1436         /* ACL_KIND_LANGUAGE */
1437         gettext_noop("must be owner of language %s"),
1438         /* ACL_KIND_NAMESPACE */
1439         gettext_noop("must be owner of schema %s"),
1440         /* ACL_KIND_OPCLASS */
1441         gettext_noop("must be owner of operator class %s"),
1442         /* ACL_KIND_CONVERSION */
1443         gettext_noop("must be owner of conversion %s"),
1444         /* ACL_KIND_TABLESPACE */
1445         gettext_noop("must be owner of tablespace %s")
1446 };
1447
1448
1449 void
1450 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
1451                            const char *objectname)
1452 {
1453         switch (aclerr)
1454         {
1455                 case ACLCHECK_OK:
1456                         /* no error, so return to caller */
1457                         break;
1458                 case ACLCHECK_NO_PRIV:
1459                         ereport(ERROR,
1460                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1461                                          errmsg(no_priv_msg[objectkind], objectname)));
1462                         break;
1463                 case ACLCHECK_NOT_OWNER:
1464                         ereport(ERROR,
1465                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1466                                          errmsg(not_owner_msg[objectkind], objectname)));
1467                         break;
1468                 default:
1469                         elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
1470                         break;
1471         }
1472 }
1473
1474
1475 /* Check if given user has rolcatupdate privilege according to pg_authid */
1476 static bool
1477 has_rolcatupdate(Oid roleid)
1478 {
1479         bool            rolcatupdate;
1480         HeapTuple       tuple;
1481
1482         tuple = SearchSysCache(AUTHOID,
1483                                                    ObjectIdGetDatum(roleid),
1484                                                    0, 0, 0);
1485         if (!HeapTupleIsValid(tuple))
1486                 ereport(ERROR,
1487                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1488                                  errmsg("role with OID %u does not exist", roleid)));
1489
1490         rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
1491
1492         ReleaseSysCache(tuple);
1493
1494         return rolcatupdate;
1495 }
1496
1497 /*
1498  * Relay for the various pg_*_mask routines depending on object kind
1499  */
1500 static AclMode
1501 pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
1502                    AclMode mask, AclMaskHow how)
1503 {
1504         switch (objkind)
1505         {
1506                 case ACL_KIND_CLASS:
1507                 case ACL_KIND_SEQUENCE:
1508                         return pg_class_aclmask(table_oid, roleid, mask, how);
1509                 case ACL_KIND_DATABASE:
1510                         return pg_database_aclmask(table_oid, roleid, mask, how);
1511                 case ACL_KIND_PROC:
1512                         return pg_proc_aclmask(table_oid, roleid, mask, how);
1513                 case ACL_KIND_LANGUAGE:
1514                         return pg_language_aclmask(table_oid, roleid, mask, how);
1515                 case ACL_KIND_NAMESPACE:
1516                         return pg_namespace_aclmask(table_oid, roleid, mask, how);
1517                 case ACL_KIND_TABLESPACE:
1518                         return pg_tablespace_aclmask(table_oid, roleid, mask, how);
1519                 default:
1520                         elog(ERROR, "unrecognized objkind: %d",
1521                                  (int) objkind);
1522                         /* not reached, but keep compiler quiet */
1523                         return ACL_NO_RIGHTS;
1524         }
1525 }
1526
1527 /*
1528  * Exported routine for examining a user's privileges for a table
1529  *
1530  * See aclmask() for a description of the API.
1531  *
1532  * Note: we give lookup failure the full ereport treatment because the
1533  * has_table_privilege() family of functions allow users to pass
1534  * any random OID to this function.  Likewise for the sibling functions
1535  * below.
1536  */
1537 AclMode
1538 pg_class_aclmask(Oid table_oid, Oid roleid,
1539                                  AclMode mask, AclMaskHow how)
1540 {
1541         AclMode         result;
1542         HeapTuple       tuple;
1543         Form_pg_class classForm;
1544         Datum           aclDatum;
1545         bool            isNull;
1546         Acl                *acl;
1547         Oid                     ownerId;
1548
1549         /*
1550          * Must get the relation's tuple from pg_class
1551          */
1552         tuple = SearchSysCache(RELOID,
1553                                                    ObjectIdGetDatum(table_oid),
1554                                                    0, 0, 0);
1555         if (!HeapTupleIsValid(tuple))
1556                 ereport(ERROR,
1557                                 (errcode(ERRCODE_UNDEFINED_TABLE),
1558                                  errmsg("relation with OID %u does not exist",
1559                                                 table_oid)));
1560         classForm = (Form_pg_class) GETSTRUCT(tuple);
1561
1562         /*
1563          * Deny anyone permission to update a system catalog unless
1564          * pg_authid.rolcatupdate is set.       (This is to let superusers protect
1565          * themselves from themselves.)  Also allow it if allowSystemTableMods.
1566          *
1567          * As of 7.4 we have some updatable system views; those shouldn't be
1568          * protected in this way.  Assume the view rules can take care of
1569          * themselves.  ACL_USAGE is if we ever have system sequences.
1570          */
1571         if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE)) &&
1572                 IsSystemClass(classForm) &&
1573                 classForm->relkind != RELKIND_VIEW &&
1574                 !has_rolcatupdate(roleid) &&
1575                 !allowSystemTableMods)
1576         {
1577 #ifdef ACLDEBUG
1578                 elog(DEBUG2, "permission denied for system catalog update");
1579 #endif
1580                 mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE);
1581         }
1582
1583         /*
1584          * Otherwise, superusers bypass all permission-checking.
1585          */
1586         if (superuser_arg(roleid))
1587         {
1588 #ifdef ACLDEBUG
1589                 elog(DEBUG2, "OID %u is superuser, home free", roleid);
1590 #endif
1591                 ReleaseSysCache(tuple);
1592                 return mask;
1593         }
1594
1595         /*
1596          * Normal case: get the relation's ACL from pg_class
1597          */
1598         ownerId = classForm->relowner;
1599
1600         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1601                                                            &isNull);
1602         if (isNull)
1603         {
1604                 /* No ACL, so build default ACL */
1605                 acl = acldefault(classForm->relkind == RELKIND_SEQUENCE ?
1606                                                  ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION,
1607                                                  ownerId);
1608                 aclDatum = (Datum) 0;
1609         }
1610         else
1611         {
1612                 /* detoast rel's ACL if necessary */
1613                 acl = DatumGetAclP(aclDatum);
1614         }
1615
1616         result = aclmask(acl, roleid, ownerId, mask, how);
1617
1618         /* if we have a detoasted copy, free it */
1619         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1620                 pfree(acl);
1621
1622         ReleaseSysCache(tuple);
1623
1624         return result;
1625 }
1626
1627 /*
1628  * Exported routine for examining a user's privileges for a database
1629  */
1630 AclMode
1631 pg_database_aclmask(Oid db_oid, Oid roleid,
1632                                         AclMode mask, AclMaskHow how)
1633 {
1634         AclMode         result;
1635         HeapTuple       tuple;
1636         Datum           aclDatum;
1637         bool            isNull;
1638         Acl                *acl;
1639         Oid                     ownerId;
1640
1641         /* Superusers bypass all permission checking. */
1642         if (superuser_arg(roleid))
1643                 return mask;
1644
1645         /*
1646          * Get the database's ACL from pg_database
1647          */
1648         tuple = SearchSysCache(DATABASEOID,
1649                                                    ObjectIdGetDatum(db_oid),
1650                                                    0, 0, 0);
1651         if (!HeapTupleIsValid(tuple))
1652                 ereport(ERROR,
1653                                 (errcode(ERRCODE_UNDEFINED_DATABASE),
1654                                  errmsg("database with OID %u does not exist", db_oid)));
1655
1656         ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
1657
1658         aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
1659                                                            &isNull);
1660         if (isNull)
1661         {
1662                 /* No ACL, so build default ACL */
1663                 acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
1664                 aclDatum = (Datum) 0;
1665         }
1666         else
1667         {
1668                 /* detoast ACL if necessary */
1669                 acl = DatumGetAclP(aclDatum);
1670         }
1671
1672         result = aclmask(acl, roleid, ownerId, mask, how);
1673
1674         /* if we have a detoasted copy, free it */
1675         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1676                 pfree(acl);
1677
1678         ReleaseSysCache(tuple);
1679
1680         return result;
1681 }
1682
1683 /*
1684  * Exported routine for examining a user's privileges for a function
1685  */
1686 AclMode
1687 pg_proc_aclmask(Oid proc_oid, Oid roleid,
1688                                 AclMode mask, AclMaskHow how)
1689 {
1690         AclMode         result;
1691         HeapTuple       tuple;
1692         Datum           aclDatum;
1693         bool            isNull;
1694         Acl                *acl;
1695         Oid                     ownerId;
1696
1697         /* Superusers bypass all permission checking. */
1698         if (superuser_arg(roleid))
1699                 return mask;
1700
1701         /*
1702          * Get the function's ACL from pg_proc
1703          */
1704         tuple = SearchSysCache(PROCOID,
1705                                                    ObjectIdGetDatum(proc_oid),
1706                                                    0, 0, 0);
1707         if (!HeapTupleIsValid(tuple))
1708                 ereport(ERROR,
1709                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1710                                  errmsg("function with OID %u does not exist", proc_oid)));
1711
1712         ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1713
1714         aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1715                                                            &isNull);
1716         if (isNull)
1717         {
1718                 /* No ACL, so build default ACL */
1719                 acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
1720                 aclDatum = (Datum) 0;
1721         }
1722         else
1723         {
1724                 /* detoast ACL if necessary */
1725                 acl = DatumGetAclP(aclDatum);
1726         }
1727
1728         result = aclmask(acl, roleid, ownerId, mask, how);
1729
1730         /* if we have a detoasted copy, free it */
1731         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1732                 pfree(acl);
1733
1734         ReleaseSysCache(tuple);
1735
1736         return result;
1737 }
1738
1739 /*
1740  * Exported routine for examining a user's privileges for a language
1741  */
1742 AclMode
1743 pg_language_aclmask(Oid lang_oid, Oid roleid,
1744                                         AclMode mask, AclMaskHow how)
1745 {
1746         AclMode         result;
1747         HeapTuple       tuple;
1748         Datum           aclDatum;
1749         bool            isNull;
1750         Acl                *acl;
1751         Oid                     ownerId;
1752
1753         /* Superusers bypass all permission checking. */
1754         if (superuser_arg(roleid))
1755                 return mask;
1756
1757         /*
1758          * Get the language's ACL from pg_language
1759          */
1760         tuple = SearchSysCache(LANGOID,
1761                                                    ObjectIdGetDatum(lang_oid),
1762                                                    0, 0, 0);
1763         if (!HeapTupleIsValid(tuple))
1764                 ereport(ERROR,
1765                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1766                                  errmsg("language with OID %u does not exist", lang_oid)));
1767
1768         /* XXX pg_language should have an owner column, but doesn't */
1769         ownerId = BOOTSTRAP_SUPERUSERID;
1770
1771         aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1772                                                            &isNull);
1773         if (isNull)
1774         {
1775                 /* No ACL, so build default ACL */
1776                 acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
1777                 aclDatum = (Datum) 0;
1778         }
1779         else
1780         {
1781                 /* detoast ACL if necessary */
1782                 acl = DatumGetAclP(aclDatum);
1783         }
1784
1785         result = aclmask(acl, roleid, ownerId, mask, how);
1786
1787         /* if we have a detoasted copy, free it */
1788         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1789                 pfree(acl);
1790
1791         ReleaseSysCache(tuple);
1792
1793         return result;
1794 }
1795
1796 /*
1797  * Exported routine for examining a user's privileges for a namespace
1798  */
1799 AclMode
1800 pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
1801                                          AclMode mask, AclMaskHow how)
1802 {
1803         AclMode         result;
1804         HeapTuple       tuple;
1805         Datum           aclDatum;
1806         bool            isNull;
1807         Acl                *acl;
1808         Oid                     ownerId;
1809
1810         /* Superusers bypass all permission checking. */
1811         if (superuser_arg(roleid))
1812                 return mask;
1813
1814         /*
1815          * If we have been assigned this namespace as a temp namespace, check to
1816          * make sure we have CREATE TEMP permission on the database, and if so act
1817          * as though we have all standard (but not GRANT OPTION) permissions on
1818          * the namespace.  If we don't have CREATE TEMP, act as though we have
1819          * only USAGE (and not CREATE) rights.
1820          *
1821          * This may seem redundant given the check in InitTempTableNamespace, but
1822          * it really isn't since current user ID may have changed since then. The
1823          * upshot of this behavior is that a SECURITY DEFINER function can create
1824          * temp tables that can then be accessed (if permission is granted) by
1825          * code in the same session that doesn't have permissions to create temp
1826          * tables.
1827          *
1828          * XXX Would it be safe to ereport a special error message as
1829          * InitTempTableNamespace does?  Returning zero here means we'll get a
1830          * generic "permission denied for schema pg_temp_N" message, which is not
1831          * remarkably user-friendly.
1832          */
1833         if (isTempNamespace(nsp_oid))
1834         {
1835                 if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
1836                                                                  ACL_CREATE_TEMP) == ACLCHECK_OK)
1837                         return mask & ACL_ALL_RIGHTS_NAMESPACE;
1838                 else
1839                         return mask & ACL_USAGE;
1840         }
1841
1842         /*
1843          * Get the schema's ACL from pg_namespace
1844          */
1845         tuple = SearchSysCache(NAMESPACEOID,
1846                                                    ObjectIdGetDatum(nsp_oid),
1847                                                    0, 0, 0);
1848         if (!HeapTupleIsValid(tuple))
1849                 ereport(ERROR,
1850                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1851                                  errmsg("schema with OID %u does not exist", nsp_oid)));
1852
1853         ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1854
1855         aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
1856                                                            &isNull);
1857         if (isNull)
1858         {
1859                 /* No ACL, so build default ACL */
1860                 acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1861                 aclDatum = (Datum) 0;
1862         }
1863         else
1864         {
1865                 /* detoast ACL if necessary */
1866                 acl = DatumGetAclP(aclDatum);
1867         }
1868
1869         result = aclmask(acl, roleid, ownerId, mask, how);
1870
1871         /* if we have a detoasted copy, free it */
1872         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1873                 pfree(acl);
1874
1875         ReleaseSysCache(tuple);
1876
1877         return result;
1878 }
1879
1880 /*
1881  * Exported routine for examining a user's privileges for a tablespace
1882  */
1883 AclMode
1884 pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
1885                                           AclMode mask, AclMaskHow how)
1886 {
1887         AclMode         result;
1888         Relation        pg_tablespace;
1889         ScanKeyData entry[1];
1890         SysScanDesc scan;
1891         HeapTuple       tuple;
1892         Datum           aclDatum;
1893         bool            isNull;
1894         Acl                *acl;
1895         Oid                     ownerId;
1896
1897         /*
1898          * Only shared relations can be stored in global space; don't let even
1899          * superusers override this
1900          */
1901         if (spc_oid == GLOBALTABLESPACE_OID && !IsBootstrapProcessingMode())
1902                 return 0;
1903
1904         /* Otherwise, superusers bypass all permission checking. */
1905         if (superuser_arg(roleid))
1906                 return mask;
1907
1908         /*
1909          * Get the tablespace's ACL from pg_tablespace
1910          *
1911          * There's no syscache for pg_tablespace, so must look the hard way
1912          */
1913         pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
1914         ScanKeyInit(&entry[0],
1915                                 ObjectIdAttributeNumber,
1916                                 BTEqualStrategyNumber, F_OIDEQ,
1917                                 ObjectIdGetDatum(spc_oid));
1918         scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
1919                                                           SnapshotNow, 1, entry);
1920         tuple = systable_getnext(scan);
1921         if (!HeapTupleIsValid(tuple))
1922                 ereport(ERROR,
1923                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1924                                  errmsg("tablespace with OID %u does not exist", spc_oid)));
1925
1926         ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
1927
1928         aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
1929                                                         RelationGetDescr(pg_tablespace), &isNull);
1930
1931         if (isNull)
1932         {
1933                 /* No ACL, so build default ACL */
1934                 acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
1935                 aclDatum = (Datum) 0;
1936         }
1937         else
1938         {
1939                 /* detoast ACL if necessary */
1940                 acl = DatumGetAclP(aclDatum);
1941         }
1942
1943         result = aclmask(acl, roleid, ownerId, mask, how);
1944
1945         /* if we have a detoasted copy, free it */
1946         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1947                 pfree(acl);
1948
1949         systable_endscan(scan);
1950         heap_close(pg_tablespace, AccessShareLock);
1951
1952         return result;
1953 }
1954
1955
1956 /*
1957  * Exported routine for checking a user's access privileges to a table
1958  *
1959  * Returns ACLCHECK_OK if the user has any of the privileges identified by
1960  * 'mode'; otherwise returns a suitable error code (in practice, always
1961  * ACLCHECK_NO_PRIV).
1962  */
1963 AclResult
1964 pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
1965 {
1966         if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
1967                 return ACLCHECK_OK;
1968         else
1969                 return ACLCHECK_NO_PRIV;
1970 }
1971
1972 /*
1973  * Exported routine for checking a user's access privileges to a database
1974  */
1975 AclResult
1976 pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
1977 {
1978         if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
1979                 return ACLCHECK_OK;
1980         else
1981                 return ACLCHECK_NO_PRIV;
1982 }
1983
1984 /*
1985  * Exported routine for checking a user's access privileges to a function
1986  */
1987 AclResult
1988 pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
1989 {
1990         if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
1991                 return ACLCHECK_OK;
1992         else
1993                 return ACLCHECK_NO_PRIV;
1994 }
1995
1996 /*
1997  * Exported routine for checking a user's access privileges to a language
1998  */
1999 AclResult
2000 pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
2001 {
2002         if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
2003                 return ACLCHECK_OK;
2004         else
2005                 return ACLCHECK_NO_PRIV;
2006 }
2007
2008 /*
2009  * Exported routine for checking a user's access privileges to a namespace
2010  */
2011 AclResult
2012 pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
2013 {
2014         if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
2015                 return ACLCHECK_OK;
2016         else
2017                 return ACLCHECK_NO_PRIV;
2018 }
2019
2020 /*
2021  * Exported routine for checking a user's access privileges to a tablespace
2022  */
2023 AclResult
2024 pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
2025 {
2026         if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
2027                 return ACLCHECK_OK;
2028         else
2029                 return ACLCHECK_NO_PRIV;
2030 }
2031
2032
2033 /*
2034  * Ownership check for a relation (specified by OID).
2035  */
2036 bool
2037 pg_class_ownercheck(Oid class_oid, Oid roleid)
2038 {
2039         HeapTuple       tuple;
2040         Oid                     ownerId;
2041
2042         /* Superusers bypass all permission checking. */
2043         if (superuser_arg(roleid))
2044                 return true;
2045
2046         tuple = SearchSysCache(RELOID,
2047                                                    ObjectIdGetDatum(class_oid),
2048                                                    0, 0, 0);
2049         if (!HeapTupleIsValid(tuple))
2050                 ereport(ERROR,
2051                                 (errcode(ERRCODE_UNDEFINED_TABLE),
2052                                  errmsg("relation with OID %u does not exist", class_oid)));
2053
2054         ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
2055
2056         ReleaseSysCache(tuple);
2057
2058         return has_privs_of_role(roleid, ownerId);
2059 }
2060
2061 /*
2062  * Ownership check for a type (specified by OID).
2063  */
2064 bool
2065 pg_type_ownercheck(Oid type_oid, Oid roleid)
2066 {
2067         HeapTuple       tuple;
2068         Oid                     ownerId;
2069
2070         /* Superusers bypass all permission checking. */
2071         if (superuser_arg(roleid))
2072                 return true;
2073
2074         tuple = SearchSysCache(TYPEOID,
2075                                                    ObjectIdGetDatum(type_oid),
2076                                                    0, 0, 0);
2077         if (!HeapTupleIsValid(tuple))
2078                 ereport(ERROR,
2079                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2080                                  errmsg("type with OID %u does not exist", type_oid)));
2081
2082         ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
2083
2084         ReleaseSysCache(tuple);
2085
2086         return has_privs_of_role(roleid, ownerId);
2087 }
2088
2089 /*
2090  * Ownership check for an operator (specified by OID).
2091  */
2092 bool
2093 pg_oper_ownercheck(Oid oper_oid, Oid roleid)
2094 {
2095         HeapTuple       tuple;
2096         Oid                     ownerId;
2097
2098         /* Superusers bypass all permission checking. */
2099         if (superuser_arg(roleid))
2100                 return true;
2101
2102         tuple = SearchSysCache(OPEROID,
2103                                                    ObjectIdGetDatum(oper_oid),
2104                                                    0, 0, 0);
2105         if (!HeapTupleIsValid(tuple))
2106                 ereport(ERROR,
2107                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2108                                  errmsg("operator with OID %u does not exist", oper_oid)));
2109
2110         ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
2111
2112         ReleaseSysCache(tuple);
2113
2114         return has_privs_of_role(roleid, ownerId);
2115 }
2116
2117 /*
2118  * Ownership check for a function (specified by OID).
2119  */
2120 bool
2121 pg_proc_ownercheck(Oid proc_oid, Oid roleid)
2122 {
2123         HeapTuple       tuple;
2124         Oid                     ownerId;
2125
2126         /* Superusers bypass all permission checking. */
2127         if (superuser_arg(roleid))
2128                 return true;
2129
2130         tuple = SearchSysCache(PROCOID,
2131                                                    ObjectIdGetDatum(proc_oid),
2132                                                    0, 0, 0);
2133         if (!HeapTupleIsValid(tuple))
2134                 ereport(ERROR,
2135                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
2136                                  errmsg("function with OID %u does not exist", proc_oid)));
2137
2138         ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
2139
2140         ReleaseSysCache(tuple);
2141
2142         return has_privs_of_role(roleid, ownerId);
2143 }
2144
2145 /*
2146  * Ownership check for a namespace (specified by OID).
2147  */
2148 bool
2149 pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
2150 {
2151         HeapTuple       tuple;
2152         Oid                     ownerId;
2153
2154         /* Superusers bypass all permission checking. */
2155         if (superuser_arg(roleid))
2156                 return true;
2157
2158         tuple = SearchSysCache(NAMESPACEOID,
2159                                                    ObjectIdGetDatum(nsp_oid),
2160                                                    0, 0, 0);
2161         if (!HeapTupleIsValid(tuple))
2162                 ereport(ERROR,
2163                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
2164                                  errmsg("schema with OID %u does not exist", nsp_oid)));
2165
2166         ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
2167
2168         ReleaseSysCache(tuple);
2169
2170         return has_privs_of_role(roleid, ownerId);
2171 }
2172
2173 /*
2174  * Ownership check for a tablespace (specified by OID).
2175  */
2176 bool
2177 pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
2178 {
2179         Relation        pg_tablespace;
2180         ScanKeyData entry[1];
2181         SysScanDesc scan;
2182         HeapTuple       spctuple;
2183         Oid                     spcowner;
2184
2185         /* Superusers bypass all permission checking. */
2186         if (superuser_arg(roleid))
2187                 return true;
2188
2189         /* There's no syscache for pg_tablespace, so must look the hard way */
2190         pg_tablespace = heap_open(TableSpaceRelationId, AccessShareLock);
2191         ScanKeyInit(&entry[0],
2192                                 ObjectIdAttributeNumber,
2193                                 BTEqualStrategyNumber, F_OIDEQ,
2194                                 ObjectIdGetDatum(spc_oid));
2195         scan = systable_beginscan(pg_tablespace, TablespaceOidIndexId, true,
2196                                                           SnapshotNow, 1, entry);
2197
2198         spctuple = systable_getnext(scan);
2199
2200         if (!HeapTupleIsValid(spctuple))
2201                 ereport(ERROR,
2202                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2203                                  errmsg("tablespace with OID %u does not exist", spc_oid)));
2204
2205         spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
2206
2207         systable_endscan(scan);
2208         heap_close(pg_tablespace, AccessShareLock);
2209
2210         return has_privs_of_role(roleid, spcowner);
2211 }
2212
2213 /*
2214  * Ownership check for an operator class (specified by OID).
2215  */
2216 bool
2217 pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
2218 {
2219         HeapTuple       tuple;
2220         Oid                     ownerId;
2221
2222         /* Superusers bypass all permission checking. */
2223         if (superuser_arg(roleid))
2224                 return true;
2225
2226         tuple = SearchSysCache(CLAOID,
2227                                                    ObjectIdGetDatum(opc_oid),
2228                                                    0, 0, 0);
2229         if (!HeapTupleIsValid(tuple))
2230                 ereport(ERROR,
2231                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2232                                  errmsg("operator class with OID %u does not exist",
2233                                                 opc_oid)));
2234
2235         ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
2236
2237         ReleaseSysCache(tuple);
2238
2239         return has_privs_of_role(roleid, ownerId);
2240 }
2241
2242 /*
2243  * Ownership check for a database (specified by OID).
2244  */
2245 bool
2246 pg_database_ownercheck(Oid db_oid, Oid roleid)
2247 {
2248         HeapTuple       tuple;
2249         Oid                     dba;
2250
2251         /* Superusers bypass all permission checking. */
2252         if (superuser_arg(roleid))
2253                 return true;
2254
2255         tuple = SearchSysCache(DATABASEOID,
2256                                                    ObjectIdGetDatum(db_oid),
2257                                                    0, 0, 0);
2258         if (!HeapTupleIsValid(tuple))
2259                 ereport(ERROR,
2260                                 (errcode(ERRCODE_UNDEFINED_DATABASE),
2261                                  errmsg("database with OID %u does not exist", db_oid)));
2262
2263         dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
2264
2265         ReleaseSysCache(tuple);
2266
2267         return has_privs_of_role(roleid, dba);
2268 }
2269
2270 /*
2271  * Ownership check for a conversion (specified by OID).
2272  */
2273 bool
2274 pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
2275 {
2276         HeapTuple       tuple;
2277         Oid                     ownerId;
2278
2279         /* Superusers bypass all permission checking. */
2280         if (superuser_arg(roleid))
2281                 return true;
2282
2283         tuple = SearchSysCache(CONOID,
2284                                                    ObjectIdGetDatum(conv_oid),
2285                                                    0, 0, 0);
2286         if (!HeapTupleIsValid(tuple))
2287                 ereport(ERROR,
2288                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2289                                  errmsg("conversion with OID %u does not exist", conv_oid)));
2290
2291         ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
2292
2293         ReleaseSysCache(tuple);
2294
2295         return has_privs_of_role(roleid, ownerId);
2296 }