Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f016c92

Browse files
committed
Fix some corner cases in ACL manipulation: don't foul up on an empty
ACL array, and force languages to be treated as owned by the bootstrap user ID. (pg_language should have a lanowner column, but until it does this will have to do as a workaround.)
1 parent 1a2be80 commit f016c92

File tree

3 files changed

+86
-71
lines changed

3 files changed

+86
-71
lines changed

src/backend/catalog/aclchk.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.89 2003/10/05 21:49:12 petere Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.90 2003/10/29 22:20:54 tgl Exp $
1212
*
1313
* NOTES
1414
* See acl.h.
@@ -106,7 +106,7 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
106106

107107
idtype = ACL_IDTYPE_UID;
108108

109-
grantee_is_owner = (aclitem.ai_grantee == owner_uid && owner_uid != InvalidOid);
109+
grantee_is_owner = (aclitem.ai_grantee == owner_uid);
110110
}
111111
else if (grantee->groupname)
112112
{
@@ -550,20 +550,23 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
550550

551551
/*
552552
* If there's no ACL, create a default.
553+
*
554+
* Note: for now, languages are treated as owned by the bootstrap
555+
* user. We should add an owner column to pg_language instead.
553556
*/
554557
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
555558
&isNull);
556559
if (isNull)
557560
old_acl = acldefault(ACL_OBJECT_LANGUAGE,
558-
InvalidOid);
561+
BOOTSTRAP_USESYSID);
559562
else
560563
/* get a detoasted copy of the ACL */
561564
old_acl = DatumGetAclPCopy(aclDatum);
562565

563566
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
564567
stmt->grantees, privileges,
565568
stmt->grant_option, stmt->behavior,
566-
InvalidOid);
569+
BOOTSTRAP_USESYSID);
567570

568571
/* finished building new ACL value, now insert it */
569572
MemSet(values, 0, sizeof(values));
@@ -1205,7 +1208,8 @@ pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
12051208
if (isNull)
12061209
{
12071210
/* No ACL, so build default ACL */
1208-
acl = acldefault(ACL_OBJECT_LANGUAGE, InvalidOid);
1211+
/* XXX pg_language should have an owner column, but doesn't */
1212+
acl = acldefault(ACL_OBJECT_LANGUAGE, BOOTSTRAP_USESYSID);
12091213
aclDatum = (Datum) 0;
12101214
}
12111215
else

src/backend/utils/adt/acl.c

Lines changed: 52 additions & 51 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.99 2003/09/25 06:58:03 petere Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.100 2003/10/29 22:20:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -542,26 +542,23 @@ acldefault(GrantObjectType objtype, AclId ownerid)
542542
break;
543543
}
544544

545-
acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
546-
+ (ownerid ? 1 : 0));
545+
acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
547546
aip = ACL_DAT(acl);
548547

549548
if (world_default != ACL_NO_RIGHTS)
550549
{
551-
aip[0].ai_grantee = ACL_ID_WORLD;
552-
aip[0].ai_grantor = ownerid;
553-
ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
550+
aip->ai_grantee = ACL_ID_WORLD;
551+
aip->ai_grantor = ownerid;
552+
ACLITEM_SET_PRIVS_IDTYPE(*aip, world_default, ACL_NO_RIGHTS,
553+
ACL_IDTYPE_WORLD);
554+
aip++;
554555
}
555556

556-
if (ownerid)
557-
{
558-
int index = (world_default != ACL_NO_RIGHTS ? 1 : 0);
559-
560-
aip[index].ai_grantee = ownerid;
561-
aip[index].ai_grantor = ownerid;
562-
/* owner gets default privileges with grant option */
563-
ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID);
564-
}
557+
aip->ai_grantee = ownerid;
558+
aip->ai_grantor = ownerid;
559+
/* owner gets default privileges with grant option */
560+
ACLITEM_SET_PRIVS_IDTYPE(*aip, owner_default, owner_default,
561+
ACL_IDTYPE_UID);
565562

