diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index c1ca85ce8d..224e61f068 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -4,7 +4,7 @@ * * 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 - 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(current_database() AS sql_identifier) AS specific_catalog, 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(p.proname AS sql_identifier) AS routine_name, 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, - pg_user u_grantee, + FROM pg_proc p, 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 - AND p.pronamespace = n.oid - AND has_function_privilege(u_grantee.usename, p.oid, 'EXECUTE') - AND (u_owner.usename = current_user OR u_grantee.usename = current_user); + WHERE p.pronamespace = n.oid + AND aclcontains(p.proacl, + makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', false)) + AND (u_grantor.usename = current_user + OR u_grantee.usename = current_user + OR u_grantee.usename = 'PUBLIC'); GRANT SELECT ON routine_privileges TO PUBLIC; @@ -940,27 +945,31 @@ GRANT SELECT ON table_constraints TO PUBLIC; */ 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(current_database() AS sql_identifier) AS table_catalog, CAST(nc.nspname AS sql_identifier) AS table_schema, CAST(c.relname AS sql_identifier) AS table_name, 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 - FROM pg_user u_owner, - pg_user u_grantee, + FROM pg_class c, 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' UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type) - WHERE u_owner.usesysid = c.relowner - AND c.relnamespace = nc.oid - AND has_table_privilege(u_grantee.usename, c.oid, pr.type) - - AND (u_owner.usename = current_user OR u_grantee.usename = current_user); + WHERE c.relnamespace = nc.oid + AND aclcontains(c.relacl, + makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false)) + AND (u_grantor.usename = current_user + OR u_grantee.usename = current_user + OR u_grantee.usename = 'PUBLIC'); GRANT SELECT ON table_privileges TO PUBLIC; diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 84abec0489..2870b5d0d6 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.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 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 bool aclitemeq(const AclItem *a1, const AclItem *a2); static Acl *recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs, DropBehavior behavior); +static AclMode convert_priv_string(text *priv_type_text); + static Oid convert_table_name(text *tablename); static AclMode convert_table_priv_string(text *priv_type_text); 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. * * RETURNS: * the new Acl */ static Acl * -makeacl(int n) +allocacl(int n) { Acl *new_acl; Size size; if (n < 0) - elog(ERROR, "makeacl: invalid size: %d", n); + elog(ERROR, "allocacl: invalid size: %d", n); size = ACL_N_SIZE(n); new_acl = (Acl *) palloc0(size); new_acl->size = size; @@ -471,7 +473,7 @@ acldefault(GrantObjectType objtype, AclId ownerid) break; } - acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0) + acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0) + (ownerid ? 1 : 0)); 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... */ if (!old_acl || ACL_NUM(old_acl) < 1) - old_acl = makeacl(1); + old_acl = allocacl(1); 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)); 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)) { /* found a match, so modify existing item */ - new_acl = makeacl(num); + new_acl = allocacl(num); new_aip = ACL_DAT(new_acl); memcpy(new_acl, old_acl, ACL_SIZE(old_acl)); break; @@ -546,7 +548,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh if (dst == num) { /* need to append a new item */ - new_acl = makeacl(num + 1); + new_acl = allocacl(num + 1); new_aip = ACL_DAT(new_acl); 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... */ if (!old_acl || ACL_NUM(old_acl) < 1) - old_acl = makeacl(1); + old_acl = allocacl(1); 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)); PG_RETURN_ACL_P(new_acl); } @@ -689,13 +691,13 @@ aclremove(PG_FUNCTION_ARGS) if (dst >= old_num) { /* 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)); } else { new_num = old_num - 1; - new_acl = makeacl(new_num); + new_acl = allocacl(new_num); new_aip = ACL_DAT(new_acl); if (dst == 0) { /* start */ @@ -734,13 +736,97 @@ aclcontains(PG_FUNCTION_ARGS) aidat = ACL_DAT(acl); for (i = 0; i < num; ++i) { - if (aip->ai_grantee == aidat[i].ai_grantee && - aip->ai_privs == aidat[i].ai_privs) + if (aip->ai_grantee == aidat[i].ai_grantee + && 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(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 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 7d6ff86796..d8ce41c6a8 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * 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 * 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"); DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ )); 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_ )); 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_ )); diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 871ed680f5..1a54042e5e 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * 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 * 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)) #define ACLITEM_SET_GOPTIONS(item,goptions) \ ((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) \ ((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 aclremove(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS); +extern Datum makeaclitem(PG_FUNCTION_ARGS); /* * prototypes for functions in aclchk.c