~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/catalog/aclchk.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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