566563
return acl;
567564
}
@@ -574,17 +571,22 @@ acldefault(GrantObjectType objtype, AclId ownerid)
574571
* NB: caller is responsible for having detoasted the input ACL, if needed.
575572
*/
576573
Acl *
577-
aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
574+
aclinsert3(const Acl *old_acl, const AclItem *mod_aip,
575+
unsigned modechg, DropBehavior behavior)
578576
{
579577
Acl *new_acl = NULL;
580578
AclItem *old_aip,
581579
*new_aip = NULL;
580+
AclMode old_privs,
581+
old_goptions,
582+
new_privs,
583+
new_goptions;
582584
int dst,
583585
num;
584586

585587
/* These checks for null input are probably dead code, but... */
586-
if (!old_acl || ACL_NUM(old_acl) < 1)
587-
old_acl = allocacl(1);
588+
if (!old_acl || ACL_NUM(old_acl) < 0)
589+
old_acl = allocacl(0);
588590
if (!mod_aip)
589591
{
590592
new_acl = allocacl(ACL_NUM(old_acl));
@@ -629,16 +631,23 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
629631
num++; /* set num to the size of new_acl */
630632
}
631633

632-
/* apply the permissions mod */
634+
old_privs = ACLITEM_GET_PRIVS(new_aip[dst]);
635+
old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
636+
637+
/* apply the specified permissions change */
633638
switch (modechg)
634639
{
635640
case ACL_MODECHG_ADD:
636-
ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
637-
ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
641+
ACLITEM_SET_PRIVS(new_aip[dst],
642+
old_privs | ACLITEM_GET_PRIVS(*mod_aip));
643+
ACLITEM_SET_GOPTIONS(new_aip[dst],
644+
old_goptions | ACLITEM_GET_GOPTIONS(*mod_aip));
638645
break;
639646
case ACL_MODECHG_DEL:
640-
ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
641-
ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
647+
ACLITEM_SET_PRIVS(new_aip[dst],
648+
old_privs & ~ACLITEM_GET_PRIVS(*mod_aip));
649+
ACLITEM_SET_GOPTIONS(new_aip[dst],
650+
old_goptions & ~ACLITEM_GET_GOPTIONS(*mod_aip));
642651
break;
643652
case ACL_MODECHG_EQL:
644653
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
@@ -648,10 +657,13 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
648657
break;
649658
}
650659

660+
new_privs = ACLITEM_GET_PRIVS(new_aip[dst]);
661+
new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
662+
651663
/*
652664
* If the adjusted entry has no permissions, delete it from the list.
653665
*/
654-
if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
666+
if (new_privs == ACL_NO_RIGHTS && new_goptions == ACL_NO_RIGHTS)
655667
{
656668
memmove(new_aip + dst,
657669
new_aip + dst + 1,
@@ -661,12 +673,14 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
661673
}
662674

663675
/*
664-
* Remove abandoned privileges (cascading revoke)
676+
* Remove abandoned privileges (cascading revoke). Currently we
677+
* can only handle this when the grantee is a user.
665678
*/
666-
if (modechg != ACL_MODECHG_ADD
667-
&& ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
668-
&& ACLITEM_GET_GOPTIONS(*mod_aip))
669-
new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
679+
if ((old_goptions & ~new_goptions) != 0
680+
&& ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID)
681+
new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
682+
(old_goptions & ~new_goptions),
683+
behavior);
670684

671685
return new_acl;
672686
}
@@ -744,8 +758,8 @@ aclremove(PG_FUNCTION_ARGS)
744758
new_num;
745759

746760
/* These checks for null input should be dead code, but... */
747-
if (!old_acl || ACL_NUM(old_acl) < 1)
748-
old_acl = allocacl(1);
761+
if (!old_acl || ACL_NUM(old_acl) < 0)
762+
old_acl = allocacl(0);
749763
if (!mod_aip)
750764
{
751765
new_acl = allocacl(ACL_NUM(old_acl));
@@ -773,27 +787,14 @@ aclremove(PG_FUNCTION_ARGS)
773787
new_num = old_num - 1;
774788
new_acl = allocacl(new_num);
775789
new_aip = ACL_DAT(new_acl);
776-
if (dst == 0)
777-
{ /* start */
778-
ereport(ERROR,
779-
(errcode(ERRCODE_DATA_EXCEPTION),
780-
errmsg("aclitem for public may not be removed")));
781-
}
782-
else if (dst == old_num - 1)
783-
{ /* end */
784-
memcpy((char *) new_aip,
785-
(char *) old_aip,
786-
new_num * sizeof(AclItem));
787-
}
788-
else
789-
{ /* middle */
790+
if (dst > 0)
790791
memcpy((char *) new_aip,
791792
(char *) old_aip,
792793
dst * sizeof(AclItem));
794+
if (dst < new_num)
793795
memcpy((char *) (new_aip + dst),
794796
(char *) (old_aip + dst + 1),
795797
(new_num - dst) * sizeof(AclItem));
796-
}
797798
}
798799

799800
PG_RETURN_ACL_P(new_acl);
@@ -839,7 +840,7 @@ makeaclitem(PG_FUNCTION_ARGS)
839840

