mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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.)
This commit is contained in:
parent
1a2be80ee7
commit
f016c92ea4
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.89 2003/10/05 21:49:12 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.90 2003/10/29 22:20:54 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* See acl.h.
|
* See acl.h.
|
||||||
@ -106,7 +106,7 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
|||||||
|
|
||||||
idtype = ACL_IDTYPE_UID;
|
idtype = ACL_IDTYPE_UID;
|
||||||
|
|
||||||
grantee_is_owner = (aclitem.ai_grantee == owner_uid && owner_uid != InvalidOid);
|
grantee_is_owner = (aclitem.ai_grantee == owner_uid);
|
||||||
}
|
}
|
||||||
else if (grantee->groupname)
|
else if (grantee->groupname)
|
||||||
{
|
{
|
||||||
@ -550,12 +550,15 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no ACL, create a default.
|
* If there's no ACL, create a default.
|
||||||
|
*
|
||||||
|
* Note: for now, languages are treated as owned by the bootstrap
|
||||||
|
* user. We should add an owner column to pg_language instead.
|
||||||
*/
|
*/
|
||||||
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
|
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
old_acl = acldefault(ACL_OBJECT_LANGUAGE,
|
old_acl = acldefault(ACL_OBJECT_LANGUAGE,
|
||||||
InvalidOid);
|
BOOTSTRAP_USESYSID);
|
||||||
else
|
else
|
||||||
/* get a detoasted copy of the ACL */
|
/* get a detoasted copy of the ACL */
|
||||||
old_acl = DatumGetAclPCopy(aclDatum);
|
old_acl = DatumGetAclPCopy(aclDatum);
|
||||||
@ -563,7 +566,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
|||||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||||
stmt->grantees, privileges,
|
stmt->grantees, privileges,
|
||||||
stmt->grant_option, stmt->behavior,
|
stmt->grant_option, stmt->behavior,
|
||||||
InvalidOid);
|
BOOTSTRAP_USESYSID);
|
||||||
|
|
||||||
/* finished building new ACL value, now insert it */
|
/* finished building new ACL value, now insert it */
|
||||||
MemSet(values, 0, sizeof(values));
|
MemSet(values, 0, sizeof(values));
|
||||||
@ -1205,7 +1208,8 @@ pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
|
|||||||
if (isNull)
|
if (isNull)
|
||||||
{
|
{
|
||||||
/* No ACL, so build default ACL */
|
/* No ACL, so build default ACL */
|
||||||
acl = acldefault(ACL_OBJECT_LANGUAGE, InvalidOid);
|
/* XXX pg_language should have an owner column, but doesn't */
|
||||||
|
acl = acldefault(ACL_OBJECT_LANGUAGE, BOOTSTRAP_USESYSID);
|
||||||
aclDatum = (Datum) 0;
|
aclDatum = (Datum) 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.99 2003/09/25 06:58:03 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.100 2003/10/29 22:20:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -542,26 +542,23 @@ acldefault(GrantObjectType objtype, AclId ownerid)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0)
|
acl = allocacl((world_default != ACL_NO_RIGHTS) ? 2 : 1);
|
||||||
+ (ownerid ? 1 : 0));
|
|
||||||
aip = ACL_DAT(acl);
|
aip = ACL_DAT(acl);
|
||||||
|
|
||||||
if (world_default != ACL_NO_RIGHTS)
|
if (world_default != ACL_NO_RIGHTS)
|
||||||
{
|
{
|
||||||
aip[0].ai_grantee = ACL_ID_WORLD;
|
aip->ai_grantee = ACL_ID_WORLD;
|
||||||
aip[0].ai_grantor = ownerid;
|
aip->ai_grantor = ownerid;
|
||||||
ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD);
|
ACLITEM_SET_PRIVS_IDTYPE(*aip, world_default, ACL_NO_RIGHTS,
|
||||||
|
ACL_IDTYPE_WORLD);
|
||||||
|
aip++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ownerid)
|
aip->ai_grantee = ownerid;
|
||||||
{
|
aip->ai_grantor = ownerid;
|
||||||
int index = (world_default != ACL_NO_RIGHTS ? 1 : 0);
|
/* owner gets default privileges with grant option */
|
||||||
|
ACLITEM_SET_PRIVS_IDTYPE(*aip, owner_default, owner_default,
|
||||||
aip[index].ai_grantee = ownerid;
|
ACL_IDTYPE_UID);
|
||||||
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;
|
return acl;
|
||||||
}
|
}
|
||||||
@ -574,17 +571,22 @@ acldefault(GrantObjectType objtype, AclId ownerid)
|
|||||||
* NB: caller is responsible for having detoasted the input ACL, if needed.
|
* NB: caller is responsible for having detoasted the input ACL, if needed.
|
||||||
*/
|
*/
|
||||||
Acl *
|
Acl *
|
||||||
aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior)
|
aclinsert3(const Acl *old_acl, const AclItem *mod_aip,
|
||||||
|
unsigned modechg, DropBehavior behavior)
|
||||||
{
|
{
|
||||||
Acl *new_acl = NULL;
|
Acl *new_acl = NULL;
|
||||||
AclItem *old_aip,
|
AclItem *old_aip,
|
||||||
*new_aip = NULL;
|
*new_aip = NULL;
|
||||||
|
AclMode old_privs,
|
||||||
|
old_goptions,
|
||||||
|
new_privs,
|
||||||
|
new_goptions;
|
||||||
int dst,
|
int dst,
|
||||||
num;
|
num;
|
||||||
|
|
||||||
/* 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) < 0)
|
||||||
old_acl = allocacl(1);
|
old_acl = allocacl(0);
|
||||||
if (!mod_aip)
|
if (!mod_aip)
|
||||||
{
|
{
|
||||||
new_acl = allocacl(ACL_NUM(old_acl));
|
new_acl = allocacl(ACL_NUM(old_acl));
|
||||||
@ -629,16 +631,23 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
|
|||||||
num++; /* set num to the size of new_acl */
|
num++; /* set num to the size of new_acl */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* apply the permissions mod */
|
old_privs = ACLITEM_GET_PRIVS(new_aip[dst]);
|
||||||
|
old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
|
||||||
|
|
||||||
|
/* apply the specified permissions change */
|
||||||
switch (modechg)
|
switch (modechg)
|
||||||
{
|
{
|
||||||
case ACL_MODECHG_ADD:
|
case ACL_MODECHG_ADD:
|
||||||
ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip));
|
ACLITEM_SET_PRIVS(new_aip[dst],
|
||||||
ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip));
|
old_privs | ACLITEM_GET_PRIVS(*mod_aip));
|
||||||
|
ACLITEM_SET_GOPTIONS(new_aip[dst],
|
||||||
|
old_goptions | ACLITEM_GET_GOPTIONS(*mod_aip));
|
||||||
break;
|
break;
|
||||||
case ACL_MODECHG_DEL:
|
case ACL_MODECHG_DEL:
|
||||||
ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip));
|
ACLITEM_SET_PRIVS(new_aip[dst],
|
||||||
ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip));
|
old_privs & ~ACLITEM_GET_PRIVS(*mod_aip));
|
||||||
|
ACLITEM_SET_GOPTIONS(new_aip[dst],
|
||||||
|
old_goptions & ~ACLITEM_GET_GOPTIONS(*mod_aip));
|
||||||
break;
|
break;
|
||||||
case ACL_MODECHG_EQL:
|
case ACL_MODECHG_EQL:
|
||||||
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
|
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
|
||||||
@ -648,10 +657,13 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_privs = ACLITEM_GET_PRIVS(new_aip[dst]);
|
||||||
|
new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the adjusted entry has no permissions, delete it from the list.
|
* If the adjusted entry has no permissions, delete it from the list.
|
||||||
*/
|
*/
|
||||||
if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS)
|
if (new_privs == ACL_NO_RIGHTS && new_goptions == ACL_NO_RIGHTS)
|
||||||
{
|
{
|
||||||
memmove(new_aip + dst,
|
memmove(new_aip + dst,
|
||||||
new_aip + dst + 1,
|
new_aip + dst + 1,
|
||||||
@ -661,12 +673,14 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBeh
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove abandoned privileges (cascading revoke)
|
* Remove abandoned privileges (cascading revoke). Currently we
|
||||||
|
* can only handle this when the grantee is a user.
|
||||||
*/
|
*/
|
||||||
if (modechg != ACL_MODECHG_ADD
|
if ((old_goptions & ~new_goptions) != 0
|
||||||
&& ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID
|
&& ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID)
|
||||||
&& ACLITEM_GET_GOPTIONS(*mod_aip))
|
new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
|
||||||
new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior);
|
(old_goptions & ~new_goptions),
|
||||||
|
behavior);
|
||||||
|
|
||||||
return new_acl;
|
return new_acl;
|
||||||
}
|
}
|
||||||
@ -744,8 +758,8 @@ aclremove(PG_FUNCTION_ARGS)
|
|||||||
new_num;
|
new_num;
|
||||||
|
|
||||||
/* 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) < 0)
|
||||||
old_acl = allocacl(1);
|
old_acl = allocacl(0);
|
||||||
if (!mod_aip)
|
if (!mod_aip)
|
||||||
{
|
{
|
||||||
new_acl = allocacl(ACL_NUM(old_acl));
|
new_acl = allocacl(ACL_NUM(old_acl));
|
||||||
@ -773,27 +787,14 @@ aclremove(PG_FUNCTION_ARGS)
|
|||||||
new_num = old_num - 1;
|
new_num = old_num - 1;
|
||||||
new_acl = allocacl(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 */
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
|
||||||
errmsg("aclitem for public may not be removed")));
|
|
||||||
}
|
|
||||||
else if (dst == old_num - 1)
|
|
||||||
{ /* end */
|
|
||||||
memcpy((char *) new_aip,
|
|
||||||
(char *) old_aip,
|
|
||||||
new_num * sizeof(AclItem));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* middle */
|
|
||||||
memcpy((char *) new_aip,
|
memcpy((char *) new_aip,
|
||||||
(char *) old_aip,
|
(char *) old_aip,
|
||||||
dst * sizeof(AclItem));
|
dst * sizeof(AclItem));
|
||||||
|
if (dst < new_num)
|
||||||
memcpy((char *) (new_aip + dst),
|
memcpy((char *) (new_aip + dst),
|
||||||
(char *) (old_aip + dst + 1),
|
(char *) (old_aip + dst + 1),
|
||||||
(new_num - dst) * sizeof(AclItem));
|
(new_num - dst) * sizeof(AclItem));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_RETURN_ACL_P(new_acl);
|
PG_RETURN_ACL_P(new_acl);
|
||||||
@ -839,7 +840,7 @@ makeaclitem(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
if (u_grantee == 0 && g_grantee == 0)
|
if (u_grantee == 0 && g_grantee == 0)
|
||||||
{
|
{
|
||||||
aclitem ->ai_grantee = 0;
|
aclitem->ai_grantee = ACL_ID_WORLD;
|
||||||
|
|
||||||
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
|
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD);
|
||||||
}
|
}
|
||||||
@ -851,18 +852,18 @@ makeaclitem(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else if (u_grantee != 0)
|
else if (u_grantee != 0)
|
||||||
{
|
{
|
||||||
aclitem ->ai_grantee = u_grantee;
|
aclitem->ai_grantee = u_grantee;
|
||||||
|
|
||||||
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
|
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID);
|
||||||
}
|
}
|
||||||
else if (g_grantee != 0)
|
else /* (g_grantee != 0) */
|
||||||
{
|
{
|
||||||
aclitem ->ai_grantee = g_grantee;
|
aclitem->ai_grantee = g_grantee;
|
||||||
|
|
||||||
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
|
ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID);
|
||||||
}
|
}
|
||||||
|
|
||||||
aclitem ->ai_grantor = grantor;
|
aclitem->ai_grantor = grantor;
|
||||||
|
|
||||||
ACLITEM_SET_PRIVS(*aclitem, priv);
|
ACLITEM_SET_PRIVS(*aclitem, priv);
|
||||||
if (goption)
|
if (goption)
|
||||||
|
@ -7,16 +7,18 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, 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.62 2003/08/17 19:58:06 tgl Exp $
|
* $Id: acl.h,v 1.63 2003/10/29 22:20:54 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* For backward-compatibility purposes we have to allow there
|
* An ACL array is simply an array of AclItems, representing the union
|
||||||
* to be a null ACL in a pg_class tuple. This will be defined as
|
* of the privileges represented by the individual items. A zero-length
|
||||||
* meaning "default protection" (i.e., whatever acldefault() returns).
|
* array represents "no privileges". There are no assumptions about the
|
||||||
|
* ordering of the items, but we do expect that there are no two entries
|
||||||
|
* in the array with the same grantor and grantee.
|
||||||
*
|
*
|
||||||
* The AclItems in an ACL array are currently kept in sorted order.
|
* For backward-compatibility purposes we have to allow null ACL entries
|
||||||
* Things will break hard if you change that without changing the
|
* in system catalogs. A null ACL will be treated as meaning "default
|
||||||
* code wherever this is included.
|
* protection" (i.e., whatever acldefault() returns).
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#ifndef ACL_H
|
#ifndef ACL_H
|
||||||
@ -45,13 +47,16 @@ typedef uint32 AclMode;
|
|||||||
/*
|
/*
|
||||||
* AclItem
|
* AclItem
|
||||||
*
|
*
|
||||||
|
* The IDTYPE included in ai_privs identifies the type of the grantee ID.
|
||||||
|
* The grantor ID currently must always be a user, never a group. (FIXME)
|
||||||
|
*
|
||||||
* Note: must be same size on all platforms, because the size is hardcoded
|
* Note: must be same size on all platforms, because the size is hardcoded
|
||||||
* in the pg_type.h entry for aclitem.
|
* in the pg_type.h entry for aclitem.
|
||||||
*/
|
*/
|
||||||
typedef struct AclItem
|
typedef struct AclItem
|
||||||
{
|
{
|
||||||
AclId ai_grantee; /* ID that this item applies to */
|
AclId ai_grantee; /* ID that this item grants privs to */
|
||||||
AclId ai_grantor;
|
AclId ai_grantor; /* grantor of privs (always a user id) */
|
||||||
AclMode ai_privs; /* AclIdType plus privilege bits */
|
AclMode ai_privs; /* AclIdType plus privilege bits */
|
||||||
} AclItem;
|
} AclItem;
|
||||||
|
|
||||||
@ -61,20 +66,25 @@ typedef struct AclItem
|
|||||||
* and the lower 15 bits are the actual privileges.
|
* and the lower 15 bits are the actual privileges.
|
||||||
*/
|
*/
|
||||||
#define ACLITEM_GET_PRIVS(item) ((item).ai_privs & 0x7FFF)
|
#define ACLITEM_GET_PRIVS(item) ((item).ai_privs & 0x7FFF)
|
||||||
#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 15) & 0x7FFF)
|
#define ACLITEM_GET_GOPTIONS(item) (((item).ai_privs >> 15) & 0x7FFF)
|
||||||
#define ACLITEM_GET_IDTYPE(item) ((item).ai_privs >> 30)
|
#define ACLITEM_GET_IDTYPE(item) ((item).ai_privs >> 30)
|
||||||
|
|
||||||
#define ACL_GRANT_OPTION_FOR(privs) (((privs) & 0x7FFF) << 15)
|
#define ACL_GRANT_OPTION_FOR(privs) (((AclMode) (privs) & 0x7FFF) << 15)
|
||||||
|
|
||||||
#define ACLITEM_SET_PRIVS(item,privs) \
|
#define ACLITEM_SET_PRIVS(item,privs) \
|
||||||
((item).ai_privs = (ACLITEM_GET_IDTYPE(item)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ((privs) & 0x7FFF))
|
((item).ai_privs = ((item).ai_privs & ~((AclMode) 0x7FFF)) | \
|
||||||
|
((AclMode) (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 = ((item).ai_privs & ~(((AclMode) 0x7FFF) << 15)) | \
|
||||||
|
(((AclMode) (goptions) & 0x7FFF) << 15))
|
||||||
#define ACLITEM_SET_IDTYPE(item,idtype) \
|
#define ACLITEM_SET_IDTYPE(item,idtype) \
|
||||||
((item).ai_privs = ((idtype)<<30) | (ACLITEM_GET_GOPTIONS(item)<<15) | ACLITEM_GET_PRIVS(item))
|
((item).ai_privs = ((item).ai_privs & ~(((AclMode) 0x03) << 30)) | \
|
||||||
|
(((AclMode) (idtype) & 0x03) << 30))
|
||||||
|
|
||||||
#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 = ((AclMode) (privs) & 0x7FFF) | \
|
||||||
|
(((AclMode) (goption) & 0x7FFF) << 15) | \
|
||||||
|
((AclMode) (idtype) << 30))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user