Represent grant options in the information schema.

This commit is contained in:
Peter Eisentraut 2003-06-11 09:23:55 +00:00
parent 65fb311a97
commit 8a2922dcb2
4 changed files with 139 additions and 38 deletions

View File

@ -4,7 +4,7 @@
* *
* Copyright 2002, PostgreSQL Global Development Group * Copyright 2002, PostgreSQL Global Development Group
* *
* $Id: information_schema.sql,v 1.7 2003/06/05 16:08:47 petere Exp $ * $Id: information_schema.sql,v 1.8 2003/06/11 09:23:55 petere Exp $
*/ */
@ -604,7 +604,7 @@ GRANT SELECT ON referential_constraints TO PUBLIC;
*/ */
CREATE VIEW routine_privileges AS CREATE VIEW routine_privileges AS
SELECT CAST(u_owner.usename AS sql_identifier) AS grantor, SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
CAST(u_grantee.usename AS sql_identifier) AS grantee, CAST(u_grantee.usename AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS specific_catalog, CAST(current_database() AS sql_identifier) AS specific_catalog,
CAST(n.nspname AS sql_identifier) AS specific_schema, CAST(n.nspname AS sql_identifier) AS specific_schema,
@ -613,17 +613,22 @@ CREATE VIEW routine_privileges AS
CAST(n.nspname AS sql_identifier) AS routine_schema, CAST(n.nspname AS sql_identifier) AS routine_schema,
CAST(p.proname AS sql_identifier) AS routine_name, CAST(p.proname AS sql_identifier) AS routine_name,
CAST('EXECUTE' AS character_data) AS privilege_type, CAST('EXECUTE' AS character_data) AS privilege_type,
CAST('NO' AS character_data) AS is_grantable CAST(
CASE WHEN aclcontains(p.proacl,
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
FROM pg_user u_owner, FROM pg_proc p,
pg_user u_grantee,
pg_namespace n, pg_namespace n,
pg_proc p pg_user u_grantor,
(SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee
WHERE u_owner.usesysid = p.proowner WHERE p.pronamespace = n.oid
AND p.pronamespace = n.oid AND aclcontains(p.proacl,
AND has_function_privilege(u_grantee.usename, p.oid, 'EXECUTE') makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', false))
AND (u_owner.usename = current_user OR u_grantee.usename = current_user); AND (u_grantor.usename = current_user
OR u_grantee.usename = current_user
OR u_grantee.usename = 'PUBLIC');
GRANT SELECT ON routine_privileges TO PUBLIC; GRANT SELECT ON routine_privileges TO PUBLIC;
@ -940,27 +945,31 @@ GRANT SELECT ON table_constraints TO PUBLIC;
*/ */
CREATE VIEW table_privileges AS CREATE VIEW table_privileges AS
SELECT CAST(u_owner.usename AS sql_identifier) AS grantor, SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
CAST(u_grantee.usename AS sql_identifier) AS grantee, CAST(u_grantee.usename AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS table_catalog, CAST(current_database() AS sql_identifier) AS table_catalog,
CAST(nc.nspname AS sql_identifier) AS table_schema, CAST(nc.nspname AS sql_identifier) AS table_schema,
CAST(c.relname AS sql_identifier) AS table_name, CAST(c.relname AS sql_identifier) AS table_name,
CAST(pr.type AS character_data) AS privilege_type, CAST(pr.type AS character_data) AS privilege_type,
CAST('NO' AS character_data) AS is_grantable, CAST(
CASE WHEN aclcontains(c.relacl,
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, true))
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
CAST('NO' AS character_data) AS with_hierarchy CAST('NO' AS character_data) AS with_hierarchy
FROM pg_user u_owner, FROM pg_class c,
pg_user u_grantee,
pg_namespace nc, pg_namespace nc,
pg_class c, pg_user u_grantor,
(SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee,
(SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE' (SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type) UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
WHERE u_owner.usesysid = c.relowner WHERE c.relnamespace = nc.oid
AND c.relnamespace = nc.oid AND aclcontains(c.relacl,
AND has_table_privilege(u_grantee.usename, c.oid, pr.type) makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false))
AND (u_grantor.usename = current_user
AND (u_owner.usename = current_user OR u_grantee.usename = current_user); OR u_grantee.usename = current_user
OR u_grantee.usename = 'PUBLIC');
GRANT SELECT ON table_privileges TO PUBLIC; GRANT SELECT ON table_privileges TO PUBLIC;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.87 2003/06/02 19:00:29 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.88 2003/06/11 09:23:55 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -32,12 +32,14 @@
static const char *getid(const char *s, char *n); static const char *getid(const char *s, char *n);
static void putid(char *p, const char *s); static void putid(char *p, const char *s);
static Acl *makeacl(int n); static Acl *allocacl(int n);
static const char *aclparse(const char *s, AclItem *aip); static const char *aclparse(const char *s, AclItem *aip);
static bool aclitemeq(const AclItem *a1, const AclItem *a2); static bool aclitemeq(const AclItem *a1, const AclItem *a2);
static Acl *recursive_revoke(Acl *acl, AclId grantee, static Acl *recursive_revoke(Acl *acl, AclId grantee,
AclMode revoke_privs, DropBehavior behavior); AclMode revoke_privs, DropBehavior behavior);
static AclMode convert_priv_string(text *priv_type_text);
static Oid convert_table_name(text *tablename); static Oid convert_table_name(text *tablename);
static AclMode convert_table_priv_string(text *priv_type_text); static AclMode convert_table_priv_string(text *priv_type_text);
static Oid convert_database_name(text *databasename); static Oid convert_database_name(text *databasename);
@ -265,20 +267,20 @@ aclparse(const char *s, AclItem *aip)
} }
/* /*
* makeacl * allocacl
* Allocates storage for a new Acl with 'n' entries. * Allocates storage for a new Acl with 'n' entries.
* *
* RETURNS: * RETURNS:
* the new Acl * the new Acl
*/ */
static Acl * static Acl *
makeacl(int n) allocacl(int n)
{ {
Acl *new_acl; Acl *new_acl;
Size size; Size size;
if (n < 0) if (n < 0)
elog(ERROR, "makeacl: invalid size: %d", n); elog(ERROR, "allocacl: invalid size: %d", n);
size = ACL_N_SIZE(n); size = ACL_N_SIZE(n);
new_acl = (Acl *) palloc0(size); new_acl = (Acl *) palloc0(size);
new_acl->size = size; new_acl->size = size;
@ -471,7 +473,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
break; break;
} }
acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0) acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
+ (ownerid ? 1 : 0)); + (ownerid ? 1 : 0));
aip = ACL_DAT(acl); aip = ACL_DAT(acl);
@ -513,10 +515,10 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
/* These checks for null input are probably dead code, but... */ /* These checks for null input are probably dead code, but... */
if (!old_acl || ACL_NUM(old_acl) < 1) if (!old_acl || ACL_NUM(old_acl) < 1)
old_acl = makeacl(1); old_acl = allocacl(1);
if (!mod_aip) if (!mod_aip)
{ {
new_acl = makeacl(ACL_NUM(old_acl)); new_acl = allocacl(ACL_NUM(old_acl));
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
return new_acl; return new_acl;
} }
@ -536,7 +538,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
if (aclitemeq(mod_aip, old_aip + dst)) if (aclitemeq(mod_aip, old_aip + dst))
{ {
/* found a match, so modify existing item */ /* found a match, so modify existing item */
new_acl = makeacl(num); new_acl = allocacl(num);
new_aip = ACL_DAT(new_acl); new_aip = ACL_DAT(new_acl);
memcpy(new_acl, old_acl, ACL_SIZE(old_acl)); memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
break; break;
@ -546,7 +548,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
if (dst == num) if (dst == num)
{ {
/* need to append a new item */ /* need to append a new item */
new_acl = makeacl(num + 1); new_acl = allocacl(num + 1);
new_aip = ACL_DAT(new_acl); new_aip = ACL_DAT(new_acl);
memcpy(new_aip, old_aip, num * sizeof(AclItem)); memcpy(new_aip, old_aip, num * sizeof(AclItem));
@ -671,10 +673,10 @@ aclremove(PG_FUNCTION_ARGS)
/* These checks for null input should be dead code, but... */ /* These checks for null input should be dead code, but... */
if (!old_acl || ACL_NUM(old_acl) < 1) if (!old_acl || ACL_NUM(old_acl) < 1)
old_acl = makeacl(1); old_acl = allocacl(1);
if (!mod_aip) if (!mod_aip)
{ {
new_acl = makeacl(ACL_NUM(old_acl)); new_acl = allocacl(ACL_NUM(old_acl));
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
PG_RETURN_ACL_P(new_acl); PG_RETURN_ACL_P(new_acl);
} }
@ -689,13 +691,13 @@ aclremove(PG_FUNCTION_ARGS)
if (dst >= old_num) if (dst >= old_num)
{ {
/* Not found, so return copy of source ACL */ /* Not found, so return copy of source ACL */
new_acl = makeacl(old_num); new_acl = allocacl(old_num);
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
} }
else else
{ {
new_num = old_num - 1; new_num = old_num - 1;
new_acl = makeacl(new_num); new_acl = allocacl(new_num);
new_aip = ACL_DAT(new_acl); new_aip = ACL_DAT(new_acl);
if (dst == 0) if (dst == 0)
{ /* start */ { /* start */
@ -734,13 +736,97 @@ aclcontains(PG_FUNCTION_ARGS)
aidat = ACL_DAT(acl); aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i) for (i = 0; i < num; ++i)
{ {
if (aip->ai_grantee == aidat[i].ai_grantee && if (aip->ai_grantee == aidat[i].ai_grantee
aip->ai_privs == aidat[i].ai_privs) && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
&& aip->ai_grantor == aidat[i].ai_grantor
&& (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip)
&& (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip))
PG_RETURN_BOOL(true); PG_RETURN_BOOL(true);
} }
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
Datum
makeaclitem(PG_FUNCTION_ARGS)
{
int32 u_grantee = PG_GETARG_INT32(0);
int32 g_grantee = PG_GETARG_INT32(1);
int32 grantor = PG_GETARG_INT32(2);
text *privtext = PG_GETARG_TEXT_P(3);
bool goption = PG_GETARG_BOOL(4);
AclItem *aclitem;
AclMode priv;
priv = convert_priv_string(privtext);
aclitem = (AclItem *) palloc(sizeof(*aclitem));
if (u_grantee == 0 && g_grantee == 0)
{
aclitem->ai_grantee = 0;
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
}
else if (u_grantee != 0 && g_grantee != 0)
{
elog(ERROR, "cannot specify both user and group");
}
else if (u_grantee != 0)
{
aclitem->ai_grantee = u_grantee;
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
}
else if (g_grantee != 0)
{
aclitem->ai_grantee = g_grantee;
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
}
aclitem->ai_grantor = grantor;
ACLITEM_SET_PRIVS(*aclitem, priv);
if (goption)
ACLITEM_SET_GOPTIONS(*aclitem, priv);
else
ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
PG_RETURN_ACLITEM_P(aclitem);
}
static AclMode
convert_priv_string(text *priv_type_text)
{
char *priv_type;
priv_type = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(priv_type_text)));
if (strcasecmp(priv_type, "SELECT") == 0)
return ACL_SELECT;
if (strcasecmp(priv_type, "INSERT") == 0)
return ACL_INSERT;
if (strcasecmp(priv_type, "UPDATE") == 0)
return ACL_UPDATE;
if (strcasecmp(priv_type, "DELETE") == 0)
return ACL_DELETE;
if (strcasecmp(priv_type, "RULE") == 0)
return ACL_RULE;
if (strcasecmp(priv_type, "REFERENCES") == 0)
return ACL_REFERENCES;
if (strcasecmp(priv_type, "TRIGGER") == 0)
return ACL_TRIGGER;
if (strcasecmp(priv_type, "EXECUTE") == 0)
return ACL_EXECUTE;
if (strcasecmp(priv_type, "USAGE") == 0)
return ACL_USAGE;
if (strcasecmp(priv_type, "CREATE") == 0)
return ACL_CREATE;
if (strcasecmp(priv_type, "TEMP") == 0)
return ACL_CREATE_TEMP;
if (strcasecmp(priv_type, "TEMPORARY") == 0)
return ACL_CREATE_TEMP;
elog(ERROR, "invalid privilege type %s", priv_type);
return ACL_NO_RIGHTS; /* keep compiler quiet */
}
/* /*
* has_table_privilege variants * has_table_privilege variants

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.302 2003/05/26 00:11:27 tgl Exp $ * $Id: pg_proc.h,v 1.303 2003/06/11 09:23:55 petere Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
@ -1318,6 +1318,8 @@ DATA(insert OID = 1036 ( aclremove PGNSP PGUID 12 f f t f s 2 1034 "1034 10
DESCR("remove ACL item"); DESCR("remove ACL item");
DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ )); DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ ));
DESCR("does ACL contain item?"); DESCR("does ACL contain item?");
DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 f f t f s 5 1033 "23 23 23 25 16" makeaclitem - _null_ ));
DESCR("make ACL item");
DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ )); DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ ));
DESCR("internal function supporting PostQuel-style sets"); DESCR("internal function supporting PostQuel-style sets");
DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ )); DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ ));

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.51 2003/01/23 23:39:07 petere Exp $ * $Id: acl.h,v 1.52 2003/06/11 09:23:55 petere Exp $
* *
* NOTES * NOTES
* For backward-compatibility purposes we have to allow there * For backward-compatibility purposes we have to allow there
@ -70,6 +70,9 @@ typedef struct AclItem
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF)) ((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF))
#define ACLITEM_SET_GOPTIONS(item,goptions) \ #define ACLITEM_SET_GOPTIONS(item,goptions) \
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (((goptions) & 0x7FFF) << 15) | ACLITEM_GET_PRIVS(item)) ((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (((goptions) & 0x7FFF) << 15) | ACLITEM_GET_PRIVS(item))
#define ACLITEM_SET_IDTYPE(item,idtype) \
((item).ai_privs = ((idtype)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ACLITEM_GET_PRIVS(item))
#define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \ #define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \
((item).ai_privs = ((privs) & 0x7FFF) |(((goption) & 0x7FFF) << 15) | ((idtype) << 30)) ((item).ai_privs = ((privs) & 0x7FFF) |(((goption) & 0x7FFF) << 15) | ((idtype) << 30))
@ -188,6 +191,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
extern Datum aclinsert(PG_FUNCTION_ARGS); extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS); extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS);
extern Datum makeaclitem(PG_FUNCTION_ARGS);
/* /*
* prototypes for functions in aclchk.c * prototypes for functions in aclchk.c