Skip to content

Commit 8a2922d

Browse files
committed
Represent grant options in the information schema.
1 parent 65fb311 commit 8a2922d

File tree

4 files changed

+139
-38
lines changed

4 files changed

+139
-38
lines changed

src/backend/catalog/information_schema.sql

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Copyright 2002, PostgreSQL Global Development Group
66
*
7-
* $Id: information_schema.sql,v 1.7 2003/06/05 16:08:47 petere Exp $
7+
* $Id: information_schema.sql,v 1.8 2003/06/11 09:23:55 petere Exp $
88
*/
99

1010

@@ -604,7 +604,7 @@ GRANT SELECT ON referential_constraints TO PUBLIC;
604604
*/
605605

606606
CREATE VIEW routine_privileges AS
607-
SELECT CAST(u_owner.usename AS sql_identifier) AS grantor,
607+
SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
608608
CAST(u_grantee.usename AS sql_identifier) AS grantee,
609609
CAST(current_database() AS sql_identifier) AS specific_catalog,
610610
CAST(n.nspname AS sql_identifier) AS specific_schema,
@@ -613,17 +613,22 @@ CREATE VIEW routine_privileges AS
613613
CAST(n.nspname AS sql_identifier) AS routine_schema,
614614
CAST(p.proname AS sql_identifier) AS routine_name,
615615
CAST('EXECUTE' AS character_data) AS privilege_type,
616-
CAST('NO' AS character_data) AS is_grantable
616+
CAST(
617+
CASE WHEN aclcontains(p.proacl,
618+
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', true))
619+
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
617620

618-
FROM pg_user u_owner,
619-
pg_user u_grantee,
621+
FROM pg_proc p,
620622
pg_namespace n,
621-
pg_proc p
623+
pg_user u_grantor,
624+
(SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee
622625

623-
WHERE u_owner.usesysid = p.proowner
624-
AND p.pronamespace = n.oid
625-
AND has_function_privilege(u_grantee.usename, p.oid, 'EXECUTE')
626-
AND (u_owner.usename = current_user OR u_grantee.usename = current_user);
626+
WHERE p.pronamespace = n.oid
627+
AND aclcontains(p.proacl,
628+
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', false))
629+
AND (u_grantor.usename = current_user
630+
OR u_grantee.usename = current_user
631+
OR u_grantee.usename = 'PUBLIC');
627632

628633
GRANT SELECT ON routine_privileges TO PUBLIC;
629634

@@ -940,27 +945,31 @@ GRANT SELECT ON table_constraints TO PUBLIC;
940945
*/
941946

942947
CREATE VIEW table_privileges AS
943-
SELECT CAST(u_owner.usename AS sql_identifier) AS grantor,
948+
SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
944949
CAST(u_grantee.usename AS sql_identifier) AS grantee,
945950
CAST(current_database() AS sql_identifier) AS table_catalog,
946951
CAST(nc.nspname AS sql_identifier) AS table_schema,
947952
CAST(c.relname AS sql_identifier) AS table_name,
948953
CAST(pr.type AS character_data) AS privilege_type,
949-
CAST('NO' AS character_data) AS is_grantable,
954+
CAST(
955+
CASE WHEN aclcontains(c.relacl,
956+
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, true))
957+
THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
950958
CAST('NO' AS character_data) AS with_hierarchy
951959

952-
FROM pg_user u_owner,
953-
pg_user u_grantee,
960+
FROM pg_class c,
954961
pg_namespace nc,
955-
pg_class c,
962+
pg_user u_grantor,
963+
(SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee,
956964
(SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
957965
UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
958966

959-
WHERE u_owner.usesysid = c.relowner
960-
AND c.relnamespace = nc.oid
961-
AND has_table_privilege(u_grantee.usename, c.oid, pr.type)
962-
963-
AND (u_owner.usename = current_user OR u_grantee.usename = current_user);
967+
WHERE c.relnamespace = nc.oid
968+
AND aclcontains(c.relacl,
969+
makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false))
970+
AND (u_grantor.usename = current_user
971+
OR u_grantee.usename = current_user
972+
OR u_grantee.usename = 'PUBLIC');
964973

965974
GRANT SELECT ON table_privileges TO PUBLIC;
966975

src/backend/utils/adt/acl.c

Lines changed: 102 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.87 2003/06/02 19:00:29 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.88 2003/06/11 09:23:55 petere Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -32,12 +32,14 @@
3232

3333
static const char *getid(const char *s, char *n);
3434
static void putid(char *p, const char *s);
35-
static Acl *makeacl(int n);
35+
static Acl *allocacl(int n);
3636
static const char *aclparse(const char *s, AclItem *aip);
3737
static bool aclitemeq(const AclItem *a1, const AclItem *a2);
3838
static Acl *recursive_revoke(Acl *acl, AclId grantee,
3939
AclMode revoke_privs, DropBehavior behavior);
4040

41+
static AclMode convert_priv_string(text *priv_type_text);
42+
4143
static Oid convert_table_name(text *tablename);
4244
static AclMode convert_table_priv_string(text *priv_type_text);
4345
static Oid convert_database_name(text *databasename);
@@ -265,20 +267,20 @@ aclparse(const char *s, AclItem *aip)
265267
}
266268

267269
/*
268-
* makeacl
270+
* allocacl
269271
* Allocates storage for a new Acl with 'n' entries.
270272
*
271273
* RETURNS:
272274
* the new Acl
273275
*/
274276
static Acl *
275-
makeacl(int n)
277+
allocacl(int n)
276278
{
277279
Acl *new_acl;
278280
Size size;
279281

280282
if (n < 0)
281-
elog(ERROR, "makeacl: invalid size: %d", n);
283+
elog(ERROR, "allocacl: invalid size: %d", n);
282284
size = ACL_N_SIZE(n);
283285
new_acl = (Acl *) palloc0(size);
284286
new_acl->size = size;
@@ -471,7 +473,7 @@ acldefault(GrantObjectType objtype, AclId ownerid)
471473
break;
472474
}
473475

474-
acl = makeacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
476+
acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
475477
+ (ownerid ? 1 : 0));
476478
aip = ACL_DAT(acl);
477479

@@ -513,10 +515,10 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
513515

514516
/* These checks for null input are probably dead code, but... */
515517
if (!old_acl || ACL_NUM(old_acl) < 1)
516-
old_acl = makeacl(1);
518+
old_acl = allocacl(1);
517519
if (!mod_aip)
518520
{
519-
new_acl = makeacl(ACL_NUM(old_acl));
521+
new_acl = allocacl(ACL_NUM(old_acl));
520522
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
521523
return new_acl;
522524
}
@@ -536,7 +538,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
536538
if (aclitemeq(mod_aip, old_aip + dst))
537539
{
538540
/* found a match, so modify existing item */
539-
new_acl = makeacl(num);
541+
new_acl = allocacl(num);
540542
new_aip = ACL_DAT(new_acl);
541543
memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
542544
break;
@@ -546,7 +548,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
546548
if (dst == num)
547549
{
548550
/* need to append a new item */
549-
new_acl = makeacl(num + 1);
551+
new_acl = allocacl(num + 1);
550552
new_aip = ACL_DAT(new_acl);
551553
memcpy(new_aip, old_aip, num * sizeof(AclItem));
552554

@@ -671,10 +673,10 @@ aclremove(PG_FUNCTION_ARGS)
671673

672674
/* These checks for null input should be dead code, but... */
673675
if (!old_acl || ACL_NUM(old_acl) < 1)
674-
old_acl = makeacl(1);
676+
old_acl = allocacl(1);
675677
if (!mod_aip)
676678
{
677-
new_acl = makeacl(ACL_NUM(old_acl));
679+
new_acl = allocacl(ACL_NUM(old_acl));
678680
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
679681
PG_RETURN_ACL_P(new_acl);
680682
}
@@ -689,13 +691,13 @@ aclremove(PG_FUNCTION_ARGS)
689691
if (dst >= old_num)
690692
{
691693
/* Not found, so return copy of source ACL */
692-
new_acl = makeacl(old_num);
694+
new_acl = allocacl(old_num);
693695
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
694696
}
695697
else
696698
{
697699
new_num = old_num - 1;
698-
new_acl = makeacl(new_num);
700+
new_acl = allocacl(new_num);
699701
new_aip = ACL_DAT(new_acl);
700702
if (dst == 0)
701703
{ /* start */
@@ -734,13 +736,97 @@ aclcontains(PG_FUNCTION_ARGS)
734736
aidat = ACL_DAT(acl);
735737
for (i = 0; i < num; ++i)
736738
{
737-
if (aip->ai_grantee == aidat[i].ai_grantee &&
738-
aip->ai_privs == aidat[i].ai_privs)
739+
if (aip->ai_grantee == aidat[i].ai_grantee
740+
&& ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i])
741+
&& aip->ai_grantor == aidat[i].ai_grantor
742+
&& (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip)
743+
&& (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip))
739744
PG_RETURN_BOOL(true);
740745
}
741746
PG_RETURN_BOOL(false);
742747
}
743748

749+
Datum
750+
makeaclitem(PG_FUNCTION_ARGS)
751+
{
752+
int32 u_grantee = PG_GETARG_INT32(0);
753+
int32 g_grantee = PG_GETARG_INT32(1);
754+
int32 grantor = PG_GETARG_INT32(2);
755+
text *privtext = PG_GETARG_TEXT_P(3);
756+
bool goption = PG_GETARG_BOOL(4);
757+
AclItem *aclitem;
758+
AclMode priv;
759+
760+
priv = convert_priv_string(privtext);
761+
762+
aclitem = (AclItem *) palloc(sizeof(*aclitem));
763+
if (u_grantee == 0 && g_grantee == 0)
764+
{
765+
aclitem->ai_grantee = 0;
766+
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
767+
}
768+
else if (u_grantee != 0 && g_grantee != 0)
769+
{
770+
elog(ERROR, "cannot specify both user and group");
771+
}
772+
else if (u_grantee != 0)
773+
{
774+
aclitem->ai_grantee = u_grantee;
775+
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
776+
}
777+
else if (g_grantee != 0)
778+
{
779+
aclitem->ai_grantee = g_grantee;
780+
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
781+
}
782+
783+
aclitem->ai_grantor = grantor;
784+
ACLITEM_SET_PRIVS(*aclitem, priv);
785+
if (goption)
786+
ACLITEM_SET_GOPTIONS(*aclitem, priv);
787+
else
788+
ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS);
789+
790+
PG_RETURN_ACLITEM_P(aclitem);
791+
}
792+
793+
static AclMode
794+
convert_priv_string(text *priv_type_text)
795+
{
796+
char *priv_type;
797+
798+
priv_type = DatumGetCString(DirectFunctionCall1(textout,
799+
PointerGetDatum(priv_type_text)));
800+
801+
if (strcasecmp(priv_type, "SELECT") == 0)
802+
return ACL_SELECT;
803+
if (strcasecmp(priv_type, "INSERT") == 0)
804+
return ACL_INSERT;
805+
if (strcasecmp(priv_type, "UPDATE") == 0)
806+
return ACL_UPDATE;
807+
if (strcasecmp(priv_type, "DELETE") == 0)
808+
return ACL_DELETE;
809+
if (strcasecmp(priv_type, "RULE") == 0)
810+
return ACL_RULE;
811+
if (strcasecmp(priv_type, "REFERENCES") == 0)
812+
return ACL_REFERENCES;
813+
if (strcasecmp(priv_type, "TRIGGER") == 0)
814+
return ACL_TRIGGER;
815+
if (strcasecmp(priv_type, "EXECUTE") == 0)
816+
return ACL_EXECUTE;
817+
if (strcasecmp(priv_type, "USAGE") == 0)
818+
return ACL_USAGE;
819+
if (strcasecmp(priv_type, "CREATE") == 0)
820+
return ACL_CREATE;
821+
if (strcasecmp(priv_type, "TEMP") == 0)
822+
return ACL_CREATE_TEMP;
823+
if (strcasecmp(priv_type, "TEMPORARY") == 0)
824+
return ACL_CREATE_TEMP;
825+
826+
elog(ERROR, "invalid privilege type %s", priv_type);
827+
return ACL_NO_RIGHTS; /* keep compiler quiet */
828+
}
829+
744830

745831
/*
746832
* has_table_privilege variants

src/include/catalog/pg_proc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: pg_proc.h,v 1.302 2003/05/26 00:11:27 tgl Exp $
10+
* $Id: pg_proc.h,v 1.303 2003/06/11 09:23:55 petere Exp $
1111
*
1212
* NOTES
1313
* 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
13181318
DESCR("remove ACL item");
13191319
DATA(insert OID = 1037 ( aclcontains PGNSP PGUID 12 f f t f s 2 16 "1034 1033" aclcontains - _null_ ));
13201320
DESCR("does ACL contain item?");
1321+
DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 f f t f s 5 1033 "23 23 23 25 16" makeaclitem - _null_ ));
1322+
DESCR("make ACL item");
13211323
DATA(insert OID = 1038 ( seteval PGNSP PGUID 12 f f t t v 1 23 "26" seteval - _null_ ));
13221324
DESCR("internal function supporting PostQuel-style sets");
13231325
DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ ));

src/include/utils/acl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: acl.h,v 1.51 2003/01/23 23:39:07 petere Exp $
10+
* $Id: acl.h,v 1.52 2003/06/11 09:23:55 petere Exp $
1111
*
1212
* NOTES
1313
* For backward-compatibility purposes we have to allow there
@@ -70,6 +70,9 @@ typedef struct AclItem
7070
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF))
7171
#define ACLITEM_SET_GOPTIONS(item,goptions) \
7272
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (((goptions) & 0x7FFF) << 15) | ACLITEM_GET_PRIVS(item))
73+
#define ACLITEM_SET_IDTYPE(item,idtype) \
74+
((item).ai_privs = ((idtype)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ACLITEM_GET_PRIVS(item))
75+
7376
#define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \
7477
((item).ai_privs = ((privs) & 0x7FFF) |(((goption) & 0x7FFF) << 15) | ((idtype) << 30))
7578

@@ -188,6 +191,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
188191
extern Datum aclinsert(PG_FUNCTION_ARGS);
189192
extern Datum aclremove(PG_FUNCTION_ARGS);
190193
extern Datum aclcontains(PG_FUNCTION_ARGS);
194+
extern Datum makeaclitem(PG_FUNCTION_ARGS);
191195

192196
/*
193197
* prototypes for functions in aclchk.c

0 commit comments

Comments
 (0)