~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

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-2011, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        src/backend/catalog/aclchk.c
 
12
 *
 
13
 * NOTES
 
14
 *        See acl.h.
 
15
 *
 
16
 *-------------------------------------------------------------------------
 
17
 */
 
18
#include "postgres.h"
 
19
 
 
20
#include "access/genam.h"
 
21
#include "access/heapam.h"
 
22
#include "access/sysattr.h"
 
23
#include "access/xact.h"
 
24
#include "catalog/catalog.h"
 
25
#include "catalog/dependency.h"
 
26
#include "catalog/indexing.h"
 
27
#include "catalog/pg_authid.h"
 
28
#include "catalog/pg_collation.h"
 
29
#include "catalog/pg_conversion.h"
 
30
#include "catalog/pg_database.h"
 
31
#include "catalog/pg_default_acl.h"
 
32
#include "catalog/pg_extension.h"
 
33
#include "catalog/pg_foreign_data_wrapper.h"
 
34
#include "catalog/pg_foreign_server.h"
 
35
#include "catalog/pg_language.h"
 
36
#include "catalog/pg_largeobject.h"
 
37
#include "catalog/pg_largeobject_metadata.h"
 
38
#include "catalog/pg_namespace.h"
 
39
#include "catalog/pg_opclass.h"
 
40
#include "catalog/pg_operator.h"
 
41
#include "catalog/pg_opfamily.h"
 
42
#include "catalog/pg_proc.h"
 
43
#include "catalog/pg_tablespace.h"
 
44
#include "catalog/pg_type.h"
 
45
#include "catalog/pg_ts_config.h"
 
46
#include "catalog/pg_ts_dict.h"
 
47
#include "commands/dbcommands.h"
 
48
#include "commands/proclang.h"
 
49
#include "commands/tablespace.h"
 
50
#include "foreign/foreign.h"
 
51
#include "miscadmin.h"
 
52
#include "parser/parse_func.h"
 
53
#include "utils/acl.h"
 
54
#include "utils/builtins.h"
 
55
#include "utils/fmgroids.h"
 
56
#include "utils/lsyscache.h"
 
57
#include "utils/rel.h"
 
58
#include "utils/syscache.h"
 
59
#include "utils/tqual.h"
 
60
 
 
61
 
 
62
/*
 
63
 * The information about one Grant/Revoke statement, in internal format: object
 
64
 * and grantees names have been turned into Oids, the privilege list is an
 
65
 * AclMode bitmask.  If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
 
66
 * all_privs is true, 'privileges' will be internally set to the right kind of
 
67
 * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
 
68
 * InternalGrant struct!)
 
69
 *
 
70
 * Note: 'all_privs' and 'privileges' represent object-level privileges only.
 
71
 * There might also be column-level privilege specifications, which are
 
72
 * represented in col_privs (this is a list of untransformed AccessPriv nodes).
 
73
 * Column privileges are only valid for objtype ACL_OBJECT_RELATION.
 
74
 */
 
75
typedef struct
 
76
{
 
77
        bool            is_grant;
 
78
        GrantObjectType objtype;
 
79
        List       *objects;
 
80
        bool            all_privs;
 
81
        AclMode         privileges;
 
82
        List       *col_privs;
 
83
        List       *grantees;
 
84
        bool            grant_option;
 
85
        DropBehavior behavior;
 
86
} InternalGrant;
 
87
 
 
88
/*
 
89
 * Internal format used by ALTER DEFAULT PRIVILEGES.
 
90
 */
 
91
typedef struct
 
92
{
 
93
        Oid                     roleid;                 /* owning role */
 
94
        Oid                     nspid;                  /* namespace, or InvalidOid if none */
 
95
        /* remaining fields are same as in InternalGrant: */
 
96
        bool            is_grant;
 
97
        GrantObjectType objtype;
 
98
        bool            all_privs;
 
99
        AclMode         privileges;
 
100
        List       *grantees;
 
101
        bool            grant_option;
 
102
        DropBehavior behavior;
 
103
} InternalDefaultACL;
 
104
 
 
105
 
 
106
static void ExecGrantStmt_oids(InternalGrant *istmt);
 
107
static void ExecGrant_Relation(InternalGrant *grantStmt);
 
108
static void ExecGrant_Database(InternalGrant *grantStmt);
 
109
static void ExecGrant_Fdw(InternalGrant *grantStmt);
 
110
static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
 
111
static void ExecGrant_Function(InternalGrant *grantStmt);
 
112
static void ExecGrant_Language(InternalGrant *grantStmt);
 
113
static void ExecGrant_Largeobject(InternalGrant *grantStmt);
 
114
static void ExecGrant_Namespace(InternalGrant *grantStmt);
 
115
static void ExecGrant_Tablespace(InternalGrant *grantStmt);
 
116
 
 
117
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
 
118
static void SetDefaultACL(InternalDefaultACL *iacls);
 
119
 
 
120
static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
 
121
static List *objectsInSchemaToOids(GrantObjectType objtype, List *nspnames);
 
122
static List *getRelationsInNamespace(Oid namespaceId, char relkind);
 
123
static void expand_col_privileges(List *colnames, Oid table_oid,
 
124
                                          AclMode this_privileges,
 
125
                                          AclMode *col_privileges,
 
126
                                          int num_col_privileges);
 
127
static void expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
 
128
                                                  AclMode this_privileges,
 
129
                                                  AclMode *col_privileges,
 
130
                                                  int num_col_privileges);
 
131
static AclMode string_to_privilege(const char *privname);
 
132
static const char *privilege_to_string(AclMode privilege);
 
133
static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
 
134
                                                 bool all_privs, AclMode privileges,
 
135
                                                 Oid objectId, Oid grantorId,
 
136
                                                 AclObjectKind objkind, const char *objname,
 
137
                                                 AttrNumber att_number, const char *colname);
 
138
static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum,
 
139
                   Oid roleid, AclMode mask, AclMaskHow how);
 
140
 
 
141
 
 
142
#ifdef ACLDEBUG
 
143
static void
 
144
dumpacl(Acl *acl)
 
145
{
 
146
        int                     i;
 
147
        AclItem    *aip;
 
148
 
 
149
        elog(DEBUG2, "acl size = %d, # acls = %d",
 
150
                 ACL_SIZE(acl), ACL_NUM(acl));
 
151
        aip = ACL_DAT(acl);
 
152
        for (i = 0; i < ACL_NUM(acl); ++i)
 
153
                elog(DEBUG2, "  acl[%d]: %s", i,
 
154
                         DatumGetCString(DirectFunctionCall1(aclitemout,
 
155
                                                                                                 PointerGetDatum(aip + i))));
 
156
}
 
157
#endif   /* ACLDEBUG */
 
158
 
 
159
 
 
160
/*
 
161
 * If is_grant is true, adds the given privileges for the list of
 
162
 * grantees to the existing old_acl.  If is_grant is false, the
 
163
 * privileges for the given grantees are removed from old_acl.
 
164
 *
 
165
 * NB: the original old_acl is pfree'd.
 
166
 */
 
167
static Acl *
 
168
merge_acl_with_grant(Acl *old_acl, bool is_grant,
 
169
                                         bool grant_option, DropBehavior behavior,
 
170
                                         List *grantees, AclMode privileges,
 
171
                                         Oid grantorId, Oid ownerId)
 
172
{
 
173
        unsigned        modechg;
 
174
        ListCell   *j;
 
175
        Acl                *new_acl;
 
176
 
 
177
        modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
 
178
 
 
179
#ifdef ACLDEBUG
 
180
        dumpacl(old_acl);
 
181
#endif
 
182
        new_acl = old_acl;
 
183
 
 
184
        foreach(j, grantees)
 
185
        {
 
186
                AclItem aclitem;
 
187
                Acl                *newer_acl;
 
188
 
 
189
                aclitem.        ai_grantee = lfirst_oid(j);
 
190
 
 
191
                /*
 
192
                 * Grant options can only be granted to individual roles, not PUBLIC.
 
193
                 * The reason is that if a user would re-grant a privilege that he
 
194
                 * held through PUBLIC, and later the user is removed, the situation
 
195
                 * is impossible to clean up.
 
196
                 */
 
197
                if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)
 
198
                        ereport(ERROR,
 
199
                                        (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
200
                                         errmsg("grant options can only be granted to roles")));
 
201
 
 
202
                aclitem.        ai_grantor = grantorId;
 
203
 
 
204
                /*
 
205
                 * The asymmetry in the conditions here comes from the spec.  In
 
206
                 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
 
207
                 * to grant both the basic privilege and its grant option. But in
 
208
                 * REVOKE, plain revoke revokes both the basic privilege and its grant
 
209
                 * option, while REVOKE GRANT OPTION revokes only the option.
 
210
                 */
 
211
                ACLITEM_SET_PRIVS_GOPTIONS(aclitem,
 
212
                                        (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
 
213
                                   (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);
 
214
 
 
215
                newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, behavior);
 
216
 
 
217
                /* avoid memory leak when there are many grantees */
 
218
                pfree(new_acl);
 
219
                new_acl = newer_acl;
 
220
 
 
221
#ifdef ACLDEBUG
 
222
                dumpacl(new_acl);
 
223
#endif
 
224
        }
 
225
 
 
226
        return new_acl;
 
227
}
 
228
 
 
229
/*
 
230
 * Restrict the privileges to what we can actually grant, and emit
 
231
 * the standards-mandated warning and error messages.
 
232
 */
 
233
static AclMode
 
234
restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
 
235
                                                 AclMode privileges, Oid objectId, Oid grantorId,
 
236
                                                 AclObjectKind objkind, const char *objname,
 
237
                                                 AttrNumber att_number, const char *colname)
 
238
{
 
239
        AclMode         this_privileges;
 
240
        AclMode         whole_mask;
 
241
 
 
242
        switch (objkind)
 
243
        {
 
244
                case ACL_KIND_COLUMN:
 
245
                        whole_mask = ACL_ALL_RIGHTS_COLUMN;
 
246
                        break;
 
247
                case ACL_KIND_CLASS:
 
248
                        whole_mask = ACL_ALL_RIGHTS_RELATION;
 
249
                        break;
 
250
                case ACL_KIND_SEQUENCE:
 
251
                        whole_mask = ACL_ALL_RIGHTS_SEQUENCE;
 
252
                        break;
 
253
                case ACL_KIND_DATABASE:
 
254
                        whole_mask = ACL_ALL_RIGHTS_DATABASE;
 
255
                        break;
 
256
                case ACL_KIND_PROC:
 
257
                        whole_mask = ACL_ALL_RIGHTS_FUNCTION;
 
258
                        break;
 
259
                case ACL_KIND_LANGUAGE:
 
260
                        whole_mask = ACL_ALL_RIGHTS_LANGUAGE;
 
261
                        break;
 
262
                case ACL_KIND_LARGEOBJECT:
 
263
                        whole_mask = ACL_ALL_RIGHTS_LARGEOBJECT;
 
264
                        break;
 
265
                case ACL_KIND_NAMESPACE:
 
266
                        whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
 
267
                        break;
 
268
                case ACL_KIND_TABLESPACE:
 
269
                        whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
 
270
                        break;
 
271
                case ACL_KIND_FDW:
 
272
                        whole_mask = ACL_ALL_RIGHTS_FDW;
 
273
                        break;
 
274
                case ACL_KIND_FOREIGN_SERVER:
 
275
                        whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 
276
                        break;
 
277
                default:
 
278
                        elog(ERROR, "unrecognized object kind: %d", objkind);
 
279
                        /* not reached, but keep compiler quiet */
 
280
                        return ACL_NO_RIGHTS;
 
281
        }
 
282
 
 
283
        /*
 
284
         * If we found no grant options, consider whether to issue a hard error.
 
285
         * Per spec, having any privilege at all on the object will get you by
 
286
         * here.
 
287
         */
 
288
        if (avail_goptions == ACL_NO_RIGHTS)
 
289
        {
 
290
                if (pg_aclmask(objkind, objectId, att_number, grantorId,
 
291
                                           whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
 
292
                                           ACLMASK_ANY) == ACL_NO_RIGHTS)
 
293
                {
 
294
                        if (objkind == ACL_KIND_COLUMN && colname)
 
295
                                aclcheck_error_col(ACLCHECK_NO_PRIV, objkind, objname, colname);
 
296
                        else
 
297
                                aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
 
298
                }
 
299
        }
 
300
 
 
301
        /*
 
302
         * Restrict the operation to what we can actually grant or revoke, and
 
303
         * issue a warning if appropriate.      (For REVOKE this isn't quite what the
 
304
         * spec says to do: the spec seems to want a warning only if no privilege
 
305
         * bits actually change in the ACL. In practice that behavior seems much
 
306
         * too noisy, as well as inconsistent with the GRANT case.)
 
307
         */
 
308
        this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
 
309
        if (is_grant)
 
310
        {
 
311
                if (this_privileges == 0)
 
312
                {
 
313
                        if (objkind == ACL_KIND_COLUMN && colname)
 
314
                                ereport(WARNING,
 
315
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
 
316
                                                 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
 
317
                                                                colname, objname)));
 
318
                        else
 
319
                                ereport(WARNING,
 
320
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
 
321
                                                 errmsg("no privileges were granted for \"%s\"",
 
322
                                                                objname)));
 
323
                }
 
324
                else if (!all_privs && this_privileges != privileges)
 
325
                {
 
326
                        if (objkind == ACL_KIND_COLUMN && colname)
 
327
                                ereport(WARNING,
 
328
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
 
329
                                                 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
 
330
                                                                colname, objname)));
 
331
                        else
 
332
                                ereport(WARNING,
 
333
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
 
334
                                                 errmsg("not all privileges were granted for \"%s\"",
 
335
                                                                objname)));
 
336
                }
 
337
        }
 
338
        else
 
339
        {
 
340
                if (this_privileges == 0)
 
341
                {
 
342
                        if (objkind == ACL_KIND_COLUMN && colname)
 
343
                                ereport(WARNING,
 
344
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
 
345
                                                 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
 
346
                                                                colname, objname)));
 
347
                        else
 
348
                                ereport(WARNING,
 
349
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
 
350
                                                 errmsg("no privileges could be revoked for \"%s\"",
 
351
                                                                objname)));
 
352
                }
 
353
                else if (!all_privs && this_privileges != privileges)
 
354
                {
 
355
                        if (objkind == ACL_KIND_COLUMN && colname)
 
356
                                ereport(WARNING,
 
357
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
 
358
                                                 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
 
359
                                                                colname, objname)));
 
360
                        else
 
361
                                ereport(WARNING,
 
362
                                                (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
 
363
                                         errmsg("not all privileges could be revoked for \"%s\"",
 
364
                                                        objname)));
 
365
                }
 
366
        }
 
367
 
 
368
        return this_privileges;
 
369
}
 
370
 
 
371
/*
 
372
 * Called to execute the utility commands GRANT and REVOKE
 
373
 */
 
374
void
 
375
ExecuteGrantStmt(GrantStmt *stmt)
 
376
{
 
377
        InternalGrant istmt;
 
378
        ListCell   *cell;
 
379
        const char *errormsg;
 
380
        AclMode         all_privileges;
 
381
 
 
382
        /*
 
383
         * Turn the regular GrantStmt into the InternalGrant form.
 
384
         */
 
385
        istmt.is_grant = stmt->is_grant;
 
386
        istmt.objtype = stmt->objtype;
 
387
 
 
388
        /* Collect the OIDs of the target objects */
 
389
        switch (stmt->targtype)
 
390
        {
 
391
                case ACL_TARGET_OBJECT:
 
392
                        istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
 
393
                        break;
 
394
                case ACL_TARGET_ALL_IN_SCHEMA:
 
395
                        istmt.objects = objectsInSchemaToOids(stmt->objtype, stmt->objects);
 
396
                        break;
 
397
                        /* ACL_TARGET_DEFAULTS should not be seen here */
 
398
                default:
 
399
                        elog(ERROR, "unrecognized GrantStmt.targtype: %d",
 
400
                                 (int) stmt->targtype);
 
401
        }
 
402
 
 
403
        /* all_privs to be filled below */
 
404
        /* privileges to be filled below */
 
405
        istmt.col_privs = NIL;          /* may get filled below */
 
406
        istmt.grantees = NIL;           /* filled below */
 
407
        istmt.grant_option = stmt->grant_option;
 
408
        istmt.behavior = stmt->behavior;
 
409
 
 
410
        /*
 
411
         * Convert the PrivGrantee list into an Oid list.  Note that at this point
 
412
         * we insert an ACL_ID_PUBLIC into the list if an empty role name is
 
413
         * detected (which is what the grammar uses if PUBLIC is found), so
 
414
         * downstream there shouldn't be any additional work needed to support
 
415
         * this case.
 
416
         */
 
417
        foreach(cell, stmt->grantees)
 
418
        {
 
419
                PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
 
420
 
 
421
                if (grantee->rolname == NULL)
 
422
                        istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
 
423
                else
 
424
                        istmt.grantees =
 
425
                                lappend_oid(istmt.grantees,
 
426
                                                        get_role_oid(grantee->rolname, false));
 
427
        }
 
428
 
 
429
        /*
 
430
         * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
 
431
         * bitmask.  Note: objtype can't be ACL_OBJECT_COLUMN.
 
432
         */
 
433
        switch (stmt->objtype)
 
434
        {
 
435
                        /*
 
436
                         * Because this might be a sequence, we test both relation and
 
437
                         * sequence bits, and later do a more limited test when we know
 
438
                         * the object type.
 
439
                         */
 
440
                case ACL_OBJECT_RELATION:
 
441
                        all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE;
 
442
                        errormsg = gettext_noop("invalid privilege type %s for relation");
 
443
                        break;
 
444
                case ACL_OBJECT_SEQUENCE:
 
445
                        all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
 
446
                        errormsg = gettext_noop("invalid privilege type %s for sequence");
 
447
                        break;
 
448
                case ACL_OBJECT_DATABASE:
 
449
                        all_privileges = ACL_ALL_RIGHTS_DATABASE;
 
450
                        errormsg = gettext_noop("invalid privilege type %s for database");
 
451
                        break;
 
452
                case ACL_OBJECT_FUNCTION:
 
453
                        all_privileges = ACL_ALL_RIGHTS_FUNCTION;
 
454
                        errormsg = gettext_noop("invalid privilege type %s for function");
 
455
                        break;
 
456
                case ACL_OBJECT_LANGUAGE:
 
457
                        all_privileges = ACL_ALL_RIGHTS_LANGUAGE;
 
458
                        errormsg = gettext_noop("invalid privilege type %s for language");
 
459
                        break;
 
460
                case ACL_OBJECT_LARGEOBJECT:
 
461
                        all_privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
 
462
                        errormsg = gettext_noop("invalid privilege type %s for large object");
 
463
                        break;
 
464
                case ACL_OBJECT_NAMESPACE:
 
465
                        all_privileges = ACL_ALL_RIGHTS_NAMESPACE;
 
466
                        errormsg = gettext_noop("invalid privilege type %s for schema");
 
467
                        break;
 
468
                case ACL_OBJECT_TABLESPACE:
 
469
                        all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
 
470
                        errormsg = gettext_noop("invalid privilege type %s for tablespace");
 
471
                        break;
 
472
                case ACL_OBJECT_FDW:
 
473
                        all_privileges = ACL_ALL_RIGHTS_FDW;
 
474
                        errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
 
475
                        break;
 
476
                case ACL_OBJECT_FOREIGN_SERVER:
 
477
                        all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 
478
                        errormsg = gettext_noop("invalid privilege type %s for foreign server");
 
479
                        break;
 
480
                default:
 
481
                        elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 
482
                                 (int) stmt->objtype);
 
483
                        /* keep compiler quiet */
 
484
                        all_privileges = ACL_NO_RIGHTS;
 
485
                        errormsg = NULL;
 
486
        }
 
487
 
 
488
        if (stmt->privileges == NIL)
 
489
        {
 
490
                istmt.all_privs = true;
 
491
 
 
492
                /*
 
493
                 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
 
494
                 * depending on the object type
 
495
                 */
 
496
                istmt.privileges = ACL_NO_RIGHTS;
 
497
        }
 
498
        else
 
499
        {
 
500
                istmt.all_privs = false;
 
501
                istmt.privileges = ACL_NO_RIGHTS;
 
502
 
 
503
                foreach(cell, stmt->privileges)
 
504
                {
 
505
                        AccessPriv *privnode = (AccessPriv *) lfirst(cell);
 
506
                        AclMode         priv;
 
507
 
 
508
                        /*
 
509
                         * If it's a column-level specification, we just set it aside in
 
510
                         * col_privs for the moment; but insist it's for a relation.
 
511
                         */
 
512
                        if (privnode->cols)
 
513
                        {
 
514
                                if (stmt->objtype != ACL_OBJECT_RELATION)
 
515
                                        ereport(ERROR,
 
516
                                                        (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
517
                                                         errmsg("column privileges are only valid for relations")));
 
518
                                istmt.col_privs = lappend(istmt.col_privs, privnode);
 
519
                                continue;
 
520
                        }
 
521
 
 
522
                        if (privnode->priv_name == NULL)        /* parser mistake? */
 
523
                                elog(ERROR, "AccessPriv node must specify privilege or columns");
 
524
                        priv = string_to_privilege(privnode->priv_name);
 
525
 
 
526
                        if (priv & ~((AclMode) all_privileges))
 
527
                                ereport(ERROR,
 
528
                                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
529
                                                 errmsg(errormsg, privilege_to_string(priv))));
 
530
 
 
531
                        istmt.privileges |= priv;
 
532
                }
 
533
        }
 
534
 
 
535
        ExecGrantStmt_oids(&istmt);
 
536
}
 
537
 
 
538
/*
 
539
 * ExecGrantStmt_oids
 
540
 *
 
541
 * Internal entry point for granting and revoking privileges.
 
542
 */
 
543
static void
 
544
ExecGrantStmt_oids(InternalGrant *istmt)
 
545
{
 
546
        switch (istmt->objtype)
 
547
        {
 
548
                case ACL_OBJECT_RELATION:
 
549
                case ACL_OBJECT_SEQUENCE:
 
550
                        ExecGrant_Relation(istmt);
 
551
                        break;
 
552
                case ACL_OBJECT_DATABASE:
 
553
                        ExecGrant_Database(istmt);
 
554
                        break;
 
555
                case ACL_OBJECT_FDW:
 
556
                        ExecGrant_Fdw(istmt);
 
557
                        break;
 
558
                case ACL_OBJECT_FOREIGN_SERVER:
 
559
                        ExecGrant_ForeignServer(istmt);
 
560
                        break;
 
561
                case ACL_OBJECT_FUNCTION:
 
562
                        ExecGrant_Function(istmt);
 
563
                        break;
 
564
                case ACL_OBJECT_LANGUAGE:
 
565
                        ExecGrant_Language(istmt);
 
566
                        break;
 
567
                case ACL_OBJECT_LARGEOBJECT:
 
568
                        ExecGrant_Largeobject(istmt);
 
569
                        break;
 
570
                case ACL_OBJECT_NAMESPACE:
 
571
                        ExecGrant_Namespace(istmt);
 
572
                        break;
 
573
                case ACL_OBJECT_TABLESPACE:
 
574
                        ExecGrant_Tablespace(istmt);
 
575
                        break;
 
576
                default:
 
577
                        elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 
578
                                 (int) istmt->objtype);
 
579
        }
 
580
}
 
581
 
 
582
/*
 
583
 * objectNamesToOids
 
584
 *
 
585
 * Turn a list of object names of a given type into an Oid list.
 
586
 */
 
587
static List *
 
588
objectNamesToOids(GrantObjectType objtype, List *objnames)
 
589
{
 
590
        List       *objects = NIL;
 
591
        ListCell   *cell;
 
592
 
 
593
        Assert(objnames != NIL);
 
594
 
 
595
        switch (objtype)
 
596
        {
 
597
                case ACL_OBJECT_RELATION:
 
598
                case ACL_OBJECT_SEQUENCE:
 
599
                        foreach(cell, objnames)
 
600
                        {
 
601
                                RangeVar   *relvar = (RangeVar *) lfirst(cell);
 
602
                                Oid                     relOid;
 
603
 
 
604
                                relOid = RangeVarGetRelid(relvar, false);
 
605
                                objects = lappend_oid(objects, relOid);
 
606
                        }
 
607
                        break;
 
608
                case ACL_OBJECT_DATABASE:
 
609
                        foreach(cell, objnames)
 
610
                        {
 
611
                                char       *dbname = strVal(lfirst(cell));
 
612
                                Oid                     dbid;
 
613
 
 
614
                                dbid = get_database_oid(dbname, false);
 
615
                                objects = lappend_oid(objects, dbid);
 
616
                        }
 
617
                        break;
 
618
                case ACL_OBJECT_FUNCTION:
 
619
                        foreach(cell, objnames)
 
620
                        {
 
621
                                FuncWithArgs *func = (FuncWithArgs *) lfirst(cell);
 
622
                                Oid                     funcid;
 
623
 
 
624
                                funcid = LookupFuncNameTypeNames(func->funcname,
 
625
                                                                                                 func->funcargs, false);
 
626
                                objects = lappend_oid(objects, funcid);
 
627
                        }
 
628
                        break;
 
629
                case ACL_OBJECT_LANGUAGE:
 
630
                        foreach(cell, objnames)
 
631
                        {
 
632
                                char       *langname = strVal(lfirst(cell));
 
633
                                Oid                     oid;
 
634
 
 
635
                                oid = get_language_oid(langname, false);
 
636
                                objects = lappend_oid(objects, oid);
 
637
                        }
 
638
                        break;
 
639
                case ACL_OBJECT_LARGEOBJECT:
 
640
                        foreach(cell, objnames)
 
641
                        {
 
642
                                Oid                     lobjOid = oidparse(lfirst(cell));
 
643
 
 
644
                                if (!LargeObjectExists(lobjOid))
 
645
                                        ereport(ERROR,
 
646
                                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
 
647
                                                         errmsg("large object %u does not exist",
 
648
                                                                        lobjOid)));
 
649
 
 
650
                                objects = lappend_oid(objects, lobjOid);
 
651
                        }
 
652
                        break;
 
653
                case ACL_OBJECT_NAMESPACE:
 
654
                        foreach(cell, objnames)
 
655
                        {
 
656
                                char       *nspname = strVal(lfirst(cell));
 
657
                                Oid                     oid;
 
658
 
 
659
                                oid = get_namespace_oid(nspname, false);
 
660
                                objects = lappend_oid(objects, oid);
 
661
                        }
 
662
                        break;
 
663
                case ACL_OBJECT_TABLESPACE:
 
664
                        foreach(cell, objnames)
 
665
                        {
 
666
                                char       *spcname = strVal(lfirst(cell));
 
667
                                Oid                     spcoid;
 
668
 
 
669
                                spcoid = get_tablespace_oid(spcname, false);
 
670
                                objects = lappend_oid(objects, spcoid);
 
671
                        }
 
672
                        break;
 
673
                case ACL_OBJECT_FDW:
 
674
                        foreach(cell, objnames)
 
675
                        {
 
676
                                char       *fdwname = strVal(lfirst(cell));
 
677
                                Oid                     fdwid = get_foreign_data_wrapper_oid(fdwname, false);
 
678
 
 
679
                                objects = lappend_oid(objects, fdwid);
 
680
                        }
 
681
                        break;
 
682
                case ACL_OBJECT_FOREIGN_SERVER:
 
683
                        foreach(cell, objnames)
 
684
                        {
 
685
                                char       *srvname = strVal(lfirst(cell));
 
686
                                Oid                     srvid = get_foreign_server_oid(srvname, false);
 
687
 
 
688
                                objects = lappend_oid(objects, srvid);
 
689
                        }
 
690
                        break;
 
691
                default:
 
692
                        elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 
693
                                 (int) objtype);
 
694
        }
 
695
 
 
696
        return objects;
 
697
}
 
698
 
 
699
/*
 
700
 * objectsInSchemaToOids
 
701
 *
 
702
 * Find all objects of a given type in specified schemas, and make a list
 
703
 * of their Oids.  We check USAGE privilege on the schemas, but there is
 
704
 * no privilege checking on the individual objects here.
 
705
 */
 
706
static List *
 
707
objectsInSchemaToOids(GrantObjectType objtype, List *nspnames)
 
708
{
 
709
        List       *objects = NIL;
 
710
        ListCell   *cell;
 
711
 
 
712
        foreach(cell, nspnames)
 
713
        {
 
714
                char       *nspname = strVal(lfirst(cell));
 
715
                Oid                     namespaceId;
 
716
                List       *objs;
 
717
 
 
718
                namespaceId = LookupExplicitNamespace(nspname);
 
719
 
 
720
                switch (objtype)
 
721
                {
 
722
                        case ACL_OBJECT_RELATION:
 
723
                                /* Process regular tables, views and foreign tables */
 
724
                                objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
 
725
                                objects = list_concat(objects, objs);
 
726
                                objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
 
727
                                objects = list_concat(objects, objs);
 
728
                                objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
 
729
                                objects = list_concat(objects, objs);
 
730
                                break;
 
731
                        case ACL_OBJECT_SEQUENCE:
 
732
                                objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
 
733
                                objects = list_concat(objects, objs);
 
734
                                break;
 
735
                        case ACL_OBJECT_FUNCTION:
 
736
                                {
 
737
                                        ScanKeyData key[1];
 
738
                                        Relation        rel;
 
739
                                        HeapScanDesc scan;
 
740
                                        HeapTuple       tuple;
 
741
 
 
742
                                        ScanKeyInit(&key[0],
 
743
                                                                Anum_pg_proc_pronamespace,
 
744
                                                                BTEqualStrategyNumber, F_OIDEQ,
 
745
                                                                ObjectIdGetDatum(namespaceId));
 
746
 
 
747
                                        rel = heap_open(ProcedureRelationId, AccessShareLock);
 
748
                                        scan = heap_beginscan(rel, SnapshotNow, 1, key);
 
749
 
 
750
                                        while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 
751
                                        {
 
752
                                                objects = lappend_oid(objects, HeapTupleGetOid(tuple));
 
753
                                        }
 
754
 
 
755
                                        heap_endscan(scan);
 
756
                                        heap_close(rel, AccessShareLock);
 
757
                                }
 
758
                                break;
 
759
                        default:
 
760
                                /* should not happen */
 
761
                                elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 
762
                                         (int) objtype);
 
763
                }
 
764
        }
 
765
 
 
766
        return objects;
 
767
}
 
768
 
 
769
/*
 
770
 * getRelationsInNamespace
 
771
 *
 
772
 * Return Oid list of relations in given namespace filtered by relation kind
 
773
 */
 
774
static List *
 
775
getRelationsInNamespace(Oid namespaceId, char relkind)
 
776
{
 
777
        List       *relations = NIL;
 
778
        ScanKeyData key[2];
 
779
        Relation        rel;
 
780
        HeapScanDesc scan;
 
781
        HeapTuple       tuple;
 
782
 
 
783
        ScanKeyInit(&key[0],
 
784
                                Anum_pg_class_relnamespace,
 
785
                                BTEqualStrategyNumber, F_OIDEQ,
 
786
                                ObjectIdGetDatum(namespaceId));
 
787
        ScanKeyInit(&key[1],
 
788
                                Anum_pg_class_relkind,
 
789
                                BTEqualStrategyNumber, F_CHAREQ,
 
790
                                CharGetDatum(relkind));
 
791
 
 
792
        rel = heap_open(RelationRelationId, AccessShareLock);
 
793
        scan = heap_beginscan(rel, SnapshotNow, 2, key);
 
794
 
 
795
        while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 
796
        {
 
797
                relations = lappend_oid(relations, HeapTupleGetOid(tuple));
 
798
        }
 
799
 
 
800
        heap_endscan(scan);
 
801
        heap_close(rel, AccessShareLock);
 
802
 
 
803
        return relations;
 
804
}
 
805
 
 
806
 
 
807
/*
 
808
 * ALTER DEFAULT PRIVILEGES statement
 
809
 */
 
810
void
 
811
ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
 
812
{
 
813
        GrantStmt  *action = stmt->action;
 
814
        InternalDefaultACL iacls;
 
815
        ListCell   *cell;
 
816
        List       *rolenames = NIL;
 
817
        List       *nspnames = NIL;
 
818
        DefElem    *drolenames = NULL;
 
819
        DefElem    *dnspnames = NULL;
 
820
        AclMode         all_privileges;
 
821
        const char *errormsg;
 
822
 
 
823
        /* Deconstruct the "options" part of the statement */
 
824
        foreach(cell, stmt->options)
 
825
        {
 
826
                DefElem    *defel = (DefElem *) lfirst(cell);
 
827
 
 
828
                if (strcmp(defel->defname, "schemas") == 0)
 
829
                {
 
830
                        if (dnspnames)
 
831
                                ereport(ERROR,
 
832
                                                (errcode(ERRCODE_SYNTAX_ERROR),
 
833
                                                 errmsg("conflicting or redundant options")));
 
834
                        dnspnames = defel;
 
835
                }
 
836
                else if (strcmp(defel->defname, "roles") == 0)
 
837
                {
 
838
                        if (drolenames)
 
839
                                ereport(ERROR,
 
840
                                                (errcode(ERRCODE_SYNTAX_ERROR),
 
841
                                                 errmsg("conflicting or redundant options")));
 
842
                        drolenames = defel;
 
843
                }
 
844
                else
 
845
                        elog(ERROR, "option \"%s\" not recognized", defel->defname);
 
846
        }
 
847
 
 
848
        if (dnspnames)
 
849
                nspnames = (List *) dnspnames->arg;
 
850
        if (drolenames)
 
851
                rolenames = (List *) drolenames->arg;
 
852
 
 
853
        /* Prepare the InternalDefaultACL representation of the statement */
 
854
        /* roleid to be filled below */
 
855
        /* nspid to be filled in SetDefaultACLsInSchemas */
 
856
        iacls.is_grant = action->is_grant;
 
857
        iacls.objtype = action->objtype;
 
858
        /* all_privs to be filled below */
 
859
        /* privileges to be filled below */
 
860
        iacls.grantees = NIL;           /* filled below */
 
861
        iacls.grant_option = action->grant_option;
 
862
        iacls.behavior = action->behavior;
 
863
 
 
864
        /*
 
865
         * Convert the PrivGrantee list into an Oid list.  Note that at this point
 
866
         * we insert an ACL_ID_PUBLIC into the list if an empty role name is
 
867
         * detected (which is what the grammar uses if PUBLIC is found), so
 
868
         * downstream there shouldn't be any additional work needed to support
 
869
         * this case.
 
870
         */
 
871
        foreach(cell, action->grantees)
 
872
        {
 
873
                PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
 
874
 
 
875
                if (grantee->rolname == NULL)
 
876
                        iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
 
877
                else
 
878
                        iacls.grantees =
 
879
                                lappend_oid(iacls.grantees,
 
880
                                                        get_role_oid(grantee->rolname, false));
 
881
        }
 
882
 
 
883
        /*
 
884
         * Convert action->privileges, a list of privilege strings, into an
 
885
         * AclMode bitmask.
 
886
         */
 
887
        switch (action->objtype)
 
888
        {
 
889
                case ACL_OBJECT_RELATION:
 
890
                        all_privileges = ACL_ALL_RIGHTS_RELATION;
 
891
                        errormsg = gettext_noop("invalid privilege type %s for relation");
 
892
                        break;
 
893
                case ACL_OBJECT_SEQUENCE:
 
894
                        all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
 
895
                        errormsg = gettext_noop("invalid privilege type %s for sequence");
 
896
                        break;
 
897
                case ACL_OBJECT_FUNCTION:
 
898
                        all_privileges = ACL_ALL_RIGHTS_FUNCTION;
 
899
                        errormsg = gettext_noop("invalid privilege type %s for function");
 
900
                        break;
 
901
                default:
 
902
                        elog(ERROR, "unrecognized GrantStmt.objtype: %d",
 
903
                                 (int) action->objtype);
 
904
                        /* keep compiler quiet */
 
905
                        all_privileges = ACL_NO_RIGHTS;
 
906
                        errormsg = NULL;
 
907
        }
 
908
 
 
909
        if (action->privileges == NIL)
 
910
        {
 
911
                iacls.all_privs = true;
 
912
 
 
913
                /*
 
914
                 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
 
915
                 * depending on the object type
 
916
                 */
 
917
                iacls.privileges = ACL_NO_RIGHTS;
 
918
        }
 
919
        else
 
920
        {
 
921
                iacls.all_privs = false;
 
922
                iacls.privileges = ACL_NO_RIGHTS;
 
923
 
 
924
                foreach(cell, action->privileges)
 
925
                {
 
926
                        AccessPriv *privnode = (AccessPriv *) lfirst(cell);
 
927
                        AclMode         priv;
 
928
 
 
929
                        if (privnode->cols)
 
930
                                ereport(ERROR,
 
931
                                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
932
                                        errmsg("default privileges cannot be set for columns")));
 
933
 
 
934
                        if (privnode->priv_name == NULL)        /* parser mistake? */
 
935
                                elog(ERROR, "AccessPriv node must specify privilege");
 
936
                        priv = string_to_privilege(privnode->priv_name);
 
937
 
 
938
                        if (priv & ~((AclMode) all_privileges))
 
939
                                ereport(ERROR,
 
940
                                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
941
                                                 errmsg(errormsg, privilege_to_string(priv))));
 
942
 
 
943
                        iacls.privileges |= priv;
 
944
                }
 
945
        }
 
946
 
 
947
        if (rolenames == NIL)
 
948
        {
 
949
                /* Set permissions for myself */
 
950
                iacls.roleid = GetUserId();
 
951
 
 
952
                SetDefaultACLsInSchemas(&iacls, nspnames);
 
953
        }
 
954
        else
 
955
        {
 
956
                /* Look up the role OIDs and do permissions checks */
 
957
                ListCell   *rolecell;
 
958
 
 
959
                foreach(rolecell, rolenames)
 
960
                {
 
961
                        char       *rolename = strVal(lfirst(rolecell));
 
962
 
 
963
                        iacls.roleid = get_role_oid(rolename, false);
 
964
 
 
965
                        /*
 
966
                         * We insist that calling user be a member of each target role. If
 
967
                         * he has that, he could become that role anyway via SET ROLE, so
 
968
                         * FOR ROLE is just a syntactic convenience and doesn't give any
 
969
                         * special privileges.
 
970
                         */
 
971
                        check_is_member_of_role(GetUserId(), iacls.roleid);
 
972
 
 
973
                        SetDefaultACLsInSchemas(&iacls, nspnames);
 
974
                }
 
975
        }
 
976
}
 
977
 
 
978
/*
 
979
 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
 
980
 *
 
981
 * All fields of *iacls except nspid were filled already
 
982
 */
 
983
static void
 
984
SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
 
985
{
 
986
        if (nspnames == NIL)
 
987
        {
 
988
                /* Set database-wide permissions if no schema was specified */
 
989
                iacls->nspid = InvalidOid;
 
990
 
 
991
                SetDefaultACL(iacls);
 
992
        }
 
993
        else
 
994
        {
 
995
                /* Look up the schema OIDs and do permissions checks */
 
996
                ListCell   *nspcell;
 
997
 
 
998
                foreach(nspcell, nspnames)
 
999
                {
 
1000
                        char       *nspname = strVal(lfirst(nspcell));
 
1001
                        AclResult       aclresult;
 
1002
 
 
1003
                        /*
 
1004
                         * Note that we must do the permissions check against the target
 
1005
                         * role not the calling user.  We require CREATE privileges, since
 
1006
                         * without CREATE you won't be able to do anything using the
 
1007
                         * default privs anyway.
 
1008
                         */
 
1009
                        iacls->nspid = get_namespace_oid(nspname, false);
 
1010
 
 
1011
                        aclresult = pg_namespace_aclcheck(iacls->nspid, iacls->roleid,
 
1012
                                                                                          ACL_CREATE);
 
1013
                        if (aclresult != ACLCHECK_OK)
 
1014
                                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 
1015
                                                           nspname);
 
1016
 
 
1017
                        SetDefaultACL(iacls);
 
1018
                }
 
1019
        }
 
1020
}
 
1021
 
 
1022
 
 
1023
/*
 
1024
 * Create or update a pg_default_acl entry
 
1025
 */
 
1026
static void
 
1027
SetDefaultACL(InternalDefaultACL *iacls)
 
1028
{
 
1029
        AclMode         this_privileges = iacls->privileges;
 
1030
        char            objtype;
 
1031
        Relation        rel;
 
1032
        HeapTuple       tuple;
 
1033
        bool            isNew;
 
1034
        Acl                *def_acl;
 
1035
        Acl                *old_acl;
 
1036
        Acl                *new_acl;
 
1037
        HeapTuple       newtuple;
 
1038
        Datum           values[Natts_pg_default_acl];
 
1039
        bool            nulls[Natts_pg_default_acl];
 
1040
        bool            replaces[Natts_pg_default_acl];
 
1041
        int                     noldmembers;
 
1042
        int                     nnewmembers;
 
1043
        Oid                *oldmembers;
 
1044
        Oid                *newmembers;
 
1045
 
 
1046
        rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
 
1047
 
 
1048
        /*
 
1049
         * The default for a global entry is the hard-wired default ACL for the
 
1050
         * particular object type.      The default for non-global entries is an empty
 
1051
         * ACL.  This must be so because global entries replace the hard-wired
 
1052
         * defaults, while others are added on.
 
1053
         */
 
1054
        if (!OidIsValid(iacls->nspid))
 
1055
                def_acl = acldefault(iacls->objtype, iacls->roleid);
 
1056
        else
 
1057
                def_acl = make_empty_acl();
 
1058
 
 
1059
        /*
 
1060
         * Convert ACL object type to pg_default_acl object type and handle
 
1061
         * all_privs option
 
1062
         */
 
1063
        switch (iacls->objtype)
 
1064
        {
 
1065
                case ACL_OBJECT_RELATION:
 
1066
                        objtype = DEFACLOBJ_RELATION;
 
1067
                        if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
 
1068
                                this_privileges = ACL_ALL_RIGHTS_RELATION;
 
1069
                        break;
 
1070
 
 
1071
                case ACL_OBJECT_SEQUENCE:
 
1072
                        objtype = DEFACLOBJ_SEQUENCE;
 
1073
                        if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
 
1074
                                this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
 
1075
                        break;
 
1076
 
 
1077
                case ACL_OBJECT_FUNCTION:
 
1078
                        objtype = DEFACLOBJ_FUNCTION;
 
1079
                        if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
 
1080
                                this_privileges = ACL_ALL_RIGHTS_FUNCTION;
 
1081
                        break;
 
1082
 
 
1083
                default:
 
1084
                        elog(ERROR, "unrecognized objtype: %d",
 
1085
                                 (int) iacls->objtype);
 
1086
                        objtype = 0;            /* keep compiler quiet */
 
1087
                        break;
 
1088
        }
 
1089
 
 
1090
        /* Search for existing row for this object type in catalog */
 
1091
        tuple = SearchSysCache3(DEFACLROLENSPOBJ,
 
1092
                                                        ObjectIdGetDatum(iacls->roleid),
 
1093
                                                        ObjectIdGetDatum(iacls->nspid),
 
1094
                                                        CharGetDatum(objtype));
 
1095
 
 
1096
        if (HeapTupleIsValid(tuple))
 
1097
        {
 
1098
                Datum           aclDatum;
 
1099
                bool            isNull;
 
1100
 
 
1101
                aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
 
1102
                                                                   Anum_pg_default_acl_defaclacl,
 
1103
                                                                   &isNull);
 
1104
                if (!isNull)
 
1105
                        old_acl = DatumGetAclPCopy(aclDatum);
 
1106
                else
 
1107
                        old_acl = NULL;         /* this case shouldn't happen, probably */
 
1108
                isNew = false;
 
1109
        }
 
1110
        else
 
1111
        {
 
1112
                old_acl = NULL;
 
1113
                isNew = true;
 
1114
        }
 
1115
 
 
1116
        if (old_acl != NULL)
 
1117
        {
 
1118
                /*
 
1119
                 * We need the members of both old and new ACLs so we can correct the
 
1120
                 * shared dependency information.  Collect data before
 
1121
                 * merge_acl_with_grant throws away old_acl.
 
1122
                 */
 
1123
                noldmembers = aclmembers(old_acl, &oldmembers);
 
1124
        }
 
1125
        else
 
1126
        {
 
1127
                /* If no or null entry, start with the default ACL value */
 
1128
                old_acl = aclcopy(def_acl);
 
1129
                /* There are no old member roles according to the catalogs */
 
1130
                noldmembers = 0;
 
1131
                oldmembers = NULL;
 
1132
        }
 
1133
 
 
1134
        /*
 
1135
         * Generate new ACL.  Grantor of rights is always the same as the target
 
1136
         * role.
 
1137
         */
 
1138
        new_acl = merge_acl_with_grant(old_acl,
 
1139
                                                                   iacls->is_grant,
 
1140
                                                                   iacls->grant_option,
 
1141
                                                                   iacls->behavior,
 
1142
                                                                   iacls->grantees,
 
1143
                                                                   this_privileges,
 
1144
                                                                   iacls->roleid,
 
1145
                                                                   iacls->roleid);
 
1146
 
 
1147
        /*
 
1148
         * If the result is the same as the default value, we do not need an
 
1149
         * explicit pg_default_acl entry, and should in fact remove the entry if
 
1150
         * it exists.  Must sort both arrays to compare properly.
 
1151
         */
 
1152
        aclitemsort(new_acl);
 
1153
        aclitemsort(def_acl);
 
1154
        if (aclequal(new_acl, def_acl))
 
1155
        {
 
1156
                /* delete old entry, if indeed there is one */
 
1157
                if (!isNew)
 
1158
                {
 
1159
                        ObjectAddress myself;
 
1160
 
 
1161
                        /*
 
1162
                         * The dependency machinery will take care of removing all
 
1163
                         * associated dependency entries.  We use DROP_RESTRICT since
 
1164
                         * there shouldn't be anything depending on this entry.
 
1165
                         */
 
1166
                        myself.classId = DefaultAclRelationId;
 
1167
                        myself.objectId = HeapTupleGetOid(tuple);
 
1168
                        myself.objectSubId = 0;
 
1169
 
 
1170
                        performDeletion(&myself, DROP_RESTRICT);
 
1171
                }
 
1172
        }
 
1173
        else
 
1174
        {
 
1175
                /* Prepare to insert or update pg_default_acl entry */
 
1176
                MemSet(values, 0, sizeof(values));
 
1177
                MemSet(nulls, false, sizeof(nulls));
 
1178
                MemSet(replaces, false, sizeof(replaces));
 
1179
 
 
1180
                if (isNew)
 
1181
                {
 
1182
                        /* insert new entry */
 
1183
                        values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
 
1184
                        values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
 
1185
                        values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
 
1186
                        values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
 
1187
 
 
1188
                        newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
 
1189
                        simple_heap_insert(rel, newtuple);
 
1190
                }
 
1191
                else
 
1192
                {
 
1193
                        /* update existing entry */
 
1194
                        values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
 
1195
                        replaces[Anum_pg_default_acl_defaclacl - 1] = true;
 
1196
 
 
1197
                        newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
 
1198
                                                                                 values, nulls, replaces);
 
1199
                        simple_heap_update(rel, &newtuple->t_self, newtuple);
 
1200
                }
 
1201
 
 
1202
                /* keep the catalog indexes up to date */
 
1203
                CatalogUpdateIndexes(rel, newtuple);
 
1204
 
 
1205
                /* these dependencies don't change in an update */
 
1206
                if (isNew)
 
1207
                {
 
1208
                        /* dependency on role */
 
1209
                        recordDependencyOnOwner(DefaultAclRelationId,
 
1210
                                                                        HeapTupleGetOid(newtuple),
 
1211
                                                                        iacls->roleid);
 
1212
 
 
1213
                        /* dependency on namespace */
 
1214
                        if (OidIsValid(iacls->nspid))
 
1215
                        {
 
1216
                                ObjectAddress myself,
 
1217
                                                        referenced;
 
1218
 
 
1219
                                myself.classId = DefaultAclRelationId;
 
1220
                                myself.objectId = HeapTupleGetOid(newtuple);
 
1221
                                myself.objectSubId = 0;
 
1222
 
 
1223
                                referenced.classId = NamespaceRelationId;
 
1224
                                referenced.objectId = iacls->nspid;
 
1225
                                referenced.objectSubId = 0;
 
1226
 
 
1227
                                recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
1228
                        }
 
1229
                }
 
1230
 
 
1231
                /*
 
1232
                 * Update the shared dependency ACL info
 
1233
                 */
 
1234
                nnewmembers = aclmembers(new_acl, &newmembers);
 
1235
 
 
1236
                updateAclDependencies(DefaultAclRelationId,
 
1237
                                                          HeapTupleGetOid(newtuple), 0,
 
1238
                                                          iacls->roleid,
 
1239
                                                          noldmembers, oldmembers,
 
1240
                                                          nnewmembers, newmembers);
 
1241
        }
 
1242
 
 
1243
        if (HeapTupleIsValid(tuple))
 
1244
                ReleaseSysCache(tuple);
 
1245
 
 
1246
        heap_close(rel, RowExclusiveLock);
 
1247
}
 
1248
 
 
1249
 
 
1250
/*
 
1251
 * RemoveRoleFromObjectACL
 
1252
 *
 
1253
 * Used by shdepDropOwned to remove mentions of a role in ACLs
 
1254
 */
 
1255
void
 
1256
RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
 
1257
{
 
1258
        if (classid == DefaultAclRelationId)
 
1259
        {
 
1260
                InternalDefaultACL iacls;
 
1261
                Form_pg_default_acl pg_default_acl_tuple;
 
1262
                Relation        rel;
 
1263
                ScanKeyData skey[1];
 
1264
                SysScanDesc scan;
 
1265
                HeapTuple       tuple;
 
1266
 
 
1267
                /* first fetch info needed by SetDefaultACL */
 
1268
                rel = heap_open(DefaultAclRelationId, AccessShareLock);
 
1269
 
 
1270
                ScanKeyInit(&skey[0],
 
1271
                                        ObjectIdAttributeNumber,
 
1272
                                        BTEqualStrategyNumber, F_OIDEQ,
 
1273
                                        ObjectIdGetDatum(objid));
 
1274
 
 
1275
                scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
 
1276
                                                                  SnapshotNow, 1, skey);
 
1277
 
 
1278
                tuple = systable_getnext(scan);
 
1279
 
 
1280
                if (!HeapTupleIsValid(tuple))
 
1281
                        elog(ERROR, "could not find tuple for default ACL %u", objid);
 
1282
 
 
1283
                pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
 
1284
 
 
1285
                iacls.roleid = pg_default_acl_tuple->defaclrole;
 
1286
                iacls.nspid = pg_default_acl_tuple->defaclnamespace;
 
1287
 
 
1288
                switch (pg_default_acl_tuple->defaclobjtype)
 
1289
                {
 
1290
                        case DEFACLOBJ_RELATION:
 
1291
                                iacls.objtype = ACL_OBJECT_RELATION;
 
1292
                                break;
 
1293
                        case DEFACLOBJ_SEQUENCE:
 
1294
                                iacls.objtype = ACL_OBJECT_SEQUENCE;
 
1295
                                break;
 
1296
                        case DEFACLOBJ_FUNCTION:
 
1297
                                iacls.objtype = ACL_OBJECT_FUNCTION;
 
1298
                                break;
 
1299
                        default:
 
1300
                                /* Shouldn't get here */
 
1301
                                elog(ERROR, "unexpected default ACL type %d",
 
1302
                                         pg_default_acl_tuple->defaclobjtype);
 
1303
                                break;
 
1304
                }
 
1305
 
 
1306
                systable_endscan(scan);
 
1307
                heap_close(rel, AccessShareLock);
 
1308
 
 
1309
                iacls.is_grant = false;
 
1310
                iacls.all_privs = true;
 
1311
                iacls.privileges = ACL_NO_RIGHTS;
 
1312
                iacls.grantees = list_make1_oid(roleid);
 
1313
                iacls.grant_option = false;
 
1314
                iacls.behavior = DROP_CASCADE;
 
1315
 
 
1316
                /* Do it */
 
1317
                SetDefaultACL(&iacls);
 
1318
        }
 
1319
        else
 
1320
        {
 
1321
                InternalGrant istmt;
 
1322
 
 
1323
                switch (classid)
 
1324
                {
 
1325
                        case RelationRelationId:
 
1326
                                /* it's OK to use RELATION for a sequence */
 
1327
                                istmt.objtype = ACL_OBJECT_RELATION;
 
1328
                                break;
 
1329
                        case DatabaseRelationId:
 
1330
                                istmt.objtype = ACL_OBJECT_DATABASE;
 
1331
                                break;
 
1332
                        case ProcedureRelationId:
 
1333
                                istmt.objtype = ACL_OBJECT_FUNCTION;
 
1334
                                break;
 
1335
                        case LanguageRelationId:
 
1336
                                istmt.objtype = ACL_OBJECT_LANGUAGE;
 
1337
                                break;
 
1338
                        case LargeObjectRelationId:
 
1339
                                istmt.objtype = ACL_OBJECT_LARGEOBJECT;
 
1340
                                break;
 
1341
                        case NamespaceRelationId:
 
1342
                                istmt.objtype = ACL_OBJECT_NAMESPACE;
 
1343
                                break;
 
1344
                        case TableSpaceRelationId:
 
1345
                                istmt.objtype = ACL_OBJECT_TABLESPACE;
 
1346
                                break;
 
1347
                        case ForeignServerRelationId:
 
1348
                                istmt.objtype = ACL_OBJECT_FOREIGN_SERVER;
 
1349
                                break;
 
1350
                        case ForeignDataWrapperRelationId:
 
1351
                                istmt.objtype = ACL_OBJECT_FDW;
 
1352
                                break;
 
1353
                        default:
 
1354
                                elog(ERROR, "unexpected object class %u", classid);
 
1355
                                break;
 
1356
                }
 
1357
                istmt.is_grant = false;
 
1358
                istmt.objects = list_make1_oid(objid);
 
1359
                istmt.all_privs = true;
 
1360
                istmt.privileges = ACL_NO_RIGHTS;
 
1361
                istmt.col_privs = NIL;
 
1362
                istmt.grantees = list_make1_oid(roleid);
 
1363
                istmt.grant_option = false;
 
1364
                istmt.behavior = DROP_CASCADE;
 
1365
 
 
1366
                ExecGrantStmt_oids(&istmt);
 
1367
        }
 
1368
}
 
1369
 
 
1370
 
 
1371
/*
 
1372
 * Remove a pg_default_acl entry
 
1373
 */
 
1374
void
 
1375
RemoveDefaultACLById(Oid defaclOid)
 
1376
{
 
1377
        Relation        rel;
 
1378
        ScanKeyData skey[1];
 
1379
        SysScanDesc scan;
 
1380
        HeapTuple       tuple;
 
1381
 
 
1382
        rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
 
1383
 
 
1384
        ScanKeyInit(&skey[0],
 
1385
                                ObjectIdAttributeNumber,
 
1386
                                BTEqualStrategyNumber, F_OIDEQ,
 
1387
                                ObjectIdGetDatum(defaclOid));
 
1388
 
 
1389
        scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
 
1390
                                                          SnapshotNow, 1, skey);
 
1391
 
 
1392
        tuple = systable_getnext(scan);
 
1393
 
 
1394
        if (!HeapTupleIsValid(tuple))
 
1395
                elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
 
1396
 
 
1397
        simple_heap_delete(rel, &tuple->t_self);
 
1398
 
 
1399
        systable_endscan(scan);
 
1400
        heap_close(rel, RowExclusiveLock);
 
1401
}
 
1402
 
 
1403
 
 
1404
/*
 
1405
 * expand_col_privileges
 
1406
 *
 
1407
 * OR the specified privilege(s) into per-column array entries for each
 
1408
 * specified attribute.  The per-column array is indexed starting at
 
1409
 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
 
1410
 */
 
1411
static void
 
1412
expand_col_privileges(List *colnames, Oid table_oid,
 
1413
                                          AclMode this_privileges,
 
1414
                                          AclMode *col_privileges,
 
1415
                                          int num_col_privileges)
 
1416
{
 
1417
        ListCell   *cell;
 
1418
 
 
1419
        foreach(cell, colnames)
 
1420
        {
 
1421
                char       *colname = strVal(lfirst(cell));
 
1422
                AttrNumber      attnum;
 
1423
 
 
1424
                attnum = get_attnum(table_oid, colname);
 
1425
                if (attnum == InvalidAttrNumber)
 
1426
                        ereport(ERROR,
 
1427
                                        (errcode(ERRCODE_UNDEFINED_COLUMN),
 
1428
                                         errmsg("column \"%s\" of relation \"%s\" does not exist",
 
1429
                                                        colname, get_rel_name(table_oid))));
 
1430
                attnum -= FirstLowInvalidHeapAttributeNumber;
 
1431
                if (attnum <= 0 || attnum >= num_col_privileges)
 
1432
                        elog(ERROR, "column number out of range");      /* safety check */
 
1433
                col_privileges[attnum] |= this_privileges;
 
1434
        }
 
1435
}
 
1436
 
 
1437
/*
 
1438
 * expand_all_col_privileges
 
1439
 *
 
1440
 * OR the specified privilege(s) into per-column array entries for each valid
 
1441
 * attribute of a relation.  The per-column array is indexed starting at
 
1442
 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
 
1443
 */
 
1444
static void
 
1445
expand_all_col_privileges(Oid table_oid, Form_pg_class classForm,
 
1446
                                                  AclMode this_privileges,
 
1447
                                                  AclMode *col_privileges,
 
1448
                                                  int num_col_privileges)
 
1449
{
 
1450
        AttrNumber      curr_att;
 
1451
 
 
1452
        Assert(classForm->relnatts - FirstLowInvalidHeapAttributeNumber < num_col_privileges);
 
1453
        for (curr_att = FirstLowInvalidHeapAttributeNumber + 1;
 
1454
                 curr_att <= classForm->relnatts;
 
1455
                 curr_att++)
 
1456
        {
 
1457
                HeapTuple       attTuple;
 
1458
                bool            isdropped;
 
1459
 
 
1460
                if (curr_att == InvalidAttrNumber)
 
1461
                        continue;
 
1462
 
 
1463
                /* Skip OID column if it doesn't exist */
 
1464
                if (curr_att == ObjectIdAttributeNumber && !classForm->relhasoids)
 
1465
                        continue;
 
1466
 
 
1467
                /* Views don't have any system columns at all */
 
1468
                if (classForm->relkind == RELKIND_VIEW && curr_att < 0)
 
1469
                        continue;
 
1470
 
 
1471
                attTuple = SearchSysCache2(ATTNUM,
 
1472
                                                                   ObjectIdGetDatum(table_oid),
 
1473
                                                                   Int16GetDatum(curr_att));
 
1474
                if (!HeapTupleIsValid(attTuple))
 
1475
                        elog(ERROR, "cache lookup failed for attribute %d of relation %u",
 
1476
                                 curr_att, table_oid);
 
1477
 
 
1478
                isdropped = ((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped;
 
1479
 
 
1480
                ReleaseSysCache(attTuple);
 
1481
 
 
1482
                /* ignore dropped columns */
 
1483
                if (isdropped)
 
1484
                        continue;
 
1485
 
 
1486
                col_privileges[curr_att - FirstLowInvalidHeapAttributeNumber] |= this_privileges;
 
1487
        }
 
1488
}
 
1489
 
 
1490
/*
 
1491
 *      This processes attributes, but expects to be called from
 
1492
 *      ExecGrant_Relation, not directly from ExecGrantStmt.
 
1493
 */
 
1494
static void
 
1495
ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname,
 
1496
                                        AttrNumber attnum, Oid ownerId, AclMode col_privileges,
 
1497
                                        Relation attRelation, const Acl *old_rel_acl)
 
1498
{
 
1499
        HeapTuple       attr_tuple;
 
1500
        Form_pg_attribute pg_attribute_tuple;
 
1501
        Acl                *old_acl;
 
1502
        Acl                *new_acl;
 
1503
        Acl                *merged_acl;
 
1504
        Datum           aclDatum;
 
1505
        bool            isNull;
 
1506
        Oid                     grantorId;
 
1507
        AclMode         avail_goptions;
 
1508
        bool            need_update;
 
1509
        HeapTuple       newtuple;
 
1510
        Datum           values[Natts_pg_attribute];
 
1511
        bool            nulls[Natts_pg_attribute];
 
1512
        bool            replaces[Natts_pg_attribute];
 
1513
        int                     noldmembers;
 
1514
        int                     nnewmembers;
 
1515
        Oid                *oldmembers;
 
1516
        Oid                *newmembers;
 
1517
 
 
1518
        attr_tuple = SearchSysCache2(ATTNUM,
 
1519
                                                                 ObjectIdGetDatum(relOid),
 
1520
                                                                 Int16GetDatum(attnum));
 
1521
        if (!HeapTupleIsValid(attr_tuple))
 
1522
                elog(ERROR, "cache lookup failed for attribute %d of relation %u",
 
1523
                         attnum, relOid);
 
1524
        pg_attribute_tuple = (Form_pg_attribute) GETSTRUCT(attr_tuple);
 
1525
 
 
1526
        /*
 
1527
         * Get working copy of existing ACL. If there's no ACL, substitute the
 
1528
         * proper default.
 
1529
         */
 
1530
        aclDatum = SysCacheGetAttr(ATTNUM, attr_tuple, Anum_pg_attribute_attacl,
 
1531
                                                           &isNull);
 
1532
        if (isNull)
 
1533
        {
 
1534
                old_acl = acldefault(ACL_OBJECT_COLUMN, ownerId);
 
1535
                /* There are no old member roles according to the catalogs */
 
1536
                noldmembers = 0;
 
1537
                oldmembers = NULL;
 
1538
        }
 
1539
        else
 
1540
        {
 
1541
                old_acl = DatumGetAclPCopy(aclDatum);
 
1542
                /* Get the roles mentioned in the existing ACL */
 
1543
                noldmembers = aclmembers(old_acl, &oldmembers);
 
1544
        }
 
1545
 
 
1546
        /*
 
1547
         * In select_best_grantor we should consider existing table-level ACL bits
 
1548
         * as well as the per-column ACL.  Build a new ACL that is their
 
1549
         * concatenation.  (This is a bit cheap and dirty compared to merging them
 
1550
         * properly with no duplications, but it's all we need here.)
 
1551
         */
 
1552
        merged_acl = aclconcat(old_rel_acl, old_acl);
 
1553
 
 
1554
        /* Determine ID to do the grant as, and available grant options */
 
1555
        select_best_grantor(GetUserId(), col_privileges,
 
1556
                                                merged_acl, ownerId,
 
1557
                                                &grantorId, &avail_goptions);
 
1558
 
 
1559
        pfree(merged_acl);
 
1560
 
 
1561
        /*
 
1562
         * Restrict the privileges to what we can actually grant, and emit the
 
1563
         * standards-mandated warning and error messages.  Note: we don't track
 
1564
         * whether the user actually used the ALL PRIVILEGES(columns) syntax for
 
1565
         * each column; we just approximate it by whether all the possible
 
1566
         * privileges are specified now.  Since the all_privs flag only determines
 
1567
         * whether a warning is issued, this seems close enough.
 
1568
         */
 
1569
        col_privileges =
 
1570
                restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
1571
                                                                 (col_privileges == ACL_ALL_RIGHTS_COLUMN),
 
1572
                                                                 col_privileges,
 
1573
                                                                 relOid, grantorId, ACL_KIND_COLUMN,
 
1574
                                                                 relname, attnum,
 
1575
                                                                 NameStr(pg_attribute_tuple->attname));
 
1576
 
 
1577
        /*
 
1578
         * Generate new ACL.
 
1579
         */
 
1580
        new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
1581
                                                                   istmt->grant_option,
 
1582
                                                                   istmt->behavior, istmt->grantees,
 
1583
                                                                   col_privileges, grantorId,
 
1584
                                                                   ownerId);
 
1585
 
 
1586
        /*
 
1587
         * We need the members of both old and new ACLs so we can correct the
 
1588
         * shared dependency information.
 
1589
         */
 
1590
        nnewmembers = aclmembers(new_acl, &newmembers);
 
1591
 
 
1592
        /* finished building new ACL value, now insert it */
 
1593
        MemSet(values, 0, sizeof(values));
 
1594
        MemSet(nulls, false, sizeof(nulls));
 
1595
        MemSet(replaces, false, sizeof(replaces));
 
1596
 
 
1597
        /*
 
1598
         * If the updated ACL is empty, we can set attacl to null, and maybe even
 
1599
         * avoid an update of the pg_attribute row.  This is worth testing because
 
1600
         * we'll come through here multiple times for any relation-level REVOKE,
 
1601
         * even if there were never any column GRANTs.  Note we are assuming that
 
1602
         * the "default" ACL state for columns is empty.
 
1603
         */
 
1604
        if (ACL_NUM(new_acl) > 0)
 
1605
        {
 
1606
                values[Anum_pg_attribute_attacl - 1] = PointerGetDatum(new_acl);
 
1607
                need_update = true;
 
1608
        }
 
1609
        else
 
1610
        {
 
1611
                nulls[Anum_pg_attribute_attacl - 1] = true;
 
1612
                need_update = !isNull;
 
1613
        }
 
1614
        replaces[Anum_pg_attribute_attacl - 1] = true;
 
1615
 
 
1616
        if (need_update)
 
1617
        {
 
1618
                newtuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attRelation),
 
1619
                                                                         values, nulls, replaces);
 
1620
 
 
1621
                simple_heap_update(attRelation, &newtuple->t_self, newtuple);
 
1622
 
 
1623
                /* keep the catalog indexes up to date */
 
1624
                CatalogUpdateIndexes(attRelation, newtuple);
 
1625
 
 
1626
                /* Update the shared dependency ACL info */
 
1627
                updateAclDependencies(RelationRelationId, relOid, attnum,
 
1628
                                                          ownerId,
 
1629
                                                          noldmembers, oldmembers,
 
1630
                                                          nnewmembers, newmembers);
 
1631
        }
 
1632
 
 
1633
        pfree(new_acl);
 
1634
 
 
1635
        ReleaseSysCache(attr_tuple);
 
1636
}
 
1637
 
 
1638
/*
 
1639
 *      This processes both sequences and non-sequences.
 
1640
 */
 
1641
static void
 
1642
ExecGrant_Relation(InternalGrant *istmt)
 
1643
{
 
1644
        Relation        relation;
 
1645
        Relation        attRelation;
 
1646
        ListCell   *cell;
 
1647
 
 
1648
        relation = heap_open(RelationRelationId, RowExclusiveLock);
 
1649
        attRelation = heap_open(AttributeRelationId, RowExclusiveLock);
 
1650
 
 
1651
        foreach(cell, istmt->objects)
 
1652
        {
 
1653
                Oid                     relOid = lfirst_oid(cell);
 
1654
                Datum           aclDatum;
 
1655
                Form_pg_class pg_class_tuple;
 
1656
                bool            isNull;
 
1657
                AclMode         this_privileges;
 
1658
                AclMode    *col_privileges;
 
1659
                int                     num_col_privileges;
 
1660
                bool            have_col_privileges;
 
1661
                Acl                *old_acl;
 
1662
                Acl                *old_rel_acl;
 
1663
                int                     noldmembers;
 
1664
                Oid                *oldmembers;
 
1665
                Oid                     ownerId;
 
1666
                HeapTuple       tuple;
 
1667
                ListCell   *cell_colprivs;
 
1668
 
 
1669
                tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
 
1670
                if (!HeapTupleIsValid(tuple))
 
1671
                        elog(ERROR, "cache lookup failed for relation %u", relOid);
 
1672
                pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
 
1673
 
 
1674
                /* Not sensible to grant on an index */
 
1675
                if (pg_class_tuple->relkind == RELKIND_INDEX)
 
1676
                        ereport(ERROR,
 
1677
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
1678
                                         errmsg("\"%s\" is an index",
 
1679
                                                        NameStr(pg_class_tuple->relname))));
 
1680
 
 
1681
                /* Composite types aren't tables either */
 
1682
                if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
 
1683
                        ereport(ERROR,
 
1684
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
1685
                                         errmsg("\"%s\" is a composite type",
 
1686
                                                        NameStr(pg_class_tuple->relname))));
 
1687
 
 
1688
                /* Used GRANT SEQUENCE on a non-sequence? */
 
1689
                if (istmt->objtype == ACL_OBJECT_SEQUENCE &&
 
1690
                        pg_class_tuple->relkind != RELKIND_SEQUENCE)
 
1691
                        ereport(ERROR,
 
1692
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
1693
                                         errmsg("\"%s\" is not a sequence",
 
1694
                                                        NameStr(pg_class_tuple->relname))));
 
1695
 
 
1696
                /* Adjust the default permissions based on object type */
 
1697
                if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
1698
                {
 
1699
                        if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
 
1700
                                this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
 
1701
                        else
 
1702
                                this_privileges = ACL_ALL_RIGHTS_RELATION;
 
1703
                }
 
1704
                else
 
1705
                        this_privileges = istmt->privileges;
 
1706
 
 
1707
                /*
 
1708
                 * The GRANT TABLE syntax can be used for sequences and non-sequences,
 
1709
                 * so we have to look at the relkind to determine the supported
 
1710
                 * permissions.  The OR of table and sequence permissions were already
 
1711
                 * checked.
 
1712
                 */
 
1713
                if (istmt->objtype == ACL_OBJECT_RELATION)
 
1714
                {
 
1715
                        if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
 
1716
                        {
 
1717
                                /*
 
1718
                                 * For backward compatibility, just throw a warning for
 
1719
                                 * invalid sequence permissions when using the non-sequence
 
1720
                                 * GRANT syntax.
 
1721
                                 */
 
1722
                                if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
 
1723
                                {
 
1724
                                        /*
 
1725
                                         * Mention the object name because the user needs to know
 
1726
                                         * which operations succeeded.  This is required because
 
1727
                                         * WARNING allows the command to continue.
 
1728
                                         */
 
1729
                                        ereport(WARNING,
 
1730
                                                        (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
1731
                                                         errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
 
1732
                                                                        NameStr(pg_class_tuple->relname))));
 
1733
                                        this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
 
1734
                                }
 
1735
                        }
 
1736
                        else
 
1737
                        {
 
1738
                                if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
 
1739
                                {
 
1740
                                        /*
 
1741
                                         * USAGE is the only permission supported by sequences but
 
1742
                                         * not by non-sequences.  Don't mention the object name
 
1743
                                         * because we didn't in the combined TABLE | SEQUENCE
 
1744
                                         * check.
 
1745
                                         */
 
1746
                                        ereport(ERROR,
 
1747
                                                        (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
1748
                                                  errmsg("invalid privilege type USAGE for table")));
 
1749
                                }
 
1750
                        }
 
1751
                }
 
1752
 
 
1753
                /*
 
1754
                 * Set up array in which we'll accumulate any column privilege bits
 
1755
                 * that need modification.      The array is indexed such that entry [0]
 
1756
                 * corresponds to FirstLowInvalidHeapAttributeNumber.
 
1757
                 */
 
1758
                num_col_privileges = pg_class_tuple->relnatts - FirstLowInvalidHeapAttributeNumber + 1;
 
1759
                col_privileges = (AclMode *) palloc0(num_col_privileges * sizeof(AclMode));
 
1760
                have_col_privileges = false;
 
