Commit bc3e9dd9 authored by Shyam Prasad N's avatar Shyam Prasad N Committed by Steve French
Browse files

cifs: Change SIDs in ACEs while transferring file ownership.



With cifsacl, when a file/dir ownership is transferred (chown/chgrp),
the ACEs in the DACL for that file will need to replace the old owner
SIDs with the new owner SID.

Signed-off-by: default avatarShyam Prasad N <sprasad@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent f5065508
Loading
Loading
Loading
Loading
+92 −47
Original line number Original line Diff line number Diff line
@@ -525,8 +525,11 @@ exit_cifs_idmap(void)
}
}


/* copy ntsd, owner sid, and group sid from a security descriptor to another */
/* copy ntsd, owner sid, and group sid from a security descriptor to another */
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
static __u32 copy_sec_desc(const struct cifs_ntsd *pntsd,
				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
				struct cifs_ntsd *pnntsd,
				__u32 sidsoffset,
				struct cifs_sid *pownersid,
				struct cifs_sid *pgrpsid)
{
{
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
@@ -540,19 +543,25 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd,
	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));


	/* copy owner sid */
	/* copy owner sid */
	if (pownersid)
		owner_sid_ptr = pownersid;
	else
		owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
		owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
				le32_to_cpu(pntsd->osidoffset));
	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
	cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
	cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);


	/* copy group sid */
	/* copy group sid */
	if (pgrpsid)
		group_sid_ptr = pgrpsid;
	else
		group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
		group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
				le32_to_cpu(pntsd->gsidoffset));
	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
					sizeof(struct cifs_sid));
					sizeof(struct cifs_sid));
	cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
	cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);


	return;
	return sidsoffset + (2 * sizeof(struct cifs_sid));
}
}




@@ -667,16 +676,22 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
	return;
	return;
}
}


static __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src)
static __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src, struct cifs_sid *psid)
{
{
	__u16 size = 1 + 1 + 2 + 4;
	__u16 size = 1 + 1 + 2 + 4;


	dst->type = src->type;
	dst->type = src->type;
	dst->flags = src->flags;
	dst->flags = src->flags;
	dst->size = src->size;
	dst->access_req = src->access_req;
	dst->access_req = src->access_req;

	/* Check if there's a replacement sid specified */
	if (psid)
		size += cifs_copy_sid(&dst->sid, psid);
	else
		size += cifs_copy_sid(&dst->sid, &src->sid);
		size += cifs_copy_sid(&dst->sid, &src->sid);


	dst->size = cpu_to_le16(size);

	return size;
	return size;
}
}


@@ -1053,11 +1068,11 @@ static __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl
		pnntace = (struct cifs_ace *) (nacl_base + nsize);
		pnntace = (struct cifs_ace *) (nacl_base + nsize);


		if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
		if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
			ace_size = cifs_copy_ace(pnntace, pntace);
			ace_size = cifs_copy_ace(pnntace, pntace, pnownersid);
		else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
		else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
			ace_size = cifs_copy_ace(pnntace, pntace);
			ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid);
		else
		else
			ace_size = cifs_copy_ace(pnntace, pntace);
			ace_size = cifs_copy_ace(pnntace, pntace, NULL);


		size += le16_to_cpu(pntace->size);
		size += le16_to_cpu(pntace->size);
		nsize += ace_size;
		nsize += ace_size;
@@ -1124,7 +1139,7 @@ static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
			goto next_ace;
			goto next_ace;
		}
		}


		nsize += cifs_copy_ace(pnntace, pntace);
		nsize += cifs_copy_ace(pnntace, pntace, NULL);
		num_aces++;
		num_aces++;


next_ace:
next_ace:
@@ -1250,16 +1265,12 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
	__u32 ndacloffset;
	__u32 ndacloffset;
	__u32 sidsoffset;
	__u32 sidsoffset;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
	struct cifs_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL;
	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
	char *end_of_acl = ((char *)pntsd) + secdesclen;
	char *end_of_acl = ((char *)pntsd) + secdesclen;
	u16 size = 0;


	if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
		owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
		group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
	dacloffset = le32_to_cpu(pntsd->dacloffset);
	dacloffset = le32_to_cpu(pntsd->dacloffset);
	if (dacloffset) {
	if (dacloffset) {
		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
@@ -1269,6 +1280,12 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
		}
		}
	}
	}


	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
			le32_to_cpu(pntsd->osidoffset));
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
			le32_to_cpu(pntsd->gsidoffset));

	if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
		ndacl_ptr->revision =
		ndacl_ptr->revision =
