Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5598 SMB needs a few more ioctls for Hyper-V
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4159 SMB2 fsctl validate negotiate error
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2188 Browsing top level share produces RPC error 1728
SMB-136 Snapshots not visible in Windows previous versions
NEX-1059 Shared folder is not available in Windows 7/8/2012 when SMB2 is enabled in Workgroup mode
(Implement "Secure Negotiation")
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
SMB-110 panic mapping a share from Nexentastor to the windows 2012 R2 client
SMB-109 Codenomicon: SMB TC: 409480 - Panic with SMB2_FIND request
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)

*** 20,71 **** */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* * Dispatch function for SMB2_IOCTL * [MS-SMB2] 3.3.5.15 */ #include <smbsrv/smb2_kproto.h> ! #include <smbsrv/winioctl.h> - struct smb2_ioctbl_ent { - uint32_t te_code; - uint32_t te_flags; - uint32_t (*te_func)(smb_request_t *, smb_fsctl_t *); - }; - static struct smb2_ioctbl_ent smb2_ioc_tbl[]; - - /* te_flags */ - #define ITF_IPC_ONLY 1 - #define ITF_NO_FID 2 - #define ITF_DISK_FID 4 - smb_sdrc_t smb2_ioctl(smb_request_t *sr) { smb2fid_t smb2fid; smb_fsctl_t fsctl; mbuf_chain_t in_mbc; - struct smb2_ioctbl_ent *te; uint32_t InputOffset; uint32_t MaxInputResp; uint32_t OutputOffset; uint32_t Flags; - uint32_t status; uint16_t StructSize; int rc = 0; bzero(&in_mbc, sizeof (in_mbc)); /* ! * SMB2 Ioctl request */ rc = smb_mbc_decodef( &sr->smb_data, "w..lqqlllllll4.", &StructSize, /* w */ /* reserved .. */ --- 20,60 ---- */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * ! * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * Dispatch function for SMB2_IOCTL * [MS-SMB2] 3.3.5.15 */ #include <smbsrv/smb2_kproto.h> ! #include <smb/winioctl.h> smb_sdrc_t smb2_ioctl(smb_request_t *sr) { smb2fid_t smb2fid; smb_fsctl_t fsctl; mbuf_chain_t in_mbc; uint32_t InputOffset; uint32_t MaxInputResp; uint32_t OutputOffset; uint32_t Flags; uint16_t StructSize; + uint16_t DeviceType; + uint32_t status = 0; int rc = 0; + /* Todo: put fsctl in sr->arg.ioctl (visible in dtrace probes) */ bzero(&in_mbc, sizeof (in_mbc)); /* ! * Decode SMB2 Ioctl request */ rc = smb_mbc_decodef( &sr->smb_data, "w..lqqlllllll4.", &StructSize, /* w */ /* reserved .. */
*** 81,188 **** &Flags); /* l */ /* reserved2 4. */ if (rc || StructSize != 57) return (SDRC_ERROR); ! if (Flags != SMB2_0_IOCTL_IS_FSCTL) { ! status = NT_STATUS_NOT_SUPPORTED; ! goto errout; } - - for (te = smb2_ioc_tbl; te->te_code; te++) { - if (te->te_code == fsctl.CtlCode) - break; } ! if (te->te_code == 0) { ! #ifdef DEBUG ! cmn_err(CE_NOTE, "smb2_ioctl: unknown code 0x%x", ! fsctl.CtlCode); ! #endif ! status = NT_STATUS_NOT_SUPPORTED; ! goto errout; ! } /* ! * Some requests are only valid on IPC$ */ ! if ((te->te_flags & ITF_IPC_ONLY) != 0 && ! !STYPE_ISIPC(sr->tid_tree->t_res_type)) { ! status = NT_STATUS_INVALID_DEVICE_REQUEST; ! goto errout; ! } /* ! * Note: some ioctl commands don't need a FID. */ ! if (te->te_flags & ITF_NO_FID) { ! if (smb2fid.temporal != ~0LL) { status = NT_STATUS_INVALID_PARAMETER; - goto errout; } ! } else { status = smb2sr_lookup_fid(sr, &smb2fid); if (status) { status = NT_STATUS_FILE_CLOSED; - goto errout; } } /* ! * Note: some ioctls require a "disk" fid. */ ! if (te->te_flags & ITF_DISK_FID) { ! if (sr->fid_ofile == NULL || ! !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) { ! status = NT_STATUS_INVALID_PARAMETER; goto errout; - } - } /* ! * If there's an input buffer, setup a shadow. */ ! if (fsctl.InputCount) { ! if (InputOffset < (SMB2_HDR_SIZE + 56)) { ! status = NT_STATUS_INVALID_PARAMETER; ! goto errout; } - rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data, - sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount); - if (rc) { - status = NT_STATUS_INVALID_PARAMETER; - goto errout; - } - } - fsctl.in_mbc = &in_mbc; ! /* ! * If output is possible, setup the output mbuf_chain ! */ ! if (fsctl.MaxOutputResp > smb2_max_trans) ! fsctl.MaxOutputResp = smb2_max_trans; ! sr->raw_data.max_bytes = fsctl.MaxOutputResp; ! fsctl.out_mbc = &sr->raw_data; /* ! * Dispatch to the handler for CtlCode */ ! status = (te->te_func)(sr, &fsctl); ! if (status != 0) { ! sr->smb2_status = status; ! if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) ! goto errout; ! /* Warnings like NT_STATUS_BUFFER_OVERFLOW are OK. */ } fsctl.InputCount = 0; InputOffset = SMB2_HDR_SIZE + 48; fsctl.OutputCount = MBC_LENGTH(&sr->raw_data); OutputOffset = (fsctl.OutputCount) ? InputOffset : 0; /* ! * SMB2 Ioctl reply */ StructSize = 49; rc = smb_mbc_encodef( &sr->reply, "w..lqqlllll4.#C", StructSize, /* w */ --- 70,195 ---- &Flags); /* l */ /* reserved2 4. */ if (rc || StructSize != 57) return (SDRC_ERROR); ! /* ! * If there's an input buffer, setup a shadow. ! */ ! if (fsctl.InputCount) { ! if (InputOffset < (SMB2_HDR_SIZE + 56)) ! return (SDRC_ERROR); ! if (fsctl.InputCount > smb2_max_trans) ! return (SDRC_ERROR); ! rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data, ! sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount); ! if (rc) { ! return (SDRC_ERROR); } } ! fsctl.in_mbc = &in_mbc; /* ! * If output is possible, setup the output mbuf_chain */ ! if (fsctl.MaxOutputResp > smb2_max_trans) ! fsctl.MaxOutputResp = smb2_max_trans; ! sr->raw_data.max_bytes = fsctl.MaxOutputResp; ! fsctl.out_mbc = &sr->raw_data; /* ! * [MS-SMB2] 3.3.5.15 ! * ! * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL ! * the server MUST fail the request with STATUS_NOT_SUPPORTED. ! * ! * If the CtlCode is any of (... see switch below...) and the ! * value of FileId in the SMB2 Header of the request is not ! * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request ! * with STATUS_INVALID_PARAMETER. (Otherwise lookup the FID.) */ ! if (Flags != SMB2_0_IOCTL_IS_FSCTL) { ! status = NT_STATUS_NOT_SUPPORTED; ! } else switch (fsctl.CtlCode) { ! case FSCTL_DFS_GET_REFERRALS: ! case FSCTL_DFS_GET_REFERRALS_EX: ! case FSCTL_QUERY_NETWORK_INTERFACE_INFO: ! case FSCTL_VALIDATE_NEGOTIATE_INFO: ! case FSCTL_PIPE_WAIT: ! if (smb2fid.temporal != ~0LL || ! smb2fid.persistent != ~0LL) { status = NT_STATUS_INVALID_PARAMETER; } ! break; ! default: status = smb2sr_lookup_fid(sr, &smb2fid); if (status) { status = NT_STATUS_FILE_CLOSED; } + break; } /* ! * Keep FID lookup before the start probe. */ ! DTRACE_SMB2_START(op__Ioctl, smb_request_t *, sr); ! ! if (status) goto errout; /* ! * Dispatch to the handler for CtlCode ! * See CTL_CODE() in winioctl.h */ ! DeviceType = fsctl.CtlCode >> 16; ! switch (DeviceType) { ! case FILE_DEVICE_DFS: /* 6 */ ! status = smb_dfs_fsctl(sr, &fsctl); ! break; ! case FILE_DEVICE_FILE_SYSTEM: /* 9 */ ! status = smb2_fsctl_fs(sr, &fsctl); ! break; ! case FILE_DEVICE_NAMED_PIPE: /* 17 */ ! status = smb_opipe_fsctl(sr, &fsctl); ! break; ! case FILE_DEVICE_NETWORK_FILE_SYSTEM: /* 20 */ ! status = smb2_fsctl_netfs(sr, &fsctl); ! break; ! default: ! status = NT_STATUS_NOT_SUPPORTED; ! break; } ! errout: ! sr->smb2_status = status; ! DTRACE_SMB2_DONE(op__Ioctl, smb_request_t *, sr); + if (status != 0) { /* ! * NT status codes with severity "error" normally cause ! * an error response with no data. However, there are ! * exceptions like smb2_fsctl_copychunk that may return ! * severity==error _with_ a data part. */ ! if ((NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) && ! (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK) && ! (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK_WRITE)) { ! /* no error data */ ! smb2sr_put_error(sr, status); ! return (SDRC_SUCCESS); } + /* Else, error response _with_ data. */ + } fsctl.InputCount = 0; InputOffset = SMB2_HDR_SIZE + 48; fsctl.OutputCount = MBC_LENGTH(&sr->raw_data); OutputOffset = (fsctl.OutputCount) ? InputOffset : 0; /* ! * Encode SMB2 Ioctl reply */ StructSize = 49; rc = smb_mbc_encodef( &sr->reply, "w..lqqlllll4.#C", StructSize, /* w */
*** 192,264 **** smb2fid.temporal, /* q */ InputOffset, /* l */ fsctl.InputCount, /* l */ OutputOffset, /* l */ fsctl.OutputCount, /* l */ ! Flags, /* l */ /* reserved2 4. */ fsctl.OutputCount, /* # */ &sr->raw_data); /* C */ ! return ((rc) ? SDRC_ERROR : SDRC_SUCCESS); - errout: - smb2sr_put_error(sr, status); return (SDRC_SUCCESS); } - - /* ARGSUSED */ - static uint32_t - smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl) - { - return (NT_STATUS_NOT_SUPPORTED); - } - - static struct smb2_ioctbl_ent - smb2_ioc_tbl[] = { - - /* - * FILE_DEVICE_DFS (6) - */ - { FSCTL_DFS_GET_REFERRALS, - ITF_IPC_ONLY | ITF_NO_FID, smb_dfs_get_referrals }, - { FSCTL_DFS_GET_REFERRALS_EX, - ITF_IPC_ONLY | ITF_NO_FID, smb_dfs_get_referrals }, - - /* - * FILE_DEVICE_FILE_SYSTEM (9) - */ - { FSCTL_SET_REPARSE_POINT, 0, smb2_fsctl_notsup }, - { FSCTL_CREATE_OR_GET_OBJECT_ID, 0, smb2_fsctl_notsup }, - { FSCTL_FILE_LEVEL_TRIM, 0, smb2_fsctl_notsup }, - - /* - * FILE_DEVICE_NAMED_PIPE (17) - */ - { FSCTL_PIPE_PEEK, - ITF_IPC_ONLY, smb_opipe_fsctl }, - { FSCTL_PIPE_TRANSCEIVE, - ITF_IPC_ONLY, smb_opipe_fsctl }, - { FSCTL_PIPE_WAIT, - ITF_IPC_ONLY | ITF_NO_FID, smb_opipe_fsctl }, - - /* - * FILE_DEVICE_NETWORK_FILE_SYSTEM (20) - */ - { FSCTL_SRV_ENUMERATE_SNAPSHOTS, - ITF_DISK_FID, smb_vss_enum_snapshots }, - { FSCTL_SRV_REQUEST_RESUME_KEY, 0, smb2_fsctl_notsup }, - { FSCTL_SRV_COPYCHUNK, 0, smb2_fsctl_notsup }, - { FSCTL_SRV_COPYCHUNK_WRITE, 0, smb2_fsctl_notsup }, - { FSCTL_SRV_READ_HASH, 0, smb2_fsctl_notsup }, - - { FSCTL_LMR_REQUEST_RESILIENCY, - ITF_NO_FID, smb2_fsctl_notsup }, - { FSCTL_QUERY_NETWORK_INTERFACE_INFO, - ITF_NO_FID, smb2_fsctl_notsup }, - { FSCTL_VALIDATE_NEGOTIATE_INFO, - ITF_NO_FID, smb2_fsctl_vneginfo }, - - /* - * End marker - */ - { 0, 0, 0 } - }; --- 199,212 ---- smb2fid.temporal, /* q */ InputOffset, /* l */ fsctl.InputCount, /* l */ OutputOffset, /* l */ fsctl.OutputCount, /* l */ ! 0, /* Flags l */ /* reserved2 4. */ fsctl.OutputCount, /* # */ &sr->raw_data); /* C */ ! if (rc) ! sr->smb2_status = NT_STATUS_INTERNAL_ERROR; return (SDRC_SUCCESS); }