Subdivided the building of NTFS ACLs

N2009_11_14_FIXES
jpandre 2008-09-09 15:19:42 +00:00
parent c699b0a0a5
commit 5770560fab
1 changed files with 481 additions and 366 deletions

View File

@ -1275,7 +1275,434 @@ struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first
return (pxdesc);
}
#endif /* POSIXACLS */
struct BUILD_CONTEXT {
BOOL isdir;
BOOL adminowns;
BOOL groupowns;
u16 selfuserperms;
u16 selfgrpperms;
u16 grpperms;
u16 othperms;
u16 mask;
u16 designates;
u16 withmask;
u16 rootspecial;
} ;
static BOOL build_user_denials(ACL *pacl,
const SID *usid, struct MAPPING* const mapping[],
ACE_FLAGS flags, const struct POSIX_ACE *pxace,
struct BUILD_CONTEXT *pset)
{
BIGSID defsid;
ACCESS_ALLOWED_ACE *pdace;
const SID *sid;
int sidsz;
int pos;
int acecnt;
le32 grants;
le32 denials;
u16 perms;
u16 mixperms;
u16 tag;
BOOL rejected;
BOOL rootuser;
BOOL avoidmask;
rejected = FALSE;
tag = pxace->tag;
perms = pxace->perms;
rootuser = FALSE;
pos = le16_to_cpu(pacl->size);
acecnt = le16_to_cpu(pacl->ace_count);
avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X))
&& ((pset->designates && pset->withmask)
|| (!pset->designates && !pset->withmask));
if (tag == POSIX_ACL_USER_OBJ) {
sid = usid;
sidsz = ntfs_sid_size(sid);
grants = OWNER_RIGHTS;
} else {
if (pxace->id) {
sid = NTFS_FIND_USID(mapping[MAPUSERS],
pxace->id, (SID*)&defsid);
grants = WORLD_RIGHTS;
} else {
sid = adminsid;
rootuser = TRUE;
grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK;
}
if (sid) {
sidsz = ntfs_sid_size(sid);
/*
* Insert denial of complement of mask for
* each designated user (except root)
* WRITE_OWNER is inserted so that
* the mask can be identified
*/
if (!avoidmask && !rootuser) {
denials = WRITE_OWNER;
pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
if (pset->isdir) {
if (!(pset->mask & POSIX_PERM_X))
denials |= DIR_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= DIR_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= DIR_READ;
} else {
if (!(pset->mask & POSIX_PERM_X))
denials |= FILE_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= FILE_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= FILE_READ;
}
if (rootuser)
grants &= ~ROOT_OWNER_UNMARK;
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
} else
rejected = TRUE;
}
if (!rejected) {
if (pset->isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
/* a possible ACE to deny owner what he/she would */
/* induely get from administrator, group or world */
/* unless owner is administrator or group */
denials = const_cpu_to_le32(0);
pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
if (!pset->adminowns && !rootuser) {
if (!pset->groupowns) {
mixperms = pset->grpperms | pset->othperms;
if (tag == POSIX_ACL_USER_OBJ)
mixperms |= pset->selfuserperms;
if (pset->isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
} else {
mixperms = ~pset->grpperms & pset->othperms;
if (tag == POSIX_ACL_USER_OBJ)
mixperms |= pset->selfuserperms;
if (pset->isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
}
denials &= ~grants;
if (denials) {
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
}
pacl->size = cpu_to_le16(pos);
pacl->ace_count = cpu_to_le16(acecnt);
return (!rejected);
}
static BOOL build_user_grants(ACL *pacl,
const SID *usid, struct MAPPING* const mapping[],
ACE_FLAGS flags, const struct POSIX_ACE *pxace,
struct BUILD_CONTEXT *pset)
{
BIGSID defsid;
ACCESS_ALLOWED_ACE *pgace;
const SID *sid;
int sidsz;
int pos;
int acecnt;
le32 grants;
u16 perms;
u16 tag;
BOOL rejected;
BOOL rootuser;
rejected = FALSE;
tag = pxace->tag;
perms = pxace->perms;
rootuser = FALSE;
pos = le16_to_cpu(pacl->size);
acecnt = le16_to_cpu(pacl->ace_count);
if (tag == POSIX_ACL_USER_OBJ) {
sid = usid;
sidsz = ntfs_sid_size(sid);
grants = OWNER_RIGHTS;
} else {
if (pxace->id) {
sid = NTFS_FIND_USID(mapping[MAPUSERS],
pxace->id, (SID*)&defsid);
if (sid)
sidsz = ntfs_sid_size(sid);
else
rejected = TRUE;
grants = WORLD_RIGHTS;
} else {
sid = adminsid;
sidsz = ntfs_sid_size(sid);
rootuser = TRUE;
grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK;
}
}
if (!rejected) {
if (pset->isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
if (rootuser)
grants &= ~ROOT_OWNER_UNMARK;
pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
pgace->type = ACCESS_ALLOWED_ACE_TYPE;
pgace->size = cpu_to_le16(sidsz + 8);
pgace->flags = flags;
pgace->mask = grants;
memcpy((char*)&pgace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt = le16_to_cpu(pacl->ace_count) + 1;
pacl->ace_count = cpu_to_le16(acecnt);
pacl->size = cpu_to_le16(pos);
}
return (!rejected);
}
/* a grant ACE for group */
/* unless group-obj has the same rights as world */
/* but present if group is owner or owner is administrator */
/* this ACE will be inserted after denials for group */
static BOOL build_group_denials_grant(ACL *pacl,
const SID *gsid, struct MAPPING* const mapping[],
ACE_FLAGS flags, const struct POSIX_ACE *pxace,
struct BUILD_CONTEXT *pset)
{
BIGSID defsid;
ACCESS_ALLOWED_ACE *pdace;
ACCESS_ALLOWED_ACE *pgace;
const SID *sid;
int sidsz;
int pos;
int acecnt;
le32 grants;
le32 denials;
u16 perms;
u16 mixperms;
u16 tag;
BOOL avoidmask;
BOOL rootgroup;
BOOL rejected;
rejected = FALSE;
tag = pxace->tag;
perms = pxace->perms;
pos = le16_to_cpu(pacl->size);
acecnt = le16_to_cpu(pacl->ace_count);
rootgroup = FALSE;
avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X))
&& ((pset->designates && pset->withmask)
|| (!pset->designates && !pset->withmask));
if (tag == POSIX_ACL_GROUP_OBJ)
sid = gsid;
else
if (pxace->id)
sid = NTFS_FIND_GSID(mapping[MAPGROUPS],
pxace->id, (SID*)&defsid);
else {
sid = adminsid;
rootgroup = TRUE;
}
if (sid) {
sidsz = ntfs_sid_size(sid);
/*
* Insert denial of complement of mask for
* each group
* WRITE_OWNER is inserted so that
* the mask can be identified
* Note : this mask may lead on Windows to
* deny rights to administrators belonging
* to some user group
*/
if ((!avoidmask && !rootgroup)
|| (pset->rootspecial
&& (tag == POSIX_ACL_GROUP_OBJ))) {
denials = WRITE_OWNER;
pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
if (pset->isdir) {
if (!(pset->mask & POSIX_PERM_X))
denials |= DIR_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= DIR_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= DIR_READ;
} else {
if (!(pset->mask & POSIX_PERM_X))
denials |= FILE_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= FILE_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= FILE_READ;
}
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
} else
rejected = TRUE;
if (!rejected
&& (pset->adminowns
|| pset->groupowns
|| avoidmask
|| rootgroup
|| (perms != pset->othperms))) {
grants = WORLD_RIGHTS;
if (rootgroup)
grants &= ~ROOT_GROUP_UNMARK;
if (pset->isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
/* a possible ACE to deny group what it would get from world */
/* or administrator, unless owner is administrator or group */
denials = const_cpu_to_le32(0);
pdace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
if (!pset->adminowns
&& !pset->groupowns
&& !rootgroup) {
mixperms = pset->othperms;
if (tag == POSIX_ACL_GROUP_OBJ)
mixperms |= pset->selfgrpperms;
if (pset->isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
denials &= ~(grants | OWNER_RIGHTS);
if (denials) {
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
/* now insert grants to group if more than world */
if (pset->adminowns
|| pset->groupowns
|| (avoidmask && (pset->designates || pset->withmask))
|| (perms & ~pset->othperms)
|| (pset->rootspecial
&& (tag == POSIX_ACL_GROUP_OBJ))
|| (tag == POSIX_ACL_GROUP)) {
if (rootgroup)
grants &= ~ROOT_GROUP_UNMARK;
pgace = (ACCESS_DENIED_ACE*)&((char*)pacl)[pos];
pgace->type = ACCESS_ALLOWED_ACE_TYPE;
pgace->flags = flags;
pgace->size = cpu_to_le16(sidsz + 8);
pgace->mask = grants;
memcpy((char*)&pgace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
pacl->size = cpu_to_le16(pos);
pacl->ace_count = cpu_to_le16(acecnt);
return (!rejected);
}
/*
* Build an ACL composed of several ACE's
@ -1360,48 +1787,29 @@ struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first
* an extra null ACE is inserted to hold these flags, using
* the same conventions as cygwin.
*
* Limitations :
* - root cannot be a designated user or group. Full rights
* are aways granted to root
*/
#if POSIXACLS
static int buildacls_posix(struct MAPPING *mapping[],
static int buildacls_posix(struct MAPPING* mapping[],
char *secattr, int offs, struct POSIX_SECURITY *pxdesc,
int isdir, const SID *usid, const SID *gsid)
{
struct {
u16 selfuserperms;
u16 selfgrpperms;
u16 grpperms;
u16 othperms;
u16 mask;
u16 designates;
u16 withmask;
u16 rootspecial;
} aceset[2], *pset;
struct BUILD_CONTEXT aceset[2], *pset;
BOOL adminowns;
BOOL groupowns;
BOOL avoidmask;
BOOL rootuser;
BOOL rootgroup;
ACL *pacl;
ACCESS_ALLOWED_ACE *pgace;
ACCESS_ALLOWED_ACE *pdace;
struct POSIX_ACE *pxace;
BOOL cantmap;
const struct POSIX_ACE *pxace;
BOOL ok;
mode_t mode;
u16 tag;
u16 perms;
u16 mixperms;
ACE_FLAGS flags;
int pos;
int i;
int k;
BIGSID defsid;
const SID *sid;
int sidsz;
int acecnt;
int usidsz;
int gsidsz;
@ -1410,7 +1818,6 @@ static int buildacls_posix(struct MAPPING *mapping[],
int ssidsz;
int nsidsz;
le32 grants;
le32 denials;
usidsz = ntfs_sid_size(usid);
gsidsz = ntfs_sid_size(gsid);
@ -1423,17 +1830,15 @@ static int buildacls_posix(struct MAPPING *mapping[],
|| ntfs_same_sid(gsid, adminsid);
groupowns = !adminowns && ntfs_same_sid(usid, gsid);
cantmap = FALSE;
ok = TRUE;
/* ACL header */
pacl = (ACL*)&secattr[offs];
pacl->revision = ACL_REVISION;
pacl->alignment1 = 0;
pacl->size = cpu_to_le16(sizeof(ACL) + usidsz + 8);
pacl->ace_count = const_cpu_to_le16(1);
pacl->ace_count = const_cpu_to_le16(0);
pacl->alignment2 = const_cpu_to_le16(0);
pos = sizeof(ACL);
acecnt = 0;
/*
* Determine what is allowed to some group or world
@ -1453,6 +1858,9 @@ static int buildacls_posix(struct MAPPING *mapping[],
pset->designates = 0;
pset->withmask = 0;
pset->rootspecial = 0;
pset->adminowns = adminowns;
pset->groupowns = groupowns;
pset->isdir = isdir;
}
for (i=pxdesc->acccnt+pxdesc->defcnt-1; i>=0; i--) {
@ -1504,8 +1912,14 @@ if (pxdesc->defcnt && (pxdesc->firstdef != pxdesc->acccnt)) {
ntfs_log_error("** error : access and default not consecutive\n");
return (0);
}
/*
* First insert all denials for owner and each
* designated user (with mask if needed)
*/
for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && !cantmap; i++) {
pacl->ace_count = const_cpu_to_le16(0);
pacl->size = const_cpu_to_le16(sizeof(ACL));
for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) {
if (i >= pxdesc->acccnt) {
flags = INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
@ -1522,144 +1936,15 @@ return (0);
}
tag = pxace->tag;
perms = pxace->perms;
avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X))
&& ((pset->designates && pset->withmask)
|| (!pset->designates && !pset->withmask));
switch (tag) {
/* insert denial ACEs for each owner or allowed user */
case POSIX_ACL_USER :
case POSIX_ACL_USER_OBJ :
rootuser = FALSE;
if (tag == POSIX_ACL_USER_OBJ) {
sid = usid;
sidsz = usidsz;
grants = OWNER_RIGHTS;
} else {
if (pxace->id) {
sid = NTFS_FIND_USID(mapping[MAPUSERS],
pxace->id, (SID*)&defsid);
grants = WORLD_RIGHTS;
} else {
sid = adminsid;
rootuser = TRUE;
grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK;
}
if (sid) {
sidsz = ntfs_sid_size(sid);
/*
* Insert denial of complement of mask for
* each designated user (except root)
* WRITE_OWNER is inserted so that
* the mask can be identified
*/
if (!avoidmask && !rootuser) {
denials = WRITE_OWNER;
pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos];
if (isdir) {
if (!(pset->mask & POSIX_PERM_X))
denials |= DIR_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= DIR_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= DIR_READ;
} else {
if (!(pset->mask & POSIX_PERM_X))
denials |= FILE_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= FILE_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= FILE_READ;
}
if (rootuser)
grants &= ~ROOT_OWNER_UNMARK;
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
} else
cantmap = TRUE;
}
if (!cantmap) {
if (isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
/* a possible ACE to deny owner what he/she would */
/* induely get from administrator, group or world */
/* unless owner is administrator or group */
denials = const_cpu_to_le32(0);
pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos];
if (!adminowns && !rootuser) {
if (!groupowns) {
mixperms = pset->grpperms | pset->othperms;
if (tag == POSIX_ACL_USER_OBJ)
mixperms |= pset->selfuserperms;
if (isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
} else {
mixperms = ~pset->grpperms & pset->othperms;
if (tag == POSIX_ACL_USER_OBJ)
mixperms |= pset->selfuserperms;
if (isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
}
denials &= ~grants;
if (denials) {
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
}
ok = build_user_denials(pacl,
usid, mapping, flags, pxace, pset);
break;
default :
break;
@ -1667,24 +1952,34 @@ return (0);
}
/*
* for directories, a world execution denial
* for directories, insert a world execution denial
* inherited to plain files.
* This is to prevent Windows from granting execution
* of files through inheritance from parent directory
*/
if (isdir) {
if (isdir && ok) {
pos = le16_to_cpu(pacl->size);
pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos];
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
pdace->size = cpu_to_le16(wsidsz + 8);
pdace->mask = FILE_EXEC;
memcpy((char*)&pdace->sid, worldsid, wsidsz);
pos += wsidsz + 8;
acecnt++;
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
pdace->size = cpu_to_le16(wsidsz + 8);
pdace->mask = FILE_EXEC;
memcpy((char*)&pdace->sid, worldsid, wsidsz);
pos += wsidsz + 8;
acecnt = le16_to_cpu(pacl->ace_count) + 1;
pacl->ace_count = cpu_to_le16(acecnt);
pacl->size = cpu_to_le16(pos);
}
for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && !cantmap; i++) {
/*
* now insert (if needed)
* - grants to owner and designated users
* - mask and denials for all groups
* - grants to other
*/
for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && ok; i++) {
if (i >= pxdesc->acccnt) {
flags = INHERIT_ONLY_ACE
| OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
@ -1701,214 +1996,30 @@ return (0);
}
tag = pxace->tag;
perms = pxace->perms;
avoidmask = (pset->mask == (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X))
&& ((pset->designates && pset->withmask)
|| (!pset->designates && !pset->withmask));
switch (tag) {
/* compute a grant ACE for each owner or allowed user */
/* ACE for each owner or allowed user */
case POSIX_ACL_USER :
case POSIX_ACL_USER_OBJ :
rootuser = FALSE;
if (tag == POSIX_ACL_USER_OBJ) {
sid = usid;
sidsz = usidsz;
grants = OWNER_RIGHTS;
} else {
if (pxace->id) {
sid = NTFS_FIND_USID(mapping[MAPUSERS],
pxace->id, (SID*)&defsid);
if (sid)
sidsz = ntfs_sid_size(sid);
else
cantmap = TRUE;
grants = WORLD_RIGHTS;
} else {
sid = adminsid;
sidsz = ntfs_sid_size(sid);
rootuser = TRUE;
grants = WORLD_RIGHTS & ~ROOT_OWNER_UNMARK;
}
}
if (!cantmap) {
if (isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
if (rootuser)
grants &= ~ROOT_OWNER_UNMARK;
pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
pgace->type = ACCESS_ALLOWED_ACE_TYPE;
pgace->size = cpu_to_le16(sidsz + 8);
pgace->flags = flags;
pgace->mask = grants;
memcpy((char*)&pgace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
ok = build_user_grants(pacl,usid,
mapping,flags,pxace,pset);
break;
case POSIX_ACL_GROUP :
case POSIX_ACL_GROUP_OBJ :
/* a grant ACE for group */
/* unless group-obj has the same rights as world */
/* but present if group is owner or owner is administrator */
/* this ACE will be inserted after denials for group */
/* denials and grants for groups */
rootgroup = FALSE;
if (tag == POSIX_ACL_GROUP_OBJ)
sid = gsid;
else
if (pxace->id)
sid = NTFS_FIND_GSID(mapping[MAPGROUPS],
pxace->id, (SID*)&defsid);
else {
sid = adminsid;
rootgroup = TRUE;
}
if (sid) {
sidsz = ntfs_sid_size(sid);
/*
* Insert denial of complement of mask for
* each group
* WRITE_OWNER is inserted so that
* the mask can be identified
* Note : this mask may lead on Windows to
* deny rights to administrators belonging
* to some user group
*/
if ((!avoidmask && !rootgroup)
|| (pset->rootspecial
&& (tag == POSIX_ACL_GROUP_OBJ))) {
denials = WRITE_OWNER;
pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos];
if (isdir) {
if (!(pset->mask & POSIX_PERM_X))
denials |= DIR_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= DIR_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= DIR_READ;
} else {
if (!(pset->mask & POSIX_PERM_X))
denials |= FILE_EXEC;
if (!(pset->mask & POSIX_PERM_W))
denials |= FILE_WRITE;
if (!(pset->mask & POSIX_PERM_R))
denials |= FILE_READ;
}
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
} else
cantmap = TRUE;
if (!cantmap
&& (adminowns
|| groupowns
|| avoidmask
|| rootgroup
|| (perms != pset->othperms))) {
grants = WORLD_RIGHTS;
if (rootgroup)
grants &= ~ROOT_GROUP_UNMARK;
if (isdir) {
if (perms & POSIX_PERM_X)
grants |= DIR_EXEC;
if (perms & POSIX_PERM_W)
grants |= DIR_WRITE;
if (perms & POSIX_PERM_R)
grants |= DIR_READ;
} else {
if (perms & POSIX_PERM_X)
grants |= FILE_EXEC;
if (perms & POSIX_PERM_W)
grants |= FILE_WRITE;
if (perms & POSIX_PERM_R)
grants |= FILE_READ;
}
/* a possible ACE to deny group what it would get from world */
/* or administrator, unless owner is administrator or group */
denials = const_cpu_to_le32(0);
pdace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
if (!adminowns
&& !groupowns
&& !rootgroup) {
mixperms = pset->othperms;
if (tag == POSIX_ACL_GROUP_OBJ)
mixperms |= pset->selfgrpperms;
if (isdir) {
if (mixperms & POSIX_PERM_X)
denials |= DIR_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= DIR_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= DIR_READ;
} else {
if (mixperms & POSIX_PERM_X)
denials |= FILE_EXEC;
if (mixperms & POSIX_PERM_W)
denials |= FILE_WRITE;
if (mixperms & POSIX_PERM_R)
denials |= FILE_READ;
}
denials &= ~(grants | OWNER_RIGHTS);
if (denials) {
pdace->type = ACCESS_DENIED_ACE_TYPE;
pdace->flags = flags;
pdace->size = cpu_to_le16(sidsz + 8);
pdace->mask = denials;
memcpy((char*)&pdace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
/* now insert grants to group if more than world */
if (adminowns
|| groupowns
|| (avoidmask && (pset->designates || pset->withmask))
|| (perms & ~pset->othperms)
|| (pset->rootspecial
&& (tag == POSIX_ACL_GROUP_OBJ))
|| (tag == POSIX_ACL_GROUP)) {
if (rootgroup)
grants &= ~ROOT_GROUP_UNMARK;
pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
pgace->type = ACCESS_ALLOWED_ACE_TYPE;
pgace->flags = flags;
pgace->size = cpu_to_le16(sidsz + 8);
pgace->mask = grants;
memcpy((char*)&pgace->sid, sid, sidsz);
pos += sidsz + 8;
acecnt++;
}
}
ok = build_group_denials_grant(pacl,gsid,
mapping,flags,pxace,pset);
break;
case POSIX_ACL_OTHER :
/* an ACE for other users */
/* grants for other users */
pos = le16_to_cpu(pacl->size);
pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
grants = WORLD_RIGHTS;
if (isdir) {
@ -1932,17 +2043,21 @@ return (0);
pgace->mask = grants;
memcpy((char*)&pgace->sid, worldsid, wsidsz);
pos += wsidsz + 8;
acecnt++;
acecnt = le16_to_cpu(pacl->ace_count) + 1;
pacl->ace_count = cpu_to_le16(acecnt);
pacl->size = cpu_to_le16(pos);
break;
}
}
if (cantmap)
if (!ok)
errno = EINVAL;
else {
/* an ACE for administrators */
/* always full access */
pos = le16_to_cpu(pacl->size);
acecnt = le16_to_cpu(pacl->ace_count);
if (isdir)
flags = OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE;
@ -1997,7 +2112,7 @@ return (0);
pacl->size = cpu_to_le16(pos);
pacl->ace_count = cpu_to_le16(acecnt);
}
return (cantmap ? 0 : pos);
return (ok ? pos : 0);
}
#endif /* POSIXACLS */