]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/acl.c
Array mega-patch.
[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.89 2003/06/24 23:14:45 momjian 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  * user-facing version of aclitemeq() for use as the
432  * aclitem equality operator
433  */
434 Datum
435 aclitem_eq(PG_FUNCTION_ARGS)
436 {
437         PG_RETURN_BOOL(aclitemeq(PG_GETARG_ACLITEM_P(0), PG_GETARG_ACLITEM_P(1)));
438 }
439
440 /*
441  * acldefault()  --- create an ACL describing default access permissions
442  *
443  * Change this routine if you want to alter the default access policy for
444  * newly-created objects (or any object with a NULL acl entry).
445  */
446 Acl *
447 acldefault(GrantObjectType objtype, AclId ownerid)
448 {
449         AclMode         world_default;
450         AclMode         owner_default;
451         Acl                *acl;
452         AclItem    *aip;
453
454         switch (objtype)
455         {
456                 case ACL_OBJECT_RELATION:
457                         world_default = ACL_NO_RIGHTS;
458                         owner_default = ACL_ALL_RIGHTS_RELATION;
459                         break;
460                 case ACL_OBJECT_DATABASE:
461                         world_default = ACL_CREATE_TEMP;        /* not NO_RIGHTS! */
462                         owner_default = ACL_ALL_RIGHTS_DATABASE;
463                         break;
464                 case ACL_OBJECT_FUNCTION:
465                         /* Grant EXECUTE by default, for now */
466                         world_default = ACL_EXECUTE;
467                         owner_default = ACL_ALL_RIGHTS_FUNCTION;
468                         break;
469                 case ACL_OBJECT_LANGUAGE:
470                         /* Grant USAGE by default, for now */
471                         world_default = ACL_USAGE;
472                         owner_default = ACL_ALL_RIGHTS_LANGUAGE;
473                         break;
474                 case ACL_OBJECT_NAMESPACE:
475                         world_default = ACL_NO_RIGHTS;
476                         owner_default = ACL_ALL_RIGHTS_NAMESPACE;
477                         break;
478                 default:
479                         elog(ERROR, "acldefault: bogus objtype %d", (int) objtype);
480                         world_default = ACL_NO_RIGHTS;          /* keep compiler quiet */
481                         owner_default = ACL_NO_RIGHTS;
482                         break;
483         }
484
485         acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
486                                   + (ownerid ? 1 : 0));
487         aip = ACL_DAT(acl);
488
489         if (world_default != ACL_NO_RIGHTS)
490         {
491                 aip[0].ai_grantee = ACL_ID_WORLD;
492                 aip[0].ai_grantor = ownerid;
493                 ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
494         }
495
496         if (ownerid)
497         {
498                 int index = (world_default != ACL_NO_RIGHTS ? 1: 0);
499
500                 aip[index].ai_grantee = ownerid;
501                 aip[index].ai_grantor = ownerid;
502                 /* owner gets default privileges with grant option */
503                 ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID);
504         }
505
506         return acl;
507 }
508
509
510 /*
511  * Add or replace an item in an ACL array.      The result is a modified copy;
512  * the input object is not changed.
513  *
514  * NB: caller is responsible for having detoasted the input ACL, if needed.
515  */
516 Acl *
517 aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
518 {
519         Acl                *new_acl = NULL;
520         AclItem    *old_aip,
521                            *new_aip = NULL;
522         int                     dst,
523                                 num;
524
525         /* These checks for null input are probably dead code, but... */
526         if (!old_acl || ACL_NUM(old_acl) < 1)
527                 old_acl = allocacl(1);
528         if (!mod_aip)
529         {
530                 new_acl = allocacl(ACL_NUM(old_acl));
531                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
532                 return new_acl;
533         }
534
535         num = ACL_NUM(old_acl);
536         old_aip = ACL_DAT(old_acl);
537
538         /*
539          * Search the ACL for an existing entry for this grantee and
540          * grantor.  If one exists, just modify the entry in-place (well,
541          * in the same position, since we actually return a copy);
542          * otherwise, insert the new entry at the end.
543          */
544
545         for (dst = 0; dst < num; ++dst)
546         {
547                 if (aclitemeq(mod_aip, old_aip + dst))
548                 {
549                         /* found a match, so modify existing item */
550                         new_acl = allocacl(num);
551                         new_aip = ACL_DAT(new_acl);
552                         memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
553                         break;
554                 }
555         }
556
557         if (dst == num)
558         {
559                 /* need to append a new item */
560                 new_acl = allocacl(num + 1);
561                 new_aip = ACL_DAT(new_acl);
562                 memcpy(new_aip, old_aip, num * sizeof(AclItem));
563
564                 /* initialize the new entry with no permissions */
565                 new_aip[dst].ai_grantee = mod_aip->ai_grantee;
566                 new_aip[dst].ai_grantor = mod_aip->ai_grantor;
567                 ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS, ACL_NO_RIGHTS,
568                                                                  ACLITEM_GET_IDTYPE(*mod_aip));
569                 num++;                                  /* set num to the size of new_acl */
570         }
571
572         /* apply the permissions mod */
573         switch (modechg)
574         {
575                 case ACL_MODECHG_ADD:
576                         ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
577                         ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
578                         break;
579                 case ACL_MODECHG_DEL:
580                         ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
581                         ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
582                         break;
583                 case ACL_MODECHG_EQL:
584                         ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
585                                                                          ACLITEM_GET_PRIVS(*mod_aip),
586                                                                          ACLITEM_GET_GOPTIONS(*mod_aip),
587                                                                          ACLITEM_GET_IDTYPE(new_aip[dst]));
588                         break;
589         }
590
591         /*
592          * If the adjusted entry has no permissions, delete it from the list.
593          */
594         if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
595         {
596                 memmove(new_aip + dst,
597                                 new_aip + dst + 1,
598                                 (num - dst - 1) * sizeof(AclItem));
599                 ARR_DIMS(new_acl)[0] = num - 1;
600                 ARR_SIZE(new_acl) -= sizeof(AclItem);
601         }
602
603         /*
604          * Remove abandoned privileges (cascading revoke)
605          */
606         if (modechg != ACL_MODECHG_ADD
607                 && ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
608                 && ACLITEM_GET_GOPTIONS(*mod_aip))
609                 new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
610
611         return new_acl;
612 }
613
614
615 /*
616  * Ensure that no privilege is "abandoned".  A privilege is abandoned
617  * if the user that granted the privilege loses the grant option.  (So
618  * the chain through which it was granted is broken.)  Either the
619  * abandoned privileges are revoked as well, or an error message is
620  * printed, depending on the drop behavior option.
621  */
622 static Acl *
623 recursive_revoke(Acl *acl,
624                                  AclId grantee,
625                                  AclMode revoke_privs,
626                                  DropBehavior behavior)
627 {
628         int i;
629
630 restart:
631         for (i = 0; i < ACL_NUM(acl); i++)
632         {
633                 AclItem *aip = ACL_DAT(acl);
634
635                 if (aip[i].ai_grantor == grantee
636                         && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
637                 {
638                         AclItem mod_acl;
639
640                         if (behavior == DROP_RESTRICT)
641                                 elog(ERROR, "dependent privileges exist (use CASCADE to revoke them too)");
642
643                         mod_acl.ai_grantor = grantee;
644                         mod_acl.ai_grantee = aip[i].ai_grantee;
645                         ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
646                                                                          revoke_privs,
647                                                                          revoke_privs,
648                                                                          ACLITEM_GET_IDTYPE(aip[i]));
649
650                         acl = aclinsert3(acl, &mod_acl, ACL_MODECHG_DEL, behavior);
651                         goto restart;
652                 }
653         }
654
655         return acl;
656 }
657
658
659 /*
660  * aclinsert (exported function)
661  */
662 Datum
663 aclinsert(PG_FUNCTION_ARGS)
664 {
665         Acl                *old_acl = PG_GETARG_ACL_P(0);
666         AclItem    *mod_aip = PG_GETARG_ACLITEM_P(1);
667
668         PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL, DROP_CASCADE));
669 }
670
671 Datum
672 aclremove(PG_FUNCTION_ARGS)
673 {
674         Acl                *old_acl = PG_GETARG_ACL_P(0);
675         AclItem    *mod_aip = PG_GETARG_ACLITEM_P(1);
676         Acl                *new_acl;
677         AclItem    *old_aip,
678                            *new_aip;
679         int                     dst,
680                                 old_num,
681                                 new_num;
682
683         /* These checks for null input should be dead code, but... */
684         if (!old_acl || ACL_NUM(old_acl) < 1)
685                 old_acl = allocacl(1);
686         if (!mod_aip)
687         {
688                 new_acl = allocacl(ACL_NUM(old_acl));
689                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
690                 PG_RETURN_ACL_P(new_acl);
691         }
692
693         old_num = ACL_NUM(old_acl);
694         old_aip = ACL_DAT(old_acl);
695
696         /* Search for the matching entry */
697         for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
698                 ;
699
700         if (dst >= old_num)
701         {
702                 /* Not found, so return copy of source ACL */
703                 new_acl = allocacl(old_num);
704                 memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
705         }
706         else
707         {
708                 new_num = old_num - 1;
709                 new_acl = allocacl(new_num);
710                 new_aip = ACL_DAT(new_acl);
711                 if (dst == 0)
712                 {                                               /* start */
713                         elog(ERROR, "aclremove: removal of the world ACL??");
714                 }
715                 else if (dst == old_num - 1)
716                 {                                               /* end */
717                         memcpy((char *) new_aip,
718                                    (char *) old_aip,
719                                    new_num * sizeof(AclItem));
720                 }
721                 else
722                 {                                               /* middle */
723                         memcpy((char *) new_aip,
724                                    (char *) old_aip,
725                                    dst * sizeof(AclItem));
726                         memcpy((char *) (new_aip + dst),
727                                    (char *) (old_aip + dst + 1),
728                                    (new_num - dst) * sizeof(AclItem));
729                 }
730         }
731
732         PG_RETURN_ACL_P(new_acl);
733 }
734
735 Datum
736 aclcontains(PG_FUNCTION_ARGS)
737 {
738         Acl                *acl = PG_GETARG_ACL_P(0);
739         AclItem    *aip = PG_GETARG_ACLITEM_P(1);
740         AclItem    *aidat;
741         int                     i,
742                                 num;
743
744         num = ACL_NUM(acl);
745         aidat = ACL_DAT(acl);
746         for (i = 0; i < num; ++i)
747         {
748                 if (aip->ai_grantee == aidat[i].ai_grantee
749                         && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
750                         && aip->ai_grantor == aidat[i].ai_grantor
751                         && (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip)
752                         && (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip))
753                         PG_RETURN_BOOL(true);
754         }
755         PG_RETURN_BOOL(false);
756 }
757
758 Datum
759 makeaclitem(PG_FUNCTION_ARGS)
760 {
761         int32           u_grantee = PG_GETARG_INT32(0);
762         int32           g_grantee = PG_GETARG_INT32(1);
763         int32           grantor = PG_GETARG_INT32(2);
764         text       *privtext = PG_GETARG_TEXT_P(3);
765         bool            goption = PG_GETARG_BOOL(4);
766         AclItem    *aclitem;
767         AclMode         priv;
768
769         priv = convert_priv_string(privtext);
770
771         aclitem = (AclItem *) palloc(sizeof(*aclitem));
772         if (u_grantee == 0 && g_grantee == 0)
773         {
774                 aclitem->ai_grantee = 0;
775                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
776         }
777         else if (u_grantee != 0 && g_grantee != 0)
778         {
779                 elog(ERROR, "cannot specify both user and group");
780         }
781         else if (u_grantee != 0)
782         {
783                 aclitem->ai_grantee = u_grantee;
784                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
785         }
786         else if (g_grantee != 0)
787         {
788                 aclitem->ai_grantee = g_grantee;
789                 ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
790         }
791
792         aclitem->ai_grantor = grantor;
793         ACLITEM_SET_PRIVS(*aclitem, priv);
794         if (goption)
795                 ACLITEM_SET_GOPTIONS(*aclitem, priv);
796         else
797                 ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
798
799         PG_RETURN_ACLITEM_P(aclitem);
800 }
801
802 static AclMode
803 convert_priv_string(text *priv_type_text)
804 {
805         char       *priv_type;
806
807         priv_type = DatumGetCString(DirectFunctionCall1(textout,
808                                                                                                         PointerGetDatum(priv_type_text)));
809
810         if (strcasecmp(priv_type, "SELECT") == 0)
811                 return ACL_SELECT;
812         if (strcasecmp(priv_type, "INSERT") == 0)
813                 return ACL_INSERT;
814         if (strcasecmp(priv_type, "UPDATE") == 0)
815                 return ACL_UPDATE;
816         if (strcasecmp(priv_type, "DELETE") == 0)
817                 return ACL_DELETE;
818         if (strcasecmp(priv_type, "RULE") == 0)
819                 return ACL_RULE;
820         if (strcasecmp(priv_type, "REFERENCES") == 0)
821                 return ACL_REFERENCES;
822         if (strcasecmp(priv_type, "TRIGGER") == 0)
823                 return ACL_TRIGGER;
824         if (strcasecmp(priv_type, "EXECUTE") == 0)
825                 return ACL_EXECUTE;
826         if (strcasecmp(priv_type, "USAGE") == 0)
827                 return ACL_USAGE;
828         if (strcasecmp(priv_type, "CREATE") == 0)
829                 return ACL_CREATE;
830         if (strcasecmp(priv_type, "TEMP") == 0)
831                 return ACL_CREATE_TEMP;
832         if (strcasecmp(priv_type, "TEMPORARY") == 0)
833                 return ACL_CREATE_TEMP;
834
835         elog(ERROR, "invalid privilege type %s", priv_type);
836         return ACL_NO_RIGHTS;           /* keep compiler quiet */
837 }
838
839
840 /*
841  * has_table_privilege variants
842  *              These are all named "has_table_privilege" at the SQL level.
843  *              They take various combinations of relation name, relation OID,
844  *              user name, user sysid, or implicit user = current_user.
845  *
846  *              The result is a boolean value: true if user has the indicated
847  *              privilege, false if not.
848  */
849
850 /*
851  * has_table_privilege_name_name
852  *              Check user privileges on a table given
853  *              name username, text tablename, and text priv name.
854  */
855 Datum
856 has_table_privilege_name_name(PG_FUNCTION_ARGS)
857 {
858         Name            username = PG_GETARG_NAME(0);
859         text       *tablename = PG_GETARG_TEXT_P(1);
860         text       *priv_type_text = PG_GETARG_TEXT_P(2);
861         int32           usesysid;
862         Oid                     tableoid;
863         AclMode         mode;
864         AclResult       aclresult;
865
866         usesysid = get_usesysid(NameStr(*username));
867         tableoid = convert_table_name(tablename);
868         mode = convert_table_priv_string(priv_type_text);
869
870         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
871
872         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
873 }
874
875 /*
876  * has_table_privilege_name
877  *              Check user privileges on a table given
878  *              text tablename and text priv name.
879  *              current_user is assumed
880  */
881 Datum
882 has_table_privilege_name(PG_FUNCTION_ARGS)
883 {
884         text       *tablename = PG_GETARG_TEXT_P(0);
885         text       *priv_type_text = PG_GETARG_TEXT_P(1);
886         AclId           usesysid;
887         Oid                     tableoid;
888         AclMode         mode;
889         AclResult       aclresult;
890
891         usesysid = GetUserId();
892         tableoid = convert_table_name(tablename);
893         mode = convert_table_priv_string(priv_type_text);
894
895         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
896
897         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
898 }
899
900 /*
901  * has_table_privilege_name_id
902  *              Check user privileges on a table given
903  *              name usename, table oid, and text priv name.
904  */
905 Datum
906 has_table_privilege_name_id(PG_FUNCTION_ARGS)
907 {
908         Name            username = PG_GETARG_NAME(0);
909         Oid                     tableoid = PG_GETARG_OID(1);
910         text       *priv_type_text = PG_GETARG_TEXT_P(2);
911         int32           usesysid;
912         AclMode         mode;
913         AclResult       aclresult;
914
915         usesysid = get_usesysid(NameStr(*username));
916         mode = convert_table_priv_string(priv_type_text);
917
918         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
919
920         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
921 }
922
923 /*
924  * has_table_privilege_id
925  *              Check user privileges on a table given
926  *              table oid, and text priv name.
927  *              current_user is assumed
928  */
929 Datum
930 has_table_privilege_id(PG_FUNCTION_ARGS)
931 {
932         Oid                     tableoid = PG_GETARG_OID(0);
933         text       *priv_type_text = PG_GETARG_TEXT_P(1);
934         AclId           usesysid;
935         AclMode         mode;
936         AclResult       aclresult;
937
938         usesysid = GetUserId();
939         mode = convert_table_priv_string(priv_type_text);
940
941         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
942
943         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
944 }
945
946 /*
947  * has_table_privilege_id_name
948  *              Check user privileges on a table given
949  *              usesysid, text tablename, and text priv name.
950  */
951 Datum
952 has_table_privilege_id_name(PG_FUNCTION_ARGS)
953 {
954         int32           usesysid = PG_GETARG_INT32(0);
955         text       *tablename = PG_GETARG_TEXT_P(1);
956         text       *priv_type_text = PG_GETARG_TEXT_P(2);
957         Oid                     tableoid;
958         AclMode         mode;
959         AclResult       aclresult;
960
961         tableoid = convert_table_name(tablename);
962         mode = convert_table_priv_string(priv_type_text);
963
964         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
965
966         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
967 }
968
969 /*
970  * has_table_privilege_id_id
971  *              Check user privileges on a table given
972  *              usesysid, table oid, and text priv name.
973  */
974 Datum
975 has_table_privilege_id_id(PG_FUNCTION_ARGS)
976 {
977         int32           usesysid = PG_GETARG_INT32(0);
978         Oid                     tableoid = PG_GETARG_OID(1);
979         text       *priv_type_text = PG_GETARG_TEXT_P(2);
980         AclMode         mode;
981         AclResult       aclresult;
982
983         mode = convert_table_priv_string(priv_type_text);
984
985         aclresult = pg_class_aclcheck(tableoid, usesysid, mode);
986
987         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
988 }
989
990 /*
991  *              Support routines for has_table_privilege family.
992  */
993
994 /*
995  * Given a table name expressed as a string, look it up and return Oid
996  */
997 static Oid
998 convert_table_name(text *tablename)
999 {
1000         RangeVar   *relrv;
1001
1002         relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename,
1003                                                                                                  "has_table_privilege"));
1004
1005         return RangeVarGetRelid(relrv, false);
1006 }
1007
1008 /*
1009  * convert_table_priv_string
1010  *              Convert text string to AclMode value.
1011  */
1012 static AclMode
1013 convert_table_priv_string(text *priv_type_text)
1014 {
1015         char       *priv_type;
1016
1017         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1018                                                                            PointerGetDatum(priv_type_text)));
1019
1020         /*
1021          * Return mode from priv_type string
1022          */
1023         if (strcasecmp(priv_type, "SELECT") == 0)
1024                 return ACL_SELECT;
1025         if (strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
1026                 return ACL_GRANT_OPTION_FOR(ACL_SELECT);
1027
1028         if (strcasecmp(priv_type, "INSERT") == 0)
1029                 return ACL_INSERT;
1030         if (strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
1031                 return ACL_GRANT_OPTION_FOR(ACL_INSERT);
1032
1033         if (strcasecmp(priv_type, "UPDATE") == 0)
1034                 return ACL_UPDATE;
1035         if (strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
1036                 return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
1037
1038         if (strcasecmp(priv_type, "DELETE") == 0)
1039                 return ACL_DELETE;
1040         if (strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
1041                 return ACL_GRANT_OPTION_FOR(ACL_DELETE);
1042
1043         if (strcasecmp(priv_type, "RULE") == 0)
1044                 return ACL_RULE;
1045         if (strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
1046                 return ACL_GRANT_OPTION_FOR(ACL_RULE);
1047
1048         if (strcasecmp(priv_type, "REFERENCES") == 0)
1049                 return ACL_REFERENCES;
1050         if (strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
1051                 return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
1052
1053         if (strcasecmp(priv_type, "TRIGGER") == 0)
1054                 return ACL_TRIGGER;
1055         if (strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
1056                 return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
1057
1058         elog(ERROR, "has_table_privilege: invalid privilege type %s",
1059                  priv_type);
1060         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1061 }
1062
1063
1064 /*
1065  * has_database_privilege variants
1066  *              These are all named "has_database_privilege" at the SQL level.
1067  *              They take various combinations of database name, database OID,
1068  *              user name, user sysid, or implicit user = current_user.
1069  *
1070  *              The result is a boolean value: true if user has the indicated
1071  *              privilege, false if not.
1072  */
1073
1074 /*
1075  * has_database_privilege_name_name
1076  *              Check user privileges on a database given
1077  *              name username, text databasename, and text priv name.
1078  */
1079 Datum
1080 has_database_privilege_name_name(PG_FUNCTION_ARGS)
1081 {
1082         Name            username = PG_GETARG_NAME(0);
1083         text       *databasename = PG_GETARG_TEXT_P(1);
1084         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1085         int32           usesysid;
1086         Oid                     databaseoid;
1087         AclMode         mode;
1088         AclResult       aclresult;
1089
1090         usesysid = get_usesysid(NameStr(*username));
1091         databaseoid = convert_database_name(databasename);
1092         mode = convert_database_priv_string(priv_type_text);
1093
1094         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1095
1096         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1097 }
1098
1099 /*
1100  * has_database_privilege_name
1101  *              Check user privileges on a database given
1102  *              text databasename and text priv name.
1103  *              current_user is assumed
1104  */
1105 Datum
1106 has_database_privilege_name(PG_FUNCTION_ARGS)
1107 {
1108         text       *databasename = PG_GETARG_TEXT_P(0);
1109         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1110         AclId           usesysid;
1111         Oid                     databaseoid;
1112         AclMode         mode;
1113         AclResult       aclresult;
1114
1115         usesysid = GetUserId();
1116         databaseoid = convert_database_name(databasename);
1117         mode = convert_database_priv_string(priv_type_text);
1118
1119         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1120
1121         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1122 }
1123
1124 /*
1125  * has_database_privilege_name_id
1126  *              Check user privileges on a database given
1127  *              name usename, database oid, and text priv name.
1128  */
1129 Datum
1130 has_database_privilege_name_id(PG_FUNCTION_ARGS)
1131 {
1132         Name            username = PG_GETARG_NAME(0);
1133         Oid                     databaseoid = PG_GETARG_OID(1);
1134         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1135         int32           usesysid;
1136         AclMode         mode;
1137         AclResult       aclresult;
1138
1139         usesysid = get_usesysid(NameStr(*username));
1140         mode = convert_database_priv_string(priv_type_text);
1141
1142         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1143
1144         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1145 }
1146
1147 /*
1148  * has_database_privilege_id
1149  *              Check user privileges on a database given
1150  *              database oid, and text priv name.
1151  *              current_user is assumed
1152  */
1153 Datum
1154 has_database_privilege_id(PG_FUNCTION_ARGS)
1155 {
1156         Oid                     databaseoid = PG_GETARG_OID(0);
1157         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1158         AclId           usesysid;
1159         AclMode         mode;
1160         AclResult       aclresult;
1161
1162         usesysid = GetUserId();
1163         mode = convert_database_priv_string(priv_type_text);
1164
1165         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1166
1167         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1168 }
1169
1170 /*
1171  * has_database_privilege_id_name
1172  *              Check user privileges on a database given
1173  *              usesysid, text databasename, and text priv name.
1174  */
1175 Datum
1176 has_database_privilege_id_name(PG_FUNCTION_ARGS)
1177 {
1178         int32           usesysid = PG_GETARG_INT32(0);
1179         text       *databasename = PG_GETARG_TEXT_P(1);
1180         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1181         Oid                     databaseoid;
1182         AclMode         mode;
1183         AclResult       aclresult;
1184
1185         databaseoid = convert_database_name(databasename);
1186         mode = convert_database_priv_string(priv_type_text);
1187
1188         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1189
1190         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1191 }
1192
1193 /*
1194  * has_database_privilege_id_id
1195  *              Check user privileges on a database given
1196  *              usesysid, database oid, and text priv name.
1197  */
1198 Datum
1199 has_database_privilege_id_id(PG_FUNCTION_ARGS)
1200 {
1201         int32           usesysid = PG_GETARG_INT32(0);
1202         Oid                     databaseoid = PG_GETARG_OID(1);
1203         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1204         AclMode         mode;
1205         AclResult       aclresult;
1206
1207         mode = convert_database_priv_string(priv_type_text);
1208
1209         aclresult = pg_database_aclcheck(databaseoid, usesysid, mode);
1210
1211         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1212 }
1213
1214 /*
1215  *              Support routines for has_database_privilege family.
1216  */
1217
1218 /*
1219  * Given a database name expressed as a string, look it up and return Oid
1220  */
1221 static Oid
1222 convert_database_name(text *databasename)
1223 {
1224         char       *dbname;
1225         Oid                     oid;
1226
1227         dbname = DatumGetCString(DirectFunctionCall1(textout,
1228                                                                                  PointerGetDatum(databasename)));
1229
1230         oid = get_database_oid(dbname);
1231         if (!OidIsValid(oid))
1232                 elog(ERROR, "database \"%s\" does not exist", dbname);
1233
1234         return oid;
1235 }
1236
1237 /*
1238  * convert_database_priv_string
1239  *              Convert text string to AclMode value.
1240  */
1241 static AclMode
1242 convert_database_priv_string(text *priv_type_text)
1243 {
1244         char       *priv_type;
1245
1246         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1247                                                                            PointerGetDatum(priv_type_text)));
1248
1249         /*
1250          * Return mode from priv_type string
1251          */
1252         if (strcasecmp(priv_type, "CREATE") == 0)
1253                 return ACL_CREATE;
1254         if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1255                 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1256
1257         if (strcasecmp(priv_type, "TEMPORARY") == 0)
1258                 return ACL_CREATE_TEMP;
1259         if (strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
1260                 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1261
1262         if (strcasecmp(priv_type, "TEMP") == 0)
1263                 return ACL_CREATE_TEMP;
1264         if (strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
1265                 return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
1266
1267         elog(ERROR, "has_database_privilege: invalid privilege type %s",
1268                  priv_type);
1269         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1270 }
1271
1272
1273 /*
1274  * has_function_privilege variants
1275  *              These are all named "has_function_privilege" at the SQL level.
1276  *              They take various combinations of function name, function OID,
1277  *              user name, user sysid, or implicit user = current_user.
1278  *
1279  *              The result is a boolean value: true if user has the indicated
1280  *              privilege, false if not.
1281  */
1282
1283 /*
1284  * has_function_privilege_name_name
1285  *              Check user privileges on a function given
1286  *              name username, text functionname, and text priv name.
1287  */
1288 Datum
1289 has_function_privilege_name_name(PG_FUNCTION_ARGS)
1290 {
1291         Name            username = PG_GETARG_NAME(0);
1292         text       *functionname = PG_GETARG_TEXT_P(1);
1293         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1294         int32           usesysid;
1295         Oid                     functionoid;
1296         AclMode         mode;
1297         AclResult       aclresult;
1298
1299         usesysid = get_usesysid(NameStr(*username));
1300         functionoid = convert_function_name(functionname);
1301         mode = convert_function_priv_string(priv_type_text);
1302
1303         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1304
1305         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1306 }
1307
1308 /*
1309  * has_function_privilege_name
1310  *              Check user privileges on a function given
1311  *              text functionname and text priv name.
1312  *              current_user is assumed
1313  */
1314 Datum
1315 has_function_privilege_name(PG_FUNCTION_ARGS)
1316 {
1317         text       *functionname = PG_GETARG_TEXT_P(0);
1318         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1319         AclId           usesysid;
1320         Oid                     functionoid;
1321         AclMode         mode;
1322         AclResult       aclresult;
1323
1324         usesysid = GetUserId();
1325         functionoid = convert_function_name(functionname);
1326         mode = convert_function_priv_string(priv_type_text);
1327
1328         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1329
1330         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1331 }
1332
1333 /*
1334  * has_function_privilege_name_id
1335  *              Check user privileges on a function given
1336  *              name usename, function oid, and text priv name.
1337  */
1338 Datum
1339 has_function_privilege_name_id(PG_FUNCTION_ARGS)
1340 {
1341         Name            username = PG_GETARG_NAME(0);
1342         Oid                     functionoid = PG_GETARG_OID(1);
1343         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1344         int32           usesysid;
1345         AclMode         mode;
1346         AclResult       aclresult;
1347
1348         usesysid = get_usesysid(NameStr(*username));
1349         mode = convert_function_priv_string(priv_type_text);
1350
1351         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1352
1353         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1354 }
1355
1356 /*
1357  * has_function_privilege_id
1358  *              Check user privileges on a function given
1359  *              function oid, and text priv name.
1360  *              current_user is assumed
1361  */
1362 Datum
1363 has_function_privilege_id(PG_FUNCTION_ARGS)
1364 {
1365         Oid                     functionoid = PG_GETARG_OID(0);
1366         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1367         AclId           usesysid;
1368         AclMode         mode;
1369         AclResult       aclresult;
1370
1371         usesysid = GetUserId();
1372         mode = convert_function_priv_string(priv_type_text);
1373
1374         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1375
1376         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1377 }
1378
1379 /*
1380  * has_function_privilege_id_name
1381  *              Check user privileges on a function given
1382  *              usesysid, text functionname, and text priv name.
1383  */
1384 Datum
1385 has_function_privilege_id_name(PG_FUNCTION_ARGS)
1386 {
1387         int32           usesysid = PG_GETARG_INT32(0);
1388         text       *functionname = PG_GETARG_TEXT_P(1);
1389         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1390         Oid                     functionoid;
1391         AclMode         mode;
1392         AclResult       aclresult;
1393
1394         functionoid = convert_function_name(functionname);
1395         mode = convert_function_priv_string(priv_type_text);
1396
1397         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1398
1399         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1400 }
1401
1402 /*
1403  * has_function_privilege_id_id
1404  *              Check user privileges on a function given
1405  *              usesysid, function oid, and text priv name.
1406  */
1407 Datum
1408 has_function_privilege_id_id(PG_FUNCTION_ARGS)
1409 {
1410         int32           usesysid = PG_GETARG_INT32(0);
1411         Oid                     functionoid = PG_GETARG_OID(1);
1412         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1413         AclMode         mode;
1414         AclResult       aclresult;
1415
1416         mode = convert_function_priv_string(priv_type_text);
1417
1418         aclresult = pg_proc_aclcheck(functionoid, usesysid, mode);
1419
1420         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1421 }
1422
1423 /*
1424  *              Support routines for has_function_privilege family.
1425  */
1426
1427 /*
1428  * Given a function name expressed as a string, look it up and return Oid
1429  */
1430 static Oid
1431 convert_function_name(text *functionname)
1432 {
1433         char       *funcname;
1434         Oid                     oid;
1435
1436         funcname = DatumGetCString(DirectFunctionCall1(textout,
1437                                                                                  PointerGetDatum(functionname)));
1438
1439         oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
1440                                                                                          CStringGetDatum(funcname)));
1441
1442         if (!OidIsValid(oid))
1443                 elog(ERROR, "function \"%s\" does not exist", funcname);
1444
1445         return oid;
1446 }
1447
1448 /*
1449  * convert_function_priv_string
1450  *              Convert text string to AclMode value.
1451  */
1452 static AclMode
1453 convert_function_priv_string(text *priv_type_text)
1454 {
1455         char       *priv_type;
1456
1457         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1458                                                                            PointerGetDatum(priv_type_text)));
1459
1460         /*
1461          * Return mode from priv_type string
1462          */
1463         if (strcasecmp(priv_type, "EXECUTE") == 0)
1464                 return ACL_EXECUTE;
1465         if (strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
1466                 return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
1467
1468         elog(ERROR, "has_function_privilege: invalid privilege type %s",
1469                  priv_type);
1470         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1471 }
1472
1473
1474 /*
1475  * has_language_privilege variants
1476  *              These are all named "has_language_privilege" at the SQL level.
1477  *              They take various combinations of language name, language OID,
1478  *              user name, user sysid, or implicit user = current_user.
1479  *
1480  *              The result is a boolean value: true if user has the indicated
1481  *              privilege, false if not.
1482  */
1483
1484 /*
1485  * has_language_privilege_name_name
1486  *              Check user privileges on a language given
1487  *              name username, text languagename, and text priv name.
1488  */
1489 Datum
1490 has_language_privilege_name_name(PG_FUNCTION_ARGS)
1491 {
1492         Name            username = PG_GETARG_NAME(0);
1493         text       *languagename = PG_GETARG_TEXT_P(1);
1494         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1495         int32           usesysid;
1496         Oid                     languageoid;
1497         AclMode         mode;
1498         AclResult       aclresult;
1499
1500         usesysid = get_usesysid(NameStr(*username));
1501         languageoid = convert_language_name(languagename);
1502         mode = convert_language_priv_string(priv_type_text);
1503
1504         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1505
1506         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1507 }
1508
1509 /*
1510  * has_language_privilege_name
1511  *              Check user privileges on a language given
1512  *              text languagename and text priv name.
1513  *              current_user is assumed
1514  */
1515 Datum
1516 has_language_privilege_name(PG_FUNCTION_ARGS)
1517 {
1518         text       *languagename = PG_GETARG_TEXT_P(0);
1519         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1520         AclId           usesysid;
1521         Oid                     languageoid;
1522         AclMode         mode;
1523         AclResult       aclresult;
1524
1525         usesysid = GetUserId();
1526         languageoid = convert_language_name(languagename);
1527         mode = convert_language_priv_string(priv_type_text);
1528
1529         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1530
1531         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1532 }
1533
1534 /*
1535  * has_language_privilege_name_id
1536  *              Check user privileges on a language given
1537  *              name usename, language oid, and text priv name.
1538  */
1539 Datum
1540 has_language_privilege_name_id(PG_FUNCTION_ARGS)
1541 {
1542         Name            username = PG_GETARG_NAME(0);
1543         Oid                     languageoid = PG_GETARG_OID(1);
1544         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1545         int32           usesysid;
1546         AclMode         mode;
1547         AclResult       aclresult;
1548
1549         usesysid = get_usesysid(NameStr(*username));
1550         mode = convert_language_priv_string(priv_type_text);
1551
1552         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1553
1554         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1555 }
1556
1557 /*
1558  * has_language_privilege_id
1559  *              Check user privileges on a language given
1560  *              language oid, and text priv name.
1561  *              current_user is assumed
1562  */
1563 Datum
1564 has_language_privilege_id(PG_FUNCTION_ARGS)
1565 {
1566         Oid                     languageoid = PG_GETARG_OID(0);
1567         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1568         AclId           usesysid;
1569         AclMode         mode;
1570         AclResult       aclresult;
1571
1572         usesysid = GetUserId();
1573         mode = convert_language_priv_string(priv_type_text);
1574
1575         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1576
1577         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1578 }
1579
1580 /*
1581  * has_language_privilege_id_name
1582  *              Check user privileges on a language given
1583  *              usesysid, text languagename, and text priv name.
1584  */
1585 Datum
1586 has_language_privilege_id_name(PG_FUNCTION_ARGS)
1587 {
1588         int32           usesysid = PG_GETARG_INT32(0);
1589         text       *languagename = PG_GETARG_TEXT_P(1);
1590         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1591         Oid                     languageoid;
1592         AclMode         mode;
1593         AclResult       aclresult;
1594
1595         languageoid = convert_language_name(languagename);
1596         mode = convert_language_priv_string(priv_type_text);
1597
1598         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1599
1600         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1601 }
1602
1603 /*
1604  * has_language_privilege_id_id
1605  *              Check user privileges on a language given
1606  *              usesysid, language oid, and text priv name.
1607  */
1608 Datum
1609 has_language_privilege_id_id(PG_FUNCTION_ARGS)
1610 {
1611         int32           usesysid = PG_GETARG_INT32(0);
1612         Oid                     languageoid = PG_GETARG_OID(1);
1613         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1614         AclMode         mode;
1615         AclResult       aclresult;
1616
1617         mode = convert_language_priv_string(priv_type_text);
1618
1619         aclresult = pg_language_aclcheck(languageoid, usesysid, mode);
1620
1621         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1622 }
1623
1624 /*
1625  *              Support routines for has_language_privilege family.
1626  */
1627
1628 /*
1629  * Given a language name expressed as a string, look it up and return Oid
1630  */
1631 static Oid
1632 convert_language_name(text *languagename)
1633 {
1634         char       *langname;
1635         Oid                     oid;
1636
1637         langname = DatumGetCString(DirectFunctionCall1(textout,
1638                                                                                  PointerGetDatum(languagename)));
1639
1640         oid = GetSysCacheOid(LANGNAME,
1641                                                  CStringGetDatum(langname),
1642                                                  0, 0, 0);
1643         if (!OidIsValid(oid))
1644                 elog(ERROR, "language \"%s\" does not exist", langname);
1645
1646         return oid;
1647 }
1648
1649 /*
1650  * convert_language_priv_string
1651  *              Convert text string to AclMode value.
1652  */
1653 static AclMode
1654 convert_language_priv_string(text *priv_type_text)
1655 {
1656         char       *priv_type;
1657
1658         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1659                                                                            PointerGetDatum(priv_type_text)));
1660
1661         /*
1662          * Return mode from priv_type string
1663          */
1664         if (strcasecmp(priv_type, "USAGE") == 0)
1665                 return ACL_USAGE;
1666         if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1667                 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1668
1669         elog(ERROR, "has_language_privilege: invalid privilege type %s",
1670                  priv_type);
1671         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1672 }
1673
1674
1675 /*
1676  * has_schema_privilege variants
1677  *              These are all named "has_schema_privilege" at the SQL level.
1678  *              They take various combinations of schema name, schema OID,
1679  *              user name, user sysid, or implicit user = current_user.
1680  *
1681  *              The result is a boolean value: true if user has the indicated
1682  *              privilege, false if not.
1683  */
1684
1685 /*
1686  * has_schema_privilege_name_name
1687  *              Check user privileges on a schema given
1688  *              name username, text schemaname, and text priv name.
1689  */
1690 Datum
1691 has_schema_privilege_name_name(PG_FUNCTION_ARGS)
1692 {
1693         Name            username = PG_GETARG_NAME(0);
1694         text       *schemaname = PG_GETARG_TEXT_P(1);
1695         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1696         int32           usesysid;
1697         Oid                     schemaoid;
1698         AclMode         mode;
1699         AclResult       aclresult;
1700
1701         usesysid = get_usesysid(NameStr(*username));
1702         schemaoid = convert_schema_name(schemaname);
1703         mode = convert_schema_priv_string(priv_type_text);
1704
1705         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1706
1707         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1708 }
1709
1710 /*
1711  * has_schema_privilege_name
1712  *              Check user privileges on a schema given
1713  *              text schemaname and text priv name.
1714  *              current_user is assumed
1715  */
1716 Datum
1717 has_schema_privilege_name(PG_FUNCTION_ARGS)
1718 {
1719         text       *schemaname = PG_GETARG_TEXT_P(0);
1720         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1721         AclId           usesysid;
1722         Oid                     schemaoid;
1723         AclMode         mode;
1724         AclResult       aclresult;
1725
1726         usesysid = GetUserId();
1727         schemaoid = convert_schema_name(schemaname);
1728         mode = convert_schema_priv_string(priv_type_text);
1729
1730         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1731
1732         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1733 }
1734
1735 /*
1736  * has_schema_privilege_name_id
1737  *              Check user privileges on a schema given
1738  *              name usename, schema oid, and text priv name.
1739  */
1740 Datum
1741 has_schema_privilege_name_id(PG_FUNCTION_ARGS)
1742 {
1743         Name            username = PG_GETARG_NAME(0);
1744         Oid                     schemaoid = PG_GETARG_OID(1);
1745         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1746         int32           usesysid;
1747         AclMode         mode;
1748         AclResult       aclresult;
1749
1750         usesysid = get_usesysid(NameStr(*username));
1751         mode = convert_schema_priv_string(priv_type_text);
1752
1753         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1754
1755         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1756 }
1757
1758 /*
1759  * has_schema_privilege_id
1760  *              Check user privileges on a schema given
1761  *              schema oid, and text priv name.
1762  *              current_user is assumed
1763  */
1764 Datum
1765 has_schema_privilege_id(PG_FUNCTION_ARGS)
1766 {
1767         Oid                     schemaoid = PG_GETARG_OID(0);
1768         text       *priv_type_text = PG_GETARG_TEXT_P(1);
1769         AclId           usesysid;
1770         AclMode         mode;
1771         AclResult       aclresult;
1772
1773         usesysid = GetUserId();
1774         mode = convert_schema_priv_string(priv_type_text);
1775
1776         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1777
1778         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1779 }
1780
1781 /*
1782  * has_schema_privilege_id_name
1783  *              Check user privileges on a schema given
1784  *              usesysid, text schemaname, and text priv name.
1785  */
1786 Datum
1787 has_schema_privilege_id_name(PG_FUNCTION_ARGS)
1788 {
1789         int32           usesysid = PG_GETARG_INT32(0);
1790         text       *schemaname = PG_GETARG_TEXT_P(1);
1791         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1792         Oid                     schemaoid;
1793         AclMode         mode;
1794         AclResult       aclresult;
1795
1796         schemaoid = convert_schema_name(schemaname);
1797         mode = convert_schema_priv_string(priv_type_text);
1798
1799         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1800
1801         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1802 }
1803
1804 /*
1805  * has_schema_privilege_id_id
1806  *              Check user privileges on a schema given
1807  *              usesysid, schema oid, and text priv name.
1808  */
1809 Datum
1810 has_schema_privilege_id_id(PG_FUNCTION_ARGS)
1811 {
1812         int32           usesysid = PG_GETARG_INT32(0);
1813         Oid                     schemaoid = PG_GETARG_OID(1);
1814         text       *priv_type_text = PG_GETARG_TEXT_P(2);
1815         AclMode         mode;
1816         AclResult       aclresult;
1817
1818         mode = convert_schema_priv_string(priv_type_text);
1819
1820         aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode);
1821
1822         PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
1823 }
1824
1825 /*
1826  *              Support routines for has_schema_privilege family.
1827  */
1828
1829 /*
1830  * Given a schema name expressed as a string, look it up and return Oid
1831  */
1832 static Oid
1833 convert_schema_name(text *schemaname)
1834 {
1835         char       *nspname;
1836         Oid                     oid;
1837
1838         nspname = DatumGetCString(DirectFunctionCall1(textout,
1839                                                                                    PointerGetDatum(schemaname)));
1840
1841         oid = GetSysCacheOid(NAMESPACENAME,
1842                                                  CStringGetDatum(nspname),
1843                                                  0, 0, 0);
1844         if (!OidIsValid(oid))
1845                 elog(ERROR, "schema \"%s\" does not exist", nspname);
1846
1847         return oid;
1848 }
1849
1850 /*
1851  * convert_schema_priv_string
1852  *              Convert text string to AclMode value.
1853  */
1854 static AclMode
1855 convert_schema_priv_string(text *priv_type_text)
1856 {
1857         char       *priv_type;
1858
1859         priv_type = DatumGetCString(DirectFunctionCall1(textout,
1860                                                                            PointerGetDatum(priv_type_text)));
1861
1862         /*
1863          * Return mode from priv_type string
1864          */
1865         if (strcasecmp(priv_type, "CREATE") == 0)
1866                 return ACL_CREATE;
1867         if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
1868                 return ACL_GRANT_OPTION_FOR(ACL_CREATE);
1869
1870         if (strcasecmp(priv_type, "USAGE") == 0)
1871                 return ACL_USAGE;
1872         if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
1873                 return ACL_GRANT_OPTION_FOR(ACL_USAGE);
1874
1875         elog(ERROR, "has_schema_privilege: invalid privilege type %s",
1876                  priv_type);
1877         return ACL_NO_RIGHTS;           /* keep compiler quiet */
1878 }