~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/acl.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * acl.c
 
4
 *        Basic access control list data structures manipulation routines.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL$
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include <ctype.h>
 
18
 
 
19
#include "catalog/namespace.h"
 
20
#include "catalog/pg_authid.h"
 
21
#include "catalog/pg_auth_members.h"
 
22
#include "catalog/pg_type.h"
 
23
#include "commands/dbcommands.h"
 
24
#include "commands/tablespace.h"
 
25
#include "foreign/foreign.h"
 
26
#include "miscadmin.h"
 
27
#include "utils/acl.h"
 
28
#include "utils/builtins.h"
 
29
#include "utils/inval.h"
 
30
#include "utils/lsyscache.h"
 
31
#include "utils/memutils.h"
 
32
#include "utils/syscache.h"
 
33
 
 
34
 
 
35
typedef struct
 
36
{
 
37
        const char *name;
 
38
        AclMode         value;
 
39
} priv_map;
 
40
 
 
41
/*
 
42
 * We frequently need to test whether a given role is a member of some other
 
43
 * role.  In most of these tests the "given role" is the same, namely the
 
44
 * active current user.  So we can optimize it by keeping a cached list of
 
45
 * all the roles the "given role" is a member of, directly or indirectly.
 
46
 * The cache is flushed whenever we detect a change in pg_auth_members.
 
47
 *
 
48
 * There are actually two caches, one computed under "has_privs" rules
 
49
 * (do not recurse where rolinherit isn't true) and one computed under
 
50
 * "is_member" rules (recurse regardless of rolinherit).
 
51
 *
 
52
 * Possibly this mechanism should be generalized to allow caching membership
 
53
 * info for multiple roles?
 
54
 *
 
55
 * The has_privs cache is:
 
56
 * cached_privs_role is the role OID the cache is for.
 
57
 * cached_privs_roles is an OID list of roles that cached_privs_role
 
58
 *              has the privileges of (always including itself).
 
59
 * The cache is valid if cached_privs_role is not InvalidOid.
 
60
 *
 
61
 * The is_member cache is similarly:
 
62
 * cached_member_role is the role OID the cache is for.
 
63
 * cached_membership_roles is an OID list of roles that cached_member_role
 
64
 *              is a member of (always including itself).
 
65
 * The cache is valid if cached_member_role is not InvalidOid.
 
66
 */
 
67
static Oid      cached_privs_role = InvalidOid;
 
68
static List *cached_privs_roles = NIL;
 
69
static Oid      cached_member_role = InvalidOid;
 
70
static List *cached_membership_roles = NIL;
 
71
 
 
72
 
 
73
static const char *getid(const char *s, char *n);
 
74
static void putid(char *p, const char *s);
 
75
static Acl *allocacl(int n);
 
76
static void check_acl(const Acl *acl);
 
77
static const char *aclparse(const char *s, AclItem *aip);
 
78
static bool aclitem_match(const AclItem *a1, const AclItem *a2);
 
79
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
 
80
                                  Oid ownerId);
 
81
static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
 
82
                                 Oid ownerId, DropBehavior behavior);
 
83
static int      oidComparator(const void *arg1, const void *arg2);
 
84
 
 
85
static AclMode convert_priv_string(text *priv_type_text);
 
86
static AclMode convert_any_priv_string(text *priv_type_text,
 
87
                                                                           const priv_map *privileges);
 
88
 
 
89
static Oid      convert_table_name(text *tablename);
 
90
static AclMode convert_table_priv_string(text *priv_type_text);
 
91
static AttrNumber convert_column_name(Oid tableoid, text *column);
 
92
static AclMode convert_column_priv_string(text *priv_type_text);
 
93
static Oid      convert_database_name(text *databasename);
 
94
static AclMode convert_database_priv_string(text *priv_type_text);
 
95
static Oid      convert_foreign_data_wrapper_name(text *fdwname);
 
96
static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
 
97
static Oid      convert_function_name(text *functionname);
 
98
static AclMode convert_function_priv_string(text *priv_type_text);
 
99
static Oid      convert_language_name(text *languagename);
 
100
static AclMode convert_language_priv_string(text *priv_type_text);
 
101
static Oid      convert_schema_name(text *schemaname);
 
102
static AclMode convert_schema_priv_string(text *priv_type_text);
 
103
static Oid      convert_server_name(text *servername);
 
104
static AclMode convert_server_priv_string(text *priv_type_text);
 
105
static Oid      convert_tablespace_name(text *tablespacename);
 
106
static AclMode convert_tablespace_priv_string(text *priv_type_text);
 
107
static AclMode convert_role_priv_string(text *priv_type_text);
 
108
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
 
109
 
 
110
static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
 
111
 
 
112
 
 
113
/*
 
114
 * getid
 
115
 *              Consumes the first alphanumeric string (identifier) found in string
 
116
 *              's', ignoring any leading white space.  If it finds a double quote
 
117
 *              it returns the word inside the quotes.
 
118
 *
 
119
 * RETURNS:
 
120
 *              the string position in 's' that points to the next non-space character
 
121
 *              in 's', after any quotes.  Also:
 
122
 *              - loads the identifier into 'n'.  (If no identifier is found, 'n'
 
123
 *                contains an empty string.)  'n' must be NAMEDATALEN bytes.
 
124
 */
 
125
static const char *
 
126
getid(const char *s, char *n)
 
127
{
 
128
        int                     len = 0;
 
129
        bool            in_quotes = false;
 
130
 
 
131
        Assert(s && n);
 
132
 
 
133
        while (isspace((unsigned char) *s))
 
134
                s++;
 
135
        /* This code had better match what putid() does, below */
 
136
        for (;
 
137
                 *s != '\0' &&
 
138
                 (isalnum((unsigned char) *s) ||
 
139
                  *s == '_' ||
 
140
                  *s == '"' ||
 
141
                  in_quotes);
 
142
                 s++)
 
143
        {
 
144
                if (*s == '"')
 
145
                {
 
146
                        /* safe to look at next char (could be '\0' though) */
 
147
                        if (*(s + 1) != '"')
 
148
                        {
 
149
                                in_quotes = !in_quotes;
 
150
                                continue;
 
151
                        }
 
152
                        /* it's an escaped double quote; skip the escaping char */
 
153
                        s++;
 
154
                }
 
155
 
 
156
                /* Add the character to the string */
 
157
                if (len >= NAMEDATALEN - 1)
 
158
                        ereport(ERROR,
 
159
                                        (errcode(ERRCODE_NAME_TOO_LONG),
 
160
                                         errmsg("identifier too long"),
 
161
                                         errdetail("Identifier must be less than %d characters.",
 
162
                                                           NAMEDATALEN)));
 
163
 
 
164
                n[len++] = *s;
 
165
        }
 
166
        n[len] = '\0';
 
167
        while (isspace((unsigned char) *s))
 
168
                s++;
 
169
        return s;
 
170
}
 
171
 
 
172
/*
 
173
 * Write a role name at *p, adding double quotes if needed.
 
174
 * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
 
175
 * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
 
176
 */
 
177
static void
 
178
putid(char *p, const char *s)
 
179
{
 
180
        const char *src;
 
181
        bool            safe = true;
 
182
 
 
183
        for (src = s; *src; src++)
 
184
        {
 
185
                /* This test had better match what getid() does, above */
 
186
                if (!isalnum((unsigned char) *src) && *src != '_')
 
187
                {
 
188
                        safe = false;
 
189
                        break;
 
190
                }
 
191
        }
 
192
        if (!safe)
 
193
                *p++ = '"';
 
194
        for (src = s; *src; src++)
 
195
        {
 
196
                /* A double quote character in a username is encoded as "" */
 
197
                if (*src == '"')
 
198
                        *p++ = '"';
 
199
                *p++ = *src;
 
200
        }
 
201
        if (!safe)
 
202
                *p++ = '"';
 
203
        *p = '\0';
 
204
}
 
205
 
 
206
/*
 
207
 * aclparse
 
208
 *              Consumes and parses an ACL specification of the form:
 
209
 *                              [group|user] [A-Za-z0-9]*=[rwaR]*
 
210
 *              from string 's', ignoring any leading white space or white space
 
211
 *              between the optional id type keyword (group|user) and the actual
 
212
 *              ACL specification.
 
213
 *
 
214
 *              The group|user decoration is unnecessary in the roles world,
 
215
 *              but we still accept it for backward compatibility.
 
216
 *
 
217
 *              This routine is called by the parser as well as aclitemin(), hence
 
218
 *              the added generality.
 
219
 *
 
220
 * RETURNS:
 
221
 *              the string position in 's' immediately following the ACL
 
222
 *              specification.  Also:
 
223
 *              - loads the structure pointed to by 'aip' with the appropriate
 
224
 *                UID/GID, id type identifier and mode type values.
 
225
 */
 
226
static const char *
 
227
aclparse(const char *s, AclItem *aip)
 
228
{
 
229
        AclMode         privs,
 
230
                                goption,
 
231
                                read;
 
232
        char            name[NAMEDATALEN];
 
233
        char            name2[NAMEDATALEN];
 
234
 
 
235
        Assert(s && aip);
 
236
 
 
237
#ifdef ACLDEBUG
 
238
        elog(LOG, "aclparse: input = \"%s\"", s);
 
239
#endif
 
240
        s = getid(s, name);
 
241
        if (*s != '=')
 
242
        {
 
243
                /* we just read a keyword, not a name */
 
244
                if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
 
245
                        ereport(ERROR,
 
246
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
247
                                         errmsg("unrecognized key word: \"%s\"", name),
 
248
                                         errhint("ACL key word must be \"group\" or \"user\".")));
 
249
                s = getid(s, name);             /* move s to the name beyond the keyword */
 
250
                if (name[0] == '\0')
 
251
                        ereport(ERROR,
 
252
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
253
                                         errmsg("missing name"),
 
254
                                         errhint("A name must follow the \"group\" or \"user\" key word.")));
 
255
        }
 
256
 
 
257
        if (*s != '=')
 
258
                ereport(ERROR,
 
259
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
260
                                 errmsg("missing \"=\" sign")));
 
261
 
 
262
        privs = goption = ACL_NO_RIGHTS;
 
263
 
 
264
        for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
 
265
        {
 
266
                switch (*s)
 
267
                {
 
268
                        case '*':
 
269
                                goption |= read;
 
270
                                break;
 
271
                        case ACL_INSERT_CHR:
 
272
                                read = ACL_INSERT;
 
273
                                break;
 
274
                        case ACL_SELECT_CHR:
 
275
                                read = ACL_SELECT;
 
276
                                break;
 
277
                        case ACL_UPDATE_CHR:
 
278
                                read = ACL_UPDATE;
 
279
                                break;
 
280
                        case ACL_DELETE_CHR:
 
281
                                read = ACL_DELETE;
 
282
                                break;
 
283
                        case ACL_TRUNCATE_CHR:
 
284
                                read = ACL_TRUNCATE;
 
285
                                break;
 
286
                        case ACL_REFERENCES_CHR:
 
287
                                read = ACL_REFERENCES;
 
288
                                break;
 
289
                        case ACL_TRIGGER_CHR:
 
290
                                read = ACL_TRIGGER;
 
291
                                break;
 
292
                        case ACL_EXECUTE_CHR:
 
293
                                read = ACL_EXECUTE;
 
294
                                break;
 
295
                        case ACL_USAGE_CHR:
 
296
                                read = ACL_USAGE;
 
297
                                break;
 
298
                        case ACL_CREATE_CHR:
 
299
                                read = ACL_CREATE;
 
300
                                break;
 
301
                        case ACL_CREATE_TEMP_CHR:
 
302
                                read = ACL_CREATE_TEMP;
 
303
                                break;
 
304
                        case ACL_CONNECT_CHR:
 
305
                                read = ACL_CONNECT;
 
306
                                break;
 
307
                        case 'R':                       /* ignore old RULE privileges */
 
308
                                read = 0;
 
309
                                break;
 
310
                        default:
 
311
                                ereport(ERROR,
 
312
                                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
313
                                          errmsg("invalid mode character: must be one of \"%s\"",
 
314
                                                         ACL_ALL_RIGHTS_STR)));
 
315
                }
 
316
 
 
317
                privs |= read;
 
318
        }
 
319
 
 
320
        if (name[0] == '\0')
 
321
                aip->ai_grantee = ACL_ID_PUBLIC;
 
322
        else
 
323
                aip->ai_grantee = get_roleid_checked(name);
 
324
 
 
325
        /*
 
326
         * XXX Allow a degree of backward compatibility by defaulting the grantor
 
327
         * to the superuser.
 
328
         */
 
329
        if (*s == '/')
 
330
        {
 
331
                s = getid(s + 1, name2);
 
332
                if (name2[0] == '\0')
 
333
                        ereport(ERROR,
 
334
                                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
335
                                         errmsg("a name must follow the \"/\" sign")));
 
336
                aip->ai_grantor = get_roleid_checked(name2);
 
337
        }
 
338
        else
 
339
        {
 
340
                aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
 
341
                ereport(WARNING,
 
342
                                (errcode(ERRCODE_INVALID_GRANTOR),
 
343
                                 errmsg("defaulting grantor to user ID %u",
 
344
                                                BOOTSTRAP_SUPERUSERID)));
 
345
        }
 
346
 
 
347
        ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
 
348
 
 
349
#ifdef ACLDEBUG
 
350
        elog(LOG, "aclparse: correctly read [%u %x %x]",
 
351
                 aip->ai_grantee, privs, goption);
 
352
#endif
 
353
 
 
354
        return s;
 
355
}
 
356
 
 
357
/*
 
358
 * allocacl
 
359
 *              Allocates storage for a new Acl with 'n' entries.
 
360
 *
 
361
 * RETURNS:
 
362
 *              the new Acl
 
363
 */
 
364
static Acl *
 
365
allocacl(int n)
 
366
{
 
367
        Acl                *new_acl;
 
368
        Size            size;
 
369
 
 
370
        if (n < 0)
 
371
                elog(ERROR, "invalid size: %d", n);
 
372
        size = ACL_N_SIZE(n);
 
373
        new_acl = (Acl *) palloc0(size);
 
374
        SET_VARSIZE(new_acl, size);
 
375
        new_acl->ndim = 1;
 
376
        new_acl->dataoffset = 0;        /* we never put in any nulls */
 
377
        new_acl->elemtype = ACLITEMOID;
 
378
        ARR_LBOUND(new_acl)[0] = 1;
 
379
        ARR_DIMS(new_acl)[0] = n;
 
380
        return new_acl;
 
381
}
 
382
 
 
383
/*
 
384
 * Copy an ACL
 
385
 */
 
386
Acl *
 
387
aclcopy(const Acl *orig_acl)
 
388
{
 
389
        Acl *result_acl;
 
390
 
 
391
        result_acl = allocacl(ACL_NUM(orig_acl));
 
392
 
 
393
        memcpy(ACL_DAT(result_acl),
 
394
                   ACL_DAT(orig_acl),
 
395
                   ACL_NUM(orig_acl) * sizeof(AclItem));
 
396
 
 
397
        return result_acl;
 
398
}
 
399
 
 
400
/*
 
401
 * Concatenate two ACLs
 
402
 *
 
403
 * This is a bit cheesy, since we may produce an ACL with redundant entries.
 
404
 * Be careful what the result is used for!
 
405
 */
 
406
Acl *
 
407
aclconcat(const Acl *left_acl, const Acl *right_acl)
 
408
{
 
409
        Acl *result_acl;
 
410
 
 
411
        result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
 
412
 
 
413
        memcpy(ACL_DAT(result_acl),
 
414
                   ACL_DAT(left_acl),
 
415
                   ACL_NUM(left_acl) * sizeof(AclItem));
 
416
 
 
417
        memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
 
418
                   ACL_DAT(right_acl),
 
419
                   ACL_NUM(right_acl) * sizeof(AclItem));
 
420
 
 
421
        return result_acl;
 
422
}
 
423
 
 
424
/*
 
425
 * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
 
426
 */
 
427
static void
 
428
check_acl(const Acl *acl)
 
429
{
 
430
        if (ARR_ELEMTYPE(acl) != ACLITEMOID)
 
431
                ereport(ERROR,
 
432
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
433
                                 errmsg("ACL array contains wrong data type")));
 
434
        if (ARR_NDIM(acl) != 1)
 
435
                ereport(ERROR,
 
436
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
437
                                 errmsg("ACL arrays must be one-dimensional")));
 
438
        if (ARR_HASNULL(acl))
 
439
                ereport(ERROR,
 
440
                                (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
 
441
                                 errmsg("ACL arrays must not contain null values")));
 
442
}
 
443
 
 
444
/*
 
445
 * aclitemin
 
446
 *              Allocates storage for, and fills in, a new AclItem given a string
 
447
 *              's' that contains an ACL specification.  See aclparse for details.
 
448
 *
 
449
 * RETURNS:
 
450
 *              the new AclItem
 
451
 */
 
452
Datum
 
453
aclitemin(PG_FUNCTION_ARGS)
 
454
{
 
455
        const char *s = PG_GETARG_CSTRING(0);
 
456
        AclItem    *aip;
 
457
 
 
458
        aip = (AclItem *) palloc(sizeof(AclItem));
 
459
        s = aclparse(s, aip);
 
460
        while (isspace((unsigned char) *s))
 
461
                ++s;
 
462
        if (*s)
 
463
                ereport(ERROR,
 
464
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
465
                           errmsg("extra garbage at the end of the ACL specification")));
 
466
 
 
467
        PG_RETURN_ACLITEM_P(aip);
 
468
}
 
469
 
 
470
/*
 
471
 * aclitemout
 
472
 *              Allocates storage for, and fills in, a new null-delimited string
 
473
 *              containing a formatted ACL specification.  See aclparse for details.
 
474
 *
 
475
 * RETURNS:
 
476
 *              the new string
 
477
 */
 
478
Datum
 
479
aclitemout(PG_FUNCTION_ARGS)
 
480
{
 
481
        AclItem    *aip = PG_GETARG_ACLITEM_P(0);
 
482
        char       *p;
 
483
        char       *out;
 
484
        HeapTuple       htup;
 
485
        unsigned        i;
 
486
 
 
487
        out = palloc(strlen("=/") +
 
488
                                 2 * N_ACL_RIGHTS +
 
489
                                 2 * (2 * NAMEDATALEN + 2) +
 
490
                                 1);
 
491
 
 
492
        p = out;
 
493
        *p = '\0';
 
494
 
 
495
        if (aip->ai_grantee != ACL_ID_PUBLIC)
 
496
        {
 
497
                htup = SearchSysCache(AUTHOID,
 
498
                                                          ObjectIdGetDatum(aip->ai_grantee),
 
499
                                                          0, 0, 0);
 
500
                if (HeapTupleIsValid(htup))
 
501
                {
 
502
                        putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
 
503
                        ReleaseSysCache(htup);
 
504
                }
 
505
                else
 
506
                {
 
507
                        /* Generate numeric OID if we don't find an entry */
 
508
                        sprintf(p, "%u", aip->ai_grantee);
 
509
                }
 
510
        }
 
511
        while (*p)
 
512
                ++p;
 
513
 
 
514
        *p++ = '=';
 
515
 
 
516
        for (i = 0; i < N_ACL_RIGHTS; ++i)
 
517
        {
 
518
                if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
 
519
                        *p++ = ACL_ALL_RIGHTS_STR[i];
 
520
                if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
 
521
                        *p++ = '*';
 
522
        }
 
523
 
 
524
        *p++ = '/';
 
525
        *p = '\0';
 
526
 
 
527
        htup = SearchSysCache(AUTHOID,
 
528
                                                  ObjectIdGetDatum(aip->ai_grantor),
 
529
                                                  0, 0, 0);
 
530
        if (HeapTupleIsValid(htup))
 
531
        {
 
532
                putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
 
533
                ReleaseSysCache(htup);
 
534
        }
 
535
        else
 
536
        {
 
537
                /* Generate numeric OID if we don't find an entry */
 
538
                sprintf(p, "%u", aip->ai_grantor);
 
539
        }
 
540
 
 
541
        PG_RETURN_CSTRING(out);
 
542
}
 
543
 
 
544
/*
 
545
 * aclitem_match
 
546
 *              Two AclItems are considered to match iff they have the same
 
547
 *              grantee and grantor; the privileges are ignored.
 
548
 */
 
549
static bool
 
550
aclitem_match(const AclItem *a1, const AclItem *a2)
 
551
{
 
552
        return a1->ai_grantee == a2->ai_grantee &&
 
553
                a1->ai_grantor == a2->ai_grantor;
 
554
}
 
555
 
 
556
/*
 
557
 * aclitem equality operator
 
558
 */
 
559
Datum
 
560
aclitem_eq(PG_FUNCTION_ARGS)
 
561
{
 
562
        AclItem    *a1 = PG_GETARG_ACLITEM_P(0);
 
563
        AclItem    *a2 = PG_GETARG_ACLITEM_P(1);
 
564
        bool            result;
 
565
 
 
566
        result = a1->ai_privs == a2->ai_privs &&
 
567
                a1->ai_grantee == a2->ai_grantee &&
 
568
                a1->ai_grantor == a2->ai_grantor;
 
569
        PG_RETURN_BOOL(result);
 
570
}
 
571
 
 
572
/*
 
573
 * aclitem hash function
 
574
 *
 
575
 * We make aclitems hashable not so much because anyone is likely to hash
 
576
 * them, as because we want array equality to work on aclitem arrays, and
 
577
 * with the typcache mechanism we must have a hash or btree opclass.
 
578
 */
 
579
Datum
 
580
hash_aclitem(PG_FUNCTION_ARGS)
 
581
{
 
582
        AclItem    *a = PG_GETARG_ACLITEM_P(0);
 
583
 
 
584
        /* not very bright, but avoids any issue of padding in struct */
 
585
        PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
 
586
}
 
587
 
 
588
 
 
589
/*
 
590
 * acldefault()  --- create an ACL describing default access permissions
 
591
 *
 
592
 * Change this routine if you want to alter the default access policy for
 
593
 * newly-created objects (or any object with a NULL acl entry).
 
594
 */
 
595
Acl *
 
596
acldefault(GrantObjectType objtype, Oid ownerId)
 
597
{
 
598
        AclMode         world_default;
 
599
        AclMode         owner_default;
 
600
        int                     nacl;
 
601
        Acl                *acl;
 
602
        AclItem    *aip;
 
603
 
 
604
        switch (objtype)
 
605
        {
 
606
                case ACL_OBJECT_COLUMN:
 
607
                        /* by default, columns have no extra privileges */
 
608
                        world_default = ACL_NO_RIGHTS;
 
609
                        owner_default = ACL_NO_RIGHTS;
 
610
                        break;
 
611
                case ACL_OBJECT_RELATION:
 
612
                        world_default = ACL_NO_RIGHTS;
 
613
                        owner_default = ACL_ALL_RIGHTS_RELATION;
 
614
                        break;
 
615
                case ACL_OBJECT_SEQUENCE:
 
616
                        world_default = ACL_NO_RIGHTS;
 
617
                        owner_default = ACL_ALL_RIGHTS_SEQUENCE;
 
618
                        break;
 
619
                case ACL_OBJECT_DATABASE:
 
620
                        /* for backwards compatibility, grant some rights by default */
 
621
                        world_default = ACL_CREATE_TEMP | ACL_CONNECT;
 
622
                        owner_default = ACL_ALL_RIGHTS_DATABASE;
 
623
                        break;
 
624
                case ACL_OBJECT_FUNCTION:
 
625
                        /* Grant EXECUTE by default, for now */
 
626
                        world_default = ACL_EXECUTE;
 
627
                        owner_default = ACL_ALL_RIGHTS_FUNCTION;
 
628
                        break;
 
629
                case ACL_OBJECT_LANGUAGE:
 
630
                        /* Grant USAGE by default, for now */
 
631
                        world_default = ACL_USAGE;
 
632
                        owner_default = ACL_ALL_RIGHTS_LANGUAGE;
 
633
                        break;
 
634
                case ACL_OBJECT_NAMESPACE:
 
635
                        world_default = ACL_NO_RIGHTS;
 
636
                        owner_default = ACL_ALL_RIGHTS_NAMESPACE;
 
637
                        break;
 
638
                case ACL_OBJECT_TABLESPACE:
 
639
                        world_default = ACL_NO_RIGHTS;
 
640
                        owner_default = ACL_ALL_RIGHTS_TABLESPACE;
 
641
                        break;
 
642
                case ACL_OBJECT_FDW:
 
643
                        world_default = ACL_NO_RIGHTS;
 
644
                        owner_default = ACL_ALL_RIGHTS_FDW;
 
645
                        break;
 
646
                case ACL_OBJECT_FOREIGN_SERVER:
 
647
                        world_default = ACL_NO_RIGHTS;
 
648
                        owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
 
649
                        break;
 
650
                default:
 
651
                        elog(ERROR, "unrecognized objtype: %d", (int) objtype);
 
652
                        world_default = ACL_NO_RIGHTS;          /* keep compiler quiet */
 
653
                        owner_default = ACL_NO_RIGHTS;
 
654
                        break;
 
655
        }
 
656
 
 
657
        nacl = 0;
 
658
        if (world_default != ACL_NO_RIGHTS)
 
659
                nacl++;
 
660
        if (owner_default != ACL_NO_RIGHTS)
 
661
                nacl++;
 
662
 
 
663
        acl = allocacl(nacl);
 
664
        aip = ACL_DAT(acl);
 
665
 
 
666
        if (world_default != ACL_NO_RIGHTS)
 
667
        {
 
668
                aip->ai_grantee = ACL_ID_PUBLIC;
 
669
                aip->ai_grantor = ownerId;
 
670
                ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
 
671
                aip++;
 
672
        }
 
673
 
 
674
        /*
 
675
         * Note that the owner's entry shows all ordinary privileges but no grant
 
676
         * options.  This is because his grant options come "from the system" and
 
677
         * not from his own efforts.  (The SQL spec says that the owner's rights
 
678
         * come from a "_SYSTEM" authid.)  However, we do consider that the
 
679
         * owner's ordinary privileges are self-granted; this lets him revoke
 
680
         * them.  We implement the owner's grant options without any explicit
 
681
         * "_SYSTEM"-like ACL entry, by internally special-casing the owner
 
682
         * whereever we are testing grant options.
 
683
         */
 
684
        if (owner_default != ACL_NO_RIGHTS)
 
685
        {
 
686
                aip->ai_grantee = ownerId;
 
687
                aip->ai_grantor = ownerId;
 
688
                ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
 
689
        }
 
690
 
 
691
        return acl;
 
692
}
 
693
 
 
694
 
 
695
/*
 
696
 * Update an ACL array to add or remove specified privileges.
 
697
 *
 
698
 *      old_acl: the input ACL array
 
699
 *      mod_aip: defines the privileges to be added, removed, or substituted
 
700
 *      modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
 
701
 *      ownerId: Oid of object owner
 
702
 *      behavior: RESTRICT or CASCADE behavior for recursive removal
 
703
 *
 
704
 * ownerid and behavior are only relevant when the update operation specifies
 
705
 * deletion of grant options.
 
706
 *
 
707
 * The result is a modified copy; the input object is not changed.
 
708
 *
 
709
 * NB: caller is responsible for having detoasted the input ACL, if needed.
 
710
 */
 
711
Acl *
 
712
aclupdate(const Acl *old_acl, const AclItem *mod_aip,
 
713
                  int modechg, Oid ownerId, DropBehavior behavior)
 
714
{
 
715
        Acl                *new_acl = NULL;
 
716
        AclItem    *old_aip,
 
717
                           *new_aip = NULL;
 
718
        AclMode         old_rights,
 
719
                                old_goptions,
 
720
                                new_rights,
 
721
                                new_goptions;
 
722
        int                     dst,
 
723
                                num;
 
724
 
 
725
        /* Caller probably already checked old_acl, but be safe */
 
726
        check_acl(old_acl);
 
727
 
 
728
        /* If granting grant options, check for circularity */
 
729
        if (modechg != ACL_MODECHG_DEL &&
 
730
                ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
 
731
                check_circularity(old_acl, mod_aip, ownerId);
 
732
 
 
733
        num = ACL_NUM(old_acl);
 
734
        old_aip = ACL_DAT(old_acl);
 
735
 
 
736
        /*
 
737
         * Search the ACL for an existing entry for this grantee and grantor. If
 
738
         * one exists, just modify the entry in-place (well, in the same position,
 
739
         * since we actually return a copy); otherwise, insert the new entry at
 
740
         * the end.
 
741
         */
 
742
 
 
743
        for (dst = 0; dst < num; ++dst)
 
744
        {
 
745
                if (aclitem_match(mod_aip, old_aip + dst))
 
746
                {
 
747
                        /* found a match, so modify existing item */
 
748
                        new_acl = allocacl(num);
 
749
                        new_aip = ACL_DAT(new_acl);
 
750
                        memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
 
751
                        break;
 
752
                }
 
753
        }
 
754
 
 
755
        if (dst == num)
 
756
        {
 
757
                /* need to append a new item */
 
758
                new_acl = allocacl(num + 1);
 
759
                new_aip = ACL_DAT(new_acl);
 
760
                memcpy(new_aip, old_aip, num * sizeof(AclItem));
 
761
 
 
762
                /* initialize the new entry with no permissions */
 
763
                new_aip[dst].ai_grantee = mod_aip->ai_grantee;
 
764
                new_aip[dst].ai_grantor = mod_aip->ai_grantor;
 
765
                ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
 
766
                                                                   ACL_NO_RIGHTS, ACL_NO_RIGHTS);
 
767
                num++;                                  /* set num to the size of new_acl */
 
768
        }
 
769
 
 
770
        old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
 
771
        old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
 
772
 
 
773
        /* apply the specified permissions change */
 
774
        switch (modechg)
 
775
        {
 
776
                case ACL_MODECHG_ADD:
 
777
                        ACLITEM_SET_RIGHTS(new_aip[dst],
 
778
                                                           old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
 
779
                        break;
 
780
                case ACL_MODECHG_DEL:
 
781
                        ACLITEM_SET_RIGHTS(new_aip[dst],
 
782
                                                           old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
 
783
                        break;
 
784
                case ACL_MODECHG_EQL:
 
785
                        ACLITEM_SET_RIGHTS(new_aip[dst],
 
786
                                                           ACLITEM_GET_RIGHTS(*mod_aip));
 
787
                        break;
 
788
        }
 
789
 
 
790
        new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
 
791
        new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
 
792
 
 
793
        /*
 
794
         * If the adjusted entry has no permissions, delete it from the list.
 
795
         */
 
796
        if (new_rights == ACL_NO_RIGHTS)
 
797
        {
 
798
                memmove(new_aip + dst,
 
799
                                new_aip + dst + 1,
 
800
                                (num - dst - 1) * sizeof(AclItem));
 
801
                /* Adjust array size to be 'num - 1' items */
 
802
                ARR_DIMS(new_acl)[0] = num - 1;
 
803
                SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
 
804
        }
 
805
 
 
806
        /*
 
807
         * Remove abandoned privileges (cascading revoke).      Currently we can only
 
808
         * handle this when the grantee is not PUBLIC.
 
809
         */
 
810
        if ((old_goptions & ~new_goptions) != 0)
 
811
        {
 
812
                Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
 
813
                new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
 
814
                                                                   (old_goptions & ~new_goptions),
 
815
                                                                   ownerId, behavior);
 
816
        }
 
817
 
 
818
        return new_acl;
 
819
}
 
820
 
 
821
/*
 
822
 * Update an ACL array to reflect a change of owner to the parent object
 
823
 *
 
824
 *      old_acl: the input ACL array (must not be NULL)
 
825
 *      oldOwnerId: Oid of the old object owner
 
826
 *      newOwnerId: Oid of the new object owner
 
827
 *
 
828
 * The result is a modified copy; the input object is not changed.
 
829
 *
 
830
 * NB: caller is responsible for having detoasted the input ACL, if needed.
 
831
 */
 
832
Acl *
 
833
aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
 
834
{
 
835
        Acl                *new_acl;
 
836
        AclItem    *new_aip;
 
837
        AclItem    *old_aip;
 
838
        AclItem    *dst_aip;
 
839
        AclItem    *src_aip;
 
840
        AclItem    *targ_aip;
 
841
        bool            newpresent = false;
 
842
        int                     dst,
 
843
                                src,
 
844
                                targ,
 
845
                                num;
 
846
 
 
847
        check_acl(old_acl);
 
848
 
 
849
        /*
 
850
         * Make a copy of the given ACL, substituting new owner ID for old
 
851
         * wherever it appears as either grantor or grantee.  Also note if the new
 
852
         * owner ID is already present.
 
853
         */
 
854
        num = ACL_NUM(old_acl);
 
855
        old_aip = ACL_DAT(old_acl);
 
856
        new_acl = allocacl(num);
 
857
        new_aip = ACL_DAT(new_acl);
 
858
        memcpy(new_aip, old_aip, num * sizeof(AclItem));
 
859
        for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
 
860
        {
 
861
                if (dst_aip->ai_grantor == oldOwnerId)
 
862
                        dst_aip->ai_grantor = newOwnerId;
 
863
                else if (dst_aip->ai_grantor == newOwnerId)
 
864
                        newpresent = true;
 
865
                if (dst_aip->ai_grantee == oldOwnerId)
 
866
                        dst_aip->ai_grantee = newOwnerId;
 
867
                else if (dst_aip->ai_grantee == newOwnerId)
 
868
                        newpresent = true;
 
869
        }
 
870
 
 
871
        /*
 
872
         * If the old ACL contained any references to the new owner, then we may
 
873
         * now have generated an ACL containing duplicate entries.      Find them and
 
874
         * merge them so that there are not duplicates.  (This is relatively
 
875
         * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
 
876
         * be the normal case.)
 
877
         *
 
878
         * To simplify deletion of duplicate entries, we temporarily leave them in
 
879
         * the array but set their privilege masks to zero; when we reach such an
 
880
         * entry it's just skipped.  (Thus, a side effect of this code will be to
 
881
         * remove privilege-free entries, should there be any in the input.)  dst
 
882
         * is the next output slot, targ is the currently considered input slot
 
883
         * (always >= dst), and src scans entries to the right of targ looking for
 
884
         * duplicates.  Once an entry has been emitted to dst it is known
 
885
         * duplicate-free and need not be considered anymore.
 
886
         */
 
887
        if (newpresent)
 
888
        {
 
889
                dst = 0;
 
890
                for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
 
891
                {
 
892
                        /* ignore if deleted in an earlier pass */
 
893
                        if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
 
894
                                continue;
 
895
                        /* find and merge any duplicates */
 
896
                        for (src = targ + 1, src_aip = targ_aip + 1; src < num;
 
897
                                 src++, src_aip++)
 
898
                        {
 
899
                                if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
 
900
                                        continue;
 
901
                                if (aclitem_match(targ_aip, src_aip))
 
902
                                {
 
903
                                        ACLITEM_SET_RIGHTS(*targ_aip,
 
904
                                                                           ACLITEM_GET_RIGHTS(*targ_aip) |
 
905
                                                                           ACLITEM_GET_RIGHTS(*src_aip));
 
906
                                        /* mark the duplicate deleted */
 
907
                                        ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
 
908
                                }
 
909
                        }
 
910
                        /* and emit to output */
 
911
                        new_aip[dst] = *targ_aip;
 
912
                        dst++;
 
913
                }
 
914
                /* Adjust array size to be 'dst' items */
 
915
                ARR_DIMS(new_acl)[0] = dst;
 
916
                SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
 
917
        }
 
918
 
 
919
        return new_acl;
 
920
}
 
921
 
 
922
 
 
923
/*
 
924
 * When granting grant options, we must disallow attempts to set up circular
 
925
 * chains of grant options.  Suppose A (the object owner) grants B some
 
926
 * privileges with grant option, and B re-grants them to C.  If C could
 
927
 * grant the privileges to B as well, then A would be unable to effectively
 
928
 * revoke the privileges from B, since recursive_revoke would consider that
 
929
 * B still has 'em from C.
 
930
 *
 
931
 * We check for this by recursively deleting all grant options belonging to
 
932
 * the target grantee, and then seeing if the would-be grantor still has the
 
933
 * grant option or not.
 
934
 */
 
935
static void
 
936
check_circularity(const Acl *old_acl, const AclItem *mod_aip,
 
937
                                  Oid ownerId)
 
938
{
 
939
        Acl                *acl;
 
940
        AclItem    *aip;
 
941
        int                     i,
 
942
                                num;
 
943
        AclMode         own_privs;
 
944
 
 
945
        check_acl(old_acl);
 
946
 
 
947
        /*
 
948
         * For now, grant options can only be granted to roles, not PUBLIC.
 
949
         * Otherwise we'd have to work a bit harder here.
 
950
         */
 
951
        Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
 
952
 
 
953
        /* The owner always has grant options, no need to check */
 
954
        if (mod_aip->ai_grantor == ownerId)
 
955
                return;
 
956
 
 
957
        /* Make a working copy */
 
958
        acl = allocacl(ACL_NUM(old_acl));
 
959
        memcpy(acl, old_acl, ACL_SIZE(old_acl));
 
960
 
 
961
        /* Zap all grant options of target grantee, plus what depends on 'em */
 
962
cc_restart:
 
963
        num = ACL_NUM(acl);
 
964
        aip = ACL_DAT(acl);
 
965
        for (i = 0; i < num; i++)
 
966
        {
 
967
                if (aip[i].ai_grantee == mod_aip->ai_grantee &&
 
968
                        ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
 
969
                {
 
970
                        Acl                *new_acl;
 
971
 
 
972
                        /* We'll actually zap ordinary privs too, but no matter */
 
973
                        new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
 
974
                                                                ownerId, DROP_CASCADE);
 
975
 
 
976
                        pfree(acl);
 
977
                        acl = new_acl;
 
978
 
 
979
                        goto cc_restart;
 
980
                }
 
981
        }
 
982
 
 
983
        /* Now we can compute grantor's independently-derived privileges */
 
984
        own_privs = aclmask(acl,
 
985
                                                mod_aip->ai_grantor,
 
986
                                                ownerId,
 
987
                                                ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
 
988
                                                ACLMASK_ALL);
 
989
        own_privs = ACL_OPTION_TO_PRIVS(own_privs);
 
990
 
 
991
        if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
 
992
                ereport(ERROR,
 
993
                                (errcode(ERRCODE_INVALID_GRANT_OPERATION),
 
994
                errmsg("grant options cannot be granted back to your own grantor")));
 
995
 
 
996
        pfree(acl);
 
997
}
 
998
 
 
999
 
 
1000
/*
 
1001
 * Ensure that no privilege is "abandoned".  A privilege is abandoned
 
1002
 * if the user that granted the privilege loses the grant option.  (So
 
1003
 * the chain through which it was granted is broken.)  Either the
 
1004
 * abandoned privileges are revoked as well, or an error message is
 
1005
 * printed, depending on the drop behavior option.
 
1006
 *
 
1007
 *      acl: the input ACL list
 
1008
 *      grantee: the user from whom some grant options have been revoked
 
1009
 *      revoke_privs: the grant options being revoked
 
1010
 *      ownerId: Oid of object owner
 
1011
 *      behavior: RESTRICT or CASCADE behavior for recursive removal
 
1012
 *
 
1013
 * The input Acl object is pfree'd if replaced.
 
1014
 */
 
1015
static Acl *
 
1016
recursive_revoke(Acl *acl,
 
1017
                                 Oid grantee,
 
1018
                                 AclMode revoke_privs,
 
1019
                                 Oid ownerId,
 
1020
                                 DropBehavior behavior)
 
1021
{
 
1022
        AclMode         still_has;
 
1023
        AclItem    *aip;
 
1024
        int                     i,
 
1025
                                num;
 
1026
 
 
1027
        check_acl(acl);
 
1028
 
 
1029
        /* The owner can never truly lose grant options, so short-circuit */
 
1030
        if (grantee == ownerId)
 
1031
                return acl;
 
1032
 
 
1033
        /* The grantee might still have the privileges via another grantor */
 
1034
        still_has = aclmask(acl, grantee, ownerId,
 
1035
                                                ACL_GRANT_OPTION_FOR(revoke_privs),
 
1036
                                                ACLMASK_ALL);
 
1037
        revoke_privs &= ~still_has;
 
1038
        if (revoke_privs == ACL_NO_RIGHTS)
 
1039
                return acl;
 
1040
 
 
1041
restart:
 
1042
        num = ACL_NUM(acl);
 
1043
        aip = ACL_DAT(acl);
 
1044
        for (i = 0; i < num; i++)
 
1045
        {
 
1046
                if (aip[i].ai_grantor == grantee
 
1047
                        && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
 
1048
                {
 
1049
                        AclItem         mod_acl;
 
1050
                        Acl                *new_acl;
 
1051
 
 
1052
                        if (behavior == DROP_RESTRICT)
 
1053
                                ereport(ERROR,
 
1054
                                                (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
 
1055
                                                 errmsg("dependent privileges exist"),
 
1056
                                                 errhint("Use CASCADE to revoke them too.")));
 
1057
 
 
1058
                        mod_acl.ai_grantor = grantee;
 
1059
                        mod_acl.ai_grantee = aip[i].ai_grantee;
 
1060
                        ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
 
1061
                                                                           revoke_privs,
 
1062
                                                                           revoke_privs);
 
1063
 
 
1064
                        new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
 
1065
                                                                ownerId, behavior);
 
1066
 
 
1067
                        pfree(acl);
 
1068
                        acl = new_acl;
 
1069
 
 
1070
                        goto restart;
 
1071
                }
 
1072
        }
 
1073
 
 
1074
        return acl;
 
1075
}
 
1076
 
 
1077
 
 
1078
/*
 
1079
 * aclmask --- compute bitmask of all privileges held by roleid.
 
1080
 *
 
1081
 * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
 
1082
 * held by the given roleid according to the given ACL list, ANDed
 
1083
 * with 'mask'.  (The point of passing 'mask' is to let the routine
 
1084
 * exit early if all privileges of interest have been found.)
 
1085
 *
 
1086
 * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
 
1087
 * is known true.  (This lets us exit soonest in cases where the
 
1088
 * caller is only going to test for zero or nonzero result.)
 
1089
 *
 
1090
 * Usage patterns:
 
1091
 *
 
1092
 * To see if any of a set of privileges are held:
 
1093
 *              if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
 
1094
 *
 
1095
 * To see if all of a set of privileges are held:
 
1096
 *              if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
 
1097
 *
 
1098
 * To determine exactly which of a set of privileges are held:
 
1099
 *              heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
 
1100
 */
 
1101
AclMode
 
1102
aclmask(const Acl *acl, Oid roleid, Oid ownerId,
 
1103
                AclMode mask, AclMaskHow how)
 
1104
{
 
1105
        AclMode         result;
 
1106
        AclMode         remaining;
 
1107
        AclItem    *aidat;
 
1108
        int                     i,
 
1109
                                num;
 
1110
 
 
1111
        /*
 
1112
         * Null ACL should not happen, since caller should have inserted
 
1113
         * appropriate default
 
1114
         */
 
1115
        if (acl == NULL)
 
1116
                elog(ERROR, "null ACL");
 
1117
 
 
1118
        check_acl(acl);
 
1119
 
 
1120
        /* Quick exit for mask == 0 */
 
1121
        if (mask == 0)
 
1122
                return 0;
 
1123
 
 
1124
        result = 0;
 
1125
 
 
1126
        /* Owner always implicitly has all grant options */
 
1127
        if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
 
1128
                has_privs_of_role(roleid, ownerId))
 
1129
        {
 
1130
                result = mask & ACLITEM_ALL_GOPTION_BITS;
 
1131
                if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 
1132
                        return result;
 
1133
        }
 
1134
 
 
1135
        num = ACL_NUM(acl);
 
1136
        aidat = ACL_DAT(acl);
 
1137
 
 
1138
        /*
 
1139
         * Check privileges granted directly to roleid or to public
 
1140
         */
 
1141
        for (i = 0; i < num; i++)
 
1142
        {
 
1143
                AclItem    *aidata = &aidat[i];
 
1144
 
 
1145
                if (aidata->ai_grantee == ACL_ID_PUBLIC ||
 
1146
                        aidata->ai_grantee == roleid)
 
1147
                {
 
1148
                        result |= aidata->ai_privs & mask;
 
1149
                        if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 
1150
                                return result;
 
1151
                }
 
1152
        }
 
1153
 
 
1154
        /*
 
1155
         * Check privileges granted indirectly via role memberships. We do this in
 
1156
         * a separate pass to minimize expensive indirect membership tests.  In
 
1157
         * particular, it's worth testing whether a given ACL entry grants any
 
1158
         * privileges still of interest before we perform the has_privs_of_role
 
1159
         * test.
 
1160
         */
 
1161
        remaining = mask & ~result;
 
1162
        for (i = 0; i < num; i++)
 
1163
        {
 
1164
                AclItem    *aidata = &aidat[i];
 
1165
 
 
1166
                if (aidata->ai_grantee == ACL_ID_PUBLIC ||
 
1167
                        aidata->ai_grantee == roleid)
 
1168
                        continue;                       /* already checked it */
 
1169
 
 
1170
                if ((aidata->ai_privs & remaining) &&
 
1171
                        has_privs_of_role(roleid, aidata->ai_grantee))
 
1172
                {
 
1173
                        result |= aidata->ai_privs & mask;
 
1174
                        if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 
1175
                                return result;
 
1176
                        remaining = mask & ~result;
 
1177
                }
 
1178
        }
 
1179
 
 
1180
        return result;
 
1181
}
 
1182
 
 
1183
 
 
1184
/*
 
1185
 * aclmask_direct --- compute bitmask of all privileges held by roleid.
 
1186
 *
 
1187
 * This is exactly like aclmask() except that we consider only privileges
 
1188
 * held *directly* by roleid, not those inherited via role membership.
 
1189
 */
 
1190
static AclMode
 
1191
aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
 
1192
                           AclMode mask, AclMaskHow how)
 
1193
{
 
1194
        AclMode         result;
 
1195
        AclItem    *aidat;
 
1196
        int                     i,
 
1197
                                num;
 
1198
 
 
1199
        /*
 
1200
         * Null ACL should not happen, since caller should have inserted
 
1201
         * appropriate default
 
1202
         */
 
1203
        if (acl == NULL)
 
1204
                elog(ERROR, "null ACL");
 
1205
 
 
1206
        check_acl(acl);
 
1207
 
 
1208
        /* Quick exit for mask == 0 */
 
1209
        if (mask == 0)
 
1210
                return 0;
 
1211
 
 
1212
        result = 0;
 
1213
 
 
1214
        /* Owner always implicitly has all grant options */
 
1215
        if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
 
1216
                roleid == ownerId)
 
1217
        {
 
1218
                result = mask & ACLITEM_ALL_GOPTION_BITS;
 
1219
                if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 
1220
                        return result;
 
1221
        }
 
1222
 
 
1223
        num = ACL_NUM(acl);
 
1224
        aidat = ACL_DAT(acl);
 
1225
 
 
1226
        /*
 
1227
         * Check privileges granted directly to roleid (and not to public)
 
1228
         */
 
1229
        for (i = 0; i < num; i++)
 
1230
        {
 
1231
                AclItem    *aidata = &aidat[i];
 
1232
 
 
1233
                if (aidata->ai_grantee == roleid)
 
1234
                {
 
1235
                        result |= aidata->ai_privs & mask;
 
1236
                        if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
 
1237
                                return result;
 
1238
                }
 
1239
        }
 
1240
 
 
1241
        return result;
 
1242
}
 
1243
 
 
1244
 
 
1245
/*
 
1246
 * aclmembers
 
1247
 *              Find out all the roleids mentioned in an Acl.
 
1248
 *              Note that we do not distinguish grantors from grantees.
 
1249
 *
 
1250
 * *roleids is set to point to a palloc'd array containing distinct OIDs
 
1251
 * in sorted order.  The length of the array is the function result.
 
1252
 */
 
1253
int
 
1254
aclmembers(const Acl *acl, Oid **roleids)
 
1255
{
 
1256
        Oid                *list;
 
1257
        const AclItem *acldat;
 
1258
        int                     i,
 
1259
                                j,
 
1260
                                k;
 
1261
 
 
1262
        if (acl == NULL || ACL_NUM(acl) == 0)
 
1263
        {
 
1264
                *roleids = NULL;
 
1265
                return 0;
 
1266
        }
 
1267
 
 
1268
        check_acl(acl);
 
1269
 
 
1270
        /* Allocate the worst-case space requirement */
 
1271
        list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
 
1272
        acldat = ACL_DAT(acl);
 
1273
 
 
1274
        /*
 
1275
         * Walk the ACL collecting mentioned RoleIds.
 
1276
         */
 
1277
        j = 0;
 
1278
        for (i = 0; i < ACL_NUM(acl); i++)
 
1279
        {
 
1280
                const AclItem *ai = &acldat[i];
 
1281
 
 
1282
                if (ai->ai_grantee != ACL_ID_PUBLIC)
 
1283
                        list[j++] = ai->ai_grantee;
 
1284
                /* grantor is currently never PUBLIC, but let's check anyway */
 
1285
                if (ai->ai_grantor != ACL_ID_PUBLIC)
 
1286
                        list[j++] = ai->ai_grantor;
 
1287
        }
 
1288
 
 
1289
        /* Sort the array */
 
1290
        qsort(list, j, sizeof(Oid), oidComparator);
 
1291
 
 
1292
        /* Remove duplicates from the array */
 
1293
        k = 0;
 
1294
        for (i = 1; i < j; i++)
 
1295
        {
 
1296
                if (list[k] != list[i])
 
1297
                        list[++k] = list[i];
 
1298
        }
 
1299
 
 
1300
        /*
 
1301
         * We could repalloc the array down to minimum size, but it's hardly worth
 
1302
         * it since it's only transient memory.
 
1303
         */
 
1304
        *roleids = list;
 
1305
 
 
1306
        return k + 1;
 
1307
}
 
1308
 
 
1309
/*
 
1310
 * oidComparator
 
1311
 *              qsort comparison function for Oids
 
1312
 */
 
1313
static int
 
1314
oidComparator(const void *arg1, const void *arg2)
 
1315
{
 
1316
        Oid                     oid1 = *(const Oid *) arg1;
 
1317
        Oid                     oid2 = *(const Oid *) arg2;
 
1318
 
 
1319
        if (oid1 > oid2)
 
1320
                return 1;
 
1321
        if (oid1 < oid2)
 
1322
                return -1;
 
1323
        return 0;
 
1324
}
 
1325
 
 
1326
 
 
1327
/*
 
1328
 * aclinsert (exported function)
 
1329
 */
 
1330
Datum
 
1331
aclinsert(PG_FUNCTION_ARGS)
 
1332
{
 
1333
        ereport(ERROR,
 
1334
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
1335
                         errmsg("aclinsert is no longer supported")));
 
1336
 
 
1337
        PG_RETURN_NULL();                       /* keep compiler quiet */
 
1338
}
 
1339
 
 
1340
Datum
 
1341
aclremove(PG_FUNCTION_ARGS)
 
1342
{
 
1343
        ereport(ERROR,
 
1344
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
1345
                         errmsg("aclremove is no longer supported")));
 
1346
 
 
1347
        PG_RETURN_NULL();                       /* keep compiler quiet */
 
1348
}
 
1349
 
 
1350
Datum
 
1351
aclcontains(PG_FUNCTION_ARGS)
 
1352
{
 
1353
        Acl                *acl = PG_GETARG_ACL_P(0);
 
1354
        AclItem    *aip = PG_GETARG_ACLITEM_P(1);
 
1355
        AclItem    *aidat;
 
1356
        int                     i,
 
1357
                                num;
 
1358
 
 
1359
        check_acl(acl);
 
1360
        num = ACL_NUM(acl);
 
1361
        aidat = ACL_DAT(acl);
 
1362
        for (i = 0; i < num; ++i)
 
1363
        {
 
1364
                if (aip->ai_grantee == aidat[i].ai_grantee &&
 
1365
                        aip->ai_grantor == aidat[i].ai_grantor &&
 
1366
                        (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
 
1367
                        PG_RETURN_BOOL(true);
 
1368
        }
 
1369
        PG_RETURN_BOOL(false);
 
1370
}
 
1371
 
 
1372
Datum
 
1373
makeaclitem(PG_FUNCTION_ARGS)
 
1374
{
 
1375
        Oid                     grantee = PG_GETARG_OID(0);
 
1376
        Oid                     grantor = PG_GETARG_OID(1);
 
1377
        text       *privtext = PG_GETARG_TEXT_P(2);
 
1378
        bool            goption = PG_GETARG_BOOL(3);
 
1379
        AclItem    *result;
 
1380
        AclMode         priv;
 
1381
 
 
1382
        priv = convert_priv_string(privtext);
 
1383
 
 
1384
        result = (AclItem *) palloc(sizeof(AclItem));
 
1385
 
 
1386
        result->ai_grantee = grantee;
 
1387
        result->ai_grantor = grantor;
 
1388
 
 
1389
        ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
 
1390
                                                           (goption ? priv : ACL_NO_RIGHTS));
 
1391
 
 
1392
        PG_RETURN_ACLITEM_P(result);
 
1393
}
 
1394
 
 
1395
static AclMode
 
1396
convert_priv_string(text *priv_type_text)
 
1397
{
 
1398
        char       *priv_type = text_to_cstring(priv_type_text);
 
1399
 
 
1400
        if (pg_strcasecmp(priv_type, "SELECT") == 0)
 
1401
                return ACL_SELECT;
 
1402
        if (pg_strcasecmp(priv_type, "INSERT") == 0)
 
1403
                return ACL_INSERT;
 
1404
        if (pg_strcasecmp(priv_type, "UPDATE") == 0)
 
1405
                return ACL_UPDATE;
 
1406
        if (pg_strcasecmp(priv_type, "DELETE") == 0)
 
1407
                return ACL_DELETE;
 
1408
        if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
 
1409
                return ACL_TRUNCATE;
 
1410
        if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
 
1411
                return ACL_REFERENCES;
 
1412
        if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
 
1413
                return ACL_TRIGGER;
 
1414
        if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
 
1415
                return ACL_EXECUTE;
 
1416
        if (pg_strcasecmp(priv_type, "USAGE") == 0)
 
1417
                return ACL_USAGE;
 
1418
        if (pg_strcasecmp(priv_type, "CREATE") == 0)
 
1419
                return ACL_CREATE;
 
1420
        if (pg_strcasecmp(priv_type, "TEMP") == 0)
 
1421
                return ACL_CREATE_TEMP;
 
1422
        if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
 
1423
                return ACL_CREATE_TEMP;
 
1424
        if (pg_strcasecmp(priv_type, "CONNECT") == 0)
 
1425
                return ACL_CONNECT;
 
1426
        if (pg_strcasecmp(priv_type, "RULE") == 0)
 
1427
                return 0;                               /* ignore old RULE privileges */
 
1428
 
 
1429
        ereport(ERROR,
 
1430
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
1431
                         errmsg("unrecognized privilege type: \"%s\"", priv_type)));
 
1432
        return ACL_NO_RIGHTS;           /* keep compiler quiet */
 
1433
}
 
1434
 
 
1435
 
 
1436
/*
 
1437
 * convert_any_priv_string: recognize privilege strings for has_foo_privilege
 
1438
 *
 
1439
 * We accept a comma-separated list of case-insensitive privilege names,
 
1440
 * producing a bitmask of the OR'd privilege bits.  We are liberal about
 
1441
 * whitespace between items, not so much about whitespace within items.
 
1442
 * The allowed privilege names are given as an array of priv_map structs,
 
1443
 * terminated by one with a NULL name pointer.
 
1444
 */
 
1445
static AclMode
 
1446
convert_any_priv_string(text *priv_type_text,
 
1447
                                                const priv_map *privileges)
 
1448
{
 
1449
        AclMode         result = 0;
 
1450
        char       *priv_type = text_to_cstring(priv_type_text);
 
1451
        char       *chunk;
 
1452
        char       *next_chunk;
 
1453
 
 
1454
        /* We rely on priv_type being a private, modifiable string */
 
1455
        for (chunk = priv_type; chunk; chunk = next_chunk)
 
1456
        {
 
1457
                int                     chunk_len;
 
1458
                const priv_map *this_priv;
 
1459
 
 
1460
                /* Split string at commas */
 
1461
                next_chunk = strchr(chunk, ',');
 
1462
                if (next_chunk)
 
1463
                        *next_chunk++ = '\0';
 
1464
 
 
1465
                /* Drop leading/trailing whitespace in this chunk */
 
1466
                while (*chunk && isspace((unsigned char) *chunk))
 
1467
                        chunk++;
 
1468
                chunk_len = strlen(chunk);
 
1469
                while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
 
1470
                        chunk_len--;
 
1471
                chunk[chunk_len] = '\0';
 
1472
 
 
1473
                /* Match to the privileges list */
 
1474
                for (this_priv = privileges; this_priv->name; this_priv++)
 
1475
                {
 
1476
                        if (pg_strcasecmp(this_priv->name, chunk) == 0)
 
1477
                        {
 
1478
                                result |= this_priv->value;
 
1479
                                break;
 
1480
                        }
 
1481
                }
 
1482
                if (!this_priv->name)
 
1483
                        ereport(ERROR,
 
1484
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
1485
                                         errmsg("unrecognized privilege type: \"%s\"", chunk)));
 
1486
        }
 
1487
 
 
1488
        pfree(priv_type);
 
1489
        return result;
 
1490
}
 
1491
 
 
1492
 
 
1493
/*
 
1494
 * has_table_privilege variants
 
1495
 *              These are all named "has_table_privilege" at the SQL level.
 
1496
 *              They take various combinations of relation name, relation OID,
 
1497
 *              user name, user OID, or implicit user = current_user.
 
1498
 *
 
1499
 *              The result is a boolean value: true if user has the indicated
 
1500
 *              privilege, false if not.  The variants that take a relation OID
 
1501
 *              return NULL if the OID doesn't exist (rather than failing, as
 
1502
 *              they did before Postgres 8.4).
 
1503
 */
 
1504
 
 
1505
/*
 
1506
 * has_table_privilege_name_name
 
1507
 *              Check user privileges on a table given
 
1508
 *              name username, text tablename, and text priv name.
 
1509
 */
 
1510
Datum
 
1511
has_table_privilege_name_name(PG_FUNCTION_ARGS)
 
1512
{
 
1513
        Name            rolename = PG_GETARG_NAME(0);
 
1514
        text       *tablename = PG_GETARG_TEXT_P(1);
 
1515
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1516
        Oid                     roleid;
 
1517
        Oid                     tableoid;
 
1518
        AclMode         mode;
 
1519
        AclResult       aclresult;
 
1520
 
 
1521
        roleid = get_roleid_checked(NameStr(*rolename));
 
1522
        tableoid = convert_table_name(tablename);
 
1523
        mode = convert_table_priv_string(priv_type_text);
 
1524
 
 
1525
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1526
 
 
1527
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1528
}
 
1529
 
 
1530
/*
 
1531
 * has_table_privilege_name
 
1532
 *              Check user privileges on a table given
 
1533
 *              text tablename and text priv name.
 
1534
 *              current_user is assumed
 
1535
 */
 
1536
Datum
 
1537
has_table_privilege_name(PG_FUNCTION_ARGS)
 
1538
{
 
1539
        text       *tablename = PG_GETARG_TEXT_P(0);
 
1540
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
1541
        Oid                     roleid;
 
1542
        Oid                     tableoid;
 
1543
        AclMode         mode;
 
1544
        AclResult       aclresult;
 
1545
 
 
1546
        roleid = GetUserId();
 
1547
        tableoid = convert_table_name(tablename);
 
1548
        mode = convert_table_priv_string(priv_type_text);
 
1549
 
 
1550
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1551
 
 
1552
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1553
}
 
1554
 
 
1555
/*
 
1556
 * has_table_privilege_name_id
 
1557
 *              Check user privileges on a table given
 
1558
 *              name usename, table oid, and text priv name.
 
1559
 */
 
1560
Datum
 
1561
has_table_privilege_name_id(PG_FUNCTION_ARGS)
 
1562
{
 
1563
        Name            username = PG_GETARG_NAME(0);
 
1564
        Oid                     tableoid = PG_GETARG_OID(1);
 
1565
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1566
        Oid                     roleid;
 
1567
        AclMode         mode;
 
1568
        AclResult       aclresult;
 
1569
 
 
1570
        roleid = get_roleid_checked(NameStr(*username));
 
1571
        mode = convert_table_priv_string(priv_type_text);
 
1572
 
 
1573
        if (!SearchSysCacheExists(RELOID,
 
1574
                                                          ObjectIdGetDatum(tableoid),
 
1575
                                                          0, 0, 0))
 
1576
                PG_RETURN_NULL();
 
1577
 
 
1578
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1579
 
 
1580
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1581
}
 
1582
 
 
1583
/*
 
1584
 * has_table_privilege_id
 
1585
 *              Check user privileges on a table given
 
1586
 *              table oid, and text priv name.
 
1587
 *              current_user is assumed
 
1588
 */
 
1589
Datum
 
1590
has_table_privilege_id(PG_FUNCTION_ARGS)
 
1591
{
 
1592
        Oid                     tableoid = PG_GETARG_OID(0);
 
1593
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
1594
        Oid                     roleid;
 
1595
        AclMode         mode;
 
1596
        AclResult       aclresult;
 
1597
 
 
1598
        roleid = GetUserId();
 
1599
        mode = convert_table_priv_string(priv_type_text);
 
1600
 
 
1601
        if (!SearchSysCacheExists(RELOID,
 
1602
                                                          ObjectIdGetDatum(tableoid),
 
1603
                                                          0, 0, 0))
 
1604
                PG_RETURN_NULL();
 
1605
 
 
1606
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1607
 
 
1608
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1609
}
 
1610
 
 
1611
/*
 
1612
 * has_table_privilege_id_name
 
1613
 *              Check user privileges on a table given
 
1614
 *              roleid, text tablename, and text priv name.
 
1615
 */
 
1616
Datum
 
1617
has_table_privilege_id_name(PG_FUNCTION_ARGS)
 
1618
{
 
1619
        Oid                     roleid = PG_GETARG_OID(0);
 
1620
        text       *tablename = PG_GETARG_TEXT_P(1);
 
1621
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1622
        Oid                     tableoid;
 
1623
        AclMode         mode;
 
1624
        AclResult       aclresult;
 
1625
 
 
1626
        tableoid = convert_table_name(tablename);
 
1627
        mode = convert_table_priv_string(priv_type_text);
 
1628
 
 
1629
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1630
 
 
1631
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1632
}
 
1633
 
 
1634
/*
 
1635
 * has_table_privilege_id_id
 
1636
 *              Check user privileges on a table given
 
1637
 *              roleid, table oid, and text priv name.
 
1638
 */
 
1639
Datum
 
1640
has_table_privilege_id_id(PG_FUNCTION_ARGS)
 
1641
{
 
1642
        Oid                     roleid = PG_GETARG_OID(0);
 
1643
        Oid                     tableoid = PG_GETARG_OID(1);
 
1644
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1645
        AclMode         mode;
 
1646
        AclResult       aclresult;
 
1647
 
 
1648
        mode = convert_table_priv_string(priv_type_text);
 
1649
 
 
1650
        if (!SearchSysCacheExists(RELOID,
 
1651
                                                          ObjectIdGetDatum(tableoid),
 
1652
                                                          0, 0, 0))
 
1653
                PG_RETURN_NULL();
 
1654
 
 
1655
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1656
 
 
1657
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1658
}
 
1659
 
 
1660
/*
 
1661
 *              Support routines for has_table_privilege family.
 
1662
 */
 
1663
 
 
1664
/*
 
1665
 * Given a table name expressed as a string, look it up and return Oid
 
1666
 */
 
1667
static Oid
 
1668
convert_table_name(text *tablename)
 
1669
{
 
1670
        RangeVar   *relrv;
 
1671
 
 
1672
        relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
 
1673
 
 
1674
        return RangeVarGetRelid(relrv, false);
 
1675
}
 
1676
 
 
1677
/*
 
1678
 * convert_table_priv_string
 
1679
 *              Convert text string to AclMode value.
 
1680
 */
 
1681
static AclMode
 
1682
convert_table_priv_string(text *priv_type_text)
 
