This is really cool - here is sample output run against a file on a Samba mount: sfrench@smf-Thinkpad-P51:~$ ./querysd /mnt/file4 Revision:1 Control: 0490 Owner: S-1-5-21--1258851229--573074714-1715408553-1000 Group: S-1-22-2-1000 DACL: Type:00 Flags:00 ff011e000105000000000005150000006374f7b4e692d7dda90e3f66e803000000001800 Type:00 Flags:00 9f011200010200000000001602000000e803000000001400 Type:00 Flags:00 9f01120001010000000000010000000000000000 On Wed, Sep 12, 2018 at 9:59 PM Ronnie Sahlberg <lsahlber@xxxxxxxxxx> wrote: > > Steve, > > Attached is a trivial program to query and partially decode the security descriptor from userspace > to illustrate how it can be used. > > > > ----- Original Message ----- > From: "Ronnie Sahlberg" <lsahlber@xxxxxxxxxx> > To: "linux-cifs" <linux-cifs@xxxxxxxxxxxxxxx> > Cc: "Steve French" <smfrench@xxxxxxxxx> > Sent: Thursday, 13 September, 2018 12:57:13 PM > Subject: [PATCH] cifs: add IOCTL for QUERY_INFO passthrough to userspace > > This allows userspace tools to query the raw info levels for cifs files > and process the response in userspace. > In particular this is useful for many of those data where there is no > corresponding native data structure in linux. > For example querying the security descriptor for a file and extract the > SIDs. > > Signed-off-by: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> > --- > fs/cifs/cifs_ioctl.h | 9 +++++++ > fs/cifs/cifsglob.h | 4 ++++ > fs/cifs/ioctl.c | 18 ++++++++++++++ > fs/cifs/smb2ops.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 98 insertions(+) > > diff --git a/fs/cifs/cifs_ioctl.h b/fs/cifs/cifs_ioctl.h > index 57ff0756e30c..d8b7353260f6 100644 > --- a/fs/cifs/cifs_ioctl.h > +++ b/fs/cifs/cifs_ioctl.h > @@ -43,8 +43,17 @@ struct smb_snapshot_array { > /* snapshots[]; */ > } __packed; > > +struct smb_query_info { > + __u32 buffer_length; > + __u32 info_type; > + __u32 file_info_class; > + __u32 additional_information; > + /* char buffer[]; */ > +} __packed; > + > #define CIFS_IOCTL_MAGIC 0xCF > #define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int) > #define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4) > #define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info) > #define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array) > +#define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info) > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > index 9dcaed031843..bb9e5b90923d 100644 > --- a/fs/cifs/cifsglob.h > +++ b/fs/cifs/cifsglob.h > @@ -465,6 +465,10 @@ struct smb_version_operations { > enum securityEnum (*select_sectype)(struct TCP_Server_Info *, > enum securityEnum); > int (*next_header)(char *); > + /* ioctl passthrough for query_info */ > + int (*ioctl_query_info)(const unsigned int xid, > + struct cifsFileInfo *file, > + unsigned long p); > }; > > struct smb_version_values { > diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c > index 54f32f9143a9..1e6b399ebb63 100644 > --- a/fs/cifs/ioctl.c > +++ b/fs/cifs/ioctl.c > @@ -34,6 +34,21 @@ > #include "cifs_ioctl.h" > #include <linux/btrfs.h> > > +static long cifs_ioctl_query_info(unsigned int xid, struct file *filep, > + unsigned long p) > +{ > + struct cifsFileInfo *pSMBFile = filep->private_data; > + struct cifs_tcon *tcon; > + > + tcon = tlink_tcon(pSMBFile->tlink); > + > + if (tcon->ses->server->ops->ioctl_query_info) > + return tcon->ses->server->ops->ioctl_query_info( > + xid, pSMBFile, p); > + else > + return -EOPNOTSUPP; > +} > + > static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, > unsigned long srcfd) > { > @@ -196,6 +211,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) > case CIFS_IOC_COPYCHUNK_FILE: > rc = cifs_ioctl_copychunk(xid, filep, arg); > break; > + case CIFS_QUERY_INFO: > + rc = cifs_ioctl_query_info(xid, filep, arg); > + break; > case CIFS_IOC_SET_INTEGRITY: > if (pSMBFile == NULL) > break; > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index 23118b7a2bbc..8c9f1c638e0f 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -1057,6 +1057,69 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, > return rc; > } > > +static int > +smb2_ioctl_query_info(const unsigned int xid, > + struct cifsFileInfo *file, > + unsigned long p) > +{ > + struct cifs_tcon *tcon = tlink_tcon(file->tlink); > + struct cifs_ses *ses = tcon->ses; > + void __user *arg = (void __user *)p; > + struct smb_query_info qi, *pqi; > + int rc = 0; > + int flags = 0; > + struct smb_rqst rqst; > + struct kvec iov[1]; > + struct kvec rsp_iov; > + int resp_buftype; > + struct smb2_query_info_rsp *rsp = NULL; > + > + if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) > + return -EFAULT; > + > + if (!ses || !(ses->server)) > + return -EIO; > + > + if (smb3_encryption_required(tcon)) > + flags |= CIFS_TRANSFORM_REQ; > + > + memset(&rqst, 0, sizeof(struct smb_rqst)); > + memset(&iov, 0, sizeof(iov)); > + rqst.rq_iov = iov; > + rqst.rq_nvec = 1; > + > + rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid, > + file->fid.volatile_fid, > + qi.file_info_class, qi.info_type, > + qi.additional_information, > + qi.buffer_length); > + if (rc) > + goto iqinf_exit; > + > + rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); > + rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; > + if (rc) > + goto iqinf_exit; > + > + pqi = arg; > + if (le32_to_cpu(rsp->OutputBufferLength) < qi.buffer_length) > + qi.buffer_length = le32_to_cpu(rsp->OutputBufferLength); > + if (copy_to_user(&pqi->buffer_length, &qi.buffer_length, > + sizeof(qi.buffer_length))) { > + rc = -EFAULT; > + goto iqinf_exit; > + } > + if (copy_to_user(pqi + 1, rsp->Buffer, qi.buffer_length)) { > + rc = -EFAULT; > + goto iqinf_exit; > + } > + > + iqinf_exit: > + SMB2_query_info_free(&rqst); > + free_rsp_buf(resp_buftype, rsp); > + return rc; > +} > + > static ssize_t > smb2_copychunk_range(const unsigned int xid, > struct cifsFileInfo *srcfile, > @@ -3303,6 +3366,7 @@ struct smb_version_operations smb20_operations = { > .set_acl = set_smb2_acl, > #endif /* CIFS_ACL */ > .next_header = smb2_next_header, > + .ioctl_query_info = smb2_ioctl_query_info, > }; > > struct smb_version_operations smb21_operations = { > @@ -3398,6 +3462,7 @@ struct smb_version_operations smb21_operations = { > .set_acl = set_smb2_acl, > #endif /* CIFS_ACL */ > .next_header = smb2_next_header, > + .ioctl_query_info = smb2_ioctl_query_info, > }; > > struct smb_version_operations smb30_operations = { > @@ -3502,6 +3567,7 @@ struct smb_version_operations smb30_operations = { > .set_acl = set_smb2_acl, > #endif /* CIFS_ACL */ > .next_header = smb2_next_header, > + .ioctl_query_info = smb2_ioctl_query_info, > }; > > struct smb_version_operations smb311_operations = { > @@ -3607,6 +3673,7 @@ struct smb_version_operations smb311_operations = { > .set_acl = set_smb2_acl, > #endif /* CIFS_ACL */ > .next_header = smb2_next_header, > + .ioctl_query_info = smb2_ioctl_query_info, > }; > > struct smb_version_values smb20_values = { > -- > 2.13.3 > -- Thanks, Steve