Merge tag 'overflow-v5.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[linux-2.6-block.git] / fs / cifs / cifsacl.c
index ae421634aa42895c76e47f930c252e303db2a670..6025d7fc7bbfd11f13b57174d2f1af149c2f200f 100644 (file)
@@ -849,6 +849,28 @@ unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
        return ace_size;
 }
 
+unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)
+{
+       int i;
+       unsigned int ace_size = 28;
+
+       pntace->type = ACCESS_ALLOWED_ACE_TYPE;
+       pntace->flags = 0x0;
+       pntace->access_req = cpu_to_le32(GENERIC_ALL);
+       pntace->sid.num_subauth = 3;
+       pntace->sid.revision = 1;
+       for (i = 0; i < NUM_AUTHS; i++)
+               pntace->sid.authority[i] = sid_unix_NFS_users.authority[i];
+
+       pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0];
+       pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1];
+       pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val);
+
+       /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
+       pntace->size = cpu_to_le16(ace_size);
+       return ace_size;
+}
+
 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
                        struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
 {
@@ -978,7 +1000,7 @@ 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,
-       bool mode_from_sid, int *aclflag)
+       bool mode_from_sid, bool id_from_sid, int *aclflag)
 {
        int rc = 0;
        __u32 dacloffset;
@@ -1019,12 +1041,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
                        if (!nowner_sid_ptr)
                                return -ENOMEM;
                        id = from_kuid(&init_user_ns, uid);
-                       rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
-                       if (rc) {
-                               cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
-                                        __func__, rc, id);
-                               kfree(nowner_sid_ptr);
-                               return rc;
+                       if (id_from_sid) {
+                               struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
+                               /* Populate the user ownership fields S-1-5-88-1 */
+                               osid->Revision = 1;
+                               osid->NumAuth = 3;
+                               osid->Authority[5] = 5;
+                               osid->SubAuthorities[0] = cpu_to_le32(88);
+                               osid->SubAuthorities[1] = cpu_to_le32(1);
+                               osid->SubAuthorities[2] = cpu_to_le32(id);
+                       } else { /* lookup sid with upcall */
+                               rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
+                               if (rc) {
+                                       cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
+                                                __func__, rc, id);
+                                       kfree(nowner_sid_ptr);
+                                       return rc;
+                               }
                        }
                        cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
                        kfree(nowner_sid_ptr);
@@ -1039,12 +1072,23 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
                        if (!ngroup_sid_ptr)
                                return -ENOMEM;
                        id = from_kgid(&init_user_ns, gid);
-                       rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
-                       if (rc) {
-                               cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
-                                        __func__, rc, id);
-                               kfree(ngroup_sid_ptr);
-                               return rc;
+                       if (id_from_sid) {
+                               struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
+                               /* Populate the group ownership fields S-1-5-88-2 */
+                               gsid->Revision = 1;
+                               gsid->NumAuth = 3;
+                               gsid->Authority[5] = 5;
+                               gsid->SubAuthorities[0] = cpu_to_le32(88);
+                               gsid->SubAuthorities[1] = cpu_to_le32(2);
+                               gsid->SubAuthorities[2] = cpu_to_le32(id);
+                       } else { /* lookup sid with upcall */
+                               rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
+                               if (rc) {
+                                       cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
+                                                __func__, rc, id);
+                                       kfree(ngroup_sid_ptr);
+                                       return rc;
+                               }
                        }
                        cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
                        kfree(ngroup_sid_ptr);
@@ -1247,7 +1291,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;
+       bool mode_from_sid, id_from_sid;
 
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
@@ -1290,8 +1334,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
        else
                mode_from_sid = false;
 
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
+               id_from_sid = true;
+       else
+               id_from_sid = false;
+
        rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
-                           mode_from_sid, &aclflag);
+                           mode_from_sid, id_from_sid, &aclflag);
 
        cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);