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