@@ -1279,11 +1296,13 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,


		rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
		rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
				    pnmode, mode_from_sid);
				    pnmode, 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 the non-dacl portion of secdesc */
		copy_sec_desc(pntsd, pnntsd, sidsoffset);
		*pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
		*pnsecdesclen = sidsoffset + (2 * sizeof(struct cifs_sid));
				NULL, NULL);
		*aclflag = CIFS_ACL_DACL;

		*aclflag |= CIFS_ACL_DACL;
	} else {
	} else {
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
@@ -1293,12 +1312,12 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,


		if (uid_valid(uid)) { /* chown */
		if (uid_valid(uid)) { /* chown */
			uid_t id;
			uid_t id;
			owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->osidoffset));
			nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
			nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
								GFP_KERNEL);
			if (!nowner_sid_ptr)
			if (!nowner_sid_ptr) {
				return -ENOMEM;
				rc = -ENOMEM;
				goto chown_chgrp_exit;
			}
			id = from_kuid(&init_user_ns, uid);
			id = from_kuid(&init_user_ns, uid);
			if (id_from_sid) {
			if (id_from_sid) {
				struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
				struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
@@ -1309,27 +1328,25 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
				osid->SubAuthorities[0] = cpu_to_le32(88);
				osid->SubAuthorities[0] = cpu_to_le32(88);
				osid->SubAuthorities[1] = cpu_to_le32(1);
				osid->SubAuthorities[1] = cpu_to_le32(1);
				osid->SubAuthorities[2] = cpu_to_le32(id);
				osid->SubAuthorities[2] = cpu_to_le32(id);

			} else { /* lookup sid with upcall */
			} else { /* lookup sid with upcall */
				rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
				rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
				if (rc) {
				if (rc) {
					cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
					cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
						 __func__, rc, id);
						 __func__, rc, id);
					kfree(nowner_sid_ptr);
					goto chown_chgrp_exit;
					return rc;
				}
				}
			}
			}
			cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
			*aclflag |= CIFS_ACL_OWNER;
			kfree(nowner_sid_ptr);
			*aclflag = CIFS_ACL_OWNER;
		}
		}
		if (gid_valid(gid)) { /* chgrp */
		if (gid_valid(gid)) { /* chgrp */
			gid_t id;
			gid_t id;
			group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->gsidoffset));
			ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
			ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
								GFP_KERNEL);
			if (!ngroup_sid_ptr)
			if (!ngroup_sid_ptr) {
				return -ENOMEM;
				rc = -ENOMEM;
				goto chown_chgrp_exit;
			}
			id = from_kgid(&init_user_ns, gid);
			id = from_kgid(&init_user_ns, gid);
			if (id_from_sid) {
			if (id_from_sid) {
				struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
				struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
@@ -1340,19 +1357,35 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
				gsid->SubAuthorities[0] = cpu_to_le32(88);
				gsid->SubAuthorities[0] = cpu_to_le32(88);
				gsid->SubAuthorities[1] = cpu_to_le32(2);
				gsid->SubAuthorities[1] = cpu_to_le32(2);
				gsid->SubAuthorities[2] = cpu_to_le32(id);
				gsid->SubAuthorities[2] = cpu_to_le32(id);

			} else { /* lookup sid with upcall */
			} else { /* lookup sid with upcall */
				rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
				rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
				if (rc) {
				if (rc) {
					cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
					cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
						 __func__, rc, id);
						 __func__, rc, id);
					kfree(ngroup_sid_ptr);
					goto chown_chgrp_exit;
					return rc;
				}
				}
			}
			}
			cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
			*aclflag |= CIFS_ACL_GROUP;
			kfree(ngroup_sid_ptr);
		}
			*aclflag = CIFS_ACL_GROUP;

		if (dacloffset) {
			/* Replace ACEs for old owner with new one */
			size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
					owner_sid_ptr, group_sid_ptr,
					nowner_sid_ptr, ngroup_sid_ptr);
			ndacl_ptr->size = cpu_to_le16(size);
		}
		}

		sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
		/* copy the non-dacl portion of secdesc */
		*pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
				nowner_sid_ptr, ngroup_sid_ptr);

chown_chgrp_exit:
		/* errors could jump here. So make sure we return soon after this */
		kfree(nowner_sid_ptr);
		kfree(ngroup_sid_ptr);
	}
	}


	return rc;
	return rc;
@@ -1598,6 +1631,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
			nsecdesclen += sizeof(struct cifs_ace);
			nsecdesclen += sizeof(struct cifs_ace);
		else /* cifsacl */
		else /* cifsacl */
			nsecdesclen += 5 * sizeof(struct cifs_ace);
			nsecdesclen += 5 * sizeof(struct cifs_ace);
	} else { /* chown */
		/* When ownership changes, changes new owner sid length could be different */
		nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
		dacloffset = le32_to_cpu(pntsd->dacloffset);
		if (dacloffset) {
			dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
			if (mode_from_sid)
				nsecdesclen +=
					le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace);
			else /* cifsacl */
				nsecdesclen += le16_to_cpu(dacl_ptr->size);
		}
	}
	}


	/*
	/*