1761
 
 
1762
                /*
 
1763
                 * If we are revoking relation privileges that are also column
 
1764
                 * privileges, we must implicitly revoke them from each column too,
 
1765
                 * per SQL spec.  (We don't need to implicitly add column privileges
 
1766
                 * during GRANT because the permissions-checking code always checks
 
1767
                 * both relation and per-column privileges.)
 
1768
                 */
 
1769
                if (!istmt->is_grant &&
 
1770
                        (this_privileges & ACL_ALL_RIGHTS_COLUMN) != 0)
 
1771
                {
 
1772
                        expand_all_col_privileges(relOid, pg_class_tuple,
 
1773
                                                                          this_privileges & ACL_ALL_RIGHTS_COLUMN,
 
1774
                                                                          col_privileges,
 
1775
                                                                          num_col_privileges);
 
1776
                        have_col_privileges = true;
 
1777
                }
 
1778
 
 
1779
                /*
 
1780
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
1781
                 * substitute the proper default.
 
1782
                 */
 
1783
                ownerId = pg_class_tuple->relowner;
 
1784
                aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
 
1785
                                                                   &isNull);
 
1786
                if (isNull)
 
1787
                {
 
1788
                        switch (pg_class_tuple->relkind)
 
1789
                        {
 
1790
                                case RELKIND_SEQUENCE:
 
1791
                                        old_acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);
 
1792
                                        break;
 
1793
                                default:
 
1794
                                        old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);
 
1795
                                        break;
 
1796
                        }
 
1797
                        /* There are no old member roles according to the catalogs */
 
1798
                        noldmembers = 0;
 
1799
                        oldmembers = NULL;
 
1800
                }
 
1801
                else
 
1802
                {
 
1803
                        old_acl = DatumGetAclPCopy(aclDatum);
 
1804
                        /* Get the roles mentioned in the existing ACL */
 
1805
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
1806
                }
 
1807
 
 
1808
                /* Need an extra copy of original rel ACL for column handling */
 
1809
                old_rel_acl = aclcopy(old_acl);
 
1810
 
 
1811
                /*
 
1812
                 * Handle relation-level privileges, if any were specified
 
1813
                 */
 
1814
                if (this_privileges != ACL_NO_RIGHTS)
 
1815
                {
 
1816
                        AclMode         avail_goptions;
 
1817
                        Acl                *new_acl;
 
1818
                        Oid                     grantorId;
 
1819
                        HeapTuple       newtuple;
 
1820
                        Datum           values[Natts_pg_class];
 
1821
                        bool            nulls[Natts_pg_class];
 
1822
                        bool            replaces[Natts_pg_class];
 
1823
                        int                     nnewmembers;
 
1824
                        Oid                *newmembers;
 
1825
                        AclObjectKind aclkind;
 
1826
 
 
1827
                        /* Determine ID to do the grant as, and available grant options */
 
1828
                        select_best_grantor(GetUserId(), this_privileges,
 
1829
                                                                old_acl, ownerId,
 
1830
                                                                &grantorId, &avail_goptions);
 
1831
 
 
1832
                        switch (pg_class_tuple->relkind)
 
1833
                        {
 
1834
                                case RELKIND_SEQUENCE:
 
1835
                                        aclkind = ACL_KIND_SEQUENCE;
 
1836
                                        break;
 
1837
                                default:
 
1838
                                        aclkind = ACL_KIND_CLASS;
 
1839
                                        break;
 
1840
                        }
 
1841
 
 
1842
                        /*
 
1843
                         * Restrict the privileges to what we can actually grant, and emit
 
1844
                         * the standards-mandated warning and error messages.
 
1845
                         */
 
1846
                        this_privileges =
 
1847
                                restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
1848
                                                                                 istmt->all_privs, this_privileges,
 
1849
                                                                                 relOid, grantorId, aclkind,
 
1850
                                                                                 NameStr(pg_class_tuple->relname),
 
1851
                                                                                 0, NULL);
 
1852
 
 
1853
                        /*
 
1854
                         * Generate new ACL.
 
1855
                         */
 
1856
                        new_acl = merge_acl_with_grant(old_acl,
 
1857
                                                                                   istmt->is_grant,
 
1858
                                                                                   istmt->grant_option,
 
1859
                                                                                   istmt->behavior,
 
1860
                                                                                   istmt->grantees,
 
1861
                                                                                   this_privileges,
 
1862
                                                                                   grantorId,
 
1863
                                                                                   ownerId);
 
1864
 
 
1865
                        /*
 
1866
                         * We need the members of both old and new ACLs so we can correct
 
1867
                         * the shared dependency information.
 
1868
                         */
 
1869
                        nnewmembers = aclmembers(new_acl, &newmembers);
 
1870
 
 
1871
                        /* finished building new ACL value, now insert it */
 
1872
                        MemSet(values, 0, sizeof(values));
 
1873
                        MemSet(nulls, false, sizeof(nulls));
 
1874
                        MemSet(replaces, false, sizeof(replaces));
 
1875
 
 
1876
                        replaces[Anum_pg_class_relacl - 1] = true;
 
1877
                        values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
 
1878
 
 
1879
                        newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
 
1880
                                                                                 values, nulls, replaces);
 
1881
 
 
1882
                        simple_heap_update(relation, &newtuple->t_self, newtuple);
 
1883
 
 
1884
                        /* keep the catalog indexes up to date */
 
1885
                        CatalogUpdateIndexes(relation, newtuple);
 
1886
 
 
1887
                        /* Update the shared dependency ACL info */
 
1888
                        updateAclDependencies(RelationRelationId, relOid, 0,
 
1889
                                                                  ownerId,
 
1890
                                                                  noldmembers, oldmembers,
 
1891
                                                                  nnewmembers, newmembers);
 
1892
 
 
1893
                        pfree(new_acl);
 
1894
                }
 
1895
 
 
1896
                /*
 
1897
                 * Handle column-level privileges, if any were specified or implied.
 
1898
                 * We first expand the user-specified column privileges into the
 
1899
                 * array, and then iterate over all nonempty array entries.
 
1900
                 */
 
1901
                foreach(cell_colprivs, istmt->col_privs)
 
1902
                {
 
1903
                        AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
 
1904
 
 
1905
                        if (col_privs->priv_name == NULL)
 
1906
                                this_privileges = ACL_ALL_RIGHTS_COLUMN;
 
1907
                        else
 
1908
                                this_privileges = string_to_privilege(col_privs->priv_name);
 
1909
 
 
1910
                        if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_COLUMN))
 
1911
                                ereport(ERROR,
 
1912
                                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
1913
                                                 errmsg("invalid privilege type %s for column",
 
1914
                                                                privilege_to_string(this_privileges))));
 
1915
 
 
1916
                        if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
 
1917
                                this_privileges & ~((AclMode) ACL_SELECT))
 
1918
                        {
 
1919
                                /*
 
1920
                                 * The only column privilege allowed on sequences is SELECT.
 
1921
                                 * This is a warning not error because we do it that way for
 
1922
                                 * relation-level privileges.
 
1923
                                 */
 
1924
                                ereport(WARNING,
 
1925
                                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
1926
                                                 errmsg("sequence \"%s\" only supports SELECT column privileges",
 
1927
                                                                NameStr(pg_class_tuple->relname))));
 
1928
 
 
1929
                                this_privileges &= (AclMode) ACL_SELECT;
 
1930
                        }
 
1931
 
 
1932
                        expand_col_privileges(col_privs->cols, relOid,
 
1933
                                                                  this_privileges,
 
1934
                                                                  col_privileges,
 
1935
                                                                  num_col_privileges);
 
1936
                        have_col_privileges = true;
 
1937
                }
 
1938
 
 
1939
                if (have_col_privileges)
 
1940
                {
 
1941
                        AttrNumber      i;
 
1942
 
 
1943
                        for (i = 0; i < num_col_privileges; i++)
 
1944
                        {
 
1945
                                if (col_privileges[i] == ACL_NO_RIGHTS)
 
1946
                                        continue;
 
1947
                                ExecGrant_Attribute(istmt,
 
1948
                                                                        relOid,
 
1949
                                                                        NameStr(pg_class_tuple->relname),
 
1950
                                                                        i + FirstLowInvalidHeapAttributeNumber,
 
1951
                                                                        ownerId,
 
1952
                                                                        col_privileges[i],
 
1953
                                                                        attRelation,
 
1954
                                                                        old_rel_acl);
 
1955
                        }
 
1956
                }
 
1957
 
 
1958
                pfree(old_rel_acl);
 
1959
                pfree(col_privileges);
 
1960
 
 
1961
                ReleaseSysCache(tuple);
 
1962
 
 
1963
                /* prevent error when processing duplicate objects */
 
1964
                CommandCounterIncrement();
 
1965
        }
 
1966
 
 
1967
        heap_close(attRelation, RowExclusiveLock);
 
1968
        heap_close(relation, RowExclusiveLock);
 
1969
}
 
1970
 
 
1971
static void
 
1972
ExecGrant_Database(InternalGrant *istmt)
 
1973
{
 
1974
        Relation        relation;
 
1975
        ListCell   *cell;
 
1976
 
 
1977
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
1978
                istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
 
1979
 
 
1980
        relation = heap_open(DatabaseRelationId, RowExclusiveLock);
 
1981
 
 
1982
        foreach(cell, istmt->objects)
 
1983
        {
 
1984
                Oid                     datId = lfirst_oid(cell);
 
1985
                Form_pg_database pg_database_tuple;
 
1986
                Datum           aclDatum;
 
1987
                bool            isNull;
 
1988
                AclMode         avail_goptions;
 
1989
                AclMode         this_privileges;
 
1990
                Acl                *old_acl;
 
1991
                Acl                *new_acl;
 
1992
                Oid                     grantorId;
 
1993
                Oid                     ownerId;
 
1994
                HeapTuple       newtuple;
 
1995
                Datum           values[Natts_pg_database];
 
1996
                bool            nulls[Natts_pg_database];
 
1997
                bool            replaces[Natts_pg_database];
 
1998
                int                     noldmembers;
 
1999
                int                     nnewmembers;
 
2000
                Oid                *oldmembers;
 
2001
                Oid                *newmembers;
 
2002
                HeapTuple       tuple;
 
2003
 
 
2004
                tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(datId));
 
2005
                if (!HeapTupleIsValid(tuple))
 
2006
                        elog(ERROR, "cache lookup failed for database %u", datId);
 
2007
 
 
2008
                pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
 
2009
 
 
2010
                /*
 
2011
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2012
                 * substitute the proper default.
 
2013
                 */
 
2014
                ownerId = pg_database_tuple->datdba;
 
2015
                aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
 
2016
                                                                RelationGetDescr(relation), &isNull);
 
2017
                if (isNull)
 
2018
                {
 
2019
                        old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
 
2020
                        /* There are no old member roles according to the catalogs */
 
2021
                        noldmembers = 0;
 
2022
                        oldmembers = NULL;
 
2023
                }
 
2024
                else
 
2025
                {
 
2026
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2027
                        /* Get the roles mentioned in the existing ACL */
 
2028
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2029
                }
 
2030
 
 
2031
                /* Determine ID to do the grant as, and available grant options */
 
2032
                select_best_grantor(GetUserId(), istmt->privileges,
 
2033
                                                        old_acl, ownerId,
 
2034
                                                        &grantorId, &avail_goptions);
 
2035
 
 
2036
                /*
 
2037
                 * Restrict the privileges to what we can actually grant, and emit the
 
2038
                 * standards-mandated warning and error messages.
 
2039
                 */
 
2040
                this_privileges =
 
2041
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2042
                                                                         istmt->all_privs, istmt->privileges,
 
2043
                                                                         datId, grantorId, ACL_KIND_DATABASE,
 
2044
                                                                         NameStr(pg_database_tuple->datname),
 
2045
                                                                         0, NULL);
 
2046
 
 
2047
                /*
 
2048
                 * Generate new ACL.
 
2049
                 */
 
2050
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2051
                                                                           istmt->grant_option, istmt->behavior,
 
2052
                                                                           istmt->grantees, this_privileges,
 
2053
                                                                           grantorId, ownerId);
 
2054
 
 
2055
                /*
 
2056
                 * We need the members of both old and new ACLs so we can correct the
 
2057
                 * shared dependency information.
 
2058
                 */
 
2059
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2060
 
 
2061
                /* finished building new ACL value, now insert it */
 
2062
                MemSet(values, 0, sizeof(values));
 
2063
                MemSet(nulls, false, sizeof(nulls));
 
2064
                MemSet(replaces, false, sizeof(replaces));
 
2065
 
 
2066
                replaces[Anum_pg_database_datacl - 1] = true;
 
2067
                values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
 
2068
 
 
2069
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2070
                                                                         nulls, replaces);
 
2071
 
 
2072
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2073
 
 
2074
                /* keep the catalog indexes up to date */
 
2075
                CatalogUpdateIndexes(relation, newtuple);
 
2076
 
 
2077
                /* Update the shared dependency ACL info */
 
2078
                updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple), 0,
 
2079
                                                          ownerId,
 
2080
                                                          noldmembers, oldmembers,
 
2081
                                                          nnewmembers, newmembers);
 
2082
 
 
2083
                ReleaseSysCache(tuple);
 
2084
 
 
2085
                pfree(new_acl);
 
2086
 
 
2087
                /* prevent error when processing duplicate objects */
 
2088
                CommandCounterIncrement();
 
2089
        }
 
2090
 
 
2091
        heap_close(relation, RowExclusiveLock);
 
2092
}
 
2093
 
 
2094
static void
 
2095
ExecGrant_Fdw(InternalGrant *istmt)
 
2096
{
 
2097
        Relation        relation;
 
2098
        ListCell   *cell;
 
2099
 
 
2100
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2101
                istmt->privileges = ACL_ALL_RIGHTS_FDW;
 
2102
 
 
2103
        relation = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
 
2104
 
 
2105
        foreach(cell, istmt->objects)
 
2106
        {
 
2107
                Oid                     fdwid = lfirst_oid(cell);
 
2108
                Form_pg_foreign_data_wrapper pg_fdw_tuple;
 
2109
                Datum           aclDatum;
 
2110
                bool            isNull;
 
2111
                AclMode         avail_goptions;
 
2112
                AclMode         this_privileges;
 
2113
                Acl                *old_acl;
 
2114
                Acl                *new_acl;
 
2115
                Oid                     grantorId;
 
2116
                Oid                     ownerId;
 
2117
                HeapTuple       tuple;
 
2118
                HeapTuple       newtuple;
 
2119
                Datum           values[Natts_pg_foreign_data_wrapper];
 
2120
                bool            nulls[Natts_pg_foreign_data_wrapper];
 
2121
                bool            replaces[Natts_pg_foreign_data_wrapper];
 
2122
                int                     noldmembers;
 
2123
                int                     nnewmembers;
 
2124
                Oid                *oldmembers;
 
2125
                Oid                *newmembers;
 
2126
 
 
2127
                tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
 
2128
                                                                ObjectIdGetDatum(fdwid));
 
2129
                if (!HeapTupleIsValid(tuple))
 
2130
                        elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
 
2131
 
 
2132
                pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
 
2133
 
 
2134
                /*
 
2135
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2136
                 * substitute the proper default.
 
2137
                 */
 
2138
                ownerId = pg_fdw_tuple->fdwowner;
 
2139
                aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
 
2140
                                                                   Anum_pg_foreign_data_wrapper_fdwacl,
 
2141
                                                                   &isNull);
 
2142
                if (isNull)
 
2143
                {
 
2144
                        old_acl = acldefault(ACL_OBJECT_FDW, ownerId);
 
2145
                        /* There are no old member roles according to the catalogs */
 
2146
                        noldmembers = 0;
 
2147
                        oldmembers = NULL;
 
2148
                }
 
2149
                else
 
2150
                {
 
2151
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2152
                        /* Get the roles mentioned in the existing ACL */
 
2153
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2154
                }
 
2155
 
 
2156
                /* Determine ID to do the grant as, and available grant options */
 
2157
                select_best_grantor(GetUserId(), istmt->privileges,
 
2158
                                                        old_acl, ownerId,
 
2159
                                                        &grantorId, &avail_goptions);
 
2160
 
 
2161
                /*
 
2162
                 * Restrict the privileges to what we can actually grant, and emit the
 
2163
                 * standards-mandated warning and error messages.
 
2164
                 */
 
2165
                this_privileges =
 
2166
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2167
                                                                         istmt->all_privs, istmt->privileges,
 
2168
                                                                         fdwid, grantorId, ACL_KIND_FDW,
 
2169
                                                                         NameStr(pg_fdw_tuple->fdwname),
 
2170
                                                                         0, NULL);
 
2171
 
 
2172
                /*
 
2173
                 * Generate new ACL.
 
2174
                 */
 
2175
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2176
                                                                           istmt->grant_option, istmt->behavior,
 
2177
                                                                           istmt->grantees, this_privileges,
 
2178
                                                                           grantorId, ownerId);
 
2179
 
 
2180
                /*
 
2181
                 * We need the members of both old and new ACLs so we can correct the
 
2182
                 * shared dependency information.
 
2183
                 */
 
2184
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2185
 
 
2186
                /* finished building new ACL value, now insert it */
 
2187
                MemSet(values, 0, sizeof(values));
 
2188
                MemSet(nulls, false, sizeof(nulls));
 
2189
                MemSet(replaces, false, sizeof(replaces));
 
2190
 
 
2191
                replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
 
2192
                values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
 
2193
 
 
2194
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2195
                                                                         nulls, replaces);
 
2196
 
 
2197
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2198
 
 
2199
                /* keep the catalog indexes up to date */
 
2200
                CatalogUpdateIndexes(relation, newtuple);
 
2201
 
 
2202
                /* Update the shared dependency ACL info */
 
2203
                updateAclDependencies(ForeignDataWrapperRelationId,
 
2204
                                                          HeapTupleGetOid(tuple), 0,
 
2205
                                                          ownerId,
 
2206
                                                          noldmembers, oldmembers,
 
2207
                                                          nnewmembers, newmembers);
 
2208
 
 
2209
                ReleaseSysCache(tuple);
 
2210
 
 
2211
                pfree(new_acl);
 
2212
 
 
2213
                /* prevent error when processing duplicate objects */
 
2214
                CommandCounterIncrement();
 
2215
        }
 
2216
 
 
2217
        heap_close(relation, RowExclusiveLock);
 
2218
}
 
2219
 
 
2220
static void
 
2221
ExecGrant_ForeignServer(InternalGrant *istmt)
 
2222
{
 
2223
        Relation        relation;
 
2224
        ListCell   *cell;
 
2225
 
 
2226
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2227
                istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 
2228
 
 
2229
        relation = heap_open(ForeignServerRelationId, RowExclusiveLock);
 
2230
 
 
2231
        foreach(cell, istmt->objects)
 
2232
        {
 
2233
                Oid                     srvid = lfirst_oid(cell);
 
2234
                Form_pg_foreign_server pg_server_tuple;
 
2235
                Datum           aclDatum;
 
2236
                bool            isNull;
 
2237
                AclMode         avail_goptions;
 
2238
                AclMode         this_privileges;
 
2239
                Acl                *old_acl;
 
2240
                Acl                *new_acl;
 
2241
                Oid                     grantorId;
 
2242
                Oid                     ownerId;
 
2243
                HeapTuple       tuple;
 
2244
                HeapTuple       newtuple;
 
2245
                Datum           values[Natts_pg_foreign_server];
 
2246
                bool            nulls[Natts_pg_foreign_server];
 
2247
                bool            replaces[Natts_pg_foreign_server];
 
2248
                int                     noldmembers;
 
2249
                int                     nnewmembers;
 
2250
                Oid                *oldmembers;
 
2251
                Oid                *newmembers;
 
2252
 
 
2253
                tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvid));
 
2254
                if (!HeapTupleIsValid(tuple))
 
2255
                        elog(ERROR, "cache lookup failed for foreign server %u", srvid);
 
2256
 
 
2257
                pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
 
2258
 
 
2259
                /*
 
2260
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2261
                 * substitute the proper default.
 
2262
                 */
 
2263
                ownerId = pg_server_tuple->srvowner;
 
2264
                aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
 
2265
                                                                   Anum_pg_foreign_server_srvacl,
 
2266
                                                                   &isNull);
 
2267
                if (isNull)
 
2268
                {
 
2269
                        old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
 
2270
                        /* There are no old member roles according to the catalogs */
 
2271
                        noldmembers = 0;
 
2272
                        oldmembers = NULL;
 
2273
                }
 
2274
                else
 
2275
                {
 
2276
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2277
                        /* Get the roles mentioned in the existing ACL */
 
2278
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2279
                }
 
2280
 
 
2281
                /* Determine ID to do the grant as, and available grant options */
 
2282
                select_best_grantor(GetUserId(), istmt->privileges,
 
2283
                                                        old_acl, ownerId,
 
2284
                                                        &grantorId, &avail_goptions);
 
2285
 
 
2286
                /*
 
2287
                 * Restrict the privileges to what we can actually grant, and emit the
 
2288
                 * standards-mandated warning and error messages.
 
2289
                 */
 
2290
                this_privileges =
 
2291
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2292
                                                                         istmt->all_privs, istmt->privileges,
 
2293
                                                                   srvid, grantorId, ACL_KIND_FOREIGN_SERVER,
 
2294
                                                                         NameStr(pg_server_tuple->srvname),
 
2295
                                                                         0, NULL);
 
2296
 
 
2297
                /*
 
2298
                 * Generate new ACL.
 
2299
                 */
 
2300
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2301
                                                                           istmt->grant_option, istmt->behavior,
 
2302
                                                                           istmt->grantees, this_privileges,
 
2303
                                                                           grantorId, ownerId);
 
2304
 
 
2305
                /*
 
2306
                 * We need the members of both old and new ACLs so we can correct the
 
2307
                 * shared dependency information.
 
2308
                 */
 
2309
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2310
 
 
2311
                /* finished building new ACL value, now insert it */
 
2312
                MemSet(values, 0, sizeof(values));
 
2313
                MemSet(nulls, false, sizeof(nulls));
 
2314
                MemSet(replaces, false, sizeof(replaces));
 
2315
 
 
2316
                replaces[Anum_pg_foreign_server_srvacl - 1] = true;
 
2317
                values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
 
2318
 
 
2319
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2320
                                                                         nulls, replaces);
 
2321
 
 
2322
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2323
 
 
2324
                /* keep the catalog indexes up to date */
 
2325
                CatalogUpdateIndexes(relation, newtuple);
 
2326
 
 
2327
                /* Update the shared dependency ACL info */
 
2328
                updateAclDependencies(ForeignServerRelationId,
 
2329
                                                          HeapTupleGetOid(tuple), 0,
 
2330
                                                          ownerId,
 
2331
                                                          noldmembers, oldmembers,
 
2332
                                                          nnewmembers, newmembers);
 
2333
 
 
2334
                ReleaseSysCache(tuple);
 
2335
 
 
2336
                pfree(new_acl);
 
2337
 
 
2338
                /* prevent error when processing duplicate objects */
 
2339
                CommandCounterIncrement();
 
2340
        }
 
2341
 
 
2342
        heap_close(relation, RowExclusiveLock);
 
2343
}
 
2344
 
 
2345
static void
 
2346
ExecGrant_Function(InternalGrant *istmt)
 
2347
{
 
2348
        Relation        relation;
 
2349
        ListCell   *cell;
 
2350
 
 
2351
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2352
                istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
 
2353
 
 
2354
        relation = heap_open(ProcedureRelationId, RowExclusiveLock);
 
2355
 
 
2356
        foreach(cell, istmt->objects)
 
2357
        {
 
2358
                Oid                     funcId = lfirst_oid(cell);
 
2359
                Form_pg_proc pg_proc_tuple;
 
2360
                Datum           aclDatum;
 
2361
                bool            isNull;
 
2362
                AclMode         avail_goptions;
 
2363
                AclMode         this_privileges;
 
2364
                Acl                *old_acl;
 
2365
                Acl                *new_acl;
 
2366
                Oid                     grantorId;
 
2367
                Oid                     ownerId;
 
2368
                HeapTuple       tuple;
 
2369
                HeapTuple       newtuple;
 
2370
                Datum           values[Natts_pg_proc];
 
2371
                bool            nulls[Natts_pg_proc];
 
2372
                bool            replaces[Natts_pg_proc];
 
2373
                int                     noldmembers;
 
2374
                int                     nnewmembers;
 
2375
                Oid                *oldmembers;
 
2376
                Oid                *newmembers;
 
2377
 
 
2378
                tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcId));
 
2379
                if (!HeapTupleIsValid(tuple))
 
2380
                        elog(ERROR, "cache lookup failed for function %u", funcId);
 
2381
 
 
2382
                pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple);
 
2383
 
 
2384
                /*
 
2385
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2386
                 * substitute the proper default.
 
2387
                 */
 
2388
                ownerId = pg_proc_tuple->proowner;
 
2389
                aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
 
2390
                                                                   &isNull);
 
2391
                if (isNull)
 
2392
                {
 
2393
                        old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
 
2394
                        /* There are no old member roles according to the catalogs */
 
2395
                        noldmembers = 0;
 
2396
                        oldmembers = NULL;
 
2397
                }
 
2398
                else
 
2399
                {
 
2400
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2401
                        /* Get the roles mentioned in the existing ACL */
 
2402
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2403
                }
 
2404
 
 
2405
                /* Determine ID to do the grant as, and available grant options */
 
2406
                select_best_grantor(GetUserId(), istmt->privileges,
 
2407
                                                        old_acl, ownerId,
 
2408
                                                        &grantorId, &avail_goptions);
 
2409
 
 
2410
                /*
 
2411
                 * Restrict the privileges to what we can actually grant, and emit the
 
2412
                 * standards-mandated warning and error messages.
 
2413
                 */
 
2414
                this_privileges =
 
2415
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2416
                                                                         istmt->all_privs, istmt->privileges,
 
2417
                                                                         funcId, grantorId, ACL_KIND_PROC,
 
2418
                                                                         NameStr(pg_proc_tuple->proname),
 
2419
                                                                         0, NULL);
 
2420
 
 
2421
                /*
 
2422
                 * Generate new ACL.
 
2423
                 */
 
2424
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2425
                                                                           istmt->grant_option, istmt->behavior,
 
2426
                                                                           istmt->grantees, this_privileges,
 
2427
                                                                           grantorId, ownerId);
 
2428
 
 
2429
                /*
 
2430
                 * We need the members of both old and new ACLs so we can correct the
 
2431
                 * shared dependency information.
 
2432
                 */
 
2433
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2434
 
 
2435
                /* finished building new ACL value, now insert it */
 
2436
                MemSet(values, 0, sizeof(values));
 
2437
                MemSet(nulls, false, sizeof(nulls));
 
2438
                MemSet(replaces, false, sizeof(replaces));
 
2439
 
 
2440
                replaces[Anum_pg_proc_proacl - 1] = true;
 
2441
                values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl);
 
2442
 
 
2443
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2444
                                                                         nulls, replaces);
 
2445
 
 
2446
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2447
 
 
2448
                /* keep the catalog indexes up to date */
 
2449
                CatalogUpdateIndexes(relation, newtuple);
 
2450
 
 
2451
                /* Update the shared dependency ACL info */
 
2452
                updateAclDependencies(ProcedureRelationId, funcId, 0,
 
2453
                                                          ownerId,
 
2454
                                                          noldmembers, oldmembers,
 
2455
                                                          nnewmembers, newmembers);
 
2456
 
 
2457
                ReleaseSysCache(tuple);
 
2458
 
 
2459
                pfree(new_acl);
 
2460
 
 
2461
                /* prevent error when processing duplicate objects */
 
2462
                CommandCounterIncrement();
 
2463
        }
 
2464
 
 
2465
        heap_close(relation, RowExclusiveLock);
 
2466
}
 
2467
 
 
2468
static void
 
2469
ExecGrant_Language(InternalGrant *istmt)
 
2470
{
 
2471
        Relation        relation;
 
2472
        ListCell   *cell;
 
2473
 
 
2474
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2475
                istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
 
2476
 
 
2477
        relation = heap_open(LanguageRelationId, RowExclusiveLock);
 
2478
 
 
2479
        foreach(cell, istmt->objects)
 
2480
        {
 
2481
                Oid                     langId = lfirst_oid(cell);
 
2482
                Form_pg_language pg_language_tuple;
 
2483
                Datum           aclDatum;
 
2484
                bool            isNull;
 
2485
                AclMode         avail_goptions;
 
2486
                AclMode         this_privileges;
 
2487
                Acl                *old_acl;
 
2488
                Acl                *new_acl;
 
2489
                Oid                     grantorId;
 
2490
                Oid                     ownerId;
 
2491
                HeapTuple       tuple;
 
2492
                HeapTuple       newtuple;
 
2493
                Datum           values[Natts_pg_language];
 
2494
                bool            nulls[Natts_pg_language];
 
2495
                bool            replaces[Natts_pg_language];
 
2496
                int                     noldmembers;
 
2497
                int                     nnewmembers;
 
2498
                Oid                *oldmembers;
 
2499
                Oid                *newmembers;
 
2500
 
 
2501
                tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(langId));
 
2502
                if (!HeapTupleIsValid(tuple))
 
2503
                        elog(ERROR, "cache lookup failed for language %u", langId);
 
2504
 
 
2505
                pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
 
2506
 
 
2507
                if (!pg_language_tuple->lanpltrusted)
 
2508
                        ereport(ERROR,
 
2509
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
2510
                                         errmsg("language \"%s\" is not trusted",
 
2511
                                                        NameStr(pg_language_tuple->lanname)),
 
2512
                                   errhint("Only superusers can use untrusted languages.")));
 
2513
 
 
2514
                /*
 
2515
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2516
                 * substitute the proper default.
 
2517
                 */
 
2518
                ownerId = pg_language_tuple->lanowner;
 
2519
                aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
 
2520
                                                                   &isNull);
 
2521
                if (isNull)
 
2522
                {
 
2523
                        old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
 
2524
                        /* There are no old member roles according to the catalogs */
 
2525
                        noldmembers = 0;
 
2526
                        oldmembers = NULL;
 
2527
                }
 
2528
                else
 
2529
                {
 
2530
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2531
                        /* Get the roles mentioned in the existing ACL */
 
2532
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2533
                }
 
2534
 
 
2535
                /* Determine ID to do the grant as, and available grant options */
 
2536
                select_best_grantor(GetUserId(), istmt->privileges,
 
2537
                                                        old_acl, ownerId,
 
2538
                                                        &grantorId, &avail_goptions);
 
2539
 
 
2540
                /*
 
2541
                 * Restrict the privileges to what we can actually grant, and emit the
 
2542
                 * standards-mandated warning and error messages.
 
2543
                 */
 
2544
                this_privileges =
 
2545
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2546
                                                                         istmt->all_privs, istmt->privileges,
 
2547
                                                                         langId, grantorId, ACL_KIND_LANGUAGE,
 
2548
                                                                         NameStr(pg_language_tuple->lanname),
 
2549
                                                                         0, NULL);
 
2550
 
 
2551
                /*
 
2552
                 * Generate new ACL.
 
2553
                 */
 
2554
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2555
                                                                           istmt->grant_option, istmt->behavior,
 
2556
                                                                           istmt->grantees, this_privileges,
 
2557
                                                                           grantorId, ownerId);
 
2558
 
 
2559
                /*
 
2560
                 * We need the members of both old and new ACLs so we can correct the
 
2561
                 * shared dependency information.
 
2562
                 */
 
2563
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2564
 
 
2565
                /* finished building new ACL value, now insert it */
 
2566
                MemSet(values, 0, sizeof(values));
 
2567
                MemSet(nulls, false, sizeof(nulls));
 
2568
                MemSet(replaces, false, sizeof(replaces));
 
2569
 
 
2570
                replaces[Anum_pg_language_lanacl - 1] = true;
 
2571
                values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl);
 
2572
 
 
2573
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2574
                                                                         nulls, replaces);
 
2575
 
 
2576
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2577
 
 
2578
                /* keep the catalog indexes up to date */
 
2579
                CatalogUpdateIndexes(relation, newtuple);
 
2580
 
 
2581
                /* Update the shared dependency ACL info */
 
2582
                updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0,
 
2583
                                                          ownerId,
 
2584
                                                          noldmembers, oldmembers,
 
2585
                                                          nnewmembers, newmembers);
 
2586
 
 
2587
                ReleaseSysCache(tuple);
 
2588
 
 
2589
                pfree(new_acl);
 
2590
 
 
2591
                /* prevent error when processing duplicate objects */
 
2592
                CommandCounterIncrement();
 
2593
        }
 
2594
 
 
2595
        heap_close(relation, RowExclusiveLock);
 
2596
}
 
2597
 
 
2598
static void
 
2599
ExecGrant_Largeobject(InternalGrant *istmt)
 
2600
{
 
2601
        Relation        relation;
 
2602
        ListCell   *cell;
 
2603
 
 
2604
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2605
                istmt->privileges = ACL_ALL_RIGHTS_LARGEOBJECT;
 
2606
 
 
2607
        relation = heap_open(LargeObjectMetadataRelationId,
 
2608
                                                 RowExclusiveLock);
 
2609
 
 
2610
        foreach(cell, istmt->objects)
 
2611
        {
 
2612
                Oid                     loid = lfirst_oid(cell);
 
2613
                Form_pg_largeobject_metadata form_lo_meta;
 
2614
                char            loname[NAMEDATALEN];
 
2615
                Datum           aclDatum;
 
2616
                bool            isNull;
 
2617
                AclMode         avail_goptions;
 
2618
                AclMode         this_privileges;
 
2619
                Acl                *old_acl;
 
2620
                Acl                *new_acl;
 
2621
                Oid                     grantorId;
 
2622
                Oid                     ownerId;
 
2623
                HeapTuple       newtuple;
 
2624
                Datum           values[Natts_pg_largeobject_metadata];
 
2625
                bool            nulls[Natts_pg_largeobject_metadata];
 
2626
                bool            replaces[Natts_pg_largeobject_metadata];
 
2627
                int                     noldmembers;
 
2628
                int                     nnewmembers;
 
2629
                Oid                *oldmembers;
 
2630
                Oid                *newmembers;
 
2631
                ScanKeyData entry[1];
 
2632
                SysScanDesc scan;
 
2633
                HeapTuple       tuple;
 
2634
 
 
2635
                /* There's no syscache for pg_largeobject_metadata */
 
2636
                ScanKeyInit(&entry[0],
 
2637
                                        ObjectIdAttributeNumber,
 
2638
                                        BTEqualStrategyNumber, F_OIDEQ,
 
2639
                                        ObjectIdGetDatum(loid));
 
2640
 
 
2641
                scan = systable_beginscan(relation,
 
2642
                                                                  LargeObjectMetadataOidIndexId, true,
 
2643
                                                                  SnapshotNow, 1, entry);
 
2644
 
 
2645
                tuple = systable_getnext(scan);
 
2646
                if (!HeapTupleIsValid(tuple))
 
2647
                        elog(ERROR, "cache lookup failed for large object %u", loid);
 
2648
 
 
2649
                form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(tuple);
 
2650
 
 
2651
                /*
 
2652
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2653
                 * substitute the proper default.
 
2654
                 */
 
2655
                ownerId = form_lo_meta->lomowner;
 
2656
                aclDatum = heap_getattr(tuple,
 
2657
                                                                Anum_pg_largeobject_metadata_lomacl,
 
2658
                                                                RelationGetDescr(relation), &isNull);
 
2659
                if (isNull)
 
2660
                {
 
2661
                        old_acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
 
2662
                        /* There are no old member roles according to the catalogs */
 
2663
                        noldmembers = 0;
 
2664
                        oldmembers = NULL;
 
2665
                }
 
2666
                else
 
2667
                {
 
2668
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2669
                        /* Get the roles mentioned in the existing ACL */
 
2670
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2671
                }
 
2672
 
 
2673
                /* Determine ID to do the grant as, and available grant options */
 
2674
                select_best_grantor(GetUserId(), istmt->privileges,
 
2675
                                                        old_acl, ownerId,
 
2676
                                                        &grantorId, &avail_goptions);
 
2677
 
 
2678
                /*
 
2679
                 * Restrict the privileges to what we can actually grant, and emit the
 
2680
                 * standards-mandated warning and error messages.
 
2681
                 */
 
2682
                snprintf(loname, sizeof(loname), "large object %u", loid);
 
2683
                this_privileges =
 
2684
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2685
                                                                         istmt->all_privs, istmt->privileges,
 
2686
                                                                         loid, grantorId, ACL_KIND_LARGEOBJECT,
 
2687
                                                                         loname, 0, NULL);
 
2688
 
 
2689
                /*
 
2690
                 * Generate new ACL.
 
2691
                 */
 
2692
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2693
                                                                           istmt->grant_option, istmt->behavior,
 
2694
                                                                           istmt->grantees, this_privileges,
 
2695
                                                                           grantorId, ownerId);
 
2696
 
 
2697
                /*
 
2698
                 * We need the members of both old and new ACLs so we can correct the
 
2699
                 * shared dependency information.
 
2700
                 */
 
2701
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2702
 
 
2703
                /* finished building new ACL value, now insert it */
 
2704
                MemSet(values, 0, sizeof(values));
 
2705
                MemSet(nulls, false, sizeof(nulls));
 
2706
                MemSet(replaces, false, sizeof(replaces));
 
2707
 
 
2708
                replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
 
2709
                values[Anum_pg_largeobject_metadata_lomacl - 1]
 
2710
                        = PointerGetDatum(new_acl);
 
2711
 
 
2712
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation),
 
2713
                                                                         values, nulls, replaces);
 
2714
 
 
2715
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2716
 
 
2717
                /* keep the catalog indexes up to date */
 
2718
                CatalogUpdateIndexes(relation, newtuple);
 
2719
 
 
2720
                /* Update the shared dependency ACL info */
 
2721
                updateAclDependencies(LargeObjectRelationId,
 
2722
                                                          HeapTupleGetOid(tuple), 0,
 
2723
                                                          ownerId,
 
2724
                                                          noldmembers, oldmembers,
 
2725
                                                          nnewmembers, newmembers);
 
2726
 
 
2727
                systable_endscan(scan);
 
2728
 
 
2729
                pfree(new_acl);
 
2730
 
 
2731
                /* prevent error when processing duplicate objects */
 
2732
                CommandCounterIncrement();
 
2733
        }
 
2734
 
 
2735
        heap_close(relation, RowExclusiveLock);
 
2736
}
 
2737
 
 
2738
static void
 
2739
ExecGrant_Namespace(InternalGrant *istmt)
 
2740
{
 
2741
        Relation        relation;
 
2742
        ListCell   *cell;
 
2743
 
 
2744
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2745
                istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
 
2746
 
 
2747
        relation = heap_open(NamespaceRelationId, RowExclusiveLock);
 
2748
 
 
2749
        foreach(cell, istmt->objects)
 
2750
        {
 
2751
                Oid                     nspid = lfirst_oid(cell);
 
2752
                Form_pg_namespace pg_namespace_tuple;
 
2753
                Datum           aclDatum;
 
2754
                bool            isNull;
 
2755
                AclMode         avail_goptions;
 
2756
                AclMode         this_privileges;
 
2757
                Acl                *old_acl;
 
2758
                Acl                *new_acl;
 
2759
                Oid                     grantorId;
 
2760
                Oid                     ownerId;
 
2761
                HeapTuple       tuple;
 
2762
                HeapTuple       newtuple;
 
2763
                Datum           values[Natts_pg_namespace];
 
2764
                bool            nulls[Natts_pg_namespace];
 
2765
                bool            replaces[Natts_pg_namespace];
 
2766
                int                     noldmembers;
 
2767
                int                     nnewmembers;
 
2768
                Oid                *oldmembers;
 
2769
                Oid                *newmembers;
 
2770
 
 
2771
                tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
 
2772
                if (!HeapTupleIsValid(tuple))
 
2773
                        elog(ERROR, "cache lookup failed for namespace %u", nspid);
 
2774
 
 
2775
                pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
 
2776
 
 
2777
                /*
 
2778
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2779
                 * substitute the proper default.
 
2780
                 */
 
2781
                ownerId = pg_namespace_tuple->nspowner;
 
2782
                aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
 
2783
                                                                   Anum_pg_namespace_nspacl,
 
2784
                                                                   &isNull);
 
2785
                if (isNull)
 
2786
                {
 
2787
                        old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
 
2788
                        /* There are no old member roles according to the catalogs */
 
2789
                        noldmembers = 0;
 
2790
                        oldmembers = NULL;
 
2791
                }
 
2792
                else
 
2793
                {
 
2794
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2795
                        /* Get the roles mentioned in the existing ACL */
 
2796
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2797
                }
 
2798
 
 
2799
                /* Determine ID to do the grant as, and available grant options */
 
2800
                select_best_grantor(GetUserId(), istmt->privileges,
 
2801
                                                        old_acl, ownerId,
 
2802
                                                        &grantorId, &avail_goptions);
 
2803
 
 
2804
                /*
 
2805
                 * Restrict the privileges to what we can actually grant, and emit the
 
2806
                 * standards-mandated warning and error messages.
 
2807
                 */
 
2808
                this_privileges =
 
2809
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2810
                                                                         istmt->all_privs, istmt->privileges,
 
2811
                                                                         nspid, grantorId, ACL_KIND_NAMESPACE,
 
2812
                                                                         NameStr(pg_namespace_tuple->nspname),
 
2813
                                                                         0, NULL);
 
2814
 
 
2815
                /*
 
2816
                 * Generate new ACL.
 
2817
                 */
 
2818
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2819
                                                                           istmt->grant_option, istmt->behavior,
 
2820
                                                                           istmt->grantees, this_privileges,
 
2821
                                                                           grantorId, ownerId);
 
2822
 
 
2823
                /*
 
2824
                 * We need the members of both old and new ACLs so we can correct the
 
2825
                 * shared dependency information.
 
2826
                 */
 
2827
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2828
 
 
2829
                /* finished building new ACL value, now insert it */
 
2830
                MemSet(values, 0, sizeof(values));
 
2831
                MemSet(nulls, false, sizeof(nulls));
 
2832
                MemSet(replaces, false, sizeof(replaces));
 
2833
 
 
2834
                replaces[Anum_pg_namespace_nspacl - 1] = true;
 
2835
                values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl);
 
2836
 
 
2837
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2838
                                                                         nulls, replaces);
 
2839
 
 
2840
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2841
 
 
2842
                /* keep the catalog indexes up to date */
 
2843
                CatalogUpdateIndexes(relation, newtuple);
 
2844
 
 
2845
                /* Update the shared dependency ACL info */
 
2846
                updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0,
 
2847
                                                          ownerId,
 
2848
                                                          noldmembers, oldmembers,
 
2849
                                                          nnewmembers, newmembers);
 
2850
 
 
2851
                ReleaseSysCache(tuple);
 
2852
 
 
2853
                pfree(new_acl);
 
2854
 
 
2855
                /* prevent error when processing duplicate objects */
 
2856
                CommandCounterIncrement();
 
2857
        }
 
2858
 
 
2859
        heap_close(relation, RowExclusiveLock);
 
2860
}
 
2861
 
 
2862
static void
 
2863
ExecGrant_Tablespace(InternalGrant *istmt)
 
2864
{
 
2865
        Relation        relation;
 
2866
        ListCell   *cell;
 
2867
 
 
2868
        if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 
2869
                istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
 
2870
 
 
2871
        relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
 
2872
 
 
2873
        foreach(cell, istmt->objects)
 
2874
        {
 
2875
                Oid                     tblId = lfirst_oid(cell);
 
2876
                Form_pg_tablespace pg_tablespace_tuple;
 
2877
                Datum           aclDatum;
 
2878
                bool            isNull;
 
2879
                AclMode         avail_goptions;
 
2880
                AclMode         this_privileges;
 
2881
                Acl                *old_acl;
 
2882
                Acl                *new_acl;
 
2883
                Oid                     grantorId;
 
2884
                Oid                     ownerId;
 
2885
                HeapTuple       newtuple;
 
2886
                Datum           values[Natts_pg_tablespace];
 
2887
                bool            nulls[Natts_pg_tablespace];
 
2888
                bool            replaces[Natts_pg_tablespace];
 
2889
                int                     noldmembers;
 
2890
                int                     nnewmembers;
 
2891
                Oid                *oldmembers;
 
2892
                Oid                *newmembers;
 
2893
                HeapTuple       tuple;
 
2894
 
 
2895
                /* Search syscache for pg_tablespace */
 
2896
                tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(tblId));
 
2897
                if (!HeapTupleIsValid(tuple))
 
2898
                        elog(ERROR, "cache lookup failed for tablespace %u", tblId);
 
2899
 
 
2900
                pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
 
2901
 
 
2902
                /*
 
2903
                 * Get owner ID and working copy of existing ACL. If there's no ACL,
 
2904
                 * substitute the proper default.
 
2905
                 */
 
2906
                ownerId = pg_tablespace_tuple->spcowner;
 
2907
                aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
 
2908
                                                                RelationGetDescr(relation), &isNull);
 
2909
                if (isNull)
 
2910
                {
 
2911
                        old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
 
2912
                        /* There are no old member roles according to the catalogs */
 
2913
                        noldmembers = 0;
 
2914
                        oldmembers = NULL;
 
2915
                }
 
2916
                else
 
2917
                {
 
2918
                        old_acl = DatumGetAclPCopy(aclDatum);
 
2919
                        /* Get the roles mentioned in the existing ACL */
 
2920
                        noldmembers = aclmembers(old_acl, &oldmembers);
 
2921
                }
 
2922
 
 
2923
                /* Determine ID to do the grant as, and available grant options */
 
2924
                select_best_grantor(GetUserId(), istmt->privileges,
 
2925
                                                        old_acl, ownerId,
 
2926
                                                        &grantorId, &avail_goptions);
 
2927
 
 
2928
                /*
 
2929
                 * Restrict the privileges to what we can actually grant, and emit the
 
2930
                 * standards-mandated warning and error messages.
 
2931
                 */
 
2932
                this_privileges =
 
2933
                        restrict_and_check_grant(istmt->is_grant, avail_goptions,
 
2934
                                                                         istmt->all_privs, istmt->privileges,
 
2935
                                                                         tblId, grantorId, ACL_KIND_TABLESPACE,
 
2936
                                                                         NameStr(pg_tablespace_tuple->spcname),
 
2937
                                                                         0, NULL);
 
2938
 
 
2939
                /*
 
2940
                 * Generate new ACL.
 
2941
                 */
 
2942
                new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
 
2943
                                                                           istmt->grant_option, istmt->behavior,
 
2944
                                                                           istmt->grantees, this_privileges,
 
2945
                                                                           grantorId, ownerId);
 
2946
 
 
2947
                /*
 
2948
                 * We need the members of both old and new ACLs so we can correct the
 
2949
                 * shared dependency information.
 
2950
                 */
 
2951
                nnewmembers = aclmembers(new_acl, &newmembers);
 
2952
 
 
2953
                /* finished building new ACL value, now insert it */
 
2954
                MemSet(values, 0, sizeof(values));
 
2955
                MemSet(nulls, false, sizeof(nulls));
 
2956
                MemSet(replaces, false, sizeof(replaces));
 
2957
 
 
2958
                replaces[Anum_pg_tablespace_spcacl - 1] = true;
 
2959
                values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
 
2960
 
 
2961
                newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
 
2962
                                                                         nulls, replaces);
 
2963
 
 
2964
                simple_heap_update(relation, &newtuple->t_self, newtuple);
 
2965
 
 
2966
                /* keep the catalog indexes up to date */
 
2967
                CatalogUpdateIndexes(relation, newtuple);
 
2968
 
 
2969
                /* Update the shared dependency ACL info */
 
