summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2020-06-12 09:25:21 -0500
committerSteve French <stfrench@microsoft.com>2020-06-12 13:21:15 -0500
commit975221eca5fbfdb4b6b1d17c9e540d4d7627ce18 (patch)
tree198ac249e567c11a1702d89557bcac88e43fdd8b /fs/cifs/smb2pdu.c
parente4bd7c4a8d2a8471d821dd29919378d1b8567091 (diff)
downloadlwn-975221eca5fbfdb4b6b1d17c9e540d4d7627ce18.tar.gz
lwn-975221eca5fbfdb4b6b1d17c9e540d4d7627ce18.zip
smb3: allow uid and gid owners to be set on create with idsfromsid mount option
Currently idsfromsid mount option allows querying owner information from the special sids used to represent POSIX uids and gids but needed changes to populate the security descriptor context with the owner information when idsfromsid mount option was used. Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c112
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) {