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