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)


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * Dispatch function for SMB2_IOCTL
  30  * [MS-SMB2] 3.3.5.15
  31  */
  32 
  33 #include <smbsrv/smb2_kproto.h>
  34 #include <smbsrv/winioctl.h>
  35 
  36 struct smb2_ioctbl_ent {
  37         uint32_t        te_code;
  38         uint32_t        te_flags;
  39         uint32_t        (*te_func)(smb_request_t *, smb_fsctl_t *);
  40 };
  41 static struct smb2_ioctbl_ent smb2_ioc_tbl[];
  42 
  43 /* te_flags */
  44 #define ITF_IPC_ONLY    1
  45 #define ITF_NO_FID      2
  46 #define ITF_DISK_FID    4
  47 
  48 smb_sdrc_t
  49 smb2_ioctl(smb_request_t *sr)
  50 {
  51         smb2fid_t smb2fid;
  52         smb_fsctl_t fsctl;
  53         mbuf_chain_t in_mbc;
  54         struct smb2_ioctbl_ent *te;
  55         uint32_t InputOffset;
  56         uint32_t MaxInputResp;
  57         uint32_t OutputOffset;
  58         uint32_t Flags;
  59         uint32_t status;
  60         uint16_t StructSize;


  61         int rc = 0;
  62 

  63         bzero(&in_mbc, sizeof (in_mbc));
  64 
  65         /*
  66          * SMB2 Ioctl request
  67          */
  68         rc = smb_mbc_decodef(
  69             &sr->smb_data, "w..lqqlllllll4.",
  70             &StructSize,            /* w */
  71             /* reserved                   .. */
  72             &fsctl.CtlCode,         /* l */
  73             &smb2fid.persistent,    /* q */
  74             &smb2fid.temporal,              /* q */
  75             &InputOffset,           /* l */
  76             &fsctl.InputCount,              /* l */
  77             &MaxInputResp,          /* l */
  78             &OutputOffset,          /* l */
  79             &fsctl.OutputCount,             /* l */
  80             &fsctl.MaxOutputResp,   /* l */
  81             &Flags);                        /* l */
  82             /* reserved2                  4. */
  83         if (rc || StructSize != 57)
  84                 return (SDRC_ERROR);
  85 
  86         if (Flags != SMB2_0_IOCTL_IS_FSCTL) {
  87                 status = NT_STATUS_NOT_SUPPORTED;
  88                 goto errout;









  89         }
  90 
  91         for (te = smb2_ioc_tbl; te->te_code; te++) {
  92                 if (te->te_code == fsctl.CtlCode)
  93                         break;
  94         }
  95         if (te->te_code == 0) {
  96 #ifdef  DEBUG
  97                 cmn_err(CE_NOTE, "smb2_ioctl: unknown code 0x%x",
  98                     fsctl.CtlCode);
  99 #endif
 100                 status = NT_STATUS_NOT_SUPPORTED;
 101                 goto errout;
 102         }
 103 
 104         /*
 105          * Some requests are only valid on IPC$
 106          */
 107         if ((te->te_flags & ITF_IPC_ONLY) != 0 &&
 108             !STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 109                 status = NT_STATUS_INVALID_DEVICE_REQUEST;
 110                 goto errout;
 111         }
 112 
 113         /*
 114          * Note: some ioctl commands don't need a FID.








 115          */
 116         if (te->te_flags & ITF_NO_FID) {
 117                 if (smb2fid.temporal != ~0LL) {








 118                         status = NT_STATUS_INVALID_PARAMETER;
 119                         goto errout;
 120                 }
 121         } else {

 122                 status = smb2sr_lookup_fid(sr, &smb2fid);
 123                 if (status) {
 124                         status = NT_STATUS_FILE_CLOSED;
 125                         goto errout;
 126                 }

 127         }
 128 
 129         /*
 130          * Note: some ioctls require a "disk" fid.
 131          */
 132         if (te->te_flags & ITF_DISK_FID) {
 133                 if (sr->fid_ofile == NULL ||
 134                     !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
 135                         status = NT_STATUS_INVALID_PARAMETER;
 136                         goto errout;
 137                 }
 138         }
 139 
 140         /*
 141          * If there's an input buffer, setup a shadow.

 142          */
 143         if (fsctl.InputCount) {
 144                 if (InputOffset < (SMB2_HDR_SIZE + 56)) {
 145                         status = NT_STATUS_INVALID_PARAMETER;
 146                         goto errout;













 147                 }
 148                 rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data,
 149                     sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount);
 150                 if (rc) {
 151                         status = NT_STATUS_INVALID_PARAMETER;
 152                         goto errout;
 153                 }
 154         }
 155         fsctl.in_mbc = &in_mbc;
 156 
 157         /*
 158          * If output is possible, setup the output mbuf_chain
 159          */
 160         if (fsctl.MaxOutputResp > smb2_max_trans)
 161                 fsctl.MaxOutputResp = smb2_max_trans;
 162         sr->raw_data.max_bytes = fsctl.MaxOutputResp;
 163         fsctl.out_mbc = &sr->raw_data;
 164 

 165         /*
 166          * Dispatch to the handler for CtlCode



 167          */
 168         status = (te->te_func)(sr, &fsctl);
 169         if (status != 0) {
 170                 sr->smb2_status = status;
 171                 if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR)
 172                         goto errout;
 173                 /* Warnings like NT_STATUS_BUFFER_OVERFLOW are OK. */
 174         }


 175 
 176         fsctl.InputCount = 0;
 177         InputOffset = SMB2_HDR_SIZE + 48;
 178 
 179         fsctl.OutputCount = MBC_LENGTH(&sr->raw_data);
 180         OutputOffset = (fsctl.OutputCount) ? InputOffset : 0;
 181 
 182         /*
 183          * SMB2 Ioctl reply
 184          */
 185         StructSize = 49;
 186         rc = smb_mbc_encodef(
 187             &sr->reply, "w..lqqlllll4.#C",
 188             StructSize,                 /* w */
 189             /* reserved                   .. */
 190             fsctl.CtlCode,              /* l */
 191             smb2fid.persistent,         /* q */
 192             smb2fid.temporal,           /* q */
 193             InputOffset,                /* l */
 194             fsctl.InputCount,           /* l */
 195             OutputOffset,               /* l */
 196             fsctl.OutputCount,          /* l */
 197             Flags,                      /* l */
 198             /* reserved2                  4. */
 199             fsctl.OutputCount,          /* # */
 200             &sr->raw_data);              /* C */
 201         return ((rc) ? SDRC_ERROR : SDRC_SUCCESS);

 202 
 203 errout:
 204         smb2sr_put_error(sr, status);
 205         return (SDRC_SUCCESS);
 206 }
 207 
 208 /* ARGSUSED */
 209 static uint32_t
 210 smb2_fsctl_notsup(smb_request_t *sr, smb_fsctl_t *fsctl)
 211 {
 212         return (NT_STATUS_NOT_SUPPORTED);
 213 }
 214 
 215 static struct smb2_ioctbl_ent
 216 smb2_ioc_tbl[] = {
 217 
 218         /*
 219          * FILE_DEVICE_DFS (6)
 220          */
 221         { FSCTL_DFS_GET_REFERRALS,
 222             ITF_IPC_ONLY | ITF_NO_FID,          smb_dfs_get_referrals },
 223         { FSCTL_DFS_GET_REFERRALS_EX,
 224             ITF_IPC_ONLY | ITF_NO_FID,          smb_dfs_get_referrals },
 225 
 226         /*
 227          * FILE_DEVICE_FILE_SYSTEM (9)
 228          */
 229         { FSCTL_SET_REPARSE_POINT,      0,      smb2_fsctl_notsup },
 230         { FSCTL_CREATE_OR_GET_OBJECT_ID, 0,     smb2_fsctl_notsup },
 231         { FSCTL_FILE_LEVEL_TRIM,        0,      smb2_fsctl_notsup },
 232 
 233         /*
 234          * FILE_DEVICE_NAMED_PIPE (17)
 235          */
 236         { FSCTL_PIPE_PEEK,
 237             ITF_IPC_ONLY,                       smb_opipe_fsctl },
 238         { FSCTL_PIPE_TRANSCEIVE,
 239             ITF_IPC_ONLY,                       smb_opipe_fsctl },
 240         { FSCTL_PIPE_WAIT,
 241             ITF_IPC_ONLY | ITF_NO_FID,          smb_opipe_fsctl },
 242 
 243         /*
 244          * FILE_DEVICE_NETWORK_FILE_SYSTEM (20)
 245          */
 246         { FSCTL_SRV_ENUMERATE_SNAPSHOTS,
 247             ITF_DISK_FID,                       smb_vss_enum_snapshots },
 248         { FSCTL_SRV_REQUEST_RESUME_KEY, 0,      smb2_fsctl_notsup },
 249         { FSCTL_SRV_COPYCHUNK,          0,      smb2_fsctl_notsup },
 250         { FSCTL_SRV_COPYCHUNK_WRITE,    0,      smb2_fsctl_notsup },
 251         { FSCTL_SRV_READ_HASH,          0,      smb2_fsctl_notsup },
 252 
 253         { FSCTL_LMR_REQUEST_RESILIENCY,
 254             ITF_NO_FID,         smb2_fsctl_notsup },
 255         { FSCTL_QUERY_NETWORK_INTERFACE_INFO,
 256             ITF_NO_FID,         smb2_fsctl_notsup },
 257         { FSCTL_VALIDATE_NEGOTIATE_INFO,
 258             ITF_NO_FID,         smb2_fsctl_vneginfo },
 259 
 260         /*
 261          * End marker
 262          */
 263         { 0, 0, 0 }
 264 };


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 /*
  29  * Dispatch function for SMB2_IOCTL
  30  * [MS-SMB2] 3.3.5.15
  31  */
  32 
  33 #include <smbsrv/smb2_kproto.h>
  34 #include <smb/winioctl.h>
  35 












  36 smb_sdrc_t
  37 smb2_ioctl(smb_request_t *sr)
  38 {
  39         smb2fid_t smb2fid;
  40         smb_fsctl_t fsctl;
  41         mbuf_chain_t in_mbc;

  42         uint32_t InputOffset;
  43         uint32_t MaxInputResp;
  44         uint32_t OutputOffset;
  45         uint32_t Flags;

  46         uint16_t StructSize;
  47         uint16_t DeviceType;
  48         uint32_t status = 0;
  49         int rc = 0;
  50 
  51         /* Todo: put fsctl in sr->arg.ioctl (visible in dtrace probes) */
  52         bzero(&in_mbc, sizeof (in_mbc));
  53 
  54         /*
  55          * Decode SMB2 Ioctl request
  56          */
  57         rc = smb_mbc_decodef(
  58             &sr->smb_data, "w..lqqlllllll4.",
  59             &StructSize,            /* w */
  60             /* reserved                   .. */
  61             &fsctl.CtlCode,         /* l */
  62             &smb2fid.persistent,    /* q */
  63             &smb2fid.temporal,              /* q */
  64             &InputOffset,           /* l */
  65             &fsctl.InputCount,              /* l */
  66             &MaxInputResp,          /* l */
  67             &OutputOffset,          /* l */
  68             &fsctl.OutputCount,             /* l */
  69             &fsctl.MaxOutputResp,   /* l */
  70             &Flags);                        /* l */
  71             /* reserved2                  4. */
  72         if (rc || StructSize != 57)
  73                 return (SDRC_ERROR);
  74 
  75         /*
  76          * If there's an input buffer, setup a shadow.
  77          */
  78         if (fsctl.InputCount) {
  79                 if (InputOffset < (SMB2_HDR_SIZE + 56))
  80                         return (SDRC_ERROR);
  81                 if (fsctl.InputCount > smb2_max_trans)
  82                         return (SDRC_ERROR);
  83                 rc = MBC_SHADOW_CHAIN(&in_mbc, &sr->smb_data,
  84                     sr->smb2_cmd_hdr + InputOffset, fsctl.InputCount);
  85                 if (rc) {
  86                         return (SDRC_ERROR);
  87                 }




  88         }
  89         fsctl.in_mbc = &in_mbc;







  90 
  91         /*
  92          * If output is possible, setup the output mbuf_chain
  93          */
  94         if (fsctl.MaxOutputResp > smb2_max_trans)
  95                 fsctl.MaxOutputResp = smb2_max_trans;
  96         sr->raw_data.max_bytes = fsctl.MaxOutputResp;
  97         fsctl.out_mbc = &sr->raw_data;

  98 
  99         /*
 100          * [MS-SMB2] 3.3.5.15
 101          *
 102          * If the Flags field of the request is not SMB2_0_IOCTL_IS_FSCTL
 103          * the server MUST fail the request with STATUS_NOT_SUPPORTED.
 104          *
 105          * If the CtlCode is any of (... see switch below...) and the
 106          * value of FileId in the SMB2 Header of the request is not
 107          * 0xFFFFFFFFFFFFFFFF, then the server MUST fail the request
 108          * with STATUS_INVALID_PARAMETER.  (Otherwise lookup the FID.)
 109          */
 110         if (Flags != SMB2_0_IOCTL_IS_FSCTL) {
 111                 status = NT_STATUS_NOT_SUPPORTED;
 112         } else switch (fsctl.CtlCode) {
 113         case FSCTL_DFS_GET_REFERRALS:
 114         case FSCTL_DFS_GET_REFERRALS_EX:
 115         case FSCTL_QUERY_NETWORK_INTERFACE_INFO:
 116         case FSCTL_VALIDATE_NEGOTIATE_INFO:
 117         case FSCTL_PIPE_WAIT:
 118                 if (smb2fid.temporal != ~0LL ||
 119                     smb2fid.persistent != ~0LL) {
 120                         status = NT_STATUS_INVALID_PARAMETER;

 121                 }
 122                 break;
 123         default:
 124                 status = smb2sr_lookup_fid(sr, &smb2fid);
 125                 if (status) {
 126                         status = NT_STATUS_FILE_CLOSED;

 127                 }
 128                 break;
 129         }
 130 
 131         /*
 132          * Keep FID lookup before the start probe.
 133          */
 134         DTRACE_SMB2_START(op__Ioctl, smb_request_t *, sr);
 135 
 136         if (status)

 137                 goto errout;


 138 
 139         /*
 140          * Dispatch to the handler for CtlCode
 141          * See CTL_CODE() in winioctl.h
 142          */
 143         DeviceType = fsctl.CtlCode >> 16;
 144         switch (DeviceType) {
 145         case FILE_DEVICE_DFS:           /* 6 */
 146                 status = smb_dfs_fsctl(sr, &fsctl);
 147                 break;
 148         case FILE_DEVICE_FILE_SYSTEM:   /* 9 */
 149                 status = smb2_fsctl_fs(sr, &fsctl);
 150                 break;
 151         case FILE_DEVICE_NAMED_PIPE:    /* 17 */
 152                 status = smb_opipe_fsctl(sr, &fsctl);
 153                 break;
 154         case FILE_DEVICE_NETWORK_FILE_SYSTEM: /* 20 */
 155                 status = smb2_fsctl_netfs(sr, &fsctl);
 156                 break;
 157         default:
 158                 status = NT_STATUS_NOT_SUPPORTED;
 159                 break;
 160         }








 161 
 162 errout:
 163         sr->smb2_status = status;
 164         DTRACE_SMB2_DONE(op__Ioctl, smb_request_t *, sr);




 165 
 166         if (status != 0) {
 167                 /*
 168                  * NT status codes with severity "error" normally cause
 169                  * an error response with no data.  However, there are
 170                  * exceptions like smb2_fsctl_copychunk that may return
 171                  * severity==error _with_ a data part.
 172                  */
 173                 if ((NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) &&
 174                     (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK) &&
 175                     (fsctl.CtlCode != FSCTL_SRV_COPYCHUNK_WRITE)) {
 176                         /* no error data */
 177                         smb2sr_put_error(sr, status);
 178                         return (SDRC_SUCCESS);
 179                 }
 180                 /* Else, error response _with_ data. */
 181         }
 182 
 183         fsctl.InputCount = 0;
 184         InputOffset = SMB2_HDR_SIZE + 48;
 185 
 186         fsctl.OutputCount = MBC_LENGTH(&sr->raw_data);
 187         OutputOffset = (fsctl.OutputCount) ? InputOffset : 0;
 188 
 189         /*
 190          * Encode SMB2 Ioctl reply
 191          */
 192         StructSize = 49;
 193         rc = smb_mbc_encodef(
 194             &sr->reply, "w..lqqlllll4.#C",
 195             StructSize,                 /* w */
 196             /* reserved                   .. */
 197             fsctl.CtlCode,              /* l */
 198             smb2fid.persistent,         /* q */
 199             smb2fid.temporal,           /* q */
 200             InputOffset,                /* l */
 201             fsctl.InputCount,           /* l */
 202             OutputOffset,               /* l */
 203             fsctl.OutputCount,          /* l */
 204             0,                  /* Flags   l */
 205             /* reserved2                  4. */
 206             fsctl.OutputCount,          /* # */
 207             &sr->raw_data);              /* C */
 208         if (rc)
 209                 sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
 210 


 211         return (SDRC_SUCCESS);
 212 }