Commit 349e13ad authored by Aurelien Aptel's avatar Aurelien Aptel Committed by Steve French

cifs: add smb2 POSIX info level

* add new info level and structs for SMB2 posix extension
* add functions to parse and validate it
Signed-off-by: default avatarAurelien Aptel <aaptel@suse.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 2e8af978
...@@ -1691,6 +1691,7 @@ struct smb_t2_rsp { ...@@ -1691,6 +1691,7 @@ struct smb_t2_rsp {
#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105 #define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106 #define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
#define SMB_FIND_FILE_UNIX 0x202 #define SMB_FIND_FILE_UNIX 0x202
#define SMB_FIND_FILE_POSIX_INFO 0x064
typedef struct smb_com_transaction2_qpi_req { typedef struct smb_com_transaction2_qpi_req {
struct smb_hdr hdr; /* wct = 14+ */ struct smb_hdr hdr; /* wct = 14+ */
......
...@@ -4302,6 +4302,101 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, ...@@ -4302,6 +4302,101 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
return rc; 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 static unsigned int
num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size) num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
{ {
......
...@@ -1613,5 +1613,49 @@ struct create_posix_rsp { ...@@ -1613,5 +1613,49 @@ struct create_posix_rsp {
* var sized group SID * var sized group SID
*/ */
} __packed; } __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 */ #endif /* _SMB2PDU_H */
...@@ -272,4 +272,6 @@ extern int smb2_query_info_compound(const unsigned int xid, ...@@ -272,4 +272,6 @@ extern int smb2_query_info_compound(const unsigned int xid,
u32 class, u32 type, u32 output_len, u32 class, u32 type, u32 output_len,
struct kvec *rsp, int *buftype, struct kvec *rsp, int *buftype,
struct cifs_sb_info *cifs_sb); 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 */ #endif /* _SMB2PROTO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment