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