1683
{
 
1684
        static const priv_map table_priv_map[] = {
 
1685
                { "SELECT", ACL_SELECT },
 
1686
                { "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
 
1687
                { "INSERT", ACL_INSERT },
 
1688
                { "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
 
1689
                { "UPDATE", ACL_UPDATE },
 
1690
                { "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
 
1691
                { "DELETE", ACL_DELETE },
 
1692
                { "DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE) },
 
1693
                { "TRUNCATE", ACL_TRUNCATE },
 
1694
                { "TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE) },
 
1695
                { "REFERENCES", ACL_REFERENCES },
 
1696
                { "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
 
1697
                { "TRIGGER", ACL_TRIGGER },
 
1698
                { "TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER) },
 
1699
                { "RULE", 0 },                  /* ignore old RULE privileges */
 
1700
                { "RULE WITH GRANT OPTION", 0 },
 
1701
                { NULL, 0 }
 
1702
        };
 
1703
 
 
1704
        return convert_any_priv_string(priv_type_text, table_priv_map);
 
1705
}
 
1706
 
 
1707
 
 
1708
/*
 
1709
 * has_any_column_privilege variants
 
1710
 *              These are all named "has_any_column_privilege" at the SQL level.
 
1711
 *              They take various combinations of relation name, relation OID,
 
1712
 *              user name, user OID, or implicit user = current_user.
 
1713
 *
 
1714
 *              The result is a boolean value: true if user has the indicated
 
1715
 *              privilege for any column of the table, false if not.  The variants
 
1716
 *              that take a relation OID return NULL if the OID doesn't exist.
 
1717
 */
 
1718
 
 
1719
/*
 
1720
 * has_any_column_privilege_name_name
 
1721
 *              Check user privileges on any column of a table given
 
1722
 *              name username, text tablename, and text priv name.
 
1723
 */
 
1724
Datum
 
1725
has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
 
1726
{
 
1727
        Name            rolename = PG_GETARG_NAME(0);
 
1728
        text       *tablename = PG_GETARG_TEXT_P(1);
 
1729
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1730
        Oid                     roleid;
 
1731
        Oid                     tableoid;
 
1732
        AclMode         mode;
 
1733
        AclResult       aclresult;
 
1734
 
 
1735
        roleid = get_roleid_checked(NameStr(*rolename));
 
1736
        tableoid = convert_table_name(tablename);
 
1737
        mode = convert_column_priv_string(priv_type_text);
 
1738
 
 
1739
        /* First check at table level, then examine each column if needed */
 
1740
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1741
        if (aclresult != ACLCHECK_OK)
 
1742
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1743
                                                                                          ACLMASK_ANY);
 
1744
 
 
1745
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1746
}
 
1747
 
 
1748
/*
 
1749
 * has_any_column_privilege_name
 
1750
 *              Check user privileges on any column of a table given
 
1751
 *              text tablename and text priv name.
 
1752
 *              current_user is assumed
 
1753
 */
 
1754
Datum
 
1755
has_any_column_privilege_name(PG_FUNCTION_ARGS)
 
1756
{
 
1757
        text       *tablename = PG_GETARG_TEXT_P(0);
 
1758
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
1759
        Oid                     roleid;
 
1760
        Oid                     tableoid;
 
1761
        AclMode         mode;
 
1762
        AclResult       aclresult;
 
1763
 
 
1764
        roleid = GetUserId();
 
1765
        tableoid = convert_table_name(tablename);
 
1766
        mode = convert_column_priv_string(priv_type_text);
 
1767
 
 
1768
        /* First check at table level, then examine each column if needed */
 
1769
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1770
        if (aclresult != ACLCHECK_OK)
 
1771
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1772
                                                                                          ACLMASK_ANY);
 
1773
 
 
1774
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1775
}
 
1776
 
 
1777
/*
 
1778
 * has_any_column_privilege_name_id
 
1779
 *              Check user privileges on any column of a table given
 
1780
 *              name usename, table oid, and text priv name.
 
1781
 */
 
1782
Datum
 
1783
has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
 
1784
{
 
1785
        Name            username = PG_GETARG_NAME(0);
 
1786
        Oid                     tableoid = PG_GETARG_OID(1);
 
1787
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1788
        Oid                     roleid;
 
1789
        AclMode         mode;
 
1790
        AclResult       aclresult;
 
1791
 
 
1792
        roleid = get_roleid_checked(NameStr(*username));
 
1793
        mode = convert_column_priv_string(priv_type_text);
 
1794
 
 
1795
        if (!SearchSysCacheExists(RELOID,
 
1796
                                                          ObjectIdGetDatum(tableoid),
 
1797
                                                          0, 0, 0))
 
1798
                PG_RETURN_NULL();
 
1799
 
 
1800
        /* First check at table level, then examine each column if needed */
 
1801
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1802
        if (aclresult != ACLCHECK_OK)
 
1803
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1804
                                                                                          ACLMASK_ANY);
 
1805
 
 
1806
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1807
}
 
1808
 
 
1809
/*
 
1810
 * has_any_column_privilege_id
 
1811
 *              Check user privileges on any column of a table given
 
1812
 *              table oid, and text priv name.
 
1813
 *              current_user is assumed
 
1814
 */
 
1815
Datum
 
1816
has_any_column_privilege_id(PG_FUNCTION_ARGS)
 
1817
{
 
1818
        Oid                     tableoid = PG_GETARG_OID(0);
 
1819
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
1820
        Oid                     roleid;
 
1821
        AclMode         mode;
 
1822
        AclResult       aclresult;
 
1823
 
 
1824
        roleid = GetUserId();
 
1825
        mode = convert_column_priv_string(priv_type_text);
 
1826
 
 
1827
        if (!SearchSysCacheExists(RELOID,
 
1828
                                                          ObjectIdGetDatum(tableoid),
 
1829
                                                          0, 0, 0))
 
1830
                PG_RETURN_NULL();
 
1831
 
 
1832
        /* First check at table level, then examine each column if needed */
 
1833
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1834
        if (aclresult != ACLCHECK_OK)
 
1835
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1836
                                                                                          ACLMASK_ANY);
 
1837
 
 
1838
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1839
}
 
1840
 
 
1841
/*
 
1842
 * has_any_column_privilege_id_name
 
1843
 *              Check user privileges on any column of a table given
 
1844
 *              roleid, text tablename, and text priv name.
 
1845
 */
 
1846
Datum
 
1847
has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
 
1848
{
 
1849
        Oid                     roleid = PG_GETARG_OID(0);
 
1850
        text       *tablename = PG_GETARG_TEXT_P(1);
 
1851
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1852
        Oid                     tableoid;
 
1853
        AclMode         mode;
 
1854
        AclResult       aclresult;
 
1855
 
 
1856
        tableoid = convert_table_name(tablename);
 
1857
        mode = convert_column_priv_string(priv_type_text);
 
1858
 
 
1859
        /* First check at table level, then examine each column if needed */
 
1860
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1861
        if (aclresult != ACLCHECK_OK)
 
1862
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1863
                                                                                          ACLMASK_ANY);
 
1864
 
 
1865
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1866
}
 
1867
 
 
1868
/*
 
1869
 * has_any_column_privilege_id_id
 
1870
 *              Check user privileges on any column of a table given
 
1871
 *              roleid, table oid, and text priv name.
 
1872
 */
 
1873
Datum
 
1874
has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
 
1875
{
 
1876
        Oid                     roleid = PG_GETARG_OID(0);
 
1877
        Oid                     tableoid = PG_GETARG_OID(1);
 
1878
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
1879
        AclMode         mode;
 
1880
        AclResult       aclresult;
 
1881
 
 
1882
        mode = convert_column_priv_string(priv_type_text);
 
1883
 
 
1884
        if (!SearchSysCacheExists(RELOID,
 
1885
                                                          ObjectIdGetDatum(tableoid),
 
1886
                                                          0, 0, 0))
 
1887
                PG_RETURN_NULL();
 
1888
 
 
1889
        /* First check at table level, then examine each column if needed */
 
1890
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1891
        if (aclresult != ACLCHECK_OK)
 
1892
                aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
 
1893
                                                                                          ACLMASK_ANY);
 
1894
 
 
1895
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
1896
}
 
1897
 
 
1898
 
 
1899
/*
 
1900
 * has_column_privilege variants
 
1901
 *              These are all named "has_column_privilege" at the SQL level.
 
1902
 *              They take various combinations of relation name, relation OID,
 
1903
 *              column name, column attnum, user name, user OID, or
 
1904
 *              implicit user = current_user.
 
1905
 *
 
1906
 *              The result is a boolean value: true if user has the indicated
 
1907
 *              privilege, false if not.  The variants that take a relation OID
 
1908
 *              and an integer attnum return NULL (rather than throwing an error)
 
1909
 *              if the column doesn't exist or is dropped.
 
1910
 */
 
1911
 
 
1912
/*
 
1913
 * column_privilege_check: check column privileges, but don't throw an error
 
1914
 *              for dropped column or table
 
1915
 *
 
1916
 * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
 
1917
 */
 
1918
static int
 
1919
column_privilege_check(Oid tableoid, AttrNumber attnum,
 
1920
                                           Oid roleid, AclMode mode)
 
1921
{
 
1922
        AclResult       aclresult;
 
1923
        HeapTuple       attTuple;
 
1924
        Form_pg_attribute attributeForm;
 
1925
 
 
1926
        /*
 
1927
         * First check if we have the privilege at the table level.  We check
 
1928
         * existence of the pg_class row before risking calling pg_class_aclcheck.
 
1929
         * Note: it might seem there's a race condition against concurrent DROP,
 
1930
         * but really it's safe because there will be no syscache flush between
 
1931
         * here and there.  So if we see the row in the syscache, so will
 
1932
         * pg_class_aclcheck.
 
1933
         */
 
1934
        if (!SearchSysCacheExists(RELOID,
 
1935
                                                          ObjectIdGetDatum(tableoid),
 
1936
                                                          0, 0, 0))
 
1937
                return -1;
 
1938
 
 
1939
        aclresult = pg_class_aclcheck(tableoid, roleid, mode);
 
1940
 
 
1941
        if (aclresult == ACLCHECK_OK)
 
1942
                return true;
 
1943
 
 
1944
        /*
 
1945
         * No table privilege, so try per-column privileges.  Again, we have to
 
1946
         * check for dropped attribute first, and we rely on the syscache not to
 
1947
         * notice a concurrent drop before pg_attribute_aclcheck fetches the row.
 
1948
         */
 
1949
        attTuple = SearchSysCache(ATTNUM,
 
1950
                                                          ObjectIdGetDatum(tableoid),
 
1951
                                                          Int16GetDatum(attnum),
 
1952
                                                          0, 0);
 
1953
        if (!HeapTupleIsValid(attTuple))
 
1954
                return -1;
 
1955
        attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
 
1956
        if (attributeForm->attisdropped)
 
1957
        {
 
1958
                ReleaseSysCache(attTuple);
 
1959
                return -1;
 
1960
        }
 
1961
        ReleaseSysCache(attTuple);
 
1962
 
 
1963
        aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
 
1964
 
 
1965
        return (aclresult == ACLCHECK_OK);
 
1966
}
 
1967
 
 
1968
/*
 
1969
 * has_column_privilege_name_name_name
 
1970
 *              Check user privileges on a column given
 
1971
 *              name username, text tablename, text colname, and text priv name.
 
1972
 */
 
1973
Datum
 
1974
has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
 
1975
{
 
1976
        Name            rolename = PG_GETARG_NAME(0);
 
1977
        text       *tablename = PG_GETARG_TEXT_P(1);
 
1978
        text       *column = PG_GETARG_TEXT_P(2);
 
1979
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
1980
        Oid                     roleid;
 
1981
        Oid                     tableoid;
 
1982
        AttrNumber      colattnum;
 
1983
        AclMode         mode;
 
1984
        int                     privresult;
 
1985
 
 
1986
        roleid = get_roleid_checked(NameStr(*rolename));
 
1987
        tableoid = convert_table_name(tablename);
 
1988
        colattnum = convert_column_name(tableoid, column);
 
1989
        mode = convert_column_priv_string(priv_type_text);
 
1990
 
 
1991
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
1992
        if (privresult < 0)
 
1993
                PG_RETURN_NULL();
 
1994
        PG_RETURN_BOOL(privresult);
 
1995
}
 
1996
 
 
1997
/*
 
1998
 * has_column_privilege_name_name_attnum
 
1999
 *              Check user privileges on a column given
 
2000
 *              name username, text tablename, int attnum, and text priv name.
 
2001
 */
 
2002
Datum
 
2003
has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
 
2004
{
 
2005
        Name            rolename = PG_GETARG_NAME(0);
 
2006
        text       *tablename = PG_GETARG_TEXT_P(1);
 
2007
        AttrNumber      colattnum = PG_GETARG_INT16(2);
 
2008
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2009
        Oid                     roleid;
 
2010
        Oid                     tableoid;
 
2011
        AclMode         mode;
 
2012
        int                     privresult;
 
2013
 
 
2014
        roleid = get_roleid_checked(NameStr(*rolename));
 
2015
        tableoid = convert_table_name(tablename);
 
2016
        mode = convert_column_priv_string(priv_type_text);
 
2017
 
 
2018
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2019
        if (privresult < 0)
 
2020
                PG_RETURN_NULL();
 
2021
        PG_RETURN_BOOL(privresult);
 
2022
}
 
2023
 
 
2024
/*
 
2025
 * has_column_privilege_name_id_name
 
2026
 *              Check user privileges on a column given
 
2027
 *              name username, table oid, text colname, and text priv name.
 
2028
 */
 
2029
Datum
 
2030
has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
 
2031
{
 
2032
        Name            username = PG_GETARG_NAME(0);
 
2033
        Oid                     tableoid = PG_GETARG_OID(1);
 
2034
        text       *column = PG_GETARG_TEXT_P(2);
 
2035
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2036
        Oid                     roleid;
 
2037
        AttrNumber      colattnum;
 
2038
        AclMode         mode;
 
2039
        int                     privresult;
 
2040
 
 
2041
        roleid = get_roleid_checked(NameStr(*username));
 
2042
        colattnum = convert_column_name(tableoid, column);
 
2043
        mode = convert_column_priv_string(priv_type_text);
 
2044
 
 
2045
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2046
        if (privresult < 0)
 
2047
                PG_RETURN_NULL();
 
2048
        PG_RETURN_BOOL(privresult);
 
2049
}
 
2050
 
 
2051
/*
 
2052
 * has_column_privilege_name_id_attnum
 
2053
 *              Check user privileges on a column given
 
2054
 *              name username, table oid, int attnum, and text priv name.
 
2055
 */
 
2056
Datum
 
2057
has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
 
2058
{
 
2059
        Name            username = PG_GETARG_NAME(0);
 
2060
        Oid                     tableoid = PG_GETARG_OID(1);
 
2061
        AttrNumber      colattnum = PG_GETARG_INT16(2);
 
2062
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2063
        Oid                     roleid;
 
2064
        AclMode         mode;
 
2065
        int                     privresult;
 
2066
 
 
2067
        roleid = get_roleid_checked(NameStr(*username));
 
2068
        mode = convert_column_priv_string(priv_type_text);
 
2069
 
 
2070
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2071
        if (privresult < 0)
 
2072
                PG_RETURN_NULL();
 
2073
        PG_RETURN_BOOL(privresult);
 
2074
}
 
2075
 
 
2076
/*
 
2077
 * has_column_privilege_id_name_name
 
2078
 *              Check user privileges on a column given
 
2079
 *              oid roleid, text tablename, text colname, and text priv name.
 
2080
 */
 
2081
Datum
 
2082
has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
 
2083
{
 
2084
        Oid                     roleid = PG_GETARG_OID(0);
 
2085
        text       *tablename = PG_GETARG_TEXT_P(1);
 
2086
        text       *column = PG_GETARG_TEXT_P(2);
 
2087
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2088
        Oid                     tableoid;
 
2089
        AttrNumber      colattnum;
 
2090
        AclMode         mode;
 
2091
        int                     privresult;
 
2092
 
 
2093
        tableoid = convert_table_name(tablename);
 
2094
        colattnum = convert_column_name(tableoid, column);
 
2095
        mode = convert_column_priv_string(priv_type_text);
 
2096
 
 
2097
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2098
        if (privresult < 0)
 
2099
                PG_RETURN_NULL();
 
2100
        PG_RETURN_BOOL(privresult);
 
2101
}
 
2102
 
 
2103
/*
 
2104
 * has_column_privilege_id_name_attnum
 
2105
 *              Check user privileges on a column given
 
2106
 *              oid roleid, text tablename, int attnum, and text priv name.
 
2107
 */
 
2108
Datum
 
2109
has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
 
2110
{
 
2111
        Oid                     roleid = PG_GETARG_OID(0);
 
2112
        text       *tablename = PG_GETARG_TEXT_P(1);
 
2113
        AttrNumber      colattnum = PG_GETARG_INT16(2);
 
2114
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2115
        Oid                     tableoid;
 
2116
        AclMode         mode;
 
2117
        int                     privresult;
 
2118
 
 
2119
        tableoid = convert_table_name(tablename);
 
2120
        mode = convert_column_priv_string(priv_type_text);
 
2121
 
 
2122
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2123
        if (privresult < 0)
 
2124
                PG_RETURN_NULL();
 
2125
        PG_RETURN_BOOL(privresult);
 
2126
}
 
2127
 
 
2128
/*
 
2129
 * has_column_privilege_id_id_name
 
2130
 *              Check user privileges on a column given
 
2131
 *              oid roleid, table oid, text colname, and text priv name.
 
2132
 */
 
2133
Datum
 
2134
has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
 
2135
{
 
2136
        Oid                     roleid = PG_GETARG_OID(0);
 
2137
        Oid                     tableoid = PG_GETARG_OID(1);
 
2138
        text       *column = PG_GETARG_TEXT_P(2);
 
2139
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2140
        AttrNumber      colattnum;
 
2141
        AclMode         mode;
 
2142
        int                     privresult;
 
2143
 
 
2144
        colattnum = convert_column_name(tableoid, column);
 
2145
        mode = convert_column_priv_string(priv_type_text);
 
2146
 
 
2147
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2148
        if (privresult < 0)
 
2149
                PG_RETURN_NULL();
 
2150
        PG_RETURN_BOOL(privresult);
 
2151
}
 
2152
 
 
2153
/*
 
2154
 * has_column_privilege_id_id_attnum
 
2155
 *              Check user privileges on a column given
 
2156
 *              oid roleid, table oid, int attnum, and text priv name.
 
2157
 */
 
2158
Datum
 
2159
has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
 
2160
{
 
2161
        Oid                     roleid = PG_GETARG_OID(0);
 
2162
        Oid                     tableoid = PG_GETARG_OID(1);
 
2163
        AttrNumber      colattnum = PG_GETARG_INT16(2);
 
2164
        text       *priv_type_text = PG_GETARG_TEXT_P(3);
 
2165
        AclMode         mode;
 
2166
        int                     privresult;
 
2167
 
 
2168
        mode = convert_column_priv_string(priv_type_text);
 
2169
 
 
2170
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2171
        if (privresult < 0)
 
2172
                PG_RETURN_NULL();
 
2173
        PG_RETURN_BOOL(privresult);
 
2174
}
 
2175
 
 
2176
/*
 
2177
 * has_column_privilege_name_name
 
2178
 *              Check user privileges on a column given
 
2179
 *              text tablename, text colname, and text priv name.
 
2180
 *              current_user is assumed
 
2181
 */
 
2182
Datum
 
2183
has_column_privilege_name_name(PG_FUNCTION_ARGS)
 
2184
{
 
2185
        text       *tablename = PG_GETARG_TEXT_P(0);
 
2186
        text       *column = PG_GETARG_TEXT_P(1);
 
2187
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2188
        Oid                     roleid;
 
2189
        Oid                     tableoid;
 
2190
        AttrNumber      colattnum;
 
2191
        AclMode         mode;
 
2192
        int                     privresult;
 
2193
 
 
2194
        roleid = GetUserId();
 
2195
        tableoid = convert_table_name(tablename);
 
2196
        colattnum = convert_column_name(tableoid, column);
 
2197
        mode = convert_column_priv_string(priv_type_text);
 
2198
 
 
2199
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2200
        if (privresult < 0)
 
2201
                PG_RETURN_NULL();
 
2202
        PG_RETURN_BOOL(privresult);
 
2203
}
 
2204
 
 
2205
/*
 
2206
 * has_column_privilege_name_attnum
 
2207
 *              Check user privileges on a column given
 
2208
 *              text tablename, int attnum, and text priv name.
 
2209
 *              current_user is assumed
 
2210
 */
 
2211
Datum
 
2212
has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
 
2213
{
 
2214
        text       *tablename = PG_GETARG_TEXT_P(0);
 
2215
        AttrNumber      colattnum = PG_GETARG_INT16(1);
 
2216
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2217
        Oid                     roleid;
 
2218
        Oid                     tableoid;
 
2219
        AclMode         mode;
 
2220
        int                     privresult;
 
2221
 
 
2222
        roleid = GetUserId();
 
2223
        tableoid = convert_table_name(tablename);
 
2224
        mode = convert_column_priv_string(priv_type_text);
 
2225
 
 
2226
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2227
        if (privresult < 0)
 
2228
                PG_RETURN_NULL();
 
2229
        PG_RETURN_BOOL(privresult);
 
2230
}
 
2231
 
 
2232
/*
 
2233
 * has_column_privilege_id_name
 
2234
 *              Check user privileges on a column given
 
2235
 *              table oid, text colname, and text priv name.
 
2236
 *              current_user is assumed
 
2237
 */
 
2238
Datum
 
2239
has_column_privilege_id_name(PG_FUNCTION_ARGS)
 
2240
{
 
2241
        Oid                     tableoid = PG_GETARG_OID(0);
 
2242
        text       *column = PG_GETARG_TEXT_P(1);
 
2243
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2244
        Oid                     roleid;
 
2245
        AttrNumber      colattnum;
 
2246
        AclMode         mode;
 
2247
        int                     privresult;
 
2248
 
 
2249
        roleid = GetUserId();
 
2250
        colattnum = convert_column_name(tableoid, column);
 
2251
        mode = convert_column_priv_string(priv_type_text);
 
2252
 
 
2253
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2254
        if (privresult < 0)
 
2255
                PG_RETURN_NULL();
 
2256
        PG_RETURN_BOOL(privresult);
 
2257
}
 
2258
 
 
2259
/*
 
2260
 * has_column_privilege_id_attnum
 
2261
 *              Check user privileges on a column given
 
2262
 *              table oid, int attnum, and text priv name.
 
2263
 *              current_user is assumed
 
2264
 */
 
2265
Datum
 
2266
has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
 
2267
{
 
2268
        Oid                     tableoid = PG_GETARG_OID(0);
 
2269
        AttrNumber      colattnum = PG_GETARG_INT16(1);
 
2270
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2271
        Oid                     roleid;
 
2272
        AclMode         mode;
 
2273
        int                     privresult;
 
2274
 
 
2275
        roleid = GetUserId();
 
2276
        mode = convert_column_priv_string(priv_type_text);
 
2277
 
 
2278
        privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
 
2279
        if (privresult < 0)
 
2280
                PG_RETURN_NULL();
 
2281
        PG_RETURN_BOOL(privresult);
 
2282
}
 
2283
 
 
2284
/*
 
2285
 *              Support routines for has_column_privilege family.
 
2286
 */
 
2287
 
 
2288
/*
 
2289
 * Given a table OID and a column name expressed as a string, look it up
 
2290
 * and return the column number
 
2291
 */
 
2292
static AttrNumber
 
2293
convert_column_name(Oid tableoid, text *column)
 
2294
{
 
2295
        AttrNumber      attnum;
 
2296
        char       *colname;
 
2297
 
 
2298
        colname = text_to_cstring(column);
 
2299
        attnum = get_attnum(tableoid, colname);
 
2300
        if (attnum == InvalidAttrNumber)
 
2301
                ereport(ERROR,
 
2302
                                (errcode(ERRCODE_UNDEFINED_COLUMN),
 
2303
                                 errmsg("column \"%s\" of relation \"%s\" does not exist",
 
2304
                                                colname, get_rel_name(tableoid))));
 
2305
        pfree(colname);
 
2306
        return attnum;
 
2307
}
 
2308
 
 
2309
/*
 
2310
 * convert_column_priv_string
 
2311
 *              Convert text string to AclMode value.
 
2312
 */
 
2313
static AclMode
 
2314
convert_column_priv_string(text *priv_type_text)
 
2315
{
 
2316
        static const priv_map column_priv_map[] = {
 
2317
                { "SELECT", ACL_SELECT },
 
2318
                { "SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT) },
 
2319
                { "INSERT", ACL_INSERT },
 
2320
                { "INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT) },
 
2321
                { "UPDATE", ACL_UPDATE },
 
2322
                { "UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE) },
 
2323
                { "REFERENCES", ACL_REFERENCES },
 
2324
                { "REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES) },
 
2325
                { NULL, 0 }
 
2326
        };
 
2327
 
 
2328
        return convert_any_priv_string(priv_type_text, column_priv_map);
 
2329
}
 
2330
 
 
2331
 
 
2332
/*
 
2333
 * has_database_privilege variants
 
2334
 *              These are all named "has_database_privilege" at the SQL level.
 
2335
 *              They take various combinations of database name, database OID,
 
2336
 *              user name, user OID, or implicit user = current_user.
 
2337
 *
 
2338
 *              The result is a boolean value: true if user has the indicated
 
2339
 *              privilege, false if not, or NULL if object doesn't exist.
 
2340
 */
 
2341
 
 
2342
/*
 
2343
 * has_database_privilege_name_name
 
2344
 *              Check user privileges on a database given
 
2345
 *              name username, text databasename, and text priv name.
 
2346
 */
 
2347
Datum
 
2348
has_database_privilege_name_name(PG_FUNCTION_ARGS)
 
2349
{
 
2350
        Name            username = PG_GETARG_NAME(0);
 
2351
        text       *databasename = PG_GETARG_TEXT_P(1);
 
2352
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2353
        Oid                     roleid;
 
2354
        Oid                     databaseoid;
 
2355
        AclMode         mode;
 
2356
        AclResult       aclresult;
 
2357
 
 
2358
        roleid = get_roleid_checked(NameStr(*username));
 
2359
        databaseoid = convert_database_name(databasename);
 
2360
        mode = convert_database_priv_string(priv_type_text);
 
2361
 
 
2362
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2363
 
 
2364
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2365
}
 
2366
 
 
2367
/*
 
2368
 * has_database_privilege_name
 
2369
 *              Check user privileges on a database given
 
2370
 *              text databasename and text priv name.
 
2371
 *              current_user is assumed
 
2372
 */
 
2373
Datum
 
2374
has_database_privilege_name(PG_FUNCTION_ARGS)
 
2375
{
 
2376
        text       *databasename = PG_GETARG_TEXT_P(0);
 
2377
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2378
        Oid                     roleid;
 
2379
        Oid                     databaseoid;
 
2380
        AclMode         mode;
 
2381
        AclResult       aclresult;
 
2382
 
 
2383
        roleid = GetUserId();
 
2384
        databaseoid = convert_database_name(databasename);
 
2385
        mode = convert_database_priv_string(priv_type_text);
 
2386
 
 
2387
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2388
 
 
2389
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2390
}
 
2391
 
 
2392
/*
 
2393
 * has_database_privilege_name_id
 
2394
 *              Check user privileges on a database given
 
2395
 *              name usename, database oid, and text priv name.
 
2396
 */
 
2397
Datum
 
2398
has_database_privilege_name_id(PG_FUNCTION_ARGS)
 
2399
{
 
2400
        Name            username = PG_GETARG_NAME(0);
 
2401
        Oid                     databaseoid = PG_GETARG_OID(1);
 
2402
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2403
        Oid                     roleid;
 
2404
        AclMode         mode;
 
2405
        AclResult       aclresult;
 
2406
 
 
2407
        roleid = get_roleid_checked(NameStr(*username));
 
2408
        mode = convert_database_priv_string(priv_type_text);
 
2409
 
 
2410
        if (!SearchSysCacheExists(DATABASEOID,
 
2411
                                                          ObjectIdGetDatum(databaseoid),
 
2412
                                                          0, 0, 0))
 
2413
                PG_RETURN_NULL();
 
2414
 
 
2415
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2416
 
 
2417
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2418
}
 
2419
 
 
2420
/*
 
2421
 * has_database_privilege_id
 
2422
 *              Check user privileges on a database given
 
2423
 *              database oid, and text priv name.
 
2424
 *              current_user is assumed
 
2425
 */
 
2426
Datum
 
2427
has_database_privilege_id(PG_FUNCTION_ARGS)
 
2428
{
 
2429
        Oid                     databaseoid = PG_GETARG_OID(0);
 
2430
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2431
        Oid                     roleid;
 
2432
        AclMode         mode;
 
2433
        AclResult       aclresult;
 
2434
 
 
2435
        roleid = GetUserId();
 
2436
        mode = convert_database_priv_string(priv_type_text);
 
2437
 
 
2438
        if (!SearchSysCacheExists(DATABASEOID,
 
2439
                                                          ObjectIdGetDatum(databaseoid),
 
2440
                                                          0, 0, 0))
 
2441
                PG_RETURN_NULL();
 
2442
 
 
2443
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2444
 
 
2445
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2446
}
 
2447
 
 
2448
/*
 
2449
 * has_database_privilege_id_name
 
2450
 *              Check user privileges on a database given
 
2451
 *              roleid, text databasename, and text priv name.
 
2452
 */
 
2453
Datum
 
2454
has_database_privilege_id_name(PG_FUNCTION_ARGS)
 
2455
{
 
2456
        Oid                     roleid = PG_GETARG_OID(0);
 
2457
        text       *databasename = PG_GETARG_TEXT_P(1);
 
2458
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2459
        Oid                     databaseoid;
 
2460
        AclMode         mode;
 
2461
        AclResult       aclresult;
 
2462
 
 
2463
        databaseoid = convert_database_name(databasename);
 
2464
        mode = convert_database_priv_string(priv_type_text);
 
2465
 
 
2466
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2467
 
 
2468
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2469
}
 
2470
 
 
2471
/*
 
2472
 * has_database_privilege_id_id
 
2473
 *              Check user privileges on a database given
 
2474
 *              roleid, database oid, and text priv name.
 
2475
 */
 
2476
Datum
 
2477
has_database_privilege_id_id(PG_FUNCTION_ARGS)
 
2478
{
 
2479
        Oid                     roleid = PG_GETARG_OID(0);
 
2480
        Oid                     databaseoid = PG_GETARG_OID(1);
 
2481
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2482
        AclMode         mode;
 
2483
        AclResult       aclresult;
 
2484
 
 
2485
        mode = convert_database_priv_string(priv_type_text);
 
2486
 
 
2487
        if (!SearchSysCacheExists(DATABASEOID,
 
2488
                                                          ObjectIdGetDatum(databaseoid),
 
2489
                                                          0, 0, 0))
 
2490
                PG_RETURN_NULL();
 
2491
 
 
2492
        aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
 
2493
 
 
2494
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2495
}
 
2496
 
 
2497
/*
 
2498
 *              Support routines for has_database_privilege family.
 
2499
 */
 
2500
 
 
2501
/*
 
2502
 * Given a database name expressed as a string, look it up and return Oid
 
2503
 */
 
2504
static Oid
 
2505
convert_database_name(text *databasename)
 
2506
{
 
2507
        char       *dbname = text_to_cstring(databasename);
 
2508
        Oid                     oid;
 
2509
 
 
2510
        oid = get_database_oid(dbname);
 
2511
        if (!OidIsValid(oid))
 
2512
                ereport(ERROR,
 
2513
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
 
2514
                                 errmsg("database \"%s\" does not exist", dbname)));
 
2515
 
 
2516
        return oid;
 
2517
}
 
2518
 
 
2519
/*
 
2520
 * convert_database_priv_string
 
2521
 *              Convert text string to AclMode value.
 
2522
 */
 
2523
static AclMode
 
2524
convert_database_priv_string(text *priv_type_text)
 
2525
{
 
2526
        static const priv_map database_priv_map[] = {
 
2527
                { "CREATE", ACL_CREATE },
 
2528
                { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
2529
                { "TEMPORARY", ACL_CREATE_TEMP },
 
2530
                { "TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
 
2531
                { "TEMP", ACL_CREATE_TEMP },
 
2532
                { "TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP) },
 
2533
                { "CONNECT", ACL_CONNECT },
 
2534
                { "CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT) },
 
2535
                { NULL, 0 }
 
2536
        };
 
2537
 
 
2538
        return convert_any_priv_string(priv_type_text, database_priv_map);
 
2539
 
 
2540
}
 
2541
 
 
2542
 
 
2543
/*
 
2544
 * has_foreign_data_wrapper_privilege variants
 
2545
 *              These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
 
2546
 *              They take various combinations of foreign-data wrapper name,
 
2547
 *              fdw OID, user name, user OID, or implicit user = current_user.
 
2548
 *
 
2549
 *              The result is a boolean value: true if user has the indicated
 
2550
 *              privilege, false if not.
 
2551
 */
 
2552
 
 
2553
/*
 
2554
 * has_foreign_data_wrapper_privilege_name_name
 
2555
 *              Check user privileges on a foreign-data wrapper given
 
2556
 *              name username, text fdwname, and text priv name.
 
2557
 */
 
2558
Datum
 
2559
has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
 
2560
{
 
2561
        Name            username = PG_GETARG_NAME(0);
 
2562
        text       *fdwname = PG_GETARG_TEXT_P(1);
 
2563
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2564
        Oid                     roleid;
 
2565
        Oid                     fdwid;
 
2566
        AclMode         mode;
 
2567
        AclResult       aclresult;
 
2568
 
 
2569
        roleid = get_roleid_checked(NameStr(*username));
 
2570
        fdwid = convert_foreign_data_wrapper_name(fdwname);
 
2571
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2572
 
 
2573
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2574
 
 
2575
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2576
}
 
2577
 
 
2578
/*
 
2579
 * has_foreign_data_wrapper_privilege_name
 
2580
 *              Check user privileges on a foreign-data wrapper given
 
2581
 *              text fdwname and text priv name.
 
2582
 *              current_user is assumed
 
2583
 */
 
2584
Datum
 
2585
has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
 
2586
{
 
2587
        text       *fdwname = PG_GETARG_TEXT_P(0);
 
2588
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2589
        Oid                     roleid;
 
2590
        Oid                     fdwid;
 
2591
        AclMode         mode;
 
2592
        AclResult       aclresult;
 
2593
 
 
2594
        roleid = GetUserId();
 
2595
        fdwid = convert_foreign_data_wrapper_name(fdwname);
 
2596
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2597
 
 
2598
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2599
 
 
2600
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2601
}
 
2602
 
 
2603
/*
 
2604
 * has_foreign_data_wrapper_privilege_name_id
 
2605
 *              Check user privileges on a foreign-data wrapper given
 
2606
 *              name usename, foreign-data wrapper oid, and text priv name.
 
2607
 */
 
2608
Datum
 
2609
has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
 
2610
{
 
2611
        Name            username = PG_GETARG_NAME(0);
 
2612
        Oid                     fdwid = PG_GETARG_OID(1);
 
2613
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2614
        Oid                     roleid;
 
2615
        AclMode         mode;
 
2616
        AclResult       aclresult;
 
2617
 
 
2618
        roleid = get_roleid_checked(NameStr(*username));
 
2619
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2620
 
 
2621
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2622
 
 
2623
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2624
}
 
2625
 
 
2626
/*
 
2627
 * has_foreign_data_wrapper_privilege_id
 
2628
 *              Check user privileges on a foreign-data wrapper given
 
2629
 *              foreign-data wrapper oid, and text priv name.
 
2630
 *              current_user is assumed
 
2631
 */
 
2632
Datum
 
2633
has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
 
2634
{
 
2635
        Oid                     fdwid = PG_GETARG_OID(0);
 
2636
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2637
        Oid                     roleid;
 
2638
        AclMode         mode;
 
2639
        AclResult       aclresult;
 
2640
 
 
2641
        roleid = GetUserId();
 
2642
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2643
 
 
2644
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2645
 
 
2646
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2647
}
 
2648
 
 
2649
/*
 
2650
 * has_foreign_data_wrapper_privilege_id_name
 
2651
 *              Check user privileges on a foreign-data wrapper given
 
2652
 *              roleid, text fdwname, and text priv name.
 
2653
 */
 
2654
Datum
 
2655
has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
 
2656
{
 
2657
        Oid                     roleid = PG_GETARG_OID(0);
 
2658
        text       *fdwname = PG_GETARG_TEXT_P(1);
 
2659
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2660
        Oid                     fdwid;
 
2661
        AclMode         mode;
 
2662
        AclResult       aclresult;
 
2663
 
 
2664
        fdwid = convert_foreign_data_wrapper_name(fdwname);
 
2665
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2666
 
 
2667
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2668
 
 
2669
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2670
}
 
2671
 
 
2672
/*
 
2673
 * has_foreign_data_wrapper_privilege_id_id
 
2674
 *              Check user privileges on a foreign-data wrapper given
 
2675
 *              roleid, fdw oid, and text priv name.
 
2676
 */
 
2677
Datum
 
2678
has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
 
2679
{
 
2680
        Oid                     roleid = PG_GETARG_OID(0);
 
2681
        Oid                     fdwid = PG_GETARG_OID(1);
 
2682
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2683
        AclMode         mode;
 
2684
        AclResult       aclresult;
 
2685
 
 
2686
        mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
 
2687
 
 
2688
        aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
 
2689
 
 
2690
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2691
}
 
2692
 
 
2693
/*
 
2694
 *              Support routines for has_foreign_data_wrapper_privilege family.
 
2695
 */
 
2696
 
 
2697
/*
 
2698
 * Given a FDW name expressed as a string, look it up and return Oid
 
2699
 */
 
2700
static Oid
 
2701
convert_foreign_data_wrapper_name(text *fdwname)
 
2702
{
 
2703
        char       *fdwstr = text_to_cstring(fdwname);
 
2704
 
 
2705
        return GetForeignDataWrapperOidByName(fdwstr, false);
 
2706
}
 
2707
 
 
2708
/*
 
2709
 * convert_foreign_data_wrapper_priv_string
 
2710
 *              Convert text string to AclMode value.
 
2711
 */
 
2712
static AclMode
 
2713
convert_foreign_data_wrapper_priv_string(text *priv_type_text)
 
2714
{
 
2715
        static const priv_map foreign_data_wrapper_priv_map[] = {
 
2716
                { "USAGE", ACL_USAGE },
 
2717
                { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
 
2718
                { NULL, 0 }
 
2719
        };
 
2720
 
 
2721
        return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
 
2722
}
 
2723
 
 
2724
 
 
2725
/*
 
2726
 * has_function_privilege variants
 
2727
 *              These are all named "has_function_privilege" at the SQL level.
 
2728
 *              They take various combinations of function name, function OID,
 
2729
 *              user name, user OID, or implicit user = current_user.
 
2730
 *
 
2731
 *              The result is a boolean value: true if user has the indicated
 
2732
 *              privilege, false if not, or NULL if object doesn't exist.
 
2733
 */
 
2734
 
 
2735
/*
 
2736
 * has_function_privilege_name_name
 
2737
 *              Check user privileges on a function given
 
2738
 *              name username, text functionname, and text priv name.
 
2739
 */
 
2740
Datum
 
2741
has_function_privilege_name_name(PG_FUNCTION_ARGS)
 
2742
{
 
2743
        Name            username = PG_GETARG_NAME(0);
 
2744
        text       *functionname = PG_GETARG_TEXT_P(1);
 
2745
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2746
        Oid                     roleid;
 
2747
        Oid                     functionoid;
 
2748
        AclMode         mode;
 
2749
        AclResult       aclresult;
 
2750
 
 
2751
        roleid = get_roleid_checked(NameStr(*username));
 
2752
        functionoid = convert_function_name(functionname);
 
2753
        mode = convert_function_priv_string(priv_type_text);
 
2754
 
 
2755
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2756
 
 
2757
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2758
}
 
2759
 
 
2760
/*
 
2761
 * has_function_privilege_name
 
2762
 *              Check user privileges on a function given
 
2763
 *              text functionname and text priv name.
 
2764
 *              current_user is assumed
 
2765
 */
 
2766
Datum
 
2767
has_function_privilege_name(PG_FUNCTION_ARGS)
 
2768
{
 
2769
        text       *functionname = PG_GETARG_TEXT_P(0);
 
2770
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2771
        Oid                     roleid;
 
2772
        Oid                     functionoid;
 
2773
        AclMode         mode;
 
2774
        AclResult       aclresult;
 
2775
 
 
2776
        roleid = GetUserId();
 
2777
        functionoid = convert_function_name(functionname);
 
2778
        mode = convert_function_priv_string(priv_type_text);
 
2779
 
 
2780
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2781
 
 
2782
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2783
}
 
2784
 
 
2785
/*
 
2786
 * has_function_privilege_name_id
 
2787
 *              Check user privileges on a function given
 
2788
 *              name usename, function oid, and text priv name.
 
2789
 */
 
2790
Datum
 
2791
has_function_privilege_name_id(PG_FUNCTION_ARGS)
 
2792
{
 
2793
        Name            username = PG_GETARG_NAME(0);
 
2794
        Oid                     functionoid = PG_GETARG_OID(1);
 
2795
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2796
        Oid                     roleid;
 
2797
        AclMode         mode;
 
2798
        AclResult       aclresult;
 
2799
 
 
2800
        roleid = get_roleid_checked(NameStr(*username));
 
2801
        mode = convert_function_priv_string(priv_type_text);
 
2802
 
 
2803
        if (!SearchSysCacheExists(PROCOID,
 
2804
                                                          ObjectIdGetDatum(functionoid),
 
2805
                                                          0, 0, 0))
 
2806
                PG_RETURN_NULL();
 
2807
 
 
2808
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2809
 
 
2810
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2811
}
 
2812
 
 
2813
/*
 
2814
 * has_function_privilege_id
 
2815
 *              Check user privileges on a function given
 
2816
 *              function oid, and text priv name.
 
2817
 *              current_user is assumed
 
2818
 */
 
2819
Datum
 
2820
has_function_privilege_id(PG_FUNCTION_ARGS)
 
2821
{
 
2822
        Oid                     functionoid = PG_GETARG_OID(0);
 
2823
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2824
        Oid                     roleid;
 
2825
        AclMode         mode;
 
2826
        AclResult       aclresult;
 
2827
 
 
2828
        roleid = GetUserId();
 
2829
        mode = convert_function_priv_string(priv_type_text);
 
2830
 
 
2831
        if (!SearchSysCacheExists(PROCOID,
 
2832
                                                          ObjectIdGetDatum(functionoid),
 
2833
                                                          0, 0, 0))
 
2834
                PG_RETURN_NULL();
 
2835
 
 
2836
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2837
 
 
2838
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2839
}
 
2840
 
 
2841
/*
 
2842
 * has_function_privilege_id_name
 
2843
 *              Check user privileges on a function given
 
2844
 *              roleid, text functionname, and text priv name.
 
2845
 */
 
2846
Datum
 
2847
has_function_privilege_id_name(PG_FUNCTION_ARGS)
 
2848
{
 
2849
        Oid                     roleid = PG_GETARG_OID(0);
 
2850
        text       *functionname = PG_GETARG_TEXT_P(1);
 
2851
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2852
        Oid                     functionoid;
 
2853
        AclMode         mode;
 
2854
        AclResult       aclresult;
 
2855
 
 
2856
        functionoid = convert_function_name(functionname);
 
2857
        mode = convert_function_priv_string(priv_type_text);
 
2858
 
 
2859
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2860
 
 
2861
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2862
}
 
2863
 
 
2864
/*
 
2865
 * has_function_privilege_id_id
 
2866
 *              Check user privileges on a function given
 
2867
 *              roleid, function oid, and text priv name.
 
2868
 */
 
2869
Datum
 
2870
has_function_privilege_id_id(PG_FUNCTION_ARGS)
 
2871
{
 
2872
        Oid                     roleid = PG_GETARG_OID(0);
 
2873
        Oid                     functionoid = PG_GETARG_OID(1);
 
2874
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2875
        AclMode         mode;
 
2876
        AclResult       aclresult;
 
2877
 
 
2878
        mode = convert_function_priv_string(priv_type_text);
 
2879
 
 
2880
        if (!SearchSysCacheExists(PROCOID,
 
2881
                                                          ObjectIdGetDatum(functionoid),
 
2882
                                                          0, 0, 0))
 
2883
                PG_RETURN_NULL();
 
2884
 
 
2885
        aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
 
2886
 
 
2887
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2888
}
 
2889
 
 
2890
/*
 
2891
 *              Support routines for has_function_privilege family.
 
2892
 */
 
2893
 
 
2894
/*
 
2895
 * Given a function name expressed as a string, look it up and return Oid
 
2896
 */
 
2897
static Oid
 
2898
convert_function_name(text *functionname)
 
2899
{
 
2900
        char       *funcname = text_to_cstring(functionname);
 
2901
        Oid                     oid;
 
2902
 
 
2903
        oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
 
2904
                                                                                           CStringGetDatum(funcname)));
 
2905
 
 
2906
        if (!OidIsValid(oid))
 
2907
                ereport(ERROR,
 
2908
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
2909
                                 errmsg("function \"%s\" does not exist", funcname)));
 
2910
 
 
2911
        return oid;
 
2912
}
 
2913
 
 
2914
/*
 
2915
 * convert_function_priv_string
 
2916
 *              Convert text string to AclMode value.
 
2917
 */
 
2918
static AclMode
 
2919
convert_function_priv_string(text *priv_type_text)
 
2920
{
 
2921
        static const priv_map function_priv_map[] = {
 
2922
                { "EXECUTE", ACL_EXECUTE },
 
2923
                { "EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE) },
 
2924
                { NULL, 0 }
 
2925
        };
 
2926
 
 
2927
        return convert_any_priv_string(priv_type_text, function_priv_map);
 
2928
}
 
2929
 
 
2930
 
 
2931
/*
 
2932
 * has_language_privilege variants
 
2933
 *              These are all named "has_language_privilege" at the SQL level.
 
2934
 *              They take various combinations of language name, language OID,
 
2935
 *              user name, user OID, or implicit user = current_user.
 
2936
 *
 
2937
 *              The result is a boolean value: true if user has the indicated
 
2938
 *              privilege, false if not, or NULL if object doesn't exist.
 
2939
 */
 
2940
 
 
2941
/*
 
2942
 * has_language_privilege_name_name
 
2943
 *              Check user privileges on a language given
 
2944
 *              name username, text languagename, and text priv name.
 
2945
 */
 
2946
Datum
 
2947
has_language_privilege_name_name(PG_FUNCTION_ARGS)
 
2948
{
 
2949
        Name            username = PG_GETARG_NAME(0);
 
2950
        text       *languagename = PG_GETARG_TEXT_P(1);
 
2951
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
2952
        Oid                     roleid;
 
2953
        Oid                     languageoid;
 
2954
        AclMode         mode;
 
2955
        AclResult       aclresult;
 
2956
 
 
2957
        roleid = get_roleid_checked(NameStr(*username));
 
2958
        languageoid = convert_language_name(languagename);
 
2959
        mode = convert_language_priv_string(priv_type_text);
 
2960
 
 
2961
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
2962
 
 
2963
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2964
}
 
2965
 
 
2966
/*
 
2967
 * has_language_privilege_name
 
2968
 *              Check user privileges on a language given
 
2969
 *              text languagename and text priv name.
 
2970
 *              current_user is assumed
 
2971
 */
 
2972
Datum
 
2973
has_language_privilege_name(PG_FUNCTION_ARGS)
 
2974
{
 
2975
        text       *languagename = PG_GETARG_TEXT_P(0);
 
2976
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
2977
        Oid                     roleid;
 
2978
        Oid                     languageoid;
 
2979
        AclMode         mode;
 
2980
        AclResult       aclresult;
 
2981
 
 
2982
        roleid = GetUserId();
 
2983
        languageoid = convert_language_name(languagename);
 
2984
        mode = convert_language_priv_string(priv_type_text);
 
2985
 
 
2986
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
2987
 
 
2988
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
2989
}
 
2990
 
 
2991
/*
 
2992
 * has_language_privilege_name_id
 
2993
 *              Check user privileges on a language given
 
2994
 *              name usename, language oid, and text priv name.
 
2995
 */
 
2996
Datum
 
2997
has_language_privilege_name_id(PG_FUNCTION_ARGS)
 
2998
{
 
2999
        Name            username = PG_GETARG_NAME(0);
 
3000
        Oid                     languageoid = PG_GETARG_OID(1);
 
3001
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3002
        Oid                     roleid;
 
3003
        AclMode         mode;
 
3004
        AclResult       aclresult;
 
3005
 
 
3006
        roleid = get_roleid_checked(NameStr(*username));
 
3007
        mode = convert_language_priv_string(priv_type_text);
 
3008
 
 
3009
        if (!SearchSysCacheExists(LANGOID,
 
3010
                                                          ObjectIdGetDatum(languageoid),
 
3011
                                                          0, 0, 0))
 
3012
                PG_RETURN_NULL();
 
3013
 
 
3014
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
3015
 
 
3016
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3017
}
 
3018
 
 
3019
/*
 
3020
 * has_language_privilege_id
 
3021
 *              Check user privileges on a language given
 
3022
 *              language oid, and text priv name.
 
3023
 *              current_user is assumed
 
3024
 */
 
3025
Datum
 
3026
has_language_privilege_id(PG_FUNCTION_ARGS)
 
3027
{
 
3028
        Oid                     languageoid = PG_GETARG_OID(0);
 
3029
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3030
        Oid                     roleid;
 
3031
        AclMode         mode;
 
3032
        AclResult       aclresult;
 
3033
 
 
3034
        roleid = GetUserId();
 
3035
        mode = convert_language_priv_string(priv_type_text);
 
3036
 
 
3037
        if (!SearchSysCacheExists(LANGOID,
 
3038
                                                          ObjectIdGetDatum(languageoid),
 
3039
                                                          0, 0, 0))
 
3040
                PG_RETURN_NULL();
 
3041
 
 
3042
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
3043
 
 
3044
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3045
}
 
3046
 
 
3047
/*
 
3048
 * has_language_privilege_id_name
 
3049
 *              Check user privileges on a language given
 
3050
 *              roleid, text languagename, and text priv name.
 
3051
 */
 
3052
Datum
 
3053
has_language_privilege_id_name(PG_FUNCTION_ARGS)
 
3054
{
 
3055
        Oid                     roleid = PG_GETARG_OID(0);
 
3056
        text       *languagename = PG_GETARG_TEXT_P(1);
 
3057
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3058
        Oid                     languageoid;
 
3059
        AclMode         mode;
 
3060
        AclResult       aclresult;
 
3061
 
 
3062
        languageoid = convert_language_name(languagename);
 
3063
        mode = convert_language_priv_string(priv_type_text);
 
3064
 
 
3065
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
3066
 
 
3067
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3068
}
 
3069
 
 
3070
/*
 
3071
 * has_language_privilege_id_id
 
3072
 *              Check user privileges on a language given
 
3073
 *              roleid, language oid, and text priv name.
 
3074
 */
 
3075
Datum
 
3076
has_language_privilege_id_id(PG_FUNCTION_ARGS)
 
3077
{
 
3078
        Oid                     roleid = PG_GETARG_OID(0);
 
3079
        Oid                     languageoid = PG_GETARG_OID(1);
 
3080
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3081
        AclMode         mode;
 
3082
        AclResult       aclresult;
 
3083
 
 
3084
        mode = convert_language_priv_string(priv_type_text);
 
3085
 
 
3086
        if (!SearchSysCacheExists(LANGOID,
 
3087
                                                          ObjectIdGetDatum(languageoid),
 
3088
                                                          0, 0, 0))
 
3089
                PG_RETURN_NULL();
 
3090
 
 
3091
        aclresult = pg_language_aclcheck(languageoid, roleid, mode);
 
3092
 
 
3093
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3094
}
 
3095
 
 
3096
/*
 
3097
 *              Support routines for has_language_privilege family.
 
3098
 */
 
3099
 
 
3100
/*
 
3101
 * Given a language name expressed as a string, look it up and return Oid
 
3102
 */
 
3103
static Oid
 
3104
convert_language_name(text *languagename)
 
3105
{
 
3106
        char       *langname = text_to_cstring(languagename);
 
3107
        Oid                     oid;
 
3108
 
 
3109
        oid = GetSysCacheOid(LANGNAME,
 
3110
                                                 CStringGetDatum(langname),
 
3111
                                                 0, 0, 0);
 
3112
        if (!OidIsValid(oid))
 
3113
                ereport(ERROR,
 
3114
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3115
                                 errmsg("language \"%s\" does not exist", langname)));
 
3116
 
 
3117
        return oid;
 
3118
}
 
3119
 
 
3120
/*
 
3121
 * convert_language_priv_string
 
3122
 *              Convert text string to AclMode value.
 
3123
 */
 
3124
static AclMode
 
3125
convert_language_priv_string(text *priv_type_text)
 
3126
{
 
3127
        static const priv_map language_priv_map[] = {
 
3128
                { "USAGE", ACL_USAGE },
 
3129
                { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
 
3130
                { NULL, 0 }
 
3131
        };
 
3132
 
 
3133
        return convert_any_priv_string(priv_type_text, language_priv_map);
 
3134
}
 
3135
 
 
3136
 
 
3137
/*
 
3138
 * has_schema_privilege variants
 
3139
 *              These are all named "has_schema_privilege" at the SQL level.
 
3140
 *              They take various combinations of schema name, schema OID,
 
3141
 *              user name, user OID, or implicit user = current_user.
 
3142
 *
 
3143
 *              The result is a boolean value: true if user has the indicated
 
3144
 *              privilege, false if not, or NULL if object doesn't exist.
 
3145
 */
 
3146
 
 
3147
/*
 
3148
 * has_schema_privilege_name_name
 
3149
 *              Check user privileges on a schema given
 
3150
 *              name username, text schemaname, and text priv name.
 
3151
 */
 
3152
Datum
 
3153
has_schema_privilege_name_name(PG_FUNCTION_ARGS)
 
3154
{
 
3155
        Name            username = PG_GETARG_NAME(0);
 
3156
        text       *schemaname = PG_GETARG_TEXT_P(1);
 
3157
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3158
        Oid                     roleid;
 
3159
        Oid                     schemaoid;
 
3160
        AclMode         mode;
 
3161
        AclResult       aclresult;
 
3162
 
 
3163
        roleid = get_roleid_checked(NameStr(*username));
 
3164
        schemaoid = convert_schema_name(schemaname);
 
3165
        mode = convert_schema_priv_string(priv_type_text);
 
3166
 
 
3167
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3168
 
 
3169
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3170
}
 
3171
 
 
3172
/*
 
3173
 * has_schema_privilege_name
 
3174
 *              Check user privileges on a schema given
 
3175
 *              text schemaname and text priv name.
 
3176
 *              current_user is assumed
 
3177
 */
 
3178
Datum
 
3179
has_schema_privilege_name(PG_FUNCTION_ARGS)
 
3180
{
 
3181
        text       *schemaname = PG_GETARG_TEXT_P(0);
 
3182
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3183
        Oid                     roleid;
 
3184
        Oid                     schemaoid;
 
3185
        AclMode         mode;
 
3186
        AclResult       aclresult;
 
3187
 
 
3188
        roleid = GetUserId();
 
3189
        schemaoid = convert_schema_name(schemaname);
 
3190
        mode = convert_schema_priv_string(priv_type_text);
 
3191
 
 
3192
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3193
 
 
3194
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3195
}
 
3196
 
 
3197
/*
 
3198
 * has_schema_privilege_name_id
 
3199
 *              Check user privileges on a schema given
 
3200
 *              name usename, schema oid, and text priv name.
 
3201
 */
 
3202
Datum
 
3203
has_schema_privilege_name_id(PG_FUNCTION_ARGS)
 
3204
{
 
3205
        Name            username = PG_GETARG_NAME(0);
 
3206
        Oid                     schemaoid = PG_GETARG_OID(1);
 
3207
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3208
        Oid                     roleid;
 
3209
        AclMode         mode;
 
3210
        AclResult       aclresult;
 
3211
 
 
3212
        roleid = get_roleid_checked(NameStr(*username));
 
3213
        mode = convert_schema_priv_string(priv_type_text);
 
3214
 
 
3215
        if (!SearchSysCacheExists(NAMESPACEOID,
 
3216
                                                          ObjectIdGetDatum(schemaoid),
 
3217
                                                          0, 0, 0))
 
3218
                PG_RETURN_NULL();
 
3219
 
 
3220
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3221
 
 
3222
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3223
}
 
3224
 
 
3225
/*
 
3226
 * has_schema_privilege_id
 
3227
 *              Check user privileges on a schema given
 
3228
 *              schema oid, and text priv name.
 
3229
 *              current_user is assumed
 
3230
 */
 
3231
Datum
 
3232
has_schema_privilege_id(PG_FUNCTION_ARGS)
 
3233
{
 
3234
        Oid                     schemaoid = PG_GETARG_OID(0);
 
3235
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3236
        Oid                     roleid;
 
3237
        AclMode         mode;
 
3238
        AclResult       aclresult;
 
3239
 
 
3240
        roleid = GetUserId();
 
3241
        mode = convert_schema_priv_string(priv_type_text);
 
3242
 
 
3243
        if (!SearchSysCacheExists(NAMESPACEOID,
 
3244
                                                          ObjectIdGetDatum(schemaoid),
 
3245
                                                          0, 0, 0))
 
3246
                PG_RETURN_NULL();
 
3247
 
 
3248
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3249
 
 
3250
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3251
}
 
3252
 
 
3253
/*
 
3254
 * has_schema_privilege_id_name
 
3255
 *              Check user privileges on a schema given
 
3256
 *              roleid, text schemaname, and text priv name.
 
3257
 */
 
3258
Datum
 
3259
has_schema_privilege_id_name(PG_FUNCTION_ARGS)
 
3260
{
 
3261
        Oid                     roleid = PG_GETARG_OID(0);
 
3262
        text       *schemaname = PG_GETARG_TEXT_P(1);
 
3263
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3264
        Oid                     schemaoid;
 
3265
        AclMode         mode;
 
3266
        AclResult       aclresult;
 
3267
 
 
3268
        schemaoid = convert_schema_name(schemaname);
 
3269
        mode = convert_schema_priv_string(priv_type_text);
 
3270
 
 
3271
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3272
 
 
3273
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3274
}
 
3275
 
 
3276
/*
 
3277
 * has_schema_privilege_id_id
 
3278
 *              Check user privileges on a schema given
 
3279
 *              roleid, schema oid, and text priv name.
 
3280
 */
 
3281
Datum
 
3282
has_schema_privilege_id_id(PG_FUNCTION_ARGS)
 
3283
{
 
3284
        Oid                     roleid = PG_GETARG_OID(0);
 
3285
        Oid                     schemaoid = PG_GETARG_OID(1);
 
3286
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3287
        AclMode         mode;
 
3288
        AclResult       aclresult;
 
3289
 
 
3290
        mode = convert_schema_priv_string(priv_type_text);
 
3291
 
 
3292
        if (!SearchSysCacheExists(NAMESPACEOID,
 
3293
                                                          ObjectIdGetDatum(schemaoid),
 
3294
                                                          0, 0, 0))
 
3295
                PG_RETURN_NULL();
 
3296
 
 
3297
        aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
 
3298
 
 
3299
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3300
}
 
3301
 
 
3302
/*
 
3303
 *              Support routines for has_schema_privilege family.
 
3304
 */
 
3305
 
 
3306
/*
 
3307
 * Given a schema name expressed as a string, look it up and return Oid
 
3308
 */
 
3309
static Oid
 
3310
convert_schema_name(text *schemaname)
 
3311
{
 
3312
        char       *nspname = text_to_cstring(schemaname);
 
3313
        Oid                     oid;
 
3314
 
 
3315
        oid = GetSysCacheOid(NAMESPACENAME,
 
3316
                                                 CStringGetDatum(nspname),
 
3317
                                                 0, 0, 0);
 
3318
        if (!OidIsValid(oid))
 
3319
                ereport(ERROR,
 
3320
                                (errcode(ERRCODE_UNDEFINED_SCHEMA),
 
3321
                                 errmsg("schema \"%s\" does not exist", nspname)));
 
3322
 
 
3323
        return oid;
 
3324
}
 
3325
 
 
3326
/*
 
3327
 * convert_schema_priv_string
 
3328
 *              Convert text string to AclMode value.
 
3329
 */
 
3330
static AclMode
 
3331
convert_schema_priv_string(text *priv_type_text)
 
3332
{
 
3333
        static const priv_map schema_priv_map[] = {
 
3334
                { "CREATE", ACL_CREATE },
 
3335
                { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3336
                { "USAGE", ACL_USAGE },
 
3337
                { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
 
3338
                { NULL, 0 }
 
3339
        };
 
3340
 
 
3341
        return convert_any_priv_string(priv_type_text, schema_priv_map);
 
3342
}
 
3343
 
 
3344
 
 
3345
/*
 
3346
 * has_server_privilege variants
 
3347
 *              These are all named "has_server_privilege" at the SQL level.
 
3348
 *              They take various combinations of foreign server name,
 
3349
 *              server OID, user name, user OID, or implicit user = current_user.
 
3350
 *
 
3351
 *              The result is a boolean value: true if user has the indicated
 
3352
 *              privilege, false if not.
 
3353
 */
 
3354
 
 
3355
/*
 
3356
 * has_server_privilege_name_name
 
3357
 *              Check user privileges on a foreign server given
 
3358
 *              name username, text servername, and text priv name.
 
3359
 */
 
3360
Datum
 
3361
has_server_privilege_name_name(PG_FUNCTION_ARGS)
 
3362
{
 
3363
        Name            username = PG_GETARG_NAME(0);
 
3364
        text       *servername = PG_GETARG_TEXT_P(1);
 
3365
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3366
        Oid                     roleid;
 
3367
        Oid                     serverid;
 
3368
        AclMode         mode;
 
3369
        AclResult       aclresult;
 
3370
 
 
3371
        roleid = get_roleid_checked(NameStr(*username));
 
3372
        serverid = convert_server_name(servername);
 
3373
        mode = convert_server_priv_string(priv_type_text);
 
3374
 
 
3375
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3376
 
 
3377
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3378
}
 
3379
 
 
3380
/*
 
3381
 * has_server_privilege_name
 
3382
 *              Check user privileges on a foreign server given
 
3383
 *              text servername and text priv name.
 
3384
 *              current_user is assumed
 
3385
 */
 
3386
Datum
 
3387
has_server_privilege_name(PG_FUNCTION_ARGS)
 
3388
{
 
3389
        text       *servername = PG_GETARG_TEXT_P(0);
 
3390
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3391
        Oid                     roleid;
 
3392
        Oid                     serverid;
 
3393
        AclMode         mode;
 
3394
        AclResult       aclresult;
 
3395
 
 
3396
        roleid = GetUserId();
 
3397
        serverid = convert_server_name(servername);
 
3398
        mode = convert_server_priv_string(priv_type_text);
 
3399
 
 
3400
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3401
 
 
3402
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3403
}
 
3404
 
 
3405
/*
 
3406
 * has_server_privilege_name_id
 
3407
 *              Check user privileges on a foreign server given
 
3408
 *              name usename, foreign server oid, and text priv name.
 
3409
 */
 
3410
Datum
 
3411
has_server_privilege_name_id(PG_FUNCTION_ARGS)
 
3412
{
 
3413
        Name            username = PG_GETARG_NAME(0);
 
3414
        Oid                     serverid = PG_GETARG_OID(1);
 
3415
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3416
        Oid                     roleid;
 
3417
        AclMode         mode;
 
3418
        AclResult       aclresult;
 
3419
 
 
3420
        roleid = get_roleid_checked(NameStr(*username));
 
3421
        mode = convert_server_priv_string(priv_type_text);
 
3422
 
 
3423
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3424
 
 
3425
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3426
}
 
3427
 
 
3428
/*
 
3429
 * has_server_privilege_id
 
3430
 *              Check user privileges on a foreign server given
 
3431
 *              server oid, and text priv name.
 
3432
 *              current_user is assumed
 
3433
 */
 
3434
Datum
 
3435
has_server_privilege_id(PG_FUNCTION_ARGS)
 
3436
{
 
3437
        Oid                     serverid = PG_GETARG_OID(0);
 
3438
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3439
        Oid                     roleid;
 
3440
        AclMode         mode;
 
3441
        AclResult       aclresult;
 
3442
 
 
3443
        roleid = GetUserId();
 
3444
        mode = convert_server_priv_string(priv_type_text);
 
3445
 
 
3446
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3447
 
 
3448
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3449
}
 
3450
 
 
3451
/*
 
3452
 * has_server_privilege_id_name
 
3453
 *              Check user privileges on a foreign server given
 
3454
 *              roleid, text servername, and text priv name.
 
3455
 */
 
3456
Datum
 
3457
has_server_privilege_id_name(PG_FUNCTION_ARGS)
 
3458
{
 
3459
        Oid                     roleid = PG_GETARG_OID(0);
 
3460
        text       *servername = PG_GETARG_TEXT_P(1);
 
3461
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3462
        Oid                     serverid;
 
3463
        AclMode         mode;
 
3464
        AclResult       aclresult;
 
3465
 
 
3466
        serverid = convert_server_name(servername);
 
3467
        mode = convert_server_priv_string(priv_type_text);
 
3468
 
 
3469
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3470
 
 
3471
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3472
}
 
3473
 
 
3474
/*
 
3475
 * has_server_privilege_id_id
 
3476
 *              Check user privileges on a foreign server given
 
3477
 *              roleid, server oid, and text priv name.
 
3478
 */
 
3479
Datum
 
3480
has_server_privilege_id_id(PG_FUNCTION_ARGS)
 
3481
{
 
3482
        Oid                     roleid = PG_GETARG_OID(0);
 
3483
        Oid                     serverid = PG_GETARG_OID(1);
 
3484
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3485
        AclMode         mode;
 
3486
        AclResult       aclresult;
 
3487
 
 
3488
        mode = convert_server_priv_string(priv_type_text);
 
3489
 
 
3490
        aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
 
3491
 
 
3492
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3493
}
 
3494
 
 
3495
/*
 
3496
 *              Support routines for has_server_privilege family.
 
3497
 */
 
3498
 
 
3499
/*
 
3500
 * Given a server name expressed as a string, look it up and return Oid
 
3501
 */
 
3502
static Oid
 
3503
convert_server_name(text *servername)
 
3504
{
 
3505
        char       *serverstr = text_to_cstring(servername);
 
3506
 
 
3507
        return GetForeignServerOidByName(serverstr, false);
 
3508
}
 
3509
 
 
3510
/*
 
3511
 * convert_server_priv_string
 
3512
 *              Convert text string to AclMode value.
 
3513
 */
 
3514
static AclMode
 
3515
convert_server_priv_string(text *priv_type_text)
 
3516
{
 
3517
        static const priv_map server_priv_map[] = {
 
3518
                { "USAGE", ACL_USAGE },
 
3519
                { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
 
3520
                { NULL, 0 }
 
3521
        };
 
3522
 
 
3523
        return convert_any_priv_string(priv_type_text, server_priv_map);
 
3524
}
 
3525
 
 
3526
 
 
3527
/*
 
3528
 * has_tablespace_privilege variants
 
3529
 *              These are all named "has_tablespace_privilege" at the SQL level.
 
3530
 *              They take various combinations of tablespace name, tablespace OID,
 
3531
 *              user name, user OID, or implicit user = current_user.
 
3532
 *
 
3533
 *              The result is a boolean value: true if user has the indicated
 
3534
 *              privilege, false if not.
 
3535
 */
 
3536
 
 
3537
/*
 
3538
 * has_tablespace_privilege_name_name
 
3539
 *              Check user privileges on a tablespace given
 
3540
 *              name username, text tablespacename, and text priv name.
 
3541
 */
 
3542
Datum
 
3543
has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
 
3544
{
 
3545
        Name            username = PG_GETARG_NAME(0);
 
3546
        text       *tablespacename = PG_GETARG_TEXT_P(1);
 
3547
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3548
        Oid                     roleid;
 
3549
        Oid                     tablespaceoid;
 
3550
        AclMode         mode;
 
3551
        AclResult       aclresult;
 
3552
 
 
3553
        roleid = get_roleid_checked(NameStr(*username));
 
3554
        tablespaceoid = convert_tablespace_name(tablespacename);
 
3555
        mode = convert_tablespace_priv_string(priv_type_text);
 
3556
 
 
3557
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3558
 
 
3559
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3560
}
 
3561
 
 
3562
/*
 
3563
 * has_tablespace_privilege_name
 
3564
 *              Check user privileges on a tablespace given
 
3565
 *              text tablespacename and text priv name.
 
3566
 *              current_user is assumed
 
3567
 */
 
3568
Datum
 
3569
has_tablespace_privilege_name(PG_FUNCTION_ARGS)
 
3570
{
 
3571
        text       *tablespacename = PG_GETARG_TEXT_P(0);
 
3572
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3573
        Oid                     roleid;
 
3574
        Oid                     tablespaceoid;
 
3575
        AclMode         mode;
 
3576
        AclResult       aclresult;
 
3577
 
 
3578
        roleid = GetUserId();
 
3579
        tablespaceoid = convert_tablespace_name(tablespacename);
 
3580
        mode = convert_tablespace_priv_string(priv_type_text);
 
3581
 
 
3582
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3583
 
 
3584
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3585
}
 
3586
 
 
3587
/*
 
3588
 * has_tablespace_privilege_name_id
 
3589
 *              Check user privileges on a tablespace given
 
3590
 *              name usename, tablespace oid, and text priv name.
 
3591
 */
 
3592
Datum
 
3593
has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
 
3594
{
 
3595
        Name            username = PG_GETARG_NAME(0);
 
3596
        Oid                     tablespaceoid = PG_GETARG_OID(1);
 
3597
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3598
        Oid                     roleid;
 
3599
        AclMode         mode;
 
3600
        AclResult       aclresult;
 
3601
 
 
3602
        roleid = get_roleid_checked(NameStr(*username));
 
3603
        mode = convert_tablespace_priv_string(priv_type_text);
 
3604
 
 
3605
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3606
 
 
3607
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3608
}
 
3609
 
 
3610
/*
 
3611
 * has_tablespace_privilege_id
 
3612
 *              Check user privileges on a tablespace given
 
3613
 *              tablespace oid, and text priv name.
 
3614
 *              current_user is assumed
 
3615
 */
 
3616
Datum
 
3617
has_tablespace_privilege_id(PG_FUNCTION_ARGS)
 
3618
{
 
3619
        Oid                     tablespaceoid = PG_GETARG_OID(0);
 
3620
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3621
        Oid                     roleid;
 
3622
        AclMode         mode;
 
3623
        AclResult       aclresult;
 
3624
 
 
3625
        roleid = GetUserId();
 
3626
        mode = convert_tablespace_priv_string(priv_type_text);
 
3627
 
 
3628
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3629
 
 
3630
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3631
}
 
3632
 
 
3633
/*
 
3634
 * has_tablespace_privilege_id_name
 
3635
 *              Check user privileges on a tablespace given
 
3636
 *              roleid, text tablespacename, and text priv name.
 
3637
 */
 
3638
Datum
 
3639
has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
 
3640
{
 
3641
        Oid                     roleid = PG_GETARG_OID(0);
 
3642
        text       *tablespacename = PG_GETARG_TEXT_P(1);
 
3643
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3644
        Oid                     tablespaceoid;
 
3645
        AclMode         mode;
 
3646
        AclResult       aclresult;
 
3647
 
 
3648
        tablespaceoid = convert_tablespace_name(tablespacename);
 
3649
        mode = convert_tablespace_priv_string(priv_type_text);
 
3650
 
 
3651
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3652
 
 
3653
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3654
}
 
3655
 
 
3656
/*
 
3657
 * has_tablespace_privilege_id_id
 
3658
 *              Check user privileges on a tablespace given
 
3659
 *              roleid, tablespace oid, and text priv name.
 
3660
 */
 
3661
Datum
 
3662
has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
 
3663
{
 
3664
        Oid                     roleid = PG_GETARG_OID(0);
 
3665
        Oid                     tablespaceoid = PG_GETARG_OID(1);
 
3666
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3667
        AclMode         mode;
 
3668
        AclResult       aclresult;
 
3669
 
 
3670
        mode = convert_tablespace_priv_string(priv_type_text);
 
3671
 
 
3672
        aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
 
3673
 
 
3674
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3675
}
 
3676
 
 
3677
/*
 
3678
 *              Support routines for has_tablespace_privilege family.
 
3679
 */
 
3680
 
 
3681
/*
 
3682
 * Given a tablespace name expressed as a string, look it up and return Oid
 
3683
 */
 
3684
static Oid
 
3685
convert_tablespace_name(text *tablespacename)
 
3686
{
 
3687
        char       *spcname = text_to_cstring(tablespacename);
 
3688
        Oid                     oid;
 
3689
 
 
3690
        oid = get_tablespace_oid(spcname);
 
3691
 
 
3692
        if (!OidIsValid(oid))
 
3693
                ereport(ERROR,
 
3694
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
 
3695
                                 errmsg("tablespace \"%s\" does not exist", spcname)));
 
3696
 
 
3697
        return oid;
 
3698
}
 
3699
 
 
3700
/*
 
3701
 * convert_tablespace_priv_string
 
3702
 *              Convert text string to AclMode value.
 
3703
 */
 
3704
static AclMode
 
3705
convert_tablespace_priv_string(text *priv_type_text)
 
3706
{
 
3707
        static const priv_map tablespace_priv_map[] = {
 
3708
                { "CREATE", ACL_CREATE },
 
3709
                { "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3710
                { NULL, 0 }
 
3711
        };
 
3712
 
 
3713
        return convert_any_priv_string(priv_type_text, tablespace_priv_map);
 
3714
}
 
3715
 
 
3716
/*
 
3717
 * pg_has_role variants
 
3718
 *              These are all named "pg_has_role" at the SQL level.
 
3719
 *              They take various combinations of role name, role OID,
 
3720
 *              user name, user OID, or implicit user = current_user.
 
3721
 *
 
3722
 *              The result is a boolean value: true if user has the indicated
 
3723
 *              privilege, false if not.
 
3724
 */
 
3725
 
 
3726
/*
 
3727
 * pg_has_role_name_name
 
3728
 *              Check user privileges on a role given
 
3729
 *              name username, name rolename, and text priv name.
 
3730
 */
 
3731
Datum
 
3732
pg_has_role_name_name(PG_FUNCTION_ARGS)
 
3733
{
 
3734
        Name            username = PG_GETARG_NAME(0);
 
3735
        Name            rolename = PG_GETARG_NAME(1);
 
3736
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3737
        Oid                     roleid;
 
3738
        Oid                     roleoid;
 
3739
        AclMode         mode;
 
3740
        AclResult       aclresult;
 
3741
 
 
3742
        roleid = get_roleid_checked(NameStr(*username));
 
3743
        roleoid = get_roleid_checked(NameStr(*rolename));
 
3744
        mode = convert_role_priv_string(priv_type_text);
 
3745
 
 
3746
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3747
 
 
3748
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3749
}
 
3750
 
 
3751
/*
 
3752
 * pg_has_role_name
 
3753
 *              Check user privileges on a role given
 
3754
 *              name rolename and text priv name.
 
3755
 *              current_user is assumed
 
3756
 */
 
3757
Datum
 
3758
pg_has_role_name(PG_FUNCTION_ARGS)
 
3759
{
 
3760
        Name            rolename = PG_GETARG_NAME(0);
 
3761
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3762
        Oid                     roleid;
 
3763
        Oid                     roleoid;
 
3764
        AclMode         mode;
 
3765
        AclResult       aclresult;
 
3766
 
 
3767
        roleid = GetUserId();
 
3768
        roleoid = get_roleid_checked(NameStr(*rolename));
 
3769
        mode = convert_role_priv_string(priv_type_text);
 
3770
 
 
3771
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3772
 
 
3773
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3774
}
 
3775
 
 
3776
/*
 
3777
 * pg_has_role_name_id
 
3778
 *              Check user privileges on a role given
 
3779
 *              name usename, role oid, and text priv name.
 
3780
 */
 
3781
Datum
 
3782
pg_has_role_name_id(PG_FUNCTION_ARGS)
 
3783
{
 
3784
        Name            username = PG_GETARG_NAME(0);
 
3785
        Oid                     roleoid = PG_GETARG_OID(1);
 
3786
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3787
        Oid                     roleid;
 
3788
        AclMode         mode;
 
3789
        AclResult       aclresult;
 
3790
 
 
3791
        roleid = get_roleid_checked(NameStr(*username));
 
3792
        mode = convert_role_priv_string(priv_type_text);
 
3793
 
 
3794
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3795
 
 
3796
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3797
}
 
3798
 
 
3799
/*
 
3800
 * pg_has_role_id
 
3801
 *              Check user privileges on a role given
 
3802
 *              role oid, and text priv name.
 
3803
 *              current_user is assumed
 
3804
 */
 
3805
Datum
 
3806
pg_has_role_id(PG_FUNCTION_ARGS)
 
3807
{
 
3808
        Oid                     roleoid = PG_GETARG_OID(0);
 
3809
        text       *priv_type_text = PG_GETARG_TEXT_P(1);
 
3810
        Oid                     roleid;
 
3811
        AclMode         mode;
 
3812
        AclResult       aclresult;
 
3813
 
 
3814
        roleid = GetUserId();
 
3815
        mode = convert_role_priv_string(priv_type_text);
 
3816
 
 
3817
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3818
 
 
3819
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3820
}
 
3821
 
 
3822
/*
 
3823
 * pg_has_role_id_name
 
3824
 *              Check user privileges on a role given
 
3825
 *              roleid, name rolename, and text priv name.
 
3826
 */
 
3827
Datum
 
3828
pg_has_role_id_name(PG_FUNCTION_ARGS)
 
3829
{
 
3830
        Oid                     roleid = PG_GETARG_OID(0);
 
3831
        Name            rolename = PG_GETARG_NAME(1);
 
3832
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3833
        Oid                     roleoid;
 
3834
        AclMode         mode;
 
3835
        AclResult       aclresult;
 
3836
 
 
3837
        roleoid = get_roleid_checked(NameStr(*rolename));
 
3838
        mode = convert_role_priv_string(priv_type_text);
 
3839
 
 
3840
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3841
 
 
3842
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3843
}
 
3844
 
 
3845
/*
 
3846
 * pg_has_role_id_id
 
3847
 *              Check user privileges on a role given
 
3848
 *              roleid, role oid, and text priv name.
 
3849
 */
 
3850
Datum
 
3851
pg_has_role_id_id(PG_FUNCTION_ARGS)
 
3852
{
 
3853
        Oid                     roleid = PG_GETARG_OID(0);
 
3854
        Oid                     roleoid = PG_GETARG_OID(1);
 
3855
        text       *priv_type_text = PG_GETARG_TEXT_P(2);
 
3856
        AclMode         mode;
 
3857
        AclResult       aclresult;
 
3858
 
 
3859
        mode = convert_role_priv_string(priv_type_text);
 
3860
 
 
3861
        aclresult = pg_role_aclcheck(roleoid, roleid, mode);
 
3862
 
 
3863
        PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
 
3864
}
 
3865
 
 
3866
/*
 
3867
 *              Support routines for pg_has_role family.
 
3868
 */
 
3869
 
 
3870
/*
 
3871
 * convert_role_priv_string
 
3872
 *              Convert text string to AclMode value.
 
3873
 *
 
3874
 * We use USAGE to denote whether the privileges of the role are accessible
 
3875
 * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
 
3876
 * (or ADMIN OPTION) to denote is_admin.  There is no ACL bit corresponding
 
3877
 * to MEMBER so we cheat and use ACL_CREATE for that.  This convention
 
3878
 * is shared only with pg_role_aclcheck, below.
 
3879
 */
 
3880
static AclMode
 
3881
convert_role_priv_string(text *priv_type_text)
 
3882
{
 
3883
        static const priv_map role_priv_map[] = {
 
3884
                { "USAGE", ACL_USAGE },
 
3885
                { "MEMBER", ACL_CREATE },
 
3886
                { "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3887
                { "USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3888
                { "MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3889
                { "MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
 
3890
                { NULL, 0 }
 
3891
        };
 
3892
 
 
3893
        return convert_any_priv_string(priv_type_text, role_priv_map);
 
3894
}
 
3895
 
 
3896
/*
 
3897
 * pg_role_aclcheck
 
3898
 *              Quick-and-dirty support for pg_has_role
 
3899
 */
 
3900
static AclResult
 
3901
pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
 
3902
{
 
3903
        if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
 
3904
        {
 
3905
                if (is_admin_of_role(roleid, role_oid))
 
3906
                        return ACLCHECK_OK;
 
3907
        }
 
3908
        if (mode & ACL_CREATE)
 
3909
        {
 
3910
                if (is_member_of_role(roleid, role_oid))
 
3911
                        return ACLCHECK_OK;
 
3912
        }
 
3913
        if (mode & ACL_USAGE)
 
3914
        {
 
3915
                if (has_privs_of_role(roleid, role_oid))
 
3916
                        return ACLCHECK_OK;
 
3917
        }
 
3918
        return ACLCHECK_NO_PRIV;
 
3919
}
 
3920
 
 
3921
 
 
3922
/*
 
3923
 * initialization function (called by InitPostgres)
 
3924
 */
 
3925
void
 
3926
initialize_acl(void)
 
3927
{
 
3928
        if (!IsBootstrapProcessingMode())
 
3929
        {
 
3930
                /*
 
3931
                 * In normal mode, set a callback on any syscache invalidation of
 
3932
                 * pg_auth_members rows
 
3933
                 */
 
3934
                CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
 
3935
                                                                          RoleMembershipCacheCallback,
 
3936
                                                                          (Datum) 0);
 
3937
        }
 
3938
}
 
3939
 
 
3940
/*
 
3941
 * RoleMembershipCacheCallback
 
3942
 *              Syscache inval callback function
 
3943
 */
 
3944
static void
 
3945
RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
 
3946
{
 
3947
        /* Force membership caches to be recomputed on next use */
 
3948
        cached_privs_role = InvalidOid;
 
3949
        cached_member_role = InvalidOid;
 
3950
}
 
3951
 
 
3952
 
 
3953
/* Check if specified role has rolinherit set */
 
3954
static bool
 
3955
has_rolinherit(Oid roleid)
 
3956
{
 
3957
        bool            result = false;
 
3958
        HeapTuple       utup;
 
3959
 
 
3960
        utup = SearchSysCache(AUTHOID,
 
3961
                                                  ObjectIdGetDatum(roleid),
 
3962
                                                  0, 0, 0);
 
3963
        if (HeapTupleIsValid(utup))
 
3964
        {
 
3965
                result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
 
3966
                ReleaseSysCache(utup);
 
3967
        }
 
3968
        return result;
 
3969
}
 
3970
 
 
3971
 
 
3972
/*
 
3973
 * Get a list of roles that the specified roleid has the privileges of
 
3974
 *
 
3975
 * This is defined not to recurse through roles that don't have rolinherit
 
3976
 * set; for such roles, membership implies the ability to do SET ROLE, but
 
3977
 * the privileges are not available until you've done so.
 
3978
 *
 
3979
 * Since indirect membership testing is relatively expensive, we cache
 
3980
 * a list of memberships.  Hence, the result is only guaranteed good until
 
3981
 * the next call of roles_has_privs_of()!
 
3982
 *
 
3983
 * For the benefit of select_best_grantor, the result is defined to be
 
3984
 * in breadth-first order, ie, closer relationships earlier.
 
3985
 */
 
3986
static List *
 
3987
roles_has_privs_of(Oid roleid)
 
3988
{
 
3989
        List       *roles_list;
 
3990
        ListCell   *l;
 
3991
        List       *new_cached_privs_roles;
 
3992
        MemoryContext oldctx;
 
3993
 
 
3994
        /* If cache is already valid, just return the list */
 
3995
        if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
 
3996
                return cached_privs_roles;
 
3997
 
 
3998
        /*
 
3999
         * Find all the roles that roleid is a member of, including multi-level
 
4000
         * recursion.  The role itself will always be the first element of the
 
4001
         * resulting list.
 
4002
         *
 
4003
         * Each element of the list is scanned to see if it adds any indirect
 
4004
         * memberships.  We can use a single list as both the record of
 
4005
         * already-found memberships and the agenda of roles yet to be scanned.
 
4006
         * This is a bit tricky but works because the foreach() macro doesn't
 
4007
         * fetch the next list element until the bottom of the loop.
 
4008
         */
 
4009
        roles_list = list_make1_oid(roleid);
 
4010
 
 
4011
        foreach(l, roles_list)
 
4012
        {
 
4013
                Oid                     memberid = lfirst_oid(l);
 
4014
                CatCList   *memlist;
 
4015
                int                     i;
 
4016
 
 
4017
                /* Ignore non-inheriting roles */
 
4018
                if (!has_rolinherit(memberid))
 
4019
                        continue;
 
4020
 
 
4021
                /* Find roles that memberid is directly a member of */
 
4022
                memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
 
4023
                                                                         ObjectIdGetDatum(memberid),
 
4024
                                                                         0, 0, 0);
 
4025
                for (i = 0; i < memlist->n_members; i++)
 
4026
                {
 
4027
                        HeapTuple       tup = &memlist->members[i]->tuple;
 
4028
                        Oid                     otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
 
4029
 
 
4030
                        /*
 
4031
                         * Even though there shouldn't be any loops in the membership
 
4032
                         * graph, we must test for having already seen this role. It is
 
4033
                         * legal for instance to have both A->B and A->C->B.
 
4034
                         */
 
4035
                        roles_list = list_append_unique_oid(roles_list, otherid);
 
4036
                }
 
4037
                ReleaseSysCacheList(memlist);
 
4038
        }
 
4039
 
 
4040
        /*
 
4041
         * Copy the completed list into TopMemoryContext so it will persist.
 
4042
         */
 
4043
        oldctx = MemoryContextSwitchTo(TopMemoryContext);
 
4044
        new_cached_privs_roles = list_copy(roles_list);
 
4045
        MemoryContextSwitchTo(oldctx);
 
4046
        list_free(roles_list);
 
4047
 
 
4048
        /*
 
4049
         * Now safe to assign to state variable
 
4050
         */
 
4051
        cached_privs_role = InvalidOid;         /* just paranoia */
 
4052
        list_free(cached_privs_roles);
 
4053
        cached_privs_roles = new_cached_privs_roles;
 
4054
        cached_privs_role = roleid;
 
4055
 
 
4056
        /* And now we can return the answer */
 
4057
        return cached_privs_roles;
 
4058
}
 
4059
 
 
4060
 
 
4061
/*
 
4062
 * Get a list of roles that the specified roleid is a member of
 
4063
 *
 
4064
 * This is defined to recurse through roles regardless of rolinherit.
 
4065
 *
 
4066
 * Since indirect membership testing is relatively expensive, we cache
 
4067
 * a list of memberships.  Hence, the result is only guaranteed good until
 
4068
 * the next call of roles_is_member_of()!
 
4069
 */
 
4070
static List *
 
4071
roles_is_member_of(Oid roleid)
 
4072
{
 
4073
        List       *roles_list;
 
4074
        ListCell   *l;
 
4075
        List       *new_cached_membership_roles;
 
4076
        MemoryContext oldctx;
 
4077
 
 
4078
        /* If cache is already valid, just return the list */
 
4079
        if (OidIsValid(cached_member_role) && cached_member_role == roleid)
 
4080
                return cached_membership_roles;
 
4081
 
 
4082
        /*
 
4083
         * Find all the roles that roleid is a member of, including multi-level
 
4084
         * recursion.  The role itself will always be the first element of the
 
4085
         * resulting list.
 
4086
         *
 
4087
         * Each element of the list is scanned to see if it adds any indirect
 
4088
         * memberships.  We can use a single list as both the record of
 
4089
         * already-found memberships and the agenda of roles yet to be scanned.
 
4090
         * This is a bit tricky but works because the foreach() macro doesn't
 
4091
         * fetch the next list element until the bottom of the loop.
 
4092
         */
 
4093
        roles_list = list_make1_oid(roleid);
 
4094
 
 
4095
        foreach(l, roles_list)
 
4096
        {
 
4097
                Oid                     memberid = lfirst_oid(l);
 
4098
                CatCList   *memlist;
 
4099
                int                     i;
 
4100
 
 
4101
                /* Find roles that memberid is directly a member of */
 
4102
                memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
 
4103
                                                                         ObjectIdGetDatum(memberid),
 
4104
                                                                         0, 0, 0);
 
4105
                for (i = 0; i < memlist->n_members; i++)
 
4106
                {
 
4107
                        HeapTuple       tup = &memlist->members[i]->tuple;
 
4108
                        Oid                     otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
 
4109
 
 
4110
                        /*
 
4111
                         * Even though there shouldn't be any loops in the membership
 
4112
                         * graph, we must test for having already seen this role. It is
 
4113
                         * legal for instance to have both A->B and A->C->B.
 
4114
                         */
 
4115
                        roles_list = list_append_unique_oid(roles_list, otherid);
 
4116
                }
 
4117
                ReleaseSysCacheList(memlist);
 
4118
        }
 
4119
 
 
4120
        /*
 
4121
         * Copy the completed list into TopMemoryContext so it will persist.
 
4122
         */
 
4123
        oldctx = MemoryContextSwitchTo(TopMemoryContext);
 
4124
        new_cached_membership_roles = list_copy(roles_list);
 
4125
        MemoryContextSwitchTo(oldctx);
 
4126
        list_free(roles_list);
 
4127
 
 
4128
        /*
 
4129
         * Now safe to assign to state variable
 
4130
         */
 
4131
        cached_member_role = InvalidOid;        /* just paranoia */
 
4132
        list_free(cached_membership_roles);
 
4133
        cached_membership_roles = new_cached_membership_roles;
 
4134
        cached_member_role = roleid;
 
4135
 
 
4136
        /* And now we can return the answer */
 
4137
        return cached_membership_roles;
 
4138
}
 
4139
 
 
4140
 
 
4141
/*
 
4142
 * Does member have the privileges of role (directly or indirectly)?
 
4143
 *
 
4144
 * This is defined not to recurse through roles that don't have rolinherit
 
4145
 * set; for such roles, membership implies the ability to do SET ROLE, but
 
4146
 * the privileges are not available until you've done so.
 
4147
 */
 
4148
bool
 
4149
has_privs_of_role(Oid member, Oid role)
 
4150
{
 
4151
        /* Fast path for simple case */
 
4152
        if (member == role)
 
4153
                return true;
 
4154
 
 
4155
        /* Superusers have every privilege, so are part of every role */
 
4156
        if (superuser_arg(member))
 
4157
                return true;
 
4158
 
 
4159
        /*
 
4160
         * Find all the roles that member has the privileges of, including
 
4161
         * multi-level recursion, then see if target role is any one of them.
 
4162
         */
 
4163
        return list_member_oid(roles_has_privs_of(member), role);
 
4164
}
 
4165
 
 
4166
 
 
4167
/*
 
4168
 * Is member a member of role (directly or indirectly)?
 
4169
 *
 
4170
 * This is defined to recurse through roles regardless of rolinherit.
 
4171
 */
 
4172
bool
 
4173
is_member_of_role(Oid member, Oid role)
 
4174
{
 
4175
        /* Fast path for simple case */
 
4176
        if (member == role)
 
4177
                return true;
 
4178
 
 
4179
        /* Superusers have every privilege, so are part of every role */
 
4180
        if (superuser_arg(member))
 
4181
                return true;
 
4182
 
 
4183
        /*
 
4184
         * Find all the roles that member is a member of, including multi-level
 
4185
         * recursion, then see if target role is any one of them.
 
4186
         */
 
4187
        return list_member_oid(roles_is_member_of(member), role);
 
4188
}
 
4189
 
 
4190
/*
 
4191
 * check_is_member_of_role
 
4192
 *              is_member_of_role with a standard permission-violation error if not
 
4193
 */
 
4194
void
 
4195
check_is_member_of_role(Oid member, Oid role)
 
4196
{
 
4197
        if (!is_member_of_role(member, role))
 
4198
                ereport(ERROR,
 
4199
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
4200
                                 errmsg("must be member of role \"%s\"",
 
4201
                                                GetUserNameFromId(role))));
 
4202
}
 
4203
 
 
4204
/*
 
4205
 * Is member a member of role, not considering superuserness?
 
4206
 *
 
4207
 * This is identical to is_member_of_role except we ignore superuser
 
4208
 * status.
 
4209
 */
 
4210
bool
 
4211
is_member_of_role_nosuper(Oid member, Oid role)
 
4212
{
 
4213
        /* Fast path for simple case */
 
4214
        if (member == role)
 
4215
                return true;
 
4216
 
 
4217
        /*
 
4218
         * Find all the roles that member is a member of, including multi-level
 
4219
         * recursion, then see if target role is any one of them.
 
4220
         */
 
4221
        return list_member_oid(roles_is_member_of(member), role);
 
4222
}
 
4223
 
 
4224
 
 
4225
/*
 
4226
 * Is member an admin of role (directly or indirectly)?  That is, is it
 
4227
 * a member WITH ADMIN OPTION?
 
4228
 *
 
4229
 * We could cache the result as for is_member_of_role, but currently this
 
4230
 * is not used in any performance-critical paths, so we don't.
 
4231
 */
 
4232
bool
 
4233
is_admin_of_role(Oid member, Oid role)
 
4234
{
 
4235
        bool            result = false;
 
4236
        List       *roles_list;
 
4237
        ListCell   *l;
 
4238
 
 
4239
        /* Fast path for simple case */
 
4240
        if (member == role)
 
4241
                return true;
 
4242
 
 
4243
        /* Superusers have every privilege, so are part of every role */
 
4244
        if (superuser_arg(member))
 
4245
                return true;
 
4246
 
 
4247
        /*
 
4248
         * Find all the roles that member is a member of, including multi-level
 
4249
         * recursion.  We build a list in the same way that is_member_of_role does
 
4250
         * to track visited and unvisited roles.
 
4251
         */
 
4252
        roles_list = list_make1_oid(member);
 
4253
 
 
4254
        foreach(l, roles_list)
 
4255
        {
 
4256
                Oid                     memberid = lfirst_oid(l);
 
4257
                CatCList   *memlist;
 
4258
                int                     i;
 
4259
 
 
4260
                /* Find roles that memberid is directly a member of */
 
4261
                memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
 
4262
                                                                         ObjectIdGetDatum(memberid),
 
4263
                                                                         0, 0, 0);
 
4264
                for (i = 0; i < memlist->n_members; i++)
 
4265
                {
 
4266
                        HeapTuple       tup = &memlist->members[i]->tuple;
 
4267
                        Oid                     otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
 
4268
 
 
4269
                        if (otherid == role &&
 
4270
                                ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
 
4271
                        {
 
4272
                                /* Found what we came for, so can stop searching */
 
4273
                                result = true;
 
4274
                                break;
 
4275
                        }
 
4276
 
 
4277
                        roles_list = list_append_unique_oid(roles_list, otherid);
 
4278
                }
 
4279
                ReleaseSysCacheList(memlist);
 
4280
                if (result)
 
4281
                        break;
 
4282
        }
 
4283
 
 
4284
        list_free(roles_list);
 
4285
 
 
4286
        return result;
 
4287
}
 
4288
 
 
4289
 
 
4290
/* does what it says ... */
 
4291
static int
 
4292
count_one_bits(AclMode mask)
 
4293
{
 
4294
        int                     nbits = 0;
 
4295
 
 
4296
        /* this code relies on AclMode being an unsigned type */
 
4297
        while (mask)
 
4298
        {
 
4299
                if (mask & 1)
 
4300
                        nbits++;
 
4301
                mask >>= 1;
 
4302
        }
 
4303
        return nbits;
 
4304
}
 
4305
 
 
4306
 
 
4307
/*
 
4308
 * Select the effective grantor ID for a GRANT or REVOKE operation.
 
4309
 *
 
4310
 * The grantor must always be either the object owner or some role that has
 
4311
 * been explicitly granted grant options.  This ensures that all granted
 
4312
 * privileges appear to flow from the object owner, and there are never
 
4313
 * multiple "original sources" of a privilege.  Therefore, if the would-be
 
4314
 * grantor is a member of a role that has the needed grant options, we have
 
4315
 * to do the grant as that role instead.
 
4316
 *
 
4317
 * It is possible that the would-be grantor is a member of several roles
 
4318
 * that have different subsets of the desired grant options, but no one
 
4319
 * role has 'em all.  In this case we pick a role with the largest number
 
4320
 * of desired options.  Ties are broken in favor of closer ancestors.
 
4321
 *
 
4322
 * roleId: the role attempting to do the GRANT/REVOKE
 
4323
 * privileges: the privileges to be granted/revoked
 
4324
 * acl: the ACL of the object in question
 
4325
 * ownerId: the role owning the object in question
 
4326
 * *grantorId: receives the OID of the role to do the grant as
 
4327
 * *grantOptions: receives the grant options actually held by grantorId
 
4328
 *
 
4329
 * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
 
4330
 */
 
4331
void
 
4332
select_best_grantor(Oid roleId, AclMode privileges,
 
4333
                                        const Acl *acl, Oid ownerId,
 
4334
                                        Oid *grantorId, AclMode *grantOptions)
 
4335
{
 
4336
        AclMode         needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
 
4337
        List       *roles_list;
 
4338
        int                     nrights;
 
4339
        ListCell   *l;
 
4340
 
 
4341
        /*
 
4342
         * The object owner is always treated as having all grant options, so if
 
4343
         * roleId is the owner it's easy.  Also, if roleId is a superuser it's
 
4344
         * easy: superusers are implicitly members of every role, so they act as
 
4345
         * the object owner.
 
4346
         */
 
4347
        if (roleId == ownerId || superuser_arg(roleId))
 
4348
        {
 
4349
                *grantorId = ownerId;
 
4350
                *grantOptions = needed_goptions;
 
4351
                return;
 
4352
        }
 
4353
 
 
4354
        /*
 
4355
         * Otherwise we have to do a careful search to see if roleId has the
 
4356
         * privileges of any suitable role.  Note: we can hang onto the result of
 
4357
         * roles_has_privs_of() throughout this loop, because aclmask_direct()
 
4358
         * doesn't query any role memberships.
 
4359
         */
 
4360
        roles_list = roles_has_privs_of(roleId);
 
4361
 
 
4362
        /* initialize candidate result as default */
 
4363
        *grantorId = roleId;
 
4364
        *grantOptions = ACL_NO_RIGHTS;
 
4365
        nrights = 0;
 
4366
 
 
4367
        foreach(l, roles_list)
 
4368
        {
 
4369
                Oid                     otherrole = lfirst_oid(l);
 
4370
                AclMode         otherprivs;
 
4371
 
 
4372
                otherprivs = aclmask_direct(acl, otherrole, ownerId,
 
4373
                                                                        needed_goptions, ACLMASK_ALL);
 
4374
                if (otherprivs == needed_goptions)
 
4375
                {
 
4376
                        /* Found a suitable grantor */
 
4377
                        *grantorId = otherrole;
 
4378
                        *grantOptions = otherprivs;
 
4379
                        return;
 
4380
                }
 
4381
 
 
4382
                /*
 
4383
                 * If it has just some of the needed privileges, remember best
 
4384
                 * candidate.
 
4385
                 */
 
4386
                if (otherprivs != ACL_NO_RIGHTS)
 
4387
                {
 
4388
                        int                     nnewrights = count_one_bits(otherprivs);
 
4389
 
 
4390
                        if (nnewrights > nrights)
 
4391
                        {
 
4392
                                *grantorId = otherrole;
 
4393
                                *grantOptions = otherprivs;
 
4394
                                nrights = nnewrights;
 
4395
                        }
 
4396
                }
 
4397
        }
 
4398
}