840841
if (u_grantee == 0 && g_grantee == 0)
841842
{
842-
aclitem ->ai_grantee = 0;
843+
aclitem->ai_grantee = ACL_ID_WORLD;
843844

844845
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
845846
}
@@ -851,18 +852,18 @@ makeaclitem(PG_FUNCTION_ARGS)
851852
}
852853
else if (u_grantee != 0)
853854
{
854-
aclitem ->ai_grantee = u_grantee;
855+
aclitem->ai_grantee = u_grantee;
855856

856857
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
857858
}
858-
else if (g_grantee != 0)
859+
else /* (g_grantee != 0) */
859860
{
860-
aclitem ->ai_grantee = g_grantee;
861+
aclitem->ai_grantee = g_grantee;
861862

862863
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
863864
}
864865

865-
aclitem ->ai_grantor = grantor;
866+
aclitem->ai_grantor = grantor;
866867

867868
ACLITEM_SET_PRIVS(*aclitem, priv);
868869
if (goption)

src/include/utils/acl.h

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: acl.h,v 1.62 2003/08/17 19:58:06 tgl Exp $
10+
* $Id: acl.h,v 1.63 2003/10/29 22:20:54 tgl Exp $
1111
*
1212
* NOTES
13-
* For backward-compatibility purposes we have to allow there
14-
* to be a null ACL in a pg_class tuple. This will be defined as
15-
* meaning "default protection" (i.e., whatever acldefault() returns).
13+
* An ACL array is simply an array of AclItems, representing the union
14+
* of the privileges represented by the individual items. A zero-length
15+
* array represents "no privileges". There are no assumptions about the
16+
* ordering of the items, but we do expect that there are no two entries
17+
* in the array with the same grantor and grantee.
1618
*
17-
* The AclItems in an ACL array are currently kept in sorted order.
18-
* Things will break hard if you change that without changing the
19-
* code wherever this is included.
19+
* For backward-compatibility purposes we have to allow null ACL entries
20+
* in system catalogs. A null ACL will be treated as meaning "default
21+
* protection" (i.e., whatever acldefault() returns).
2022
*-------------------------------------------------------------------------
2123
*/
2224
#ifndef ACL_H
@@ -45,13 +47,16 @@ typedef uint32 AclMode;
4547
/*
4648
* AclItem
4749
*
50+
* The IDTYPE included in ai_privs identifies the type of the grantee ID.
51+
* The grantor ID currently must always be a user, never a group. (FIXME)
52+
*
4853
* Note: must be same size on all platforms, because the size is hardcoded
4954
* in the pg_type.h entry for aclitem.
5055
*/
5156
typedef struct AclItem
5257
{
53-
AclId ai_grantee; /* ID that this item applies to */
54-
AclId ai_grantor;
58+
AclId ai_grantee; /* ID that this item grants privs to */
59+
AclId ai_grantor; /* grantor of privs (always a user id) */
5560
AclMode ai_privs; /* AclIdType plus privilege bits */
5661
} AclItem;
5762

@@ -61,20 +66,25 @@ typedef struct AclItem
6166
* and the lower 15 bits are the actual privileges.
6267
*/
6368
#define ACLITEM_GET_PRIVS(item) ((item).ai_privs & 0x7FFF)
64-
#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 15) & 0x7FFF)
69+
#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 15) & 0x7FFF)
6570
#define ACLITEM_GET_IDTYPE(item) ((item).ai_privs >> 30)
6671

67-
#define ACL_GRANT_OPTION_FOR(privs) (((privs) & 0x7FFF) << 15)
72+
#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0x7FFF) << 15)
6873

6974
#define ACLITEM_SET_PRIVS(item,privs) \
70-
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF))
75+
((item).ai_privs = ((item).ai_privs & ~((AclMode) 0x7FFF)) | \
76+
((AclMode) (privs) & 0x7FFF))
7177
#define ACLITEM_SET_GOPTIONS(item,goptions) \
72-
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (((goptions) & 0x7FFF) << 15) | ACLITEM_GET_PRIVS(item))
78+
((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0x7FFF) << 15)) | \
79+
(((AclMode) (goptions) & 0x7FFF) << 15))
7380
#define ACLITEM_SET_IDTYPE(item,idtype) \
74-
((item).ai_privs = ((idtype)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ACLITEM_GET_PRIVS(item))
81+
((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0x03) << 30)) | \
82+
(((AclMode) (idtype) & 0x03) << 30))
7583

7684
#define ACLITEM_SET_PRIVS_IDTYPE(item,privs,goption,idtype) \
77-
((item).ai_privs = ((privs) & 0x7FFF) |(((goption) & 0x7FFF) << 15) | ((idtype) << 30))
85+
((item).ai_privs = ((AclMode) (privs) & 0x7FFF) | \
86+
(((AclMode) (goption) & 0x7FFF) << 15) | \
87+
((AclMode) (idtype) << 30))
7888

7989

8090
/*

0 commit comments

Comments
 (0)