summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsacl.c22
-rw-r--r--fs/cifs/cifsacl.h15
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/smb2pdu.c112
4 files changed, 129 insertions, 21 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index ae421634aa42..63aaa363ed14 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -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)
{
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index 21d7dee98d01..17562ea00e18 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -176,6 +176,21 @@ struct smb3_acl {
__le16 Sbz2; /* MBZ */
} __packed;
+/*
+ * Used to store the special 'NFS SIDs' used to persist the POSIX uid and gid
+ * See See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+struct owner_sid {
+ u8 Revision;
+ u8 NumAuth;
+ u8 Authority[6];
+ __le32 SubAuthorities[3];
+} __packed;
+
+struct owner_group_sids {
+ struct owner_sid owner;
+ struct owner_sid group;
+} __packed;
/*
* Minimum security identifier can be one for system defined Users
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b603da73f4f5..7a836ec0438e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -222,6 +222,7 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
const char *, int);
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);
extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode);
+extern unsigned int setup_special_user_owner_ACE(struct cifs_ace *pace);
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
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) {