2970
                updateAclDependencies(TableSpaceRelationId, tblId, 0,
 
2971
                                                          ownerId,
 
2972
                                                          noldmembers, oldmembers,
 
2973
                                                          nnewmembers, newmembers);
 
2974
 
 
2975
                ReleaseSysCache(tuple);
 
2976
                pfree(new_acl);
 
2977
 
 
2978
                /* prevent error when processing duplicate objects */
 
2979
                CommandCounterIncrement();
 
2980
        }
 
2981
 
 
2982
        heap_close(relation, RowExclusiveLock);
 
2983
}
 
2984
 
 
2985
 
 
2986
static AclMode
 
2987
string_to_privilege(const char *privname)
 
2988
{
 
2989
        if (strcmp(privname, "insert") == 0)
 
2990
                return ACL_INSERT;
 
2991
        if (strcmp(privname, "select") == 0)
 
2992
                return ACL_SELECT;
 
2993
        if (strcmp(privname, "update") == 0)
 
2994
                return ACL_UPDATE;
 
2995
        if (strcmp(privname, "delete") == 0)
 
2996
                return ACL_DELETE;
 
2997
        if (strcmp(privname, "truncate") == 0)
 
2998
                return ACL_TRUNCATE;
 
2999
        if (strcmp(privname, "references") == 0)
 
3000
                return ACL_REFERENCES;
 
3001
        if (strcmp(privname, "trigger") == 0)
 
3002
                return ACL_TRIGGER;
 
3003
        if (strcmp(privname, "execute") == 0)
 
3004
                return ACL_EXECUTE;
 
3005
        if (strcmp(privname, "usage") == 0)
 
3006
                return ACL_USAGE;
 
3007
        if (strcmp(privname, "create") == 0)
 
3008
                return ACL_CREATE;
 
3009
        if (strcmp(privname, "temporary") == 0)
 
3010
                return ACL_CREATE_TEMP;
 
3011
        if (strcmp(privname, "temp") == 0)
 
3012
                return ACL_CREATE_TEMP;
 
3013
        if (strcmp(privname, "connect") == 0)
 
3014
                return ACL_CONNECT;
 
3015
        if (strcmp(privname, "rule") == 0)
 
3016
                return 0;                               /* ignore old RULE privileges */
 
3017
        ereport(ERROR,
 
3018
                        (errcode(ERRCODE_SYNTAX_ERROR),
 
3019
                         errmsg("unrecognized privilege type \"%s\"", privname)));
 
3020
        return 0;                                       /* appease compiler */
 
3021
}
 
3022
 
 
3023
static const char *
 
3024
privilege_to_string(AclMode privilege)
 
3025
{
 
3026
        switch (privilege)
 
3027
        {
 
3028
                case ACL_INSERT:
 
3029
                        return "INSERT";
 
3030
                case ACL_SELECT:
 
3031
                        return "SELECT";
 
3032
                case ACL_UPDATE:
 
3033
                        return "UPDATE";
 
3034
                case ACL_DELETE:
 
3035
                        return "DELETE";
 
3036
                case ACL_TRUNCATE:
 
3037
                        return "TRUNCATE";
 
3038
                case ACL_REFERENCES:
 
3039
                        return "REFERENCES";
 
3040
                case ACL_TRIGGER:
 
3041
                        return "TRIGGER";
 
3042
                case ACL_EXECUTE:
 
3043
                        return "EXECUTE";
 
3044
                case ACL_USAGE:
 
3045
                        return "USAGE";
 
3046
                case ACL_CREATE:
 
3047
                        return "CREATE";
 
3048
                case ACL_CREATE_TEMP:
 
3049
                        return "TEMP";
 
3050
                case ACL_CONNECT:
 
3051
                        return "CONNECT";
 
3052
                default:
 
3053
                        elog(ERROR, "unrecognized privilege: %d", (int) privilege);
 
3054
        }
 
3055
        return NULL;                            /* appease compiler */
 
3056
}
 
3057
 
 
3058
/*
 
3059
 * Standardized reporting of aclcheck permissions failures.
 
3060
 *
 
3061
 * Note: we do not double-quote the %s's below, because many callers
 
3062
 * supply strings that might be already quoted.
 
3063
 */
 
3064
 
 
3065
static const char *const no_priv_msg[MAX_ACL_KIND] =
 
3066
{
 
3067
        /* ACL_KIND_COLUMN */
 
3068
        gettext_noop("permission denied for column %s"),
 
3069
        /* ACL_KIND_CLASS */
 
3070
        gettext_noop("permission denied for relation %s"),
 
3071
        /* ACL_KIND_SEQUENCE */
 
3072
        gettext_noop("permission denied for sequence %s"),
 
3073
        /* ACL_KIND_DATABASE */
 
3074
        gettext_noop("permission denied for database %s"),
 
3075
        /* ACL_KIND_PROC */
 
3076
        gettext_noop("permission denied for function %s"),
 
3077
        /* ACL_KIND_OPER */
 
3078
        gettext_noop("permission denied for operator %s"),
 
3079
        /* ACL_KIND_TYPE */
 
3080
        gettext_noop("permission denied for type %s"),
 
3081
        /* ACL_KIND_LANGUAGE */
 
3082
        gettext_noop("permission denied for language %s"),
 
3083
        /* ACL_KIND_LARGEOBJECT */
 
3084
        gettext_noop("permission denied for large object %s"),
 
3085
        /* ACL_KIND_NAMESPACE */
 
3086
        gettext_noop("permission denied for schema %s"),
 
3087
        /* ACL_KIND_OPCLASS */
 
3088
        gettext_noop("permission denied for operator class %s"),
 
3089
        /* ACL_KIND_OPFAMILY */
 
3090
        gettext_noop("permission denied for operator family %s"),
 
3091
        /* ACL_KIND_COLLATION */
 
3092
        gettext_noop("permission denied for collation %s"),
 
3093
        /* ACL_KIND_CONVERSION */
 
3094
        gettext_noop("permission denied for conversion %s"),
 
3095
        /* ACL_KIND_TABLESPACE */
 
3096
        gettext_noop("permission denied for tablespace %s"),
 
3097
        /* ACL_KIND_TSDICTIONARY */
 
3098
        gettext_noop("permission denied for text search dictionary %s"),
 
3099
        /* ACL_KIND_TSCONFIGURATION */
 
3100
        gettext_noop("permission denied for text search configuration %s"),
 
3101
        /* ACL_KIND_FDW */
 
3102
        gettext_noop("permission denied for foreign-data wrapper %s"),
 
3103
        /* ACL_KIND_FOREIGN_SERVER */
 
3104
        gettext_noop("permission denied for foreign server %s"),
 
3105
        /* ACL_KIND_EXTENSION */
 
3106
        gettext_noop("permission denied for extension %s"),
 
3107
};
 
3108
 
 
3109
static const char *const not_owner_msg[MAX_ACL_KIND] =
 
3110
{
 
3111
        /* ACL_KIND_COLUMN */
 
3112
        gettext_noop("must be owner of relation %s"),
 
3113
        /* ACL_KIND_CLASS */
 
3114
        gettext_noop("must be owner of relation %s"),
 
3115
        /* ACL_KIND_SEQUENCE */
 
3116
        gettext_noop("must be owner of sequence %s"),
 
3117
        /* ACL_KIND_DATABASE */
 
3118
        gettext_noop("must be owner of database %s"),
 
3119
        /* ACL_KIND_PROC */
 
3120
        gettext_noop("must be owner of function %s"),
 
3121
        /* ACL_KIND_OPER */
 
3122
        gettext_noop("must be owner of operator %s"),
 
3123
        /* ACL_KIND_TYPE */
 
3124
        gettext_noop("must be owner of type %s"),
 
3125
        /* ACL_KIND_LANGUAGE */
 
3126
        gettext_noop("must be owner of language %s"),
 
3127
        /* ACL_KIND_LARGEOBJECT */
 
3128
        gettext_noop("must be owner of large object %s"),
 
3129
        /* ACL_KIND_NAMESPACE */
 
3130
        gettext_noop("must be owner of schema %s"),
 
3131
        /* ACL_KIND_OPCLASS */
 
3132
        gettext_noop("must be owner of operator class %s"),
 
3133
        /* ACL_KIND_OPFAMILY */
 
3134
        gettext_noop("must be owner of operator family %s"),
 
3135
        /* ACL_KIND_COLLATION */
 
3136
        gettext_noop("must be owner of collation %s"),
 
3137
        /* ACL_KIND_CONVERSION */
 
3138
        gettext_noop("must be owner of conversion %s"),
 
3139
        /* ACL_KIND_TABLESPACE */
 
3140
        gettext_noop("must be owner of tablespace %s"),
 
3141
        /* ACL_KIND_TSDICTIONARY */
 
3142
        gettext_noop("must be owner of text search dictionary %s"),
 
3143
        /* ACL_KIND_TSCONFIGURATION */
 
3144
        gettext_noop("must be owner of text search configuration %s"),
 
3145
        /* ACL_KIND_FDW */
 
3146
        gettext_noop("must be owner of foreign-data wrapper %s"),
 
3147
        /* ACL_KIND_FOREIGN_SERVER */
 
3148
        gettext_noop("must be owner of foreign server %s"),
 
3149
        /* ACL_KIND_EXTENSION */
 
3150
        gettext_noop("must be owner of extension %s"),
 
3151
};
 
3152
 
 
3153
 
 
3154
void
 
3155
aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
 
3156
                           const char *objectname)
 
3157
{
 
3158
        switch (aclerr)
 
3159
        {
 
3160
                case ACLCHECK_OK:
 
3161
                        /* no error, so return to caller */
 
3162
                        break;
 
3163
                case ACLCHECK_NO_PRIV:
 
3164
                        ereport(ERROR,
 
3165
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
3166
                                         errmsg(no_priv_msg[objectkind], objectname)));
 
3167
                        break;
 
3168
                case ACLCHECK_NOT_OWNER:
 
3169
                        ereport(ERROR,
 
3170
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
3171
                                         errmsg(not_owner_msg[objectkind], objectname)));
 
3172
                        break;
 
3173
                default:
 
3174
                        elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
 
3175
                        break;
 
3176
        }
 
3177
}
 
3178
 
 
3179
 
 
3180
void
 
3181
aclcheck_error_col(AclResult aclerr, AclObjectKind objectkind,
 
3182
                                   const char *objectname, const char *colname)
 
3183
{
 
3184
        switch (aclerr)
 
3185
        {
 
3186
                case ACLCHECK_OK:
 
3187
                        /* no error, so return to caller */
 
3188
                        break;
 
3189
                case ACLCHECK_NO_PRIV:
 
3190
                        ereport(ERROR,
 
3191
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
3192
                         errmsg("permission denied for column \"%s\" of relation \"%s\"",
 
3193
                                        colname, objectname)));
 
3194
                        break;
 
3195
                case ACLCHECK_NOT_OWNER:
 
3196
                        /* relation msg is OK since columns don't have separate owners */
 
3197
                        ereport(ERROR,
 
3198
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
3199
                                         errmsg(not_owner_msg[objectkind], objectname)));
 
3200
                        break;
 
3201
                default:
 
3202
                        elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);
 
3203
                        break;
 
3204
        }
 
3205
}
 
3206
 
 
3207
 
 
3208
/* Check if given user has rolcatupdate privilege according to pg_authid */
 
3209
static bool
 
3210
has_rolcatupdate(Oid roleid)
 
3211
{
 
3212
        bool            rolcatupdate;
 
3213
        HeapTuple       tuple;
 
3214
 
 
3215
        tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
 
3216
        if (!HeapTupleIsValid(tuple))
 
3217
                ereport(ERROR,
 
3218
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3219
                                 errmsg("role with OID %u does not exist", roleid)));
 
3220
 
 
3221
        rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
 
3222
 
 
3223
        ReleaseSysCache(tuple);
 
3224
 
 
3225
        return rolcatupdate;
 
3226
}
 
3227
 
 
3228
/*
 
3229
 * Relay for the various pg_*_mask routines depending on object kind
 
3230
 */
 
3231
static AclMode
 
3232
pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid,
 
3233
                   AclMode mask, AclMaskHow how)
 
3234
{
 
3235
        switch (objkind)
 
3236
        {
 
3237
                case ACL_KIND_COLUMN:
 
3238
                        return
 
3239
                                pg_class_aclmask(table_oid, roleid, mask, how) |
 
3240
                                pg_attribute_aclmask(table_oid, attnum, roleid, mask, how);
 
3241
                case ACL_KIND_CLASS:
 
3242
                case ACL_KIND_SEQUENCE:
 
3243
                        return pg_class_aclmask(table_oid, roleid, mask, how);
 
3244
                case ACL_KIND_DATABASE:
 
3245
                        return pg_database_aclmask(table_oid, roleid, mask, how);
 
3246
                case ACL_KIND_PROC:
 
3247
                        return pg_proc_aclmask(table_oid, roleid, mask, how);
 
3248
                case ACL_KIND_LANGUAGE:
 
3249
                        return pg_language_aclmask(table_oid, roleid, mask, how);
 
3250
                case ACL_KIND_LARGEOBJECT:
 
3251
                        return pg_largeobject_aclmask_snapshot(table_oid, roleid,
 
3252
                                                                                                   mask, how, SnapshotNow);
 
3253
                case ACL_KIND_NAMESPACE:
 
3254
                        return pg_namespace_aclmask(table_oid, roleid, mask, how);
 
3255
                case ACL_KIND_TABLESPACE:
 
3256
                        return pg_tablespace_aclmask(table_oid, roleid, mask, how);
 
3257
                case ACL_KIND_FDW:
 
3258
                        return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
 
3259
                case ACL_KIND_FOREIGN_SERVER:
 
3260
                        return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
 
3261
                default:
 
3262
                        elog(ERROR, "unrecognized objkind: %d",
 
3263
                                 (int) objkind);
 
3264
                        /* not reached, but keep compiler quiet */
 
3265
                        return ACL_NO_RIGHTS;
 
3266
        }
 
3267
}
 
3268
 
 
3269
 
 
3270
/* ****************************************************************
 
3271
 * Exported routines for examining a user's privileges for various objects
 
3272
 *
 
3273
 * See aclmask() for a description of the common API for these functions.
 
3274
 *
 
3275
 * Note: we give lookup failure the full ereport treatment because the
 
3276
 * has_xxx_privilege() family of functions allow users to pass any random
 
3277
 * OID to these functions.
 
3278
 * ****************************************************************
 
3279
 */
 
3280
 
 
3281
/*
 
3282
 * Exported routine for examining a user's privileges for a column
 
3283
 *
 
3284
 * Note: this considers only privileges granted specifically on the column.
 
3285
 * It is caller's responsibility to take relation-level privileges into account
 
3286
 * as appropriate.      (For the same reason, we have no special case for
 
3287
 * superuser-ness here.)
 
3288
 */
 
3289
AclMode
 
3290
pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
 
3291
                                         AclMode mask, AclMaskHow how)
 
3292
{
 
3293
        AclMode         result;
 
3294
        HeapTuple       classTuple;
 
3295
        HeapTuple       attTuple;
 
3296
        Form_pg_class classForm;
 
3297
        Form_pg_attribute attributeForm;
 
3298
        Datum           aclDatum;
 
3299
        bool            isNull;
 
3300
        Acl                *acl;
 
3301
        Oid                     ownerId;
 
3302
 
 
3303
        /*
 
3304
         * First, get the column's ACL from its pg_attribute entry
 
3305
         */
 
3306
        attTuple = SearchSysCache2(ATTNUM,
 
3307
                                                           ObjectIdGetDatum(table_oid),
 
3308
                                                           Int16GetDatum(attnum));
 
3309
        if (!HeapTupleIsValid(attTuple))
 
3310
                ereport(ERROR,
 
3311
                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
3312
                                 errmsg("attribute %d of relation with OID %u does not exist",
 
3313
                                                attnum, table_oid)));
 
3314
        attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
 
3315
 
 
3316
        /* Throw error on dropped columns, too */
 
3317
        if (attributeForm->attisdropped)
 
3318
                ereport(ERROR,
 
3319
                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
3320
                                 errmsg("attribute %d of relation with OID %u does not exist",
 
3321
                                                attnum, table_oid)));
 
3322
 
 
3323
        aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
 
3324
                                                           &isNull);
 
3325
 
 
3326
        /*
 
3327
         * Here we hard-wire knowledge that the default ACL for a column grants no
 
3328
         * privileges, so that we can fall out quickly in the very common case
 
3329
         * where attacl is null.
 
3330
         */
 
3331
        if (isNull)
 
3332
        {
 
3333
                ReleaseSysCache(attTuple);
 
3334
                return 0;
 
3335
        }
 
3336
 
 
3337
        /*
 
3338
         * Must get the relation's ownerId from pg_class.  Since we already found
 
3339
         * a pg_attribute entry, the only likely reason for this to fail is that a
 
3340
         * concurrent DROP of the relation committed since then (which could only
 
3341
         * happen if we don't have lock on the relation).  We prefer to report "no
 
3342
         * privileges" rather than failing in such a case, so as to avoid unwanted
 
3343
         * failures in has_column_privilege() tests.
 
3344
         */
 
3345
        classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
 
3346
        if (!HeapTupleIsValid(classTuple))
 
3347
        {
 
3348
                ReleaseSysCache(attTuple);
 
3349
                return 0;
 
3350
        }
 
3351
        classForm = (Form_pg_class) GETSTRUCT(classTuple);
 
3352
 
 
3353
        ownerId = classForm->relowner;
 
3354
 
 
3355
        ReleaseSysCache(classTuple);
 
3356
 
 
3357
        /* detoast column's ACL if necessary */
 
3358
        acl = DatumGetAclP(aclDatum);
 
3359
 
 
3360
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3361
 
 
3362
        /* if we have a detoasted copy, free it */
 
3363
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3364
                pfree(acl);
 
3365
 
 
3366
        ReleaseSysCache(attTuple);
 
3367
 
 
3368
        return result;
 
3369
}
 
3370
 
 
3371
/*
 
3372
 * Exported routine for examining a user's privileges for a table
 
3373
 */
 
3374
AclMode
 
3375
pg_class_aclmask(Oid table_oid, Oid roleid,
 
3376
                                 AclMode mask, AclMaskHow how)
 
3377
{
 
3378
        AclMode         result;
 
3379
        HeapTuple       tuple;
 
3380
        Form_pg_class classForm;
 
3381
        Datum           aclDatum;
 
3382
        bool            isNull;
 
3383
        Acl                *acl;
 
3384
        Oid                     ownerId;
 
3385
 
 
3386
        /*
 
3387
         * Must get the relation's tuple from pg_class
 
3388
         */
 
3389
        tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
 
3390
        if (!HeapTupleIsValid(tuple))
 
3391
                ereport(ERROR,
 
3392
                                (errcode(ERRCODE_UNDEFINED_TABLE),
 
3393
                                 errmsg("relation with OID %u does not exist",
 
3394
                                                table_oid)));
 
3395
        classForm = (Form_pg_class) GETSTRUCT(tuple);
 
3396
 
 
3397
        /*
 
3398
         * Deny anyone permission to update a system catalog unless
 
3399
         * pg_authid.rolcatupdate is set.       (This is to let superusers protect
 
3400
         * themselves from themselves.)  Also allow it if allowSystemTableMods.
 
3401
         *
 
3402
         * As of 7.4 we have some updatable system views; those shouldn't be
 
3403
         * protected in this way.  Assume the view rules can take care of
 
3404
         * themselves.  ACL_USAGE is if we ever have system sequences.
 
3405
         */
 
3406
        if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
 
3407
                IsSystemClass(classForm) &&
 
3408
                classForm->relkind != RELKIND_VIEW &&
 
3409
                !has_rolcatupdate(roleid) &&
 
3410
                !allowSystemTableMods)
 
3411
        {
 
3412
#ifdef ACLDEBUG
 
3413
                elog(DEBUG2, "permission denied for system catalog update");
 
3414
#endif
 
3415
                mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);
 
3416
        }
 
3417
 
 
3418
        /*
 
3419
         * Otherwise, superusers bypass all permission-checking.
 
3420
         */
 
3421
        if (superuser_arg(roleid))
 
3422
        {
 
3423
#ifdef ACLDEBUG
 
3424
                elog(DEBUG2, "OID %u is superuser, home free", roleid);
 
3425
#endif
 
3426
                ReleaseSysCache(tuple);
 
3427
                return mask;
 
3428
        }
 
3429
 
 
3430
        /*
 
3431
         * Normal case: get the relation's ACL from pg_class
 
3432
         */
 
3433
        ownerId = classForm->relowner;
 
3434
 
 
3435
        aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
 
3436
                                                           &isNull);
 
3437
        if (isNull)
 
3438
        {
 
3439
                /* No ACL, so build default ACL */
 
3440
                switch (classForm->relkind)
 
3441
                {
 
3442
                        case RELKIND_SEQUENCE:
 
3443
                                acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);
 
3444
                                break;
 
3445
                        default:
 
3446
                                acl = acldefault(ACL_OBJECT_RELATION, ownerId);
 
3447
                                break;
 
3448
                }
 
3449
                aclDatum = (Datum) 0;
 
3450
        }
 
3451
        else
 
3452
        {
 
3453
                /* detoast rel's ACL if necessary */
 
3454
                acl = DatumGetAclP(aclDatum);
 
3455
        }
 
3456
 
 
3457
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3458
 
 
3459
        /* if we have a detoasted copy, free it */
 
3460
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3461
                pfree(acl);
 
3462
 
 
3463
        ReleaseSysCache(tuple);
 
3464
 
 
3465
        return result;
 
3466
}
 
3467
 
 
3468
/*
 
3469
 * Exported routine for examining a user's privileges for a database
 
3470
 */
 
3471
AclMode
 
3472
pg_database_aclmask(Oid db_oid, Oid roleid,
 
3473
                                        AclMode mask, AclMaskHow how)
 
3474
{
 
3475
        AclMode         result;
 
3476
        HeapTuple       tuple;
 
3477
        Datum           aclDatum;
 
3478
        bool            isNull;
 
3479
        Acl                *acl;
 
3480
        Oid                     ownerId;
 
3481
 
 
3482
        /* Superusers bypass all permission checking. */
 
3483
        if (superuser_arg(roleid))
 
3484
                return mask;
 
3485
 
 
3486
        /*
 
3487
         * Get the database's ACL from pg_database
 
3488
         */
 
3489
        tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
 
3490
        if (!HeapTupleIsValid(tuple))
 
3491
                ereport(ERROR,
 
3492
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
 
3493
                                 errmsg("database with OID %u does not exist", db_oid)));
 
3494
 
 
3495
        ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
 
3496
 
 
3497
        aclDatum = SysCacheGetAttr(DATABASEOID, tuple, Anum_pg_database_datacl,
 
3498
                                                           &isNull);
 
3499
        if (isNull)
 
3500
        {
 
3501
                /* No ACL, so build default ACL */
 
3502
                acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
 
3503
                aclDatum = (Datum) 0;
 
3504
        }
 
3505
        else
 
3506
        {
 
3507
                /* detoast ACL if necessary */
 
3508
                acl = DatumGetAclP(aclDatum);
 
3509
        }
 
3510
 
 
3511
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3512
 
 
3513
        /* if we have a detoasted copy, free it */
 
3514
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3515
                pfree(acl);
 
3516
 
 
3517
        ReleaseSysCache(tuple);
 
3518
 
 
3519
        return result;
 
3520
}
 
3521
 
 
3522
/*
 
3523
 * Exported routine for examining a user's privileges for a function
 
3524
 */
 
3525
AclMode
 
3526
pg_proc_aclmask(Oid proc_oid, Oid roleid,
 
3527
                                AclMode mask, AclMaskHow how)
 
3528
{
 
3529
        AclMode         result;
 
3530
        HeapTuple       tuple;
 
3531
        Datum           aclDatum;
 
3532
        bool            isNull;
 
3533
        Acl                *acl;
 
3534
        Oid                     ownerId;
 
3535
 
 
3536
        /* Superusers bypass all permission checking. */
 
3537
        if (superuser_arg(roleid))
 
3538
                return mask;
 
3539
 
 
3540
        /*
 
3541
         * Get the function's ACL from pg_proc
 
3542
         */
 
3543
        tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
 
3544
        if (!HeapTupleIsValid(tuple))
 
3545
                ereport(ERROR,
 
3546
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
3547
                                 errmsg("function with OID %u does not exist", proc_oid)));
 
3548
 
 
3549
        ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
 
3550
 
 
3551
        aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
 
3552
                                                           &isNull);
 
3553
        if (isNull)
 
3554
        {
 
3555
                /* No ACL, so build default ACL */
 
3556
                acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
 
3557
                aclDatum = (Datum) 0;
 
3558
        }
 
3559
        else
 
3560
        {
 
3561
                /* detoast ACL if necessary */
 
3562
                acl = DatumGetAclP(aclDatum);
 
3563
        }
 
3564
 
 
3565
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3566
 
 
3567
        /* if we have a detoasted copy, free it */
 
3568
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3569
                pfree(acl);
 
3570
 
 
3571
        ReleaseSysCache(tuple);
 
3572
 
 
3573
        return result;
 
3574
}
 
3575
 
 
3576
/*
 
3577
 * Exported routine for examining a user's privileges for a language
 
3578
 */
 
3579
AclMode
 
3580
pg_language_aclmask(Oid lang_oid, Oid roleid,
 
3581
                                        AclMode mask, AclMaskHow how)
 
3582
{
 
3583
        AclMode         result;
 
3584
        HeapTuple       tuple;
 
3585
        Datum           aclDatum;
 
3586
        bool            isNull;
 
3587
        Acl                *acl;
 
3588
        Oid                     ownerId;
 
3589
 
 
3590
        /* Superusers bypass all permission checking. */
 
3591
        if (superuser_arg(roleid))
 
3592
                return mask;
 
3593
 
 
3594
        /*
 
3595
         * Get the language's ACL from pg_language
 
3596
         */
 
3597
        tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lang_oid));
 
3598
        if (!HeapTupleIsValid(tuple))
 
3599
                ereport(ERROR,
 
3600
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3601
                                 errmsg("language with OID %u does not exist", lang_oid)));
 
3602
 
 
3603
        ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
 
3604
 
 
3605
        aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
 
3606
                                                           &isNull);
 
3607
        if (isNull)
 
3608
        {
 
3609
                /* No ACL, so build default ACL */
 
3610
                acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId);
 
3611
                aclDatum = (Datum) 0;
 
3612
        }
 
3613
        else
 
3614
        {
 
3615
                /* detoast ACL if necessary */
 
3616
                acl = DatumGetAclP(aclDatum);
 
3617
        }
 
3618
 
 
3619
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3620
 
 
3621
        /* if we have a detoasted copy, free it */
 
3622
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3623
                pfree(acl);
 
3624
 
 
3625
        ReleaseSysCache(tuple);
 
3626
 
 
3627
        return result;
 
3628
}
 
3629
 
 
3630
/*
 
3631
 * Exported routine for examining a user's privileges for a largeobject
 
3632
 *
 
3633
 * When a large object is opened for reading, it is opened relative to the
 
3634
 * caller's snapshot, but when it is opened for writing, it is always relative
 
3635
 * to SnapshotNow, as documented in doc/src/sgml/lobj.sgml.  This function
 
3636
 * takes a snapshot argument so that the permissions check can be made relative
 
3637
 * to the same snapshot that will be used to read the underlying data.
 
3638
 */
 
3639
AclMode
 
3640
pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
 
3641
                                                                AclMode mask, AclMaskHow how,
 
3642
                                                                Snapshot snapshot)
 
3643
{
 
3644
        AclMode         result;
 
3645
        Relation        pg_lo_meta;
 
3646
        ScanKeyData entry[1];
 
3647
        SysScanDesc scan;
 
3648
        HeapTuple       tuple;
 
3649
        Datum           aclDatum;
 
3650
        bool            isNull;
 
3651
        Acl                *acl;
 
3652
        Oid                     ownerId;
 
3653
 
 
3654
        /* Superusers bypass all permission checking. */
 
3655
        if (superuser_arg(roleid))
 
3656
                return mask;
 
3657
 
 
3658
        /*
 
3659
         * Get the largeobject's ACL from pg_language_metadata
 
3660
         */
 
3661
        pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
 
3662
                                                   AccessShareLock);
 
3663
 
 
3664
        ScanKeyInit(&entry[0],
 
3665
                                ObjectIdAttributeNumber,
 
3666
                                BTEqualStrategyNumber, F_OIDEQ,
 
3667
                                ObjectIdGetDatum(lobj_oid));
 
3668
 
 
3669
        scan = systable_beginscan(pg_lo_meta,
 
3670
                                                          LargeObjectMetadataOidIndexId, true,
 
3671
                                                          snapshot, 1, entry);
 
3672
 
 
3673
        tuple = systable_getnext(scan);
 
3674
        if (!HeapTupleIsValid(tuple))
 
3675
                ereport(ERROR,
 
3676
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3677
                                 errmsg("large object %u does not exist", lobj_oid)));
 
3678
 
 
3679
        ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
 
3680
 
 
3681
        aclDatum = heap_getattr(tuple, Anum_pg_largeobject_metadata_lomacl,
 
3682
                                                        RelationGetDescr(pg_lo_meta), &isNull);
 
3683
 
 
3684
        if (isNull)
 
3685
        {
 
3686
                /* No ACL, so build default ACL */
 
3687
                acl = acldefault(ACL_OBJECT_LARGEOBJECT, ownerId);
 
3688
                aclDatum = (Datum) 0;
 
3689
        }
 
3690
        else
 
3691
        {
 
3692
                /* detoast ACL if necessary */
 
3693
                acl = DatumGetAclP(aclDatum);
 
3694
        }
 
3695
 
 
3696
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3697
 
 
3698
        /* if we have a detoasted copy, free it */
 
3699
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3700
                pfree(acl);
 
3701
 
 
3702
        systable_endscan(scan);
 
3703
 
 
3704
        heap_close(pg_lo_meta, AccessShareLock);
 
3705
 
 
3706
        return result;
 
3707
}
 
3708
 
 
3709
/*
 
3710
 * Exported routine for examining a user's privileges for a namespace
 
3711
 */
 
3712
AclMode
 
3713
pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
 
3714
                                         AclMode mask, AclMaskHow how)
 
3715
{
 
3716
        AclMode         result;
 
3717
        HeapTuple       tuple;
 
3718
        Datum           aclDatum;
 
3719
        bool            isNull;
 
3720
        Acl                *acl;
 
3721
        Oid                     ownerId;
 
3722
 
 
3723
        /* Superusers bypass all permission checking. */
 
3724
        if (superuser_arg(roleid))
 
3725
                return mask;
 
3726
 
 
3727
        /*
 
3728
         * If we have been assigned this namespace as a temp namespace, check to
 
3729
         * make sure we have CREATE TEMP permission on the database, and if so act
 
3730
         * as though we have all standard (but not GRANT OPTION) permissions on
 
3731
         * the namespace.  If we don't have CREATE TEMP, act as though we have
 
3732
         * only USAGE (and not CREATE) rights.
 
3733
         *
 
3734
         * This may seem redundant given the check in InitTempTableNamespace, but
 
3735
         * it really isn't since current user ID may have changed since then. The
 
3736
         * upshot of this behavior is that a SECURITY DEFINER function can create
 
3737
         * temp tables that can then be accessed (if permission is granted) by
 
3738
         * code in the same session that doesn't have permissions to create temp
 
3739
         * tables.
 
3740
         *
 
3741
         * XXX Would it be safe to ereport a special error message as
 
3742
         * InitTempTableNamespace does?  Returning zero here means we'll get a
 
3743
         * generic "permission denied for schema pg_temp_N" message, which is not
 
3744
         * remarkably user-friendly.
 
3745
         */
 
3746
        if (isTempNamespace(nsp_oid))
 
3747
        {
 
3748
                if (pg_database_aclcheck(MyDatabaseId, roleid,
 
3749
                                                                 ACL_CREATE_TEMP) == ACLCHECK_OK)
 
3750
                        return mask & ACL_ALL_RIGHTS_NAMESPACE;
 
3751
                else
 
3752
                        return mask & ACL_USAGE;
 
3753
        }
 
3754
 
 
3755
        /*
 
3756
         * Get the schema's ACL from pg_namespace
 
3757
         */
 
3758
        tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
 
3759
        if (!HeapTupleIsValid(tuple))
 
3760
                ereport(ERROR,
 
3761
                                (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
3762
                                 errmsg("schema with OID %u does not exist", nsp_oid)));
 
3763
 
 
3764
        ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
 
3765
 
 
3766
        aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
 
3767
                                                           &isNull);
 
3768
        if (isNull)
 
3769
        {
 
3770
                /* No ACL, so build default ACL */
 
3771
                acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
 
3772
                aclDatum = (Datum) 0;
 
3773
        }
 
3774
        else
 
3775
        {
 
3776
                /* detoast ACL if necessary */
 
3777
                acl = DatumGetAclP(aclDatum);
 
3778
        }
 
3779
 
 
3780
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3781
 
 
3782
        /* if we have a detoasted copy, free it */
 
3783
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3784
                pfree(acl);
 
3785
 
 
3786
        ReleaseSysCache(tuple);
 
3787
 
 
3788
        return result;
 
3789
}
 
3790
 
 
3791
/*
 
3792
 * Exported routine for examining a user's privileges for a tablespace
 
3793
 */
 
3794
AclMode
 
3795
pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
 
3796
                                          AclMode mask, AclMaskHow how)
 
3797
{
 
3798
        AclMode         result;
 
3799
        HeapTuple       tuple;
 
3800
        Datum           aclDatum;
 
3801
        bool            isNull;
 
3802
        Acl                *acl;
 
3803
        Oid                     ownerId;
 
3804
 
 
3805
        /* Superusers bypass all permission checking. */
 
3806
        if (superuser_arg(roleid))
 
3807
                return mask;
 
3808
 
 
3809
        /*
 
3810
         * Get the tablespace's ACL from pg_tablespace
 
3811
         */
 
3812
        tuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
 
3813
        if (!HeapTupleIsValid(tuple))
 
3814
                ereport(ERROR,
 
3815
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3816
                                 errmsg("tablespace with OID %u does not exist", spc_oid)));
 
3817
 
 
3818
        ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
 
3819
 
 
3820
        aclDatum = SysCacheGetAttr(TABLESPACEOID, tuple,
 
3821
                                                           Anum_pg_tablespace_spcacl,
 
3822
                                                           &isNull);
 
3823
 
 
3824
        if (isNull)
 
3825
        {
 
3826
                /* No ACL, so build default ACL */
 
3827
                acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
 
3828
                aclDatum = (Datum) 0;
 
3829
        }
 
3830
        else
 
3831
        {
 
3832
                /* detoast ACL if necessary */
 
3833
                acl = DatumGetAclP(aclDatum);
 
3834
        }
 
3835
 
 
3836
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3837
 
 
3838
        /* if we have a detoasted copy, free it */
 
3839
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3840
                pfree(acl);
 
3841
 
 
3842
        ReleaseSysCache(tuple);
 
3843
 
 
3844
        return result;
 
3845
}
 
3846
 
 
3847
/*
 
3848
 * Exported routine for examining a user's privileges for a foreign
 
3849
 * data wrapper
 
3850
 */
 
3851
AclMode
 
3852
pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
 
3853
                                                                AclMode mask, AclMaskHow how)
 
3854
{
 
3855
        AclMode         result;
 
3856
        HeapTuple       tuple;
 
3857
        Datum           aclDatum;
 
3858
        bool            isNull;
 
3859
        Acl                *acl;
 
3860
        Oid                     ownerId;
 
3861
 
 
3862
        Form_pg_foreign_data_wrapper fdwForm;
 
3863
 
 
3864
        /* Bypass permission checks for superusers */
 
3865
        if (superuser_arg(roleid))
 
3866
                return mask;
 
3867
 
 
3868
        /*
 
3869
         * Must get the FDW's tuple from pg_foreign_data_wrapper
 
3870
         */
 
3871
        tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdw_oid));
 
3872
        if (!HeapTupleIsValid(tuple))
 
3873
                ereport(ERROR,
 
3874
                                (errmsg("foreign-data wrapper with OID %u does not exist",
 
3875
                                                fdw_oid)));
 
3876
        fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
 
3877
 
 
3878
        /*
 
3879
         * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
 
3880
         */
 
3881
        ownerId = fdwForm->fdwowner;
 
3882
 
 
3883
        aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
 
3884
                                                           Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
 
3885
        if (isNull)
 
3886
        {
 
3887
                /* No ACL, so build default ACL */
 
3888
                acl = acldefault(ACL_OBJECT_FDW, ownerId);
 
3889
                aclDatum = (Datum) 0;
 
3890
        }
 
3891
        else
 
3892
        {
 
3893
                /* detoast rel's ACL if necessary */
 
3894
                acl = DatumGetAclP(aclDatum);
 
3895
        }
 
3896
 
 
3897
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3898
 
 
3899
        /* if we have a detoasted copy, free it */
 
3900
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3901
                pfree(acl);
 
3902
 
 
3903
        ReleaseSysCache(tuple);
 
3904
 
 
3905
        return result;
 
3906
}
 
3907
 
 
3908
/*
 
3909
 * Exported routine for examining a user's privileges for a foreign
 
3910
 * server.
 
3911
 */
 
3912
AclMode
 
3913
pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
 
3914
                                                  AclMode mask, AclMaskHow how)
 
3915
{
 
3916
        AclMode         result;
 
3917
        HeapTuple       tuple;
 
3918
        Datum           aclDatum;
 
3919
        bool            isNull;
 
3920
        Acl                *acl;
 
3921
        Oid                     ownerId;
 
3922
 
 
3923
        Form_pg_foreign_server srvForm;
 
3924
 
 
3925
        /* Bypass permission checks for superusers */
 
3926
        if (superuser_arg(roleid))
 
3927
                return mask;
 
3928
 
 
3929
        /*
 
3930
         * Must get the FDW's tuple from pg_foreign_data_wrapper
 
3931
         */
 
3932
        tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
 
3933
        if (!HeapTupleIsValid(tuple))
 
3934
                ereport(ERROR,
 
3935
                                (errmsg("foreign server with OID %u does not exist",
 
3936
                                                srv_oid)));
 
3937
        srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
 
3938
 
 
3939
        /*
 
3940
         * Normal case: get the foreign server's ACL from pg_foreign_server
 
3941
         */
 
3942
        ownerId = srvForm->srvowner;
 
3943
 
 
3944
        aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
 
3945
                                                           Anum_pg_foreign_server_srvacl, &isNull);
 
3946
        if (isNull)
 
3947
        {
 
3948
                /* No ACL, so build default ACL */
 
3949
                acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
 
3950
                aclDatum = (Datum) 0;
 
3951
        }
 
3952
        else
 
3953
        {
 
3954
                /* detoast rel's ACL if necessary */
 
3955
                acl = DatumGetAclP(aclDatum);
 
3956
        }
 
3957
 
 
3958
        result = aclmask(acl, roleid, ownerId, mask, how);
 
3959
 
 
3960
        /* if we have a detoasted copy, free it */
 
3961
        if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
 
3962
                pfree(acl);
 
3963
 
 
3964
        ReleaseSysCache(tuple);
 
3965
 
 
3966
        return result;
 
3967
}
 
3968
 
 
3969
/*
 
3970
 * Exported routine for checking a user's access privileges to a column
 
3971
 *
 
3972
 * Returns ACLCHECK_OK if the user has any of the privileges identified by
 
3973
 * 'mode'; otherwise returns a suitable error code (in practice, always
 
3974
 * ACLCHECK_NO_PRIV).
 
3975
 *
 
3976
 * As with pg_attribute_aclmask, only privileges granted directly on the
 
3977
 * column are considered here.
 
3978
 */
 
3979
AclResult
 
3980
pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
 
3981
                                          Oid roleid, AclMode mode)
 
3982
{
 
3983
        if (pg_attribute_aclmask(table_oid, attnum, roleid, mode, ACLMASK_ANY) != 0)
 
3984
                return ACLCHECK_OK;
 
3985
        else
 
3986
                return ACLCHECK_NO_PRIV;
 
3987
}
 
3988
 
 
3989
/*
 
3990
 * Exported routine for checking a user's access privileges to any/all columns
 
3991
 *
 
3992
 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
 
3993
 * privileges identified by 'mode' on any non-dropped column in the relation;
 
3994
 * otherwise returns a suitable error code (in practice, always
 
3995
 * ACLCHECK_NO_PRIV).
 
3996
 *
 
3997
 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
 
3998
 * privileges identified by 'mode' on each non-dropped column in the relation
 
3999
 * (and there must be at least one such column); otherwise returns a suitable
 
4000
 * error code (in practice, always ACLCHECK_NO_PRIV).
 
4001
 *
 
4002
 * As with pg_attribute_aclmask, only privileges granted directly on the
 
4003
 * column(s) are considered here.
 
4004
 *
 
4005
 * Note: system columns are not considered here; there are cases where that
 
4006
 * might be appropriate but there are also cases where it wouldn't.
 
4007
 */
 
4008
AclResult
 
4009
pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
 
4010
                                                  AclMaskHow how)
 
4011
{
 
4012
        AclResult       result;
 
4013
        HeapTuple       classTuple;
 
4014
        Form_pg_class classForm;
 
4015
        AttrNumber      nattrs;
 
4016
        AttrNumber      curr_att;
 
4017
 
 
4018
        /*
 
4019
         * Must fetch pg_class row to check number of attributes.  As in
 
4020
         * pg_attribute_aclmask, we prefer to return "no privileges" instead of
 
4021
         * throwing an error if we get any unexpected lookup errors.
 
4022
         */
 
4023
        classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
 
4024
        if (!HeapTupleIsValid(classTuple))
 
4025
                return ACLCHECK_NO_PRIV;
 
4026
        classForm = (Form_pg_class) GETSTRUCT(classTuple);
 
4027
 
 
4028
        nattrs = classForm->relnatts;
 
4029
 
 
4030
        ReleaseSysCache(classTuple);
 
4031
 
 
4032
        /*
 
4033
         * Initialize result in case there are no non-dropped columns.  We want to
 
4034
         * report failure in such cases for either value of 'how'.
 
4035
         */
 
4036
        result = ACLCHECK_NO_PRIV;
 
4037
 
 
4038
        for (curr_att = 1; curr_att <= nattrs; curr_att++)
 
4039
        {
 
4040
                HeapTuple       attTuple;
 
4041
                AclMode         attmask;
 
4042
 
 
4043
                attTuple = SearchSysCache2(ATTNUM,
 
4044
                                                                   ObjectIdGetDatum(table_oid),
 
4045
                                                                   Int16GetDatum(curr_att));
 
4046
                if (!HeapTupleIsValid(attTuple))
 
4047
                        continue;
 
4048
 
 
4049
                /* ignore dropped columns */
 
4050
                if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
 
4051
                {
 
4052
                        ReleaseSysCache(attTuple);
 
4053
                        continue;
 
4054
                }
 
4055
 
 
4056
                /*
 
4057
                 * Here we hard-wire knowledge that the default ACL for a column
 
4058
                 * grants no privileges, so that we can fall out quickly in the very
 
4059
                 * common case where attacl is null.
 
4060
                 */
 
4061
                if (heap_attisnull(attTuple, Anum_pg_attribute_attacl))
 
4062
                        attmask = 0;
 
4063
                else
 
4064
                        attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
 
4065
                                                                                   mode, ACLMASK_ANY);
 
4066
 
 
4067
                ReleaseSysCache(attTuple);
 
4068
 
 
4069
                if (attmask != 0)
 
4070
                {
 
4071
                        result = ACLCHECK_OK;
 
4072
                        if (how == ACLMASK_ANY)
 
4073
                                break;                  /* succeed on any success */
 
4074
                }
 
4075
                else
 
4076
                {
 
4077
                        result = ACLCHECK_NO_PRIV;
 
4078
                        if (how == ACLMASK_ALL)
 
4079
                                break;                  /* fail on any failure */
 
4080
                }
 
4081
        }
 
4082
 
 
4083
        return result;
 
4084
}
 
4085
 
 
4086
/*
 
4087
 * Exported routine for checking a user's access privileges to a table
 
4088
 *
 
4089
 * Returns ACLCHECK_OK if the user has any of the privileges identified by
 
4090
 * 'mode'; otherwise returns a suitable error code (in practice, always
 
4091
 * ACLCHECK_NO_PRIV).
 
4092
 */
 
4093
AclResult
 
4094
pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
 
4095
{
 
4096
        if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4097
                return ACLCHECK_OK;
 
4098
        else
 
4099
                return ACLCHECK_NO_PRIV;
 
4100
}
 
4101
 
 
4102
/*
 
4103
 * Exported routine for checking a user's access privileges to a database
 
4104
 */
 
4105
AclResult
 
4106
pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
 
