summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2019-12-06 11:02:38 +0300
committerSteve French <stfrench@microsoft.com>2019-12-06 23:15:52 +0300
commitfdef665ba44ad5ed154af2acfb19ae2ee3bf5dcc (patch)
tree20f45c141c6a5dcefc0f5869d46b1179aae745f8 /fs/cifs/smb2pdu.c
parent9a7d5a9e6d7921e1854b4606ce8c3e17d565f463 (diff)
downloadlinux-fdef665ba44ad5ed154af2acfb19ae2ee3bf5dcc.tar.xz
smb3: fix mode passed in on create for modetosid mount option
When using the special SID to store the mode bits in an ACE (See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx) which is enabled with mount parm "modefromsid" we were not passing in the mode via SMB3 create (although chmod was enabled). SMB3 create allows a security descriptor context to be passed in (which is more atomic and thus preferable to setting the mode bits after create via a setinfo). This patch enables setting the mode bits on create when using modefromsid mount option. In addition it fixes an endian error in the definition of the Control field flags in the SMB3 security descriptor. It also makes the ACE type of the special SID better match the documentation (and behavior of servers which use this to store mode bits in SMB3 ACLs). Signed-off-by: Steve French <stfrench@microsoft.com> Acked-by: Ronnie Sahlberg <lsahlber@redhat.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c71
1 files changed, 69 insertions, 2 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 187a5ce68806..b77643e02157 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2191,6 +2191,72 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
return 0;
}
+/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
+static struct crt_sd_ctxt *
+create_sd_buf(umode_t mode, unsigned int *len)
+{
+ struct crt_sd_ctxt *buf;
+ struct cifs_ace *pace;
+ unsigned int sdlen, acelen;
+
+ *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace), 8);
+ buf = kzalloc(*len, GFP_KERNEL);
+ if (buf == NULL)
+ return buf;
+
+ sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) +
+ sizeof(struct cifs_ace);
+
+ buf->ccontext.DataOffset = cpu_to_le16(offsetof
+ (struct crt_sd_ctxt, sd));
+ buf->ccontext.DataLength = cpu_to_le32(sdlen);
+ buf->ccontext.NameOffset = cpu_to_le16(offsetof
+ (struct crt_sd_ctxt, Name));
+ buf->ccontext.NameLength = cpu_to_le16(4);
+ /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */
+ buf->Name[0] = 'S';
+ buf->Name[1] = 'e';
+ buf->Name[2] = 'c';
+ buf->Name[3] = 'D';
+ buf->sd.Revision = 1; /* Must be one see MS-DTYP 2.4.6 */
+ /*
+ * ACL is "self relative" ie ACL is stored in contiguous block of memory
+ * and "DP" ie the DACL is present
+ */
+ buf->sd.Control = cpu_to_le16(ACL_CONTROL_SR | ACL_CONTROL_DP);
+
+ /* offset owner, group and Sbz1 and SACL are all zero */
+ buf->sd.OffsetDacl = cpu_to_le32(sizeof(struct smb3_sd));
+ buf->acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */
+
+ /* create one ACE to hold the mode embedded in reserved special SID */
+ pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf);
+ acelen = setup_special_mode_ACE(pace, (__u64)mode);
+ buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen);
+ buf->acl.AceCount = cpu_to_le16(1);
+ return buf;
+}
+
+static int
+add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+{
+ struct smb2_create_req *req = iov[0].iov_base;
+ unsigned int num = *num_iovec;
+ unsigned int len = 0;
+
+ iov[num].iov_base = create_sd_buf(mode, &len);
+ if (iov[num].iov_base == NULL)
+ return -ENOMEM;
+ iov[num].iov_len = len;
+ if (!req->CreateContextsOffset)
+ req->CreateContextsOffset = cpu_to_le32(
+ sizeof(struct smb2_create_req) +
+ iov[num - 1].iov_len);
+ le32_add_cpu(&req->CreateContextsLength, len);
+ *num_iovec = num + 1;
+ return 0;
+}
+
static struct crt_query_id_ctxt *
create_query_id_buf(void)
{
@@ -2563,7 +2629,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
return rc;
}
- if ((oparms->disposition == FILE_CREATE) &&
+ if ((oparms->disposition != FILE_OPEN) &&
(oparms->mode != ACL_NO_MODE)) {
if (n_iov > 2) {
struct create_context *ccontext =
@@ -2572,7 +2638,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
cpu_to_le32(iov[n_iov-1].iov_len);
}
- /* rc = add_sd_context(iov, &n_iov, oparms->mode); */
+ cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
+ rc = add_sd_context(iov, &n_iov, oparms->mode);
if (rc)
return rc;
}