cifs: add smb2 POSIX info level
authorAurelien Aptel <aaptel@suse.com>
Sat, 8 Feb 2020 14:50:57 +0000 (15:50 +0100)
committerSteve French <stfrench@microsoft.com>
Mon, 23 Mar 2020 03:49:09 +0000 (22:49 -0500)
* add new info level and structs for SMB2 posix extension
* add functions to parse and validate it

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifspdu.h
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h

index 79d842e7240c7cff027eebb5915cded50e8b8e3c..8e15887d1f1fc280008136558f4253ac8a0979f3 100644 (file)
@@ -1691,6 +1691,7 @@ struct smb_t2_rsp {
 #define SMB_FIND_FILE_ID_FULL_DIR_INFO    0x105
 #define SMB_FIND_FILE_ID_BOTH_DIR_INFO    0x106
 #define SMB_FIND_FILE_UNIX                0x202
+#define SMB_FIND_FILE_POSIX_INFO          0x064
 
 typedef struct smb_com_transaction2_qpi_req {
        struct smb_hdr hdr;     /* wct = 14+ */
index ab31d6f5422189f151b71d5d39155f5d324d4b86..08d6a130e512e923a213389128a61f12470a97a6 100644 (file)
@@ -4302,6 +4302,101 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        return rc;
 }
 
+static int posix_info_sid_size(const void *beg, const void *end)
+{
+       size_t subauth;
+       int total;
+
+       if (beg + 1 > end)
+               return -1;
+
+       subauth = *(u8 *)(beg+1);
+       if (subauth < 1 || subauth > 15)
+               return -1;
+
+       total = 1 + 1 + 6 + 4*subauth;
+       if (beg + total > end)
+               return -1;
+
+       return total;
+}
+
+int posix_info_parse(const void *beg, const void *end,
+                    struct smb2_posix_info_parsed *out)
+
+{
+       int total_len = 0;
+       int sid_len;
+       int name_len;
+       const void *owner_sid;
+       const void *group_sid;
+       const void *name;
+
+       /* if no end bound given, assume payload to be correct */
+       if (!end) {
+               const struct smb2_posix_info *p = beg;
+
+               end = beg + le32_to_cpu(p->NextEntryOffset);
+               /* last element will have a 0 offset, pick a sensible bound */
+               if (end == beg)
+                       end += 0xFFFF;
+       }
+
+       /* check base buf */
+       if (beg + sizeof(struct smb2_posix_info) > end)
+               return -1;
+       total_len = sizeof(struct smb2_posix_info);
+
+       /* check owner sid */
+       owner_sid = beg + total_len;
+       sid_len = posix_info_sid_size(owner_sid, end);
+       if (sid_len < 0)
+               return -1;
+       total_len += sid_len;
+
+       /* check group sid */
+       group_sid = beg + total_len;
+       sid_len = posix_info_sid_size(group_sid, end);
+       if (sid_len < 0)
+               return -1;
+       total_len += sid_len;
+
+       /* check name len */
+       if (beg + total_len + 4 > end)
+               return -1;
+       name_len = le32_to_cpu(*(__le32 *)(beg + total_len));
+       if (name_len < 1 || name_len > 0xFFFF)
+               return -1;
+       total_len += 4;
+
+       /* check name */
+       name = beg + total_len;
+       if (name + name_len > end)
+               return -1;
+       total_len += name_len;
+
+       if (out) {
+               out->base = beg;
+               out->size = total_len;
+               out->name_len = name_len;
+               out->name = name;
+               memcpy(&out->owner, owner_sid,
+                      posix_info_sid_size(owner_sid, end));
+               memcpy(&out->group, group_sid,
+                      posix_info_sid_size(group_sid, end));
+       }
+       return total_len;
+}
+
+static int posix_info_extra_size(const void *beg, const void *end)
+{
+       int len = posix_info_parse(beg, end, NULL);
+
+       if (len < 0)
+               return -1;
+       return len - sizeof(struct smb2_posix_info);
+}
+
 static unsigned int
 num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
 {
index 3addecebc25d821b5bee6997e7fd94f48f875ed8..7003119785230ea42ff31e17550eef9d8b038b31 100644 (file)
@@ -1613,5 +1613,49 @@ struct create_posix_rsp {
         * var sized group SID
         */
 } __packed;
+
+/*
+ * SMB2-only POSIX info level
+ *
+ * See posix_info_sid_size(), posix_info_extra_size() and
+ * posix_info_parse() to help with the handling of this struct.
+ */
+struct smb2_posix_info {
+       __le32 NextEntryOffset;
+       __u32 Ignored;
+       __le64 CreationTime;
+       __le64 LastAccessTime;
+       __le64 LastWriteTime;
+       __le64 ChangeTime;
+       __le64 EndOfFile;
+       __le64 AllocationSize;
+       __le32 DosAttributes;
+       __le64 Inode;
+       __le32 DeviceId;
+       __le32 Zero;
+       /* beginning of POSIX Create Context Response */
+       __le32 HardLinks;
+       __le32 ReparseTag;
+       __le32 Mode;
+       /*
+        * var sized owner SID
+        * var sized group SID
+        * le32 filenamelength
+        * u8  filename[]
+        */
+} __packed;
+
+/*
+ * Parsed version of the above struct. Allows direct access to the
+ * variable length fields
+ */
+struct smb2_posix_info_parsed {
+       const struct smb2_posix_info *base;
+       size_t size;
+       struct cifs_sid owner;
+       struct cifs_sid group;
+       int name_len;
+       const u8 *name;
 };
+
 #endif                         /* _SMB2PDU_H */
index de6388ef344f940d8ea469f4b6fe0b7db98aff51..c0f0801e7e8e055bd4e974776008d77519424298 100644 (file)
@@ -272,4 +272,6 @@ extern int smb2_query_info_compound(const unsigned int xid,
                                    u32 class, u32 type, u32 output_len,
                                    struct kvec *rsp, int *buftype,
                                    struct cifs_sb_info *cifs_sb);
+int posix_info_parse(const void *beg, const void *end,
+                    struct smb2_posix_info_parsed *out);
 #endif                 /* _SMB2PROTO_H */