diff --git a/posixacls.patch b/posixacls.patch index 46a05650..c0a1d3f2 100644 --- a/posixacls.patch +++ b/posixacls.patch @@ -285,126 +285,9 @@ /* * Security API for direct access to security descriptors * based on Win32 API ---- ntfsdev/ntfs-3g/libntfs-3g/security.c 2008-04-20 11:31:59.000000000 +0200 -+++ ntfsacls/ntfs-3g/libntfs-3g/security.c 2008-04-20 12:48:47.000000000 +0200 -@@ -77,12 +77,38 @@ - #define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */ - #define FIRST_SECURITY_ID 0x100 /* Lowest security id */ - -+#define FORCEMASK 0 /* temporary for debugging */ -+ -+/* -+ * JPA The following must be in some library... -+ * but did not found out where -+ */ -+ -+#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8)) -+#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \ -+ | ((x & 0xff00) << 8) | ((x & 255) << 24)) -+ -+#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x)) -+#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x)) -+ -+/* -+ * Struct to hold the input mapping file -+ * (private to this module) -+ */ -+ -+struct MAPLIST { -+ struct MAPLIST *next; -+ char *uidstr; /* uid text from the same record */ -+ char *gidstr; /* gid text from the same record */ -+ char *sidstr; /* sid text from the same record */ -+ char maptext[LINESZ + 1]; -+}; -+ - /* - * Matching of ntfs permissions to Linux permissions - * these constants are adapted to endianness - * when setting, set them all - * when checking, check one is present -- * (checks needed) - */ - - /* flags which are set to mean exec, write or read */ -@@ -123,18 +149,6 @@ - #define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE - #define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) - --/* -- * JPA The following must be in some library... -- * but did not found out where -- */ -- --#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8)) --#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \ -- | ((x & 0xff00) << 8) | ((x & 255) << 24)) -- --#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x)) --#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x)) -- - - struct SII { /* this is an image of an $SII index entry */ - le16 offs; -@@ -175,19 +189,6 @@ - } ; - - /* -- * Struct to hold the input mapping file -- * (private to this module) -- */ -- --struct MAPLIST { -- struct MAPLIST *next; -- char *uidstr; /* uid text from the same record */ -- char *gidstr; /* gid text from the same record */ -- char *sidstr; /* sid text from the same record */ -- char maptext[LINESZ + 1]; --}; -- --/* - * A type large enough to hold any SID - */ - -@@ -278,7 +279,7 @@ - * SID for generic creator-group - * S-1-3-1 - */ -- -+ - static const char groupsidbytes[] = { - 1, /* revision */ - 1, /* auth count */ -@@ -320,13 +321,13 @@ - return ( - /* check whether S-1-1-0 : world */ - ((usid->sub_authority_count == 1) -- && (usid->identifier_authority.high_part == cpu_to_be32(0)) -+ && (usid->identifier_authority.high_part == cpu_to_be16(0)) - && (usid->identifier_authority.low_part == cpu_to_be32(1)) - && (usid->sub_authority[0] == 0)) - - /* check whether S-1-5-32-545 : local user */ - || ((usid->sub_authority_count == 2) -- && (usid->identifier_authority.high_part == cpu_to_be32(0)) -+ && (usid->identifier_authority.high_part == cpu_to_be16(0)) - && (usid->identifier_authority.low_part == cpu_to_be32(5)) - && (usid->sub_authority[0] == cpu_to_le32(32)) - && (usid->sub_authority[1] == cpu_to_le32(545))) -@@ -339,10 +340,10 @@ - * probably test for other configurations - */ - --static int is_user_sid(const SID * usid) -+static int is_user_sid(const SID *usid) - { - return ((usid->sub_authority_count == 5) -- && (usid->identifier_authority.high_part == cpu_to_be32(0)) -+ && (usid->identifier_authority.high_part == cpu_to_be16(0)) - && (usid->identifier_authority.low_part == cpu_to_be32(5)) - && (usid->sub_authority[0] == cpu_to_le32(21))); - } -@@ -528,6 +529,672 @@ +--- ntfsdev/ntfs-3g/libntfs-3g/security.c 2008-04-21 15:52:57.000000000 +0200 ++++ ntfsacls/ntfs-3g/libntfs-3g/security.c 2008-04-21 15:55:24.000000000 +0200 +@@ -526,6 +526,673 @@ return (ok); } @@ -541,6 +424,7 @@ + + ok = valid_posix(pxdesc); + if (!ok) { ++ ntfs_log_error("Bad Posix ACL in %s line %d\n",file,line); + } + return (ok); +} @@ -1077,7 +961,7 @@ /** * ntfs_guid_is_zero - check if a GUID is zero * @guid: [IN] guid to check -@@ -1986,8 +2653,16 @@ +@@ -1984,8 +2651,16 @@ pseccache = *scx->pseccache; if (pseccache) { for (index1=0; index1<=pseccache->head.last; index1++) @@ -1095,7 +979,7 @@ free(pseccache); } } -@@ -1995,9 +2670,36 @@ +@@ -1993,9 +2668,36 @@ static int compare(const struct CACHED_SECURID *cached, const struct CACHED_SECURID *item) { @@ -1118,8 +1002,7 @@ + *sizeof(struct POSIX_ACE) : + 0); + return ((cached->uid != item->uid) - || (cached->gid != item->gid) -- || (cached->dmode != item->dmode))); ++ || (cached->gid != item->gid) + || (cached->dmode != item->dmode) + || (csize != isize) + || (csize @@ -1128,13 +1011,14 @@ + &((struct POSIX_SECURITY*)item->variable)->acl, csize))); +#else + return ((cached->uid != item->uid) -+ || (cached->gid != item->gid) + || (cached->gid != item->gid) +- || (cached->dmode != item->dmode))); + || (cached->dmode != item->dmode)); +#endif } static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached, -@@ -2061,20 +2763,30 @@ +@@ -2059,13 +2761,23 @@ * security id associated) */ @@ -1158,15 +1042,7 @@ unsigned int index1; unsigned int index2; int i; - - /* cacheing is only possible if a security_id has been defined */ - if (test_nino_flag(ni, v3_Extensions) -- && (ni->security_id)) { -+ && ni->security_id) { - /* - * Immediately test the most frequent situation - * where the entry exists -@@ -2089,7 +2801,26 @@ +@@ -2087,7 +2799,26 @@ cacheentry = &pcache->cachetable[index1][index2]; cacheentry->uid = uid; cacheentry->gid = gid; @@ -1193,7 +1069,7 @@ cacheentry->inh_fileid = cpu_to_le32(0); cacheentry->inh_dirid = cpu_to_le32(0); cacheentry->valid = 1; -@@ -2116,7 +2847,26 @@ +@@ -2114,7 +2845,26 @@ if (cacheentry) { cacheentry->uid = uid; cacheentry->gid = gid; @@ -1220,7 +1096,7 @@ cacheentry->inh_fileid = cpu_to_le32(0); cacheentry->inh_dirid = cpu_to_le32(0); cacheentry->valid = 1; -@@ -2134,16 +2884,27 @@ +@@ -2132,12 +2882,22 @@ wanted.perm.uid = uid; wanted.perm.gid = gid; @@ -1243,13 +1119,7 @@ legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache( scx->vol->legacy_cache, GENERIC(&wanted), (cache_compare)leg_compare); -- if (legacy) cacheentry = &legacy->perm; -+ if (legacy) -+ cacheentry = &legacy->perm; - } - #endif - } -@@ -2206,6 +2967,12 @@ +@@ -2205,6 +2965,12 @@ } } #endif @@ -1262,22 +1132,13 @@ return (cacheentry); } -@@ -2276,19 +3043,35 @@ - - /* - * Build an ACL composed of several ACE's -- * (not expected to fail) -+ * returns size of ACL or zero if failed - * - * Three schemes are defined : - * +@@ -2282,12 +3048,28 @@ * 1) if root is neither owner nor group up to 7 ACE's are set up : -- * - grants to owner (always present) * - denials to owner (preventing grants to world or group to apply) -- * - grants to group (unless groups has same rights as world) -+ * - grants to owner (always present) -+ * - grants to group (unless group has no more than world rights) - * - denials to group (preventing grants to world to apply) + * - grants to owner (always present) +- * - denials to group (preventing grants to world to apply) + * - grants to group (unless group has no more than world rights) ++ * - denials to group (preventing grants to world to apply) * - grants to world (unless none) * - full privileges to administrator, always present * - full privileges to system, always present @@ -1301,17 +1162,7 @@ * 2) if root is either owner or group, two problems arise : * - granting full rights to administrator (as needed to transpose * to Windows rights bypassing granting to root) would imply -@@ -2316,8 +3099,8 @@ - * have the same SID), but is not root. - * In this situation up to 6 ACE's are set up : - * -- * - grants to owner (always present) - * - denials to owner (preventing grants to world to apply) -+ * - grants to owner (always present) - * - grants to group (unless groups has same rights as world) - * - grants to world (unless none) - * - full privileges to administrator, always present -@@ -2330,18 +3113,40 @@ +@@ -2329,18 +3111,40 @@ * Special flags (S_ISVTX, S_ISGID, S_ISUID) : * an extra null ACE is inserted to hold these flags, using * the same conventions as cygwin. @@ -1360,8 +1211,8 @@ int acecnt; int usidsz; int gsidsz; -@@ -2356,10 +3161,14 @@ - gsidsz = sid_size(gsid); +@@ -2356,10 +3160,14 @@ + wsidsz = sid_size(worldsid); asidsz = sid_size(adminsid); ssidsz = sid_size(systemsid); + mode = pxdesc->mode; @@ -1376,7 +1227,7 @@ /* ACL header */ pacl = (ACL*)&secattr[offs]; pacl->revision = ACL_REVISION; -@@ -2370,10 +3179,524 @@ +@@ -2370,65 +3178,591 @@ pos = sizeof(ACL); acecnt = 0; @@ -1384,6 +1235,22 @@ - /* this ACE will be inserted after denial for owner */ - - grants = OWNER_RIGHTS; +- if (isdir) { +- gflags = DIR_INHERITANCE; +- if (mode & S_IXUSR) +- grants |= DIR_EXEC; +- if (mode & S_IWUSR) +- grants |= DIR_WRITE; +- if (mode & S_IRUSR) +- grants |= DIR_READ; +- } else { +- gflags = FILE_INHERITANCE; +- if (mode & S_IXUSR) +- grants |= FILE_EXEC; +- if (mode & S_IWUSR) +- grants |= FILE_WRITE; +- if (mode & S_IRUSR) +- grants |= FILE_READ; + /* + * Determine what is allowed to some group or world + * to prevent designated users or other groups to get @@ -1407,12 +1274,12 @@ + } + switch (pxace->tag) { + case POSIX_ACL_USER : -+ /* do no want root as designated user */ ++/* ! probably do no want root as designated user */ + if (!pxace->id) + adminowns = TRUE; + break; + case POSIX_ACL_GROUP : -+ /* do no want root as designated group */ ++/* ! probably do no want root as designated group */ + if (!pxace->id) + adminowns = TRUE; + /* fall through */ @@ -1427,8 +1294,33 @@ + default : + break; + } -+ } -+ + } + +- /* a possible ACE to deny owner what he/she would */ +- /* induely get from administrator, group or world */ +- /* unless owner is administrator or group */ +- +- denials = 0; +- pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; +- if (!adminowns) { +- if (!groupowns) { +- if (isdir) { +- pdace->flags = DIR_INHERITANCE; +- if (mode & (S_IXGRP | S_IXOTH)) +- denials |= DIR_EXEC; +- if (mode & (S_IWGRP | S_IWOTH)) +- denials |= DIR_WRITE; +- if (mode & (S_IRGRP | S_IROTH)) +- denials |= DIR_READ; +- } else { +- pdace->flags = FILE_INHERITANCE; +- if (mode & (S_IXGRP | S_IXOTH)) +- denials |= FILE_EXEC; +- if (mode & (S_IWGRP | S_IWOTH)) +- denials |= FILE_WRITE; +- if (mode & (S_IRGRP | S_IROTH)) +- denials |= FILE_READ; +- } +if (pxdesc->defcnt && (pxdesc->firstdef != pxdesc->acccnt)) { +ntfs_log_error("** error : access and default not consecutive\n"); +return (0); @@ -1439,7 +1331,15 @@ + | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + pset = &aceset[1]; + pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt]; -+ } else { + } else { +- if (isdir) { +- pdace->flags = DIR_INHERITANCE; +- if ((mode & S_IXOTH) && !(mode & S_IXGRP)) +- denials |= DIR_EXEC; +- if ((mode & S_IWOTH) && !(mode & S_IWGRP)) +- denials |= DIR_WRITE; +- if ((mode & S_IROTH) && !(mode & S_IRGRP)) +- denials |= DIR_READ; + flags = NO_PROPAGATE_INHERIT_ACE; + pset = &aceset[0]; + pxace = &pxdesc->acl.ace[i]; @@ -1456,7 +1356,9 @@ + sid = usid; + sidsz = usidsz; + grants = OWNER_RIGHTS; -+ } else { + } else { +- pdace->flags = FILE_INHERITANCE; +- if ((mode & S_IXOTH) && !(mode & S_IXGRP)) + sid = find_usid(scx, pxace->id, (SID*)&defsid); + if (sid) { + sidsz = sid_size(sid); @@ -1573,6 +1475,22 @@ + } + } + ++ /* ++ * for directories, a world execution denial ++ * inherited to plain files ++ */ ++ ++ if (isdir) { ++ 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++; ++ } ++ + for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && !cantmap; i++) { + if (i >= pxdesc->acccnt) { + flags = INHERIT_ONLY_ACE @@ -1747,10 +1665,6 @@ + pgace->flags = flags; + pgace->size = cpu_to_le16(sidsz + 8); + pgace->mask = grants; -+#if FORCEMASK -+ if (opt_m) -+ pgace->mask = cpu_to_le32(forcemsk); -+#endif + memcpy((char*)&pgace->sid, sid, sidsz); + pos += sidsz + 8; + acecnt++; @@ -1762,7 +1676,6 @@ + + /* an ACE for world users */ + -+ wsidsz = sid_size(worldsid); + pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; + grants = WORLD_RIGHTS; + if (isdir) { @@ -1882,6 +1795,7 @@ + + usidsz = sid_size(usid); + gsidsz = sid_size(gsid); ++ wsidsz = sid_size(worldsid); + asidsz = sid_size(adminsid); + ssidsz = sid_size(systemsid); + adminowns = same_sid(usid, adminsid) @@ -1902,21 +1816,65 @@ + /* this ACE will be inserted after denial for owner */ + + grants = OWNER_RIGHTS; - if (isdir) { - gflags = DIR_INHERITANCE; - if (mode & S_IXUSR) -@@ -2519,8 +3842,8 @@ - } - - if (adminowns -- || groupowns -- || ((mode >> 3) & ~mode & 7)) { -+ || groupowns -+ || ((mode >> 3) & ~mode & 7)) { - /* now insert grants to group */ - /* if more rights than other */ - pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos]; -@@ -2623,6 +3946,106 @@ ++ if (isdir) { ++ gflags = DIR_INHERITANCE; ++ if (mode & S_IXUSR) ++ grants |= DIR_EXEC; ++ if (mode & S_IWUSR) ++ grants |= DIR_WRITE; ++ if (mode & S_IRUSR) ++ grants |= DIR_READ; ++ } else { ++ gflags = FILE_INHERITANCE; ++ if (mode & S_IXUSR) ++ grants |= FILE_EXEC; ++ if (mode & S_IWUSR) ++ grants |= FILE_WRITE; ++ if (mode & S_IRUSR) ++ 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 = 0; ++ pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos]; ++ if (!adminowns) { ++ if (!groupowns) { ++ if (isdir) { ++ pdace->flags = DIR_INHERITANCE; ++ if (mode & (S_IXGRP | S_IXOTH)) ++ denials |= DIR_EXEC; ++ if (mode & (S_IWGRP | S_IWOTH)) ++ denials |= DIR_WRITE; ++ if (mode & (S_IRGRP | S_IROTH)) ++ denials |= DIR_READ; ++ } else { ++ pdace->flags = FILE_INHERITANCE; ++ if (mode & (S_IXGRP | S_IXOTH)) ++ denials |= FILE_EXEC; ++ if (mode & (S_IWGRP | S_IWOTH)) ++ denials |= FILE_WRITE; ++ if (mode & (S_IRGRP | S_IROTH)) ++ denials |= FILE_READ; ++ } ++ } else { ++ if (isdir) { ++ pdace->flags = DIR_INHERITANCE; ++ if ((mode & S_IXOTH) && !(mode & S_IXGRP)) ++ denials |= DIR_EXEC; ++ if ((mode & S_IWOTH) && !(mode & S_IWGRP)) ++ denials |= DIR_WRITE; ++ if ((mode & S_IROTH) && !(mode & S_IRGRP)) ++ denials |= DIR_READ; ++ } else { ++ pdace->flags = FILE_INHERITANCE; ++ if ((mode & S_IXOTH) && !(mode & S_IXGRP)) + denials |= FILE_EXEC; + if ((mode & S_IWOTH) && !(mode & S_IWGRP)) + denials |= FILE_WRITE; +@@ -2638,6 +3972,108 @@ return (pos); } @@ -1957,6 +1915,8 @@ + + 8 + wsidsz /* one ACE for world */ + + 8 + asidsz /* one ACE for admin */ + + 8 + ssidsz; /* one ACE for system */ ++ if (isdir) /* a world denial for directories */ ++ newattrsz += 8 + wsidsz; + if (pxdesc->mode & 07000) /* a NULL ACE for special modes */ + newattrsz += 8 + sid_size(nullsid); + /* account for non-owning users and groups */ @@ -2023,10 +1983,14 @@ /* * Build a full security descriptor * returns descriptor in allocated memory, must free() after use -@@ -2802,6 +4225,142 @@ - return (perm); - } - +@@ -2816,9 +4252,154 @@ + if (special & FILE_READ_DATA) + perm |= S_ISVTX; + } +- return (perm); ++ return (perm); ++} ++ +#if POSIXACLS + +/* @@ -2045,6 +2009,7 @@ + struct POSIX_ACE *pxace; + mode_t grantgrps; + mode_t grantwrld; ++ mode_t denywrld; + mode_t allow; + mode_t deny; + mode_t perms; @@ -2054,12 +2019,20 @@ + tagsset = 0; + /* + * Determine what is granted to some group or world ++ * Also get denials to world which are meant to prevent ++ * execution flags to be inherited by plain files + */ + pxace = posix_desc->acl.ace; + grantgrps = 0; + grantwrld = 0; ++ denywrld = 0; + for (j=start; j<(start + count); j++) { -+ if (!(pxace[j].perms & POSIX_PERM_DENIAL)) { ++ if (pxace[j].perms & POSIX_PERM_DENIAL) { ++ /* deny world exec unless for default */ ++ if ((pxace[j].tag == POSIX_ACL_OTHER) ++ && !start) ++ denywrld = pxace[j].perms; ++ } else { + switch (pxace[j].tag) { + case POSIX_ACL_GROUP_OBJ : + case POSIX_ACL_GROUP : @@ -2084,10 +2057,10 @@ + tag = pxace[j].tag; + id = pxace[j].id; + if (pxace[j].perms & POSIX_PERM_DENIAL) { -+ deny = pxace[j].perms; ++ deny = pxace[j].perms | denywrld; + allow = 0; + } else { -+ deny = 0; ++ deny = denywrld; + allow = pxace[j].perms; + } + j++; @@ -2159,14 +2132,14 @@ + posix_desc->tagsset = tagsset; + } + return (k - target); -+} -+ + } + +#endif + /* * Interpret an ACL and extract meaningful grants * (standard case : different owner, group and administrator) -@@ -2942,6 +4501,108 @@ +@@ -2974,6 +4555,119 @@ special)); } @@ -2187,6 +2160,7 @@ + u16 tagsset; + struct POSIX_ACE *pxace; + int acccnt; ++ mode_t denywrld; + mode_t allow; + mode_t deny; + mode_t perms; @@ -2196,6 +2170,19 @@ + pxace = posix_desc->acl.ace; + acccnt = posix_desc->acccnt; + tagsset = 0; ++ denywrld = 0; ++ /* ++ * Get denials to world which are meant to prevent ++ * execution flags to be inherited by plain files ++ */ ++ for (j=start; j<(start + count); j++) { ++ if (pxace[j].perms & POSIX_PERM_DENIAL) { ++ /* deny world exec not for default */ ++ if ((pxace[j].tag == POSIX_ACL_OTHER) ++ && !start) ++ denywrld = pxace[j].perms; ++ } ++ } + /* + * Collect groups of ACEs related to the same id + * and determine what is granted (denials are ignored) @@ -2215,18 +2202,15 @@ + && (pxace[j].tag == POSIX_ACL_MASK)) + j++; + } else { -+ if (pxace[j].perms & POSIX_PERM_DENIAL) { -+ j++; -+ } else { ++ if (!(pxace[j].perms & POSIX_PERM_DENIAL)) + allow = pxace[j].perms; ++ j++; ++ while ((j < (start + count)) ++ && (pxace[j].tag == tag) ++ && (pxace[j].id == id)) { ++ if (!(pxace[j].perms & POSIX_PERM_DENIAL)) ++ allow |= pxace[j].perms; + j++; -+ while ((j < (start + count)) -+ && (pxace[j].tag == tag) -+ && (pxace[j].id == id)) { -+ if (!(pxace[j].perms & POSIX_PERM_DENIAL)) -+ allow |= pxace[j].perms; -+ j++; -+ } + } + } + @@ -2236,7 +2220,7 @@ + if (tag == POSIX_ACL_MASK) + perms = ~deny; + else -+ perms = allow; ++ perms = allow & ~denywrld; + if (tag != POSIX_ACL_SPECIAL) { + pxace[k].tag = tag; + pxace[k].id = id; @@ -2275,7 +2259,18 @@ /* * Interpret an ACL and extract meaningful grants * (special case : owner or/and group is administrator) -@@ -3115,6 +4776,373 @@ +@@ -3041,8 +4735,8 @@ + offace += le16_to_cpu(pace->size); + } + return (merge_permissions(ni, +- allowown & ~(denyown | denyall), +- allowgrp & ~(denygrp | denyall), ++ allowown & ~(denyown | denyall), ++ allowgrp & ~(denygrp | denyall), + allowall & ~denyall, + special)); + } +@@ -3152,6 +4846,373 @@ #endif @@ -2334,9 +2329,10 @@ + * by just translating permissions and ids + * Add 2 to the count of ACE to be able to insert + * a group ACE later in access and default ACLs -+ * and add 2 more to be able to insert ACEs for owner and other ++ * and add 2 more to be able to insert ACEs for owner ++ * and 1 more for other + */ -+ alloccnt = acecnt + 4; ++ alloccnt = acecnt + 5; + pxdesc = (struct POSIX_SECURITY*)malloc( + sizeof(struct POSIX_SECURITY) + + alloccnt*sizeof(struct POSIX_ACE)); @@ -2414,6 +2410,8 @@ + } else if (is_world_sid((const SID*)&pace->sid)) { + pxace->id = -1; + pxace->tag = POSIX_ACL_OTHER; ++ if (pace->type == ACCESS_DENIED_ACE_TYPE) ++ ignore = TRUE; + } else if (same_sid((const SID*)&pace->sid,nullsid)) { + pxace->id = -1; + pxace->tag = POSIX_ACL_SPECIAL; @@ -2509,75 +2507,77 @@ + k++; + } + /* -+ * Duplicate world perms as owner perms if none (access ACE only) ++ * Set basic owner perms if none (both lists) ++ * This happens for files created by Windows in directories ++ * created by Linux and owned by root, because Windows ++ * merges the admin ACEs + */ -+ if (!(ctx[0].tagsset & POSIX_ACL_USER_OBJ)) { -+ pxace = &pxdesc->acl.ace[k]; -+ pxace->tag = POSIX_ACL_USER_OBJ; -+ pxace->id = -1; -+ pxace->perms = ctx[0].permswrld; -+ ctx[0].tagsset |= POSIX_ACL_USER_OBJ; -+ k++; -+ } ++// for (i=0; i<2; i++) ++ for (i=0; i<1; i++) ++ if (!(ctx[i].tagsset & POSIX_ACL_USER_OBJ) ++ && (ctx[i].tagsset & POSIX_ACL_OTHER)) { ++ if (i) ++ pxace = &pxdesc->acl.ace[--l]; ++ else ++ pxace = &pxdesc->acl.ace[k++]; ++ pxace->tag = POSIX_ACL_USER_OBJ; ++ pxace->id = -1; ++ pxace->perms = POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X; ++ ctx[i].tagsset |= POSIX_ACL_USER_OBJ; ++ } + /* + * Duplicate world perms as group_obj perms if none + */ -+ if ((ctx[0].tagsset & POSIX_ACL_OTHER) -+ && !(ctx[0].tagsset & POSIX_ACL_GROUP_OBJ)) { -+ pxace = &pxdesc->acl.ace[k]; -+ pxace->tag = POSIX_ACL_GROUP_OBJ; -+ pxace->id = -1; -+ pxace->perms = ctx[0].permswrld; -+ ctx[0].tagsset |= POSIX_ACL_GROUP_OBJ; -+ k++; -+ } -+ if ((ctx[1].tagsset & POSIX_ACL_OTHER) -+ && !(ctx[1].tagsset & POSIX_ACL_GROUP_OBJ)) { -+ pxace = &pxdesc->acl.ace[l - 1]; -+ pxace->tag = POSIX_ACL_GROUP_OBJ; -+ pxace->id = -1; -+ pxace->perms = ctx[1].permswrld; -+ ctx[1].tagsset |= POSIX_ACL_GROUP_OBJ; -+ l--; -+ } ++ for (i=0; i<2; i++) ++ if ((ctx[i].tagsset & POSIX_ACL_OTHER) ++ && !(ctx[i].tagsset & POSIX_ACL_GROUP_OBJ)) { ++ if (i) ++ pxace = &pxdesc->acl.ace[--l]; ++ else ++ pxace = &pxdesc->acl.ace[k++]; ++ pxace->tag = POSIX_ACL_GROUP_OBJ; ++ pxace->id = -1; ++ pxace->perms = ctx[i].permswrld; ++ ctx[i].tagsset |= POSIX_ACL_GROUP_OBJ; ++ } + /* + * Also duplicate world perms as group perms if they + * were converted to mask and not followed by a group entry + */ + if (ctx[0].groupmask) { -+ for (i=k-2; i>=0; i--) { -+ if ((pxdesc->acl.ace[i].tag == POSIX_ACL_MASK) -+ && (pxdesc->acl.ace[i].id != -1) -+ && ((pxdesc->acl.ace[i+1].tag != POSIX_ACL_GROUP) -+ || (pxdesc->acl.ace[i+1].id -+ != pxdesc->acl.ace[i].id))) { ++ for (j=k-2; j>=0; j--) { ++ if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) ++ && (pxdesc->acl.ace[j].id != -1) ++ && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) ++ || (pxdesc->acl.ace[j+1].id ++ != pxdesc->acl.ace[j].id))) { + pxace = &pxdesc->acl.ace[k]; + pxace->tag = POSIX_ACL_GROUP; -+ pxace->id = pxdesc->acl.ace[i].id; ++ pxace->id = pxdesc->acl.ace[j].id; + pxace->perms = ctx[0].permswrld; + ctx[0].tagsset |= POSIX_ACL_GROUP; + k++; + } -+ if (pxdesc->acl.ace[i].tag == POSIX_ACL_MASK) -+ pxdesc->acl.ace[i].id = -1; ++ if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) ++ pxdesc->acl.ace[j].id = -1; + } + } + if (ctx[1].groupmask) { -+ for (i=l; i<(alloccnt-1); i++) { -+ if ((pxdesc->acl.ace[i].tag == POSIX_ACL_MASK) -+ && (pxdesc->acl.ace[i].id != -1) -+ && ((pxdesc->acl.ace[i+1].tag != POSIX_ACL_GROUP) -+ || (pxdesc->acl.ace[i+1].id -+ != pxdesc->acl.ace[i].id))) { ++ for (j=l; j<(alloccnt-1); j++) { ++ if ((pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) ++ && (pxdesc->acl.ace[j].id != -1) ++ && ((pxdesc->acl.ace[j+1].tag != POSIX_ACL_GROUP) ++ || (pxdesc->acl.ace[j+1].id ++ != pxdesc->acl.ace[j].id))) { + pxace = &pxdesc->acl.ace[l - 1]; + pxace->tag = POSIX_ACL_GROUP; -+ pxace->id = pxdesc->acl.ace[i].id; ++ pxace->id = pxdesc->acl.ace[j].id; + pxace->perms = ctx[1].permswrld; + ctx[1].tagsset |= POSIX_ACL_GROUP; + l--; + } -+ if (pxdesc->acl.ace[i].tag == POSIX_ACL_MASK) -+ pxdesc->acl.ace[i].id = -1; ++ if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK) ++ pxdesc->acl.ace[j].id = -1; + } + } + @@ -2586,24 +2586,19 @@ + * there are designated users or groups + * (the space for it has not beed used) + */ -+ if ((ctx[0].tagsset & (POSIX_ACL_USER | POSIX_ACL_GROUP)) -+ && !(ctx[0].tagsset & POSIX_ACL_MASK)) { -+ pxace = &pxdesc->acl.ace[k]; -+ pxace->tag = POSIX_ACL_MASK; -+ pxace->id = -1; -+ pxace->perms = POSIX_PERM_DENIAL; -+ ctx[0].tagsset |= POSIX_ACL_MASK; -+ k++; -+ } -+ if ((ctx[1].tagsset & (POSIX_ACL_USER | POSIX_ACL_GROUP)) -+ && !(ctx[1].tagsset & POSIX_ACL_MASK)) { -+ pxace = &pxdesc->acl.ace[l - 1]; -+ pxace->tag = POSIX_ACL_MASK; -+ pxace->id = -1; -+ pxace->perms = POSIX_PERM_DENIAL; -+ ctx[1].tagsset |= POSIX_ACL_MASK; -+ l--; -+ } ++ for (i=0; i<2; i++) ++ if ((ctx[i].tagsset & (POSIX_ACL_USER | POSIX_ACL_GROUP)) ++ && !(ctx[i].tagsset & POSIX_ACL_MASK)) { ++ if (i) ++ pxace = &pxdesc->acl.ace[--l]; ++ else ++ pxace = &pxdesc->acl.ace[k++]; ++ pxace->tag = POSIX_ACL_MASK; ++ pxace->id = -1; ++ pxace->perms = POSIX_PERM_DENIAL; ++ ctx[i].tagsset |= POSIX_ACL_MASK; ++ } ++ + if (k > l) { + ntfs_log_error("Posix descriptor is longer than expected\n"); + errno = EIO; @@ -2649,7 +2644,7 @@ /* * Build unix-style (mode_t) permissions from an ACL * returns the requested permissions -@@ -3204,6 +5232,80 @@ +@@ -3241,6 +5302,80 @@ return (securattr); } @@ -2730,7 +2725,7 @@ /* * Get permissions to access a file * Takes into account the relation of user to file (owner, group, ...) -@@ -3212,8 +5314,13 @@ +@@ -3249,8 +5384,13 @@ * returns -1 if there is a problem */ @@ -2744,7 +2739,7 @@ { const SECURITY_DESCRIPTOR_RELATIVE *phead; const struct CACHED_PERMISSIONS *cached; -@@ -3223,6 +5330,9 @@ +@@ -3260,6 +5400,9 @@ uid_t uid; gid_t gid; int perm; @@ -2754,7 +2749,7 @@ if (!scx->usermapping || !scx->uid) perm = 07777; -@@ -3230,9 +5340,15 @@ +@@ -3267,9 +5410,15 @@ /* check whether available in cache */ cached = fetch_cache(scx,ni); if (cached) { @@ -2770,7 +2765,7 @@ } else { perm = 0; /* default to no permission */ securattr = getsecurityattr(scx->vol, path, ni); -@@ -3244,14 +5360,32 @@ +@@ -3281,14 +5430,32 @@ gid = findgroup(scx,gsid); #if OWNERFROMACL usid = acl_owner(securattr); @@ -2803,7 +2798,7 @@ if (!perm && same_sid(usid, adminsid)) { uid = find_tenant(scx, securattr); if (uid) -@@ -3276,29 +5410,165 @@ +@@ -3313,15 +5480,28 @@ } if (test_nino_flag(ni, v3_Extensions) && (perm >= 0)) { @@ -2814,31 +2809,28 @@ enter_cache(scx, ni, uid, gid, perm); +#endif -+ } + } +#if POSIXACLS + if (pxdesc) { + perm = access_check_posix(scx,pxdesc,request,uid,gid); + free(pxdesc); + } +#endif -+ free(securattr); -+ } else { -+ perm = -1; -+ uid = gid = 0; -+ } -+ } + free(securattr); + } else { + perm = -1; + uid = gid = 0; + } + } +#if POSIXACLS +#else -+ if (perm >= 0) { -+ if (uid == scx->uid) -+ perm &= 07700; -+ else -+ if ((gid == scx->gid) -+ || groupmember(scx, scx->uid, gid)) -+ perm &= 07070; -+ else -+ perm &= 07007; -+ } + if (perm >= 0) { + if (uid == scx->uid) + perm &= 07700; +@@ -3332,10 +5512,133 @@ + else + perm &= 07007; + } +#endif + } + return (perm); @@ -2921,8 +2913,8 @@ + if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS) + enter_cache(scx, ni, uid, + gid, pxdesc); - } - free(securattr); ++ } ++ free(securattr); + } else + pxdesc = (struct POSIX_SECURITY*)NULL; + } @@ -2951,24 +2943,11 @@ + errno = ENOSPC; + } + } - } else { -- perm = -1; -- uid = gid = 0; ++ } else { + outsize = 0; + errno = EIO; + ntfs_log_error("Invalid Posix ACL built\n"); - } -- } -- if (perm >= 0) { -- if (uid == scx->uid) -- perm &= 07700; -- else -- if ((gid == scx->gid) -- || groupmember(scx, scx->uid, gid)) -- perm &= 07070; -- else -- perm &= 07007; -- } ++ } + if (!cached) + free(pxdesc); + } else @@ -2983,7 +2962,7 @@ /* * Get owner, group and permissions in an stat structure * returns permissions, or -1 if there is a problem -@@ -3314,6 +5584,9 @@ +@@ -3351,6 +5654,9 @@ const SID *gsid; /* group of file/directory */ const struct CACHED_PERMISSIONS *cached; int perm; @@ -2993,7 +2972,7 @@ if (!scx->usermapping) perm = 07777; -@@ -3340,8 +5613,17 @@ +@@ -3377,8 +5683,17 @@ usid = (const SID*)& securattr[le32_to_cpu(phead->owner)]; #endif @@ -3011,7 +2990,7 @@ /* * fetch owner and group for cacheing */ -@@ -3371,8 +5653,14 @@ +@@ -3408,8 +5723,14 @@ stbuf->st_gid = findgroup(scx,gsid); stbuf->st_mode = (stbuf->st_mode & ~07777) + perm; @@ -3026,7 +3005,7 @@ } free(securattr); } -@@ -3381,6 +5669,87 @@ +@@ -3418,6 +5739,87 @@ return (perm); } @@ -3114,7 +3093,7 @@ /* * Allocate a security_id for a file being created * -@@ -3388,6 +5757,144 @@ +@@ -3425,6 +5827,144 @@ */ le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx, @@ -3259,7 +3238,7 @@ uid_t uid, gid_t gid, mode_t mode, BOOL isdir) { #if !FORCE_FORMAT_v1x -@@ -3455,6 +5962,7 @@ +@@ -3492,6 +6032,7 @@ return (securid); } @@ -3267,7 +3246,7 @@ /* * Update ownership and mode of a file, reusing an existing -@@ -3463,8 +5971,14 @@ +@@ -3500,8 +6041,14 @@ * Returns zero if successful */ @@ -3282,7 +3261,7 @@ { int res; const struct CACHED_SECURID *cached; -@@ -3486,8 +6000,17 @@ +@@ -3523,8 +6070,17 @@ wanted.gid = gid; wanted.dmode = mode & 07777; if (isdir) wanted.dmode |= 0x10000; @@ -3300,7 +3279,7 @@ cached = (const struct CACHED_SECURID*)ntfs_fetch_cache( scx->vol->securid_cache, GENERIC(&wanted), (cache_compare)compare); -@@ -3511,8 +6034,17 @@ +@@ -3548,8 +6104,17 @@ uid, gid); usid = gsid = adminsid; } @@ -3318,7 +3297,7 @@ if (newattr) { res = update_secur_descr(scx->vol, newattr, ni); if (!res) { -@@ -3529,8 +6061,13 @@ +@@ -3566,8 +6131,13 @@ struct CACHED_PERMISSIONS_LEGACY legacy; legacy.mft_no = ni->mft_no; @@ -3332,7 +3311,7 @@ ntfs_invalidate_cache(scx->vol->legacy_cache, GENERIC(&legacy), (cache_compare)leg_compare); -@@ -3549,6 +6086,115 @@ +@@ -3586,6 +6156,115 @@ return (res); } @@ -3448,15 +3427,9 @@ /* * Set new permissions to a file -@@ -3568,18 +6214,40 @@ - char *oldattr; - const SID *usid; - const SID *gsid; -+ uid_t processuid; +@@ -3609,6 +6288,12 @@ uid_t uid; -- uid_t fileuid; -- uid_t filegid; -+ uid_t gid; + uid_t gid; int res; +#if POSIXACLS + BOOL isdir; @@ -3467,14 +3440,10 @@ /* get the current owner, either from cache or from old attribute */ res = 0; -- usid = (const SID*)NULL; -+usid = (const SID*)NULL; - cached = fetch_cache(scx, ni); +@@ -3616,6 +6301,22 @@ if (cached) { -- fileuid = cached->uid; -- filegid = cached->gid; -+ uid = cached->uid; -+ gid = cached->gid; + uid = cached->uid; + gid = cached->gid; +#if POSIXACLS + oldpxdesc = cached->pxdesc; + if (oldpxdesc) { @@ -3494,14 +3463,10 @@ } else { oldattr = getsecurityattr(scx->vol,path, ni); if (oldattr) { -@@ -3590,25 +6258,42 @@ - usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)]; - #endif +@@ -3628,6 +6329,13 @@ gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)]; -- fileuid = findowner(scx,usid); -- filegid = findgroup(scx,gsid); -+ uid = findowner(scx,usid); -+ gid = findgroup(scx,gsid); + uid = findowner(scx,usid); + gid = findgroup(scx,gsid); +#if POSIXACLS + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != 0; + newpxdesc = build_permissions_posix(scx, @@ -3512,24 +3477,10 @@ free(oldattr); } else res = -1; - } - - if (!res) { -- uid = scx->uid; -- if (!uid || (fileuid == uid)) { -+ processuid = scx->uid; -+ if (!processuid || (uid == processuid)) { - /* - * clear setgid if file group does - * not match process group - */ -- if (uid && (filegid != scx->gid) -- && !groupmember(scx, scx->uid, filegid)) -+ if (processuid && (gid != scx->gid) -+ && !groupmember(scx, scx->uid, gid)) +@@ -3643,7 +6351,18 @@ + if (processuid && (gid != scx->gid) + && !groupmember(scx, scx->uid, gid)) mode &= ~S_ISGID; -- res = ntfs_set_owner_mode(scx, ni, -- fileuid, filegid, mode); +#if POSIXACLS + if (newpxdesc) { + newpxdesc->mode = mode; @@ -3540,12 +3491,12 @@ + res = ntfs_set_owner_mode(scx, ni, uid, gid, + mode, newpxdesc); +#else -+ res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); + res = ntfs_set_owner_mode(scx, ni, uid, gid, mode); +#endif } else { errno = EPERM; res = -1; /* neither owner nor root */ -@@ -3723,7 +6408,11 @@ +@@ -3758,7 +6477,11 @@ if (!scx->usermapping || !scx->uid) allow = 1; else { @@ -3558,16 +3509,7 @@ if (perm >= 0) { res = EACCES; switch (accesstype) { -@@ -3755,7 +6444,7 @@ - allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) - && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0); - break; -- default : -+ default: - res = EINVAL; - allow = 0; - break; -@@ -3838,6 +6527,10 @@ +@@ -3873,6 +6596,10 @@ mode_t mode; int perm; int res; @@ -3578,7 +3520,7 @@ res = 0; /* get the current owner and mode from cache or security attributes */ -@@ -3847,10 +6540,23 @@ +@@ -3882,10 +6609,23 @@ fileuid = cached->uid; filegid = cached->gid; mode = cached->mode; @@ -3602,7 +3544,7 @@ oldattr = getsecurityattr(scx->vol, path, ni); if (oldattr) { phead = (const SECURITY_DESCRIPTOR_RELATIVE*) -@@ -3863,6 +6569,21 @@ +@@ -3898,6 +6638,21 @@ usid = (const SID*) &oldattr[le32_to_cpu(phead->owner)]; #endif @@ -3624,7 +3566,7 @@ mode = perm = build_permissions(oldattr, usid, gsid, ni); if (perm >= 0) { -@@ -3870,6 +6591,7 @@ +@@ -3905,6 +6660,7 @@ filegid = findgroup(scx,gsid); } else res = -1; @@ -3632,7 +3574,7 @@ free(oldattr); } else res = -1; -@@ -3891,11 +6613,19 @@ +@@ -3926,11 +6682,19 @@ /* unless request originated by root */ if (uid && (fileuid != uid)) mode &= 01777;