4107
{
 
4108
        if (pg_database_aclmask(db_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4109
                return ACLCHECK_OK;
 
4110
        else
 
4111
                return ACLCHECK_NO_PRIV;
 
4112
}
 
4113
 
 
4114
/*
 
4115
 * Exported routine for checking a user's access privileges to a function
 
4116
 */
 
4117
AclResult
 
4118
pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
 
4119
{
 
4120
        if (pg_proc_aclmask(proc_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4121
                return ACLCHECK_OK;
 
4122
        else
 
4123
                return ACLCHECK_NO_PRIV;
 
4124
}
 
4125
 
 
4126
/*
 
4127
 * Exported routine for checking a user's access privileges to a language
 
4128
 */
 
4129
AclResult
 
4130
pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode)
 
4131
{
 
4132
        if (pg_language_aclmask(lang_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4133
                return ACLCHECK_OK;
 
4134
        else
 
4135
                return ACLCHECK_NO_PRIV;
 
4136
}
 
4137
 
 
4138
/*
 
4139
 * Exported routine for checking a user's access privileges to a largeobject
 
4140
 */
 
4141
AclResult
 
4142
pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode,
 
4143
                                                                 Snapshot snapshot)
 
4144
{
 
4145
        if (pg_largeobject_aclmask_snapshot(lobj_oid, roleid, mode,
 
4146
                                                                                ACLMASK_ANY, snapshot) != 0)
 
4147
                return ACLCHECK_OK;
 
4148
        else
 
4149
                return ACLCHECK_NO_PRIV;
 
4150
}
 
4151
 
 
4152
/*
 
4153
 * Exported routine for checking a user's access privileges to a namespace
 
4154
 */
 
4155
AclResult
 
4156
pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
 
4157
{
 
4158
        if (pg_namespace_aclmask(nsp_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4159
                return ACLCHECK_OK;
 
4160
        else
 
4161
                return ACLCHECK_NO_PRIV;
 
4162
}
 
4163
 
 
4164
/*
 
4165
 * Exported routine for checking a user's access privileges to a tablespace
 
4166
 */
 
4167
AclResult
 
4168
pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
 
4169
{
 
4170
        if (pg_tablespace_aclmask(spc_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4171
                return ACLCHECK_OK;
 
4172
        else
 
4173
                return ACLCHECK_NO_PRIV;
 
4174
}
 
4175
 
 
4176
/*
 
4177
 * Exported routine for checking a user's access privileges to a foreign
 
4178
 * data wrapper
 
4179
 */
 
4180
AclResult
 
4181
pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
 
4182
{
 
4183
        if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4184
                return ACLCHECK_OK;
 
4185
        else
 
4186
                return ACLCHECK_NO_PRIV;
 
4187
}
 
4188
 
 
4189
/*
 
4190
 * Exported routine for checking a user's access privileges to a foreign
 
4191
 * server
 
4192
 */
 
4193
AclResult
 
4194
pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
 
4195
{
 
4196
        if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
 
4197
                return ACLCHECK_OK;
 
4198
        else
 
4199
                return ACLCHECK_NO_PRIV;
 
4200
}
 
4201
 
 
4202
/*
 
4203
 * Ownership check for a relation (specified by OID).
 
4204
 */
 
4205
bool
 
4206
pg_class_ownercheck(Oid class_oid, Oid roleid)
 
4207
{
 
4208
        HeapTuple       tuple;
 
4209
        Oid                     ownerId;
 
4210
 
 
4211
        /* Superusers bypass all permission checking. */
 
4212
        if (superuser_arg(roleid))
 
4213
                return true;
 
4214
 
 
4215
        tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
 
4216
        if (!HeapTupleIsValid(tuple))
 
4217
                ereport(ERROR,
 
4218
                                (errcode(ERRCODE_UNDEFINED_TABLE),
 
4219
                                 errmsg("relation with OID %u does not exist", class_oid)));
 
4220
 
 
4221
        ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
 
4222
 
 
4223
        ReleaseSysCache(tuple);
 
4224
 
 
4225
        return has_privs_of_role(roleid, ownerId);
 
4226
}
 
4227
 
 
4228
/*
 
4229
 * Ownership check for a type (specified by OID).
 
4230
 */
 
4231
bool
 
4232
pg_type_ownercheck(Oid type_oid, Oid roleid)
 
4233
{
 
4234
        HeapTuple       tuple;
 
4235
        Oid                     ownerId;
 
4236
 
 
4237
        /* Superusers bypass all permission checking. */
 
4238
        if (superuser_arg(roleid))
 
4239
                return true;
 
4240
 
 
4241
        tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
 
4242
        if (!HeapTupleIsValid(tuple))
 
4243
                ereport(ERROR,
 
4244
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4245
                                 errmsg("type with OID %u does not exist", type_oid)));
 
4246
 
 
4247
        ownerId = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
 
4248
 
 
4249
        ReleaseSysCache(tuple);
 
4250
 
 
4251
        return has_privs_of_role(roleid, ownerId);
 
4252
}
 
4253
 
 
4254
/*
 
4255
 * Ownership check for an operator (specified by OID).
 
4256
 */
 
4257
bool
 
4258
pg_oper_ownercheck(Oid oper_oid, Oid roleid)
 
4259
{
 
4260
        HeapTuple       tuple;
 
4261
        Oid                     ownerId;
 
4262
 
 
4263
        /* Superusers bypass all permission checking. */
 
4264
        if (superuser_arg(roleid))
 
4265
                return true;
 
4266
 
 
4267
        tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(oper_oid));
 
4268
        if (!HeapTupleIsValid(tuple))
 
4269
                ereport(ERROR,
 
4270
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
4271
                                 errmsg("operator with OID %u does not exist", oper_oid)));
 
4272
 
 
4273
        ownerId = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
 
4274
 
 
4275
        ReleaseSysCache(tuple);
 
4276
 
 
4277
        return has_privs_of_role(roleid, ownerId);
 
4278
}
 
4279
 
 
4280
/*
 
4281
 * Ownership check for a function (specified by OID).
 
4282
 */
 
4283
bool
 
4284
pg_proc_ownercheck(Oid proc_oid, Oid roleid)
 
4285
{
 
4286
        HeapTuple       tuple;
 
4287
        Oid                     ownerId;
 
4288
 
 
4289
        /* Superusers bypass all permission checking. */
 
4290
        if (superuser_arg(roleid))
 
4291
                return true;
 
4292
 
 
4293
        tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(proc_oid));
 
4294
        if (!HeapTupleIsValid(tuple))
 
4295
                ereport(ERROR,
 
4296
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
4297
                                 errmsg("function with OID %u does not exist", proc_oid)));
 
4298
 
 
4299
        ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
 
4300
 
 
4301
        ReleaseSysCache(tuple);
 
4302
 
 
4303
        return has_privs_of_role(roleid, ownerId);
 
4304
}
 
4305
 
 
4306
/*
 
4307
 * Ownership check for a procedural language (specified by OID)
 
4308
 */
 
4309
bool
 
4310
pg_language_ownercheck(Oid lan_oid, Oid roleid)
 
4311
{
 
4312
        HeapTuple       tuple;
 
4313
        Oid                     ownerId;
 
4314
 
 
4315
        /* Superusers bypass all permission checking. */
 
4316
        if (superuser_arg(roleid))
 
4317
                return true;
 
4318
 
 
4319
        tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(lan_oid));
 
4320
        if (!HeapTupleIsValid(tuple))
 
4321
                ereport(ERROR,
 
4322
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
4323
                                 errmsg("language with OID %u does not exist", lan_oid)));
 
4324
 
 
4325
        ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
 
4326
 
 
4327
        ReleaseSysCache(tuple);
 
4328
 
 
4329
        return has_privs_of_role(roleid, ownerId);
 
4330
}
 
4331
 
 
4332
/*
 
4333
 * Ownership check for a largeobject (specified by OID)
 
4334
 *
 
4335
 * This is only used for operations like ALTER LARGE OBJECT that are always
 
4336
 * relative to SnapshotNow.
 
4337
 */
 
4338
bool
 
4339
pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
 
4340
{
 
4341
        Relation        pg_lo_meta;
 
4342
        ScanKeyData entry[1];
 
4343
        SysScanDesc scan;
 
4344
        HeapTuple       tuple;
 
4345
        Oid                     ownerId;
 
4346
 
 
4347
        /* Superusers bypass all permission checking. */
 
4348
        if (superuser_arg(roleid))
 
4349
                return true;
 
4350
 
 
4351
        /* There's no syscache for pg_largeobject_metadata */
 
4352
        pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
 
4353
                                                   AccessShareLock);
 
4354
 
 
4355
        ScanKeyInit(&entry[0],
 
4356
                                ObjectIdAttributeNumber,
 
4357
                                BTEqualStrategyNumber, F_OIDEQ,
 
4358
                                ObjectIdGetDatum(lobj_oid));
 
4359
 
 
4360
        scan = systable_beginscan(pg_lo_meta,
 
4361
                                                          LargeObjectMetadataOidIndexId, true,
 
4362
                                                          SnapshotNow, 1, entry);
 
4363
 
 
4364
        tuple = systable_getnext(scan);
 
4365
        if (!HeapTupleIsValid(tuple))
 
4366
                ereport(ERROR,
 
4367
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4368
                                 errmsg("large object %u does not exist", lobj_oid)));
 
4369
 
 
4370
        ownerId = ((Form_pg_largeobject_metadata) GETSTRUCT(tuple))->lomowner;
 
4371
 
 
4372
        systable_endscan(scan);
 
4373
        heap_close(pg_lo_meta, AccessShareLock);
 
4374
 
 
4375
        return has_privs_of_role(roleid, ownerId);
 
4376
}
 
4377
 
 
4378
/*
 
4379
 * Ownership check for a namespace (specified by OID).
 
4380
 */
 
4381
bool
 
4382
pg_namespace_ownercheck(Oid nsp_oid, Oid roleid)
 
4383
{
 
4384
        HeapTuple       tuple;
 
4385
        Oid                     ownerId;
 
4386
 
 
4387
        /* Superusers bypass all permission checking. */
 
4388
        if (superuser_arg(roleid))
 
4389
                return true;
 
4390
 
 
4391
        tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
 
4392
        if (!HeapTupleIsValid(tuple))
 
4393
                ereport(ERROR,
 
4394
                                (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
4395
                                 errmsg("schema with OID %u does not exist", nsp_oid)));
 
4396
 
 
4397
        ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
 
4398
 
 
4399
        ReleaseSysCache(tuple);
 
4400
 
 
4401
        return has_privs_of_role(roleid, ownerId);
 
4402
}
 
4403
 
 
4404
/*
 
4405
 * Ownership check for a tablespace (specified by OID).
 
4406
 */
 
4407
bool
 
4408
pg_tablespace_ownercheck(Oid spc_oid, Oid roleid)
 
4409
{
 
4410
        HeapTuple       spctuple;
 
4411
        Oid                     spcowner;
 
4412
 
 
4413
        /* Superusers bypass all permission checking. */
 
4414
        if (superuser_arg(roleid))
 
4415
                return true;
 
4416
 
 
4417
        /* Search syscache for pg_tablespace */
 
4418
        spctuple = SearchSysCache1(TABLESPACEOID, ObjectIdGetDatum(spc_oid));
 
4419
        if (!HeapTupleIsValid(spctuple))
 
4420
                ereport(ERROR,
 
4421
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4422
                                 errmsg("tablespace with OID %u does not exist", spc_oid)));
 
4423
 
 
4424
        spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
 
4425
 
 
4426
        ReleaseSysCache(spctuple);
 
4427
 
 
4428
        return has_privs_of_role(roleid, spcowner);
 
4429
}
 
4430
 
 
4431
/*
 
4432
 * Ownership check for an operator class (specified by OID).
 
4433
 */
 
4434
bool
 
4435
pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
 
4436
{
 
4437
        HeapTuple       tuple;
 
4438
        Oid                     ownerId;
 
4439
 
 
4440
        /* Superusers bypass all permission checking. */
 
4441
        if (superuser_arg(roleid))
 
4442
                return true;
 
4443
 
 
4444
        tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opc_oid));
 
4445
        if (!HeapTupleIsValid(tuple))
 
4446
                ereport(ERROR,
 
4447
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4448
                                 errmsg("operator class with OID %u does not exist",
 
4449
                                                opc_oid)));
 
4450
 
 
4451
        ownerId = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
 
4452
 
 
4453
        ReleaseSysCache(tuple);
 
4454
 
 
4455
        return has_privs_of_role(roleid, ownerId);
 
4456
}
 
4457
 
 
4458
/*
 
4459
 * Ownership check for an operator family (specified by OID).
 
4460
 */
 
4461
bool
 
4462
pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
 
4463
{
 
4464
        HeapTuple       tuple;
 
4465
        Oid                     ownerId;
 
4466
 
 
4467
        /* Superusers bypass all permission checking. */
 
4468
        if (superuser_arg(roleid))
 
4469
                return true;
 
4470
 
 
4471
        tuple = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opf_oid));
 
4472
        if (!HeapTupleIsValid(tuple))
 
4473
                ereport(ERROR,
 
4474
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4475
                                 errmsg("operator family with OID %u does not exist",
 
4476
                                                opf_oid)));
 
4477
 
 
4478
        ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
 
4479
 
 
4480
        ReleaseSysCache(tuple);
 
4481
 
 
4482
        return has_privs_of_role(roleid, ownerId);
 
4483
}
 
4484
 
 
4485
/*
 
4486
 * Ownership check for a text search dictionary (specified by OID).
 
4487
 */
 
4488
bool
 
4489
pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
 
4490
{
 
4491
        HeapTuple       tuple;
 
4492
        Oid                     ownerId;
 
4493
 
 
4494
        /* Superusers bypass all permission checking. */
 
4495
        if (superuser_arg(roleid))
 
4496
                return true;
 
4497
 
 
4498
        tuple = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dict_oid));
 
4499
        if (!HeapTupleIsValid(tuple))
 
4500
                ereport(ERROR,
 
4501
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4502
                                 errmsg("text search dictionary with OID %u does not exist",
 
4503
                                                dict_oid)));
 
4504
 
 
4505
        ownerId = ((Form_pg_ts_dict) GETSTRUCT(tuple))->dictowner;
 
4506
 
 
4507
        ReleaseSysCache(tuple);
 
4508
 
 
4509
        return has_privs_of_role(roleid, ownerId);
 
4510
}
 
4511
 
 
4512
/*
 
4513
 * Ownership check for a text search configuration (specified by OID).
 
4514
 */
 
4515
bool
 
4516
pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid)
 
4517
{
 
4518
        HeapTuple       tuple;
 
4519
        Oid                     ownerId;
 
4520
 
 
4521
        /* Superusers bypass all permission checking. */
 
4522
        if (superuser_arg(roleid))
 
4523
                return true;
 
4524
 
 
4525
        tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfg_oid));
 
4526
        if (!HeapTupleIsValid(tuple))
 
4527
                ereport(ERROR,
 
4528
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4529
                           errmsg("text search configuration with OID %u does not exist",
 
4530
                                          cfg_oid)));
 
4531
 
 
4532
        ownerId = ((Form_pg_ts_config) GETSTRUCT(tuple))->cfgowner;
 
4533
 
 
4534
        ReleaseSysCache(tuple);
 
4535
 
 
4536
        return has_privs_of_role(roleid, ownerId);
 
4537
}
 
4538
 
 
4539
/*
 
4540
 * Ownership check for a foreign-data wrapper (specified by OID).
 
4541
 */
 
4542
bool
 
4543
pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid)
 
4544
{
 
4545
        HeapTuple       tuple;
 
4546
        Oid                     ownerId;
 
4547
 
 
4548
        /* Superusers bypass all permission checking. */
 
4549
        if (superuser_arg(roleid))
 
4550
                return true;
 
4551
 
 
4552
        tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(srv_oid));
 
4553
        if (!HeapTupleIsValid(tuple))
 
4554
                ereport(ERROR,
 
4555
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4556
                                 errmsg("foreign-data wrapper with OID %u does not exist",
 
4557
                                                srv_oid)));
 
4558
 
 
4559
        ownerId = ((Form_pg_foreign_data_wrapper) GETSTRUCT(tuple))->fdwowner;
 
4560
 
 
4561
        ReleaseSysCache(tuple);
 
4562
 
 
4563
        return has_privs_of_role(roleid, ownerId);
 
4564
}
 
4565
 
 
4566
/*
 
4567
 * Ownership check for a foreign server (specified by OID).
 
4568
 */
 
4569
bool
 
4570
pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
 
4571
{
 
4572
        HeapTuple       tuple;
 
4573
        Oid                     ownerId;
 
4574
 
 
4575
        /* Superusers bypass all permission checking. */
 
4576
        if (superuser_arg(roleid))
 
4577
                return true;
 
4578
 
 
4579
        tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srv_oid));
 
4580
        if (!HeapTupleIsValid(tuple))
 
4581
                ereport(ERROR,
 
4582
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4583
                                 errmsg("foreign server with OID %u does not exist",
 
4584
                                                srv_oid)));
 
4585
 
 
4586
        ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
 
4587
 
 
4588
        ReleaseSysCache(tuple);
 
4589
 
 
4590
        return has_privs_of_role(roleid, ownerId);
 
4591
}
 
4592
 
 
4593
/*
 
4594
 * Ownership check for a database (specified by OID).
 
4595
 */
 
4596
bool
 
4597
pg_database_ownercheck(Oid db_oid, Oid roleid)
 
4598
{
 
4599
        HeapTuple       tuple;
 
4600
        Oid                     dba;
 
4601
 
 
4602
        /* Superusers bypass all permission checking. */
 
4603
        if (superuser_arg(roleid))
 
4604
                return true;
 
4605
 
 
4606
        tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(db_oid));
 
4607
        if (!HeapTupleIsValid(tuple))
 
4608
                ereport(ERROR,
 
4609
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
 
4610
                                 errmsg("database with OID %u does not exist", db_oid)));
 
4611
 
 
4612
        dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
 
4613
 
 
4614
        ReleaseSysCache(tuple);
 
4615
 
 
4616
        return has_privs_of_role(roleid, dba);
 
4617
}
 
4618
 
 
4619
/*
 
4620
 * Ownership check for a collation (specified by OID).
 
4621
 */
 
4622
bool
 
4623
pg_collation_ownercheck(Oid coll_oid, Oid roleid)
 
4624
{
 
4625
        HeapTuple       tuple;
 
4626
        Oid                     ownerId;
 
4627
 
 
4628
        /* Superusers bypass all permission checking. */
 
4629
        if (superuser_arg(roleid))
 
4630
                return true;
 
4631
 
 
4632
        tuple = SearchSysCache1(COLLOID, ObjectIdGetDatum(coll_oid));
 
4633
        if (!HeapTupleIsValid(tuple))
 
4634
                ereport(ERROR,
 
4635
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4636
                                 errmsg("collation with OID %u does not exist", coll_oid)));
 
4637
 
 
4638
        ownerId = ((Form_pg_collation) GETSTRUCT(tuple))->collowner;
 
4639
 
 
4640
        ReleaseSysCache(tuple);
 
4641
 
 
4642
        return has_privs_of_role(roleid, ownerId);
 
4643
}
 
4644
 
 
4645
/*
 
4646
 * Ownership check for a conversion (specified by OID).
 
4647
 */
 
4648
bool
 
4649
pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
 
4650
{
 
4651
        HeapTuple       tuple;
 
4652
        Oid                     ownerId;
 
4653
 
 
4654
        /* Superusers bypass all permission checking. */
 
4655
        if (superuser_arg(roleid))
 
4656
                return true;
 
4657
 
 
4658
        tuple = SearchSysCache1(CONVOID, ObjectIdGetDatum(conv_oid));
 
4659
        if (!HeapTupleIsValid(tuple))
 
4660
                ereport(ERROR,
 
4661
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4662
                                 errmsg("conversion with OID %u does not exist", conv_oid)));
 
4663
 
 
4664
        ownerId = ((Form_pg_conversion) GETSTRUCT(tuple))->conowner;
 
4665
 
 
4666
        ReleaseSysCache(tuple);
 
4667
 
 
4668
        return has_privs_of_role(roleid, ownerId);
 
4669
}
 
4670
 
 
4671
/*
 
4672
 * Ownership check for an extension (specified by OID).
 
4673
 */
 
4674
bool
 
4675
pg_extension_ownercheck(Oid ext_oid, Oid roleid)
 
4676
{
 
4677
        Relation        pg_extension;
 
4678
        ScanKeyData entry[1];
 
4679
        SysScanDesc scan;
 
4680
        HeapTuple       tuple;
 
4681
        Oid                     ownerId;
 
4682
 
 
4683
        /* Superusers bypass all permission checking. */
 
4684
        if (superuser_arg(roleid))
 
4685
                return true;
 
4686
 
 
4687
        /* There's no syscache for pg_extension, so do it the hard way */
 
4688
        pg_extension = heap_open(ExtensionRelationId, AccessShareLock);
 
4689
 
 
4690
        ScanKeyInit(&entry[0],
 
4691
                                ObjectIdAttributeNumber,
 
4692
                                BTEqualStrategyNumber, F_OIDEQ,
 
4693
                                ObjectIdGetDatum(ext_oid));
 
4694
 
 
4695
        scan = systable_beginscan(pg_extension,
 
4696
                                                          ExtensionOidIndexId, true,
 
4697
                                                          SnapshotNow, 1, entry);
 
4698
 
 
4699
        tuple = systable_getnext(scan);
 
4700
        if (!HeapTupleIsValid(tuple))
 
4701
                ereport(ERROR,
 
4702
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
4703
                                 errmsg("extension with OID %u does not exist", ext_oid)));
 
4704
 
 
4705
        ownerId = ((Form_pg_extension) GETSTRUCT(tuple))->extowner;
 
4706
 
 
4707
        systable_endscan(scan);
 
4708
        heap_close(pg_extension, AccessShareLock);
 
4709
 
 
4710
        return has_privs_of_role(roleid, ownerId);
 
4711
}
 
4712
 
 
4713
/*
 
4714
 * Check whether specified role has CREATEROLE privilege (or is a superuser)
 
4715
 *
 
4716
 * Note: roles do not have owners per se; instead we use this test in
 
4717
 * places where an ownership-like permissions test is needed for a role.
 
4718
 * Be sure to apply it to the role trying to do the operation, not the
 
4719
 * role being operated on!      Also note that this generally should not be
 
4720
 * considered enough privilege if the target role is a superuser.
 
4721
 * (We don't handle that consideration here because we want to give a
 
4722
 * separate error message for such cases, so the caller has to deal with it.)
 
4723
 */
 
4724
bool
 
4725
has_createrole_privilege(Oid roleid)
 
4726
{
 
4727
        bool            result = false;
 
4728
        HeapTuple       utup;
 
4729
 
 
4730
        /* Superusers bypass all permission checking. */
 
4731
        if (superuser_arg(roleid))
 
4732
                return true;
 
4733
 
 
4734
        utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
 
4735
        if (HeapTupleIsValid(utup))
 
4736
        {
 
4737
                result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
 
4738
                ReleaseSysCache(utup);
 
4739
        }
 
4740
        return result;
 
4741
}
 
4742
 
 
4743
/*
 
4744
 * Fetch pg_default_acl entry for given role, namespace and object type
 
4745
 * (object type must be given in pg_default_acl's encoding).
 
4746
 * Returns NULL if no such entry.
 
4747
 */
 
4748
static Acl *
 
4749
get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
 
4750
{
 
4751
        Acl                *result = NULL;
 
4752
        HeapTuple       tuple;
 
4753
 
 
4754
        tuple = SearchSysCache3(DEFACLROLENSPOBJ,
 
4755
                                                        ObjectIdGetDatum(roleId),
 
4756
                                                        ObjectIdGetDatum(nsp_oid),
 
4757
                                                        CharGetDatum(objtype));
 
4758
 
 
4759
        if (HeapTupleIsValid(tuple))
 
4760
        {
 
4761
                Datum           aclDatum;
 
4762
                bool            isNull;
 
4763
 
 
4764
                aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
 
4765
                                                                   Anum_pg_default_acl_defaclacl,
 
4766
                                                                   &isNull);
 
4767
                if (!isNull)
 
4768
                        result = DatumGetAclPCopy(aclDatum);
 
4769
                ReleaseSysCache(tuple);
 
4770
        }
 
4771
 
 
4772
        return result;
 
4773
}
 
4774
 
 
4775
/*
 
4776
 * Get default permissions for newly created object within given schema
 
4777
 *
 
4778
 * Returns NULL if built-in system defaults should be used
 
4779
 */
 
4780
Acl *
 
4781
get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
 
4782
{
 
4783
        Acl                *result;
 
4784
        Acl                *glob_acl;
 
4785
        Acl                *schema_acl;
 
4786
        Acl                *def_acl;
 
4787
        char            defaclobjtype;
 
4788
 
 
4789
        /*
 
4790
         * Use NULL during bootstrap, since pg_default_acl probably isn't there
 
4791
         * yet.
 
4792
         */
 
4793
        if (IsBootstrapProcessingMode())
 
4794
                return NULL;
 
4795
 
 
4796
        /* Check if object type is supported in pg_default_acl */
 
4797
        switch (objtype)
 
4798
        {
 
4799
                case ACL_OBJECT_RELATION:
 
4800
                        defaclobjtype = DEFACLOBJ_RELATION;
 
4801
                        break;
 
4802
 
 
4803
                case ACL_OBJECT_SEQUENCE:
 
4804
                        defaclobjtype = DEFACLOBJ_SEQUENCE;
 
4805
                        break;
 
4806
 
 
4807
                case ACL_OBJECT_FUNCTION:
 
4808
                        defaclobjtype = DEFACLOBJ_FUNCTION;
 
4809
                        break;
 
4810
 
 
4811
                default:
 
4812
                        return NULL;
 
4813
        }
 
4814
 
 
4815
        /* Look up the relevant pg_default_acl entries */
 
4816
        glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
 
4817
        schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
 
4818
 
 
4819
        /* Quick out if neither entry exists */
 
4820
        if (glob_acl == NULL && schema_acl == NULL)
 
4821
                return NULL;
 
4822
 
 
4823
        /* We need to know the hard-wired default value, too */
 
4824
        def_acl = acldefault(objtype, ownerId);
 
4825
 
 
4826
        /* If there's no global entry, substitute the hard-wired default */
 
4827
        if (glob_acl == NULL)
 
4828
                glob_acl = def_acl;
 
4829
 
 
4830
        /* Merge in any per-schema privileges */
 
4831
        result = aclmerge(glob_acl, schema_acl, ownerId);
 
4832
 
 
4833
        /*
 
4834
         * For efficiency, we want to return NULL if the result equals default.
 
4835
         * This requires sorting both arrays to get an accurate comparison.
 
4836
         */
 
4837
        aclitemsort(result);
 
4838
        aclitemsort(def_acl);
 
4839
        if (aclequal(result, def_acl))
 
4840
                result = NULL;
 
4841
 
 
4842
        return result;
 
4843
}