Commit 22442179 authored by Steve French's avatar Steve French

cifs: allow chmod to set mode bits using special sid

    When mounting with "modefromsid" set mode bits (chmod) by
    adding ACE with special SID (S-1-5-88-3-<mode>) to the ACL.
    Subsequent patch will fix setting default mode on file
    create and mkdir.

    See See e.g.
        https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/hh509017(v=ws.10)Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent e2f8fbfb
...@@ -806,7 +806,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -806,7 +806,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
struct cifs_sid *pgrpsid, __u64 nmode) struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
{ {
u16 size = 0; u16 size = 0;
struct cifs_acl *pnndacl; struct cifs_acl *pnndacl;
...@@ -820,8 +820,33 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, ...@@ -820,8 +820,33 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
&sid_everyone, nmode, S_IRWXO); &sid_everyone, nmode, S_IRWXO);
/* TBD: Move this ACE to the top of ACE list instead of bottom */
if (modefromsid) {
struct cifs_ace *pntace =
(struct cifs_ace *)((char *)pnndacl + size);
int i;
pntace->type = ACCESS_DENIED;
pntace->flags = 0x0;
pntace->sid.num_subauth = 3;
pntace->sid.revision = 1;
/* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4) */
pntace->size = cpu_to_le16(28);
size += 28;
for (i = 0; i < NUM_AUTHS; i++)
pntace->sid.authority[i] =
sid_unix_NFS_mode.authority[i];
pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
pndacl->num_aces = cpu_to_le32(4);
size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
&sid_unix_NFS_mode, nmode, S_IRWXO);
} else
pndacl->num_aces = cpu_to_le32(3);
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
pndacl->num_aces = cpu_to_le32(3);
return 0; return 0;
} }
...@@ -921,7 +946,8 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, ...@@ -921,7 +946,8 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
/* Convert permission bits from mode to equivalent CIFS ACL */ /* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
__u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag) __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid,
bool mode_from_sid, int *aclflag)
{ {
int rc = 0; int rc = 0;
__u32 dacloffset; __u32 dacloffset;
...@@ -946,7 +972,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, ...@@ -946,7 +972,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
ndacl_ptr->num_aces = 0; ndacl_ptr->num_aces = 0;
rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
nmode); nmode, mode_from_sid);
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
/* copy sec desc control portion & owner and group sids */ /* copy sec desc control portion & owner and group sids */
copy_sec_desc(pntsd, pnntsd, sidsoffset); copy_sec_desc(pntsd, pnntsd, sidsoffset);
...@@ -1196,6 +1222,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, ...@@ -1196,6 +1222,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
struct smb_version_operations *ops; struct smb_version_operations *ops;
bool mode_from_sid;
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
...@@ -1233,8 +1260,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, ...@@ -1233,8 +1260,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
return -ENOMEM; return -ENOMEM;
} }
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
mode_from_sid = true;
else
mode_from_sid = false;
rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
&aclflag); mode_from_sid, &aclflag);
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
......
...@@ -2489,7 +2489,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2489,7 +2489,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_GID) if (attrs->ia_valid & ATTR_GID)
gid = attrs->ia_gid; gid = attrs->ia_gid;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
if (uid_valid(uid) || gid_valid(gid)) { if (uid_valid(uid) || gid_valid(gid)) {
rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64, rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
uid, gid); uid, gid);
...@@ -2510,7 +2511,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2510,7 +2511,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_MODE) { if (attrs->ia_valid & ATTR_MODE) {
mode = attrs->ia_mode; mode = attrs->ia_mode;
rc = 0; rc = 0;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
rc = id_mode_to_cifs_acl(inode, full_path, mode, rc = id_mode_to_cifs_acl(inode, full_path, mode,
INVALID_UID, INVALID_GID); INVALID_UID, INVALID_GID);
if (rc) { if (rc) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment