aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2003-01-23 23:39:07 +0000
committerPeter Eisentraut <peter_e@gmx.net>2003-01-23 23:39:07 +0000
commitef7422510e93266e5aa9bb926d6747d5f2ae21f4 (patch)
tree98643df576fccfcb2cc4c9e37fcf533f64f1a56c /src/backend/utils/adt
parentaa78ca3a9591def436d6ce87cb37e7ad5f584308 (diff)
downloadpostgresql-ef7422510e93266e5aa9bb926d6747d5f2ae21f4.tar.gz
postgresql-ef7422510e93266e5aa9bb926d6747d5f2ae21f4.zip
Grant options, and cascading revoke. Grant options are allowed only for
users right now, not groups. Extension of has_foo_privileges functions to query the grant options. Extension of aclitem type to store grantor.
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/acl.c349
1 files changed, 224 insertions, 125 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index a0e94b5bbb3..5e98556b312 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.84 2002/12/05 04:04:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.85 2003/01/23 23:39:01 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,9 +32,10 @@
static const char *getid(const char *s, char *n);
static Acl *makeacl(int n);
-static const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
+static const char *aclparse(const char *s, AclItem *aip);
static bool aclitemeq(const AclItem *a1, const AclItem *a2);
-static bool aclitemgt(const AclItem *a1, const AclItem *a2);
+static Acl *recursive_revoke(Acl *acl, AclId grantee,
+ AclMode revoke_privs, DropBehavior behavior);
static Oid convert_table_name(text *tablename);
static AclMode convert_table_priv_string(text *priv_type_text);
@@ -102,7 +103,7 @@ getid(const char *s, char *n)
/*
* aclparse
* Consumes and parses an ACL specification of the form:
- * [group|user] [A-Za-z0-9]*[+-=][rwaR]*
+ * [group|user] [A-Za-z0-9]*=[rwaR]*
* from string 's', ignoring any leading white space or white space
* between the optional id type keyword (group|user) and the actual
* ACL specification.
@@ -115,25 +116,23 @@ getid(const char *s, char *n)
* specification. Also:
* - loads the structure pointed to by 'aip' with the appropriate
* UID/GID, id type identifier and mode type values.
- * - loads 'modechg' with the mode change flag.
*/
static const char *
-aclparse(const char *s, AclItem *aip, unsigned *modechg)
+aclparse(const char *s, AclItem *aip)
{
- AclMode privs;
+ AclMode privs, goption, read;
uint32 idtype;
char name[NAMEDATALEN];
+ char name2[NAMEDATALEN];
- Assert(s && aip && modechg);
+ Assert(s && aip);
#ifdef ACLDEBUG
elog(LOG, "aclparse: input = '%s'", s);
#endif
idtype = ACL_IDTYPE_UID;
s = getid(s, name);
- if (*s != ACL_MODECHG_ADD_CHR &&
- *s != ACL_MODECHG_DEL_CHR &&
- *s != ACL_MODECHG_EQL_CHR)
+ if (*s != '=')
{
/* we just read a keyword, not a name */
if (strncmp(name, ACL_IDTYPE_GID_KEYWORD, sizeof(name)) == 0)
@@ -147,87 +146,93 @@ aclparse(const char *s, AclItem *aip, unsigned *modechg)
if (name[0] == '\0')
idtype = ACL_IDTYPE_WORLD;
- switch (*s)
- {
- case ACL_MODECHG_ADD_CHR:
- *modechg = ACL_MODECHG_ADD;
- break;
- case ACL_MODECHG_DEL_CHR:
- *modechg = ACL_MODECHG_DEL;
- break;
- case ACL_MODECHG_EQL_CHR:
- *modechg = ACL_MODECHG_EQL;
- break;
- default:
- elog(ERROR, "aclparse: mode change flag must use \"%c%c%c\"",
- ACL_MODECHG_ADD_CHR,
- ACL_MODECHG_DEL_CHR,
- ACL_MODECHG_EQL_CHR);
- }
+ if (*s != '=')
+ elog(ERROR, "aclparse: expecting \"=\" sign");
- privs = ACL_NO_RIGHTS;
+ privs = goption = ACL_NO_RIGHTS;
- while (isalpha((unsigned char) *++s))
+ for (++s, read=0; isalpha((unsigned char) *s) || *s == '*'; s++)
{
switch (*s)
{
+ case '*':
+ goption |= read;
+ break;
case ACL_INSERT_CHR:
- privs |= ACL_INSERT;
+ read = ACL_INSERT;
break;
case ACL_SELECT_CHR:
- privs |= ACL_SELECT;
+ read = ACL_SELECT;
break;
case ACL_UPDATE_CHR:
- privs |= ACL_UPDATE;
+ read = ACL_UPDATE;
break;
case ACL_DELETE_CHR:
- privs |= ACL_DELETE;
+ read = ACL_DELETE;
break;
case ACL_RULE_CHR:
- privs |= ACL_RULE;
+ read = ACL_RULE;
break;
case ACL_REFERENCES_CHR:
- privs |= ACL_REFERENCES;
+ read = ACL_REFERENCES;
break;
case ACL_TRIGGER_CHR:
- privs |= ACL_TRIGGER;
+ read = ACL_TRIGGER;
break;
case ACL_EXECUTE_CHR:
- privs |= ACL_EXECUTE;
+ read = ACL_EXECUTE;
break;
case ACL_USAGE_CHR:
- privs |= ACL_USAGE;
+ read = ACL_USAGE;
break;
case ACL_CREATE_CHR:
- privs |= ACL_CREATE;
+ read = ACL_CREATE;
break;
case ACL_CREATE_TEMP_CHR:
- privs |= ACL_CREATE_TEMP;
+ read = ACL_CREATE_TEMP;
break;
default:
elog(ERROR, "aclparse: mode flags must use \"%s\"",
ACL_ALL_RIGHTS_STR);
}
+
+ privs |= read;
}
switch (idtype)
{
case ACL_IDTYPE_UID:
- aip->ai_id = get_usesysid(name);
+ aip->ai_grantee = get_usesysid(name);
break;
case ACL_IDTYPE_GID:
- aip->ai_id = get_grosysid(name);
+ aip->ai_grantee = get_grosysid(name);
break;
case ACL_IDTYPE_WORLD:
- aip->ai_id = ACL_ID_WORLD;
+ aip->ai_grantee = ACL_ID_WORLD;
break;
}
- ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, idtype);
+ /* XXX Allow a degree of backward compatibility by defaulting the
+ * grantor to the superuser. */
+ if (*s == '/')
+ {
+ s = getid(s + 1, name2);
+ if (name2[0] == '\0')
+ elog(ERROR, "aclparse: a name must follow the \"/\" sign");
+
+ aip->ai_grantor = get_usesysid(name2);
+ }
+ else
+ {
+ aip->ai_grantor = BOOTSTRAP_USESYSID;
+ elog(WARNING, "defaulting grantor to %u", BOOTSTRAP_USESYSID);
+ }
+
+ ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype);
#ifdef ACLDEBUG
- elog(LOG, "aclparse: correctly read [%x %d %x], modechg=%x",
- idtype, aip->ai_id, privs, *modechg);
+ elog(LOG, "aclparse: correctly read [%x %d %x]",
+ idtype, aip->ai_grantee, privs);
#endif
return s;
}
@@ -271,12 +276,9 @@ aclitemin(PG_FUNCTION_ARGS)
{
const char *s = PG_GETARG_CSTRING(0);
AclItem *aip;
- unsigned modechg;
aip = (AclItem *) palloc(sizeof(AclItem));
- s = aclparse(s, aip, &modechg);
- if (modechg != ACL_MODECHG_EQL)
- elog(ERROR, "aclitemin: cannot accept anything but = ACLs");
+ s = aclparse(s, aip);
while (isspace((unsigned char) *s))
++s;
if (*s)
@@ -302,14 +304,14 @@ aclitemout(PG_FUNCTION_ARGS)
unsigned i;
char *tmpname;
- p = out = palloc(strlen("group = ") + N_ACL_RIGHTS + NAMEDATALEN + 1);
+ p = out = palloc(strlen("group = ") + 2 * N_ACL_RIGHTS + 2* NAMEDATALEN + 2);
*p = '\0';
switch (ACLITEM_GET_IDTYPE(*aip))
{
case ACL_IDTYPE_UID:
htup = SearchSysCache(SHADOWSYSID,
- ObjectIdGetDatum(aip->ai_id),
+ ObjectIdGetDatum(aip->ai_grantee),
0, 0, 0);
if (HeapTupleIsValid(htup))
{
@@ -324,14 +326,14 @@ aclitemout(PG_FUNCTION_ARGS)
char *tmp;
tmp = DatumGetCString(DirectFunctionCall1(int4out,
- Int32GetDatum((int32) aip->ai_id)));
+ Int32GetDatum((int32) aip->ai_grantee)));
strcat(p, tmp);
pfree(tmp);
}
break;
case ACL_IDTYPE_GID:
strcat(p, "group ");
- tmpname = get_groname(aip->ai_id);
+ tmpname = get_groname(aip->ai_grantee);
if (tmpname != NULL)
strncat(p, tmpname, NAMEDATALEN);
else
@@ -340,7 +342,7 @@ aclitemout(PG_FUNCTION_ARGS)
char *tmp;
tmp = DatumGetCString(DirectFunctionCall1(int4out,
- Int32GetDatum((int32) aip->ai_id)));
+ Int32GetDatum((int32) aip->ai_grantee)));
strcat(p, tmp);
pfree(tmp);
}
@@ -354,10 +356,43 @@ aclitemout(PG_FUNCTION_ARGS)
}
while (*p)
++p;
+
*p++ = '=';
+
for (i = 0; i < N_ACL_RIGHTS; ++i)
- if (aip->ai_privs & (1 << i))
+ {
+ if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
*p++ = ACL_ALL_RIGHTS_STR[i];
+ if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
+ *p++ = '*';
+ }
+
+ *p++ = '/';
+ *p = '\0';
+
+ htup = SearchSysCache(SHADOWSYSID,
+ ObjectIdGetDatum(aip->ai_grantor),
+ 0, 0, 0);
+ if (HeapTupleIsValid(htup))
+ {
+ strncat(p,
+ NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename),
+ NAMEDATALEN);
+ ReleaseSysCache(htup);
+ }
+ else
+ {
+ /* Generate numeric UID if we don't find an entry */
+ char *tmp;
+
+ tmp = DatumGetCString(DirectFunctionCall1(int4out,
+ Int32GetDatum((int32) aip->ai_grantor)));
+ strcat(p, tmp);
+ pfree(tmp);
+ }
+
+ while (*p)
+ ++p;
*p = '\0';
PG_RETURN_CSTRING(out);
@@ -365,29 +400,15 @@ aclitemout(PG_FUNCTION_ARGS)
/*
* aclitemeq
- * aclitemgt
- * AclItem equality and greater-than comparison routines.
* Two AclItems are considered equal iff they have the same
- * identifier (and identifier type); the privileges are ignored.
- * Note that these routines are really only useful for sorting
- * AclItems into identifier order.
- *
- * RETURNS:
- * a boolean value indicating = or >
+ * grantee and grantor; the privileges are ignored.
*/
static bool
aclitemeq(const AclItem *a1, const AclItem *a2)
{
return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
- a1->ai_id == a2->ai_id;
-}
-
-static bool
-aclitemgt(const AclItem *a1, const AclItem *a2)
-{
- return ((ACLITEM_GET_IDTYPE(*a1) > ACLITEM_GET_IDTYPE(*a2)) ||
- (ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
- a1->ai_id > a2->ai_id));
+ a1->ai_grantee == a2->ai_grantee &&
+ a1->ai_grantor == a2->ai_grantor;
}
@@ -436,15 +457,25 @@ acldefault(GrantObjectType objtype, AclId ownerid)
break;
}
- acl = makeacl(ownerid ? 2 : 1);
+ acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
+ + (ownerid ? 1 : 0));
aip = ACL_DAT(acl);
- aip[0].ai_id = ACL_ID_WORLD;
- ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_IDTYPE_WORLD);
+ if (world_default != ACL_NO_RIGHTS)
+ {
+ aip[0].ai_grantee = ACL_ID_WORLD;
+ aip[0].ai_grantor = ownerid;
+ ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
+ }
+
if (ownerid)
{
- aip[1].ai_id = ownerid;
- ACLITEM_SET_PRIVS_IDTYPE(aip[1], owner_default, ACL_IDTYPE_UID);
+ int index = (world_default != ACL_NO_RIGHTS ? 1: 0);
+
+ aip[index].ai_grantee = ownerid;
+ aip[index].ai_grantor = ownerid;
+ /* owner gets default privileges with grant option */
+ ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID);
}
return acl;
@@ -458,7 +489,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
* NB: caller is responsible for having detoasted the input ACL, if needed.
*/
Acl *
-aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
+aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
{
Acl *new_acl;
AclItem *old_aip,
@@ -480,49 +511,35 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
old_aip = ACL_DAT(old_acl);
/*
- * Search the ACL for an existing entry for 'id'. If one exists, just
- * modify the entry in-place (well, in the same position, since we
- * actually return a copy); otherwise, insert the new entry in
- * sort-order.
+ * Search the ACL for an existing entry for this grantee and
+ * grantor. If one exists, just modify the entry in-place (well,
+ * in the same position, since we actually return a copy);
+ * otherwise, insert the new entry at the end.
*/
- /* find the first element not less than the element to be inserted */
- for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip + dst); ++dst)
- ;
- if (dst < num && aclitemeq(mod_aip, old_aip + dst))
+ for (dst = 0; dst < num; ++dst)
{
- /* found a match, so modify existing item */
- new_acl = makeacl(num);
- new_aip = ACL_DAT(new_acl);
- memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+ if (aclitemeq(mod_aip, old_aip + dst))
+ {
+ /* found a match, so modify existing item */
+ new_acl = makeacl(num);
+ new_aip = ACL_DAT(new_acl);
+ memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
+ break;
+ }
}
- else
+
+ if (dst == num)
{
- /* need to insert a new item */
+ /* need to append a new item */
new_acl = makeacl(num + 1);
new_aip = ACL_DAT(new_acl);
- if (dst == 0)
- { /* start */
- elog(ERROR, "aclinsert3: insertion before world ACL??");
- }
- else if (dst >= num)
- { /* end */
- memcpy((char *) new_aip,
- (char *) old_aip,
- num * sizeof(AclItem));
- }
- else
- { /* middle */
- memcpy((char *) new_aip,
- (char *) old_aip,
- dst * sizeof(AclItem));
- memcpy((char *) (new_aip + dst + 1),
- (char *) (old_aip + dst),
- (num - dst) * sizeof(AclItem));
- }
+ memcpy(new_aip, old_aip, num * sizeof(AclItem));
+
/* initialize the new entry with no permissions */
- new_aip[dst].ai_id = mod_aip->ai_id;
- ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS,
+ new_aip[dst].ai_grantee = mod_aip->ai_grantee;
+ new_aip[dst].ai_grantor = mod_aip->ai_grantor;
+ ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS, ACL_NO_RIGHTS,
ACLITEM_GET_IDTYPE(*mod_aip));
num++; /* set num to the size of new_acl */
}
@@ -531,35 +548,89 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
switch (modechg)
{
case ACL_MODECHG_ADD:
- new_aip[dst].ai_privs |= ACLITEM_GET_PRIVS(*mod_aip);
+ ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
+ ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
break;
case ACL_MODECHG_DEL:
- new_aip[dst].ai_privs &= ~ACLITEM_GET_PRIVS(*mod_aip);
+ ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
+ ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
break;
case ACL_MODECHG_EQL:
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
ACLITEM_GET_PRIVS(*mod_aip),
+ ACLITEM_GET_GOPTIONS(*mod_aip),
ACLITEM_GET_IDTYPE(new_aip[dst]));
break;
}
/*
- * if the adjusted entry has no permissions, delete it from the list.
- * For example, this helps in removing entries for users who no longer
- * exist. EXCEPTION: never remove the world entry.
+ * If the adjusted entry has no permissions, delete it from the list.
*/
- if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS && dst > 0)
+ if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
{
- memmove((char *) (new_aip + dst),
- (char *) (new_aip + dst + 1),
+ memmove(new_aip + dst,
+ new_aip + dst + 1,
(num - dst - 1) * sizeof(AclItem));
ARR_DIMS(new_acl)[0] = num - 1;
ARR_SIZE(new_acl) -= sizeof(AclItem);
}
+ /*
+ * Remove abandoned privileges (cascading revoke)
+ */
+ if (modechg != ACL_MODECHG_ADD
+ && ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
+ && ACLITEM_GET_GOPTIONS(*mod_aip))
+ new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
+
return new_acl;
}
+
+/*
+ * Ensure that no privilege is "abandoned". A privilege is abandoned
+ * if the user that granted the privilege loses the grant option. (So
+ * the chain through which it was granted is broken.) Either the
+ * abandoned privileges are revoked as well, or an error message is
+ * printed, depending on the drop behavior option.
+ */
+static Acl *
+recursive_revoke(Acl *acl,
+ AclId grantee,
+ AclMode revoke_privs,
+ DropBehavior behavior)
+{
+ int i;
+
+restart:
+ for (i = 0; i < ACL_NUM(acl); i++)
+ {
+ AclItem *aip = ACL_DAT(acl);
+
+ if (aip[i].ai_grantor == grantee
+ && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
+ {
+ AclItem mod_acl;
+
+ if (behavior == DROP_RESTRICT)
+ elog(ERROR, "dependent privileges exist (use CASCADE to revoke them too)");
+
+ mod_acl.ai_grantor = grantee;
+ mod_acl.ai_grantee = aip[i].ai_grantee;
+ ACLITEM_SET_PRIVS_IDTYPE(mod_acl,
+ revoke_privs,
+ revoke_privs,
+ ACLITEM_GET_IDTYPE(aip[i]));
+
+ acl = aclinsert3(acl, &mod_acl, ACL_MODECHG_DEL, behavior);
+ goto restart;
+ }
+ }
+
+ return acl;
+}
+
+
/*
* aclinsert (exported function)
*/
@@ -569,7 +640,7 @@ aclinsert(PG_FUNCTION_ARGS)
Acl *old_acl = PG_GETARG_ACL_P(0);
AclItem *mod_aip = PG_GETARG_ACLITEM_P(1);
- PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
+ PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL, DROP_CASCADE));
}
Datum
@@ -649,7 +720,7 @@ aclcontains(PG_FUNCTION_ARGS)
aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i)
{
- if (aip->ai_id == aidat[i].ai_id &&
+ if (aip->ai_grantee == aidat[i].ai_grantee &&
aip->ai_privs == aidat[i].ai_privs)
PG_RETURN_BOOL(true);
}
@@ -842,24 +913,38 @@ convert_table_priv_string(text *priv_type_text)
*/
if (strcasecmp(priv_type, "SELECT") == 0)
return ACL_SELECT;
+ if (strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_SELECT);
if (strcasecmp(priv_type, "INSERT") == 0)
return ACL_INSERT;
+ if (strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_INSERT);
if (strcasecmp(priv_type, "UPDATE") == 0)
return ACL_UPDATE;
+ if (strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_UPDATE);
if (strcasecmp(priv_type, "DELETE") == 0)
return ACL_DELETE;
+ if (strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_DELETE);
if (strcasecmp(priv_type, "RULE") == 0)
return ACL_RULE;
+ if (strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_RULE);
if (strcasecmp(priv_type, "REFERENCES") == 0)
return ACL_REFERENCES;
+ if (strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_REFERENCES);
if (strcasecmp(priv_type, "TRIGGER") == 0)
return ACL_TRIGGER;
+ if (strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_TRIGGER);
elog(ERROR, "has_table_privilege: invalid privilege type %s",
priv_type);
@@ -1057,12 +1142,18 @@ convert_database_priv_string(text *priv_type_text)
*/
if (strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
+ if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_CREATE);
if (strcasecmp(priv_type, "TEMPORARY") == 0)
return ACL_CREATE_TEMP;
+ if (strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
if (strcasecmp(priv_type, "TEMP") == 0)
return ACL_CREATE_TEMP;
+ if (strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP);
elog(ERROR, "has_database_privilege: invalid privilege type %s",
priv_type);
@@ -1262,6 +1353,8 @@ convert_function_priv_string(text *priv_type_text)
*/
if (strcasecmp(priv_type, "EXECUTE") == 0)
return ACL_EXECUTE;
+ if (strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_EXECUTE);
elog(ERROR, "has_function_privilege: invalid privilege type %s",
priv_type);
@@ -1461,6 +1554,8 @@ convert_language_priv_string(text *priv_type_text)
*/
if (strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
+ if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_USAGE);
elog(ERROR, "has_language_privilege: invalid privilege type %s",
priv_type);
@@ -1660,9 +1755,13 @@ convert_schema_priv_string(text *priv_type_text)
*/
if (strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
+ if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_CREATE);
if (strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
+ if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
+ return ACL_GRANT_OPTION_FOR(ACL_USAGE);
elog(ERROR, "has_schema_privilege: invalid privilege type %s",
priv_type);