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