mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-27 03:53:48 +08:00
1f64eafe7c
As this is a patch to standard version, all changes since ntfs-3g.1.2531SR.1 are also reflected.
3619 lines
93 KiB
Diff
3619 lines
93 KiB
Diff
--- ntfsdev/ntfs-3g/src/ntfs-3g.c 2008-07-13 11:22:47.000000000 +0200
|
|
+++ ntfsacls/ntfs-3g/src/ntfs-3g.c 2008-07-13 11:33:14.000000000 +0200
|
|
@@ -1072,9 +1072,15 @@
|
|
securid = ntfs_inherited_id(&security, dir_path,
|
|
dir_ni, S_ISDIR(type));
|
|
else
|
|
+#if POSIXACLS
|
|
+ securid = ntfs_alloc_securid(&security,
|
|
+ security.uid, security.gid,
|
|
+ dir_path, dir_ni, perm, S_ISDIR(type));
|
|
+#else
|
|
securid = ntfs_alloc_securid(&security,
|
|
security.uid, security.gid, perm,
|
|
S_ISDIR(type));
|
|
+#endif
|
|
/* Create object specified in @type. */
|
|
switch (type) {
|
|
case S_IFCHR:
|
|
@@ -1103,10 +1109,18 @@
|
|
* could not be allocated (eg NTFS 1.x)
|
|
*/
|
|
if (ctx->security.usermapping) {
|
|
+#if POSIXACLS
|
|
+ if (!securid
|
|
+ && ntfs_set_inherited_posix(&security, ni,
|
|
+ security.uid, security.gid,
|
|
+ dir_path, dir_ni, perm) < 0)
|
|
+ set_fuse_error(&res);
|
|
+#else
|
|
if (!securid
|
|
&& ntfs_set_owner_mode(&security, ni,
|
|
security.uid, security.gid, perm) < 0)
|
|
set_fuse_error(&res);
|
|
+#endif
|
|
else {
|
|
/* Adjust read-only (for Windows) */
|
|
if (perm & S_IWUSR)
|
|
@@ -1752,6 +1766,38 @@
|
|
ntfschar *lename = NULL;
|
|
int res, lename_len;
|
|
|
|
+#if POSIXACLS
|
|
+ struct SECURITY_CONTEXT security;
|
|
+
|
|
+ /* hijack Posix ACL retrieval */
|
|
+ if ((size > 0)
|
|
+ && (!strcmp(name,"system.posix_acl_access")
|
|
+ || !strcmp(name,"system.posix_acl_default"))) {
|
|
+
|
|
+ if (ntfs_fuse_is_named_data_stream(path))
|
|
+ return -EINVAL; /* n/a for named data streams. */
|
|
+
|
|
+ /* JPA return unsupported if no user mapping has been defined */
|
|
+ if (!ntfs_fuse_fill_security_context(&security)) {
|
|
+ if (ctx->silent)
|
|
+ res = 0;
|
|
+ else
|
|
+ res = -EOPNOTSUPP;
|
|
+
|
|
+ } else {
|
|
+ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
|
+ if (!ni)
|
|
+ res = -errno;
|
|
+ else {
|
|
+ res = ntfs_get_posix_acl(&security,path,
|
|
+ name,value,size,ni);
|
|
+ if (ntfs_inode_close(ni))
|
|
+ set_fuse_error(&res);
|
|
+ }
|
|
+ }
|
|
+ return (res);
|
|
+ }
|
|
+#endif
|
|
if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
|
|
return ntfs_fuse_getxattr_windows(path, name, value, size);
|
|
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
|
|
@@ -1802,6 +1848,37 @@
|
|
ntfschar *lename = NULL;
|
|
int res, lename_len;
|
|
|
|
+#if POSIXACLS
|
|
+ struct SECURITY_CONTEXT security;
|
|
+
|
|
+ /* hijack Posix ACL setting */
|
|
+ if (!strcmp(name,"system.posix_acl_access")
|
|
+ || !strcmp(name,"system.posix_acl_default")) {
|
|
+
|
|
+ if (ntfs_fuse_is_named_data_stream(path))
|
|
+ return -EINVAL; /* n/a for named data streams. */
|
|
+
|
|
+ /* JPA return unsupported if no user mapping has been defined */
|
|
+ if (!ntfs_fuse_fill_security_context(&security)) {
|
|
+ if (ctx->silent)
|
|
+ res = 0;
|
|
+ else
|
|
+ res = -EOPNOTSUPP;
|
|
+
|
|
+ } else {
|
|
+ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
|
+ if (!ni)
|
|
+ res = -errno;
|
|
+ else {
|
|
+ res = ntfs_set_posix_acl(&security,path,
|
|
+ name,value,size,ni);
|
|
+ if (ntfs_inode_close(ni))
|
|
+ set_fuse_error(&res);
|
|
+ }
|
|
+ }
|
|
+ return (res);
|
|
+ }
|
|
+#endif
|
|
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
|
|
return -EOPNOTSUPP;
|
|
if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
|
|
@@ -1860,6 +1937,37 @@
|
|
int res = 0, lename_len;
|
|
|
|
|
|
+#if POSIXACLS
|
|
+ struct SECURITY_CONTEXT security;
|
|
+
|
|
+ /* hijack Posix ACL removal */
|
|
+ if (!strcmp(name,"system.posix_acl_access")
|
|
+ || !strcmp(name,"system.posix_acl_default")) {
|
|
+
|
|
+ if (ntfs_fuse_is_named_data_stream(path))
|
|
+ return -EINVAL; /* n/a for named data streams. */
|
|
+
|
|
+ /* JPA return unsupported if no user mapping has been defined */
|
|
+ if (!ntfs_fuse_fill_security_context(&security)) {
|
|
+ if (ctx->silent)
|
|
+ res = 0;
|
|
+ else
|
|
+ res = -EOPNOTSUPP;
|
|
+
|
|
+ } else {
|
|
+ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
|
+ if (!ni)
|
|
+ res = -errno;
|
|
+ else {
|
|
+ res = ntfs_remove_posix_acl(&security,path,
|
|
+ name,ni);
|
|
+ if (ntfs_inode_close(ni))
|
|
+ set_fuse_error(&res);
|
|
+ }
|
|
+ }
|
|
+ return (res);
|
|
+ }
|
|
+#endif
|
|
if (ctx->streams != NF_STREAMS_INTERFACE_XATTR)
|
|
return -EOPNOTSUPP;
|
|
if (strncmp(name, nf_ns_xattr_preffix, nf_ns_xattr_preffix_len) ||
|
|
--- ntfsdev/ntfs-3g/include/ntfs-3g/security.h 2008-07-13 09:11:26.000000000 +0200
|
|
+++ ntfsacls/ntfs-3g/include/ntfs-3g/security.h 2008-07-13 11:33:14.000000000 +0200
|
|
@@ -30,6 +30,8 @@
|
|
#include "inode.h"
|
|
#include "dir.h"
|
|
|
|
+#define POSIXACLS 1
|
|
+
|
|
/*
|
|
* item in the mapping list
|
|
*/
|
|
@@ -52,6 +54,10 @@
|
|
gid_t gid;
|
|
le32 inh_fileid;
|
|
le32 inh_dirid;
|
|
+#if POSIXACLS
|
|
+ void *pxdesc;
|
|
+ unsigned int pxdescsize:16;
|
|
+#endif
|
|
unsigned int mode:12;
|
|
unsigned int valid:1;
|
|
} ;
|
|
@@ -129,6 +135,65 @@
|
|
pid_t tid; /* thread id of thread requesting */
|
|
} ;
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Posix ACL structures
|
|
+ */
|
|
+
|
|
+struct POSIX_ACE {
|
|
+ u16 tag;
|
|
+ u16 perms;
|
|
+ s32 id;
|
|
+} ;
|
|
+
|
|
+struct POSIX_ACL {
|
|
+ u8 version;
|
|
+ u8 flags;
|
|
+ u16 filler;
|
|
+ struct POSIX_ACE ace[0];
|
|
+} ;
|
|
+
|
|
+struct POSIX_SECURITY {
|
|
+ mode_t mode;
|
|
+ int acccnt;
|
|
+ int defcnt;
|
|
+ int firstdef;
|
|
+ u16 tagsset;
|
|
+ struct POSIX_ACL acl;
|
|
+} ;
|
|
+
|
|
+/*
|
|
+ * Posix tags, cpu-endian 16 bits
|
|
+ */
|
|
+
|
|
+enum {
|
|
+ POSIX_ACL_USER_OBJ = 1,
|
|
+ POSIX_ACL_USER = 2,
|
|
+ POSIX_ACL_GROUP_OBJ = 4,
|
|
+ POSIX_ACL_GROUP = 8,
|
|
+ POSIX_ACL_MASK = 16,
|
|
+ POSIX_ACL_OTHER = 32,
|
|
+ POSIX_ACL_SPECIAL = 64 /* internal use only */
|
|
+} ;
|
|
+
|
|
+#define POSIX_ACL_EXTENSIONS (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK)
|
|
+
|
|
+/*
|
|
+ * Posix permissions, cpu-endian 16 bits
|
|
+ */
|
|
+
|
|
+enum {
|
|
+ POSIX_PERM_X = 1,
|
|
+ POSIX_PERM_W = 2,
|
|
+ POSIX_PERM_R = 4,
|
|
+ POSIX_PERM_DENIAL = 64 /* internal use only */
|
|
+} ;
|
|
+
|
|
+#define POSIX_VERSION 2
|
|
+
|
|
+#endif
|
|
+
|
|
extern const GUID *const zero_guid;
|
|
|
|
extern BOOL ntfs_guid_is_zero(const GUID *guid);
|
|
@@ -169,17 +234,46 @@
|
|
BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
|
const char *path, int accesstype);
|
|
|
|
+#if POSIXACLS
|
|
+le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
|
+ uid_t uid, gid_t gid, const char *dir_path,
|
|
+ ntfs_inode *dir_ni, mode_t mode, BOOL isdir);
|
|
+#else
|
|
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
|
uid_t uid, gid_t gid, mode_t mode, BOOL isdir);
|
|
+#endif
|
|
int ntfs_set_owner(struct SECURITY_CONTEXT *scx,
|
|
const char *path, ntfs_inode *ni, uid_t uid, gid_t gid);
|
|
+#if POSIXACLS
|
|
+int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
|
+ ntfs_inode *ni, uid_t uid, gid_t gid,
|
|
+ mode_t mode, struct POSIX_SECURITY *pxdesc);
|
|
+#else
|
|
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
|
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
|
|
+#endif
|
|
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
|
const char *dir_path, ntfs_inode *dir_ni, BOOL fordir);
|
|
int ntfs_open_secure(ntfs_volume *vol);
|
|
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
|
|
+ ntfs_inode *ni, uid_t uid, gid_t gid,
|
|
+ const char *dir_path, ntfs_inode *dir_ni, mode_t mode);
|
|
+int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, char *value, size_t size,
|
|
+ ntfs_inode *ni);
|
|
+int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, const char *value, size_t size,
|
|
+ ntfs_inode *ni);
|
|
+int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, ntfs_inode *ni);
|
|
+
|
|
+#endif
|
|
+
|
|
+
|
|
/*
|
|
* Security API for direct access to security descriptors
|
|
* based on Win32 API
|
|
--- ntfsdev/ntfs-3g/libntfs-3g/security.c 2008-07-13 09:11:26.000000000 +0200
|
|
+++ ntfsacls/ntfs-3g/libntfs-3g/security.c 2008-07-13 12:44:56.000000000 +0200
|
|
@@ -526,6 +526,673 @@
|
|
return (ok);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Do sanity checks on a Posix descriptor
|
|
+ * Should not be called with a NULL argument
|
|
+ * returns TRUE if considered safe
|
|
+ * if not, error should be logged by caller
|
|
+ */
|
|
+
|
|
+static BOOL valid_posix(const struct POSIX_SECURITY *pxdesc)
|
|
+{
|
|
+ const struct POSIX_ACL *pacl;
|
|
+ int i;
|
|
+ BOOL ok;
|
|
+ u16 tag;
|
|
+ u32 id;
|
|
+ int perms;
|
|
+ struct {
|
|
+ u16 previous;
|
|
+ u32 previousid;
|
|
+ u16 tagsset;
|
|
+ mode_t mode;
|
|
+ int owners;
|
|
+ int groups;
|
|
+ int others;
|
|
+ } checks[2], *pchk;
|
|
+
|
|
+ for (i=0; i<2; i++) {
|
|
+ checks[i].mode = 0;
|
|
+ checks[i].tagsset = 0;
|
|
+ checks[i].owners = 0;
|
|
+ checks[i].groups = 0;
|
|
+ checks[i].others = 0;
|
|
+ checks[i].previous = 0;
|
|
+ checks[i].previousid = 0;
|
|
+ }
|
|
+ ok = TRUE;
|
|
+ pacl = &pxdesc->acl;
|
|
+ /*
|
|
+ * header (strict for now)
|
|
+ */
|
|
+ if ((pacl->version != POSIX_VERSION)
|
|
+ || (pacl->flags != 0)
|
|
+ || (pacl->filler != 0))
|
|
+ ok = FALSE;
|
|
+ /*
|
|
+ * Reject multiple owner, group or other
|
|
+ * but do not require them to be present
|
|
+ * Also check the ACEs are in correct order
|
|
+ * which implies there is no duplicates
|
|
+ */
|
|
+ for (i=0; i<pxdesc->acccnt + pxdesc->defcnt; i++) {
|
|
+ if (i >= pxdesc->firstdef)
|
|
+ pchk = &checks[1];
|
|
+ else
|
|
+ pchk = &checks[0];
|
|
+ perms = pacl->ace[i].perms;
|
|
+ tag = pacl->ace[i].tag;
|
|
+ pchk->tagsset |= tag;
|
|
+ id = pacl->ace[i].id;
|
|
+ if (perms & ~7) ok = FALSE;
|
|
+ if ((tag < pchk->previous)
|
|
+ || ((tag == pchk->previous)
|
|
+ && (id <= pchk->previousid)))
|
|
+ ok = FALSE;
|
|
+ pchk->previous = tag;
|
|
+ pchk->previousid = id;
|
|
+ switch (tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ if (pchk->owners++)
|
|
+ ok = FALSE;
|
|
+ if (id != (u32)-1)
|
|
+ ok = FALSE;
|
|
+ pchk->mode |= perms << 6;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ if (pchk->groups++)
|
|
+ ok = FALSE;
|
|
+ if (id != (u32)-1)
|
|
+ ok = FALSE;
|
|
+ pchk->mode = (pchk->mode & 07707) | (perms << 3);
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ if (pchk->others++)
|
|
+ ok = FALSE;
|
|
+ if (id != (u32)-1)
|
|
+ ok = FALSE;
|
|
+ pchk->mode |= perms;
|
|
+ break;
|
|
+ case POSIX_ACL_USER :
|
|
+ case POSIX_ACL_GROUP :
|
|
+ /* cannot accept root as designated user/grp */
|
|
+ if ((id == (u32)-1) || (id == (u32)0))
|
|
+ ok = FALSE;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ if (id != (u32)-1)
|
|
+ ok = FALSE;
|
|
+ pchk->mode = (pchk->mode & 07707) | (perms << 3);
|
|
+ break;
|
|
+ default :
|
|
+ ok = FALSE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if ((pxdesc->acccnt > 0)
|
|
+ && ((checks[0].owners != 1) || (checks[0].groups != 1)
|
|
+ || (checks[0].others != 1)))
|
|
+ ok = FALSE;
|
|
+ /* do not check owner, group or other are present in */
|
|
+ /* the default ACL, Windows does not necessarily set them */
|
|
+ /* descriptor */
|
|
+ if (pxdesc->defcnt && (pxdesc->acccnt > pxdesc->firstdef))
|
|
+ ok = FALSE;
|
|
+ if ((pxdesc->acccnt < 0) || (pxdesc->defcnt < 0))
|
|
+ ok = FALSE;
|
|
+ /* check mode, unless null or no tag set */
|
|
+ if (pxdesc->mode
|
|
+ && checks[0].tagsset
|
|
+ && (checks[0].mode != (pxdesc->mode & 0777)))
|
|
+ ok = FALSE;
|
|
+ /* check tagsset */
|
|
+ if (pxdesc->tagsset != checks[0].tagsset)
|
|
+ ok = FALSE;
|
|
+ return (ok);
|
|
+}
|
|
+
|
|
+static BOOL valid_posix_chk(const struct POSIX_SECURITY *pxdesc, const char *file, int line)
|
|
+{
|
|
+ BOOL ok;
|
|
+
|
|
+ ok = valid_posix(pxdesc);
|
|
+ if (!ok) {
|
|
+ ntfs_log_error("Bad Posix ACL in %s line %d\n",file,line);
|
|
+ }
|
|
+ return (ok);
|
|
+}
|
|
+
|
|
+#define valid_posix(p) valid_posix_chk((p),__FILE__,__LINE__)
|
|
+
|
|
+/*
|
|
+ * Set standard header data into a Posix ACL
|
|
+ * The mode argument should provide the 3 upper bits of target mode
|
|
+ */
|
|
+
|
|
+static mode_t posix_header(struct POSIX_SECURITY *pxdesc, mode_t basemode)
|
|
+{
|
|
+ mode_t mode;
|
|
+ u16 tagsset;
|
|
+ struct POSIX_ACE *pace;
|
|
+ int i;
|
|
+
|
|
+ mode = basemode & 07000;
|
|
+ tagsset = 0;
|
|
+ for (i=0; i<pxdesc->acccnt; i++) {
|
|
+ pace = &pxdesc->acl.ace[i];
|
|
+ tagsset |= pace->tag;
|
|
+ switch(pace->tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ mode |= (pace->perms & 7) << 6;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ case POSIX_ACL_MASK :
|
|
+ mode = (mode & 07707) | ((pace->perms & 7) << 3);
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ mode |= pace->perms & 7;
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ pxdesc->tagsset = tagsset;
|
|
+ pxdesc->mode = mode;
|
|
+ pxdesc->acl.version = POSIX_VERSION;
|
|
+ pxdesc->acl.flags = 0;
|
|
+ pxdesc->acl.filler = 0;
|
|
+ return (mode);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Sort ACEs in a Posix ACL
|
|
+ * This is useful for always getting reusable converted ACLs,
|
|
+ * it also helps in merging ACEs.
|
|
+ * Repeated tag+id are allowed and not merged here.
|
|
+ *
|
|
+ * Tags should be in ascending sequence and for a repeatable tag
|
|
+ * ids should be in ascending sequence.
|
|
+ */
|
|
+
|
|
+static void sort_posix(struct POSIX_SECURITY *pxdesc)
|
|
+{
|
|
+ struct POSIX_ACL *pacl;
|
|
+ struct POSIX_ACE ace;
|
|
+ int i;
|
|
+ int offs;
|
|
+ BOOL done;
|
|
+ u16 tag;
|
|
+ u16 previous;
|
|
+ u32 id;
|
|
+ u32 previousid;
|
|
+
|
|
+
|
|
+ /*
|
|
+ * Check sequencing of tag+id in access ACE's
|
|
+ */
|
|
+ pacl = &pxdesc->acl;
|
|
+ do {
|
|
+ done = TRUE;
|
|
+ previous = pacl->ace[0].tag;
|
|
+ previousid = pacl->ace[0].id;
|
|
+ for (i=1; i<pxdesc->acccnt; i++) {
|
|
+ tag = pacl->ace[i].tag;
|
|
+ id = pacl->ace[i].id;
|
|
+
|
|
+ if ((tag < previous)
|
|
+ || ((tag == previous) && (id < previousid))) {
|
|
+ done = FALSE;
|
|
+ memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE));
|
|
+ memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE));
|
|
+ memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE));
|
|
+ } else {
|
|
+ previous = tag;
|
|
+ previousid = id;
|
|
+ }
|
|
+ }
|
|
+ } while (!done);
|
|
+ /*
|
|
+ * Same for default ACEs
|
|
+ */
|
|
+ do {
|
|
+ done = TRUE;
|
|
+ offs = pxdesc->firstdef;
|
|
+ previous = pacl->ace[offs].tag;
|
|
+ previousid = pacl->ace[offs].id;
|
|
+ for (i=offs+1; i<offs+pxdesc->defcnt; i++) {
|
|
+ tag = pacl->ace[i].tag;
|
|
+ id = pacl->ace[i].id;
|
|
+
|
|
+ if ((tag < previous)
|
|
+ || ((tag == previous) && (id < previousid))) {
|
|
+ done = FALSE;
|
|
+ memcpy(&ace,&pacl->ace[i-1],sizeof(struct POSIX_ACE));
|
|
+ memcpy(&pacl->ace[i-1],&pacl->ace[i],sizeof(struct POSIX_ACE));
|
|
+ memcpy(&pacl->ace[i],&ace,sizeof(struct POSIX_ACE));
|
|
+ } else {
|
|
+ previous = tag;
|
|
+ previousid = id;
|
|
+ }
|
|
+ }
|
|
+ } while (!done);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Merge a new mode into a Posix descriptor
|
|
+ * The Posix descriptor is not reallocated, its size is unchanged
|
|
+ *
|
|
+ * returns 0 if ok
|
|
+ */
|
|
+
|
|
+static int merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode)
|
|
+{
|
|
+ int i;
|
|
+ BOOL maskfound;
|
|
+ struct POSIX_ACE *pace;
|
|
+ int todo;
|
|
+
|
|
+ maskfound = FALSE;
|
|
+ todo = POSIX_ACL_USER_OBJ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER;
|
|
+ for (i=pxdesc->acccnt-1; i>=0; i--) {
|
|
+ pace = &pxdesc->acl.ace[i];
|
|
+ switch(pace->tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ pace->perms = (mode >> 6) & 7;
|
|
+ todo &= ~POSIX_ACL_USER_OBJ;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ if (!maskfound)
|
|
+ pace->perms = (mode >> 3) & 7;
|
|
+ todo &= ~POSIX_ACL_GROUP_OBJ;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ pace->perms = (mode >> 3) & 7;
|
|
+ maskfound = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ pace->perms = mode & 7;
|
|
+ todo &= ~POSIX_ACL_OTHER;
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ pxdesc->mode = mode;
|
|
+ return (todo ? -1 : 0);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Merge new owner and group into a Posix descriptor
|
|
+ * The Posix descriptor is reallocated, it has to be freed
|
|
+ *
|
|
+ * returns NULL if there is a problem
|
|
+ */
|
|
+
|
|
+static struct POSIX_SECURITY *merge_owner_posix(const struct POSIX_SECURITY *pxdesc,
|
|
+ uid_t uid, gid_t gid, uid_t olduid, gid_t oldgid)
|
|
+{
|
|
+ struct POSIX_SECURITY *newpxdesc;
|
|
+ const struct POSIX_ACE *oldace;
|
|
+ struct POSIX_ACE *newace;
|
|
+ BOOL uidpresent;
|
|
+ BOOL gidpresent;
|
|
+ BOOL maskpresent;
|
|
+ mode_t ownerperms;
|
|
+ mode_t groupperms;
|
|
+ mode_t mode;
|
|
+ BOOL ignore;
|
|
+ u16 tagsset;
|
|
+ int count;
|
|
+ size_t size;
|
|
+ int i;
|
|
+ int k,l;
|
|
+
|
|
+ /*
|
|
+ * Check whether the new owner and group were
|
|
+ * already designated in the ACL, and there is a mask
|
|
+ * Also get permissions of previous owner and group
|
|
+ */
|
|
+ ownerperms = 0;
|
|
+ groupperms = 0;
|
|
+ uidpresent = FALSE;
|
|
+ gidpresent = FALSE;
|
|
+ maskpresent = FALSE;
|
|
+ for (i=0; i<pxdesc->acccnt; i++) {
|
|
+ oldace = &pxdesc->acl.ace[i];
|
|
+ switch (oldace->tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ ownerperms = oldace->perms;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ groupperms = oldace->perms;
|
|
+ break;
|
|
+ case POSIX_ACL_USER :
|
|
+ if ((uid != (uid_t)-1)
|
|
+ && ((uid_t)oldace->id == uid))
|
|
+ uidpresent = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP :
|
|
+ if ((gid != (gid_t)-1)
|
|
+ && ((gid_t)oldace->id == gid))
|
|
+ gidpresent = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ maskpresent = TRUE;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ count = pxdesc->acccnt + pxdesc->defcnt;
|
|
+ if (!uidpresent)
|
|
+ count++;
|
|
+ if (!gidpresent)
|
|
+ count++;
|
|
+ if (!maskpresent)
|
|
+ count++;
|
|
+ size = sizeof(struct POSIX_SECURITY) + count*sizeof(struct POSIX_ACE);
|
|
+ newpxdesc = (struct POSIX_SECURITY*)malloc(size);
|
|
+ if (newpxdesc) {
|
|
+ k = 0;
|
|
+ mode = pxdesc->mode & 07000;
|
|
+ tagsset = 0;
|
|
+ if (!uidpresent) {
|
|
+ newace = newpxdesc->acl.ace;
|
|
+ newace->tag = POSIX_ACL_USER_OBJ;
|
|
+ newace->id = -1;
|
|
+ newace->perms = ownerperms;
|
|
+ mode |= (ownerperms << 6);
|
|
+ k++;
|
|
+ }
|
|
+ if (!gidpresent) {
|
|
+ newace = &newpxdesc->acl.ace[k];
|
|
+ newace->tag = POSIX_ACL_GROUP_OBJ;
|
|
+ newace->id = -1;
|
|
+ newace->perms = groupperms;
|
|
+ mode |= (groupperms << 3);
|
|
+ k++;
|
|
+ }
|
|
+ for (i=0; i<pxdesc->acccnt; i++) {
|
|
+ oldace = &pxdesc->acl.ace[i];
|
|
+ newace = &newpxdesc->acl.ace[k];
|
|
+ ignore = FALSE;
|
|
+ switch (oldace->tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ if (olduid) {
|
|
+ newace->tag = POSIX_ACL_USER;
|
|
+ newace->id = olduid;
|
|
+ } else
|
|
+ ignore = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_USER :
|
|
+ if ((uid_t)oldace->id == uid) {
|
|
+ newace->tag = POSIX_ACL_USER_OBJ;
|
|
+ newace->id = -1;
|
|
+ mode |= (oldace->perms << 6);
|
|
+ } else {
|
|
+ newace->tag = oldace->tag;
|
|
+ newace->id = oldace->id;
|
|
+ }
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ if (oldgid) {
|
|
+ newace->tag = POSIX_ACL_GROUP;
|
|
+ newace->id = oldgid;
|
|
+ } else
|
|
+ ignore = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP :
|
|
+ if ((uid_t)oldace->id == gid) {
|
|
+ newace->tag = POSIX_ACL_GROUP_OBJ;
|
|
+ newace->id = -1;
|
|
+ mode |= (oldace->perms << 3);
|
|
+ } else {
|
|
+ newace->tag = oldace->tag;
|
|
+ newace->id = oldace->id;
|
|
+ }
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ mode |= oldace->perms;
|
|
+ /* fall through */
|
|
+ default :
|
|
+ newace->tag = oldace->tag;
|
|
+ newace->id = oldace->id;
|
|
+ }
|
|
+ if (!ignore) {
|
|
+ newace->perms = oldace->perms;
|
|
+ tagsset |= newace->tag;
|
|
+ k++;
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
+ * If there were no mask, and we have created
|
|
+ * a designated user or group, we need a mask
|
|
+ * similar to group, so that the group righs
|
|
+ * appear unchanged
|
|
+ */
|
|
+ if (!maskpresent
|
|
+ && (olduid || oldgid)) {
|
|
+ newace = &newpxdesc->acl.ace[k];
|
|
+ newace->tag = POSIX_ACL_MASK;
|
|
+ newace->perms = groupperms;
|
|
+ newace->id = -1;
|
|
+ tagsset |= POSIX_ACL_MASK;
|
|
+ k++;
|
|
+ }
|
|
+/* default ACE left unchanged */
|
|
+ l = 0;
|
|
+ for (i=0; i<pxdesc->defcnt; i++) {
|
|
+ oldace = &pxdesc->acl.ace[i + pxdesc->firstdef];
|
|
+ newace = &newpxdesc->acl.ace[l + k];
|
|
+ newace->tag = oldace->tag;
|
|
+ newace->id = oldace->id;
|
|
+ newace->perms = oldace->perms;
|
|
+ l++;
|
|
+ }
|
|
+ /* now set headers */
|
|
+ newpxdesc->acccnt = k;
|
|
+ newpxdesc->firstdef = k;
|
|
+ newpxdesc->defcnt = l;
|
|
+ newpxdesc->mode = mode;
|
|
+ newpxdesc->tagsset = tagsset;
|
|
+ newpxdesc->acl.version = POSIX_VERSION;
|
|
+ newpxdesc->acl.flags = 0;
|
|
+ newpxdesc->acl.filler = 0;
|
|
+ /* and finally sort */
|
|
+ sort_posix(newpxdesc);
|
|
+ } else
|
|
+ errno = ENOMEM;
|
|
+ return (newpxdesc);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Replace an access or default Posix ACL
|
|
+ * The resulting ACL is checked for validity
|
|
+ *
|
|
+ * Returns a new ACL or NULL if there is a problem
|
|
+ */
|
|
+
|
|
+static struct POSIX_SECURITY *replace_acl(const struct POSIX_SECURITY *oldpxdesc,
|
|
+ const struct POSIX_ACL *newacl, int count, BOOL deflt)
|
|
+{
|
|
+ struct POSIX_SECURITY *newpxdesc;
|
|
+ size_t newsize;
|
|
+ int offset;
|
|
+ int oldoffset;
|
|
+ int i;
|
|
+
|
|
+ if (deflt)
|
|
+ newsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (oldpxdesc->acccnt + count)*sizeof(struct POSIX_ACE);
|
|
+ else
|
|
+ newsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (oldpxdesc->defcnt + count)*sizeof(struct POSIX_ACE);
|
|
+ newpxdesc = (struct POSIX_SECURITY*)malloc(newsize);
|
|
+ if (newpxdesc) {
|
|
+ if (deflt) {
|
|
+ offset = oldpxdesc->acccnt;
|
|
+ newpxdesc->acccnt = oldpxdesc->acccnt;
|
|
+ newpxdesc->defcnt = count;
|
|
+ newpxdesc->firstdef = offset;
|
|
+ /* copy access ACEs */
|
|
+ for (i=0; i<newpxdesc->acccnt; i++)
|
|
+ newpxdesc->acl.ace[i] = oldpxdesc->acl.ace[i];
|
|
+ /* copy default ACEs */
|
|
+ for (i=0; i<count; i++)
|
|
+ newpxdesc->acl.ace[i + offset] = newacl->ace[i];
|
|
+ } else {
|
|
+ offset = count;
|
|
+ newpxdesc->acccnt = count;
|
|
+ newpxdesc->defcnt = oldpxdesc->defcnt;
|
|
+ newpxdesc->firstdef = count;
|
|
+ /* copy access ACEs */
|
|
+ for (i=0; i<count; i++)
|
|
+ newpxdesc->acl.ace[i] = newacl->ace[i];
|
|
+ /* copy default ACEs */
|
|
+ oldoffset = oldpxdesc->firstdef;
|
|
+ for (i=0; i<newpxdesc->defcnt; i++)
|
|
+ newpxdesc->acl.ace[i + offset] = oldpxdesc->acl.ace[i + oldoffset];
|
|
+ }
|
|
+ /* assume special flags unchanged */
|
|
+ posix_header(newpxdesc, oldpxdesc->mode);
|
|
+ if (!valid_posix(newpxdesc)) {
|
|
+ free(newpxdesc);
|
|
+ newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+ errno = EINVAL;
|
|
+ }
|
|
+ } else
|
|
+ errno = ENOMEM;
|
|
+ return (newpxdesc);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Build an inherited Posix descriptor from parent
|
|
+ * descriptor (if any) restricted to creation mode
|
|
+ *
|
|
+ * Returns the inherited descriptor or NULL if there is a problem
|
|
+ */
|
|
+
|
|
+static struct POSIX_SECURITY *build_inherited_posix(
|
|
+ const struct POSIX_SECURITY *pxdesc, mode_t mode, BOOL isdir)
|
|
+{
|
|
+ struct POSIX_SECURITY *pydesc;
|
|
+ struct POSIX_ACE *pyace;
|
|
+ int count;
|
|
+ int defcnt;
|
|
+ int size;
|
|
+ int i;
|
|
+ s16 tagsset;
|
|
+
|
|
+ if (pxdesc && pxdesc->defcnt) {
|
|
+ if (isdir)
|
|
+ count = 2*pxdesc->defcnt + 3;
|
|
+ else
|
|
+ count = pxdesc->defcnt + 3;
|
|
+ } else
|
|
+ count = 3;
|
|
+ pydesc = (struct POSIX_SECURITY*)malloc(
|
|
+ sizeof(struct POSIX_SECURITY) + count*sizeof(struct POSIX_ACE));
|
|
+ if (pydesc) {
|
|
+ /*
|
|
+ * Copy inherited tags and adapt perms
|
|
+ */
|
|
+ tagsset = 0;
|
|
+ defcnt = (pxdesc ? pxdesc->defcnt : 0);
|
|
+ for (i=defcnt-1; i>=0; i--) {
|
|
+ pyace = &pydesc->acl.ace[i];
|
|
+ *pyace = pxdesc->acl.ace[pxdesc->firstdef + i];
|
|
+ switch (pyace->tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ pyace->perms &= (mode >> 6) & 7;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ if (!(tagsset & POSIX_ACL_MASK))
|
|
+ pyace->perms &= (mode >> 3) & 7;
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ pyace->perms &= mode & 7;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ pyace->perms &= (mode >> 3) & 7;
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ tagsset |= pyace->tag;
|
|
+ }
|
|
+ pydesc->acccnt = defcnt;
|
|
+ /*
|
|
+ * If some standard tags were missing, append them from mode
|
|
+ * and sort the list
|
|
+ */
|
|
+ if (~tagsset & (POSIX_ACL_USER_OBJ
|
|
+ | POSIX_ACL_GROUP_OBJ | POSIX_ACL_OTHER)) {
|
|
+ i = defcnt;
|
|
+ /* owner was missing */
|
|
+ if (!(tagsset & POSIX_ACL_USER_OBJ)) {
|
|
+ pyace = &pydesc->acl.ace[i];
|
|
+ pyace->tag = POSIX_ACL_USER_OBJ;
|
|
+ pyace->id = -1;
|
|
+ pyace->perms = (mode >> 6) & 7;
|
|
+ tagsset |= POSIX_ACL_USER_OBJ;
|
|
+ i++;
|
|
+ }
|
|
+ /* owning group was missing */
|
|
+ if (!(tagsset & POSIX_ACL_GROUP_OBJ)) {
|
|
+ pyace = &pydesc->acl.ace[i];
|
|
+ pyace->tag = POSIX_ACL_GROUP_OBJ;
|
|
+ pyace->id = -1;
|
|
+ pyace->perms = (mode >> 3) & 7;
|
|
+ tagsset |= POSIX_ACL_GROUP_OBJ;
|
|
+ i++;
|
|
+ }
|
|
+ /* other was missing */
|
|
+ if (!(tagsset & POSIX_ACL_OTHER)) {
|
|
+ pyace = &pydesc->acl.ace[i];
|
|
+ pyace->tag = POSIX_ACL_OTHER;
|
|
+ pyace->id = -1;
|
|
+ pyace->perms = mode & 7;
|
|
+ tagsset |= POSIX_ACL_OTHER;
|
|
+ i++;
|
|
+ }
|
|
+ pydesc->acccnt = i;
|
|
+ pydesc->firstdef = i;
|
|
+ pydesc->defcnt = 0;
|
|
+ sort_posix(pydesc);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * append as a default ACL if a directory
|
|
+ */
|
|
+ pydesc->firstdef = pydesc->acccnt;
|
|
+ if (defcnt && isdir) {
|
|
+ size = sizeof(struct POSIX_ACE)*defcnt;
|
|
+ memcpy(&pydesc->acl.ace[pydesc->firstdef],
|
|
+ &pxdesc->acl.ace[pxdesc->firstdef],size);
|
|
+ pydesc->defcnt = defcnt;
|
|
+ } else {
|
|
+ pydesc->defcnt = 0;
|
|
+ }
|
|
+ /* assume special bits are not inherited */
|
|
+ posix_header(pydesc, mode & 07000);
|
|
+ if (!valid_posix(pydesc)) {
|
|
+ ntfs_log_error("Error building an inherited Posix desc\n");
|
|
+ errno = EIO;
|
|
+ free(pydesc);
|
|
+ pydesc = (struct POSIX_SECURITY*)NULL;
|
|
+ }
|
|
+ } else
|
|
+ errno = ENOMEM;
|
|
+ return (pydesc);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
/**
|
|
* ntfs_guid_is_zero - check if a GUID is zero
|
|
* @guid: [IN] guid to check
|
|
@@ -1484,7 +2151,7 @@
|
|
ntfs_attr_remove(ni,
|
|
AT_SECURITY_DESCRIPTOR,
|
|
AT_UNNAMED, 0);
|
|
- }
|
|
+ }
|
|
set_nino_flag(ni, v3_Extensions);
|
|
ni->security_id = securid;
|
|
ntfs_attr_close(na);
|
|
@@ -1984,8 +2651,16 @@
|
|
pseccache = *scx->pseccache;
|
|
if (pseccache) {
|
|
for (index1=0; index1<=pseccache->head.last; index1++)
|
|
- if (pseccache->cachetable[index1])
|
|
+ if (pseccache->cachetable[index1]) {
|
|
+#if POSIXACLS
|
|
+ unsigned int index2;
|
|
+
|
|
+ for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++)
|
|
+ if (pseccache->cachetable[index1][index2].pxdesc)
|
|
+ free(pseccache->cachetable[index1][index2].pxdesc);
|
|
+#endif
|
|
free(pseccache->cachetable[index1]);
|
|
+ }
|
|
free(pseccache);
|
|
}
|
|
}
|
|
@@ -1993,9 +2668,36 @@
|
|
static int compare(const struct CACHED_SECURID *cached,
|
|
const struct CACHED_SECURID *item)
|
|
{
|
|
- return (((cached->uid != item->uid)
|
|
+#if POSIXACLS
|
|
+ size_t csize;
|
|
+ size_t isize;
|
|
+
|
|
+ /* only compare data and sizes */
|
|
+ csize = (cached->variable ?
|
|
+ sizeof(struct POSIX_ACL)
|
|
+ + (((struct POSIX_SECURITY*)cached->variable)->acccnt
|
|
+ + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
|
|
+ *sizeof(struct POSIX_ACE) :
|
|
+ 0);
|
|
+ isize = (item->variable ?
|
|
+ sizeof(struct POSIX_ACL)
|
|
+ + (((struct POSIX_SECURITY*)item->variable)->acccnt
|
|
+ + ((struct POSIX_SECURITY*)item->variable)->defcnt)
|
|
+ *sizeof(struct POSIX_ACE) :
|
|
+ 0);
|
|
+ return ((cached->uid != item->uid)
|
|
+ || (cached->gid != item->gid)
|
|
+ || (cached->dmode != item->dmode)
|
|
+ || (csize != isize)
|
|
+ || (csize
|
|
+ && isize
|
|
+ && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
|
|
+ &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
|
|
+#else
|
|
+ return ((cached->uid != item->uid)
|
|
|| (cached->gid != item->gid)
|
|
- || (cached->dmode != item->dmode)));
|
|
+ || (cached->dmode != item->dmode));
|
|
+#endif
|
|
}
|
|
|
|
static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
|
|
@@ -2059,13 +2761,23 @@
|
|
* security id associated)
|
|
*/
|
|
|
|
+#if POSIXACLS
|
|
+static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
|
|
+ ntfs_inode *ni, uid_t uid, gid_t gid,
|
|
+ struct POSIX_SECURITY *pxdesc)
|
|
+#else
|
|
static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
|
|
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
|
|
+#endif
|
|
{
|
|
struct CACHED_PERMISSIONS *cacheentry;
|
|
struct CACHED_PERMISSIONS *cacheblock;
|
|
struct PERMISSIONS_CACHE *pcache;
|
|
u32 securindex;
|
|
+#if POSIXACLS
|
|
+ int pxsize;
|
|
+ struct POSIX_SECURITY *pxcached;
|
|
+#endif
|
|
unsigned int index1;
|
|
unsigned int index2;
|
|
int i;
|
|
@@ -2087,7 +2799,26 @@
|
|
cacheentry = &pcache->cachetable[index1][index2];
|
|
cacheentry->uid = uid;
|
|
cacheentry->gid = gid;
|
|
+#if POSIXACLS
|
|
+ if (cacheentry->pxdesc)
|
|
+ free(cacheentry->pxdesc);
|
|
+ if (pxdesc) {
|
|
+ pxsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
|
|
+ if (pxcached) {
|
|
+ memcpy(pxcached, pxdesc, pxsize);
|
|
+ cacheentry->pxdesc = pxcached;
|
|
+ } else {
|
|
+ cacheentry->valid = 0;
|
|
+ cacheentry = (struct CACHED_PERMISSIONS*)NULL;
|
|
+ }
|
|
+ cacheentry->mode = pxdesc->mode & 07777;
|
|
+ } else
|
|
+ cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#else
|
|
cacheentry->mode = mode & 07777;
|
|
+#endif
|
|
cacheentry->inh_fileid = cpu_to_le32(0);
|
|
cacheentry->inh_dirid = cpu_to_le32(0);
|
|
cacheentry->valid = 1;
|
|
@@ -2114,7 +2845,26 @@
|
|
if (cacheentry) {
|
|
cacheentry->uid = uid;
|
|
cacheentry->gid = gid;
|
|
+#if POSIXACLS
|
|
+ if (cacheentry->pxdesc)
|
|
+ free(cacheentry->pxdesc);
|
|
+ if (pxdesc) {
|
|
+ pxsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
|
|
+ if (pxcached) {
|
|
+ memcpy(pxcached, pxdesc, pxsize);
|
|
+ cacheentry->pxdesc = pxcached;
|
|
+ } else {
|
|
+ cacheentry->valid = 0;
|
|
+ cacheentry = (struct CACHED_PERMISSIONS*)NULL;
|
|
+ }
|
|
+ cacheentry->mode = pxdesc->mode & 07777;
|
|
+ } else
|
|
+ cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#else
|
|
cacheentry->mode = mode & 07777;
|
|
+#endif
|
|
cacheentry->inh_fileid = cpu_to_le32(0);
|
|
cacheentry->inh_dirid = cpu_to_le32(0);
|
|
cacheentry->valid = 1;
|
|
@@ -2132,12 +2882,22 @@
|
|
|
|
wanted.perm.uid = uid;
|
|
wanted.perm.gid = gid;
|
|
+#if POSIXACLS
|
|
+ wanted.perm.mode = pxdesc->mode & 07777;
|
|
+ wanted.perm.inh_fileid = cpu_to_le32(0);
|
|
+ wanted.perm.inh_dirid = cpu_to_le32(0);
|
|
+ wanted.mft_no = ni->mft_no;
|
|
+ wanted.variable = (void*)pxdesc;
|
|
+ wanted.varsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+#else
|
|
wanted.perm.mode = mode & 07777;
|
|
wanted.perm.inh_fileid = cpu_to_le32(0);
|
|
wanted.perm.inh_dirid = cpu_to_le32(0);
|
|
wanted.mft_no = ni->mft_no;
|
|
wanted.variable = (void*)NULL;
|
|
wanted.varsize = 0;
|
|
+#endif
|
|
legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
|
|
scx->vol->legacy_cache, GENERIC(&wanted),
|
|
(cache_compare)leg_compare);
|
|
@@ -2205,6 +2965,12 @@
|
|
}
|
|
}
|
|
#endif
|
|
+#if POSIXACLS
|
|
+ if (cacheentry && !cacheentry->pxdesc) {
|
|
+ ntfs_log_error("No Posix descriptor in cache\n");
|
|
+ cacheentry = (struct CACHED_PERMISSIONS*)NULL;
|
|
+ }
|
|
+#endif
|
|
return (cacheentry);
|
|
}
|
|
|
|
@@ -2282,12 +3048,28 @@
|
|
* 1) if root is neither owner nor group up to 7 ACE's are set up :
|
|
* - denials to owner (preventing grants to world or group 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
|
|
*
|
|
+ * The same scheme is applied for Posix ACLs, with the mask represented
|
|
+ * as denials prepended to grants for designated users and groups
|
|
+ *
|
|
+ * This is inspired by an Internet Draft from Marius Aamodt Eriksen
|
|
+ * for mapping NFSv4 ACLs to Posix ACLs (draft-ietf-nfsv4-acl-mapping-00.txt)
|
|
+ *
|
|
+ * Note that denials to group are located after grants to owner.
|
|
+ * This only occurs in the unfrequent situation where world
|
|
+ * has more rights than group and cannot be avoided if owner and other
|
|
+ * have some common right which is denied to group (eg for mode 745
|
|
+ * executing has to be denied to group, but not to owner or world).
|
|
+ * This rare situation is processed by Windows correctly, but
|
|
+ * Windows utilities may want to change the order, with a
|
|
+ * consequence of applying the group denials to the Windows owner.
|
|
+ * The interpretation on Linux is not affected by the order change.
|
|
+ *
|
|
* 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
|
|
@@ -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.
|
|
- */
|
|
-
|
|
-static int buildacls(char *secattr, int offs, mode_t mode, int isdir,
|
|
- const SID * usid, const SID * gsid)
|
|
-{
|
|
+ *
|
|
+ * Limitations :
|
|
+ * - root cannot be a designated user or group. Full rights
|
|
+ * are aways granted to root
|
|
+ */
|
|
+
|
|
+#if POSIXACLS
|
|
+
|
|
+static int buildacls_posix(struct SECURITY_CONTEXT *scx,
|
|
+ char *secattr, int offs, struct POSIX_SECURITY *pxdesc,
|
|
+ int isdir, const SID *usid, const SID *gsid)
|
|
+{
|
|
+ struct {
|
|
+ u16 grpperms;
|
|
+ u16 othperms;
|
|
+ u16 mask;
|
|
+ } aceset[2], *pset;
|
|
+ BOOL adminowns;
|
|
+ BOOL groupowns;
|
|
ACL *pacl;
|
|
ACCESS_ALLOWED_ACE *pgace;
|
|
ACCESS_ALLOWED_ACE *pdace;
|
|
- BOOL adminowns;
|
|
- BOOL groupowns;
|
|
- ACE_FLAGS gflags;
|
|
+ struct POSIX_ACE *pxace;
|
|
+ BOOL cantmap;
|
|
+ mode_t mode;
|
|
+ u16 tag;
|
|
+ u16 perms;
|
|
+ u16 mixperms;
|
|
+ ACE_FLAGS flags;
|
|
int pos;
|
|
+ int i;
|
|
+ BIGSID defsid;
|
|
+ const SID *sid;
|
|
+ int sidsz;
|
|
int acecnt;
|
|
int usidsz;
|
|
int gsidsz;
|
|
@@ -2356,10 +3160,14 @@
|
|
wsidsz = sid_size(worldsid);
|
|
asidsz = sid_size(adminsid);
|
|
ssidsz = sid_size(systemsid);
|
|
+ mode = pxdesc->mode;
|
|
+ /* adminowns and groupowns are used for both lists */
|
|
adminowns = same_sid(usid, adminsid)
|
|
- || same_sid(gsid, adminsid);
|
|
+ || same_sid(gsid, adminsid);
|
|
groupowns = !adminowns && same_sid(usid, gsid);
|
|
|
|
+ cantmap = FALSE;
|
|
+
|
|
/* ACL header */
|
|
pacl = (ACL*)&secattr[offs];
|
|
pacl->revision = ACL_REVISION;
|
|
@@ -2370,62 +3178,584 @@
|
|
pos = sizeof(ACL);
|
|
acecnt = 0;
|
|
|
|
- /* compute a grant ACE for owner */
|
|
- /* 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
|
|
+ * rights from groups or world
|
|
+ * Also get global mask
|
|
+ */
|
|
+ aceset[0].grpperms = 0;
|
|
+ aceset[0].othperms = 0;
|
|
+ aceset[0].mask = (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X);
|
|
+ aceset[1].grpperms = 0;
|
|
+ aceset[1].othperms = 0;
|
|
+ aceset[1].mask = (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X);
|
|
+
|
|
+ for (i=pxdesc->acccnt+pxdesc->defcnt-1; i>=0; i--) {
|
|
+ if (i >= pxdesc->acccnt) {
|
|
+ pset = &aceset[1];
|
|
+ pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt];
|
|
+ } else {
|
|
+ pset = &aceset[0];
|
|
+ pxace = &pxdesc->acl.ace[i];
|
|
+ }
|
|
+ switch (pxace->tag) {
|
|
+ case POSIX_ACL_USER :
|
|
+/* ! probably do no want root as designated user */
|
|
+ if (!pxace->id)
|
|
+ adminowns = TRUE;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP :
|
|
+/* ! probably do no want root as designated group */
|
|
+ if (!pxace->id)
|
|
+ adminowns = TRUE;
|
|
+ /* fall through */
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ pset->grpperms |= pxace->perms;
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ pset->othperms = pxace->perms;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ pset->mask = pxace->perms;
|
|
+ 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);
|
|
+}
|
|
+ for (i=0; (i<(pxdesc->acccnt + pxdesc->defcnt)) && !cantmap; i++) {
|
|
+ if (i >= pxdesc->acccnt) {
|
|
+ flags = INHERIT_ONLY_ACE
|
|
+ | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
|
+ pset = &aceset[1];
|
|
+ pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt];
|
|
} 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];
|
|
+ }
|
|
+ tag = pxace->tag;
|
|
+ perms = pxace->perms;
|
|
+ switch (tag) {
|
|
+
|
|
+ /* compute a grant ACE for each owner or allowed user */
|
|
+
|
|
+ case POSIX_ACL_USER :
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ if (tag == POSIX_ACL_USER_OBJ) {
|
|
+ sid = usid;
|
|
+ sidsz = usidsz;
|
|
+ grants = OWNER_RIGHTS;
|
|
+ } else {
|
|
+ sid = find_usid(scx, pxace->id, (SID*)&defsid);
|
|
+ if (sid) {
|
|
+ sidsz = sid_size(sid);
|
|
+ /*
|
|
+ * Insert denial of complement of mask for
|
|
+ * each designated user
|
|
+ * WRITE_OWNER is inserted so that
|
|
+ * the mask can be identified
|
|
+ */
|
|
+ if (pset->mask != (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) {
|
|
+ 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++;
|
|
+ }
|
|
+ grants = WORLD_RIGHTS;
|
|
+ } 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 = 0;
|
|
+ pdace = (ACCESS_DENIED_ACE*) &secattr[offs + pos];
|
|
+ if (!adminowns) {
|
|
+ if (!groupowns) {
|
|
+ mixperms = pset->grpperms | pset->othperms;
|
|
+ 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 (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++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 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
|
|
+ | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
|
+ pset = &aceset[1];
|
|
+ pxace = &pxdesc->acl.ace[i + pxdesc->firstdef - pxdesc->acccnt];
|
|
+ } else {
|
|
+ flags = NO_PROPAGATE_INHERIT_ACE;
|
|
+ pset = &aceset[0];
|
|
+ pxace = &pxdesc->acl.ace[i];
|
|
+ }
|
|
+ tag = pxace->tag;
|
|
+ perms = pxace->perms;
|
|
+ switch (tag) {
|
|
+
|
|
+ /* compute a grant ACE for each owner or allowed user */
|
|
+
|
|
+ case POSIX_ACL_USER :
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ if (tag == POSIX_ACL_USER_OBJ) {
|
|
+ sid = usid;
|
|
+ sidsz = usidsz;
|
|
+ grants = OWNER_RIGHTS;
|
|
+ } else {
|
|
+ sid = find_usid(scx, pxace->id, (SID*)&defsid);
|
|
+ if (sid)
|
|
+ sidsz = sid_size(sid);
|
|
+ else
|
|
+ cantmap = TRUE;
|
|
+ grants = WORLD_RIGHTS;
|
|
+ }
|
|
+ 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;
|
|
+ }
|
|
+ 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++;
|
|
+ }
|
|
+ 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 */
|
|
+
|
|
+ if (tag == POSIX_ACL_GROUP_OBJ) {
|
|
+ sid = gsid;
|
|
+ sidsz = gsidsz;
|
|
+ } else {
|
|
+ sid = find_gsid(scx, pxace->id, (SID*)&defsid);
|
|
+ if (sid) {
|
|
+ sidsz = sid_size(sid);
|
|
+ /*
|
|
+ * Insert denial of complement of mask for
|
|
+ * each designated user
|
|
+ * WRITE_OWNER is inserted so that
|
|
+ * the mask can be identified
|
|
+ */
|
|
+ if (pset->mask != (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X)) {
|
|
+ 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
|
|
+ || (perms != pset->othperms)
|
|
+ || (tag == POSIX_ACL_GROUP))) {
|
|
+ grants = WORLD_RIGHTS;
|
|
+ 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 = 0;
|
|
+ pdace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
|
|
+ if (!adminowns && !groupowns) {
|
|
+ mixperms = pset->othperms;
|
|
+ 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
|
|
+ || (perms & ~pset->othperms)
|
|
+ || (tag == POSIX_ACL_GROUP)) {
|
|
+ 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++;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case POSIX_ACL_OTHER :
|
|
+
|
|
+ /* an ACE for world users */
|
|
+
|
|
+ pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
|
|
+ grants = WORLD_RIGHTS;
|
|
+ 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;
|
|
+ }
|
|
+ pgace->type = ACCESS_ALLOWED_ACE_TYPE;
|
|
+ pgace->flags = flags;
|
|
+ pgace->size = cpu_to_le16(wsidsz + 8);
|
|
+ pgace->mask = grants;
|
|
+ memcpy((char*)&pgace->sid, worldsid, wsidsz);
|
|
+ pos += wsidsz + 8;
|
|
+ acecnt++;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (cantmap)
|
|
+ errno = EINVAL;
|
|
+ else {
|
|
+ /* an ACE for administrators */
|
|
+ /* always full access */
|
|
+
|
|
+ if (isdir)
|
|
+ flags = OBJECT_INHERIT_ACE
|
|
+ | CONTAINER_INHERIT_ACE;
|
|
+ else
|
|
+ flags = NO_PROPAGATE_INHERIT_ACE;
|
|
+ pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
|
|
+ pgace->type = ACCESS_ALLOWED_ACE_TYPE;
|
|
+ pgace->flags = flags;
|
|
+ pgace->size = cpu_to_le16(asidsz + 8);
|
|
+ grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC;
|
|
+ pgace->mask = grants;
|
|
+ memcpy((char*)&pgace->sid, adminsid, asidsz);
|
|
+ pos += asidsz + 8;
|
|
+ acecnt++;
|
|
+
|
|
+ /* an ACE for system (needed ?) */
|
|
+ /* always full access */
|
|
+
|
|
+ pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
|
|
+ pgace->type = ACCESS_ALLOWED_ACE_TYPE;
|
|
+ pgace->flags = flags;
|
|
+ pgace->size = cpu_to_le16(ssidsz + 8);
|
|
+ grants = OWNER_RIGHTS | FILE_READ | FILE_WRITE | FILE_EXEC;
|
|
+ pgace->mask = grants;
|
|
+ memcpy((char*)&pgace->sid, systemsid, ssidsz);
|
|
+ pos += ssidsz + 8;
|
|
+ acecnt++;
|
|
+
|
|
+ /* a null ACE to hold special flags */
|
|
+ /* using the same representation as cygwin */
|
|
+
|
|
+ if (mode & (S_ISVTX | S_ISGID | S_ISUID)) {
|
|
+ nsidsz = sid_size(nullsid);
|
|
+ pgace = (ACCESS_ALLOWED_ACE*)&secattr[offs + pos];
|
|
+ pgace->type = ACCESS_ALLOWED_ACE_TYPE;
|
|
+ pgace->flags = NO_PROPAGATE_INHERIT_ACE;
|
|
+ pgace->size = cpu_to_le16(nsidsz + 8);
|
|
+ grants = 0;
|
|
+ if (mode & S_ISUID)
|
|
+ grants |= FILE_APPEND_DATA;
|
|
+ if (mode & S_ISGID)
|
|
+ grants |= FILE_WRITE_DATA;
|
|
+ if (mode & S_ISVTX)
|
|
+ grants |= FILE_READ_DATA;
|
|
+ pgace->mask = grants;
|
|
+ memcpy((char*)&pgace->sid, nullsid, nsidsz);
|
|
+ pos += nsidsz + 8;
|
|
+ acecnt++;
|
|
+ }
|
|
+
|
|
+ /* fix ACL header */
|
|
+ pacl->size = cpu_to_le16(pos);
|
|
+ pacl->ace_count = cpu_to_le16(acecnt);
|
|
+ }
|
|
+ return (cantmap ? 0 : pos);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+static int buildacls(char *secattr, int offs, mode_t mode, int isdir,
|
|
+ const SID * usid, const SID * gsid)
|
|
+{
|
|
+ ACL *pacl;
|
|
+ ACCESS_ALLOWED_ACE *pgace;
|
|
+ ACCESS_ALLOWED_ACE *pdace;
|
|
+ BOOL adminowns;
|
|
+ BOOL groupowns;
|
|
+ ACE_FLAGS gflags;
|
|
+ int pos;
|
|
+ int acecnt;
|
|
+ int usidsz;
|
|
+ int gsidsz;
|
|
+ int wsidsz;
|
|
+ int asidsz;
|
|
+ int ssidsz;
|
|
+ int nsidsz;
|
|
+ le32 grants;
|
|
+ le32 denials;
|
|
+
|
|
+ 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)
|
|
+ || same_sid(gsid, adminsid);
|
|
+ groupowns = !adminowns && same_sid(usid, gsid);
|
|
+
|
|
+ /* 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 = cpu_to_le16(1);
|
|
+ pacl->alignment2 = cpu_to_le16(0);
|
|
+ pos = sizeof(ACL);
|
|
+ acecnt = 0;
|
|
+
|
|
+ /* compute a grant ACE for owner */
|
|
+ /* 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;
|
|
+ }
|
|
+
|
|
+ /* 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))
|
|
@@ -2638,6 +3968,108 @@
|
|
return (pos);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Build a full security descriptor from a Posix ACL
|
|
+ * returns descriptor in allocated memory, must free() after use
|
|
+ */
|
|
+
|
|
+static char *build_secur_descr_posix(struct SECURITY_CONTEXT *scx,
|
|
+ struct POSIX_SECURITY *pxdesc,
|
|
+ int isdir, const SID *usid, const SID *gsid)
|
|
+{
|
|
+ int newattrsz;
|
|
+ SECURITY_DESCRIPTOR_RELATIVE *pnhead;
|
|
+ char *newattr;
|
|
+ int aclsz;
|
|
+ int usidsz;
|
|
+ int gsidsz;
|
|
+ int wsidsz;
|
|
+ int asidsz;
|
|
+ int ssidsz;
|
|
+ int k;
|
|
+
|
|
+ usidsz = sid_size(usid);
|
|
+ gsidsz = sid_size(gsid);
|
|
+ wsidsz = sid_size(worldsid);
|
|
+ asidsz = sid_size(adminsid);
|
|
+ ssidsz = sid_size(systemsid);
|
|
+
|
|
+ /* allocate enough space for the new security attribute */
|
|
+ newattrsz = sizeof(SECURITY_DESCRIPTOR_RELATIVE) /* header */
|
|
+ + usidsz + gsidsz /* usid and gsid */
|
|
+ + sizeof(ACL) /* acl header */
|
|
+ + 2*(8 + usidsz) /* two possible ACE for user */
|
|
+ + 2*(8 + gsidsz) /* two possible ACE for group */
|
|
+ + 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 */
|
|
+ for (k=0; k<pxdesc->acccnt; k++) {
|
|
+ if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER)
|
|
+ || (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP))
|
|
+ newattrsz += 3*40; /* fixme : maximum size */
|
|
+ }
|
|
+ /* account for default ACE's */
|
|
+ newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */
|
|
+ newattr = (char*)ntfs_malloc(newattrsz);
|
|
+ if (newattr) {
|
|
+ /* build the main header part */
|
|
+ pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
|
|
+ pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
|
|
+ pnhead->alignment = 0;
|
|
+ /*
|
|
+ * The flag SE_DACL_PROTECTED prevents the ACL
|
|
+ * to be changed in an inheritance after creation
|
|
+ */
|
|
+ pnhead->control = SE_DACL_PRESENT | SE_DACL_PROTECTED
|
|
+ | SE_SELF_RELATIVE;
|
|
+ /*
|
|
+ * Windows prefers ACL first, do the same to
|
|
+ * get the same hash value and avoid duplication
|
|
+ */
|
|
+ /* build permissions */
|
|
+ aclsz = buildacls_posix(scx,newattr,
|
|
+ sizeof(SECURITY_DESCRIPTOR_RELATIVE),
|
|
+ pxdesc, isdir, usid, gsid);
|
|
+ if (aclsz && ((aclsz + usidsz + gsidsz) <= newattrsz)) {
|
|
+ /* append usid and gsid */
|
|
+ memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE)
|
|
+ + aclsz], usid, usidsz);
|
|
+ memcpy(&newattr[sizeof(SECURITY_DESCRIPTOR_RELATIVE)
|
|
+ + aclsz + usidsz], gsid, gsidsz);
|
|
+ /* positions of ACL, USID and GSID into header */
|
|
+ pnhead->owner =
|
|
+ cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)
|
|
+ + aclsz);
|
|
+ pnhead->group =
|
|
+ cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)
|
|
+ + aclsz + usidsz);
|
|
+ pnhead->sacl = cpu_to_le32(0);
|
|
+ pnhead->dacl =
|
|
+ cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
|
+ } else {
|
|
+ /* ACL failure (errno set) or overflow */
|
|
+ free(newattr);
|
|
+ newattr = (char*)NULL;
|
|
+ if (aclsz) {
|
|
+ /* hope error was detected before overflowing */
|
|
+ ntfs_log_error("Security descriptor is longer than expected\n");
|
|
+ errno = EIO;
|
|
+ }
|
|
+ }
|
|
+ } else
|
|
+ errno = ENOMEM;
|
|
+ return (newattr);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* Build a full security descriptor
|
|
* returns descriptor in allocated memory, must free() after use
|
|
@@ -2819,6 +4251,151 @@
|
|
return (perm);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Normalize a Posix ACL either from a sorted raw set of
|
|
+ * access ACEs or default ACEs
|
|
+ * (standard case : different owner, group and administrator)
|
|
+ */
|
|
+
|
|
+static int norm_std_permissions_posix(struct POSIX_SECURITY *posix_desc,
|
|
+ BOOL groupowns, int start, int count, int target)
|
|
+{
|
|
+ int j,k;
|
|
+ s32 id;
|
|
+ u16 tag;
|
|
+ u16 tagsset;
|
|
+ struct POSIX_ACE *pxace;
|
|
+ mode_t grantgrps;
|
|
+ mode_t grantwrld;
|
|
+ mode_t denywrld;
|
|
+ mode_t allow;
|
|
+ mode_t deny;
|
|
+ mode_t perms;
|
|
+ mode_t mode;
|
|
+
|
|
+ mode = 0;
|
|
+ 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) {
|
|
+ /* 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 :
|
|
+ grantgrps |= pxace[j].perms;
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ grantwrld = pxace[j].perms;
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
+ * Collect groups of ACEs related to the same id
|
|
+ * and determine what is granted and what is denied.
|
|
+ * It is important the ACEs have been sorted
|
|
+ */
|
|
+ j = start;
|
|
+ k = target;
|
|
+ while (j < (start + count)) {
|
|
+ tag = pxace[j].tag;
|
|
+ id = pxace[j].id;
|
|
+ if (pxace[j].perms & POSIX_PERM_DENIAL) {
|
|
+ deny = pxace[j].perms | denywrld;
|
|
+ allow = 0;
|
|
+ } else {
|
|
+ deny = denywrld;
|
|
+ allow = pxace[j].perms;
|
|
+ }
|
|
+ j++;
|
|
+ while ((j < (start + count))
|
|
+ && (pxace[j].tag == tag)
|
|
+ && (pxace[j].id == id)) {
|
|
+ if (pxace[j].perms & POSIX_PERM_DENIAL)
|
|
+ deny |= pxace[j].perms;
|
|
+ else
|
|
+ allow |= pxace[j].perms;
|
|
+ j++;
|
|
+ }
|
|
+ /*
|
|
+ * Build the permissions equivalent to grants and denials
|
|
+ */
|
|
+ if (groupowns) {
|
|
+ if (tag == POSIX_ACL_MASK)
|
|
+ perms = ~deny;
|
|
+ else
|
|
+ perms = allow & ~deny;
|
|
+ } else
|
|
+ switch (tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ case POSIX_ACL_USER :
|
|
+ perms = (allow | grantgrps | grantwrld) & ~deny;
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ case POSIX_ACL_GROUP :
|
|
+ perms = (allow | grantwrld) & ~deny;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ perms = ~deny;
|
|
+ break;
|
|
+ default :
|
|
+ perms = allow & ~deny;
|
|
+ break;
|
|
+ }
|
|
+ /*
|
|
+ * Store into a Posix ACE
|
|
+ */
|
|
+ if (tag != POSIX_ACL_SPECIAL) {
|
|
+ pxace[k].tag = tag;
|
|
+ pxace[k].id = id;
|
|
+ pxace[k].perms = perms
|
|
+ & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X);
|
|
+ tagsset |= tag;
|
|
+ k++;
|
|
+ }
|
|
+ switch (tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ mode |= ((perms & 7) << 6);
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ case POSIX_ACL_MASK :
|
|
+ mode = (mode & 07707) | ((perms & 7) << 3);
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ mode |= perms & 7;
|
|
+ break;
|
|
+ case POSIX_ACL_SPECIAL :
|
|
+ mode |= (perms & (S_ISVTX | S_ISUID | S_ISGID));
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!start) { /* not satisfactory */
|
|
+ posix_desc->mode = mode;
|
|
+ posix_desc->tagsset = tagsset;
|
|
+ }
|
|
+ return (k - target);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* Interpret an ACL and extract meaningful grants
|
|
* (standard case : different owner, group and administrator)
|
|
@@ -2974,6 +4551,119 @@
|
|
special));
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Normalize a Posix ACL either from a sorted raw set of
|
|
+ * access ACEs or default ACEs
|
|
+ * (special case : owner or/and group is administrator)
|
|
+ */
|
|
+
|
|
+static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc,
|
|
+ int start, int count, int target)
|
|
+{
|
|
+ int j,k;
|
|
+ s32 id;
|
|
+ u16 tag;
|
|
+ u16 tagsset;
|
|
+ struct POSIX_ACE *pxace;
|
|
+ int acccnt;
|
|
+ mode_t denywrld;
|
|
+ mode_t allow;
|
|
+ mode_t deny;
|
|
+ mode_t perms;
|
|
+ mode_t mode;
|
|
+
|
|
+ mode = 0;
|
|
+ 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)
|
|
+ * It is important the ACEs have been sorted
|
|
+ */
|
|
+ j = start;
|
|
+ k = target;
|
|
+ deny = 0;
|
|
+ while (j < (start + count)) {
|
|
+ allow = 0;
|
|
+ tag = pxace[j].tag;
|
|
+ id = pxace[j].id;
|
|
+ if (tag == POSIX_ACL_MASK) {
|
|
+ deny = pxace[j].perms;
|
|
+ j++;
|
|
+ while ((j < (start + count))
|
|
+ && (pxace[j].tag == POSIX_ACL_MASK))
|
|
+ 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++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Store the grants into a Posix ACE
|
|
+ */
|
|
+ if (tag == POSIX_ACL_MASK)
|
|
+ perms = ~deny;
|
|
+ else
|
|
+ perms = allow & ~denywrld;
|
|
+ if (tag != POSIX_ACL_SPECIAL) {
|
|
+ pxace[k].tag = tag;
|
|
+ pxace[k].id = id;
|
|
+ pxace[k].perms = perms
|
|
+ & (POSIX_PERM_R | POSIX_PERM_W | POSIX_PERM_X);
|
|
+ tagsset |= tag;
|
|
+ k++;
|
|
+ }
|
|
+ switch (tag) {
|
|
+ case POSIX_ACL_USER_OBJ :
|
|
+ mode |= ((perms & 7) << 6);
|
|
+ break;
|
|
+ case POSIX_ACL_GROUP_OBJ :
|
|
+ case POSIX_ACL_MASK :
|
|
+ mode = (mode & 07707) | ((perms & 7) << 3);
|
|
+ break;
|
|
+ case POSIX_ACL_OTHER :
|
|
+ mode |= perms & 7;
|
|
+ break;
|
|
+ case POSIX_ACL_SPECIAL :
|
|
+ mode |= perms & (S_ISVTX | S_ISUID | S_ISGID);
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!start) { /* not satisfactory */
|
|
+ posix_desc->mode = mode;
|
|
+ posix_desc->tagsset = tagsset;
|
|
+ }
|
|
+ return (k - target);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* Interpret an ACL and extract meaningful grants
|
|
* (special case : owner or/and group is administrator)
|
|
@@ -3041,8 +4731,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 +4842,374 @@
|
|
|
|
#endif
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Build Posix permissions from an ACL
|
|
+ * returns a pointer to the requested permissions
|
|
+ * or a null pointer (with errno set) if there is a problem
|
|
+ */
|
|
+
|
|
+static struct POSIX_SECURITY *build_permissions_posix(struct SECURITY_CONTEXT *scx,
|
|
+ const char *securattr,
|
|
+ const SID *usid, const SID *gsid, ntfs_inode *ni)
|
|
+{
|
|
+ const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+ const ACL *pacl;
|
|
+ const ACCESS_ALLOWED_ACE *pace;
|
|
+ struct POSIX_ACE *pxace;
|
|
+ struct {
|
|
+ uid_t prevuid;
|
|
+ gid_t prevgid;
|
|
+ BOOL groupmask;
|
|
+ s16 tagsset;
|
|
+ mode_t permswrld;
|
|
+ } ctx[2], *pctx;
|
|
+ int offdacl;
|
|
+ int offace;
|
|
+ int alloccnt;
|
|
+ int acecnt;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+ int i,j;
|
|
+ int k,l;
|
|
+ BOOL ignore;
|
|
+ BOOL adminowns;
|
|
+ BOOL groupowns;
|
|
+ BOOL firstinh;
|
|
+
|
|
+ phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
|
|
+ offdacl = le32_to_cpu(phead->dacl);
|
|
+ if (offdacl) {
|
|
+ pacl = (const ACL*)&securattr[offdacl];
|
|
+ acecnt = le16_to_cpu(pacl->ace_count);
|
|
+ offace = offdacl + sizeof(ACL);
|
|
+ } else {
|
|
+ acecnt = 0;
|
|
+ offace = 0;
|
|
+ }
|
|
+ adminowns = FALSE;
|
|
+ groupowns = same_sid(gsid,usid);
|
|
+ firstinh = FALSE;
|
|
+ /*
|
|
+ * Build a raw posix security descriptor
|
|
+ * 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 1 more for other
|
|
+ */
|
|
+ alloccnt = acecnt + 5;
|
|
+ pxdesc = (struct POSIX_SECURITY*)malloc(
|
|
+ sizeof(struct POSIX_SECURITY)
|
|
+ + alloccnt*sizeof(struct POSIX_ACE));
|
|
+ k = 0;
|
|
+ l = alloccnt;
|
|
+ for (i=0; i<2; i++) {
|
|
+ ctx[i].permswrld = 0;
|
|
+ ctx[i].prevuid = -1;
|
|
+ ctx[i].prevgid = -1;
|
|
+ ctx[i].groupmask = FALSE;
|
|
+ ctx[i].tagsset = 0;
|
|
+ }
|
|
+ for (j=0; j<acecnt; j++) {
|
|
+ pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
|
|
+ if (pace->flags & INHERIT_ONLY_ACE) {
|
|
+ pxace = &pxdesc->acl.ace[l - 1];
|
|
+ pctx = &ctx[1];
|
|
+ } else {
|
|
+ pxace = &pxdesc->acl.ace[k];
|
|
+ pctx = &ctx[0];
|
|
+ }
|
|
+ ignore = FALSE;
|
|
+ if (same_sid(usid, &pace->sid)) {
|
|
+ pxace->id = -1;
|
|
+ /*
|
|
+ * Owner has no write-owner right :
|
|
+ * a group was defined same as owner
|
|
+ * or admin was owner or group :
|
|
+ * denials are meant to owner
|
|
+ * and grants are meant to group
|
|
+ */
|
|
+ if (!(pace->mask & WRITE_OWNER)
|
|
+ && (pace->type == ACCESS_ALLOWED_ACE_TYPE)) {
|
|
+ if (same_sid(gsid,usid)) {
|
|
+ pxace->tag = POSIX_ACL_GROUP_OBJ;
|
|
+ pxace->id = -1;
|
|
+ } else {
|
|
+ if (same_sid(&pace->sid,usid))
|
|
+ groupowns = TRUE;
|
|
+ gid = findgroup(scx,&pace->sid);
|
|
+ if (gid) {
|
|
+ pxace->tag = POSIX_ACL_GROUP;
|
|
+ pxace->id = gid;
|
|
+ pctx->prevgid = gid;
|
|
+ } else
|
|
+ ignore = TRUE;
|
|
+ }
|
|
+ } else {
|
|
+ /* system ignored, and admin */
|
|
+ /* ignored at first position */
|
|
+ pxace->tag = POSIX_ACL_USER_OBJ;
|
|
+ if (pace->flags & INHERIT_ONLY_ACE) {
|
|
+ if ((firstinh && same_sid(&pace->sid,adminsid))
|
|
+ || same_sid(&pace->sid,systemsid))
|
|
+ ignore = TRUE;
|
|
+ if (!firstinh) {
|
|
+ firstinh = TRUE;
|
|
+ }
|
|
+ } else {
|
|
+ if ((adminowns && same_sid(&pace->sid,adminsid))
|
|
+ || same_sid(&pace->sid,systemsid))
|
|
+ ignore = TRUE;
|
|
+ if (same_sid(usid,adminsid))
|
|
+ adminowns = TRUE;
|
|
+ }
|
|
+ }
|
|
+ } else if (same_sid(gsid, &pace->sid)) {
|
|
+ pxace->id = -1;
|
|
+ pxace->tag = POSIX_ACL_GROUP_OBJ;
|
|
+ if (same_sid(gsid,adminsid)) {
|
|
+ adminowns = TRUE;
|
|
+ if (pace->mask & WRITE_OWNER)
|
|
+ ignore = TRUE;
|
|
+ }
|
|
+ } else if (is_world_sid((const SID*)&pace->sid)) {
|
|
+ pxace->id = -1;
|
|
+ pxace->tag = POSIX_ACL_OTHER;
|
|
+ if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
|
+ && (pace->flags & INHERIT_ONLY_ACE))
|
|
+ ignore = TRUE;
|
|
+ } else if (same_sid((const SID*)&pace->sid,nullsid)) {
|
|
+ pxace->id = -1;
|
|
+ pxace->tag = POSIX_ACL_SPECIAL;
|
|
+ } else {
|
|
+ uid = findowner(scx,&pace->sid);
|
|
+ if (uid) {
|
|
+ if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
|
+ && (pace->mask & WRITE_OWNER)
|
|
+ && (pctx->prevuid != uid)) {
|
|
+ pxace->id = -1;
|
|
+ pxace->tag = POSIX_ACL_MASK;
|
|
+ } else {
|
|
+ pxace->id = uid;
|
|
+ pxace->tag = POSIX_ACL_USER;
|
|
+ }
|
|
+ pctx->prevuid = uid;
|
|
+ } else {
|
|
+ gid = findgroup(scx,&pace->sid);
|
|
+ if (gid) {
|
|
+ if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
|
+ && (pace->mask & WRITE_OWNER)
|
|
+ && (pctx->prevgid != gid)) {
|
|
+ pxace->tag = POSIX_ACL_MASK;
|
|
+ pctx->groupmask = TRUE;
|
|
+ } else {
|
|
+ pxace->tag = POSIX_ACL_GROUP;
|
|
+ }
|
|
+ pxace->id = gid;
|
|
+ pctx->prevgid = gid;
|
|
+ } else {
|
|
+ /*
|
|
+ * do not grant rights to unknown
|
|
+ * people and do not define root as a
|
|
+ * designated user or group
|
|
+ */
|
|
+ ignore = TRUE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (!ignore) {
|
|
+ pxace->perms = 0;
|
|
+ /* specific decoding for vtx/uid/gid */
|
|
+ if (pxace->tag == POSIX_ACL_SPECIAL) {
|
|
+ if (pace->mask & FILE_APPEND_DATA)
|
|
+ pxace->perms |= S_ISUID;
|
|
+ if (pace->mask & FILE_WRITE_DATA)
|
|
+ pxace->perms |= S_ISGID;
|
|
+ if (pace->mask & FILE_READ_DATA)
|
|
+ pxace->perms |= S_ISVTX;
|
|
+ } else
|
|
+ if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
|
+ if (pace->mask & DIR_GEXEC)
|
|
+ pxace->perms |= POSIX_PERM_X;
|
|
+ if (pace->mask & DIR_GWRITE)
|
|
+ pxace->perms |= POSIX_PERM_W;
|
|
+ if (pace->mask & DIR_GREAD)
|
|
+ pxace->perms |= POSIX_PERM_R;
|
|
+ } else {
|
|
+ if (pace->mask & FILE_GEXEC)
|
|
+ pxace->perms |= POSIX_PERM_X;
|
|
+ if (pace->mask & FILE_GWRITE)
|
|
+ pxace->perms |= POSIX_PERM_W;
|
|
+ if (pace->mask & FILE_GREAD)
|
|
+ pxace->perms |= POSIX_PERM_R;
|
|
+ }
|
|
+
|
|
+ if (pace->type != ACCESS_ALLOWED_ACE_TYPE)
|
|
+ pxace->perms |= POSIX_PERM_DENIAL;
|
|
+ else
|
|
+ if (pxace->tag == POSIX_ACL_OTHER)
|
|
+ pctx->permswrld = pxace->perms;
|
|
+ pctx->tagsset |= pxace->tag;
|
|
+ if (pace->flags & INHERIT_ONLY_ACE) {
|
|
+ l--;
|
|
+ } else {
|
|
+ k++;
|
|
+ }
|
|
+
|
|
+
|
|
+ }
|
|
+ offace += le16_to_cpu(pace->size);
|
|
+ }
|
|
+ /*
|
|
+ * Create world perms if none (access ACE only)
|
|
+ */
|
|
+ if (!(ctx[0].tagsset & POSIX_ACL_OTHER)) {
|
|
+ pxace = &pxdesc->acl.ace[k];
|
|
+ pxace->tag = POSIX_ACL_OTHER;
|
|
+ pxace->id = -1;
|
|
+ pxace->perms = 0;
|
|
+ ctx[0].tagsset |= POSIX_ACL_OTHER;
|
|
+ ctx[0].permswrld = 0;
|
|
+ k++;
|
|
+ }
|
|
+ /*
|
|
+ * 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
|
|
+ */
|
|
+ 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
|
|
+ */
|
|
+ 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 (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[j].id;
|
|
+ pxace->perms = ctx[0].permswrld;
|
|
+ ctx[0].tagsset |= POSIX_ACL_GROUP;
|
|
+ k++;
|
|
+ }
|
|
+ if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK)
|
|
+ pxdesc->acl.ace[j].id = -1;
|
|
+ }
|
|
+ }
|
|
+ if (ctx[1].groupmask) {
|
|
+ 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[j].id;
|
|
+ pxace->perms = ctx[1].permswrld;
|
|
+ ctx[1].tagsset |= POSIX_ACL_GROUP;
|
|
+ l--;
|
|
+ }
|
|
+ if (pxdesc->acl.ace[j].tag == POSIX_ACL_MASK)
|
|
+ pxdesc->acl.ace[j].id = -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Insert default mask if none present and
|
|
+ * there are designated users or groups
|
|
+ * (the space for it has not beed used)
|
|
+ */
|
|
+ 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;
|
|
+ free(pxdesc);
|
|
+ pxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+ } else {
|
|
+ pxdesc->acccnt = k;
|
|
+ pxdesc->defcnt = alloccnt - l;
|
|
+ pxdesc->firstdef = l;
|
|
+ pxdesc->tagsset = ctx[0].tagsset;
|
|
+ pxdesc->acl.version = POSIX_VERSION;
|
|
+ pxdesc->acl.flags = 0;
|
|
+ pxdesc->acl.filler = 0;
|
|
+ sort_posix(pxdesc);
|
|
+ if (adminowns) {
|
|
+ k = norm_ownadmin_permissions_posix(pxdesc,
|
|
+ 0, pxdesc->acccnt, 0);
|
|
+ pxdesc->acccnt = k;
|
|
+ l = norm_ownadmin_permissions_posix(pxdesc,
|
|
+ pxdesc->firstdef, pxdesc->defcnt, k);
|
|
+ pxdesc->firstdef = k;
|
|
+ pxdesc->defcnt = l;
|
|
+ } else {
|
|
+ k = norm_std_permissions_posix(pxdesc,groupowns,
|
|
+ 0, pxdesc->acccnt, 0);
|
|
+ pxdesc->acccnt = k;
|
|
+ l = norm_std_permissions_posix(pxdesc,groupowns,
|
|
+ pxdesc->firstdef, pxdesc->defcnt, k);
|
|
+ pxdesc->firstdef = k;
|
|
+ pxdesc->defcnt = l;
|
|
+ }
|
|
+ }
|
|
+ if (pxdesc && !valid_posix(pxdesc)) {
|
|
+ ntfs_log_error("Invalid Posix descriptor built\n");
|
|
+ errno = EIO;
|
|
+ free(pxdesc);
|
|
+ pxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+ }
|
|
+ return (pxdesc);
|
|
+}
|
|
+
|
|
+#endif
|
|
/*
|
|
* Build unix-style (mode_t) permissions from an ACL
|
|
* returns the requested permissions
|
|
@@ -3241,6 +5299,80 @@
|
|
return (securattr);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+static int access_check_posix(struct SECURITY_CONTEXT *scx,
|
|
+ struct POSIX_SECURITY *pxdesc, mode_t request,
|
|
+ uid_t uid, gid_t gid)
|
|
+{
|
|
+ struct POSIX_ACE *pxace;
|
|
+ int userperms;
|
|
+ int groupperms;
|
|
+ int mask;
|
|
+ BOOL somegroup;
|
|
+ mode_t perms;
|
|
+ int i;
|
|
+
|
|
+ perms = pxdesc->mode;
|
|
+ /* owner */
|
|
+ if (uid == scx->uid)
|
|
+ perms &= 07700;
|
|
+ else {
|
|
+ /* analyze designated users and get mask */
|
|
+ userperms = -1;
|
|
+ groupperms = -1;
|
|
+ mask = 7;
|
|
+ for (i=pxdesc->acccnt-1; i>=0 ; i--) {
|
|
+ pxace = &pxdesc->acl.ace[i];
|
|
+ switch (pxace->tag) {
|
|
+ case POSIX_ACL_USER :
|
|
+ if ((uid_t)pxace->id == scx->uid)
|
|
+ userperms = pxace->perms;
|
|
+ break;
|
|
+ case POSIX_ACL_MASK :
|
|
+ mask = pxace->perms & 7;
|
|
+ break;
|
|
+ default :
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ /* designated users */
|
|
+ if (userperms >= 0)
|
|
+ perms = (perms & 07000) + (userperms & mask);
|
|
+ else {
|
|
+ /* owning group */
|
|
+ if (!(~(perms >> 3) & request & mask)
|
|
+ && ((gid == scx->gid)
|
|
+ || groupmember(scx, scx->uid, gid)))
|
|
+ perms &= 07070;
|
|
+ else {
|
|
+ /* other groups */
|
|
+ groupperms = -1;
|
|
+ somegroup = FALSE;
|
|
+ for (i=pxdesc->acccnt-1; i>=0 ; i--) {
|
|
+ pxace = &pxdesc->acl.ace[i];
|
|
+ if ((pxace->tag == POSIX_ACL_GROUP)
|
|
+ && groupmember(scx, uid, pxace->id)) {
|
|
+ if (!(~pxace->perms & request & mask))
|
|
+ groupperms = pxace->perms;
|
|
+ somegroup = TRUE;
|
|
+ }
|
|
+ }
|
|
+ if (groupperms >= 0)
|
|
+ perms = (perms & 07000) + (groupperms & mask);
|
|
+ else
|
|
+ if (somegroup)
|
|
+ perms = 0;
|
|
+ else
|
|
+ perms &= 07007;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return (perms);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
/*
|
|
* Get permissions to access a file
|
|
* Takes into account the relation of user to file (owner, group, ...)
|
|
@@ -3249,8 +5381,13 @@
|
|
* returns -1 if there is a problem
|
|
*/
|
|
|
|
+#if POSIXACLS
|
|
+static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
|
|
+ const char *path, ntfs_inode * ni, mode_t request)
|
|
+#else
|
|
static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
|
|
const char *path, ntfs_inode * ni)
|
|
+#endif
|
|
{
|
|
const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
|
const struct CACHED_PERMISSIONS *cached;
|
|
@@ -3260,6 +5397,9 @@
|
|
uid_t uid;
|
|
gid_t gid;
|
|
int perm;
|
|
+#if POSIXACLS
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+#endif
|
|
|
|
if (!scx->usermapping || !scx->uid)
|
|
perm = 07777;
|
|
@@ -3267,9 +5407,15 @@
|
|
/* check whether available in cache */
|
|
cached = fetch_cache(scx,ni);
|
|
if (cached) {
|
|
+#if POSIXACLS
|
|
+ uid = cached->uid;
|
|
+ gid = cached->gid;
|
|
+ perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
|
|
+#else
|
|
perm = cached->mode;
|
|
uid = cached->uid;
|
|
gid = cached->gid;
|
|
+#endif
|
|
} else {
|
|
perm = 0; /* default to no permission */
|
|
securattr = getsecurityattr(scx->vol, path, ni);
|
|
@@ -3281,14 +5427,32 @@
|
|
gid = findgroup(scx,gsid);
|
|
#if OWNERFROMACL
|
|
usid = acl_owner(securattr);
|
|
+#if POSIXACLS
|
|
+ pxdesc = build_permissions_posix(scx,securattr,
|
|
+ usid, gsid, ni);
|
|
+ if (pxdesc)
|
|
+ perm = pxdesc->mode & 07777;
|
|
+ else
|
|
+ perm = -1;
|
|
+#else
|
|
perm = build_permissions(securattr,
|
|
usid, gsid, ni);
|
|
+#endif
|
|
uid = findowner(scx,usid);
|
|
#else
|
|
usid = (const SID*)&
|
|
securattr[le32_to_cpu(phead->owner)];
|
|
+#if POSIXACLS
|
|
+ pxdesc = build_permissions_posix(scx,securattr,
|
|
+ usid, gsid, ni);
|
|
+ if (pxdesc)
|
|
+ perm = pxdesc->mode & 07777;
|
|
+ else
|
|
+ perm = -1;
|
|
+#else
|
|
perm = build_permissions(securattr,
|
|
usid, gsid, ni);
|
|
+#endif
|
|
if (!perm && same_sid(usid, adminsid)) {
|
|
uid = find_tenant(scx, securattr);
|
|
if (uid)
|
|
@@ -3313,29 +5477,165 @@
|
|
}
|
|
if (test_nino_flag(ni, v3_Extensions)
|
|
&& (perm >= 0)) {
|
|
+#if POSIXACLS
|
|
+ enter_cache(scx, ni, uid,
|
|
+ gid, pxdesc);
|
|
+#else
|
|
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;
|
|
+ }
|
|
+ }
|
|
+#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;
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ return (perm);
|
|
+}
|
|
+
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Get a Posix ACL
|
|
+ * returns size or -errno if there is a problem
|
|
+ */
|
|
+
|
|
+int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, char *value, size_t size,
|
|
+ ntfs_inode *ni)
|
|
+{
|
|
+ const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+ const struct CACHED_PERMISSIONS *cached;
|
|
+ char *securattr;
|
|
+ const SID *usid; /* owner of file/directory */
|
|
+ const SID *gsid; /* group of file/directory */
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+ int perm;
|
|
+ size_t outsize;
|
|
+
|
|
+ outsize = 0; /* default to error */
|
|
+ if (!scx->usermapping)
|
|
+ errno = ENOTSUP;
|
|
+ else {
|
|
+ /* check whether available in cache */
|
|
+ cached = fetch_cache(scx,ni);
|
|
+ if (cached)
|
|
+ pxdesc = cached->pxdesc;
|
|
+ else {
|
|
+ securattr = getsecurityattr(scx->vol, path, ni);
|
|
+ if (securattr) {
|
|
+ phead =
|
|
+ (const SECURITY_DESCRIPTOR_RELATIVE*)
|
|
+ securattr;
|
|
+ gsid = (const SID*)&
|
|
+ securattr[le32_to_cpu(phead->group)];
|
|
+#if OWNERFROMACL
|
|
+ usid = acl_owner(securattr);
|
|
+#else
|
|
+ usid = (const SID*)&
|
|
+ securattr[le32_to_cpu(phead->owner)];
|
|
+#endif
|
|
+ pxdesc = build_permissions_posix(scx,securattr,
|
|
+ usid, gsid, ni);
|
|
+
|
|
+ /*
|
|
+ * fetch owner and group for cacheing
|
|
+ */
|
|
+ if (pxdesc) {
|
|
+ perm = pxdesc->mode & 07777;
|
|
+ /*
|
|
+ * Create a security id if there were none
|
|
+ * and upgrade option is selected
|
|
+ */
|
|
+ if (!test_nino_flag(ni, v3_Extensions)
|
|
+ && (scx->vol->secure_flags
|
|
+ & (1 << SECURITY_ADDSECURIDS))) {
|
|
+ upgrade_secur_desc(scx->vol,
|
|
+ path, securattr, ni);
|
|
+ }
|
|
+#if OWNERFROMACL
|
|
+ uid = findowner(scx,usid);
|
|
+#else
|
|
+ if (!perm && same_sid(usid, adminsid)) {
|
|
+ uid = find_tenant(scx,
|
|
+ securattr);
|
|
+ if (uid)
|
|
+ perm = 0700;
|
|
+ } else
|
|
+ uid = findowner(scx,usid);
|
|
+#endif
|
|
+ gid = findgroup(scx,gsid);
|
|
+ if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
|
|
+ enter_cache(scx, ni, uid,
|
|
+ gid, pxdesc);
|
|
}
|
|
free(securattr);
|
|
+ } else
|
|
+ pxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+ }
|
|
+
|
|
+ if (pxdesc) {
|
|
+ if (valid_posix(pxdesc)) {
|
|
+ if (!strcmp(name,"system.posix_acl_default")) {
|
|
+ outsize = sizeof(struct POSIX_ACL)
|
|
+ + pxdesc->defcnt*sizeof(struct POSIX_ACE);
|
|
+ if (outsize <= size) {
|
|
+ memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
|
|
+ memcpy(&value[sizeof(struct POSIX_ACL)],
|
|
+ &pxdesc->acl.ace[pxdesc->firstdef],
|
|
+ outsize-sizeof(struct POSIX_ACL));
|
|
+ } else {
|
|
+ outsize = 0;
|
|
+ errno = ENOSPC;
|
|
+ }
|
|
+ } else {
|
|
+ outsize = sizeof(struct POSIX_ACL)
|
|
+ + pxdesc->acccnt*sizeof(struct POSIX_ACE);
|
|
+ if (outsize <= size)
|
|
+ memcpy(value,&pxdesc->acl,outsize);
|
|
+ else {
|
|
+ outsize = 0;
|
|
+ errno = ENOSPC;
|
|
+ }
|
|
+ }
|
|
} else {
|
|
- perm = -1;
|
|
- uid = gid = 0;
|
|
+ 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
|
|
+ outsize = 0;
|
|
}
|
|
- return (perm);
|
|
+ return (outsize ? (int)outsize : -errno);
|
|
}
|
|
|
|
+#endif
|
|
+
|
|
/*
|
|
* Get owner, group and permissions in an stat structure
|
|
* returns permissions, or -1 if there is a problem
|
|
@@ -3351,6 +5651,9 @@
|
|
const SID *gsid; /* group of file/directory */
|
|
const struct CACHED_PERMISSIONS *cached;
|
|
int perm;
|
|
+#if POSIXACLS
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+#endif
|
|
|
|
if (!scx->usermapping)
|
|
perm = 07777;
|
|
@@ -3377,8 +5680,17 @@
|
|
usid = (const SID*)&
|
|
securattr[le32_to_cpu(phead->owner)];
|
|
#endif
|
|
+#if POSIXACLS
|
|
+ pxdesc = build_permissions_posix(scx, securattr,
|
|
+ usid, gsid, ni);
|
|
+ if (pxdesc)
|
|
+ perm = pxdesc->mode & 07777;
|
|
+ else
|
|
+ perm = -1;
|
|
+#else
|
|
perm = build_permissions(securattr,
|
|
usid, gsid, ni);
|
|
+#endif
|
|
/*
|
|
* fetch owner and group for cacheing
|
|
*/
|
|
@@ -3408,8 +5720,14 @@
|
|
stbuf->st_gid = findgroup(scx,gsid);
|
|
stbuf->st_mode =
|
|
(stbuf->st_mode & ~07777) + perm;
|
|
+#if POSIXACLS
|
|
+ enter_cache(scx, ni, stbuf->st_uid,
|
|
+ stbuf->st_gid, pxdesc);
|
|
+ free(pxdesc);
|
|
+#else
|
|
enter_cache(scx, ni, stbuf->st_uid,
|
|
stbuf->st_gid, perm);
|
|
+#endif
|
|
}
|
|
free(securattr);
|
|
}
|
|
@@ -3418,6 +5736,87 @@
|
|
return (perm);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Get the base for a Posix inheritance and
|
|
+ * build an inherited Posix descriptor
|
|
+ */
|
|
+
|
|
+static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
|
|
+ const char *dir_path, ntfs_inode *dir_ni,
|
|
+ mode_t mode, BOOL isdir)
|
|
+{
|
|
+ const struct CACHED_PERMISSIONS *cached;
|
|
+ const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+ struct POSIX_SECURITY *pydesc;
|
|
+ char *securattr;
|
|
+ const SID *usid;
|
|
+ const SID *gsid;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+
|
|
+ pydesc = (struct POSIX_SECURITY*)NULL;
|
|
+ /* check whether parent directory is available in cache */
|
|
+ cached = fetch_cache(scx,dir_ni);
|
|
+ if (cached) {
|
|
+ uid = cached->uid;
|
|
+ gid = cached->gid;
|
|
+ pxdesc = cached->pxdesc;
|
|
+ if (pxdesc) {
|
|
+ pydesc = build_inherited_posix(pxdesc,mode,isdir);
|
|
+ }
|
|
+ } else {
|
|
+ securattr = getsecurityattr(scx->vol, dir_path, dir_ni);
|
|
+ if (securattr) {
|
|
+ phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
|
|
+ securattr;
|
|
+ gsid = (const SID*)&
|
|
+ securattr[le32_to_cpu(phead->group)];
|
|
+ gid = findgroup(scx,gsid);
|
|
+#if OWNERFROMACL
|
|
+ usid = acl_owner(securattr);
|
|
+ pxdesc = build_permissions_posix(scx,securattr,
|
|
+ usid, gsid, dir_ni);
|
|
+ uid = findowner(scx,usid);
|
|
+#else
|
|
+ usid = (const SID*)&
|
|
+ securattr[le32_to_cpu(phead->owner)];
|
|
+ pxdesc = build_permissions_posix(scx,securattr,
|
|
+ usid, gsid, dir_ni);
|
|
+ if (pxdesc && same_sid(usid, adminsid)) {
|
|
+ uid = find_tenant(scx, securattr);
|
|
+ } else
|
|
+ uid = findowner(scx,usid);
|
|
+#endif
|
|
+ if (pxdesc) {
|
|
+ /*
|
|
+ * Create a security id if there were none
|
|
+ * and upgrade option is selected
|
|
+ */
|
|
+ if (!test_nino_flag(dir_ni, v3_Extensions)
|
|
+ && (scx->vol->secure_flags
|
|
+ & (1 << SECURITY_ADDSECURIDS))) {
|
|
+ upgrade_secur_desc(scx->vol, dir_path,
|
|
+ securattr, dir_ni);
|
|
+ /*
|
|
+ * fetch owner and group for cacheing
|
|
+ * if there is a securid
|
|
+ */
|
|
+ }
|
|
+ if (test_nino_flag(dir_ni, v3_Extensions)) {
|
|
+ enter_cache(scx, dir_ni, uid,
|
|
+ gid, pxdesc);
|
|
+ }
|
|
+ pydesc = build_inherited_posix(pxdesc, mode, isdir);
|
|
+ free(pxdesc);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return (pydesc);
|
|
+}
|
|
+
|
|
/*
|
|
* Allocate a security_id for a file being created
|
|
*
|
|
@@ -3425,6 +5824,144 @@
|
|
*/
|
|
|
|
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
|
+ uid_t uid, gid_t gid, const char *dir_path,
|
|
+ ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
|
|
+{
|
|
+#if !FORCE_FORMAT_v1x
|
|
+ const struct CACHED_SECURID *cached;
|
|
+ struct CACHED_SECURID wanted;
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+ char *newattr;
|
|
+ int newattrsz;
|
|
+ const SID *usid;
|
|
+ const SID *gsid;
|
|
+ BIGSID defusid;
|
|
+ BIGSID defgsid;
|
|
+ le32 securid;
|
|
+#endif
|
|
+
|
|
+ securid = cpu_to_le32(0);
|
|
+
|
|
+#if !FORCE_FORMAT_v1x
|
|
+
|
|
+ pxdesc = inherit_posix(scx, dir_path, dir_ni, mode, isdir);
|
|
+ if (pxdesc) {
|
|
+ /* check whether target securid is known in cache */
|
|
+
|
|
+ wanted.uid = uid;
|
|
+ wanted.gid = gid;
|
|
+ wanted.dmode = pxdesc->mode & mode & 07777;
|
|
+ if (isdir) wanted.dmode |= 0x10000;
|
|
+ wanted.variable = (void*)pxdesc;
|
|
+ wanted.varsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
|
|
+ scx->vol->securid_cache, GENERIC(&wanted),
|
|
+ (cache_compare)compare);
|
|
+ /* quite simple, if we are lucky */
|
|
+ if (cached)
|
|
+ securid = cached->securid;
|
|
+
|
|
+ /* not in cache : make sure we can create ids */
|
|
+
|
|
+ if (!cached && (scx->vol->major_ver >= 3)) {
|
|
+ usid = find_usid(scx,uid,(SID*)&defusid);
|
|
+ gsid = find_gsid(scx,gid,(SID*)&defgsid);
|
|
+ if (!usid || !gsid) {
|
|
+ ntfs_log_error("File created by an unmapped user/group %d/%d\n",
|
|
+ (int)uid, (int)gid);
|
|
+ usid = gsid = adminsid;
|
|
+ }
|
|
+ newattr = build_secur_descr_posix(scx, pxdesc,
|
|
+ isdir, usid, gsid);
|
|
+ if (newattr) {
|
|
+ newattrsz = attr_size(newattr);
|
|
+ securid = setsecurityattr(scx->vol,
|
|
+ (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
|
|
+ newattrsz);
|
|
+ if (securid) {
|
|
+ /* update cache, for subsequent use */
|
|
+ wanted.securid = securid;
|
|
+ ntfs_enter_cache(scx->vol->securid_cache,
|
|
+ GENERIC(&wanted),
|
|
+ (cache_compare)compare);
|
|
+ }
|
|
+ free(newattr);
|
|
+ } else {
|
|
+ /*
|
|
+ * could not build new security attribute
|
|
+ * errno set by build_secur_descr()
|
|
+ */
|
|
+ }
|
|
+ }
|
|
+ free(pxdesc);
|
|
+ }
|
|
+#endif
|
|
+ return (securid);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Apply Posix inheritance to a newly created file
|
|
+ * (for NTFS 1.x only : no securid)
|
|
+ */
|
|
+
|
|
+int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
|
|
+ ntfs_inode *ni, uid_t uid, gid_t gid,
|
|
+ const char *dir_path, ntfs_inode *dir_ni, mode_t mode)
|
|
+{
|
|
+ struct POSIX_SECURITY *pxdesc;
|
|
+ char *newattr;
|
|
+ const SID *usid;
|
|
+ const SID *gsid;
|
|
+ BIGSID defusid;
|
|
+ BIGSID defgsid;
|
|
+ BOOL isdir;
|
|
+ int res;
|
|
+
|
|
+ res = -1;
|
|
+ isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != 0;
|
|
+ pxdesc = inherit_posix(scx, dir_path, dir_ni, mode, isdir);
|
|
+ if (pxdesc) {
|
|
+ usid = find_usid(scx,uid,(SID*)&defusid);
|
|
+ gsid = find_gsid(scx,gid,(SID*)&defgsid);
|
|
+ if (!usid || !gsid) {
|
|
+ ntfs_log_error("File created by an unmapped user/group %d/%d\n",
|
|
+ (int)uid, (int)gid);
|
|
+ usid = gsid = adminsid;
|
|
+ }
|
|
+ newattr = build_secur_descr_posix(scx, pxdesc,
|
|
+ isdir, usid, gsid);
|
|
+ if (newattr) {
|
|
+ res = update_secur_descr(scx->vol, newattr, ni);
|
|
+#if CACHE_LEGACY_SIZE
|
|
+ /* also invalidate legacy cache */
|
|
+ if (isdir && !ni->security_id) {
|
|
+ struct CACHED_PERMISSIONS_LEGACY legacy;
|
|
+
|
|
+ legacy.mft_no = ni->mft_no;
|
|
+ legacy.variable = pxdesc;
|
|
+ legacy.varsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ ntfs_invalidate_cache(scx->vol->legacy_cache,
|
|
+ GENERIC(&legacy),
|
|
+ (cache_compare)leg_compare);
|
|
+ }
|
|
+#endif
|
|
+ free(newattr);
|
|
+
|
|
+ } else {
|
|
+ /*
|
|
+ * could not build new security attribute
|
|
+ * errno set by build_secur_descr()
|
|
+ */
|
|
+ }
|
|
+ }
|
|
+ return (res);
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
|
|
uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
|
|
{
|
|
#if !FORCE_FORMAT_v1x
|
|
@@ -3492,6 +6029,7 @@
|
|
return (securid);
|
|
}
|
|
|
|
+#endif
|
|
|
|
/*
|
|
* Update ownership and mode of a file, reusing an existing
|
|
@@ -3500,8 +6038,14 @@
|
|
* Returns zero if successful
|
|
*/
|
|
|
|
+#if POSIXACLS
|
|
+int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
|
+ uid_t uid, gid_t gid, mode_t mode,
|
|
+ struct POSIX_SECURITY *pxdesc)
|
|
+#else
|
|
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
|
uid_t uid, gid_t gid, mode_t mode)
|
|
+#endif
|
|
{
|
|
int res;
|
|
const struct CACHED_SECURID *cached;
|
|
@@ -3522,8 +6066,17 @@
|
|
wanted.gid = gid;
|
|
wanted.dmode = mode & 07777;
|
|
if (isdir) wanted.dmode |= 0x10000;
|
|
+#if POSIXACLS
|
|
+ wanted.variable = (void*)pxdesc;
|
|
+ if (pxdesc)
|
|
+ wanted.varsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ else
|
|
+ wanted.varsize = 0;
|
|
+#else
|
|
wanted.variable = (void*)NULL;
|
|
wanted.varsize = 0;
|
|
+#endif
|
|
if (test_nino_flag(ni, v3_Extensions)) {
|
|
cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
|
|
scx->vol->securid_cache, GENERIC(&wanted),
|
|
@@ -3548,8 +6101,17 @@
|
|
uid, gid);
|
|
usid = gsid = adminsid;
|
|
}
|
|
+#if POSIXACLS
|
|
+ if (pxdesc)
|
|
+ newattr = build_secur_descr_posix(scx, pxdesc,
|
|
+ isdir, usid, gsid);
|
|
+ else
|
|
+ newattr = build_secur_descr(mode,
|
|
+ isdir, usid, gsid);
|
|
+#else
|
|
newattr = build_secur_descr(mode,
|
|
isdir, usid, gsid);
|
|
+#endif
|
|
if (newattr) {
|
|
res = update_secur_descr(scx->vol, newattr, ni);
|
|
if (!res) {
|
|
@@ -3566,8 +6128,13 @@
|
|
struct CACHED_PERMISSIONS_LEGACY legacy;
|
|
|
|
legacy.mft_no = ni->mft_no;
|
|
+#if POSIXACLS
|
|
+ legacy.variable = wanted.variable;
|
|
+ legacy.varsize = wanted.varsize;
|
|
+#else
|
|
legacy.variable = (void*)NULL;
|
|
legacy.varsize = 0;
|
|
+#endif
|
|
ntfs_invalidate_cache(scx->vol->legacy_cache,
|
|
GENERIC(&legacy),
|
|
(cache_compare)leg_compare);
|
|
@@ -3586,6 +6153,115 @@
|
|
return (res);
|
|
}
|
|
|
|
+#if POSIXACLS
|
|
+
|
|
+/*
|
|
+ * Set a new access or default Posix ACL to a file
|
|
+ * (or remove ACL if no input data)
|
|
+ * Validity of input data is checked after merging
|
|
+ *
|
|
+ * Returns 0, or -1 if there is a problem
|
|
+ */
|
|
+
|
|
+int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, const char *value, size_t size,
|
|
+ ntfs_inode *ni)
|
|
+{
|
|
+ const SECURITY_DESCRIPTOR_RELATIVE *phead;
|
|
+ const struct CACHED_PERMISSIONS *cached;
|
|
+ char *oldattr;
|
|
+ uid_t processuid;
|
|
+ const SID *usid;
|
|
+ const SID *gsid;
|
|
+ uid_t uid;
|
|
+ uid_t gid;
|
|
+ int res;
|
|
+ mode_t mode;
|
|
+ BOOL isdir;
|
|
+ BOOL deflt;
|
|
+ int count;
|
|
+ struct POSIX_SECURITY *oldpxdesc;
|
|
+ struct POSIX_SECURITY *newpxdesc;
|
|
+
|
|
+ /* get the current pxsec, either from cache or from old attribute */
|
|
+ res = -1;
|
|
+ deflt = !strcmp(name,"system.posix_acl_default");
|
|
+ if (size)
|
|
+ count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
|
|
+ else
|
|
+ count = 0;
|
|
+ isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != 0;
|
|
+ newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+ if (!deflt || isdir) {
|
|
+ cached = fetch_cache(scx, ni);
|
|
+ if (cached) {
|
|
+ uid = cached->uid;
|
|
+ gid = cached->gid;
|
|
+ oldpxdesc = cached->pxdesc;
|
|
+ if (oldpxdesc) {
|
|
+ mode = oldpxdesc->mode;
|
|
+ newpxdesc = replace_acl(oldpxdesc,
|
|
+ (const struct POSIX_ACL*)value,count,deflt);
|
|
+ }
|
|
+ } else {
|
|
+ oldattr = getsecurityattr(scx->vol,path, ni);
|
|
+ if (oldattr) {
|
|
+ phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
|
|
+#if OWNERFROMACL
|
|
+ usid = acl_owner(oldattr);
|
|
+#else
|
|
+ usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
|
|
+#endif
|
|
+ gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
|
|
+ uid = findowner(scx,usid);
|
|
+ gid = findgroup(scx,gsid);
|
|
+ oldpxdesc = build_permissions_posix(scx,
|
|
+ oldattr, usid, gsid, ni);
|
|
+ if (oldpxdesc) {
|
|
+ mode = oldpxdesc->mode;
|
|
+ newpxdesc = replace_acl(oldpxdesc,
|
|
+ (const struct POSIX_ACL*)value,count,deflt);
|
|
+ free(oldpxdesc);
|
|
+ }
|
|
+ free(oldattr);
|
|
+ }
|
|
+ }
|
|
+ } else
|
|
+ errno = EINVAL;
|
|
+
|
|
+ if (newpxdesc) {
|
|
+ processuid = scx->uid;
|
|
+ if (!processuid || (uid == processuid)) {
|
|
+ /*
|
|
+ * clear setgid if file group does
|
|
+ * not match process group
|
|
+ */
|
|
+ if (processuid && (gid != scx->gid)
|
|
+ && !groupmember(scx, scx->uid, gid)) {
|
|
+ newpxdesc->mode &= ~S_ISGID;
|
|
+ }
|
|
+ res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
|
+ newpxdesc->mode, newpxdesc);
|
|
+ } else
|
|
+ errno = EPERM;
|
|
+ free(newpxdesc);
|
|
+ }
|
|
+ return (res ? -1 : 0);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Remove a default Posix ACL from a file
|
|
+ */
|
|
+
|
|
+int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
|
|
+ const char *name, ntfs_inode *ni)
|
|
+{
|
|
+ return (ntfs_set_posix_acl(scx, path, name,
|
|
+ (const char*)NULL, 0, ni));
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
|
|
/*
|
|
* Set new permissions to a file
|
|
@@ -3609,6 +6285,12 @@
|
|
uid_t uid;
|
|
uid_t gid;
|
|
int res;
|
|
+#if POSIXACLS
|
|
+ BOOL isdir;
|
|
+ int pxsize;
|
|
+ const struct POSIX_SECURITY *oldpxdesc;
|
|
+ struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#endif
|
|
|
|
/* get the current owner, either from cache or from old attribute */
|
|
res = 0;
|
|
@@ -3616,6 +6298,22 @@
|
|
if (cached) {
|
|
uid = cached->uid;
|
|
gid = cached->gid;
|
|
+#if POSIXACLS
|
|
+ oldpxdesc = cached->pxdesc;
|
|
+ if (oldpxdesc) {
|
|
+ /* must copy before merging */
|
|
+ pxsize = sizeof(struct POSIX_SECURITY)
|
|
+ + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
|
|
+ newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
|
|
+ if (newpxdesc) {
|
|
+ memcpy(newpxdesc, oldpxdesc, pxsize);
|
|
+ if (merge_mode_posix(newpxdesc, mode))
|
|
+ res = -1;
|
|
+ } else
|
|
+ res = -1;
|
|
+ } else
|
|
+ newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#endif
|
|
} else {
|
|
oldattr = getsecurityattr(scx->vol,path, ni);
|
|
if (oldattr) {
|
|
@@ -3628,6 +6326,13 @@
|
|
gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
|
|
uid = findowner(scx,usid);
|
|
gid = findgroup(scx,gsid);
|
|
+#if POSIXACLS
|
|
+ isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != 0;
|
|
+ newpxdesc = build_permissions_posix(scx,
|
|
+ oldattr, usid, gsid, ni);
|
|
+ if (!newpxdesc || merge_mode_posix(newpxdesc, mode))
|
|
+ res = -1;
|
|
+#endif
|
|
free(oldattr);
|
|
} else
|
|
res = -1;
|
|
@@ -3643,7 +6348,17 @@
|
|
if (processuid && (gid != scx->gid)
|
|
&& !groupmember(scx, scx->uid, gid))
|
|
mode &= ~S_ISGID;
|
|
+#if POSIXACLS
|
|
+ if (newpxdesc) {
|
|
+ newpxdesc->mode = mode;
|
|
+ res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
|
+ mode, newpxdesc);
|
|
+ } else
|
|
+ res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
|
+ mode, newpxdesc);
|
|
+#else
|
|
res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
|
|
+#endif
|
|
} else {
|
|
errno = EPERM;
|
|
res = -1; /* neither owner nor root */
|
|
@@ -3657,6 +6372,9 @@
|
|
res = -1;
|
|
errno = EIO;
|
|
}
|
|
+#if POSIXACLS
|
|
+ if (newpxdesc) free(newpxdesc);
|
|
+#endif
|
|
return (res ? -1 : 0);
|
|
}
|
|
|
|
@@ -3759,7 +6477,11 @@
|
|
if (!scx->usermapping || !scx->uid)
|
|
allow = 1;
|
|
else {
|
|
- perm = ntfs_get_perm(scx, path, ni);
|
|
+#if POSIXACLS
|
|
+ perm = ntfs_get_perm(scx, path, ni, accesstype);
|
|
+#else
|
|
+ perm = ntfs_get_perm(scx, path, ni);
|
|
+#endif
|
|
if (perm >= 0) {
|
|
res = EACCES;
|
|
switch (accesstype) {
|
|
@@ -3880,6 +6602,10 @@
|
|
mode_t mode;
|
|
int perm;
|
|
int res;
|
|
+#if POSIXACLS
|
|
+ struct POSIX_SECURITY *oldpxdesc;
|
|
+ struct POSIX_SECURITY *newpxdesc;
|
|
+#endif
|
|
|
|
res = 0;
|
|
/* get the current owner and mode from cache or security attributes */
|
|
@@ -3889,10 +6615,23 @@
|
|
fileuid = cached->uid;
|
|
filegid = cached->gid;
|
|
mode = cached->mode;
|
|
+#if POSIXACLS
|
|
+ oldpxdesc = cached->pxdesc;
|
|
+ if (oldpxdesc) {
|
|
+ newpxdesc = merge_owner_posix(oldpxdesc,
|
|
+ uid, gid, fileuid, filegid);
|
|
+ if (!newpxdesc)
|
|
+ res = -1;
|
|
+ } else
|
|
+ newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#endif
|
|
} else {
|
|
fileuid = 0;
|
|
filegid = 0;
|
|
mode = 0;
|
|
+#if POSIXACLS
|
|
+ newpxdesc = (struct POSIX_SECURITY*)NULL;
|
|
+#endif
|
|
oldattr = getsecurityattr(scx->vol, path, ni);
|
|
if (oldattr) {
|
|
phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
|
|
@@ -3905,6 +6644,21 @@
|
|
usid = (const SID*)
|
|
&oldattr[le32_to_cpu(phead->owner)];
|
|
#endif
|
|
+#if POSIXACLS
|
|
+ oldpxdesc = build_permissions_posix(scx, oldattr,
|
|
+ usid, gsid, ni);
|
|
+ if (oldpxdesc) {
|
|
+ fileuid = findowner(scx,usid);
|
|
+ filegid = findgroup(scx,gsid);
|
|
+ mode = perm = oldpxdesc->mode;
|
|
+ newpxdesc = merge_owner_posix(oldpxdesc,
|
|
+ uid, gid, fileuid, filegid);
|
|
+ free(oldpxdesc);
|
|
+ if (!newpxdesc)
|
|
+ res = -1;
|
|
+ } else
|
|
+ res = -1;
|
|
+#else
|
|
mode = perm = build_permissions(oldattr,
|
|
usid, gsid, ni);
|
|
if (perm >= 0) {
|
|
@@ -3912,6 +6666,7 @@
|
|
filegid = findgroup(scx,gsid);
|
|
} else
|
|
res = -1;
|
|
+#endif
|
|
free(oldattr);
|
|
} else
|
|
res = -1;
|
|
@@ -3933,11 +6688,19 @@
|
|
/* unless request originated by root */
|
|
if (uid && (fileuid != uid))
|
|
mode &= 01777;
|
|
+#if POSIXACLS
|
|
+ res = ntfs_set_owner_mode(scx, ni, uid, gid,
|
|
+ mode, newpxdesc);
|
|
+#else
|
|
res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
|
|
+#endif
|
|
} else {
|
|
res = -1; /* neither owner nor root */
|
|
errno = EPERM;
|
|
}
|
|
+#if POSIXACLS
|
|
+ free(newpxdesc);
|
|
+#endif
|
|
} else {
|
|
/*
|
|
* Should not happen : a default descriptor is generated
|