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-15577 SMB2 ioct dfs_get_referral returns wrong error
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15577 SMB2 ioct dfs_get_referral returns wrong error
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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>
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 2013 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 #include <smbsrv/smb_kproto.h>
  29 #include <smbsrv/smb_dfs.h>
  30 #include <smbsrv/smb_door.h>
  31 #include <smbsrv/winioctl.h>
  32 
  33 /*
  34  * Get Referral response header flags
  35  * For exact meaning refer to MS-DFSC spec.
  36  *
  37  * R: ReferralServers
  38  * S: StorageServers
  39  * T: TargetFailback
  40  */
  41 #define DFS_HDRFLG_R            0x00000001
  42 #define DFS_HDRFLG_S            0x00000002
  43 #define DFS_HDRFLG_T            0x00000004
  44 
  45 /*
  46  * Entry flags
  47  */
  48 #define DFS_ENTFLG_T            0x0004
  49 
  50 /*
  51  * Referral entry types/versions


  67 #define DFS_REFV1_ENTSZ         8
  68 #define DFS_REFV2_ENTSZ         22
  69 #define DFS_REFV3_ENTSZ         34
  70 #define DFS_REFV4_ENTSZ         34
  71 
  72 static dfs_reftype_t smb_dfs_get_reftype(const char *);
  73 static void smb_dfs_encode_hdr(mbuf_chain_t *, dfs_info_t *);
  74 static uint32_t smb_dfs_encode_refv1(smb_request_t *, mbuf_chain_t *,
  75     dfs_info_t *);
  76 static uint32_t smb_dfs_encode_refv2(smb_request_t *, mbuf_chain_t *,
  77     dfs_info_t *);
  78 static uint32_t smb_dfs_encode_refv3x(smb_request_t *, mbuf_chain_t *,
  79     dfs_info_t *, uint16_t);
  80 static void smb_dfs_encode_targets(mbuf_chain_t *, dfs_info_t *);
  81 static uint32_t smb_dfs_referrals_get(smb_request_t *, char *, dfs_reftype_t,
  82     dfs_referral_response_t *);
  83 static void smb_dfs_referrals_free(dfs_referral_response_t *);
  84 static uint16_t smb_dfs_referrals_unclen(dfs_info_t *, uint16_t);
  85 
  86 /*
























  87  * Note: SMB1 callers in smb_trans2_dfs.c
  88  * smb_com_trans2_report_dfs_inconsistency
  89  * smb_com_trans2_get_dfs_referral
  90  */
  91 
  92 /*
  93  * See [MS-DFSC] for details about this command

  94  */
  95 uint32_t
  96 smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
  97 {
  98         dfs_info_t *referrals;
  99         dfs_referral_response_t refrsp;
 100         dfs_reftype_t reftype;
 101         char *path;
 102         uint16_t maxver;
 103         uint32_t status;
 104         int rc;
 105 
 106         /*
 107          * The caller checks this, because the error reporting method
 108          * varies across SMB versions.
 109          */
 110         ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
 111 
 112         /*
 113          * XXX Instead of decoding the referral request and encoding
 114          * the response here (in-kernel) we could pass the given
 115          * request buffer in our door call, and let that return the
 116          * response buffer ready to stuff into out_mbc.  That would
 117          * allow all this decoding/encoding to happen at user-level.
 118          * (and most of this file would go away. :-)
 119          */
 120         switch (fsctl->CtlCode) {
 121         case FSCTL_DFS_GET_REFERRALS:
 122                 /*
 123                  * Input data is (w) MaxReferralLevel, (U) path
 124                  */
 125                 rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
 126                     sr, &maxver, &path);
 127                 if (rc != 0)
 128                         return (NT_STATUS_INVALID_PARAMETER);
 129                 break;
 130 
 131         case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
 132         default:
 133                 return (NT_STATUS_NOT_SUPPORTED);
 134         }
 135 
 136         reftype = smb_dfs_get_reftype((const char *)path);
 137         switch (reftype) {
 138         case DFS_REFERRAL_INVALID:
 139                 /* Need to check the error for this case */
 140                 return (NT_STATUS_INVALID_PARAMETER);
 141 
 142         case DFS_REFERRAL_DOMAIN:
 143         case DFS_REFERRAL_DC:
 144                 /* MS-DFSC: this error is returned by non-DC root */
 145                 return (NT_STATUS_INVALID_PARAMETER);
 146 
 147         case DFS_REFERRAL_SYSVOL:
 148                 /* MS-DFSC: this error is returned by non-DC root */
 149                 return (NT_STATUS_NO_SUCH_DEVICE);
 150 
 151         default:
 152                 break;
 153         }
 154 
 155         status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);


 374                     DFS_REFERRAL_V2, DFS_REFV2_ENTSZ, server_type, flags,
 375                     proximity, referrals->i_timeout, path_offs, altpath_offs,
 376                     netpath_offs);
 377 
 378                 total_targetsz += targetsz;
 379         }
 380 
 381         smb_dfs_encode_targets(mbc, referrals);
 382 
 383         return (NT_STATUS_SUCCESS);
 384 }
 385 
 386 /*
 387  * Prepare a response with V3/V4 referral format.
 388  *
 389  * For more details, see comments for smb_dfs_encode_refv2() or see
 390  * MS-DFSC specification.
 391  */
 392 static uint32_t
 393 smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc,
 394         dfs_info_t *referrals,
 395     uint16_t ver)
 396 {
 397         _NOTE(ARGUNUSED(sr))
 398         uint16_t entsize, rep_bufsize, hdrsize;
 399         uint16_t server_type;
 400         uint16_t flags = 0;
 401         uint16_t path_offs, altpath_offs, netpath_offs;
 402         uint16_t targetsz, total_targetsz = 0;
 403         uint16_t dfs_pathsz;
 404         uint16_t r;
 405 
 406         hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ;
 407         rep_bufsize = MBC_MAXBYTES(mbc);
 408         dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
 409         entsize = hdrsize + dfs_pathsz + dfs_pathsz +
 410             smb_dfs_referrals_unclen(referrals, 0);
 411 
 412         if (entsize > rep_bufsize) {
 413                 /* need room for at least one referral */
 414                 return (NT_STATUS_BUFFER_OVERFLOW);
 415         }


 487  * Get referral information for the specified path from user space
 488  * using a door call.
 489  */
 490 static uint32_t
 491 smb_dfs_referrals_get(smb_request_t *sr, char *dfs_path, dfs_reftype_t reftype,
 492     dfs_referral_response_t *refrsp)
 493 {
 494         dfs_referral_query_t    req;
 495         int                     rc;
 496 
 497         req.rq_type = reftype;
 498         req.rq_path = dfs_path;
 499 
 500         bzero(refrsp, sizeof (dfs_referral_response_t));
 501         refrsp->rp_status = NT_STATUS_NOT_FOUND;
 502 
 503         rc = smb_kdoor_upcall(sr->sr_server, SMB_DR_DFS_GET_REFERRALS,
 504             &req, dfs_referral_query_xdr, refrsp, dfs_referral_response_xdr);
 505 
 506         if (rc != 0 || refrsp->rp_status != ERROR_SUCCESS) {
 507                 return (NT_STATUS_NO_SUCH_DEVICE);
 508         }
 509 
 510         (void) strsubst(refrsp->rp_referrals.i_uncpath, '/', '\\');
 511         return (NT_STATUS_SUCCESS);
 512 }
 513 
 514 static void
 515 smb_dfs_referrals_free(dfs_referral_response_t *refrsp)
 516 {
 517         xdr_free(dfs_referral_response_xdr, (char *)refrsp);
 518 }
 519 
 520 /*
 521  * Returns the Unicode string length for the target UNC of
 522  * the specified entry by 'refno'
 523  *
 524  * Note that the UNC path should be encoded with ONE leading
 525  * slash not two as is common to user-visible UNC paths.
 526  */
 527 static uint16_t


   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 #include <smbsrv/smb_kproto.h>
  29 #include <smbsrv/smb_dfs.h>
  30 #include <smbsrv/smb_door.h>
  31 #include <smb/winioctl.h>
  32 
  33 /*
  34  * Get Referral response header flags
  35  * For exact meaning refer to MS-DFSC spec.
  36  *
  37  * R: ReferralServers
  38  * S: StorageServers
  39  * T: TargetFailback
  40  */
  41 #define DFS_HDRFLG_R            0x00000001
  42 #define DFS_HDRFLG_S            0x00000002
  43 #define DFS_HDRFLG_T            0x00000004
  44 
  45 /*
  46  * Entry flags
  47  */
  48 #define DFS_ENTFLG_T            0x0004
  49 
  50 /*
  51  * Referral entry types/versions


  67 #define DFS_REFV1_ENTSZ         8
  68 #define DFS_REFV2_ENTSZ         22
  69 #define DFS_REFV3_ENTSZ         34
  70 #define DFS_REFV4_ENTSZ         34
  71 
  72 static dfs_reftype_t smb_dfs_get_reftype(const char *);
  73 static void smb_dfs_encode_hdr(mbuf_chain_t *, dfs_info_t *);
  74 static uint32_t smb_dfs_encode_refv1(smb_request_t *, mbuf_chain_t *,
  75     dfs_info_t *);
  76 static uint32_t smb_dfs_encode_refv2(smb_request_t *, mbuf_chain_t *,
  77     dfs_info_t *);
  78 static uint32_t smb_dfs_encode_refv3x(smb_request_t *, mbuf_chain_t *,
  79     dfs_info_t *, uint16_t);
  80 static void smb_dfs_encode_targets(mbuf_chain_t *, dfs_info_t *);
  81 static uint32_t smb_dfs_referrals_get(smb_request_t *, char *, dfs_reftype_t,
  82     dfs_referral_response_t *);
  83 static void smb_dfs_referrals_free(dfs_referral_response_t *);
  84 static uint16_t smb_dfs_referrals_unclen(dfs_info_t *, uint16_t);
  85 
  86 /*
  87  * Handle device type FILE_DEVICE_DFS
  88  * for smb2_ioctl
  89  */
  90 uint32_t
  91 smb_dfs_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
  92 {
  93         uint32_t status;
  94 
  95         if (!STYPE_ISIPC(sr->tid_tree->t_res_type))
  96                 return (NT_STATUS_INVALID_DEVICE_REQUEST);
  97 
  98         switch (fsctl->CtlCode) {
  99         case FSCTL_DFS_GET_REFERRALS:
 100                 status = smb_dfs_get_referrals(sr, fsctl);
 101                 break;
 102         case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
 103         default:
 104                 status = NT_STATUS_NOT_SUPPORTED;
 105         }
 106 
 107         return (status);
 108 }
 109 
 110 /*
 111  * Note: SMB1 callers in smb_trans2_dfs.c
 112  * smb_com_trans2_report_dfs_inconsistency
 113  * smb_com_trans2_get_dfs_referral
 114  */
 115 
 116 /*
 117  * See [MS-DFSC] for details about this command
 118  * Handles FSCTL_DFS_GET_REFERRALS (only)
 119  */
 120 uint32_t
 121 smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
 122 {
 123         dfs_info_t *referrals;
 124         dfs_referral_response_t refrsp;
 125         dfs_reftype_t reftype;
 126         char *path;
 127         uint16_t maxver;
 128         uint32_t status;
 129         int rc;
 130 
 131         /*
 132          * The caller checks this, because the error reporting method
 133          * varies across SMB versions.
 134          */
 135         ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
 136 
 137         /*
 138          * XXX Instead of decoding the referral request and encoding
 139          * the response here (in-kernel) we could pass the given
 140          * request buffer in our door call, and let that return the
 141          * response buffer ready to stuff into out_mbc.  That would
 142          * allow all this decoding/encoding to happen at user-level.
 143          * (and most of this file would go away. :-)
 144          */
 145 

 146         /*
 147          * Input data is (w) MaxReferralLevel, (U) path
 148          */
 149         rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
 150             sr, &maxver, &path);
 151         if (rc != 0)
 152                 return (NT_STATUS_INVALID_PARAMETER);

 153 





 154         reftype = smb_dfs_get_reftype((const char *)path);
 155         switch (reftype) {
 156         case DFS_REFERRAL_INVALID:
 157                 /* Need to check the error for this case */
 158                 return (NT_STATUS_INVALID_PARAMETER);
 159 
 160         case DFS_REFERRAL_DOMAIN:
 161         case DFS_REFERRAL_DC:
 162                 /* MS-DFSC: this error is returned by non-DC root */
 163                 return (NT_STATUS_INVALID_PARAMETER);
 164 
 165         case DFS_REFERRAL_SYSVOL:
 166                 /* MS-DFSC: this error is returned by non-DC root */
 167                 return (NT_STATUS_NO_SUCH_DEVICE);
 168 
 169         default:
 170                 break;
 171         }
 172 
 173         status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);


 392                     DFS_REFERRAL_V2, DFS_REFV2_ENTSZ, server_type, flags,
 393                     proximity, referrals->i_timeout, path_offs, altpath_offs,
 394                     netpath_offs);
 395 
 396                 total_targetsz += targetsz;
 397         }
 398 
 399         smb_dfs_encode_targets(mbc, referrals);
 400 
 401         return (NT_STATUS_SUCCESS);
 402 }
 403 
 404 /*
 405  * Prepare a response with V3/V4 referral format.
 406  *
 407  * For more details, see comments for smb_dfs_encode_refv2() or see
 408  * MS-DFSC specification.
 409  */
 410 static uint32_t
 411 smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc,
 412         dfs_info_t *referrals, uint16_t ver)

 413 {
 414         _NOTE(ARGUNUSED(sr))
 415         uint16_t entsize, rep_bufsize, hdrsize;
 416         uint16_t server_type;
 417         uint16_t flags = 0;
 418         uint16_t path_offs, altpath_offs, netpath_offs;
 419         uint16_t targetsz, total_targetsz = 0;
 420         uint16_t dfs_pathsz;
 421         uint16_t r;
 422 
 423         hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ;
 424         rep_bufsize = MBC_MAXBYTES(mbc);
 425         dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
 426         entsize = hdrsize + dfs_pathsz + dfs_pathsz +
 427             smb_dfs_referrals_unclen(referrals, 0);
 428 
 429         if (entsize > rep_bufsize) {
 430                 /* need room for at least one referral */
 431                 return (NT_STATUS_BUFFER_OVERFLOW);
 432         }


 504  * Get referral information for the specified path from user space
 505  * using a door call.
 506  */
 507 static uint32_t
 508 smb_dfs_referrals_get(smb_request_t *sr, char *dfs_path, dfs_reftype_t reftype,
 509     dfs_referral_response_t *refrsp)
 510 {
 511         dfs_referral_query_t    req;
 512         int                     rc;
 513 
 514         req.rq_type = reftype;
 515         req.rq_path = dfs_path;
 516 
 517         bzero(refrsp, sizeof (dfs_referral_response_t));
 518         refrsp->rp_status = NT_STATUS_NOT_FOUND;
 519 
 520         rc = smb_kdoor_upcall(sr->sr_server, SMB_DR_DFS_GET_REFERRALS,
 521             &req, dfs_referral_query_xdr, refrsp, dfs_referral_response_xdr);
 522 
 523         if (rc != 0 || refrsp->rp_status != ERROR_SUCCESS) {
 524                 return (NT_STATUS_FS_DRIVER_REQUIRED);
 525         }
 526 
 527         (void) strsubst(refrsp->rp_referrals.i_uncpath, '/', '\\');
 528         return (NT_STATUS_SUCCESS);
 529 }
 530 
 531 static void
 532 smb_dfs_referrals_free(dfs_referral_response_t *refrsp)
 533 {
 534         xdr_free(dfs_referral_response_xdr, (char *)refrsp);
 535 }
 536 
 537 /*
 538  * Returns the Unicode string length for the target UNC of
 539  * the specified entry by 'refno'
 540  *
 541  * Note that the UNC path should be encoded with ONE leading
 542  * slash not two as is common to user-visible UNC paths.
 543  */
 544 static uint16_t