diff mbox series

[CIFS] Allow chmod to set mode using special SID

Message ID CAH2r5msHdqJ-oSiB+RGEoknHvY4FWeX81YAw2+_D_wYuoL3PJA@mail.gmail.com (mailing list archive)
State New, archived
Headers show
Series [CIFS] Allow chmod to set mode using special SID | expand

Commit Message

Steve French July 19, 2019, 8:31 a.m. UTC
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)

An example:

# touch /mnt-to-windows/newfile0754

# chmod 0754 /mnt-to-windows/newfile0754

# stat /mnt-to-windows/newfile0754
  File: /mnt-to-windows/newfile0754
  Size: 0          Blocks: 0          IO Block: 1048576 regular empty file
Device: 33h/51d Inode: 3659174697263184  Links: 1
Access: (0754/-rwxr-xr--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-07-19 08:21:14.970287500 +0000
Modify: 2019-07-19 08:21:14.970287500 +0000
Change: 2019-07-19 08:21:25.665086200 +0000

(Notice the last ACE which has the mode bits embedded, 492 decimal is
0754 octal)

# getcifsacl /mnt-to-windows/newfile0754
REVISION:0x1
CONTROL:0x8004
OWNER:S-1-5-32-544
GROUP:S-1-5-21-3447553893-1265514152-1435875098-513
ACL:S-1-5-32-544:ALLOWED/0x0/FULL
ACL:S-1-5-21-3447553893-1265514152-1435875098-513:ALLOWED/0x0/0x1f01b9
ACL:S-1-1-0:ALLOWED/0x0/0x1f0199
ACL:S-1-5-88-3-492:DENIED/0x0/
diff mbox series

Patch

From ee2cea10a32827be97d0f7504ac5a835a35bd1a6 Mon Sep 17 00:00:00 2001
From: Ubuntu
 <smfrench@ubuntu19gcmfast.5reoe5booczudeqqf4h4mvn2ue.jx.internal.cloudapp.net>
Date: Fri, 19 Jul 2019 08:15:55 +0000
Subject: [PATCH] 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: Steve French <stfrench@microsoft.com>
---
 fs/cifs/cifsacl.c | 42 +++++++++++++++++++++++++++++++++++++-----
 fs/cifs/inode.c   |  6 ++++--
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 2a14748b8e09..a31bee51b1b4 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -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,
-			struct cifs_sid *pgrpsid, __u64 nmode)
+			struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
 {
 	u16 size = 0;
 	struct cifs_acl *pnndacl;
@@ -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),
 					 &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->num_aces = cpu_to_le32(3);
 
 	return 0;
 }
@@ -921,7 +946,8 @@  static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
 
 /* Convert permission bits from mode to equivalent CIFS ACL */
 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;
 	__u32 dacloffset;
@@ -946,7 +972,7 @@  static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
 		ndacl_ptr->num_aces = 0;
 
 		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);
 		/* copy sec desc control portion & owner and group sids */
 		copy_sec_desc(pntsd, pnntsd, sidsoffset);
@@ -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 tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 	struct smb_version_operations *ops;
+	bool mode_from_sid;
 
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
@@ -1233,8 +1260,13 @@  id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
 		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,
-				&aclflag);
+			    mode_from_sid, &aclflag);
 
 	cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index c1e620ebcf7c..83664735efa5 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -2489,7 +2489,8 @@  cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	if (attrs->ia_valid & ATTR_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)) {
 			rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
 							uid, gid);
@@ -2510,7 +2511,8 @@  cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	if (attrs->ia_valid & ATTR_MODE) {
 		mode = attrs->ia_mode;
 		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,
 						INVALID_UID, INVALID_GID);
 			if (rc) {
-- 
2.20.1