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)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb2_ioctl.c
↓ open down ↓ 14 lines elided ↑ open up ↑
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  /*
  29   29   * Dispatch function for SMB2_IOCTL
  30   30   * [MS-SMB2] 3.3.5.15
  31   31   */
  32   32  
  33   33  #include <smbsrv/smb2_kproto.h>
  34      -#include <smbsrv/winioctl.h>
       34 +#include <smb/winioctl.h>
  35   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   36  smb_sdrc_t
  49   37  smb2_ioctl(smb_request_t *sr)
  50   38  {
  51   39          smb2fid_t smb2fid;
  52   40          smb_fsctl_t fsctl;
  53   41          mbuf_chain_t in_mbc;
  54      -        struct smb2_ioctbl_ent *te;
  55   42          uint32_t InputOffset;
  56   43          uint32_t MaxInputResp;
  57   44          uint32_t OutputOffset;
  58   45          uint32_t Flags;
  59      -        uint32_t status;
  60   46          uint16_t StructSize;
       47 +        uint16_t DeviceType;
       48 +        uint32_t status = 0;
  61   49          int rc = 0;
  62   50  
       51 +        /* Todo: put fsctl in sr->arg.ioctl (visible in dtrace probes) */
  63   52          bzero(&in_mbc, sizeof (in_mbc));
  64   53  
  65   54          /*
  66      -         * SMB2 Ioctl request
       55 +         * Decode SMB2 Ioctl request
  67   56           */
  68   57          rc = smb_mbc_decodef(
  69   58              &sr->smb_data, "w..lqqlllllll4.",
  70   59              &StructSize,                /* w */
  71   60              /* reserved                   .. */
  72   61              &fsctl.CtlCode,             /* l */
  73   62              &smb2fid.persistent,        /* q */
  74   63              &smb2fid.temporal,          /* q */
  75   64              &InputOffset,               /* l */
  76   65              &fsctl.InputCount,          /* l */
  77   66              &MaxInputResp,              /* l */
  78   67              &OutputOffset,              /* l */
  79   68              &fsctl.OutputCount,         /* l */
  80   69              &fsctl.MaxOutputResp,       /* l */
  81   70              &Flags);                    /* l */
  82   71              /* reserved2                  4. */
  83   72          if (rc || StructSize != 57)
  84   73                  return (SDRC_ERROR);
  85   74  
  86      -        if (Flags != SMB2_0_IOCTL_IS_FSCTL) {
  87      -                status = NT_STATUS_NOT_SUPPORTED;
  88      -                goto errout;
       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 +                }
  89   88          }
       89 +        fsctl.in_mbc = &in_mbc;
  90   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   91          /*
 105      -         * Some requests are only valid on IPC$
       92 +         * If output is possible, setup the output mbuf_chain
 106   93           */
 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      -        }
       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;
 112   98  
 113   99          /*
 114      -         * Note: some ioctl commands don't need a FID.
      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.)
 115  109           */
 116      -        if (te->te_flags & ITF_NO_FID) {
 117      -                if (smb2fid.temporal != ~0LL) {
      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) {
 118  120                          status = NT_STATUS_INVALID_PARAMETER;
 119      -                        goto errout;
 120  121                  }
 121      -        } else {
      122 +                break;
      123 +        default:
 122  124                  status = smb2sr_lookup_fid(sr, &smb2fid);
 123  125                  if (status) {
 124  126                          status = NT_STATUS_FILE_CLOSED;
 125      -                        goto errout;
 126  127                  }
      128 +                break;
 127  129          }
 128  130  
 129  131          /*
 130      -         * Note: some ioctls require a "disk" fid.
      132 +         * Keep FID lookup before the start probe.
 131  133           */
 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      -        }
      134 +        DTRACE_SMB2_START(op__Ioctl, smb_request_t *, sr);
 139  135  
      136 +        if (status)
      137 +                goto errout;
      138 +
 140  139          /*
 141      -         * If there's an input buffer, setup a shadow.
      140 +         * Dispatch to the handler for CtlCode
      141 +         * See CTL_CODE() in winioctl.h
 142  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      -                }
      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;
 154  160          }
 155      -        fsctl.in_mbc = &in_mbc;
 156  161  
 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;
      162 +errout:
      163 +        sr->smb2_status = status;
      164 +        DTRACE_SMB2_DONE(op__Ioctl, smb_request_t *, sr);
 164  165  
 165      -        /*
 166      -         * Dispatch to the handler for CtlCode
 167      -         */
 168      -        status = (te->te_func)(sr, &fsctl);
 169  166          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. */
      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. */
 174  181          }
 175  182  
 176  183          fsctl.InputCount = 0;
 177  184          InputOffset = SMB2_HDR_SIZE + 48;
 178  185  
 179  186          fsctl.OutputCount = MBC_LENGTH(&sr->raw_data);
 180  187          OutputOffset = (fsctl.OutputCount) ? InputOffset : 0;
 181  188  
 182  189          /*
 183      -         * SMB2 Ioctl reply
      190 +         * Encode SMB2 Ioctl reply
 184  191           */
 185  192          StructSize = 49;
 186  193          rc = smb_mbc_encodef(
 187  194              &sr->reply, "w..lqqlllll4.#C",
 188  195              StructSize,                 /* w */
 189  196              /* reserved                   .. */
 190  197              fsctl.CtlCode,              /* l */
 191  198              smb2fid.persistent,         /* q */
 192  199              smb2fid.temporal,           /* q */
 193  200              InputOffset,                /* l */
 194  201              fsctl.InputCount,           /* l */
 195  202              OutputOffset,               /* l */
 196  203              fsctl.OutputCount,          /* l */
 197      -            Flags,                      /* l */
      204 +            0,                  /* Flags   l */
 198  205              /* reserved2                  4. */
 199  206              fsctl.OutputCount,          /* # */
 200  207              &sr->raw_data);             /* C */
 201      -        return ((rc) ? SDRC_ERROR : SDRC_SUCCESS);
      208 +        if (rc)
      209 +                sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
 202  210  
 203      -errout:
 204      -        smb2sr_put_error(sr, status);
 205  211          return (SDRC_SUCCESS);
 206  212  }
 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      -};
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX