]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/acl.c
Represent grant options in the information schema.
[postgresql] / src / backend / utils / adt / acl.c
1 /*-------------------------------------------------------------------------
2  *
3  * acl.c
4  *        Basic access control list data structures manipulation routines.
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.88 2003/06/11 09:23:55 petere Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <ctype.h>
18
19 #include "catalog/namespace.h"
20 #include "catalog/pg_shadow.h"
21 #include "catalog/pg_type.h"
22 #include "commands/dbcommands.h"
23 #include "miscadmin.h"
24 #include "utils/acl.h"
25 #include "utils/builtins.h"
26 #include "utils/lsyscache.h"
27 #include "utils/syscache.h"
28
29
30 #define ACL_IDTYPE_GID_KEYWORD  "group"
31 #define ACL_IDTYPE_UID_KEYWORD  "user"
32
33 static const char *getid(const char *s, char *n);
34 static void putid(char *p, const char *s);
35 static Acl *allocacl(int n);
36 static const char *aclparse(const char *s, AclItem *aip);
37 static bool aclitemeq(const AclItem *a1, const AclItem *a2);
38 static Acl *recursive_revoke(Acl *acl, AclId grantee,
39                                                          AclMode revoke_privs, DropBehavior behavior);
40
41 static AclMode convert_priv_string(text *priv_type_text);
42
43 static Oid      convert_table_name(text *tablename);
44 static AclMode convert_table_priv_string(text *priv_type_text);
45 static Oid      convert_database_name(text *databasename);
46 static AclMode convert_database_priv_string(text *priv_type_text);
47 static Oid      convert_function_name(text *functionname);
48 static AclMode convert_function_priv_string(text *priv_type_text);
49 static Oid      convert_language_name(text *languagename);
50 static AclMode convert_language_priv_string(text *priv_type_text);
51 static Oid      convert_schema_name(text *schemaname);
52 static AclMode convert_schema_priv_string(text *priv_type_text);
53
54
55 /*
56  * getid
57  *              Consumes the first alphanumeric string (identifier) found in string
58  *              's', ignoring any leading white space.  If it finds a double quote
59  *              it returns the word inside the quotes.
60  *
61  * RETURNS:
62  *              the string position in 's' that points to the next non-space character
63  *              in 's', after any quotes.  Also:
64  *              - loads the identifier into 'name'.  (If no identifier is found, 'name'
65  *                contains an empty string.)  name must be NAMEDATALEN bytes.
66  */
67 static const char *
68 getid(const char *s, char *n)
69 {
70         int                     len = 0;
71         bool            in_quotes = false;
72
73         Assert(s && n);
74
75         while (isspace((unsigned char) *s))
76                 s++;
77         /* This test had better match what putid() does, below */
78         for (;
79                  *s != '\0' &&
80                          (isalnum((unsigned char) *s) ||
81                           *s == '_' ||
82                           *s == '"' ||
83                           in_quotes);
84                  s++)
85         {
86                 if (*s == '"')
87                 {
88                         in_quotes = !in_quotes;
89                 }
90                 else
91                 {
92                         if (len >= NAMEDATALEN-1)
93                                 elog(ERROR, "identifier must be less than %d characters",
94                                          NAMEDATALEN);
95                         n[len++] = *s;
96                 }
97         }
98         n[len] = '\0';
99         while (isspace((unsigned char) *s))
100                 s++;
101         return s;
102 }
103
104 /*
105  * Write a user or group Name at *p, surrounding it with double quotes if
106  * needed.  There must be at least NAMEDATALEN+2 bytes available at *p.
107  */
108 static void
109 putid(char *p, const char *s)
110 {
111         const char *src;
112         bool    safe = true;
113
114         for (src = s; *src; src++)
115         {
116                 /* This test had better match what getid() does, above */
117                 if (!isalnum((unsigned char) *src) && *src != '_')
118                 {
119                         safe = false;
120                         break;
121                 }
122         }
123         if (!safe)
124                 *p++ = '"';
125         for (src = s; *src; src++)
126                 *p++ = *src;
127         if (!safe)
128                 *p++ = '"';
129         *p = '\0';
130 }
131
132 /*
133  * aclparse
134  *              Consumes and parses an ACL specification of the form:
135  *                              [group|user] [A-Za-z0-9]*=[rwaR]*
136  *              from string 's', ignoring any leading white space or white space
137  *              between the optional id type keyword (group|user) and the actual
138  *              ACL specification.
139  *
140  *              This routine is called by the parser as well as aclitemin(), hence
141  *              the added generality.
142  *
143  * RETURNS:
144  *              the string position in 's' immediately following the ACL
145  *              specification.  Also:
146  *              - loads the structure pointed to by 'aip' with the appropriate
147  *                UID/GID, id type identifier and mode type values.
148  */
149 static const char *
150 aclparse(const char *s, AclItem *aip)
151 {
152         AclMode         privs, goption, read;
153         uint32          idtype;
154         char            name[NAMEDATALEN];
155         char            name2[NAMEDATALEN];
156
157         Assert(s && aip);
158
159 #ifdef ACLDEBUG
160         elog(LOG, "aclparse: input = '%s'", s);
161 #endif
162         idtype = ACL_IDTYPE_UID;
163         s = getid(s, name);
164         if (*s != '=')
165         {
166                 /* we just read a keyword, not a name */
167                 if (strncmp(name, ACL_IDTYPE_GID_KEYWORD, sizeof(name)) == 0)
168                         idtype = ACL_IDTYPE_GID;
169                 else if (strncmp(name, ACL_IDTYPE_UID_KEYWORD, sizeof(name)) != 0)
170                         elog(ERROR, "aclparse: bad keyword, must be [group|user]");
171                 s = getid(s, name);             /* move s to the name beyond the keyword */
172                 if (name[0] == '\0')
173                         elog(ERROR, "aclparse: a name must follow the [group|user] keyword");
174         }
175         if (name[0] == '\0')
176                 idtype = ACL_IDTYPE_WORLD;
177
178         if (*s != '=')
179                 elog(ERROR, "aclparse: expecting \"=\" sign");
180
181         privs = goption = ACL_NO_RIGHTS;
182
183         for (++s, read=0; isalpha((unsigned char) *s) || *s == '*'; s++)
184         {
185                 switch (*s)
186                 {
187                         case '*':
188                                 goption |= read;
189                                 break;
190                         case ACL_INSERT_CHR:
191                                 read = ACL_INSERT;
192                                 break;
193                         case ACL_SELECT_CHR:
194                                 read = ACL_SELECT;
195                                 break;
196                         case ACL_UPDATE_CHR:
197                                 read = ACL_UPDATE;
198                                 break;
199                         case ACL_DELETE_CHR:
200                                 read = ACL_DELETE;
201                                 break;
202                         case ACL_RULE_CHR:
203                                 read = ACL_RULE;
204                                 break;
205                         case ACL_REFERENCES_CHR:
206                                 read = ACL_REFERENCES;
207                                 break;
208                         case ACL_TRIGGER_CHR:
209                                 read = ACL_TRIGGER;
210                                 break;
211                         case ACL_EXECUTE_CHR:
212                                 read = ACL_EXECUTE;
213                                 break;
214                         case ACL_USAGE_CHR:
215                                 read = ACL_USAGE;
216                                 break;
217                         case ACL_CREATE_CHR:
218                                 read = ACL_CREATE;
219                                 break;
220                         case ACL_CREATE_TEMP_CHR:
221                                 read = ACL_CREATE_TEMP;
222                                 break;
223                         default:
224                                 elog(ERROR, "aclparse: mode flags must use \"%s\"",
225                                          ACL_ALL_RIGHTS_STR);
226                 }
227
228                 privs |= read;
229         }
230
231         switch (idtype)
232         {
233                 case ACL_IDTYPE_UID:
234                         aip->ai_grantee = get_usesysid(name);
235                         break;
236                 case ACL_IDTYPE_GID:
237                         aip->ai_grantee = get_grosysid(name);
238                         break;
239                 case ACL_IDTYPE_WORLD:
240                         aip->ai_grantee = ACL_ID_WORLD;
241                         break;
242         }
243
244         /* XXX Allow a degree of backward compatibility by defaulting the
245          * grantor to the superuser. */
246         if (*s == '/')
247         {
248                 s = getid(s + 1, name2);
249                 if (name2[0] == '\0')
250                         elog(ERROR, "aclparse: a name must follow the \"/\" sign");
251
252                 aip->ai_grantor = get_usesysid(name2);
253         }
254         else
255         {
256                 aip->ai_grantor = BOOTSTRAP_USESYSID;
257                 elog(WARNING, "defaulting grantor to %u", BOOTSTRAP_USESYSID);
258         }
259
260         ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype);
261
262 #ifdef ACLDEBUG
263         elog(LOG, "aclparse: correctly read [%x %d %x]",
264                  idtype, aip->ai_grantee, privs);
265 #endif
266         return s;
267 }
268
269 /*
270  * allocacl
271  *              Allocates storage for a new Acl with 'n' entries.
272  *
273  * RETURNS:
274  *              the new Acl
275  */
276 static Acl *
277 allocacl(int n)
278 {
279         Acl                *new_acl;
280         Size            size;
281
282         if (n < 0)
283                 elog(ERROR, "allocacl: invalid size: %d", n);
284         size = ACL_N_SIZE(n);
285         new_acl = (Acl *) palloc0(size);
286         new_acl->size = size;
287         new_acl->ndim = 1;
288         new_acl->flags = 0;
289         new_acl->elemtype = ACLITEMOID;
290         ARR_LBOUND(new_acl)[0] = 0;
291         ARR_DIMS(new_acl)[0] = n;
292         return new_acl;
293 }
294
295 /*
296  * aclitemin
297  *              Allocates storage for, and fills in, a new AclItem given a string
298  *              's' that contains an ACL specification.  See aclparse for details.
299  *
300  * RETURNS:
301  *              the new AclItem
302  */
303 Datum
304 aclitemin(PG_FUNCTION_ARGS)
305 {
306         const char *s = PG_GETARG_CSTRING(0);
307         AclItem    *aip;
308
309         aip = (AclItem *) palloc(sizeof(AclItem));
310         s = aclparse(s, aip);
311         while (isspace((unsigned char) *s))
312                 ++s;
313         if (*s)
314                 elog(ERROR, "aclitemin: extra garbage at end of specification");
315         PG_RETURN_ACLITEM_P(aip);
316 }
317
318 /*
319  * aclitemout
320  *              Allocates storage for, and fills in, a new null-delimited string
321  *              containing a formatted ACL specification.  See aclparse for details.
322  *
323  * RETURNS:
324  *              the new string
325  */
326 Datum
327 aclitemout(PG_FUNCTION_ARGS)
328 {
329         AclItem    *aip = PG_GETARG_ACLITEM_P(0);
330         char       *p;
331         char       *out;
332         HeapTuple       htup;
333         unsigned        i;
334         char       *tmpname;
335
336         out = palloc(strlen("group =/") +
337                                  2 * N_ACL_RIGHTS +
338                                  2 * (NAMEDATALEN+2) +
339                                  1);
340
341         p = out;
342         *p = '\0';
343
344         switch (ACLITEM_GET_IDTYPE(*aip))
345         {
346                 case ACL_IDTYPE_UID:
347                         htup = SearchSysCache(SHADOWSYSID,
348                                                                   ObjectIdGetDatum(aip->ai_grantee),
349                                                                   0, 0, 0);
350                         if (HeapTupleIsValid(htup))
351                         {
352                                 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
353                                 ReleaseSysCache(htup);
354                         }
355                         else
356                         {
357                                 /* Generate numeric UID if we don't find an entry */
358                                 sprintf(p, "%d", aip->ai_grantee);
359                         }
360                         break;
361                 case ACL_IDTYPE_GID:
362                         strcpy(p, "group ");
363                         p += strlen(p);
364                         tmpname = get_groname(aip->ai_grantee);
365                         if (tmpname != NULL)
366                                 putid(p, tmpname);
367                         else
368                         {
369                                 /* Generate numeric GID if we don't find an entry */
370                                 sprintf(p, "%d", aip->ai_grantee);
371                         }
372                         break;
373                 case ACL_IDTYPE_WORLD:
374                         break;
375                 default:
376                         elog(ERROR, "aclitemout: bad idtype: %d",
377                                  ACLITEM_GET_IDTYPE(*aip));
378                         break;
379         }
380         while (*p)
381                 ++p;
382
383         *p++ = '=';
384
385         for (i = 0; i < N_ACL_RIGHTS; ++i)
386         {
387                 if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
388                         *p++ = ACL_ALL_RIGHTS_STR[i];
389                 if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
390                         *p++ = '*';
391         }
392
393         *p++ = '/';
394         *p = '\0';
395
396         htup = SearchSysCache(SHADOWSYSID,
397                                                   ObjectIdGetDatum(aip->ai_grantor),
398                                                   0, 0, 0);
399         if (HeapTupleIsValid(htup))
400         {
401                 putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename));
402                 ReleaseSysCache(htup);
403         }
404         else
405         {
406                 /* Generate numeric UID if we don't find an entry */
407                 sprintf(p, "%d", aip->ai_grantor);
408         }
409
410         while (*p)
411                 ++p;
412         *p = '\0';
413
414         PG_RETURN_CSTRING(out);
415 }
416
417 /*
418  * aclitemeq
419  *              Two AclItems are considered equal iff they have the same
420  *              grantee and grantor; the privileges are ignored.
421  */
422 static bool
423 aclitemeq(const AclItem *a1, const AclItem *a2)
424 {
425         return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
426                 a1->ai_grantee == a2->ai_grantee &&
427                 a1->ai_grantor == a2->ai_grantor;
428 }
429
430
431 /*
432  * acldefault()  --- create an ACL describing default access permissions
433  *
434  * Change this routine if you want to alter the default access policy for
435  * newly-created objects (or any object with a NULL acl entry).
436  */
437 Acl *
438 acldefault(GrantObjectType objtype, AclId ownerid)
439 {
440         AclMode         world_default;
441         AclMode         owner_default;
442         Acl                *acl;
443         AclItem    *aip;
444
445         switch (objtype)
446         {
447                 case ACL_OBJECT_RELATION:
448                         world_default = ACL_NO_RIGHTS;
449                         owner_default = ACL_ALL_RIGHTS_RELATION;
450                         break;
451                 case ACL_OBJECT_DATABASE:
452                         world_default = ACL_CREATE_TEMP;        /* not NO_RIGHTS! */
453                         owner_default = ACL_ALL_RIGHTS_DATABASE;
454                         break;
455                 case ACL_OBJECT_FUNCTION:
456                         /* Grant EXECUTE by default, for now */
457                         world_default = ACL_EXECUTE;
458                         owner_default = ACL_ALL_RIGHTS_FUNCTION;
459                         break;
460                 case ACL_OBJECT_LANGUAGE:
461                         /* Grant USAGE by default, for now */
462                         world_default = ACL_USAGE;
463                         owner_default = ACL_ALL_RIGHTS_LANGUAGE;
464                         break;
465                 case ACL_OBJECT_NAMESPACE:
466                         world_default = ACL_NO_RIGHTS;
467                         owner_default = ACL_ALL_RIGHTS_NAMESPACE;
468                         break;
469                 default:
470                         elog(ERROR, "acldefault: bogus objtype %d", (int) objtype);
471                         world_default = ACL_NO_RIGHTS;          /* keep compiler quiet */
472                         owner_default = ACL_NO_RIGHTS;
473                         break;
474         }
475
476         acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
477                                   + (ownerid ? 1 : 0));
478         aip = ACL_DAT(acl);
479
480         if (world_default != ACL_NO_RIGHTS)
481         {
482                 aip[0].ai_grantee = ACL_ID_WORLD;
483                 aip[0].ai_grantor = ownerid;
484                 ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
485         }
486
487         if (ownerid)
488         {
489                 int index = (world_default != ACL_NO_RIGHTS ? 1: 0);
490
491                 aip[index].ai_grantee = ownerid;
492                 aip[index].ai_grantor = ownerid;
493                 /* owner gets default privileges with grant option */
494                 ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID);
495         }
496
497         return acl;
498 }
499
500
501 /*
502  * Add or replace an item in an ACL array.      The result is a modified copy;
503  * the input object is not changed.
504  *
505  * NB: caller is responsible for having detoasted the input ACL, if needed.
506  */
507 Acl *
508 aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
509 {
510         Acl                *new_acl = NULL;
511         AclItem    *old_aip,
512                            *new_aip = NULL;
513         int                     dst,
514                                 num;
515
516         /* These checks for null input are probably dead code, but... */
517         if (!old_acl || ACL_NUM(old_acl) < 1)
518                 old_acl = allocacl(1);
519         if (!mod_aip)
520         {
521                 new_acl = allocacl(ACL_NUM(old_acl));
522                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
523                 return new_acl;
524         }
525
526         num = ACL_NUM(old_acl);
527         old_aip = ACL_DAT(old_acl);
528
529         /*
530          * Search the ACL for an existing entry for this grantee and
531          * grantor.  If one exists, just modify the entry in-place (well,
532          * in the same position, since we actually return a copy);
533          * otherwise, insert the new entry at the end.
534          */
535
536         for (dst = 0; dst < num; ++dst)
537         {
538                 if (aclitemeq(mod_aip, old_aip + dst))
539                 {
540                         /* found a match, so modify existing item */
541                         new_acl = allocacl(num);
542                         new_aip = ACL_DAT(new_acl);
543                         memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
544                         break;
545                 }
546         }
547
548         if (dst == num)
549         {
550                 /* need to append a new item */
551                 new_acl = allocacl(num + 1);
552                 new_aip = ACL_DAT(new_acl);
553                 memcpy(new_aip, old_aip, num * sizeof(AclItem));
554
555                 /* initialize the new entry with no permissions */
556                 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
557                 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
558                 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS, ACL_NO_RIGHTS,
559                                                                  ACLITEM_GET_IDTYPE(*mod_aip));
560                 num++;                                  /* set num to the size of new_acl */
561         }
562
563         /* apply the permissions mod */
564         switch (modechg)
565         {
566                 case ACL_MODECHG_ADD:
567                         ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
568                         ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
569                         break;
570                 case ACL_MODECHG_DEL:
571                         ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
572                         ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
573                         break;
574                 case ACL_MODECHG_EQL:
575                         ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
576                                                                          ACLITEM_GET_PRIVS(*mod_aip),
577                                                                          ACLITEM_GET_GOPTIONS(*mod_aip),
578                                                                          ACLITEM_GET_IDTYPE(new_aip[dst]));
579                         break;
580         }
581
582         /*
583          * If the adjusted entry has no permissions, delete it from the list.
584          */
585         if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
586         {
587                 memmove(new_aip + dst,
588                                 new_aip + dst + 1,
589                                 (num - dst - 1) * sizeof(AclItem));
590                 ARR_DIMS(new_acl)[0] = num - 1;
591                 ARR_SIZE(new_acl) -= sizeof(AclItem);
592         }
593
594         /*
595          * Remove abandoned privileges (cascading revoke)
596          */
597         if (modechg != ACL_MODECHG_ADD
598                 && ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
599                 && ACLITEM_GET_GOPTIONS(*mod_aip))
600                 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
601
602         return new_acl;
603 }
604
605
606 /*
607  * Ensure that no privilege is "abandoned".  A privilege is abandoned
608  * if the user that granted the privilege loses the grant option.  (So
609  * the chain through which it was granted is broken.)  Either the
610  * abandoned privileges are revoked as well, or an error message is
611  * printed, depending on the drop behavior option.
612  */
613 static Acl *
614 recursive_revoke(Acl *acl,
615                                  AclId grantee,
616                                  AclMode revoke_privs,
617                                  DropBehavior behavior)
618 {
619         int i;
620
621 restart:
622         for (i = 0; i < ACL_NUM(acl); i++)
623         {
624                 AclItem *aip = ACL_DAT(acl);
625
626                 if (aip[i].ai_grantor == grantee
627                         && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
628                 {
629                         AclItem mod_acl;
630
631                         if (behavior == DROP_RESTRICT)
632                                 elog(ERROR, "dependent privileges exist (use CASCADE to revoke them too)");
633
634                         mod_acl.ai_grantor = grantee;
635                         mod_acl.ai_grantee = aip[i].ai_grantee;
636                         ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
637                                                                          revoke_privs,
638                                                                          revoke_privs,
639                                                                          ACLITEM_GET_IDTYPE(aip[i]));
640
641                         acl = aclinsert3(acl, &mod_acl, ACL_MODECHG_DEL, behavior);
642                         goto restart;
643                 }
644         }
645
646         return acl;
647 }
648
649
650 /*
651  * aclinsert (exported function)
652  */
653 Datum
654 aclinsert(PG_FUNCTION_ARGS)
655 {
656         Acl                *old_acl = PG_GETARG_ACL_P(0);
657         AclItem    *mod_aip = PG_GETARG_ACLITEM_P(1);
658
659         PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL, DROP_CASCADE));
660 }
661
662 Datum
663 aclremove(PG_FUNCTION_ARGS)
664 {
665         Acl                *old_acl = PG_GETARG_ACL_P(0);
666         AclItem    *mod_aip = PG_GETARG_ACLITEM_P(1);
667         Acl                *new_acl;
668         AclItem    *old_aip,
669                            *new_aip;
670         int                     dst,
671                                 old_num,
672                                 new_num;
673
674         /* These checks for null input should be dead code, but... */
675         if (!old_acl || ACL_NUM(old_acl) < 1)
676                 old_acl = allocacl(1);
677         if (!mod_aip)
678         {
679                 new_acl = allocacl(ACL_NUM(old_acl));
680                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
681                 PG_RETURN_ACL_P(new_acl);
682         }
683
684         old_num = ACL_NUM(old_acl);
685         old_aip = ACL_DAT(old_acl);
686
687         /* Search for the matching entry */
688         for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
689                 ;
690
691         if (dst >= old_num)
692         {
693                 /* Not found, so return copy of source ACL */
694                 new_acl = allocacl(old_num);
695                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
696         }
697         else
698         {
699                 new_num = old_num - 1;
700                 new_acl = allocacl(new_num);
701                 new_aip = ACL_DAT(new_acl);
702                 if (dst == 0)
703                 {                                               /* start */
704                         elog(ERROR, "aclremove: removal of the world ACL??");
705                 }
706                 else if (dst == old_num - 1)
707                 {                                               /* end */
708                         memcpy((char *) new_aip,
709                                    (char *) old_aip,
710                                    new_num * sizeof(AclItem));
711                 }
712                 else
713                 {                                               /* middle */
714                         memcpy((char *) new_aip,
715                                    (char *) old_aip,
716                                    dst * sizeof(AclItem));
717                         memcpy((char *) (new_aip + dst),
718                                    (char *) (old_aip + dst + 1),
719                                    (new_num - dst) * sizeof(AclItem));
720                 }
721         }
722
723         PG_RETURN_ACL_P(new_acl);
724 }
725
726 Datum
727 aclcontains(PG_FUNCTION_ARGS)
728 {
729         Acl                *acl = PG_GETARG_ACL_P(0);
730         AclItem    *aip = PG_GETARG_ACLITEM_P(1);
731         AclItem    *aidat;
732         int                     i,
733                                 num;
734
735         num = ACL_NUM(acl);
736         aidat = ACL_DAT(acl);
737         for (i = 0; i < num; ++i)
738         {
739                 if (aip->ai_grantee == aidat[i].ai_grantee
740                         && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
741                         && aip->ai_grantor == aidat[i].ai_grantor
742                         && (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip)
743                         && (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip))
744                         PG_RETURN_BOOL(true);
745         }
746         PG_RETURN_BOOL(false);
747 }
748
749 Datum
750 makeaclitem(PG_FUNCTION_ARGS)
751 {
752         int32           u_grantee = PG_GETARG_INT32(0);
753         int32           g_grantee = PG_GETARG_INT32(1);
754         int32           grantor = PG_GETARG_INT32(2);
755         text       *privtext = PG_GETARG_TEXT_P(3);
756         bool            goption = PG_GETARG_BOOL(4);
757         AclItem    *aclitem;
758         AclMode         priv;
759
760         priv = convert_priv_string(privtext);
761
762         aclitem = (AclItem *) palloc(sizeof(*aclitem));
763         if (u_grantee == 0 && g_grantee == 0)
764         {
765                 aclitem->ai_grantee = 0;
766                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
767         }
768         else if (u_grantee != 0 && g_grantee != 0)
769         {
770                 elog(ERROR, "cannot specify both user and group");
771         }
772         else if (u_grantee != 0)
773         {
774                 aclitem->ai_grantee = u_grantee;
775                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
776         }
777         else if (g_grantee != 0)
778         {
779                 aclitem->ai_grantee = g_grantee;
780                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
781         }
782
783         aclitem->ai_grantor = grantor;
784         ACLITEM_SET_PRIVS(*aclitem, priv);
785         if (goption)
786                 ACLITEM_SET_GOPTIONS(*aclitem, priv);
787         else
788                 ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
789
790         PG_RETURN_ACLITEM_P(aclitem);
791 }
792
793 static AclMode
794 convert_priv_string(text *priv_type_text)
795 {
796         char       *priv_type;
797
798         priv_type = DatumGetCString(DirectFunctionCall1(textout,
799                                                                                                         PointerGetDatum(priv_type_text)));
800
801         if (strcasecmp(priv_type, "SELECT") == 0)
802                 return ACL_SELECT;
803         if (strcasecmp(priv_type, "INSERT") == 0)
804                 return ACL_INSERT;
805         if (strcasecmp(priv_type, "UPDATE") == 0)
806                 return ACL_UPDATE;
807         if (strcasecmp(priv_type, "DELETE") == 0)
808                 return ACL_DELETE;
809         if (strcasecmp(priv_type, "RULE") == 0)
810                 return ACL_RULE;
811         if (strcasecmp(priv_type, "REFERENCES") == 0)
812                 return ACL_REFERENCES;
813         if (strcasecmp(priv_type, "TRIGGER") == 0)
814                 return ACL_TRIGGER;
815         if (strcasecmp(priv_type, "EXECUTE") == 0)
816                 return ACL_EXECUTE;
817         if (strcasecmp(priv_type, "USAGE") == 0)
818                 return ACL_USAGE;
819         if (strcasecmp(priv_type, "CREATE") == 0)
820                 return ACL_CREATE;
821         if (strcasecmp(priv_type, "TEMP") == 0)
822                 return ACL_CREATE_TEMP;
823         if (strcasecmp(priv_type, "TEMPORARY") == 0)
824                 return ACL_CREATE_TEMP;
825
826         elog(ERROR, "invalid privilege type %s", priv_type);
827         return ACL_NO_RIGHTS;           /* keep compiler quiet */
828 }
829
830
831 /*
832  * has_table_privilege variants
833  *              These are all named "has_table_privilege" at the SQL level.
834  *              They take various combinations of relation name, relation OID,
835  *              user name, user sysid, or implicit user = current_user.
836  *
837  *              The result is a boolean value: true if user has the indicated
838  *              privilege, false if not.
839  */
840
841 /*
842  * has_table_privilege_name_name
843  *              Check user privileges on a table given
844  *              name username, text tablename, and text priv name.
845  */
846 Datum
847 has_table_privilege_name_name(PG_FUNCTION_ARGS)
848 {
849         Name            username = PG_GETARG_NAME(0);
850         text       *tablename = PG_GETARG_TEXT_P(1);
851         text       *priv_type_text = PG_GETARG_TEXT_P(2);
852         int32           usesysid;
853         Oid                     tableoid;
854         AclMode         mode;
855         AclResult       aclresult;
856
857         usesysid = get_usesysid(NameStr(*username));
858         tableoid = convert_table_name(tablename);
859         mode = convert_table_priv_string(priv_type_text);
860
861         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
862
863         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
864 }
865
866 /*
867  * has_table_privilege_name
868  *              Check user privileges on a table given
869  *              text tablename and text priv name.
870  *              current_user is assumed
871  */
872 Datum
873 has_table_privilege_name(PG_FUNCTION_ARGS)
874 {
875         text       *tablename = PG_GETARG_TEXT_P(0);
876         text       *priv_type_text = PG_GETARG_TEXT_P(1);
877         AclId           usesysid;
878         Oid                     tableoid;
879         AclMode         mode;
880         AclResult       aclresult;
881
882         usesysid = GetUserId();
883         tableoid = convert_table_name(tablename);
884         mode = convert_table_priv_string(priv_type_text);
885
886         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
887
888         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
889 }
890
891 /*
892  * has_table_privilege_name_id
893  *              Check user privileges on a table given
894  *              name usename, table oid, and text priv name.
895  */
896 Datum
897 has_table_privilege_name_id(PG_FUNCTION_ARGS)
898 {
899         Name            username = PG_GETARG_NAME(0);
900         Oid                     tableoid = PG_GETARG_OID(1);
901         text       *priv_type_text = PG_GETARG_TEXT_P(2);
902         int32           usesysid;
903         AclMode         mode;
904         AclResult       aclresult;
905
906         usesysid = get_usesysid(NameStr(*username));
907         mode = convert_table_priv_string(priv_type_text);
908
909         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
910
911         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
912 }
913
914 /*
915  * has_table_privilege_id
916  *              Check user privileges on a table given
917  *              table oid, and text priv name.
918  *              current_user is assumed
919  */
920 Datum
921 has_table_privilege_id(PG_FUNCTION_ARGS)
922 {
923         Oid                     tableoid = PG_GETARG_OID(0);
924         text       *priv_type_text = PG_GETARG_TEXT_P(1);
925         AclId           usesysid;
926         AclMode         mode;
927         AclResult       aclresult;
928
929         usesysid = GetUserId();
930         mode = convert_table_priv_string(priv_type_text);
931
932         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
933
934         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
935 }
936
937 /*
938  * has_table_privilege_id_name
939  *              Check user privileges on a table given
940  *              usesysid, text tablename, and text priv name.
941  */
942 Datum
943 has_table_privilege_id_name(PG_FUNCTION_ARGS)
944 {
945         int32           usesysid = PG_GETARG_INT32(0);
946         text       *tablename = PG_GETARG_TEXT_P(1);
947         text       *priv_type_text = PG_GETARG_TEXT_P(2);
948         Oid                     tableoid;
949         AclMode         mode;
950         AclResult       aclresult;
951
952         tableoid = convert_table_name(tablename);
953         mode = convert_table_priv_string(priv_type_text);
954
955         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
956
957         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
958 }
959
960 /*
961  * has_table_privilege_id_id
962  *              Check user privileges on a table given
963  *              usesysid, table oid, and text priv name.
964  */
965 Datum
966 has_table_privilege_id_id(PG_FUNCTION_ARGS)
967 {
968         int32           usesysid = PG_GETARG_INT32(0);
969         Oid                     tableoid = PG_GETARG_OID(1);
970         text       *priv_type_text = PG_GETARG_TEXT_P(2);
971         AclMode         mode;
972         AclResult       aclresult;
973
974         mode = convert_table_priv_string(priv_type_text);
975
976         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
977
978         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
979 }
980
981 /*
982  *              Support routines for has_table_privilege family.
983  */
984
985 /*
986  * Given a table name expressed as a string, look it up and return Oid
987  */
988 static Oid
989 convert_table_name(text *tablename)
990 {
991         RangeVar   *relrv;
992
993         relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
994                                                                                                  "has_table_privilege"));
995
996         return RangeVarGetRelid(relrv, false);
997 }
998
999 /*
1000  * convert_table_priv_string
1001  *              Convert text string to AclMode value.
1002  */
1003 static AclMode
1004 convert_table_priv_string(text *priv_type_text)
1005 {
1006         char       *priv_type;
1007
1008         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1009                                                                            PointerGetDatum(priv_type_text)));
1010
1011         /*
1012          * Return mode from priv_type string
1013          */
1014         if (strcasecmp(priv_type, "SELECT") == 0)
1015                 return ACL_SELECT;
1016         if (strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1017                 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1018
1019         if (strcasecmp(priv_type, "INSERT") == 0)
1020                 return ACL_INSERT;
1021         if (strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1022                 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1023
1024         if (strcasecmp(priv_type, "UPDATE") == 0)
1025                 return ACL_UPDATE;
1026         if (strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1027                 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1028
1029         if (strcasecmp(priv_type, "DELETE") == 0)
1030                 return ACL_DELETE;
1031         if (strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1032                 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1033
1034         if (strcasecmp(priv_type, "RULE") == 0)
1035                 return ACL_RULE;
1036         if (strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1037                 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1038
1039         if (strcasecmp(priv_type, "REFERENCES") == 0)
1040                 return ACL_REFERENCES;
1041         if (strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1042                 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1043
1044         if (strcasecmp(priv_type, "TRIGGER") == 0)
1045                 return ACL_TRIGGER;
1046         if (strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1047                 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1048
1049         elog(ERROR, "has_table_privilege: invalid privilege type %s",
1050                  priv_type);
1051         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1052 }
1053
1054
1055 /*
1056  * has_database_privilege variants
1057  *              These are all named "has_database_privilege" at the SQL level.
1058  *              They take various combinations of database name, database OID,
1059  *              user name, user sysid, or implicit user = current_user.
1060  *
1061  *              The result is a boolean value: true if user has the indicated
1062  *              privilege, false if not.
1063  */
1064
1065 /*
1066  * has_database_privilege_name_name
1067  *              Check user privileges on a database given
1068  *              name username, text databasename, and text priv name.
1069  */
1070 Datum
1071 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1072 {
1073         Name            username = PG_GETARG_NAME(0);
1074         text       *databasename = PG_GETARG_TEXT_P(1);
1075         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1076         int32           usesysid;
1077         Oid                     databaseoid;
1078         AclMode         mode;
1079         AclResult       aclresult;
1080
1081         usesysid = get_usesysid(NameStr(*username));
1082         databaseoid = convert_database_name(databasename);
1083         mode = convert_database_priv_string(priv_type_text);
1084
1085         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1086
1087         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1088 }
1089
1090 /*
1091  * has_database_privilege_name
1092  *              Check user privileges on a database given
1093  *              text databasename and text priv name.
1094  *              current_user is assumed
1095  */
1096 Datum
1097 has_database_privilege_name(PG_FUNCTION_ARGS)
1098 {
1099         text       *databasename = PG_GETARG_TEXT_P(0);
1100         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1101         AclId           usesysid;
1102         Oid                     databaseoid;
1103         AclMode         mode;
1104         AclResult       aclresult;
1105
1106         usesysid = GetUserId();
1107         databaseoid = convert_database_name(databasename);
1108         mode = convert_database_priv_string(priv_type_text);
1109
1110         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1111
1112         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1113 }
1114
1115 /*
1116  * has_database_privilege_name_id
1117  *              Check user privileges on a database given
1118  *              name usename, database oid, and text priv name.
1119  */
1120 Datum
1121 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1122 {
1123         Name            username = PG_GETARG_NAME(0);
1124         Oid                     databaseoid = PG_GETARG_OID(1);
1125         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1126         int32           usesysid;
1127         AclMode         mode;
1128         AclResult       aclresult;
1129
1130         usesysid = get_usesysid(NameStr(*username));
1131         mode = convert_database_priv_string(priv_type_text);
1132
1133         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1134
1135         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1136 }
1137
1138 /*
1139  * has_database_privilege_id
1140  *              Check user privileges on a database given
1141  *              database oid, and text priv name.
1142  *              current_user is assumed
1143  */
1144 Datum
1145 has_database_privilege_id(PG_FUNCTION_ARGS)
1146 {
1147         Oid                     databaseoid = PG_GETARG_OID(0);
1148         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1149         AclId           usesysid;
1150         AclMode         mode;
1151         AclResult       aclresult;
1152
1153         usesysid = GetUserId();
1154         mode = convert_database_priv_string(priv_type_text);
1155
1156         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1157
1158         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1159 }
1160
1161 /*
1162  * has_database_privilege_id_name
1163  *              Check user privileges on a database given
1164  *              usesysid, text databasename, and text priv name.
1165  */
1166 Datum
1167 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1168 {
1169         int32           usesysid = PG_GETARG_INT32(0);
1170         text       *databasename = PG_GETARG_TEXT_P(1);
1171         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1172         Oid                     databaseoid;
1173         AclMode         mode;
1174         AclResult       aclresult;
1175
1176         databaseoid = convert_database_name(databasename);
1177         mode = convert_database_priv_string(priv_type_text);
1178
1179         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1180
1181         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1182 }
1183
1184 /*
1185  * has_database_privilege_id_id
1186  *              Check user privileges on a database given
1187  *              usesysid, database oid, and text priv name.
1188  */
1189 Datum
1190 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1191 {
1192         int32           usesysid = PG_GETARG_INT32(0);
1193         Oid                     databaseoid = PG_GETARG_OID(1);
1194         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1195         AclMode         mode;
1196         AclResult       aclresult;
1197
1198         mode = convert_database_priv_string(priv_type_text);
1199
1200         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1201
1202         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1203 }
1204
1205 /*
1206  *              Support routines for has_database_privilege family.
1207  */
1208
1209 /*
1210  * Given a database name expressed as a string, look it up and return Oid
1211  */
1212 static Oid
1213 convert_database_name(text *databasename)
1214 {
1215         char       *dbname;
1216         Oid                     oid;
1217
1218         dbname = DatumGetCString(DirectFunctionCall1(textout,
1219                                                                                  PointerGetDatum(databasename)));
1220
1221         oid = get_database_oid(dbname);
1222         if (!OidIsValid(oid))
1223                 elog(ERROR, "database \"%s\" does not exist", dbname);
1224
1225         return oid;
1226 }
1227
1228 /*
1229  * convert_database_priv_string
1230  *              Convert text string to AclMode value.
1231  */
1232 static AclMode
1233 convert_database_priv_string(text *priv_type_text)
1234 {
1235         char       *priv_type;
1236
1237         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1238                                                                            PointerGetDatum(priv_type_text)));
1239
1240         /*
1241          * Return mode from priv_type string
1242          */
1243         if (strcasecmp(priv_type, "CREATE") == 0)
1244                 return ACL_CREATE;
1245         if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1246                 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1247
1248         if (strcasecmp(priv_type, "TEMPORARY") == 0)
1249                 return ACL_CREATE_TEMP;
1250         if (strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1251                 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1252
1253         if (strcasecmp(priv_type, "TEMP") == 0)
1254                 return ACL_CREATE_TEMP;
1255         if (strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1256                 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1257
1258         elog(ERROR, "has_database_privilege: invalid privilege type %s",
1259                  priv_type);
1260         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1261 }
1262
1263
1264 /*
1265  * has_function_privilege variants
1266  *              These are all named "has_function_privilege" at the SQL level.
1267  *              They take various combinations of function name, function OID,
1268  *              user name, user sysid, or implicit user = current_user.
1269  *
1270  *              The result is a boolean value: true if user has the indicated
1271  *              privilege, false if not.
1272  */
1273
1274 /*
1275  * has_function_privilege_name_name
1276  *              Check user privileges on a function given
1277  *              name username, text functionname, and text priv name.
1278  */
1279 Datum
1280 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1281 {
1282         Name            username = PG_GETARG_NAME(0);
1283         text       *functionname = PG_GETARG_TEXT_P(1);
1284         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1285         int32           usesysid;
1286         Oid                     functionoid;
1287         AclMode         mode;
1288         AclResult       aclresult;
1289
1290         usesysid = get_usesysid(NameStr(*username));
1291         functionoid = convert_function_name(functionname);
1292         mode = convert_function_priv_string(priv_type_text);
1293
1294         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1295
1296         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1297 }
1298
1299 /*
1300  * has_function_privilege_name
1301  *              Check user privileges on a function given
1302  *              text functionname and text priv name.
1303  *              current_user is assumed
1304  */
1305 Datum
1306 has_function_privilege_name(PG_FUNCTION_ARGS)
1307 {
1308         text       *functionname = PG_GETARG_TEXT_P(0);
1309         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1310         AclId           usesysid;
1311         Oid                     functionoid;
1312         AclMode         mode;
1313         AclResult       aclresult;
1314
1315         usesysid = GetUserId();
1316         functionoid = convert_function_name(functionname);
1317         mode = convert_function_priv_string(priv_type_text);
1318
1319         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1320
1321         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1322 }
1323
1324 /*
1325  * has_function_privilege_name_id
1326  *              Check user privileges on a function given
1327  *              name usename, function oid, and text priv name.
1328  */
1329 Datum
1330 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1331 {
1332         Name            username = PG_GETARG_NAME(0);
1333         Oid                     functionoid = PG_GETARG_OID(1);
1334         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1335         int32           usesysid;
1336         AclMode         mode;
1337         AclResult       aclresult;
1338
1339         usesysid = get_usesysid(NameStr(*username));
1340         mode = convert_function_priv_string(priv_type_text);
1341
1342         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1343
1344         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1345 }
1346
1347 /*
1348  * has_function_privilege_id
1349  *              Check user privileges on a function given
1350  *              function oid, and text priv name.
1351  *              current_user is assumed
1352  */
1353 Datum
1354 has_function_privilege_id(PG_FUNCTION_ARGS)
1355 {
1356         Oid                     functionoid = PG_GETARG_OID(0);
1357         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1358         AclId           usesysid;
1359         AclMode         mode;
1360         AclResult       aclresult;
1361
1362         usesysid = GetUserId();
1363         mode = convert_function_priv_string(priv_type_text);
1364
1365         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1366
1367         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1368 }
1369
1370 /*
1371  * has_function_privilege_id_name
1372  *              Check user privileges on a function given
1373  *              usesysid, text functionname, and text priv name.
1374  */
1375 Datum
1376 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1377 {
1378         int32           usesysid = PG_GETARG_INT32(0);
1379         text       *functionname = PG_GETARG_TEXT_P(1);
1380         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1381         Oid                     functionoid;
1382         AclMode         mode;
1383         AclResult       aclresult;
1384
1385         functionoid = convert_function_name(functionname);
1386         mode = convert_function_priv_string(priv_type_text);
1387
1388         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1389
1390         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1391 }
1392
1393 /*
1394  * has_function_privilege_id_id
1395  *              Check user privileges on a function given
1396  *              usesysid, function oid, and text priv name.
1397  */
1398 Datum
1399 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1400 {
1401         int32           usesysid = PG_GETARG_INT32(0);
1402         Oid                     functionoid = PG_GETARG_OID(1);
1403         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1404         AclMode         mode;
1405         AclResult       aclresult;
1406
1407         mode = convert_function_priv_string(priv_type_text);
1408
1409         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1410
1411         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1412 }
1413
1414 /*
1415  *              Support routines for has_function_privilege family.
1416  */
1417
1418 /*
1419  * Given a function name expressed as a string, look it up and return Oid
1420  */
1421 static Oid
1422 convert_function_name(text *functionname)
1423 {
1424         char       *funcname;
1425         Oid                     oid;
1426
1427         funcname = DatumGetCString(DirectFunctionCall1(textout,
1428                                                                                  PointerGetDatum(functionname)));
1429
1430         oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1431                                                                                          CStringGetDatum(funcname)));
1432
1433         if (!OidIsValid(oid))
1434                 elog(ERROR, "function \"%s\" does not exist", funcname);
1435
1436         return oid;
1437 }
1438
1439 /*
1440  * convert_function_priv_string
1441  *              Convert text string to AclMode value.
1442  */
1443 static AclMode
1444 convert_function_priv_string(text *priv_type_text)
1445 {
1446         char       *priv_type;
1447
1448         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1449                                                                            PointerGetDatum(priv_type_text)));
1450
1451         /*
1452          * Return mode from priv_type string
1453          */
1454         if (strcasecmp(priv_type, "EXECUTE") == 0)
1455                 return ACL_EXECUTE;
1456         if (strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1457                 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1458
1459         elog(ERROR, "has_function_privilege: invalid privilege type %s",
1460                  priv_type);
1461         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1462 }
1463
1464
1465 /*
1466  * has_language_privilege variants
1467  *              These are all named "has_language_privilege" at the SQL level.
1468  *              They take various combinations of language name, language OID,
1469  *              user name, user sysid, or implicit user = current_user.
1470  *
1471  *              The result is a boolean value: true if user has the indicated
1472  *              privilege, false if not.
1473  */
1474
1475 /*
1476  * has_language_privilege_name_name
1477  *              Check user privileges on a language given
1478  *              name username, text languagename, and text priv name.
1479  */
1480 Datum
1481 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1482 {
1483         Name            username = PG_GETARG_NAME(0);
1484         text       *languagename = PG_GETARG_TEXT_P(1);
1485         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1486         int32           usesysid;
1487         Oid                     languageoid;
1488         AclMode         mode;
1489         AclResult       aclresult;
1490
1491         usesysid = get_usesysid(NameStr(*username));
1492         languageoid = convert_language_name(languagename);
1493         mode = convert_language_priv_string(priv_type_text);
1494
1495         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1496
1497         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1498 }
1499
1500 /*
1501  * has_language_privilege_name
1502  *              Check user privileges on a language given
1503  *              text languagename and text priv name.
1504  *              current_user is assumed
1505  */
1506 Datum
1507 has_language_privilege_name(PG_FUNCTION_ARGS)
1508 {
1509         text       *languagename = PG_GETARG_TEXT_P(0);
1510         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1511         AclId           usesysid;
1512         Oid                     languageoid;
1513         AclMode         mode;
1514         AclResult       aclresult;
1515
1516         usesysid = GetUserId();
1517         languageoid = convert_language_name(languagename);
1518         mode = convert_language_priv_string(priv_type_text);
1519
1520         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1521
1522         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1523 }
1524
1525 /*
1526  * has_language_privilege_name_id
1527  *              Check user privileges on a language given
1528  *              name usename, language oid, and text priv name.
1529  */
1530 Datum
1531 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1532 {
1533         Name            username = PG_GETARG_NAME(0);
1534         Oid                     languageoid = PG_GETARG_OID(1);
1535         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1536         int32           usesysid;
1537         AclMode         mode;
1538         AclResult       aclresult;
1539
1540         usesysid = get_usesysid(NameStr(*username));
1541         mode = convert_language_priv_string(priv_type_text);
1542
1543         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1544
1545         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1546 }
1547
1548 /*
1549  * has_language_privilege_id
1550  *              Check user privileges on a language given
1551  *              language oid, and text priv name.
1552  *              current_user is assumed
1553  */
1554 Datum
1555 has_language_privilege_id(PG_FUNCTION_ARGS)
1556 {
1557         Oid                     languageoid = PG_GETARG_OID(0);
1558         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1559         AclId           usesysid;
1560         AclMode         mode;
1561         AclResult       aclresult;
1562
1563         usesysid = GetUserId();
1564         mode = convert_language_priv_string(priv_type_text);
1565
1566         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1567
1568         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1569 }
1570
1571 /*
1572  * has_language_privilege_id_name
1573  *              Check user privileges on a language given
1574  *              usesysid, text languagename, and text priv name.
1575  */
1576 Datum
1577 has_language_privilege_id_name(PG_FUNCTION_ARGS)
1578 {
1579         int32           usesysid = PG_GETARG_INT32(0);
1580         text       *languagename = PG_GETARG_TEXT_P(1);
1581         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1582         Oid                     languageoid;
1583         AclMode         mode;
1584         AclResult       aclresult;
1585
1586         languageoid = convert_language_name(languagename);
1587         mode = convert_language_priv_string(priv_type_text);
1588
1589         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1590
1591         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1592 }
1593
1594 /*
1595  * has_language_privilege_id_id
1596  *              Check user privileges on a language given
1597  *              usesysid, language oid, and text priv name.
1598  */
1599 Datum
1600 has_language_privilege_id_id(PG_FUNCTION_ARGS)
1601 {
1602         int32           usesysid = PG_GETARG_INT32(0);
1603         Oid                     languageoid = PG_GETARG_OID(1);
1604         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1605         AclMode         mode;
1606         AclResult       aclresult;
1607
1608         mode = convert_language_priv_string(priv_type_text);
1609
1610         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1611
1612         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1613 }
1614
1615 /*
1616  *              Support routines for has_language_privilege family.
1617  */
1618
1619 /*
1620  * Given a language name expressed as a string, look it up and return Oid
1621  */
1622 static Oid
1623 convert_language_name(text *languagename)
1624 {
1625         char       *langname;
1626         Oid                     oid;
1627
1628         langname = DatumGetCString(DirectFunctionCall1(textout,
1629                                                                                  PointerGetDatum(languagename)));
1630
1631         oid = GetSysCacheOid(LANGNAME,
1632                                                  CStringGetDatum(langname),
1633                                                  0, 0, 0);
1634         if (!OidIsValid(oid))
1635                 elog(ERROR, "language \"%s\" does not exist", langname);
1636
1637         return oid;
1638 }
1639
1640 /*
1641  * convert_language_priv_string
1642  *              Convert text string to AclMode value.
1643  */
1644 static AclMode
1645 convert_language_priv_string(text *priv_type_text)
1646 {
1647         char       *priv_type;
1648
1649         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1650                                                                            PointerGetDatum(priv_type_text)));
1651
1652         /*
1653          * Return mode from priv_type string
1654          */
1655         if (strcasecmp(priv_type, "USAGE") == 0)
1656                 return ACL_USAGE;
1657         if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1658                 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1659
1660         elog(ERROR, "has_language_privilege: invalid privilege type %s",
1661                  priv_type);
1662         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1663 }
1664
1665
1666 /*
1667  * has_schema_privilege variants
1668  *              These are all named "has_schema_privilege" at the SQL level.
1669  *              They take various combinations of schema name, schema OID,
1670  *              user name, user sysid, or implicit user = current_user.
1671  *
1672  *              The result is a boolean value: true if user has the indicated
1673  *              privilege, false if not.
1674  */
1675
1676 /*
1677  * has_schema_privilege_name_name
1678  *              Check user privileges on a schema given
1679  *              name username, text schemaname, and text priv name.
1680  */
1681 Datum
1682 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
1683 {
1684         Name            username = PG_GETARG_NAME(0);
1685         text       *schemaname = PG_GETARG_TEXT_P(1);
1686         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1687         int32           usesysid;
1688         Oid                     schemaoid;
1689         AclMode         mode;
1690         AclResult       aclresult;
1691
1692         usesysid = get_usesysid(NameStr(*username));
1693         schemaoid = convert_schema_name(schemaname);
1694         mode = convert_schema_priv_string(priv_type_text);
1695
1696         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1697
1698         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1699 }
1700
1701 /*
1702  * has_schema_privilege_name
1703  *              Check user privileges on a schema given
1704  *              text schemaname and text priv name.
1705  *              current_user is assumed
1706  */
1707 Datum
1708 has_schema_privilege_name(PG_FUNCTION_ARGS)
1709 {
1710         text       *schemaname = PG_GETARG_TEXT_P(0);
1711         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1712         AclId           usesysid;
1713         Oid                     schemaoid;
1714         AclMode         mode;
1715         AclResult       aclresult;
1716
1717         usesysid = GetUserId();
1718         schemaoid = convert_schema_name(schemaname);
1719         mode = convert_schema_priv_string(priv_type_text);
1720
1721         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1722
1723         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1724 }
1725
1726 /*
1727  * has_schema_privilege_name_id
1728  *              Check user privileges on a schema given
1729  *              name usename, schema oid, and text priv name.
1730  */
1731 Datum
1732 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
1733 {
1734         Name            username = PG_GETARG_NAME(0);
1735         Oid                     schemaoid = PG_GETARG_OID(1);
1736         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1737         int32           usesysid;
1738         AclMode         mode;
1739         AclResult       aclresult;
1740
1741         usesysid = get_usesysid(NameStr(*username));
1742         mode = convert_schema_priv_string(priv_type_text);
1743
1744         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1745
1746         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1747 }
1748
1749 /*
1750  * has_schema_privilege_id
1751  *              Check user privileges on a schema given
1752  *              schema oid, and text priv name.
1753  *              current_user is assumed
1754  */
1755 Datum
1756 has_schema_privilege_id(PG_FUNCTION_ARGS)
1757 {
1758         Oid                     schemaoid = PG_GETARG_OID(0);
1759         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1760         AclId           usesysid;
1761         AclMode         mode;
1762         AclResult       aclresult;
1763
1764         usesysid = GetUserId();
1765         mode = convert_schema_priv_string(priv_type_text);
1766
1767         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1768
1769         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1770 }
1771
1772 /*
1773  * has_schema_privilege_id_name
1774  *              Check user privileges on a schema given
1775  *              usesysid, text schemaname, and text priv name.
1776  */
1777 Datum
1778 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
1779 {
1780         int32           usesysid = PG_GETARG_INT32(0);
1781         text       *schemaname = PG_GETARG_TEXT_P(1);
1782         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1783         Oid                     schemaoid;
1784         AclMode         mode;
1785         AclResult       aclresult;
1786
1787         schemaoid = convert_schema_name(schemaname);
1788         mode = convert_schema_priv_string(priv_type_text);
1789
1790         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1791
1792         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1793 }
1794
1795 /*
1796  * has_schema_privilege_id_id
1797  *              Check user privileges on a schema given
1798  *              usesysid, schema oid, and text priv name.
1799  */
1800 Datum
1801 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
1802 {
1803         int32           usesysid = PG_GETARG_INT32(0);
1804         Oid                     schemaoid = PG_GETARG_OID(1);
1805         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1806         AclMode         mode;
1807         AclResult       aclresult;
1808
1809         mode = convert_schema_priv_string(priv_type_text);
1810
1811         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1812
1813         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1814 }
1815
1816 /*
1817  *              Support routines for has_schema_privilege family.
1818  */
1819
1820 /*
1821  * Given a schema name expressed as a string, look it up and return Oid
1822  */
1823 static Oid
1824 convert_schema_name(text *schemaname)
1825 {
1826         char       *nspname;
1827         Oid                     oid;
1828
1829         nspname = DatumGetCString(DirectFunctionCall1(textout,
1830                                                                                    PointerGetDatum(schemaname)));
1831
1832         oid = GetSysCacheOid(NAMESPACENAME,
1833                                                  CStringGetDatum(nspname),
1834                                                  0, 0, 0);
1835         if (!OidIsValid(oid))
1836                 elog(ERROR, "schema \"%s\" does not exist", nspname);
1837
1838         return oid;
1839 }
1840
1841 /*
1842  * convert_schema_priv_string
1843  *              Convert text string to AclMode value.
1844  */
1845 static AclMode
1846 convert_schema_priv_string(text *priv_type_text)
1847 {
1848         char       *priv_type;
1849
1850         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1851                                                                            PointerGetDatum(priv_type_text)));
1852
1853         /*
1854          * Return mode from priv_type string
1855          */
1856         if (strcasecmp(priv_type, "CREATE") == 0)
1857                 return ACL_CREATE;
1858         if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1859                 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1860
1861         if (strcasecmp(priv_type, "USAGE") == 0)
1862                 return ACL_USAGE;
1863         if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1864                 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1865
1866         elog(ERROR, "has_schema_privilege: invalid privilege type %s",
1867                  priv_type);
1868         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1869 }