1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 /*
  34  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  35  * Use is subject to license terms.
  36  *
  37  * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
  38  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  39  */
  40 
  41 #include <sys/param.h>
  42 #include <sys/systm.h>
  43 #include <sys/inttypes.h>
  44 #include <sys/time.h>
  45 #include <sys/vnode.h>
  46 #include <sys/sunddi.h>
  47 #include <sys/cmn_err.h>
  48 
  49 #include <netsmb/smb_osdep.h>
  50 
  51 #include <netsmb/smb.h>
  52 #include <netsmb/smb2.h>
  53 #include <netsmb/smb_conn.h>
  54 #include <netsmb/smb_subr.h>
  55 #include <netsmb/smb_rq.h>
  56 #include <netsmb/smb2_rq.h>
  57 
  58 #include <smbfs/smbfs.h>
  59 #include <smbfs/smbfs_node.h>
  60 #include <smbfs/smbfs_subr.h>
  61 
  62 
  63 /*
  64  * Todo: locking over-the-wire
  65  */
  66 #if 0   // todo
  67 
  68 int
  69 smbfs_smb2_locking(struct smbnode *np, int op, uint32_t pid,
  70         offset_t start, uint64_t len, int largelock,
  71         struct smb_cred *scrp, uint32_t timeout)
  72 {
  73         return (ENOTSUP);
  74 }
  75 
  76 #endif  // todo
  77 
  78 /*
  79  * Helper for smbfs_getattr_otw
  80  * used when we don't have an open FID
  81  *
  82  * For SMB2 we need to do an attribute-only open.  The
  83  * data returned by open gets us everything we need, so
  84  * just close the handle and we're done.
  85  */
  86 int
  87 smbfs_smb2_getpattr(
  88         struct smbnode *np,
  89         struct smbfattr *fap,
  90         struct smb_cred *scrp)
  91 {
  92         smb_fh_t tmp_fh;
  93         struct smb_share *ssp = np->n_mount->smi_share;
  94         uint32_t rights = (STD_RIGHT_READ_CONTROL_ACCESS |
  95             SA_RIGHT_FILE_READ_ATTRIBUTES);
  96         int error;
  97 
  98         bzero(&tmp_fh, sizeof (tmp_fh));
  99         error = smbfs_smb_ntcreatex(np,
 100             NULL, 0, 0, /* name nmlen xattr */
 101             rights, SMB_EFA_NORMAL,
 102             NTCREATEX_SHARE_ACCESS_ALL,
 103             NTCREATEX_DISP_OPEN,
 104             0, /* create options */
 105             scrp, &tmp_fh,
 106             NULL, fap);
 107         if (error == 0) {
 108                 (void) smb_smb_close(ssp, &tmp_fh, scrp);
 109         }
 110 
 111         return (error);
 112 }
 113 
 114 /*
 115  * Common SMB2 query file info
 116  */
 117 static int
 118 smbfs_smb2_query_info(struct smb_share *ssp, smb2fid_t *fid,
 119         struct mdchain *info_mdp, uint32_t *iolen,
 120         uint8_t type, uint8_t level, uint32_t addl_info,
 121         struct smb_cred *scrp)
 122 {
 123         struct smb_rq *rqp = NULL;
 124         struct mbchain *mbp;
 125         struct mdchain *mdp;
 126         uint32_t dlen = 0;
 127         uint16_t doff = 0;
 128         uint16_t ssize = 0;
 129         int error;
 130 
 131         error = smb_rq_alloc(SSTOCP(ssp), SMB2_QUERY_INFO, scrp, &rqp);
 132         if (error)
 133                 goto out;
 134 
 135         /*
 136          * Build the SMB 2 Query Info req.
 137          */
 138         smb_rq_getrequest(rqp, &mbp);
 139         mb_put_uint16le(mbp, 41);               // struct size
 140         mb_put_uint8(mbp, type);
 141         mb_put_uint8(mbp, level);
 142         mb_put_uint32le(mbp, *iolen);           // out buf len
 143         mb_put_uint16le(mbp, 0);                // in buf off
 144         mb_put_uint16le(mbp, 0);                // reserved
 145         mb_put_uint32le(mbp, 0);                // in buf len
 146         mb_put_uint32le(mbp, addl_info);
 147         mb_put_uint32le(mbp, 0);                // flags
 148         mb_put_uint64le(mbp, fid->fid_persistent);
 149         mb_put_uint64le(mbp, fid->fid_volatile);
 150 
 151         error = smb2_rq_simple(rqp);
 152         if (error) {
 153                 if (rqp->sr_error == NT_STATUS_INVALID_PARAMETER)
 154                         error = ENOTSUP;
 155                 goto out;
 156         }
 157 
 158         /*
 159          * Parse SMB 2 Query Info response
 160          */
 161         smb_rq_getreply(rqp, &mdp);
 162 
 163         /* Check structure size is 9 */
 164         md_get_uint16le(mdp, &ssize);
 165         if (ssize != 9) {
 166                 error = EBADRPC;
 167                 goto out;
 168         }
 169 
 170         /* Get data off, len */
 171         md_get_uint16le(mdp, &doff);
 172         md_get_uint32le(mdp, &dlen);
 173         *iolen = dlen;
 174 
 175         /*
 176          * Skip ahead to the payload, as needed.
 177          * Current offset is SMB2_HDRLEN + 8.
 178          */
 179         if (dlen != 0) {
 180                 mblk_t *m = NULL;
 181                 int skip = (int)doff - (SMB2_HDRLEN + 8);
 182                 if (skip < 0) {
 183                         error = EBADRPC;
 184                         goto out;
 185                 }
 186                 if (skip > 0) {
 187                         md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
 188                 }
 189                 error = md_get_mbuf(mdp, dlen, &m);
 190                 if (error)
 191                         goto out;
 192                 md_initm(info_mdp, m);
 193         }
 194 
 195 out:
 196         smb_rq_done(rqp);
 197 
 198         return (error);
 199 }
 200 
 201 
 202 /*
 203  * Get FileAllInformation for an open file
 204  * and parse into *fap
 205  */
 206 int
 207 smbfs_smb2_qfileinfo(struct smb_share *ssp, smb2fid_t *fid,
 208         struct smbfattr *fap, struct smb_cred *scrp)
 209 {
 210         struct mdchain info_mdc, *mdp = &info_mdc;
 211         uint32_t iolen = 1024;
 212         int error;
 213 
 214         bzero(mdp, sizeof (*mdp));
 215 
 216         error = smbfs_smb2_query_info(ssp, fid, mdp, &iolen,
 217             SMB2_0_INFO_FILE, FileAllInformation, 0, scrp);
 218         if (error)
 219                 goto out;
 220 
 221         error = smbfs_decode_file_all_info(ssp, mdp, fap);
 222 
 223 out:
 224         md_done(mdp);
 225 
 226         return (error);
 227 }
 228 
 229 /*
 230  * Get some SMB2_0_INFO_FILESYSTEM info
 231  *
 232  * Note: This can be called during mount.  We don't have any
 233  * smbfs_node_t or pathname, so do our own attr. open on
 234  * the root of the share to get a handle for this request.
 235  */
 236 static int
 237 smbfs_smb2_query_fs_info(struct smb_share *ssp, struct mdchain *mdp,
 238         uint8_t level, struct smb_cred *scrp)
 239 {
 240         smb2fid_t fid;
 241         uint32_t iolen = 1024;
 242         boolean_t opened = B_FALSE;
 243         int error;
 244 
 245         /*
 246          * Need a FID for smb2, and this is called during mount
 247          * so "go behind" the usual open/close functions.
 248          */
 249         error = smb2_smb_ntcreate(
 250             ssp, NULL,  // name
 251             NULL, NULL, // create ctx in, out
 252             0,  /* NTCREATEX_FLAGS... */
 253             SA_RIGHT_FILE_READ_ATTRIBUTES,
 254             SMB_EFA_NORMAL,
 255             NTCREATEX_SHARE_ACCESS_ALL,
 256             NTCREATEX_DISP_OPEN,
 257             0, /* create options */
 258             NTCREATEX_IMPERSONATION_IMPERSONATION,
 259             scrp, &fid, NULL, NULL);
 260         if (error != 0)
 261                 goto out;
 262         opened = B_TRUE;
 263 
 264         error = smbfs_smb2_query_info(ssp, &fid, mdp, &iolen,
 265             SMB2_0_INFO_FILESYSTEM, level, 0, scrp);
 266 
 267 out:
 268         if (opened)
 269                 (void) smb2_smb_close(ssp, &fid, scrp);
 270 
 271         return (error);
 272 }
 273 
 274 /*
 275  * Get FileFsAttributeInformation and
 276  * parse into *info
 277  */
 278 int
 279 smbfs_smb2_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *info,
 280         struct smb_cred *scrp)
 281 {
 282         struct mdchain info_mdc, *mdp = &info_mdc;
 283         int error;
 284 
 285         bzero(mdp, sizeof (*mdp));
 286 
 287         error = smbfs_smb2_query_fs_info(ssp, mdp,
 288             FileFsAttributeInformation, scrp);
 289         if (error)
 290                 goto out;
 291         error = smbfs_decode_fs_attr_info(ssp, mdp, info);
 292 
 293 out:
 294         md_done(mdp);
 295 
 296         return (error);
 297 }
 298 
 299 /*
 300  * Get FileFsFullSizeInformation and
 301  * parse into *info
 302  */
 303 int
 304 smbfs_smb2_statfs(struct smb_share *ssp,
 305         struct smb_fs_size_info *info,
 306         struct smb_cred *scrp)
 307 {
 308         struct mdchain info_mdc, *mdp = &info_mdc;
 309         int error;
 310 
 311         bzero(mdp, sizeof (*mdp));
 312 
 313         error = smbfs_smb2_query_fs_info(ssp, mdp,
 314             FileFsFullSizeInformation, scrp);
 315         if (error)
 316                 goto out;
 317 
 318         md_get_uint64le(mdp, &info->total_units);
 319         md_get_uint64le(mdp, &info->caller_avail);
 320         md_get_uint64le(mdp, &info->actual_avail);
 321 
 322         md_get_uint32le(mdp, &info->sect_per_unit);
 323         error = md_get_uint32le(mdp, &info->bytes_per_sect);
 324 
 325 out:
 326         md_done(mdp);
 327 
 328         return (error);
 329 }
 330 
 331 int
 332 smbfs_smb2_flush(struct smb_share *ssp, smb2fid_t *fid,
 333         struct smb_cred *scrp)
 334 {
 335         struct smb_rq *rqp;
 336         struct mbchain *mbp;
 337         int error;
 338 
 339         error = smb_rq_alloc(SSTOCP(ssp), SMB2_FLUSH, scrp, &rqp);
 340         if (error)
 341                 return (error);
 342 
 343         /*
 344          * Build the SMB 2 Flush Request
 345          */
 346         smb_rq_getrequest(rqp, &mbp);
 347         mb_put_uint16le(mbp, 24);       /* struct size */
 348         mb_put_uint16le(mbp, 0);        /* reserved */
 349         mb_put_uint32le(mbp, 0);        /* reserved */
 350 
 351         mb_put_uint64le(mbp, fid->fid_persistent);
 352         mb_put_uint64le(mbp, fid->fid_volatile);
 353 
 354         rqp->sr_flags |= SMBR_NORECONNECT;
 355         error = smb2_rq_simple(rqp);
 356         smb_rq_done(rqp);
 357 
 358         return (error);
 359 }
 360 
 361 /*
 362  * Set file info via an open handle.
 363  * Caller provides payload, info level.
 364  */
 365 static int
 366 smbfs_smb2_set_info(struct smb_share *ssp, smb2fid_t *fid,
 367         struct mbchain *info_mbp, uint8_t type, uint8_t level,
 368         uint32_t addl_info, struct smb_cred *scrp)
 369 {
 370         struct smb_rq *rqp = NULL;
 371         struct mbchain *mbp;
 372         uint32_t *buffer_lenp;
 373         int base, len;
 374         int error;
 375 
 376         error = smb_rq_alloc(SSTOCP(ssp), SMB2_SET_INFO, scrp, &rqp);
 377         if (error)
 378                 goto out;
 379 
 380         /*
 381          * Build the SMB 2 Set Info req.
 382          */
 383         smb_rq_getrequest(rqp, &mbp);
 384         mb_put_uint16le(mbp, 33);               // struct size
 385         mb_put_uint8(mbp, type);
 386         mb_put_uint8(mbp, level);
 387         buffer_lenp = mb_reserve(mbp, sizeof (uint32_t));
 388         mb_put_uint16le(mbp, SMB2_HDRLEN + 32); // Buffer Offset
 389         mb_put_uint16le(mbp, 0);                // Reserved
 390         mb_put_uint32le(mbp, addl_info);        // Additional Info
 391 
 392         mb_put_uint64le(mbp, fid->fid_persistent);
 393         mb_put_uint64le(mbp, fid->fid_volatile);
 394 
 395         /*
 396          * Now the payload
 397          */
 398         base = mbp->mb_count;
 399         error = mb_put_mbchain(mbp, info_mbp);
 400         if (error)
 401                 goto out;
 402         len = mbp->mb_count - base;
 403         *buffer_lenp = htolel(len);
 404         if (error)
 405                 goto out;
 406 
 407         /*
 408          * Run the request.
 409          * Don't care about the (empty) reply.
 410          */
 411         error = smb2_rq_simple(rqp);
 412 
 413 out:
 414         smb_rq_done(rqp);
 415 
 416         return (error);
 417 }
 418 
 419 int
 420 smbfs_smb2_seteof(struct smb_share *ssp, smb2fid_t *fid,
 421         uint64_t newsize, struct smb_cred *scrp)
 422 {
 423         struct mbchain data_mb, *mbp = &data_mb;
 424         uint8_t level = FileEndOfFileInformation;
 425         int error;
 426 
 427         mb_init(mbp);
 428         mb_put_uint64le(mbp, newsize);
 429         error = smbfs_smb2_set_info(ssp, fid, mbp,
 430             SMB2_0_INFO_FILE, level, 0, scrp);
 431         mb_done(mbp);
 432 
 433         return (error);
 434 }
 435 
 436 int
 437 smbfs_smb2_setdisp(struct smb_share *ssp, smb2fid_t *fid,
 438         uint8_t newdisp, struct smb_cred *scrp)
 439 {
 440         struct mbchain data_mb, *mbp = &data_mb;
 441         uint8_t level = FileDispositionInformation;
 442         int error;
 443 
 444         mb_init(mbp);
 445         mb_put_uint8(mbp, newdisp);
 446         error = smbfs_smb2_set_info(ssp, fid, mbp,
 447             SMB2_0_INFO_FILE,  level, 0, scrp);
 448         mb_done(mbp);
 449 
 450         return (error);
 451 }
 452 
 453 /*
 454  * Set FileBasicInformation on an open handle
 455  * Caller builds the mbchain.
 456  */
 457 int
 458 smbfs_smb2_setfattr(struct smb_share *ssp, smb2fid_t *fid,
 459         struct mbchain *mbp, struct smb_cred *scrp)
 460 {
 461         uint8_t level = FileBasicInformation;
 462         int error;
 463 
 464         error = smbfs_smb2_set_info(ssp, fid, mbp,
 465             SMB2_0_INFO_FILE,  level, 0, scrp);
 466         return (error);
 467 }
 468 
 469 /*
 470  * Build a FileRenameInformation and call setinfo
 471  */
 472 int
 473 smbfs_smb2_rename(struct smbnode *np, struct smbnode *tdnp,
 474         const char *tname, int tnlen, int overwrite,
 475         smb2fid_t *fid, struct smb_cred *scrp)
 476 {
 477         struct smb_share *ssp = np->n_mount->smi_share;
 478         struct mbchain data_mb, *mbp = &data_mb;
 479         uint32_t *name_lenp;
 480         uint8_t level = FileRenameInformation;
 481         int base, len;
 482         int error;
 483 
 484         mb_init(mbp);
 485 
 486         mb_put_uint32le(mbp, (overwrite & 1));
 487         mb_put_uint32le(mbp, 0);                // reserved
 488         mb_put_uint64le(mbp, 0);                // Root Dir
 489         name_lenp = mb_reserve(mbp, 4);
 490 
 491         /* Target name (full path) */
 492         base = mbp->mb_count;
 493         if (tnlen > 0) {
 494                 error = smbfs_fullpath(mbp, SSTOVC(ssp),
 495                     tdnp, tname, tnlen, '\\');
 496                 if (error)
 497                         goto out;
 498         }
 499         len = mbp->mb_count - base;
 500         *name_lenp = htolel(len);
 501 
 502         error = smbfs_smb2_set_info(ssp, fid, mbp,
 503             SMB2_0_INFO_FILE,  level, 0, scrp);
 504 
 505 out:
 506         mb_done(mbp);
 507 
 508         return (error);
 509 }
 510 
 511 /*
 512  * Later servers have maxtransact at a megabyte or more,
 513  * but we don't want to buffer up that much data, so use
 514  * the lesser of that or 64k.
 515  */
 516 #define SMBFS_QDIR_MAX_BUF      (1<<16)
 517 
 518 /*
 519  * SMB2 query directory
 520  */
 521 static int
 522 smbfs_smb2_qdir(struct smbfs_fctx *ctx)
 523 {
 524         smb_fh_t *fhp = ctx->f_fhp;
 525         smb_share_t *ssp = ctx->f_ssp;
 526         smb_vc_t *vcp = SSTOVC(ssp);
 527         struct smb_rq *rqp;
 528         struct mbchain *mbp;
 529         struct mdchain *mdp;
 530         uint16_t *name_lenp;
 531         uint8_t level, flags;
 532         uint16_t ssize = 0;
 533         uint16_t obuf_off = 0;
 534         uint32_t obuf_len = 0;
 535         uint32_t obuf_req;
 536         int error;
 537 
 538         level = (uint8_t)ctx->f_infolevel;
 539         flags = 0;
 540         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE)
 541                 flags |= SMB2_QDIR_FLAG_SINGLE;
 542         if (ctx->f_flags & SMBFS_RDD_FINDFIRST)
 543                 ctx->f_rkey = 0;
 544         else
 545                 flags |= SMB2_QDIR_FLAG_INDEX;
 546 
 547         obuf_req = SMBFS_QDIR_MAX_BUF;
 548         if (obuf_req > vcp->vc_sopt.sv2_maxtransact)
 549                 obuf_req = vcp->vc_sopt.sv2_maxtransact;
 550 
 551         if (ctx->f_rq) {
 552                 smb_rq_done(ctx->f_rq);
 553                 ctx->f_rq = NULL;
 554         }
 555         error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB2_QUERY_DIRECTORY,
 556             ctx->f_scred, &rqp);
 557         if (error)
 558                 return (error);
 559         ctx->f_rq = rqp;
 560 
 561         /*
 562          * Build an SMB2 Query Dir req.
 563          */
 564         smb_rq_getrequest(rqp, &mbp);
 565 
 566         mb_put_uint16le(mbp, 33);                       /* Struct size */
 567         mb_put_uint8(mbp, level);
 568         mb_put_uint8(mbp, flags);
 569         mb_put_uint32le(mbp, ctx->f_rkey);           /* FileIndex */
 570 
 571         mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
 572         mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
 573 
 574         mb_put_uint16le(mbp, 96);
 575         name_lenp = mb_reserve(mbp, sizeof (uint16_t)); /* FileNameLen */
 576         mb_put_uint32le(mbp, obuf_req);                 /* Output Buf Len */
 577 
 578         /* Add in the name if any */
 579         if (ctx->f_wclen > 0) {
 580                 int base, len;
 581 
 582                 /* Put the match pattern. */
 583                 base = mbp->mb_count;
 584                 error = smb_put_dmem(mbp, vcp,
 585                     ctx->f_wildcard, ctx->f_wclen,
 586                     SMB_CS_NONE, NULL);
 587                 if (error)
 588                         return (error);
 589 
 590                 /* Update the FileNameLen */
 591                 len = mbp->mb_count - base;
 592                 *name_lenp = htoles(len);
 593         } else {
 594                 /* Empty string */
 595                 mb_put_uint16le(mbp, 0);
 596                 *name_lenp = 0;
 597         }
 598 
 599         error = smb2_rq_simple(rqp);
 600         if (error != 0)
 601                 goto out;
 602 
 603         /*
 604          * Parse the SMB2 Query Dir response
 605          */
 606         smb_rq_getreply(rqp, &mdp);
 607 
 608         /* Check structure size is 9 */
 609         md_get_uint16le(mdp, &ssize);
 610         if (ssize != 9) {
 611                 error = EBADRPC;
 612                 goto out;
 613         }
 614 
 615         /* Get output buffer offset, length */
 616         md_get_uint16le(mdp, &obuf_off);
 617         md_get_uint32le(mdp, &obuf_len);
 618 
 619         /*
 620          * After read at EOF we'll have just one word:
 621          * NextEntryOffset == 0  Allow some padding.
 622          */
 623         if (obuf_len < 8) {
 624                 error = ENOENT;
 625                 goto out;
 626         }
 627 
 628         /*
 629          * If this reply is shorter than requested by 1k
 630          * or more, we must have reached EOF.
 631          */
 632         if ((obuf_len + 1024) < obuf_req)
 633                 ctx->f_flags |= SMBFS_RDD_EOF;
 634 
 635         /*
 636          * Have data. Put the payload in ctx->f_mdchain
 637          * Current offset is SMB2_HDRLEN + 8.
 638          */
 639         {
 640                 mblk_t *m = NULL;
 641                 int skip = (int)obuf_off - (SMB2_HDRLEN + 8);
 642                 if (skip < 0) {
 643                         error = EBADRPC;
 644                         goto out;
 645                 }
 646                 if (skip > 0) {
 647                         md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
 648                 }
 649                 error = md_get_mbuf(mdp, obuf_len, &m);
 650                 if (error)
 651                         goto out;
 652                 md_done(&ctx->f_mdchain);
 653                 md_initm(&ctx->f_mdchain, m);
 654         }
 655 
 656         /*
 657          * SMB2 Query Directory does not provie an EntryCount.
 658          * Instead, we'll advance f_eofs (entry offset)
 659          * through the range [0..f_left]
 660          */
 661         ctx->f_left = obuf_len;
 662         ctx->f_eofs = 0;
 663         return (0);
 664 
 665 out:
 666         if (error != 0) {
 667                 /*
 668                  * Failed parsing the FindFirst or FindNext response.
 669                  * Force this directory listing closed, otherwise the
 670                  * calling process may hang in an infinite loop.
 671                  */
 672                 ctx->f_left = 0;
 673                 ctx->f_eofs = 0;
 674                 ctx->f_flags |= SMBFS_RDD_EOF;
 675         }
 676 
 677         return (error);
 678 }
 679 
 680 int
 681 smbfs_smb2_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
 682     const char *wildcard, int wclen, uint32_t attr)
 683 {
 684         smb_fh_t *fhp = NULL;
 685         uint32_t rights =
 686             STD_RIGHT_READ_CONTROL_ACCESS |
 687             SA_RIGHT_FILE_READ_ATTRIBUTES |
 688             SA_RIGHT_FILE_READ_DATA;
 689         int error;
 690 
 691         /*
 692          * Set f_type no matter what, so cleanup will call
 693          * smbfs_smb2_findclose, error or not.
 694          */
 695         ctx->f_type = ft_SMB2;
 696         ASSERT(ctx->f_dnp == dnp);
 697 
 698         /*
 699          * Get a file handle on the directory
 700          */
 701         error = smb_fh_create(ctx->f_ssp, &fhp);
 702         if (error != 0)
 703                 goto errout;
 704 
 705         error = smbfs_smb_ntcreatex(dnp,
 706             NULL, 0, 0, /* name nmlen xattr */
 707             rights, SMB_EFA_NORMAL,
 708             NTCREATEX_SHARE_ACCESS_ALL,
 709             NTCREATEX_DISP_OPEN,
 710             0, /* create options */
 711             ctx->f_scred, fhp,
 712             NULL, NULL); /* cr_act_p fa_p */
 713         if (error != 0)
 714                 goto errout;
 715 
 716         fhp->fh_rights = rights;
 717         smb_fh_opened(fhp);
 718         ctx->f_fhp = fhp;
 719 
 720         ctx->f_namesz = SMB_MAXFNAMELEN + 1;
 721         ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 722         ctx->f_infolevel = FileFullDirectoryInformation;
 723         ctx->f_attrmask = attr;
 724         ctx->f_wildcard = wildcard;
 725         ctx->f_wclen = wclen;
 726 
 727         return (0);
 728 
 729 errout:
 730         if (fhp != NULL)
 731                 smb_fh_rele(fhp);
 732         return (error);
 733 }
 734 
 735 int
 736 smbfs_smb2_findclose(struct smbfs_fctx *ctx)
 737 {
 738         smb_fh_t *fhp = NULL;
 739 
 740         if ((fhp = ctx->f_fhp) != NULL) {
 741                 ctx->f_fhp = NULL;
 742                 smb_fh_rele(fhp);
 743         }
 744         if (ctx->f_name)
 745                 kmem_free(ctx->f_name, ctx->f_namesz);
 746         if (ctx->f_rq)
 747                 smb_rq_done(ctx->f_rq);
 748         md_done(&ctx->f_mdchain);
 749 
 750         return (0);
 751 }
 752 
 753 /*
 754  * Get a buffer of directory entries (if we don't already have
 755  * some remaining in the current buffer) then decode one.
 756  */
 757 int
 758 smbfs_smb2_findnext(struct smbfs_fctx *ctx, uint16_t limit)
 759 {
 760         int error;
 761 
 762         /*
 763          * If we've scanned to the end of the current buffer
 764          * try to read anohther buffer of dir entries.
 765          * Treat anything less than 8 bytes as an "empty"
 766          * buffer to ensure we can read something.
 767          * (There may be up to 8 bytes of padding.)
 768          */
 769         if ((ctx->f_eofs + 8) > ctx->f_left) {
 770                 /* Scanned the whole buffer. */
 771                 if (ctx->f_flags & SMBFS_RDD_EOF)
 772                         return (ENOENT);
 773                 ctx->f_limit = limit;
 774                 error = smbfs_smb2_qdir(ctx);
 775                 if (error)
 776                         return (error);
 777                 ctx->f_otws++;
 778         }
 779 
 780         /*
 781          * Decode one entry
 782          */
 783         error = smbfs_decode_dirent(ctx);
 784 
 785         return (error);
 786 }
 787 
 788 
 789 /*
 790  * Helper for smbfs_xa_get_streaminfo
 791  * Query stream info
 792  */
 793 int
 794 smbfs_smb2_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
 795         struct smb_cred *scrp)
 796 {
 797         smb_share_t *ssp = np->n_mount->smi_share;
 798         smb_fh_t *fhp = NULL;
 799         uint32_t rights =
 800             STD_RIGHT_READ_CONTROL_ACCESS |
 801             SA_RIGHT_FILE_READ_ATTRIBUTES;
 802         uint32_t iolen = INT16_MAX;
 803         int error;
 804 
 805         /*
 806          * Get a file handle on the object
 807          * with read attr. rights.
 808          */
 809         error = smb_fh_create(ssp, &fhp);
 810         if (error != 0)
 811                 goto out;
 812         error = smbfs_smb_ntcreatex(np,
 813             NULL, 0, 0, /* name nmlen xattr */
 814             rights, SMB_EFA_NORMAL,
 815             NTCREATEX_SHARE_ACCESS_ALL,
 816             NTCREATEX_DISP_OPEN,
 817             0, /* create options */
 818             scrp, fhp, NULL, NULL);
 819         if (error != 0)
 820                 goto out;
 821 
 822         smb_fh_opened(fhp);
 823 
 824         /*
 825          * Query stream info
 826          */
 827         error = smbfs_smb2_query_info(ssp, &fhp->fh_fid2, mdp, &iolen,
 828             SMB2_0_INFO_FILE, FileStreamInformation, 0, scrp);
 829 
 830 out:
 831         if (fhp != NULL)
 832                 smb_fh_rele(fhp);
 833         return (error);
 834 }
 835 
 836 
 837 /*
 838  * OTW function to Get a security descriptor (SD).
 839  *
 840  * The *reslen param is bufsize(in) / length(out)
 841  * Note: On success, this fills in mdp->md_top,
 842  * which the caller should free.
 843  */
 844 int
 845 smbfs_smb2_getsec(struct smb_share *ssp, smb2fid_t *fid,
 846         uint32_t selector, mblk_t **res, uint32_t *reslen,
 847         struct smb_cred *scrp)
 848 {
 849         struct mdchain info_mdc, *mdp = &info_mdc;
 850         int error;
 851 
 852         bzero(mdp, sizeof (*mdp));
 853 
 854         error = smbfs_smb2_query_info(ssp, fid, mdp, reslen,
 855             SMB2_0_INFO_SECURITY, 0, selector, scrp);
 856         if (error)
 857                 goto out;
 858 
 859         if (mdp->md_top == NULL) {
 860                 error = EBADRPC;
 861                 goto out;
 862         }
 863         *res = mdp->md_top;
 864         mdp->md_top = NULL;
 865 
 866 out:
 867         md_done(mdp);
 868         return (error);
 869 }
 870 
 871 
 872 /*
 873  * OTW function to Set a security descriptor (SD).
 874  * Caller data are carried in an mbchain_t.
 875  *
 876  * Note: This normally consumes mbp->mb_top, and clears
 877  * that pointer when it does.
 878  */
 879 int
 880 smbfs_smb2_setsec(struct smb_share *ssp, smb2fid_t *fid,
 881         uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
 882 {
 883         struct mbchain info_mbp, *mbp = &info_mbp;
 884         int error;
 885 
 886         ASSERT(*mp != NULL);
 887         mb_initm(mbp, *mp);
 888         *mp = NULL; /* consumed */
 889 
 890         error = smbfs_smb2_set_info(ssp, fid, mbp,
 891             SMB2_0_INFO_SECURITY, 0, selector, scrp);
 892 
 893         mb_done(mbp);
 894 
 895         return (error);
 896 }