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-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)


   4  * The contents of this file are subject to the terms of the
   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 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 /*
  27  * Functions supporting Solaris Extended Attributes,
  28  * used to provide access to CIFS "named streams".
  29  */
  30 
  31 #include <sys/systm.h>

  32 #include <sys/cred.h>
  33 #include <sys/vnode.h>
  34 #include <sys/vfs.h>
  35 #include <sys/filio.h>
  36 #include <sys/uio.h>
  37 #include <sys/dirent.h>
  38 #include <sys/errno.h>
  39 #include <sys/sysmacros.h>
  40 #include <sys/kmem.h>
  41 #include <sys/stat.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/u8_textprep.h>
  44 
  45 #include <netsmb/smb_osdep.h>

  46 #include <netsmb/smb.h>

  47 #include <netsmb/smb_conn.h>
  48 #include <netsmb/smb_subr.h>
  49 #include <netsmb/smb_rq.h>
  50 
  51 #include <smbfs/smbfs.h>
  52 #include <smbfs/smbfs_node.h>
  53 #include <smbfs/smbfs_subr.h>
  54 
  55 #include <fs/fs_subr.h>
  56 
  57 /*
  58  * Solaris wants there to be a directory node to contain
  59  * all the extended attributes.  The SMB protocol does not
  60  * really support a directory here, and uses very different
  61  * operations to list attributes, etc. so we "fake up" an
  62  * smbnode here to represent the attributes directory.
  63  *
  64  * We need to give this (fake) directory a unique identity,
  65  * and since we're using the full remote pathname as the
  66  * unique identity of all nodes, the easiest thing to do


 272         /* Note: pvp has a VN_HOLD */
 273         pnp = VTOSMB(pvp);
 274 
 275         /* Get stream name (ptr and length) */
 276         ASSERT(xnp->n_rplen > pnp->n_rplen);
 277         nlen = xnp->n_rplen - pnp->n_rplen;
 278         name = xnp->n_rpath + pnp->n_rplen;
 279         sname = name;
 280 
 281         /* Note: this can allocate a new "name" */
 282         error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp);
 283         if (error == 0 && name != sname)
 284                 smbfs_name_free(name, nlen);
 285 
 286         VN_RELE(pvp);
 287 
 288         return (error);
 289 }
 290 
 291 /*
 292  * Fetch the entire attribute list here in findopen.
 293  * Will parse the results in findnext.
 294  *
 295  * This is called on the XATTR directory, so we
 296  * have to get the (real) parent object first.
 297  */
 298 /* ARGSUSED */
 299 int
 300 smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
 301         const char *wildcard, int wclen)
 302 {
 303         vnode_t *pvp;   /* parent */
 304         smbnode_t *pnp;
 305         struct smb_t2rq *t2p;
 306         struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 307         struct mbchain *mbp;
 308         int error;
 309 
 310         ASSERT(dnp->n_flag & N_XATTR);
 311 
 312         ctx->f_type = ft_XA;
 313         ctx->f_namesz = SMB_MAXFNAMELEN + 1;
 314         if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
 315                 ctx->f_namesz *= 2;
 316         ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 317 
 318         error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
 319         if (error)
 320                 return (error);
 321         ASSERT(pvp);
 322         /* Note: pvp has a VN_HOLD */
 323         pnp = VTOSMB(pvp);
 324 
 325         if (ctx->f_t2) {
 326                 smb_t2_done(ctx->f_t2);
 327                 ctx->f_t2 = NULL;
 328         }

 329 
 330         error = smb_t2_alloc(SSTOCP(ctx->f_ssp),
 331             SMB_TRANS2_QUERY_PATH_INFORMATION,
 332             ctx->f_scred, &t2p);


 333         if (error)
 334                 goto out;
 335         ctx->f_t2 = t2p;
 336 
 337         mbp = &t2p->t2_tparam;
 338         (void) mb_init(mbp);
 339         (void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
 340         (void) mb_put_uint32le(mbp, 0);
 341         error = smbfs_fullpath(mbp, vcp, pnp, NULL, NULL, 0);
 342         if (error)
 343                 goto out;
 344         t2p->t2_maxpcount = 2;
 345         t2p->t2_maxdcount = INT16_MAX;
 346         error = smb_t2_request(t2p);
 347         if (error) {
 348                 if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
 349                         error = ENOTSUP;
 350         }
 351         /*
 352          * No returned parameters to parse.
 353          * Returned data are in t2_rdata,
 354          * which we'll parse in _findnext.
 355          * However, save the wildcard.
 356          */
 357         ctx->f_wildcard = wildcard;
 358         ctx->f_wclen = wclen;
 359 





 360 out:
 361         VN_RELE(pvp);
 362         return (error);
 363 }
 364 
 365 /*
 366  * Get the next name in an XATTR directory into f_name

 367  */
 368 /* ARGSUSED */
 369 int
 370 smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)

 371 {
 372         struct mdchain *mdp;
 373         struct smb_t2rq *t2p;
 374         uint32_t size, next;
 375         uint64_t llongint;
 376         int error, skip, used, nmlen;
 377 
 378         t2p = ctx->f_t2;
 379         mdp = &t2p->t2_rdata;
 380 
 381         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 382                 ASSERT(ctx->f_wildcard);
 383                 SMBVDEBUG("wildcard: %s\n", ctx->f_wildcard);
 384         }


 385 
 386 again:
 387         if (ctx->f_flags & SMBFS_RDD_EOF)
 388                 return (ENOENT);
 389 
 390         /* Parse FILE_STREAM_INFORMATION */
 391         if ((error = md_get_uint32le(mdp, &next)) != 0)     /* offset to */
 392                 return (ENOENT);
 393         if ((error = md_get_uint32le(mdp, &size)) != 0) /* name len */
 394                 return (ENOENT);
 395         (void) md_get_uint64le(mdp, &llongint); /* file size */
 396         ctx->f_attr.fa_size = llongint;
 397         (void) md_get_uint64le(mdp, NULL);      /* alloc. size */
 398         used = 4 + 4 + 8 + 8;   /* how much we consumed */
 399 
 400         /*
 401          * Copy the string, but skip the first char (":")
 402          * Watch out for zero-length strings here.
 403          */
 404         if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
 405                 if (size >= 2) {
 406                         size -= 2; used += 2;
 407                         (void) md_get_uint16le(mdp, NULL);
 408                 }
 409                 nmlen = min(size, SMB_MAXFNAMELEN * 2);
 410         } else {
 411                 if (size >= 1) {
 412                         size -= 1; used += 1;
 413                         (void) md_get_uint8(mdp, NULL);
 414                 }
 415                 nmlen = min(size, SMB_MAXFNAMELEN);
 416         }
 417 
 418         ASSERT(nmlen < ctx->f_namesz);
 419         ctx->f_nmlen = nmlen;
 420         error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);











 421         if (error)
 422                 return (error);
 423         used += nmlen;

 424 
 425         /*
 426          * Convert UCS-2 to UTF-8
 427          */
 428         smbfs_fname_tolocal(ctx);
 429         if (nmlen)

 430                 SMBVDEBUG("name: %s\n", ctx->f_name);
 431         else
 432                 SMBVDEBUG("null name!\n");
 433 
 434         /*
 435          * Skip padding until next offset
 436          */
 437         if (next > used) {
 438                 skip = next - used;
 439                 (void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
 440         }
 441         if (next == 0)
 442                 ctx->f_flags |= SMBFS_RDD_EOF;
 443 
 444         /*
 445          * Chop off the trailing ":$DATA"
 446          * The 6 here is strlen(":$DATA")
 447          */
 448         if (ctx->f_nmlen >= 6) {
 449                 char *p = ctx->f_name + ctx->f_nmlen - 6;
 450                 if (strncmp(p, ":$DATA", 6) == 0) {
 451                         *p = '\0'; /* Chop! */
 452                         ctx->f_nmlen -= 6;
 453                 }
 454         }
 455 
 456         /*
 457          * The Chop above will typically leave
 458          * an empty name in the first slot,
 459          * which we will skip here.
 460          */
 461         if (ctx->f_nmlen == 0)
 462                 goto again;
 463 
 464         /*
 465          * If this is a lookup of a specific name,
 466          * skip past any non-matching names.


 467          */
 468         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 469                 if (ctx->f_wclen != ctx->f_nmlen)
 470                         goto again;
 471                 if (u8_strcmp(ctx->f_wildcard, ctx->f_name,
 472                     ctx->f_nmlen, U8_STRCMP_CI_LOWER,
 473                     U8_UNICODE_LATEST, &error) || error)
 474                         goto again;
 475         }
 476 
 477         return (0);
 478 }
 479 
 480 /*
 481  * Find first/next/close for XATTR directories.
 482  * NB: also used by smbfs_smb_lookup
 483  */
 484 
 485 int
 486 smbfs_xa_findclose(struct smbfs_fctx *ctx)
 487 {
 488 
 489         if (ctx->f_name)
 490                 kmem_free(ctx->f_name, ctx->f_namesz);
 491         if (ctx->f_t2)
 492                 smb_t2_done(ctx->f_t2);
 493 
 494         return (0);
 495 }


   4  * The contents of this file are subject to the terms of the
   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 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Functions supporting Solaris Extended Attributes,
  29  * used to provide access to CIFS "named streams".
  30  */
  31 
  32 #include <sys/systm.h>
  33 #include <sys/inttypes.h>
  34 #include <sys/cred.h>
  35 #include <sys/vnode.h>
  36 #include <sys/vfs.h>
  37 #include <sys/filio.h>
  38 #include <sys/uio.h>
  39 #include <sys/dirent.h>
  40 #include <sys/errno.h>
  41 #include <sys/sysmacros.h>
  42 #include <sys/kmem.h>
  43 #include <sys/stat.h>
  44 #include <sys/cmn_err.h>
  45 #include <sys/u8_textprep.h>
  46 
  47 #include <netsmb/smb_osdep.h>
  48 
  49 #include <netsmb/smb.h>
  50 #include <netsmb/smb2.h>
  51 #include <netsmb/smb_conn.h>
  52 #include <netsmb/smb_subr.h>
  53 #include <netsmb/smb_rq.h>
  54 
  55 #include <smbfs/smbfs.h>
  56 #include <smbfs/smbfs_node.h>
  57 #include <smbfs/smbfs_subr.h>
  58 
  59 #include <fs/fs_subr.h>
  60 
  61 /*
  62  * Solaris wants there to be a directory node to contain
  63  * all the extended attributes.  The SMB protocol does not
  64  * really support a directory here, and uses very different
  65  * operations to list attributes, etc. so we "fake up" an
  66  * smbnode here to represent the attributes directory.
  67  *
  68  * We need to give this (fake) directory a unique identity,
  69  * and since we're using the full remote pathname as the
  70  * unique identity of all nodes, the easiest thing to do


 276         /* Note: pvp has a VN_HOLD */
 277         pnp = VTOSMB(pvp);
 278 
 279         /* Get stream name (ptr and length) */
 280         ASSERT(xnp->n_rplen > pnp->n_rplen);
 281         nlen = xnp->n_rplen - pnp->n_rplen;
 282         name = xnp->n_rpath + pnp->n_rplen;
 283         sname = name;
 284 
 285         /* Note: this can allocate a new "name" */
 286         error = smbfs_smb_lookup(pnp, &name, &nlen, fap, scrp);
 287         if (error == 0 && name != sname)
 288                 smbfs_name_free(name, nlen);
 289 
 290         VN_RELE(pvp);
 291 
 292         return (error);
 293 }
 294 
 295 /*
 296  * Actually go OtW to get the list of "streams".

 297  *
 298  * This is called on the XATTR directory, so we
 299  * have to get the (real) parent object first.
 300  */
 301 static int
 302 smbfs_xa_get_streaminfo(struct smbfs_fctx *ctx)


 303 {
 304         vnode_t *pvp;   /* parent */
 305         smbnode_t *pnp;
 306         smbnode_t *dnp = ctx->f_dnp;
 307         struct mdchain *mdp;

 308         int error;
 309 








 310         error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
 311         if (error)
 312                 return (error);
 313         ASSERT(pvp);
 314         /* Note: pvp has a VN_HOLD */
 315         pnp = VTOSMB(pvp);
 316 
 317         /*
 318          * Get stream info into f_mdchain
 319          */
 320         mdp = &ctx->f_mdchain;
 321         md_done(mdp);
 322 
 323         if (SSTOVC(ctx->f_ssp)->vc_flags & SMBV_SMB2) {
 324                 error = smbfs_smb2_get_streaminfo(pnp, mdp, ctx->f_scred);
 325         } else {
 326                 error = smbfs_smb1_get_streaminfo(pnp, mdp, ctx->f_scred);
 327         }
 328         if (error)
 329                 goto out;

 330 














 331         /*
 332          * Have stream info in ctx->f_mdchain
 333          * Initialize buffer length, position.


 334          */
 335         ctx->f_left = m_fixhdr(mdp->md_top);
 336         ctx->f_eofs = 0;
 337 
 338         /*
 339          * After one successful call, we're at EOF.
 340          */
 341         ctx->f_flags |= SMBFS_RDD_EOF;
 342 
 343 out:
 344         VN_RELE(pvp);
 345         return (error);
 346 }
 347 
 348 /*
 349  * Get a buffer of directory entries (if we don't already have
 350  * some remaining in the current buffer) then decode one.
 351  */

 352 int
 353 smbfs_xa_findopen(struct smbfs_fctx *ctx, struct smbnode *dnp,
 354         const char *wildcard, int wclen)
 355 {





 356 
 357         ASSERT(dnp->n_flag & N_XATTR);

 358 
 359         ctx->f_type = ft_XA;
 360         ctx->f_namesz = SMB_MAXFNAMELEN + 1;
 361         ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 362         ctx->f_infolevel = FileStreamInformation;
 363         ctx->f_wildcard = wildcard;
 364         ctx->f_wclen = wclen;
 365 
 366         return (0);
 367 }

 368 









 369 
 370 /*
 371  * Get the next name in an XATTR directory

 372  */
 373 /* ARGSUSED */
 374 int
 375 smbfs_xa_findnext(struct smbfs_fctx *ctx, uint16_t limit)
 376 {
 377         int error;








 378 
 379         /*
 380          * If we've scanned to the end of the current buffer
 381          * try to read anohther buffer of dir entries.
 382          * Treat anything less than 8 bytes as an "empty"
 383          * buffer to ensure we can read something.
 384          * (There may be up to 8 bytes of padding.)
 385          */
 386 again:
 387         if ((ctx->f_eofs + 8) > ctx->f_left) {
 388                 /* Scanned the whole buffer. */
 389                 if (ctx->f_flags & SMBFS_RDD_EOF)
 390                         return (ENOENT);
 391                 ctx->f_limit = limit;
 392                 error = smbfs_xa_get_streaminfo(ctx);
 393                 if (error)
 394                         return (error);
 395                 ctx->f_otws++;
 396         }
 397 
 398         /*
 399          * Decode one entry, advance f_eofs
 400          */
 401         error = smbfs_decode_dirent(ctx);
 402         if (error)
 403                 return (error);
 404         SMBVDEBUG("name: %s\n", ctx->f_name);


 405 
 406         /*










 407          * Chop off the trailing ":$DATA"
 408          * The 6 here is strlen(":$DATA")
 409          */
 410         if (ctx->f_nmlen >= 6) {
 411                 char *p = ctx->f_name + ctx->f_nmlen - 6;
 412                 if (strncmp(p, ":$DATA", 6) == 0) {
 413                         *p = '\0'; /* Chop! */
 414                         ctx->f_nmlen -= 6;
 415                 }
 416         }
 417 
 418         /*
 419          * The Chop above will typically leave
 420          * an empty name in the first slot,
 421          * which we will skip here.
 422          */
 423         if (ctx->f_nmlen == 0)
 424                 goto again;
 425 
 426         /*
 427          * When called by lookup, we'll have the "single" flag,
 428          * and a name with no wildcards.  We need to filter here
 429          * because smbfs_xa_get_streaminfo() gets ALL the names
 430          * (not just those matching our pattern).
 431          */
 432         if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
 433                 if (ctx->f_wclen != ctx->f_nmlen)
 434                         goto again;
 435                 if (u8_strcmp(ctx->f_wildcard, ctx->f_name,
 436                     ctx->f_nmlen, U8_STRCMP_CI_LOWER,
 437                     U8_UNICODE_LATEST, &error) || error)
 438                         goto again;
 439         }
 440 
 441         return (0);
 442 }
 443 
 444 /*
 445  * Find first/next/close for XATTR directories.
 446  * NB: also used by smbfs_smb_lookup
 447  */
 448 
 449 int
 450 smbfs_xa_findclose(struct smbfs_fctx *ctx)
 451 {
 452 
 453         if (ctx->f_name)
 454                 kmem_free(ctx->f_name, ctx->f_namesz);


 455 
 456         return (0);
 457 }