1
/*-------------------------------------------------------------------------
4
* Basic access control list data structures manipulation routines.
6
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
13
*-------------------------------------------------------------------------
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"
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.
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).
52
* Possibly this mechanism should be generalized to allow caching membership
53
* info for multiple roles?
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.
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.
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;
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,
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);
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);
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);
110
static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
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.
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.
126
getid(const char *s, char *n)
129
bool in_quotes = false;
133
while (isspace((unsigned char) *s))
135
/* This code had better match what putid() does, below */
138
(isalnum((unsigned char) *s) ||
146
/* safe to look at next char (could be '\0' though) */
149
in_quotes = !in_quotes;
152
/* it's an escaped double quote; skip the escaping char */
156
/* Add the character to the string */
157
if (len >= NAMEDATALEN - 1)
159
(errcode(ERRCODE_NAME_TOO_LONG),
160
errmsg("identifier too long"),
161
errdetail("Identifier must be less than %d characters.",
167
while (isspace((unsigned char) *s))
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
178
putid(char *p, const char *s)
183
for (src = s; *src; src++)
185
/* This test had better match what getid() does, above */
186
if (!isalnum((unsigned char) *src) && *src != '_')
194
for (src = s; *src; src++)
196
/* A double quote character in a username is encoded as "" */
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
214
* The group|user decoration is unnecessary in the roles world,
215
* but we still accept it for backward compatibility.
217
* This routine is called by the parser as well as aclitemin(), hence
218
* the added generality.
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.
227
aclparse(const char *s, AclItem *aip)
232
char name[NAMEDATALEN];
233
char name2[NAMEDATALEN];
238
elog(LOG, "aclparse: input = \"%s\"", s);
243
/* we just read a keyword, not a name */
244
if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
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 */
252
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
253
errmsg("missing name"),
254
errhint("A name must follow the \"group\" or \"user\" key word.")));
259
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
260
errmsg("missing \"=\" sign")));
262
privs = goption = ACL_NO_RIGHTS;
264
for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
283
case ACL_TRUNCATE_CHR:
286
case ACL_REFERENCES_CHR:
287
read = ACL_REFERENCES;
289
case ACL_TRIGGER_CHR:
292
case ACL_EXECUTE_CHR:
301
case ACL_CREATE_TEMP_CHR:
302
read = ACL_CREATE_TEMP;
304
case ACL_CONNECT_CHR:
307
case 'R': /* ignore old RULE privileges */
312
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
313
errmsg("invalid mode character: must be one of \"%s\"",
314
ACL_ALL_RIGHTS_STR)));
321
aip->ai_grantee = ACL_ID_PUBLIC;
323
aip->ai_grantee = get_roleid_checked(name);
326
* XXX Allow a degree of backward compatibility by defaulting the grantor
331
s = getid(s + 1, name2);
332
if (name2[0] == '\0')
334
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
335
errmsg("a name must follow the \"/\" sign")));
336
aip->ai_grantor = get_roleid_checked(name2);
340
aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
342
(errcode(ERRCODE_INVALID_GRANTOR),
343
errmsg("defaulting grantor to user ID %u",
344
BOOTSTRAP_SUPERUSERID)));
347
ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
350
elog(LOG, "aclparse: correctly read [%u %x %x]",
351
aip->ai_grantee, privs, goption);
359
* Allocates storage for a new Acl with 'n' entries.
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);
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;
387
aclcopy(const Acl *orig_acl)
391
result_acl = allocacl(ACL_NUM(orig_acl));
393
memcpy(ACL_DAT(result_acl),
395
ACL_NUM(orig_acl) * sizeof(AclItem));
401
* Concatenate two ACLs
403
* This is a bit cheesy, since we may produce an ACL with redundant entries.
404
* Be careful what the result is used for!
407
aclconcat(const Acl *left_acl, const Acl *right_acl)
411
result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
413
memcpy(ACL_DAT(result_acl),
415
ACL_NUM(left_acl) * sizeof(AclItem));
417
memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
419
ACL_NUM(right_acl) * sizeof(AclItem));
425
* Verify that an ACL array is acceptable (one-dimensional and has no nulls)
428
check_acl(const Acl *acl)
430
if (ARR_ELEMTYPE(acl) != ACLITEMOID)
432
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
433
errmsg("ACL array contains wrong data type")));
434
if (ARR_NDIM(acl) != 1)
436
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
437
errmsg("ACL arrays must be one-dimensional")));
438
if (ARR_HASNULL(acl))
440
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
441
errmsg("ACL arrays must not contain null values")));
446
* Allocates storage for, and fills in, a new AclItem given a string
447
* 's' that contains an ACL specification. See aclparse for details.
453
aclitemin(PG_FUNCTION_ARGS)
455
const char *s = PG_GETARG_CSTRING(0);
458
aip = (AclItem *) palloc(sizeof(AclItem));
459
s = aclparse(s, aip);
460
while (isspace((unsigned char) *s))
464
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
465
errmsg("extra garbage at the end of the ACL specification")));
467
PG_RETURN_ACLITEM_P(aip);
472
* Allocates storage for, and fills in, a new null-delimited string
473
* containing a formatted ACL specification. See aclparse for details.
479
aclitemout(PG_FUNCTION_ARGS)
481
AclItem *aip = PG_GETARG_ACLITEM_P(0);
487
out = palloc(strlen("=/") +
489
2 * (2 * NAMEDATALEN + 2) +
495
if (aip->ai_grantee != ACL_ID_PUBLIC)
497
htup = SearchSysCache(AUTHOID,
498
ObjectIdGetDatum(aip->ai_grantee),
500
if (HeapTupleIsValid(htup))
502
putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
503
ReleaseSysCache(htup);
507
/* Generate numeric OID if we don't find an entry */
508
sprintf(p, "%u", aip->ai_grantee);
516
for (i = 0; i < N_ACL_RIGHTS; ++i)
518
if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
519
*p++ = ACL_ALL_RIGHTS_STR[i];
520
if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
527
htup = SearchSysCache(AUTHOID,
528
ObjectIdGetDatum(aip->ai_grantor),
530
if (HeapTupleIsValid(htup))
532
putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
533
ReleaseSysCache(htup);
537
/* Generate numeric OID if we don't find an entry */
538
sprintf(p, "%u", aip->ai_grantor);
541
PG_RETURN_CSTRING(out);
546
* Two AclItems are considered to match iff they have the same
547
* grantee and grantor; the privileges are ignored.
550
aclitem_match(const AclItem *a1, const AclItem *a2)
552
return a1->ai_grantee == a2->ai_grantee &&
553
a1->ai_grantor == a2->ai_grantor;
557
* aclitem equality operator
560
aclitem_eq(PG_FUNCTION_ARGS)
562
AclItem *a1 = PG_GETARG_ACLITEM_P(0);
563
AclItem *a2 = PG_GETARG_ACLITEM_P(1);
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);
573
* aclitem hash function
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.
580
hash_aclitem(PG_FUNCTION_ARGS)
582
AclItem *a = PG_GETARG_ACLITEM_P(0);
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));
590
* acldefault() --- create an ACL describing default access permissions
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).
596
acldefault(GrantObjectType objtype, Oid ownerId)
598
AclMode world_default;
599
AclMode owner_default;
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;
611
case ACL_OBJECT_RELATION:
612
world_default = ACL_NO_RIGHTS;
613
owner_default = ACL_ALL_RIGHTS_RELATION;
615
case ACL_OBJECT_SEQUENCE:
616
world_default = ACL_NO_RIGHTS;
617
owner_default = ACL_ALL_RIGHTS_SEQUENCE;
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;
624
case ACL_OBJECT_FUNCTION:
625
/* Grant EXECUTE by default, for now */
626
world_default = ACL_EXECUTE;
627
owner_default = ACL_ALL_RIGHTS_FUNCTION;
629
case ACL_OBJECT_LANGUAGE:
630
/* Grant USAGE by default, for now */
631
world_default = ACL_USAGE;
632
owner_default = ACL_ALL_RIGHTS_LANGUAGE;
634
case ACL_OBJECT_NAMESPACE:
635
world_default = ACL_NO_RIGHTS;
636
owner_default = ACL_ALL_RIGHTS_NAMESPACE;
638
case ACL_OBJECT_TABLESPACE:
639
world_default = ACL_NO_RIGHTS;
640
owner_default = ACL_ALL_RIGHTS_TABLESPACE;
643
world_default = ACL_NO_RIGHTS;
644
owner_default = ACL_ALL_RIGHTS_FDW;
646
case ACL_OBJECT_FOREIGN_SERVER:
647
world_default = ACL_NO_RIGHTS;
648
owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
651
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
652
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
653
owner_default = ACL_NO_RIGHTS;
658
if (world_default != ACL_NO_RIGHTS)
660
if (owner_default != ACL_NO_RIGHTS)
663
acl = allocacl(nacl);
666
if (world_default != ACL_NO_RIGHTS)
668
aip->ai_grantee = ACL_ID_PUBLIC;
669
aip->ai_grantor = ownerId;
670
ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
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.
684
if (owner_default != ACL_NO_RIGHTS)
686
aip->ai_grantee = ownerId;
687
aip->ai_grantor = ownerId;
688
ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
696
* Update an ACL array to add or remove specified privileges.
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
704
* ownerid and behavior are only relevant when the update operation specifies
705
* deletion of grant options.
707
* The result is a modified copy; the input object is not changed.
709
* NB: caller is responsible for having detoasted the input ACL, if needed.
712
aclupdate(const Acl *old_acl, const AclItem *mod_aip,
713
int modechg, Oid ownerId, DropBehavior behavior)
725
/* Caller probably already checked old_acl, but be safe */
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);
733
num = ACL_NUM(old_acl);
734
old_aip = ACL_DAT(old_acl);
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
743
for (dst = 0; dst < num; ++dst)
745
if (aclitem_match(mod_aip, old_aip + dst))
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));
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));
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 */
770
old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
771
old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
773
/* apply the specified permissions change */
776
case ACL_MODECHG_ADD:
777
ACLITEM_SET_RIGHTS(new_aip[dst],
778
old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
780
case ACL_MODECHG_DEL:
781
ACLITEM_SET_RIGHTS(new_aip[dst],
782
old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
784
case ACL_MODECHG_EQL:
785
ACLITEM_SET_RIGHTS(new_aip[dst],
786
ACLITEM_GET_RIGHTS(*mod_aip));
790
new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
791
new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
794
* If the adjusted entry has no permissions, delete it from the list.
796
if (new_rights == ACL_NO_RIGHTS)
798
memmove(new_aip + dst,
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));
807
* Remove abandoned privileges (cascading revoke). Currently we can only
808
* handle this when the grantee is not PUBLIC.
810
if ((old_goptions & ~new_goptions) != 0)
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),
822
* Update an ACL array to reflect a change of owner to the parent object
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
828
* The result is a modified copy; the input object is not changed.
830
* NB: caller is responsible for having detoasted the input ACL, if needed.
833
aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
841
bool newpresent = false;
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.
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++)
861
if (dst_aip->ai_grantor == oldOwnerId)
862
dst_aip->ai_grantor = newOwnerId;
863
else if (dst_aip->ai_grantor == newOwnerId)
865
if (dst_aip->ai_grantee == oldOwnerId)
866
dst_aip->ai_grantee = newOwnerId;
867
else if (dst_aip->ai_grantee == newOwnerId)
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.)
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.
890
for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
892
/* ignore if deleted in an earlier pass */
893
if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
895
/* find and merge any duplicates */
896
for (src = targ + 1, src_aip = targ_aip + 1; src < num;
899
if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
901
if (aclitem_match(targ_aip, src_aip))
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);
910
/* and emit to output */
911
new_aip[dst] = *targ_aip;
914
/* Adjust array size to be 'dst' items */
915
ARR_DIMS(new_acl)[0] = dst;
916
SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
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.
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.
936
check_circularity(const Acl *old_acl, const AclItem *mod_aip,
948
* For now, grant options can only be granted to roles, not PUBLIC.
949
* Otherwise we'd have to work a bit harder here.
951
Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
953
/* The owner always has grant options, no need to check */
954
if (mod_aip->ai_grantor == ownerId)
957
/* Make a working copy */
958
acl = allocacl(ACL_NUM(old_acl));
959
memcpy(acl, old_acl, ACL_SIZE(old_acl));
961
/* Zap all grant options of target grantee, plus what depends on 'em */
965
for (i = 0; i < num; i++)
967
if (aip[i].ai_grantee == mod_aip->ai_grantee &&
968
ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
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);
983
/* Now we can compute grantor's independently-derived privileges */
984
own_privs = aclmask(acl,
987
ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
989
own_privs = ACL_OPTION_TO_PRIVS(own_privs);
991
if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
993
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
994
errmsg("grant options cannot be granted back to your own grantor")));
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.
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
1013
* The input Acl object is pfree'd if replaced.
1016
recursive_revoke(Acl *acl,
1018
AclMode revoke_privs,
1020
DropBehavior behavior)
1029
/* The owner can never truly lose grant options, so short-circuit */
1030
if (grantee == ownerId)
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),
1037
revoke_privs &= ~still_has;
1038
if (revoke_privs == ACL_NO_RIGHTS)
1044
for (i = 0; i < num; i++)
1046
if (aip[i].ai_grantor == grantee
1047
&& (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
1052
if (behavior == DROP_RESTRICT)
1054
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1055
errmsg("dependent privileges exist"),
1056
errhint("Use CASCADE to revoke them too.")));
1058
mod_acl.ai_grantor = grantee;
1059
mod_acl.ai_grantee = aip[i].ai_grantee;
1060
ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
1064
new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
1079
* aclmask --- compute bitmask of all privileges held by roleid.
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.)
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.)
1092
* To see if any of a set of privileges are held:
1093
* if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
1095
* To see if all of a set of privileges are held:
1096
* if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
1098
* To determine exactly which of a set of privileges are held:
1099
* heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
1102
aclmask(const Acl *acl, Oid roleid, Oid ownerId,
1103
AclMode mask, AclMaskHow how)
1112
* Null ACL should not happen, since caller should have inserted
1113
* appropriate default
1116
elog(ERROR, "null ACL");
1120
/* Quick exit for mask == 0 */
1126
/* Owner always implicitly has all grant options */
1127
if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1128
has_privs_of_role(roleid, ownerId))
1130
result = mask & ACLITEM_ALL_GOPTION_BITS;
1131
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1136
aidat = ACL_DAT(acl);
1139
* Check privileges granted directly to roleid or to public
1141
for (i = 0; i < num; i++)
1143
AclItem *aidata = &aidat[i];
1145
if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1146
aidata->ai_grantee == roleid)
1148
result |= aidata->ai_privs & mask;
1149
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
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
1161
remaining = mask & ~result;
1162
for (i = 0; i < num; i++)
1164
AclItem *aidata = &aidat[i];
1166
if (aidata->ai_grantee == ACL_ID_PUBLIC ||
1167
aidata->ai_grantee == roleid)
1168
continue; /* already checked it */
1170
if ((aidata->ai_privs & remaining) &&
1171
has_privs_of_role(roleid, aidata->ai_grantee))
1173
result |= aidata->ai_privs & mask;
1174
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1176
remaining = mask & ~result;
1185
* aclmask_direct --- compute bitmask of all privileges held by roleid.
1187
* This is exactly like aclmask() except that we consider only privileges
1188
* held *directly* by roleid, not those inherited via role membership.
1191
aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
1192
AclMode mask, AclMaskHow how)
1200
* Null ACL should not happen, since caller should have inserted
1201
* appropriate default
1204
elog(ERROR, "null ACL");
1208
/* Quick exit for mask == 0 */
1214
/* Owner always implicitly has all grant options */
1215
if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
1218
result = mask & ACLITEM_ALL_GOPTION_BITS;
1219
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1224
aidat = ACL_DAT(acl);
1227
* Check privileges granted directly to roleid (and not to public)
1229
for (i = 0; i < num; i++)
1231
AclItem *aidata = &aidat[i];
1233
if (aidata->ai_grantee == roleid)
1235
result |= aidata->ai_privs & mask;
1236
if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
1247
* Find out all the roleids mentioned in an Acl.
1248
* Note that we do not distinguish grantors from grantees.
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.
1254
aclmembers(const Acl *acl, Oid **roleids)
1257
const AclItem *acldat;
1262
if (acl == NULL || ACL_NUM(acl) == 0)
1270
/* Allocate the worst-case space requirement */
1271
list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
1272
acldat = ACL_DAT(acl);
1275
* Walk the ACL collecting mentioned RoleIds.
1278
for (i = 0; i < ACL_NUM(acl); i++)
1280
const AclItem *ai = &acldat[i];
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;
1289
/* Sort the array */
1290
qsort(list, j, sizeof(Oid), oidComparator);
1292
/* Remove duplicates from the array */
1294
for (i = 1; i < j; i++)
1296
if (list[k] != list[i])
1297
list[++k] = list[i];
1301
* We could repalloc the array down to minimum size, but it's hardly worth
1302
* it since it's only transient memory.
1311
* qsort comparison function for Oids
1314
oidComparator(const void *arg1, const void *arg2)
1316
Oid oid1 = *(const Oid *) arg1;
1317
Oid oid2 = *(const Oid *) arg2;
1328
* aclinsert (exported function)
1331
aclinsert(PG_FUNCTION_ARGS)
1334
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1335
errmsg("aclinsert is no longer supported")));
1337
PG_RETURN_NULL(); /* keep compiler quiet */
1341
aclremove(PG_FUNCTION_ARGS)
1344
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1345
errmsg("aclremove is no longer supported")));
1347
PG_RETURN_NULL(); /* keep compiler quiet */
1351
aclcontains(PG_FUNCTION_ARGS)
1353
Acl *acl = PG_GETARG_ACL_P(0);
1354
AclItem *aip = PG_GETARG_ACLITEM_P(1);
1361
aidat = ACL_DAT(acl);
1362
for (i = 0; i < num; ++i)
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);
1369
PG_RETURN_BOOL(false);
1373
makeaclitem(PG_FUNCTION_ARGS)
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);
1382
priv = convert_priv_string(privtext);
1384
result = (AclItem *) palloc(sizeof(AclItem));
1386
result->ai_grantee = grantee;
1387
result->ai_grantor = grantor;
1389
ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
1390
(goption ? priv : ACL_NO_RIGHTS));
1392
PG_RETURN_ACLITEM_P(result);
1396
convert_priv_string(text *priv_type_text)
1398
char *priv_type = text_to_cstring(priv_type_text);
1400
if (pg_strcasecmp(priv_type, "SELECT") == 0)
1402
if (pg_strcasecmp(priv_type, "INSERT") == 0)
1404
if (pg_strcasecmp(priv_type, "UPDATE") == 0)
1406
if (pg_strcasecmp(priv_type, "DELETE") == 0)
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)
1414
if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
1416
if (pg_strcasecmp(priv_type, "USAGE") == 0)
1418
if (pg_strcasecmp(priv_type, "CREATE") == 0)
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)
1426
if (pg_strcasecmp(priv_type, "RULE") == 0)
1427
return 0; /* ignore old RULE privileges */
1430
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1431
errmsg("unrecognized privilege type: \"%s\"", priv_type)));
1432
return ACL_NO_RIGHTS; /* keep compiler quiet */
1437
* convert_any_priv_string: recognize privilege strings for has_foo_privilege
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.
1446
convert_any_priv_string(text *priv_type_text,
1447
const priv_map *privileges)
1450
char *priv_type = text_to_cstring(priv_type_text);
1454
/* We rely on priv_type being a private, modifiable string */
1455
for (chunk = priv_type; chunk; chunk = next_chunk)
1458
const priv_map *this_priv;
1460
/* Split string at commas */
1461
next_chunk = strchr(chunk, ',');
1463
*next_chunk++ = '\0';
1465
/* Drop leading/trailing whitespace in this chunk */
1466
while (*chunk && isspace((unsigned char) *chunk))
1468
chunk_len = strlen(chunk);
1469
while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
1471
chunk[chunk_len] = '\0';
1473
/* Match to the privileges list */
1474
for (this_priv = privileges; this_priv->name; this_priv++)
1476
if (pg_strcasecmp(this_priv->name, chunk) == 0)
1478
result |= this_priv->value;
1482
if (!this_priv->name)
1484
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1485
errmsg("unrecognized privilege type: \"%s\"", chunk)));
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.
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).
1506
* has_table_privilege_name_name
1507
* Check user privileges on a table given
1508
* name username, text tablename, and text priv name.
1511
has_table_privilege_name_name(PG_FUNCTION_ARGS)
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);
1519
AclResult aclresult;
1521
roleid = get_roleid_checked(NameStr(*rolename));
1522
tableoid = convert_table_name(tablename);
1523
mode = convert_table_priv_string(priv_type_text);
1525
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1527
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
1537
has_table_privilege_name(PG_FUNCTION_ARGS)
1539
text *tablename = PG_GETARG_TEXT_P(0);
1540
text *priv_type_text = PG_GETARG_TEXT_P(1);
1544
AclResult aclresult;
1546
roleid = GetUserId();
1547
tableoid = convert_table_name(tablename);
1548
mode = convert_table_priv_string(priv_type_text);
1550
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1552
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1556
* has_table_privilege_name_id
1557
* Check user privileges on a table given
1558
* name usename, table oid, and text priv name.
1561
has_table_privilege_name_id(PG_FUNCTION_ARGS)
1563
Name username = PG_GETARG_NAME(0);
1564
Oid tableoid = PG_GETARG_OID(1);
1565
text *priv_type_text = PG_GETARG_TEXT_P(2);
1568
AclResult aclresult;
1570
roleid = get_roleid_checked(NameStr(*username));
1571
mode = convert_table_priv_string(priv_type_text);
1573
if (!SearchSysCacheExists(RELOID,
1574
ObjectIdGetDatum(tableoid),
1578
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1580
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
1590
has_table_privilege_id(PG_FUNCTION_ARGS)
1592
Oid tableoid = PG_GETARG_OID(0);
1593
text *priv_type_text = PG_GETARG_TEXT_P(1);
1596
AclResult aclresult;
1598
roleid = GetUserId();
1599
mode = convert_table_priv_string(priv_type_text);
1601
if (!SearchSysCacheExists(RELOID,
1602
ObjectIdGetDatum(tableoid),
1606
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1608
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1612
* has_table_privilege_id_name
1613
* Check user privileges on a table given
1614
* roleid, text tablename, and text priv name.
1617
has_table_privilege_id_name(PG_FUNCTION_ARGS)
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);
1624
AclResult aclresult;
1626
tableoid = convert_table_name(tablename);
1627
mode = convert_table_priv_string(priv_type_text);
1629
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1631
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1635
* has_table_privilege_id_id
1636
* Check user privileges on a table given
1637
* roleid, table oid, and text priv name.
1640
has_table_privilege_id_id(PG_FUNCTION_ARGS)
1642
Oid roleid = PG_GETARG_OID(0);
1643
Oid tableoid = PG_GETARG_OID(1);
1644
text *priv_type_text = PG_GETARG_TEXT_P(2);
1646
AclResult aclresult;
1648
mode = convert_table_priv_string(priv_type_text);
1650
if (!SearchSysCacheExists(RELOID,
1651
ObjectIdGetDatum(tableoid),
1655
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1657
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1661
* Support routines for has_table_privilege family.
1665
* Given a table name expressed as a string, look it up and return Oid
1668
convert_table_name(text *tablename)
1672
relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
1674
return RangeVarGetRelid(relrv, false);
1678
* convert_table_priv_string
1679
* Convert text string to AclMode value.
1682
convert_table_priv_string(text *priv_type_text)
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 },
1704
return convert_any_priv_string(priv_type_text, table_priv_map);
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.
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.
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.
1725
has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
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);
1733
AclResult aclresult;
1735
roleid = get_roleid_checked(NameStr(*rolename));
1736
tableoid = convert_table_name(tablename);
1737
mode = convert_column_priv_string(priv_type_text);
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,
1745
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
1755
has_any_column_privilege_name(PG_FUNCTION_ARGS)
1757
text *tablename = PG_GETARG_TEXT_P(0);
1758
text *priv_type_text = PG_GETARG_TEXT_P(1);
1762
AclResult aclresult;
1764
roleid = GetUserId();
1765
tableoid = convert_table_name(tablename);
1766
mode = convert_column_priv_string(priv_type_text);
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,
1774
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
1783
has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
1785
Name username = PG_GETARG_NAME(0);
1786
Oid tableoid = PG_GETARG_OID(1);
1787
text *priv_type_text = PG_GETARG_TEXT_P(2);
1790
AclResult aclresult;
1792
roleid = get_roleid_checked(NameStr(*username));
1793
mode = convert_column_priv_string(priv_type_text);
1795
if (!SearchSysCacheExists(RELOID,
1796
ObjectIdGetDatum(tableoid),
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,
1806
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
1816
has_any_column_privilege_id(PG_FUNCTION_ARGS)
1818
Oid tableoid = PG_GETARG_OID(0);
1819
text *priv_type_text = PG_GETARG_TEXT_P(1);
1822
AclResult aclresult;
1824
roleid = GetUserId();
1825
mode = convert_column_priv_string(priv_type_text);
1827
if (!SearchSysCacheExists(RELOID,
1828
ObjectIdGetDatum(tableoid),
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,
1838
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
1847
has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
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);
1854
AclResult aclresult;
1856
tableoid = convert_table_name(tablename);
1857
mode = convert_column_priv_string(priv_type_text);
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,
1865
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
1874
has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
1876
Oid roleid = PG_GETARG_OID(0);
1877
Oid tableoid = PG_GETARG_OID(1);
1878
text *priv_type_text = PG_GETARG_TEXT_P(2);
1880
AclResult aclresult;
1882
mode = convert_column_priv_string(priv_type_text);
1884
if (!SearchSysCacheExists(RELOID,
1885
ObjectIdGetDatum(tableoid),
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,
1895
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
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.
1913
* column_privilege_check: check column privileges, but don't throw an error
1914
* for dropped column or table
1916
* Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
1919
column_privilege_check(Oid tableoid, AttrNumber attnum,
1920
Oid roleid, AclMode mode)
1922
AclResult aclresult;
1924
Form_pg_attribute attributeForm;
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.
1934
if (!SearchSysCacheExists(RELOID,
1935
ObjectIdGetDatum(tableoid),
1939
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
1941
if (aclresult == ACLCHECK_OK)
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.
1949
attTuple = SearchSysCache(ATTNUM,
1950
ObjectIdGetDatum(tableoid),
1951
Int16GetDatum(attnum),
1953
if (!HeapTupleIsValid(attTuple))
1955
attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
1956
if (attributeForm->attisdropped)
1958
ReleaseSysCache(attTuple);
1961
ReleaseSysCache(attTuple);
1963
aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
1965
return (aclresult == ACLCHECK_OK);
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.
1974
has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
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);
1982
AttrNumber colattnum;
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);
1991
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
1994
PG_RETURN_BOOL(privresult);
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.
2003
has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
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);
2014
roleid = get_roleid_checked(NameStr(*rolename));
2015
tableoid = convert_table_name(tablename);
2016
mode = convert_column_priv_string(priv_type_text);
2018
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2021
PG_RETURN_BOOL(privresult);
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.
2030
has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
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);
2037
AttrNumber colattnum;
2041
roleid = get_roleid_checked(NameStr(*username));
2042
colattnum = convert_column_name(tableoid, column);
2043
mode = convert_column_priv_string(priv_type_text);
2045
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2048
PG_RETURN_BOOL(privresult);
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.
2057
has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
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);
2067
roleid = get_roleid_checked(NameStr(*username));
2068
mode = convert_column_priv_string(priv_type_text);
2070
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2073
PG_RETURN_BOOL(privresult);
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.
2082
has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
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);
2089
AttrNumber colattnum;
2093
tableoid = convert_table_name(tablename);
2094
colattnum = convert_column_name(tableoid, column);
2095
mode = convert_column_priv_string(priv_type_text);
2097
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2100
PG_RETURN_BOOL(privresult);
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.
2109
has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
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);
2119
tableoid = convert_table_name(tablename);
2120
mode = convert_column_priv_string(priv_type_text);
2122
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2125
PG_RETURN_BOOL(privresult);
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.
2134
has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
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;
2144
colattnum = convert_column_name(tableoid, column);
2145
mode = convert_column_priv_string(priv_type_text);
2147
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2150
PG_RETURN_BOOL(privresult);
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.
2159
has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
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);
2168
mode = convert_column_priv_string(priv_type_text);
2170
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2173
PG_RETURN_BOOL(privresult);
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
2183
has_column_privilege_name_name(PG_FUNCTION_ARGS)
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);
2190
AttrNumber colattnum;
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);
2199
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2202
PG_RETURN_BOOL(privresult);
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
2212
has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
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);
2222
roleid = GetUserId();
2223
tableoid = convert_table_name(tablename);
2224
mode = convert_column_priv_string(priv_type_text);
2226
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2229
PG_RETURN_BOOL(privresult);
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
2239
has_column_privilege_id_name(PG_FUNCTION_ARGS)
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);
2245
AttrNumber colattnum;
2249
roleid = GetUserId();
2250
colattnum = convert_column_name(tableoid, column);
2251
mode = convert_column_priv_string(priv_type_text);
2253
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2256
PG_RETURN_BOOL(privresult);
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
2266
has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
2268
Oid tableoid = PG_GETARG_OID(0);
2269
AttrNumber colattnum = PG_GETARG_INT16(1);
2270
text *priv_type_text = PG_GETARG_TEXT_P(2);
2275
roleid = GetUserId();
2276
mode = convert_column_priv_string(priv_type_text);
2278
privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
2281
PG_RETURN_BOOL(privresult);
2285
* Support routines for has_column_privilege family.
2289
* Given a table OID and a column name expressed as a string, look it up
2290
* and return the column number
2293
convert_column_name(Oid tableoid, text *column)
2298
colname = text_to_cstring(column);
2299
attnum = get_attnum(tableoid, colname);
2300
if (attnum == InvalidAttrNumber)
2302
(errcode(ERRCODE_UNDEFINED_COLUMN),
2303
errmsg("column \"%s\" of relation \"%s\" does not exist",
2304
colname, get_rel_name(tableoid))));
2310
* convert_column_priv_string
2311
* Convert text string to AclMode value.
2314
convert_column_priv_string(text *priv_type_text)
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) },
2328
return convert_any_priv_string(priv_type_text, column_priv_map);
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.
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.
2343
* has_database_privilege_name_name
2344
* Check user privileges on a database given
2345
* name username, text databasename, and text priv name.
2348
has_database_privilege_name_name(PG_FUNCTION_ARGS)
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);
2356
AclResult aclresult;
2358
roleid = get_roleid_checked(NameStr(*username));
2359
databaseoid = convert_database_name(databasename);
2360
mode = convert_database_priv_string(priv_type_text);
2362
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2364
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2374
has_database_privilege_name(PG_FUNCTION_ARGS)
2376
text *databasename = PG_GETARG_TEXT_P(0);
2377
text *priv_type_text = PG_GETARG_TEXT_P(1);
2381
AclResult aclresult;
2383
roleid = GetUserId();
2384
databaseoid = convert_database_name(databasename);
2385
mode = convert_database_priv_string(priv_type_text);
2387
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2389
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2393
* has_database_privilege_name_id
2394
* Check user privileges on a database given
2395
* name usename, database oid, and text priv name.
2398
has_database_privilege_name_id(PG_FUNCTION_ARGS)
2400
Name username = PG_GETARG_NAME(0);
2401
Oid databaseoid = PG_GETARG_OID(1);
2402
text *priv_type_text = PG_GETARG_TEXT_P(2);
2405
AclResult aclresult;
2407
roleid = get_roleid_checked(NameStr(*username));
2408
mode = convert_database_priv_string(priv_type_text);
2410
if (!SearchSysCacheExists(DATABASEOID,
2411
ObjectIdGetDatum(databaseoid),
2415
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2417
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2427
has_database_privilege_id(PG_FUNCTION_ARGS)
2429
Oid databaseoid = PG_GETARG_OID(0);
2430
text *priv_type_text = PG_GETARG_TEXT_P(1);
2433
AclResult aclresult;
2435
roleid = GetUserId();
2436
mode = convert_database_priv_string(priv_type_text);
2438
if (!SearchSysCacheExists(DATABASEOID,
2439
ObjectIdGetDatum(databaseoid),
2443
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2445
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2449
* has_database_privilege_id_name
2450
* Check user privileges on a database given
2451
* roleid, text databasename, and text priv name.
2454
has_database_privilege_id_name(PG_FUNCTION_ARGS)
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);
2461
AclResult aclresult;
2463
databaseoid = convert_database_name(databasename);
2464
mode = convert_database_priv_string(priv_type_text);
2466
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2468
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2472
* has_database_privilege_id_id
2473
* Check user privileges on a database given
2474
* roleid, database oid, and text priv name.
2477
has_database_privilege_id_id(PG_FUNCTION_ARGS)
2479
Oid roleid = PG_GETARG_OID(0);
2480
Oid databaseoid = PG_GETARG_OID(1);
2481
text *priv_type_text = PG_GETARG_TEXT_P(2);
2483
AclResult aclresult;
2485
mode = convert_database_priv_string(priv_type_text);
2487
if (!SearchSysCacheExists(DATABASEOID,
2488
ObjectIdGetDatum(databaseoid),
2492
aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
2494
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2498
* Support routines for has_database_privilege family.
2502
* Given a database name expressed as a string, look it up and return Oid
2505
convert_database_name(text *databasename)
2507
char *dbname = text_to_cstring(databasename);
2510
oid = get_database_oid(dbname);
2511
if (!OidIsValid(oid))
2513
(errcode(ERRCODE_UNDEFINED_DATABASE),
2514
errmsg("database \"%s\" does not exist", dbname)));
2520
* convert_database_priv_string
2521
* Convert text string to AclMode value.
2524
convert_database_priv_string(text *priv_type_text)
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) },
2538
return convert_any_priv_string(priv_type_text, database_priv_map);
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.
2549
* The result is a boolean value: true if user has the indicated
2550
* privilege, false if not.
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.
2559
has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
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);
2567
AclResult aclresult;
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);
2573
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2575
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2585
has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
2587
text *fdwname = PG_GETARG_TEXT_P(0);
2588
text *priv_type_text = PG_GETARG_TEXT_P(1);
2592
AclResult aclresult;
2594
roleid = GetUserId();
2595
fdwid = convert_foreign_data_wrapper_name(fdwname);
2596
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2598
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2600
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
2609
has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
2611
Name username = PG_GETARG_NAME(0);
2612
Oid fdwid = PG_GETARG_OID(1);
2613
text *priv_type_text = PG_GETARG_TEXT_P(2);
2616
AclResult aclresult;
2618
roleid = get_roleid_checked(NameStr(*username));
2619
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2621
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2623
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2633
has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
2635
Oid fdwid = PG_GETARG_OID(0);
2636
text *priv_type_text = PG_GETARG_TEXT_P(1);
2639
AclResult aclresult;
2641
roleid = GetUserId();
2642
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2644
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2646
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
2655
has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
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);
2662
AclResult aclresult;
2664
fdwid = convert_foreign_data_wrapper_name(fdwname);
2665
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2667
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2669
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
2678
has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
2680
Oid roleid = PG_GETARG_OID(0);
2681
Oid fdwid = PG_GETARG_OID(1);
2682
text *priv_type_text = PG_GETARG_TEXT_P(2);
2684
AclResult aclresult;
2686
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
2688
aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
2690
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2694
* Support routines for has_foreign_data_wrapper_privilege family.
2698
* Given a FDW name expressed as a string, look it up and return Oid
2701
convert_foreign_data_wrapper_name(text *fdwname)
2703
char *fdwstr = text_to_cstring(fdwname);
2705
return GetForeignDataWrapperOidByName(fdwstr, false);
2709
* convert_foreign_data_wrapper_priv_string
2710
* Convert text string to AclMode value.
2713
convert_foreign_data_wrapper_priv_string(text *priv_type_text)
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) },
2721
return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
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.
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.
2736
* has_function_privilege_name_name
2737
* Check user privileges on a function given
2738
* name username, text functionname, and text priv name.
2741
has_function_privilege_name_name(PG_FUNCTION_ARGS)
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);
2749
AclResult aclresult;
2751
roleid = get_roleid_checked(NameStr(*username));
2752
functionoid = convert_function_name(functionname);
2753
mode = convert_function_priv_string(priv_type_text);
2755
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2757
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2767
has_function_privilege_name(PG_FUNCTION_ARGS)
2769
text *functionname = PG_GETARG_TEXT_P(0);
2770
text *priv_type_text = PG_GETARG_TEXT_P(1);
2774
AclResult aclresult;
2776
roleid = GetUserId();
2777
functionoid = convert_function_name(functionname);
2778
mode = convert_function_priv_string(priv_type_text);
2780
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2782
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2786
* has_function_privilege_name_id
2787
* Check user privileges on a function given
2788
* name usename, function oid, and text priv name.
2791
has_function_privilege_name_id(PG_FUNCTION_ARGS)
2793
Name username = PG_GETARG_NAME(0);
2794
Oid functionoid = PG_GETARG_OID(1);
2795
text *priv_type_text = PG_GETARG_TEXT_P(2);
2798
AclResult aclresult;
2800
roleid = get_roleid_checked(NameStr(*username));
2801
mode = convert_function_priv_string(priv_type_text);
2803
if (!SearchSysCacheExists(PROCOID,
2804
ObjectIdGetDatum(functionoid),
2808
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2810
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2820
has_function_privilege_id(PG_FUNCTION_ARGS)
2822
Oid functionoid = PG_GETARG_OID(0);
2823
text *priv_type_text = PG_GETARG_TEXT_P(1);
2826
AclResult aclresult;
2828
roleid = GetUserId();
2829
mode = convert_function_priv_string(priv_type_text);
2831
if (!SearchSysCacheExists(PROCOID,
2832
ObjectIdGetDatum(functionoid),
2836
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2838
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2842
* has_function_privilege_id_name
2843
* Check user privileges on a function given
2844
* roleid, text functionname, and text priv name.
2847
has_function_privilege_id_name(PG_FUNCTION_ARGS)
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);
2854
AclResult aclresult;
2856
functionoid = convert_function_name(functionname);
2857
mode = convert_function_priv_string(priv_type_text);
2859
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2861
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2865
* has_function_privilege_id_id
2866
* Check user privileges on a function given
2867
* roleid, function oid, and text priv name.
2870
has_function_privilege_id_id(PG_FUNCTION_ARGS)
2872
Oid roleid = PG_GETARG_OID(0);
2873
Oid functionoid = PG_GETARG_OID(1);
2874
text *priv_type_text = PG_GETARG_TEXT_P(2);
2876
AclResult aclresult;
2878
mode = convert_function_priv_string(priv_type_text);
2880
if (!SearchSysCacheExists(PROCOID,
2881
ObjectIdGetDatum(functionoid),
2885
aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
2887
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2891
* Support routines for has_function_privilege family.
2895
* Given a function name expressed as a string, look it up and return Oid
2898
convert_function_name(text *functionname)
2900
char *funcname = text_to_cstring(functionname);
2903
oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
2904
CStringGetDatum(funcname)));
2906
if (!OidIsValid(oid))
2908
(errcode(ERRCODE_UNDEFINED_FUNCTION),
2909
errmsg("function \"%s\" does not exist", funcname)));
2915
* convert_function_priv_string
2916
* Convert text string to AclMode value.
2919
convert_function_priv_string(text *priv_type_text)
2921
static const priv_map function_priv_map[] = {
2922
{ "EXECUTE", ACL_EXECUTE },
2923
{ "EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE) },
2927
return convert_any_priv_string(priv_type_text, function_priv_map);
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.
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.
2942
* has_language_privilege_name_name
2943
* Check user privileges on a language given
2944
* name username, text languagename, and text priv name.
2947
has_language_privilege_name_name(PG_FUNCTION_ARGS)
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);
2955
AclResult aclresult;
2957
roleid = get_roleid_checked(NameStr(*username));
2958
languageoid = convert_language_name(languagename);
2959
mode = convert_language_priv_string(priv_type_text);
2961
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2963
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
2973
has_language_privilege_name(PG_FUNCTION_ARGS)
2975
text *languagename = PG_GETARG_TEXT_P(0);
2976
text *priv_type_text = PG_GETARG_TEXT_P(1);
2980
AclResult aclresult;
2982
roleid = GetUserId();
2983
languageoid = convert_language_name(languagename);
2984
mode = convert_language_priv_string(priv_type_text);
2986
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
2988
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
2992
* has_language_privilege_name_id
2993
* Check user privileges on a language given
2994
* name usename, language oid, and text priv name.
2997
has_language_privilege_name_id(PG_FUNCTION_ARGS)
2999
Name username = PG_GETARG_NAME(0);
3000
Oid languageoid = PG_GETARG_OID(1);
3001
text *priv_type_text = PG_GETARG_TEXT_P(2);
3004
AclResult aclresult;
3006
roleid = get_roleid_checked(NameStr(*username));
3007
mode = convert_language_priv_string(priv_type_text);
3009
if (!SearchSysCacheExists(LANGOID,
3010
ObjectIdGetDatum(languageoid),
3014
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3016
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3026
has_language_privilege_id(PG_FUNCTION_ARGS)
3028
Oid languageoid = PG_GETARG_OID(0);
3029
text *priv_type_text = PG_GETARG_TEXT_P(1);
3032
AclResult aclresult;
3034
roleid = GetUserId();
3035
mode = convert_language_priv_string(priv_type_text);
3037
if (!SearchSysCacheExists(LANGOID,
3038
ObjectIdGetDatum(languageoid),
3042
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3044
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3048
* has_language_privilege_id_name
3049
* Check user privileges on a language given
3050
* roleid, text languagename, and text priv name.
3053
has_language_privilege_id_name(PG_FUNCTION_ARGS)
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);
3060
AclResult aclresult;
3062
languageoid = convert_language_name(languagename);
3063
mode = convert_language_priv_string(priv_type_text);
3065
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3067
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3071
* has_language_privilege_id_id
3072
* Check user privileges on a language given
3073
* roleid, language oid, and text priv name.
3076
has_language_privilege_id_id(PG_FUNCTION_ARGS)
3078
Oid roleid = PG_GETARG_OID(0);
3079
Oid languageoid = PG_GETARG_OID(1);
3080
text *priv_type_text = PG_GETARG_TEXT_P(2);
3082
AclResult aclresult;
3084
mode = convert_language_priv_string(priv_type_text);
3086
if (!SearchSysCacheExists(LANGOID,
3087
ObjectIdGetDatum(languageoid),
3091
aclresult = pg_language_aclcheck(languageoid, roleid, mode);
3093
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3097
* Support routines for has_language_privilege family.
3101
* Given a language name expressed as a string, look it up and return Oid
3104
convert_language_name(text *languagename)
3106
char *langname = text_to_cstring(languagename);
3109
oid = GetSysCacheOid(LANGNAME,
3110
CStringGetDatum(langname),
3112
if (!OidIsValid(oid))
3114
(errcode(ERRCODE_UNDEFINED_OBJECT),
3115
errmsg("language \"%s\" does not exist", langname)));
3121
* convert_language_priv_string
3122
* Convert text string to AclMode value.
3125
convert_language_priv_string(text *priv_type_text)
3127
static const priv_map language_priv_map[] = {
3128
{ "USAGE", ACL_USAGE },
3129
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
3133
return convert_any_priv_string(priv_type_text, language_priv_map);
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.
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.
3148
* has_schema_privilege_name_name
3149
* Check user privileges on a schema given
3150
* name username, text schemaname, and text priv name.
3153
has_schema_privilege_name_name(PG_FUNCTION_ARGS)
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);
3161
AclResult aclresult;
3163
roleid = get_roleid_checked(NameStr(*username));
3164
schemaoid = convert_schema_name(schemaname);
3165
mode = convert_schema_priv_string(priv_type_text);
3167
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3169
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3179
has_schema_privilege_name(PG_FUNCTION_ARGS)
3181
text *schemaname = PG_GETARG_TEXT_P(0);
3182
text *priv_type_text = PG_GETARG_TEXT_P(1);
3186
AclResult aclresult;
3188
roleid = GetUserId();
3189
schemaoid = convert_schema_name(schemaname);
3190
mode = convert_schema_priv_string(priv_type_text);
3192
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3194
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3198
* has_schema_privilege_name_id
3199
* Check user privileges on a schema given
3200
* name usename, schema oid, and text priv name.
3203
has_schema_privilege_name_id(PG_FUNCTION_ARGS)
3205
Name username = PG_GETARG_NAME(0);
3206
Oid schemaoid = PG_GETARG_OID(1);
3207
text *priv_type_text = PG_GETARG_TEXT_P(2);
3210
AclResult aclresult;
3212
roleid = get_roleid_checked(NameStr(*username));
3213
mode = convert_schema_priv_string(priv_type_text);
3215
if (!SearchSysCacheExists(NAMESPACEOID,
3216
ObjectIdGetDatum(schemaoid),
3220
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3222
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3232
has_schema_privilege_id(PG_FUNCTION_ARGS)
3234
Oid schemaoid = PG_GETARG_OID(0);
3235
text *priv_type_text = PG_GETARG_TEXT_P(1);
3238
AclResult aclresult;
3240
roleid = GetUserId();
3241
mode = convert_schema_priv_string(priv_type_text);
3243
if (!SearchSysCacheExists(NAMESPACEOID,
3244
ObjectIdGetDatum(schemaoid),
3248
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3250
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3254
* has_schema_privilege_id_name
3255
* Check user privileges on a schema given
3256
* roleid, text schemaname, and text priv name.
3259
has_schema_privilege_id_name(PG_FUNCTION_ARGS)
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);
3266
AclResult aclresult;
3268
schemaoid = convert_schema_name(schemaname);
3269
mode = convert_schema_priv_string(priv_type_text);
3271
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3273
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3277
* has_schema_privilege_id_id
3278
* Check user privileges on a schema given
3279
* roleid, schema oid, and text priv name.
3282
has_schema_privilege_id_id(PG_FUNCTION_ARGS)
3284
Oid roleid = PG_GETARG_OID(0);
3285
Oid schemaoid = PG_GETARG_OID(1);
3286
text *priv_type_text = PG_GETARG_TEXT_P(2);
3288
AclResult aclresult;
3290
mode = convert_schema_priv_string(priv_type_text);
3292
if (!SearchSysCacheExists(NAMESPACEOID,
3293
ObjectIdGetDatum(schemaoid),
3297
aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
3299
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3303
* Support routines for has_schema_privilege family.
3307
* Given a schema name expressed as a string, look it up and return Oid
3310
convert_schema_name(text *schemaname)
3312
char *nspname = text_to_cstring(schemaname);
3315
oid = GetSysCacheOid(NAMESPACENAME,
3316
CStringGetDatum(nspname),
3318
if (!OidIsValid(oid))
3320
(errcode(ERRCODE_UNDEFINED_SCHEMA),
3321
errmsg("schema \"%s\" does not exist", nspname)));
3327
* convert_schema_priv_string
3328
* Convert text string to AclMode value.
3331
convert_schema_priv_string(text *priv_type_text)
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) },
3341
return convert_any_priv_string(priv_type_text, schema_priv_map);
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.
3351
* The result is a boolean value: true if user has the indicated
3352
* privilege, false if not.
3356
* has_server_privilege_name_name
3357
* Check user privileges on a foreign server given
3358
* name username, text servername, and text priv name.
3361
has_server_privilege_name_name(PG_FUNCTION_ARGS)
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);
3369
AclResult aclresult;
3371
roleid = get_roleid_checked(NameStr(*username));
3372
serverid = convert_server_name(servername);
3373
mode = convert_server_priv_string(priv_type_text);
3375
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3377
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3387
has_server_privilege_name(PG_FUNCTION_ARGS)
3389
text *servername = PG_GETARG_TEXT_P(0);
3390
text *priv_type_text = PG_GETARG_TEXT_P(1);
3394
AclResult aclresult;
3396
roleid = GetUserId();
3397
serverid = convert_server_name(servername);
3398
mode = convert_server_priv_string(priv_type_text);
3400
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3402
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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.
3411
has_server_privilege_name_id(PG_FUNCTION_ARGS)
3413
Name username = PG_GETARG_NAME(0);
3414
Oid serverid = PG_GETARG_OID(1);
3415
text *priv_type_text = PG_GETARG_TEXT_P(2);
3418
AclResult aclresult;
3420
roleid = get_roleid_checked(NameStr(*username));
3421
mode = convert_server_priv_string(priv_type_text);
3423
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3425
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3435
has_server_privilege_id(PG_FUNCTION_ARGS)
3437
Oid serverid = PG_GETARG_OID(0);
3438
text *priv_type_text = PG_GETARG_TEXT_P(1);
3441
AclResult aclresult;
3443
roleid = GetUserId();
3444
mode = convert_server_priv_string(priv_type_text);
3446
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3448
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3452
* has_server_privilege_id_name
3453
* Check user privileges on a foreign server given
3454
* roleid, text servername, and text priv name.
3457
has_server_privilege_id_name(PG_FUNCTION_ARGS)
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);
3464
AclResult aclresult;
3466
serverid = convert_server_name(servername);
3467
mode = convert_server_priv_string(priv_type_text);
3469
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3471
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3475
* has_server_privilege_id_id
3476
* Check user privileges on a foreign server given
3477
* roleid, server oid, and text priv name.
3480
has_server_privilege_id_id(PG_FUNCTION_ARGS)
3482
Oid roleid = PG_GETARG_OID(0);
3483
Oid serverid = PG_GETARG_OID(1);
3484
text *priv_type_text = PG_GETARG_TEXT_P(2);
3486
AclResult aclresult;
3488
mode = convert_server_priv_string(priv_type_text);
3490
aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
3492
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3496
* Support routines for has_server_privilege family.
3500
* Given a server name expressed as a string, look it up and return Oid
3503
convert_server_name(text *servername)
3505
char *serverstr = text_to_cstring(servername);
3507
return GetForeignServerOidByName(serverstr, false);
3511
* convert_server_priv_string
3512
* Convert text string to AclMode value.
3515
convert_server_priv_string(text *priv_type_text)
3517
static const priv_map server_priv_map[] = {
3518
{ "USAGE", ACL_USAGE },
3519
{ "USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE) },
3523
return convert_any_priv_string(priv_type_text, server_priv_map);
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.
3533
* The result is a boolean value: true if user has the indicated
3534
* privilege, false if not.
3538
* has_tablespace_privilege_name_name
3539
* Check user privileges on a tablespace given
3540
* name username, text tablespacename, and text priv name.
3543
has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
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);
3551
AclResult aclresult;
3553
roleid = get_roleid_checked(NameStr(*username));
3554
tablespaceoid = convert_tablespace_name(tablespacename);
3555
mode = convert_tablespace_priv_string(priv_type_text);
3557
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3559
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3569
has_tablespace_privilege_name(PG_FUNCTION_ARGS)
3571
text *tablespacename = PG_GETARG_TEXT_P(0);
3572
text *priv_type_text = PG_GETARG_TEXT_P(1);
3576
AclResult aclresult;
3578
roleid = GetUserId();
3579
tablespaceoid = convert_tablespace_name(tablespacename);
3580
mode = convert_tablespace_priv_string(priv_type_text);
3582
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3584
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3588
* has_tablespace_privilege_name_id
3589
* Check user privileges on a tablespace given
3590
* name usename, tablespace oid, and text priv name.
3593
has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
3595
Name username = PG_GETARG_NAME(0);
3596
Oid tablespaceoid = PG_GETARG_OID(1);
3597
text *priv_type_text = PG_GETARG_TEXT_P(2);
3600
AclResult aclresult;
3602
roleid = get_roleid_checked(NameStr(*username));
3603
mode = convert_tablespace_priv_string(priv_type_text);
3605
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3607
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
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
3617
has_tablespace_privilege_id(PG_FUNCTION_ARGS)
3619
Oid tablespaceoid = PG_GETARG_OID(0);
3620
text *priv_type_text = PG_GETARG_TEXT_P(1);
3623
AclResult aclresult;
3625
roleid = GetUserId();
3626
mode = convert_tablespace_priv_string(priv_type_text);
3628
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3630
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3634
* has_tablespace_privilege_id_name
3635
* Check user privileges on a tablespace given
3636
* roleid, text tablespacename, and text priv name.
3639
has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
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);
3646
AclResult aclresult;
3648
tablespaceoid = convert_tablespace_name(tablespacename);
3649
mode = convert_tablespace_priv_string(priv_type_text);
3651
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3653
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3657
* has_tablespace_privilege_id_id
3658
* Check user privileges on a tablespace given
3659
* roleid, tablespace oid, and text priv name.
3662
has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
3664
Oid roleid = PG_GETARG_OID(0);
3665
Oid tablespaceoid = PG_GETARG_OID(1);
3666
text *priv_type_text = PG_GETARG_TEXT_P(2);
3668
AclResult aclresult;
3670
mode = convert_tablespace_priv_string(priv_type_text);
3672
aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
3674
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3678
* Support routines for has_tablespace_privilege family.
3682
* Given a tablespace name expressed as a string, look it up and return Oid
3685
convert_tablespace_name(text *tablespacename)
3687
char *spcname = text_to_cstring(tablespacename);
3690
oid = get_tablespace_oid(spcname);
3692
if (!OidIsValid(oid))
3694
(errcode(ERRCODE_UNDEFINED_OBJECT),
3695
errmsg("tablespace \"%s\" does not exist", spcname)));
3701
* convert_tablespace_priv_string
3702
* Convert text string to AclMode value.
3705
convert_tablespace_priv_string(text *priv_type_text)
3707
static const priv_map tablespace_priv_map[] = {
3708
{ "CREATE", ACL_CREATE },
3709
{ "CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE) },
3713
return convert_any_priv_string(priv_type_text, tablespace_priv_map);
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.
3722
* The result is a boolean value: true if user has the indicated
3723
* privilege, false if not.
3727
* pg_has_role_name_name
3728
* Check user privileges on a role given
3729
* name username, name rolename, and text priv name.
3732
pg_has_role_name_name(PG_FUNCTION_ARGS)
3734
Name username = PG_GETARG_NAME(0);
3735
Name rolename = PG_GETARG_NAME(1);
3736
text *priv_type_text = PG_GETARG_TEXT_P(2);
3740
AclResult aclresult;
3742
roleid = get_roleid_checked(NameStr(*username));
3743
roleoid = get_roleid_checked(NameStr(*rolename));
3744
mode = convert_role_priv_string(priv_type_text);
3746
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3748
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3753
* Check user privileges on a role given
3754
* name rolename and text priv name.
3755
* current_user is assumed
3758
pg_has_role_name(PG_FUNCTION_ARGS)
3760
Name rolename = PG_GETARG_NAME(0);
3761
text *priv_type_text = PG_GETARG_TEXT_P(1);
3765
AclResult aclresult;
3767
roleid = GetUserId();
3768
roleoid = get_roleid_checked(NameStr(*rolename));
3769
mode = convert_role_priv_string(priv_type_text);
3771
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3773
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3777
* pg_has_role_name_id
3778
* Check user privileges on a role given
3779
* name usename, role oid, and text priv name.
3782
pg_has_role_name_id(PG_FUNCTION_ARGS)
3784
Name username = PG_GETARG_NAME(0);
3785
Oid roleoid = PG_GETARG_OID(1);
3786
text *priv_type_text = PG_GETARG_TEXT_P(2);
3789
AclResult aclresult;
3791
roleid = get_roleid_checked(NameStr(*username));
3792
mode = convert_role_priv_string(priv_type_text);
3794
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3796
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3801
* Check user privileges on a role given
3802
* role oid, and text priv name.
3803
* current_user is assumed
3806
pg_has_role_id(PG_FUNCTION_ARGS)
3808
Oid roleoid = PG_GETARG_OID(0);
3809
text *priv_type_text = PG_GETARG_TEXT_P(1);
3812
AclResult aclresult;
3814
roleid = GetUserId();
3815
mode = convert_role_priv_string(priv_type_text);
3817
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3819
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3823
* pg_has_role_id_name
3824
* Check user privileges on a role given
3825
* roleid, name rolename, and text priv name.
3828
pg_has_role_id_name(PG_FUNCTION_ARGS)
3830
Oid roleid = PG_GETARG_OID(0);
3831
Name rolename = PG_GETARG_NAME(1);
3832
text *priv_type_text = PG_GETARG_TEXT_P(2);
3835
AclResult aclresult;
3837
roleoid = get_roleid_checked(NameStr(*rolename));
3838
mode = convert_role_priv_string(priv_type_text);
3840
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3842
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3847
* Check user privileges on a role given
3848
* roleid, role oid, and text priv name.
3851
pg_has_role_id_id(PG_FUNCTION_ARGS)
3853
Oid roleid = PG_GETARG_OID(0);
3854
Oid roleoid = PG_GETARG_OID(1);
3855
text *priv_type_text = PG_GETARG_TEXT_P(2);
3857
AclResult aclresult;
3859
mode = convert_role_priv_string(priv_type_text);
3861
aclresult = pg_role_aclcheck(roleoid, roleid, mode);
3863
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
3867
* Support routines for pg_has_role family.
3871
* convert_role_priv_string
3872
* Convert text string to AclMode value.
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.
3881
convert_role_priv_string(text *priv_type_text)
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) },
3893
return convert_any_priv_string(priv_type_text, role_priv_map);
3898
* Quick-and-dirty support for pg_has_role
3901
pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
3903
if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
3905
if (is_admin_of_role(roleid, role_oid))
3908
if (mode & ACL_CREATE)
3910
if (is_member_of_role(roleid, role_oid))
3913
if (mode & ACL_USAGE)
3915
if (has_privs_of_role(roleid, role_oid))
3918
return ACLCHECK_NO_PRIV;
3923
* initialization function (called by InitPostgres)
3926
initialize_acl(void)
3928
if (!IsBootstrapProcessingMode())
3931
* In normal mode, set a callback on any syscache invalidation of
3932
* pg_auth_members rows
3934
CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
3935
RoleMembershipCacheCallback,
3941
* RoleMembershipCacheCallback
3942
* Syscache inval callback function
3945
RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
3947
/* Force membership caches to be recomputed on next use */
3948
cached_privs_role = InvalidOid;
3949
cached_member_role = InvalidOid;
3953
/* Check if specified role has rolinherit set */
3955
has_rolinherit(Oid roleid)
3957
bool result = false;
3960
utup = SearchSysCache(AUTHOID,
3961
ObjectIdGetDatum(roleid),
3963
if (HeapTupleIsValid(utup))
3965
result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
3966
ReleaseSysCache(utup);
3973
* Get a list of roles that the specified roleid has the privileges of
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.
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()!
3983
* For the benefit of select_best_grantor, the result is defined to be
3984
* in breadth-first order, ie, closer relationships earlier.
3987
roles_has_privs_of(Oid roleid)
3991
List *new_cached_privs_roles;
3992
MemoryContext oldctx;
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;
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
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.
4009
roles_list = list_make1_oid(roleid);
4011
foreach(l, roles_list)
4013
Oid memberid = lfirst_oid(l);
4017
/* Ignore non-inheriting roles */
4018
if (!has_rolinherit(memberid))
4021
/* Find roles that memberid is directly a member of */
4022
memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4023
ObjectIdGetDatum(memberid),
4025
for (i = 0; i < memlist->n_members; i++)
4027
HeapTuple tup = &memlist->members[i]->tuple;
4028
Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
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.
4035
roles_list = list_append_unique_oid(roles_list, otherid);
4037
ReleaseSysCacheList(memlist);
4041
* Copy the completed list into TopMemoryContext so it will persist.
4043
oldctx = MemoryContextSwitchTo(TopMemoryContext);
4044
new_cached_privs_roles = list_copy(roles_list);
4045
MemoryContextSwitchTo(oldctx);
4046
list_free(roles_list);
4049
* Now safe to assign to state variable
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;
4056
/* And now we can return the answer */
4057
return cached_privs_roles;
4062
* Get a list of roles that the specified roleid is a member of
4064
* This is defined to recurse through roles regardless of rolinherit.
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()!
4071
roles_is_member_of(Oid roleid)
4075
List *new_cached_membership_roles;
4076
MemoryContext oldctx;
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;
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
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.
4093
roles_list = list_make1_oid(roleid);
4095
foreach(l, roles_list)
4097
Oid memberid = lfirst_oid(l);
4101
/* Find roles that memberid is directly a member of */
4102
memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4103
ObjectIdGetDatum(memberid),
4105
for (i = 0; i < memlist->n_members; i++)
4107
HeapTuple tup = &memlist->members[i]->tuple;
4108
Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
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.
4115
roles_list = list_append_unique_oid(roles_list, otherid);
4117
ReleaseSysCacheList(memlist);
4121
* Copy the completed list into TopMemoryContext so it will persist.
4123
oldctx = MemoryContextSwitchTo(TopMemoryContext);
4124
new_cached_membership_roles = list_copy(roles_list);
4125
MemoryContextSwitchTo(oldctx);
4126
list_free(roles_list);
4129
* Now safe to assign to state variable
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;
4136
/* And now we can return the answer */
4137
return cached_membership_roles;
4142
* Does member have the privileges of role (directly or indirectly)?
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.
4149
has_privs_of_role(Oid member, Oid role)
4151
/* Fast path for simple case */
4155
/* Superusers have every privilege, so are part of every role */
4156
if (superuser_arg(member))
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.
4163
return list_member_oid(roles_has_privs_of(member), role);
4168
* Is member a member of role (directly or indirectly)?
4170
* This is defined to recurse through roles regardless of rolinherit.
4173
is_member_of_role(Oid member, Oid role)
4175
/* Fast path for simple case */
4179
/* Superusers have every privilege, so are part of every role */
4180
if (superuser_arg(member))
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.
4187
return list_member_oid(roles_is_member_of(member), role);
4191
* check_is_member_of_role
4192
* is_member_of_role with a standard permission-violation error if not
4195
check_is_member_of_role(Oid member, Oid role)
4197
if (!is_member_of_role(member, role))
4199
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4200
errmsg("must be member of role \"%s\"",
4201
GetUserNameFromId(role))));
4205
* Is member a member of role, not considering superuserness?
4207
* This is identical to is_member_of_role except we ignore superuser
4211
is_member_of_role_nosuper(Oid member, Oid role)
4213
/* Fast path for simple case */
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.
4221
return list_member_oid(roles_is_member_of(member), role);
4226
* Is member an admin of role (directly or indirectly)? That is, is it
4227
* a member WITH ADMIN OPTION?
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.
4233
is_admin_of_role(Oid member, Oid role)
4235
bool result = false;
4239
/* Fast path for simple case */
4243
/* Superusers have every privilege, so are part of every role */
4244
if (superuser_arg(member))
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.
4252
roles_list = list_make1_oid(member);
4254
foreach(l, roles_list)
4256
Oid memberid = lfirst_oid(l);
4260
/* Find roles that memberid is directly a member of */
4261
memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1,
4262
ObjectIdGetDatum(memberid),
4264
for (i = 0; i < memlist->n_members; i++)
4266
HeapTuple tup = &memlist->members[i]->tuple;
4267
Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
4269
if (otherid == role &&
4270
((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
4272
/* Found what we came for, so can stop searching */
4277
roles_list = list_append_unique_oid(roles_list, otherid);
4279
ReleaseSysCacheList(memlist);
4284
list_free(roles_list);
4290
/* does what it says ... */
4292
count_one_bits(AclMode mask)
4296
/* this code relies on AclMode being an unsigned type */
4308
* Select the effective grantor ID for a GRANT or REVOKE operation.
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.
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.
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
4329
* If no grant options exist, we set grantorId to roleId, grantOptions to 0.
4332
select_best_grantor(Oid roleId, AclMode privileges,
4333
const Acl *acl, Oid ownerId,
4334
Oid *grantorId, AclMode *grantOptions)
4336
AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
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
4347
if (roleId == ownerId || superuser_arg(roleId))
4349
*grantorId = ownerId;
4350
*grantOptions = needed_goptions;
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.
4360
roles_list = roles_has_privs_of(roleId);
4362
/* initialize candidate result as default */
4363
*grantorId = roleId;
4364
*grantOptions = ACL_NO_RIGHTS;
4367
foreach(l, roles_list)
4369
Oid otherrole = lfirst_oid(l);
4372
otherprivs = aclmask_direct(acl, otherrole, ownerId,
4373
needed_goptions, ACLMASK_ALL);
4374
if (otherprivs == needed_goptions)
4376
/* Found a suitable grantor */
4377
*grantorId = otherrole;
4378
*grantOptions = otherprivs;
4383
* If it has just some of the needed privileges, remember best
4386
if (otherprivs != ACL_NO_RIGHTS)
4388
int nnewrights = count_one_bits(otherprivs);
4390
if (nnewrights > nrights)
4392
*grantorId = otherrole;
4393
*grantOptions = otherprivs;
4394
nrights = nnewrights;