diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 112 |
1 files changed, 91 insertions, 21 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3f5c3dd57c86..c6b9e617343a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2317,28 +2317,73 @@ add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp) return 0; } +/* See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */ +static void setup_owner_group_sids(char *buf) +{ + struct owner_group_sids *sids = (struct owner_group_sids *)buf; + + /* Populate the user ownership fields S-1-5-88-1 */ + sids->owner.Revision = 1; + sids->owner.NumAuth = 3; + sids->owner.Authority[5] = 5; + sids->owner.SubAuthorities[0] = cpu_to_le32(88); + sids->owner.SubAuthorities[1] = cpu_to_le32(1); + sids->owner.SubAuthorities[2] = cpu_to_le32(current_fsuid().val); + + /* Populate the group ownership fields S-1-5-88-2 */ + sids->group.Revision = 1; + sids->group.NumAuth = 3; + sids->group.Authority[5] = 5; + sids->group.SubAuthorities[0] = cpu_to_le32(88); + sids->group.SubAuthorities[1] = cpu_to_le32(2); + sids->group.SubAuthorities[2] = cpu_to_le32(current_fsgid().val); +} + /* 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) +create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) { struct crt_sd_ctxt *buf; struct cifs_ace *pace; unsigned int sdlen, acelen; + unsigned int owner_offset = 0; + unsigned int group_offset = 0; + + *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 2), 8); + + if (set_owner) { + /* offset fields are from beginning of security descriptor not of create context */ + owner_offset = sizeof(struct smb3_acl) + (sizeof(struct cifs_ace) * 2); + + /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */ + *len += sizeof(struct owner_group_sids); + } - *len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace) * 2, - 8); buf = kzalloc(*len, GFP_KERNEL); if (buf == NULL) return buf; + if (set_owner) { + buf->sd.OffsetOwner = cpu_to_le32(owner_offset); + group_offset = owner_offset + sizeof(struct owner_sid); + buf->sd.OffsetGroup = cpu_to_le32(group_offset); + } else { + buf->sd.OffsetOwner = 0; + buf->sd.OffsetGroup = 0; + } + sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) + 2 * sizeof(struct cifs_ace); + if (set_owner) { + sdlen += sizeof(struct owner_group_sids); + setup_owner_group_sids(owner_offset + sizeof(struct create_context) + 8 /* name */ + + (char *)buf); + } 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.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'; @@ -2359,23 +2404,34 @@ create_sd_buf(umode_t mode, unsigned int *len) /* 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); + + if (set_owner) { + /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */ + pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); + acelen += setup_special_user_owner_ACE(pace); + /* it does not appear necessary to add an ACE for the NFS group SID */ + buf->acl.AceCount = cpu_to_le16(3); + } else + buf->acl.AceCount = cpu_to_le16(2); + /* and one more ACE to allow access for authenticated users */ pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); acelen += setup_authusers_ACE(pace); + buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen); - buf->acl.AceCount = cpu_to_le16(2); + return buf; } static int -add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) +add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner) { 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); + iov[num].iov_base = create_sd_buf(mode, set_owner, &len); if (iov[num].iov_base == NULL) return -ENOMEM; iov[num].iov_len = len; @@ -2764,21 +2820,35 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, return rc; } - if ((oparms->disposition != FILE_OPEN) && - (oparms->cifs_sb) && - (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && - (oparms->mode != ACL_NO_MODE)) { - if (n_iov > 2) { - struct create_context *ccontext = - (struct create_context *)iov[n_iov-1].iov_base; - ccontext->Next = - cpu_to_le32(iov[n_iov-1].iov_len); + if ((oparms->disposition != FILE_OPEN) && (oparms->cifs_sb)) { + bool set_mode; + bool set_owner; + + if ((oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) && + (oparms->mode != ACL_NO_MODE)) + set_mode = true; + else { + set_mode = false; + oparms->mode = ACL_NO_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; + if (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) + set_owner = true; + else + set_owner = false; + + if (set_owner | set_mode) { + if (n_iov > 2) { + struct create_context *ccontext = + (struct create_context *)iov[n_iov-1].iov_base; + ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len); + } + + cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); + rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner); + if (rc) + return rc; + } } if (n_iov > 2) { |