OSDN Git Service

7ace67de6b2f394f1b9384a571b28091e8f94d87
[pg-rex/syncrep.git] / src / backend / catalog / aclchk.c
1 /*-------------------------------------------------------------------------
2  *
3  * aclchk.c
4  *        Routines to check access control permissions.
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.86 2003/08/04 00:43:16 momjian 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/catname.h"
23 #include "catalog/indexing.h"
24 #include "catalog/namespace.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_type.h"
34 #include "miscadmin.h"
35 #include "parser/parse_func.h"
36 #include "utils/acl.h"
37 #include "utils/fmgroids.h"
38 #include "utils/lsyscache.h"
39 #include "utils/syscache.h"
40
41
42 static void ExecuteGrantStmt_Relation(GrantStmt *stmt);
43 static void ExecuteGrantStmt_Database(GrantStmt *stmt);
44 static void ExecuteGrantStmt_Function(GrantStmt *stmt);
45 static void ExecuteGrantStmt_Language(GrantStmt *stmt);
46 static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
47
48 static const char *privilege_to_string(AclMode privilege);
49
50 static AclResult aclcheck(Acl *acl, AclId userid, AclMode mode);
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  * If is_grant is true, adds the given privileges for the list of
73  * grantees to the existing old_acl.  If is_grant is false, the
74  * privileges for the given grantees are removed from old_acl.
75  */
76 static Acl *
77 merge_acl_with_grant(Acl *old_acl, bool is_grant,
78                                          List *grantees, AclMode privileges,
79                                          bool grant_option, DropBehavior behavior)
80 {
81         unsigned        modechg;
82         List       *j;
83         Acl                *new_acl;
84
85         modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
86
87 #ifdef ACLDEBUG
88         dumpacl(old_acl);
89 #endif
90         new_acl = old_acl;
91
92         foreach(j, grantees)
93         {
94                 PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
95                 AclItem aclitem;
96                 uint32          idtype;
97
98                 if (grantee->username)
99                 {
100                         aclitem.        ai_grantee = get_usesysid(grantee->username);
101
102                         idtype = ACL_IDTYPE_UID;
103                 }
104                 else if (grantee->groupname)
105                 {
106                         aclitem.        ai_grantee = get_grosysid(grantee->groupname);
107
108                         idtype = ACL_IDTYPE_GID;
109                 }
110                 else
111                 {
112                         aclitem.        ai_grantee = ACL_ID_WORLD;
113
114                         idtype = ACL_IDTYPE_WORLD;
115                 }
116
117                 /*
118                  * Grant options can only be granted to individual users, not
119                  * groups or public.  The reason is that if a user would re-grant
120                  * a privilege that he held through a group having a grant option,
121                  * and later the user is removed from the group, the situation is
122                  * impossible to clean up.
123                  */
124                 if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
125                         ereport(ERROR,
126                                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
127                                          errmsg("grant options can only be granted to individual users")));
128
129                 aclitem.        ai_grantor = GetUserId();
130
131                 ACLITEM_SET_PRIVS_IDTYPE(aclitem,
132                                 (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
133                                 (grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS,
134                                                                  idtype);
135
136                 new_acl = aclinsert3(new_acl, &aclitem, modechg, behavior);
137
138 #ifdef ACLDEBUG
139                 dumpacl(new_acl);
140 #endif
141         }
142
143         return new_acl;
144 }
145
146
147 /*
148  * Called to execute the utility commands GRANT and REVOKE
149  */
150 void
151 ExecuteGrantStmt(GrantStmt *stmt)
152 {
153         switch (stmt->objtype)
154         {
155                 case ACL_OBJECT_RELATION:
156                         ExecuteGrantStmt_Relation(stmt);
157                         break;
158                 case ACL_OBJECT_DATABASE:
159                         ExecuteGrantStmt_Database(stmt);
160                         break;
161                 case ACL_OBJECT_FUNCTION:
162                         ExecuteGrantStmt_Function(stmt);
163                         break;
164                 case ACL_OBJECT_LANGUAGE:
165                         ExecuteGrantStmt_Language(stmt);
166                         break;
167                 case ACL_OBJECT_NAMESPACE:
168                         ExecuteGrantStmt_Namespace(stmt);
169                         break;
170                 default:
171                         elog(ERROR, "unrecognized GrantStmt.objtype: %d",
172                                  (int) stmt->objtype);
173         }
174 }
175
176 static void
177 ExecuteGrantStmt_Relation(GrantStmt *stmt)
178 {
179         AclMode         privileges;
180         List       *i;
181
182         if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
183                 privileges = ACL_ALL_RIGHTS_RELATION;
184         else
185         {
186                 privileges = ACL_NO_RIGHTS;
187                 foreach(i, stmt->privileges)
188                 {
189                         AclMode         priv = lfirsti(i);
190
191                         if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
192                                 ereport(ERROR,
193                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
194                                                  errmsg("invalid privilege type %s for table",
195                                                                 privilege_to_string(priv))));
196                         privileges |= priv;
197                 }
198         }
199
200         foreach(i, stmt->objects)
201         {
202                 RangeVar   *relvar = (RangeVar *) lfirst(i);
203                 Oid                     relOid;
204                 Relation        relation;
205                 HeapTuple       tuple;
206                 Form_pg_class pg_class_tuple;
207                 Datum           aclDatum;
208                 bool            isNull;
209                 Acl                *old_acl;
210                 Acl                *new_acl;
211                 HeapTuple       newtuple;
212                 Datum           values[Natts_pg_class];
213                 char            nulls[Natts_pg_class];
214                 char            replaces[Natts_pg_class];
215
216                 /* open pg_class */
217                 relation = heap_openr(RelationRelationName, RowExclusiveLock);
218                 relOid = RangeVarGetRelid(relvar, false);
219                 tuple = SearchSysCache(RELOID,
220                                                            ObjectIdGetDatum(relOid),
221                                                            0, 0, 0);
222                 if (!HeapTupleIsValid(tuple))
223                         elog(ERROR, "cache lookup failed for relation %u", relOid);
224                 pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
225
226                 if (stmt->is_grant
227                         && !pg_class_ownercheck(relOid, GetUserId())
228                         && pg_class_aclcheck(relOid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
229                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, relvar->relname);
230
231                 /* Not sensible to grant on an index */
232                 if (pg_class_tuple->relkind == RELKIND_INDEX)
233                         ereport(ERROR,
234                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
235                                          errmsg("\"%s\" is an index",
236                                                         relvar->relname)));
237
238                 /*
239                  * If there's no ACL, create a default using the pg_class.relowner
240                  * field.
241                  */
242                 aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
243                                                                    &isNull);
244                 if (isNull)
245                         old_acl = acldefault(ACL_OBJECT_RELATION,
246                                                                  pg_class_tuple->relowner);
247                 else
248                         /* get a detoasted copy of the ACL */
249                         old_acl = DatumGetAclPCopy(aclDatum);
250
251                 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
252                                                                            stmt->grantees, privileges,
253                                                                          stmt->grant_option, stmt->behavior);
254
255                 /* finished building new ACL value, now insert it */
256                 MemSet(values, 0, sizeof(values));
257                 MemSet(nulls, ' ', sizeof(nulls));
258                 MemSet(replaces, ' ', sizeof(replaces));
259
260                 replaces[Anum_pg_class_relacl - 1] = 'r';
261                 values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
262
263                 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
264
265                 ReleaseSysCache(tuple);
266
267                 simple_heap_update(relation, &newtuple->t_self, newtuple);
268
269                 /* keep the catalog indexes up to date */
270                 CatalogUpdateIndexes(relation, newtuple);
271
272                 pfree(old_acl);
273                 pfree(new_acl);
274
275                 heap_close(relation, RowExclusiveLock);
276         }
277 }
278
279 static void
280 ExecuteGrantStmt_Database(GrantStmt *stmt)
281 {
282         AclMode         privileges;
283         List       *i;
284
285         if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
286                 privileges = ACL_ALL_RIGHTS_DATABASE;
287         else
288         {
289                 privileges = ACL_NO_RIGHTS;
290                 foreach(i, stmt->privileges)
291                 {
292                         AclMode         priv = lfirsti(i);
293
294                         if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
295                                 ereport(ERROR,
296                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
297                                                  errmsg("invalid privilege type %s for database",
298                                                                 privilege_to_string(priv))));
299                         privileges |= priv;
300                 }
301         }
302
303         foreach(i, stmt->objects)
304         {
305                 char       *dbname = strVal(lfirst(i));
306                 Relation        relation;
307                 ScanKeyData entry[1];
308                 HeapScanDesc scan;
309                 HeapTuple       tuple;
310                 Form_pg_database pg_database_tuple;
311                 Datum           aclDatum;
312                 bool            isNull;
313                 Acl                *old_acl;
314                 Acl                *new_acl;
315                 HeapTuple       newtuple;
316                 Datum           values[Natts_pg_database];
317                 char            nulls[Natts_pg_database];
318                 char            replaces[Natts_pg_database];
319
320                 relation = heap_openr(DatabaseRelationName, RowExclusiveLock);
321                 ScanKeyEntryInitialize(&entry[0], 0,
322                                                            Anum_pg_database_datname, F_NAMEEQ,
323                                                            CStringGetDatum(dbname));
324                 scan = heap_beginscan(relation, SnapshotNow, 1, entry);
325                 tuple = heap_getnext(scan, ForwardScanDirection);
326                 if (!HeapTupleIsValid(tuple))
327                         ereport(ERROR,
328                                         (errcode(ERRCODE_UNDEFINED_DATABASE),
329                                          errmsg("database \"%s\" does not exist", dbname)));
330                 pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
331
332                 if (stmt->is_grant
333                         && pg_database_tuple->datdba != GetUserId()
334                         && pg_database_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
335                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
336                                                    NameStr(pg_database_tuple->datname));
337
338                 /*
339                  * If there's no ACL, create a default.
340                  */
341                 aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
342                                                                 RelationGetDescr(relation), &isNull);
343                 if (isNull)
344                         old_acl = acldefault(ACL_OBJECT_DATABASE,
345                                                                  pg_database_tuple->datdba);
346                 else
347                         /* get a detoasted copy of the ACL */
348                         old_acl = DatumGetAclPCopy(aclDatum);
349
350                 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
351                                                                            stmt->grantees, privileges,
352                                                                          stmt->grant_option, stmt->behavior);
353
354                 /* finished building new ACL value, now insert it */
355                 MemSet(values, 0, sizeof(values));
356                 MemSet(nulls, ' ', sizeof(nulls));
357                 MemSet(replaces, ' ', sizeof(replaces));
358
359                 replaces[Anum_pg_database_datacl - 1] = 'r';
360                 values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
361
362                 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
363
364                 simple_heap_update(relation, &newtuple->t_self, newtuple);
365
366                 /* keep the catalog indexes up to date */
367                 CatalogUpdateIndexes(relation, newtuple);
368
369                 pfree(old_acl);
370                 pfree(new_acl);
371
372                 heap_endscan(scan);
373
374                 heap_close(relation, RowExclusiveLock);
375         }
376 }
377
378 static void
379 ExecuteGrantStmt_Function(GrantStmt *stmt)
380 {
381         AclMode         privileges;
382         List       *i;
383
384         if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
385                 privileges = ACL_ALL_RIGHTS_FUNCTION;
386         else
387         {
388                 privileges = ACL_NO_RIGHTS;
389                 foreach(i, stmt->privileges)
390                 {
391                         AclMode         priv = lfirsti(i);
392
393                         if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
394                                 ereport(ERROR,
395                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
396                                                  errmsg("invalid privilege type %s for function",
397                                                                 privilege_to_string(priv))));
398                         privileges |= priv;
399                 }
400         }
401
402         foreach(i, stmt->objects)
403         {
404                 FuncWithArgs *func = (FuncWithArgs *) lfirst(i);
405                 Oid                     oid;
406                 Relation        relation;
407                 HeapTuple       tuple;
408                 Form_pg_proc pg_proc_tuple;
409                 Datum           aclDatum;
410                 bool            isNull;
411                 Acl                *old_acl;
412                 Acl                *new_acl;
413                 HeapTuple       newtuple;
414                 Datum           values[Natts_pg_proc];
415                 char            nulls[Natts_pg_proc];
416                 char            replaces[Natts_pg_proc];
417
418                 oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false);
419
420                 relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
421                 tuple = SearchSysCache(PROCOID,
422                                                            ObjectIdGetDatum(oid),
423                                                            0, 0, 0);
424                 if (!HeapTupleIsValid(tuple))
425                         elog(ERROR, "cache lookup failed for function %u", oid);
426                 pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
427
428                 if (stmt->is_grant
429                         && !pg_proc_ownercheck(oid, GetUserId())
430                         && pg_proc_aclcheck(oid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
431                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
432                                                    NameStr(pg_proc_tuple->proname));
433
434                 /*
435                  * If there's no ACL, create a default using the pg_proc.proowner
436                  * field.
437                  */
438                 aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
439                                                                    &isNull);
440                 if (isNull)
441                         old_acl = acldefault(ACL_OBJECT_FUNCTION,
442                                                                  pg_proc_tuple->proowner);
443                 else
444                         /* get a detoasted copy of the ACL */
445                         old_acl = DatumGetAclPCopy(aclDatum);
446
447                 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
448                                                                            stmt->grantees, privileges,
449                                                                          stmt->grant_option, stmt->behavior);
450
451                 /* finished building new ACL value, now insert it */
452                 MemSet(values, 0, sizeof(values));
453                 MemSet(nulls, ' ', sizeof(nulls));
454                 MemSet(replaces, ' ', sizeof(replaces));
455
456                 replaces[Anum_pg_proc_proacl - 1] = 'r';
457                 values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
458
459                 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
460
461                 ReleaseSysCache(tuple);
462
463                 simple_heap_update(relation, &newtuple->t_self, newtuple);
464
465                 /* keep the catalog indexes up to date */
466                 CatalogUpdateIndexes(relation, newtuple);
467
468                 pfree(old_acl);
469                 pfree(new_acl);
470
471                 heap_close(relation, RowExclusiveLock);
472         }
473 }
474
475 static void
476 ExecuteGrantStmt_Language(GrantStmt *stmt)
477 {
478         AclMode         privileges;
479         List       *i;
480
481         if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
482                 privileges = ACL_ALL_RIGHTS_LANGUAGE;
483         else
484         {
485                 privileges = ACL_NO_RIGHTS;
486                 foreach(i, stmt->privileges)
487                 {
488                         AclMode         priv = lfirsti(i);
489
490                         if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
491                                 ereport(ERROR,
492                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
493                                                  errmsg("invalid privilege type %s for language",
494                                                                 privilege_to_string(priv))));
495                         privileges |= priv;
496                 }
497         }
498
499         foreach(i, stmt->objects)
500         {
501                 char       *langname = strVal(lfirst(i));
502                 Relation        relation;
503                 HeapTuple       tuple;
504                 Form_pg_language pg_language_tuple;
505                 Datum           aclDatum;
506                 bool            isNull;
507                 Acl                *old_acl;
508                 Acl                *new_acl;
509                 HeapTuple       newtuple;
510                 Datum           values[Natts_pg_language];
511                 char            nulls[Natts_pg_language];
512                 char            replaces[Natts_pg_language];
513
514                 relation = heap_openr(LanguageRelationName, RowExclusiveLock);
515                 tuple = SearchSysCache(LANGNAME,
516                                                            PointerGetDatum(langname),
517                                                            0, 0, 0);
518                 if (!HeapTupleIsValid(tuple))
519                         ereport(ERROR,
520                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
521                                          errmsg("language \"%s\" does not exist", langname)));
522                 pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
523
524                 if (!pg_language_tuple->lanpltrusted && stmt->is_grant)
525                         ereport(ERROR,
526                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
527                                          errmsg("language \"%s\" is not trusted", langname)));
528
529                 if (stmt->is_grant
530                         && !superuser()
531                         && pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
532                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
533                                                    NameStr(pg_language_tuple->lanname));
534
535                 /*
536                  * If there's no ACL, create a default.
537                  */
538                 aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
539                                                                    &isNull);
540                 if (isNull)
541                         old_acl = acldefault(ACL_OBJECT_LANGUAGE,
542                                                                  InvalidOid);
543                 else
544                         /* get a detoasted copy of the ACL */
545                         old_acl = DatumGetAclPCopy(aclDatum);
546
547                 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
548                                                                            stmt->grantees, privileges,
549                                                                          stmt->grant_option, stmt->behavior);
550
551                 /* finished building new ACL value, now insert it */
552                 MemSet(values, 0, sizeof(values));
553                 MemSet(nulls, ' ', sizeof(nulls));
554                 MemSet(replaces, ' ', sizeof(replaces));
555
556                 replaces[Anum_pg_language_lanacl - 1] = 'r';
557                 values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
558
559                 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
560
561                 ReleaseSysCache(tuple);
562
563                 simple_heap_update(relation, &newtuple->t_self, newtuple);
564
565                 /* keep the catalog indexes up to date */
566                 CatalogUpdateIndexes(relation, newtuple);
567
568                 pfree(old_acl);
569                 pfree(new_acl);
570
571                 heap_close(relation, RowExclusiveLock);
572         }
573 }
574
575 static void
576 ExecuteGrantStmt_Namespace(GrantStmt *stmt)
577 {
578         AclMode         privileges;
579         List       *i;
580
581         if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
582                 privileges = ACL_ALL_RIGHTS_NAMESPACE;
583         else
584         {
585                 privileges = ACL_NO_RIGHTS;
586                 foreach(i, stmt->privileges)
587                 {
588                         AclMode         priv = lfirsti(i);
589
590                         if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
591                                 ereport(ERROR,
592                                                 (errcode(ERRCODE_INVALID_GRANT_OPERATION),
593                                                  errmsg("invalid privilege type %s for schema",
594                                                                 privilege_to_string(priv))));
595                         privileges |= priv;
596                 }
597         }
598
599         foreach(i, stmt->objects)
600         {
601                 char       *nspname = strVal(lfirst(i));
602                 Relation        relation;
603                 HeapTuple       tuple;
604                 Form_pg_namespace pg_namespace_tuple;
605                 Datum           aclDatum;
606                 bool            isNull;
607                 Acl                *old_acl;
608                 Acl                *new_acl;
609                 HeapTuple       newtuple;
610                 Datum           values[Natts_pg_namespace];
611                 char            nulls[Natts_pg_namespace];
612                 char            replaces[Natts_pg_namespace];
613
614                 relation = heap_openr(NamespaceRelationName, RowExclusiveLock);
615                 tuple = SearchSysCache(NAMESPACENAME,
616                                                            CStringGetDatum(nspname),
617                                                            0, 0, 0);
618                 if (!HeapTupleIsValid(tuple))
619                         ereport(ERROR,
620                                         (errcode(ERRCODE_UNDEFINED_SCHEMA),
621                                          errmsg("schema \"%s\" does not exist", nspname)));
622                 pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
623
624                 if (stmt->is_grant
625                  && !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())
626                         && pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
627                         aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
628                                                    nspname);
629
630                 /*
631                  * If there's no ACL, create a default using the
632                  * pg_namespace.nspowner field.
633                  */
634                 aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
635                                                                    Anum_pg_namespace_nspacl,
636                                                                    &isNull);
637                 if (isNull)
638                         old_acl = acldefault(ACL_OBJECT_NAMESPACE,
639                                                                  pg_namespace_tuple->nspowner);
640                 else
641                         /* get a detoasted copy of the ACL */
642                         old_acl = DatumGetAclPCopy(aclDatum);
643
644                 new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
645                                                                            stmt->grantees, privileges,
646                                                                          stmt->grant_option, stmt->behavior);
647
648                 /* finished building new ACL value, now insert it */
649                 MemSet(values, 0, sizeof(values));
650                 MemSet(nulls, ' ', sizeof(nulls));
651                 MemSet(replaces, ' ', sizeof(replaces));
652
653                 replaces[Anum_pg_namespace_nspacl - 1] = 'r';
654                 values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
655
656                 newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
657
658                 ReleaseSysCache(tuple);
659
660                 simple_heap_update(relation, &newtuple->t_self, newtuple);
661
662                 /* keep the catalog indexes up to date */
663                 CatalogUpdateIndexes(relation, newtuple);
664
665                 pfree(old_acl);
666                 pfree(new_acl);
667
668                 heap_close(relation, RowExclusiveLock);
669         }
670 }
671
672
673 static const char *
674 privilege_to_string(AclMode privilege)
675 {
676         switch (privilege)
677         {
678                 case ACL_INSERT:
679                         return "INSERT";
680                 case ACL_SELECT:
681                         return "SELECT";
682                 case ACL_UPDATE:
683                         return "UPDATE";
684                 case ACL_DELETE:
685                         return "DELETE";
686                 case ACL_RULE:
687                         return "RULE";
688                 case ACL_REFERENCES:
689                         return "REFERENCES";
690                 case ACL_TRIGGER:
691                         return "TRIGGER";
692                 case ACL_EXECUTE:
693                         return "EXECUTE";
694                 case ACL_USAGE:
695                         return "USAGE";
696                 case ACL_CREATE:
697                         return "CREATE";
698                 case ACL_CREATE_TEMP:
699                         return "TEMP";
700                 default:
701                         elog(ERROR, "unrecognized privilege: %d", (int) privilege);
702         }
703         return NULL;                            /* appease compiler */
704 }
705
706
707 AclId
708 get_grosysid(char *groname)
709 {
710         HeapTuple       tuple;
711         AclId           id = 0;
712
713         tuple = SearchSysCache(GRONAME,
714                                                    PointerGetDatum(groname),
715                                                    0, 0, 0);
716         if (HeapTupleIsValid(tuple))
717         {
718                 id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;
719                 ReleaseSysCache(tuple);
720         }
721         else
722                 ereport(ERROR,
723                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
724                                  errmsg("group \"%s\" does not exist", groname)));
725         return id;
726 }
727
728 /*
729  * Convert group ID to name, or return NULL if group can't be found
730  */
731 char *
732 get_groname(AclId grosysid)
733 {
734         HeapTuple       tuple;
735         char       *name = NULL;
736
737         tuple = SearchSysCache(GROSYSID,
738                                                    ObjectIdGetDatum(grosysid),
739                                                    0, 0, 0);
740         if (HeapTupleIsValid(tuple))
741         {
742                 name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));
743                 ReleaseSysCache(tuple);
744         }
745         return name;
746 }
747
748 /*
749  * Is user a member of group?
750  */
751 static bool
752 in_group(AclId uid, AclId gid)
753 {
754         bool            result = false;
755         HeapTuple       tuple;
756         Datum           att;
757         bool            isNull;
758         IdList     *glist;
759         AclId      *aidp;
760         int                     i,
761                                 num;
762
763         tuple = SearchSysCache(GROSYSID,
764                                                    ObjectIdGetDatum(gid),
765                                                    0, 0, 0);
766         if (HeapTupleIsValid(tuple))
767         {
768                 att = SysCacheGetAttr(GROSYSID,
769                                                           tuple,
770                                                           Anum_pg_group_grolist,
771                                                           &isNull);
772                 if (!isNull)
773                 {
774                         /* be sure the IdList is not toasted */
775                         glist = DatumGetIdListP(att);
776                         /* scan it */
777                         num = IDLIST_NUM(glist);
778                         aidp = IDLIST_DAT(glist);
779                         for (i = 0; i < num; ++i)
780                         {
781                                 if (aidp[i] == uid)
782                                 {
783                                         result = true;
784                                         break;
785                                 }
786                         }
787                         /* if IdList was toasted, free detoasted copy */
788                         if ((Pointer) glist != DatumGetPointer(att))
789                                 pfree(glist);
790                 }
791                 ReleaseSysCache(tuple);
792         }
793         else
794                 ereport(WARNING,
795                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
796                                  errmsg("group with ID %u does not exist", gid)));
797         return result;
798 }
799
800
801 /*
802  * aclcheck
803  *
804  * Returns ACLCHECK_OK if the 'userid' has ACL entries in 'acl' to
805  * satisfy any one of the requirements of 'mode'.  Returns an
806  * appropriate ACLCHECK_* error code otherwise.
807  */
808 static AclResult
809 aclcheck(Acl *acl, AclId userid, AclMode mode)
810 {
811         AclItem    *aidat;
812         int                     i,
813                                 num;
814
815         /*
816          * Null ACL should not happen, since caller should have inserted
817          * appropriate default
818          */
819         if (acl == NULL)
820         {
821                 elog(ERROR, "null ACL");
822                 return ACLCHECK_NO_PRIV;
823         }
824
825         num = ACL_NUM(acl);
826         aidat = ACL_DAT(acl);
827
828         /*
829          * See if privilege is granted directly to user or to public
830          */
831         for (i = 0; i < num; i++)
832                 if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_WORLD
833                         || (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_UID
834                                 && aidat[i].ai_grantee == userid))
835                 {
836                         if (aidat[i].ai_privs & mode)
837                                 return ACLCHECK_OK;
838                 }
839
840         /*
841          * See if he has the permission via any group (do this in a separate
842          * pass to avoid expensive(?) lookups in pg_group)
843          */
844         for (i = 0; i < num; i++)
845                 if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID
846                         && aidat[i].ai_privs & mode
847                         && in_group(userid, aidat[i].ai_grantee))
848                         return ACLCHECK_OK;
849
850         /* If here, doesn't have the privilege. */
851         return ACLCHECK_NO_PRIV;
852 }
853
854
855 /*
856  * Standardized reporting of aclcheck permissions failures.
857  *
858  * Note: we do not double-quote the %s's below, because many callers
859  * supply strings that might be already quoted.
860  */
861
862 static const char *const no_priv_msg[MAX_ACL_KIND] =
863 {
864         /* ACL_KIND_CLASS */
865         gettext_noop("permission denied for relation %s"),
866         /* ACL_KIND_DATABASE */
867         gettext_noop("permission denied for database %s"),
868         /* ACL_KIND_PROC */
869         gettext_noop("permission denied for function %s"),
870         /* ACL_KIND_OPER */
871         gettext_noop("permission denied for operator %s"),
872         /* ACL_KIND_TYPE */
873         gettext_noop("permission denied for type %s"),
874         /* ACL_KIND_LANGUAGE */
875         gettext_noop("permission denied for language %s"),
876         /* ACL_KIND_NAMESPACE */
877         gettext_noop("permission denied for schema %s"),
878         /* ACL_KIND_OPCLASS */
879         gettext_noop("permission denied for operator class %s"),
880         /* ACL_KIND_CONVERSION */
881         gettext_noop("permission denied for conversion %s")
882 };
883
884 static const char *const not_owner_msg[MAX_ACL_KIND] =
885 {
886         /* ACL_KIND_CLASS */
887         gettext_noop("must be owner of relation %s"),
888         /* ACL_KIND_DATABASE */
889         gettext_noop("must be owner of database %s"),
890         /* ACL_KIND_PROC */
891         gettext_noop("must be owner of function %s"),
892         /* ACL_KIND_OPER */
893         gettext_noop("must be owner of operator %s"),
894         /* ACL_KIND_TYPE */
895         gettext_noop("must be owner of type %s"),
896         /* ACL_KIND_LANGUAGE */
897         gettext_noop("must be owner of language %s"),
898         /* ACL_KIND_NAMESPACE */
899         gettext_noop("must be owner of schema %s"),
900         /* ACL_KIND_OPCLASS */
901         gettext_noop("must be owner of operator class %s"),
902         /* ACL_KIND_CONVERSION */
903         gettext_noop("must be owner of conversion %s")
904 };
905
906
907 void
908 aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
909                            const char *objectname)
910 {
911         switch (aclerr)
912         {
913                 case ACLCHECK_OK:
914                         /* no error, so return to caller */
915                         break;
916                 case ACLCHECK_NO_PRIV:
917                         ereport(ERROR,
918                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
919                                          errmsg(no_priv_msg[objectkind], objectname)));
920                         break;
921                 case ACLCHECK_NOT_OWNER:
922                         ereport(ERROR,
923                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
924                                          errmsg(not_owner_msg[objectkind], objectname)));
925                         break;
926                 default:
927                         elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
928                         break;
929         }
930 }
931
932
933 /*
934  * Exported routine for checking a user's access privileges to a table
935  *
936  * Note: we give lookup failure the full ereport treatment because the
937  * has_table_privilege() family of functions allow users to pass
938  * any random OID to this function.  Likewise for the sibling functions
939  * below.
940  */
941 AclResult
942 pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
943 {
944         AclResult       result;
945         bool            usesuper,
946                                 usecatupd;
947         HeapTuple       tuple;
948         Datum           aclDatum;
949         bool            isNull;
950         Acl                *acl;
951
952         /*
953          * Validate userid, find out if he is superuser, also get usecatupd
954          */
955         tuple = SearchSysCache(SHADOWSYSID,
956                                                    ObjectIdGetDatum(userid),
957                                                    0, 0, 0);
958         if (!HeapTupleIsValid(tuple))
959                 ereport(ERROR,
960                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
961                                  errmsg("user with ID %u does not exist", userid)));
962
963         usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd;
964
965         ReleaseSysCache(tuple);
966
967         usesuper = superuser_arg(userid);
968
969         /*
970          * Now get the relation's tuple from pg_class
971          */
972         tuple = SearchSysCache(RELOID,
973                                                    ObjectIdGetDatum(table_oid),
974                                                    0, 0, 0);
975         if (!HeapTupleIsValid(tuple))
976                 ereport(ERROR,
977                                 (errcode(ERRCODE_UNDEFINED_TABLE),
978                           errmsg("relation with OID %u does not exist", table_oid)));
979
980         /*
981          * Deny anyone permission to update a system catalog unless
982          * pg_shadow.usecatupd is set.  (This is to let superusers protect
983          * themselves from themselves.)
984          */
985         if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
986                 !allowSystemTableMods &&
987                 IsSystemClass((Form_pg_class) GETSTRUCT(tuple)) &&
988                 !usecatupd)
989         {
990 #ifdef ACLDEBUG
991                 elog(DEBUG2, "permission denied for system catalog update");
992 #endif
993                 ReleaseSysCache(tuple);
994                 return ACLCHECK_NO_PRIV;
995         }
996
997         /*
998          * Otherwise, superusers bypass all permission-checking.
999          */
1000         if (usesuper)
1001         {
1002 #ifdef ACLDEBUG
1003                 elog(DEBUG2, "%u is superuser, home free", userid);
1004 #endif
1005                 ReleaseSysCache(tuple);
1006                 return ACLCHECK_OK;
1007         }
1008
1009         /*
1010          * Normal case: get the relation's ACL from pg_class
1011          */
1012         aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
1013                                                            &isNull);
1014         if (isNull)
1015         {
1016                 /* No ACL, so build default ACL for rel */
1017                 AclId           ownerId;
1018
1019                 ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
1020                 acl = acldefault(ACL_OBJECT_RELATION, ownerId);
1021                 aclDatum = (Datum) 0;
1022         }
1023         else
1024         {
1025                 /* detoast rel's ACL if necessary */
1026                 acl = DatumGetAclP(aclDatum);
1027         }
1028
1029         result = aclcheck(acl, userid, mode);
1030
1031         /* if we have a detoasted copy, free it */
1032         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1033                 pfree(acl);
1034
1035         ReleaseSysCache(tuple);
1036
1037         return result;
1038 }
1039
1040 /*
1041  * Exported routine for checking a user's access privileges to a database
1042  */
1043 AclResult
1044 pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode)
1045 {
1046         AclResult       result;
1047         Relation        pg_database;
1048         ScanKeyData entry[1];
1049         HeapScanDesc scan;
1050         HeapTuple       tuple;
1051         Datum           aclDatum;
1052         bool            isNull;
1053         Acl                *acl;
1054
1055         /* Superusers bypass all permission checking. */
1056         if (superuser_arg(userid))
1057                 return ACLCHECK_OK;
1058
1059         /*
1060          * Get the database's ACL from pg_database
1061          *
1062          * There's no syscache for pg_database, so must look the hard way
1063          */
1064         pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1065         ScanKeyEntryInitialize(&entry[0], 0x0,
1066                                                    ObjectIdAttributeNumber, F_OIDEQ,
1067                                                    ObjectIdGetDatum(db_oid));
1068         scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
1069         tuple = heap_getnext(scan, ForwardScanDirection);
1070         if (!HeapTupleIsValid(tuple))
1071                 ereport(ERROR,
1072                                 (errcode(ERRCODE_UNDEFINED_DATABASE),
1073                                  errmsg("database with OID %u does not exist", db_oid)));
1074
1075         aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
1076                                                         RelationGetDescr(pg_database), &isNull);
1077
1078         if (isNull)
1079         {
1080                 /* No ACL, so build default ACL */
1081                 AclId           ownerId;
1082
1083                 ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
1084                 acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
1085                 aclDatum = (Datum) 0;
1086         }
1087         else
1088         {
1089                 /* detoast ACL if necessary */
1090                 acl = DatumGetAclP(aclDatum);
1091         }
1092
1093         result = aclcheck(acl, userid, mode);
1094
1095         /* if we have a detoasted copy, free it */
1096         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1097                 pfree(acl);
1098
1099         heap_endscan(scan);
1100         heap_close(pg_database, AccessShareLock);
1101
1102         return result;
1103 }
1104
1105 /*
1106  * Exported routine for checking a user's access privileges to a function
1107  */
1108 AclResult
1109 pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
1110 {
1111         AclResult       result;
1112         HeapTuple       tuple;
1113         Datum           aclDatum;
1114         bool            isNull;
1115         Acl                *acl;
1116
1117         /* Superusers bypass all permission checking. */
1118         if (superuser_arg(userid))
1119                 return ACLCHECK_OK;
1120
1121         /*
1122          * Get the function's ACL from pg_proc
1123          */
1124         tuple = SearchSysCache(PROCOID,
1125                                                    ObjectIdGetDatum(proc_oid),
1126                                                    0, 0, 0);
1127         if (!HeapTupleIsValid(tuple))
1128                 ereport(ERROR,
1129                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1130                            errmsg("function with OID %u does not exist", proc_oid)));
1131
1132         aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
1133                                                            &isNull);
1134         if (isNull)
1135         {
1136                 /* No ACL, so build default ACL */
1137                 AclId           ownerId;
1138
1139                 ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1140                 acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
1141                 aclDatum = (Datum) 0;
1142         }
1143         else
1144         {
1145                 /* detoast ACL if necessary */
1146                 acl = DatumGetAclP(aclDatum);
1147         }
1148
1149         result = aclcheck(acl, userid, mode);
1150
1151         /* if we have a detoasted copy, free it */
1152         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1153                 pfree(acl);
1154
1155         ReleaseSysCache(tuple);
1156
1157         return result;
1158 }
1159
1160 /*
1161  * Exported routine for checking a user's access privileges to a language
1162  */
1163 AclResult
1164 pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
1165 {
1166         AclResult       result;
1167         HeapTuple       tuple;
1168         Datum           aclDatum;
1169         bool            isNull;
1170         Acl                *acl;
1171
1172         /* Superusers bypass all permission checking. */
1173         if (superuser_arg(userid))
1174                 return ACLCHECK_OK;
1175
1176         /*
1177          * Get the language's ACL from pg_language
1178          */
1179         tuple = SearchSysCache(LANGOID,
1180                                                    ObjectIdGetDatum(lang_oid),
1181                                                    0, 0, 0);
1182         if (!HeapTupleIsValid(tuple))
1183                 ereport(ERROR,
1184                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1185                            errmsg("language with OID %u does not exist", lang_oid)));
1186
1187         aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
1188                                                            &isNull);
1189         if (isNull)
1190         {
1191                 /* No ACL, so build default ACL */
1192                 acl = acldefault(ACL_OBJECT_LANGUAGE, InvalidOid);
1193                 aclDatum = (Datum) 0;
1194         }
1195         else
1196         {
1197                 /* detoast ACL if necessary */
1198                 acl = DatumGetAclP(aclDatum);
1199         }
1200
1201         result = aclcheck(acl, userid, mode);
1202
1203         /* if we have a detoasted copy, free it */
1204         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1205                 pfree(acl);
1206
1207         ReleaseSysCache(tuple);
1208
1209         return result;
1210 }
1211
1212 /*
1213  * Exported routine for checking a user's access privileges to a namespace
1214  */
1215 AclResult
1216 pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
1217 {
1218         AclResult       result;
1219         HeapTuple       tuple;
1220         Datum           aclDatum;
1221         bool            isNull;
1222         Acl                *acl;
1223
1224         /*
1225          * If we have been assigned this namespace as a temp namespace, assume
1226          * we have all grantable privileges on it.
1227          */
1228         if (isTempNamespace(nsp_oid))
1229                 return ACLCHECK_OK;
1230
1231         /* Superusers bypass all permission checking. */
1232         if (superuser_arg(userid))
1233                 return ACLCHECK_OK;
1234
1235         /*
1236          * Get the schema's ACL from pg_namespace
1237          */
1238         tuple = SearchSysCache(NAMESPACEOID,
1239                                                    ObjectIdGetDatum(nsp_oid),
1240                                                    0, 0, 0);
1241         if (!HeapTupleIsValid(tuple))
1242                 ereport(ERROR,
1243                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1244                                  errmsg("schema with OID %u does not exist", nsp_oid)));
1245
1246         aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
1247                                                            &isNull);
1248         if (isNull)
1249         {
1250                 /* No ACL, so build default ACL */
1251                 AclId           ownerId;
1252
1253                 ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1254                 acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
1255                 aclDatum = (Datum) 0;
1256         }
1257         else
1258         {
1259                 /* detoast ACL if necessary */
1260                 acl = DatumGetAclP(aclDatum);
1261         }
1262
1263         result = aclcheck(acl, userid, mode);
1264
1265         /* if we have a detoasted copy, free it */
1266         if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
1267                 pfree(acl);
1268
1269         ReleaseSysCache(tuple);
1270
1271         return result;
1272 }
1273
1274
1275 /*
1276  * Ownership check for a relation (specified by OID).
1277  */
1278 bool
1279 pg_class_ownercheck(Oid class_oid, AclId userid)
1280 {
1281         HeapTuple       tuple;
1282         AclId           owner_id;
1283
1284         /* Superusers bypass all permission checking. */
1285         if (superuser_arg(userid))
1286                 return true;
1287
1288         tuple = SearchSysCache(RELOID,
1289                                                    ObjectIdGetDatum(class_oid),
1290                                                    0, 0, 0);
1291         if (!HeapTupleIsValid(tuple))
1292                 ereport(ERROR,
1293                                 (errcode(ERRCODE_UNDEFINED_TABLE),
1294                           errmsg("relation with OID %u does not exist", class_oid)));
1295
1296         owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
1297
1298         ReleaseSysCache(tuple);
1299
1300         return userid == owner_id;
1301 }
1302
1303 /*
1304  * Ownership check for a type (specified by OID).
1305  */
1306 bool
1307 pg_type_ownercheck(Oid type_oid, AclId userid)
1308 {
1309         HeapTuple       tuple;
1310         AclId           owner_id;
1311
1312         /* Superusers bypass all permission checking. */
1313         if (superuser_arg(userid))
1314                 return true;
1315
1316         tuple = SearchSysCache(TYPEOID,
1317                                                    ObjectIdGetDatum(type_oid),
1318                                                    0, 0, 0);
1319         if (!HeapTupleIsValid(tuple))
1320                 ereport(ERROR,
1321                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1322                                  errmsg("type with OID %u does not exist", type_oid)));
1323
1324         owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
1325
1326         ReleaseSysCache(tuple);
1327
1328         return userid == owner_id;
1329 }
1330
1331 /*
1332  * Ownership check for an operator (specified by OID).
1333  */
1334 bool
1335 pg_oper_ownercheck(Oid oper_oid, AclId userid)
1336 {
1337         HeapTuple       tuple;
1338         AclId           owner_id;
1339
1340         /* Superusers bypass all permission checking. */
1341         if (superuser_arg(userid))
1342                 return true;
1343
1344         tuple = SearchSysCache(OPEROID,
1345                                                    ObjectIdGetDatum(oper_oid),
1346                                                    0, 0, 0);
1347         if (!HeapTupleIsValid(tuple))
1348                 ereport(ERROR,
1349                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1350                            errmsg("operator with OID %u does not exist", oper_oid)));
1351
1352         owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
1353
1354         ReleaseSysCache(tuple);
1355
1356         return userid == owner_id;
1357 }
1358
1359 /*
1360  * Ownership check for a function (specified by OID).
1361  */
1362 bool
1363 pg_proc_ownercheck(Oid proc_oid, AclId userid)
1364 {
1365         HeapTuple       tuple;
1366         AclId           owner_id;
1367
1368         /* Superusers bypass all permission checking. */
1369         if (superuser_arg(userid))
1370                 return true;
1371
1372         tuple = SearchSysCache(PROCOID,
1373                                                    ObjectIdGetDatum(proc_oid),
1374                                                    0, 0, 0);
1375         if (!HeapTupleIsValid(tuple))
1376                 ereport(ERROR,
1377                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
1378                            errmsg("function with OID %u does not exist", proc_oid)));
1379
1380         owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
1381
1382         ReleaseSysCache(tuple);
1383
1384         return userid == owner_id;
1385 }
1386
1387 /*
1388  * Ownership check for a namespace (specified by OID).
1389  */
1390 bool
1391 pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
1392 {
1393         HeapTuple       tuple;
1394         AclId           owner_id;
1395
1396         /* Superusers bypass all permission checking. */
1397         if (superuser_arg(userid))
1398                 return true;
1399
1400         tuple = SearchSysCache(NAMESPACEOID,
1401                                                    ObjectIdGetDatum(nsp_oid),
1402                                                    0, 0, 0);
1403         if (!HeapTupleIsValid(tuple))
1404                 ereport(ERROR,
1405                                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1406                                  errmsg("schema with OID %u does not exist", nsp_oid)));
1407
1408         owner_id = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
1409
1410         ReleaseSysCache(tuple);
1411
1412         return userid == owner_id;
1413 }
1414
1415 /*
1416  * Ownership check for an operator class (specified by OID).
1417  */
1418 bool
1419 pg_opclass_ownercheck(Oid opc_oid, AclId userid)
1420 {
1421         HeapTuple       tuple;
1422         AclId           owner_id;
1423
1424         /* Superusers bypass all permission checking. */
1425         if (superuser_arg(userid))
1426                 return true;
1427
1428         tuple = SearchSysCache(CLAOID,
1429                                                    ObjectIdGetDatum(opc_oid),
1430                                                    0, 0, 0);
1431         if (!HeapTupleIsValid(tuple))
1432                 ereport(ERROR,
1433                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1434                                  errmsg("operator class with OID %u does not exist",
1435                                                 opc_oid)));
1436
1437         owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
1438
1439         ReleaseSysCache(tuple);
1440
1441         return userid == owner_id;
1442 }
1443
1444
1445 /*
1446  * Ownership check for database (specified as OID)
1447  */
1448 bool
1449 pg_database_ownercheck(Oid db_oid, AclId userid)
1450 {
1451         Relation        pg_database;
1452         ScanKeyData entry[1];
1453         HeapScanDesc scan;
1454         HeapTuple       dbtuple;
1455         int32           dba;
1456
1457         /* Superusers bypass all permission checking. */
1458         if (superuser_arg(userid))
1459                 return true;
1460
1461         /* There's no syscache for pg_database, so must look the hard way */
1462         pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
1463         ScanKeyEntryInitialize(&entry[0], 0x0,
1464                                                    ObjectIdAttributeNumber, F_OIDEQ,
1465                                                    ObjectIdGetDatum(db_oid));
1466         scan = heap_beginscan(pg_database, SnapshotNow, 1, entry);
1467
1468         dbtuple = heap_getnext(scan, ForwardScanDirection);
1469
1470         if (!HeapTupleIsValid(dbtuple))
1471                 ereport(ERROR,
1472                                 (errcode(ERRCODE_UNDEFINED_DATABASE),
1473                                  errmsg("database with OID %u does not exist", db_oid)));
1474
1475         dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
1476
1477         heap_endscan(scan);
1478         heap_close(pg_database, AccessShareLock);
1479
1480         return userid == dba;
1481 }