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)

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
          +++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c
↓ open down ↓ 25 lines elided ↑ open up ↑
  26   26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   *
  32   32   * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $
  33   33   */
  34   34  
  35   35  /*
  36      - * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  37   36   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  38   37   * Use is subject to license terms.
       38 + *
       39 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  39   40   */
  40   41  
  41   42  #include <sys/param.h>
  42   43  #include <sys/systm.h>
  43   44  #include <sys/time.h>
  44   45  #include <sys/vnode.h>
  45   46  #include <sys/sunddi.h>
  46   47  
  47   48  #include <netsmb/smb_osdep.h>
  48   49  
  49   50  #include <netsmb/smb.h>
       51 +#include <netsmb/smb2.h>
  50   52  #include <netsmb/smb_conn.h>
  51   53  #include <netsmb/smb_subr.h>
  52   54  #include <netsmb/smb_rq.h>
  53   55  
  54   56  #include <smbfs/smbfs.h>
  55   57  #include <smbfs/smbfs_node.h>
  56   58  #include <smbfs/smbfs_subr.h>
  57   59  
  58   60  /*
  59   61   * In the Darwin code, this function used to compute the full path
↓ open down ↓ 6 lines elided ↑ open up ↑
  66   68   * Note that this logic must match that in smbfs_getino
  67   69   */
  68   70  int
  69   71  smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
  70   72          const char *name, int nmlen, u_int8_t sep)
  71   73  {
  72   74          int caseopt = SMB_CS_NONE;
  73   75          int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
  74   76          int error;
  75   77  
  76      -        if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
  77      -                caseopt |= SMB_CS_UPPER;
  78      -
  79      -        if (unicode) {
       78 +        /*
       79 +         * SMB1 may need an alignment pad before (not SMB2)
       80 +         */
       81 +        if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
       82 +            ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
  80   83                  error = mb_put_padbyte(mbp);
  81   84                  if (error)
  82   85                          return (error);
  83   86          }
  84   87  
  85   88          error = smb_put_dmem(mbp, vcp,
  86   89              dnp->n_rpath, dnp->n_rplen,
  87   90              caseopt, NULL);
  88   91          if (name) {
  89   92                  /*
↓ open down ↓ 25 lines elided ↑ open up ↑
 115  118                                  error = mb_put_uint8(mbp, sep);
 116  119                          if (error)
 117  120                                  return (error);
 118  121                  }
 119  122                  /* Put the name */
 120  123                  error = smb_put_dmem(mbp, vcp,
 121  124                      name, nmlen, caseopt, NULL);
 122  125                  if (error)
 123  126                          return (error);
 124  127          }
 125      -        /* Put NULL termination. */
 126      -        if (unicode)
 127      -                error = mb_put_uint16le(mbp, 0);
 128      -        else
 129      -                error = mb_put_uint8(mbp, 0);
 130  128  
      129 +        /* SMB1 wants NULL termination. */
      130 +        if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
      131 +                if (unicode)
      132 +                        error = mb_put_uint16le(mbp, 0);
      133 +                else
      134 +                        error = mb_put_uint8(mbp, 0);
      135 +        }
      136 +
 131  137          return (error);
 132  138  }
 133  139  
 134  140  /*
 135  141   * Convert a Unicode directory entry to UTF-8
 136  142   */
 137  143  void
 138  144  smbfs_fname_tolocal(struct smbfs_fctx *ctx)
 139  145  {
 140  146          uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
↓ open down ↓ 34 lines elided ↑ open up ↑
 175  181          ctx->f_nmlen = (int)outlen;
 176  182          return;
 177  183  
 178  184  errout:
 179  185          /*
 180  186           * Conversion failed, but our caller does not
 181  187           * deal with errors here, so just put a "?".
 182  188           * Don't expect to ever see this.
 183  189           */
 184  190          (void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
      191 +}
      192 +
      193 +/*
      194 + * Decode a directory entry from OtW form into ctx->f_attr
      195 + *
      196 + * Caller already put some (wire-format) directory entries
      197 + * into ctx->f_mdchain and we expect to find one.
      198 + *
      199 + * Advancing correctly through the buffer can be tricky if one
      200 + * tries to add up the size of an entry as you go (which is how
      201 + * the darwin code this is derived from did it).  The easiest way
      202 + * to correctly advance the position is to get a whole dirent
      203 + * into another mdchain (entry_mdc) based on NextEntryOffset,
      204 + * and then scan the data from that mdchain.  On the last entry,
      205 + * we don't know the entire length, so just scan directly from
      206 + * what remains of the multi-entry buffer instead of trying to
      207 + * figure out the length to copy into a separate mdchain.
      208 + */
      209 +int
      210 +smbfs_decode_dirent(struct smbfs_fctx *ctx)
      211 +{
      212 +        struct mdchain entry_mdc;
      213 +        struct mdchain *mdp = &ctx->f_mdchain;
      214 +        size_t nmlen;
      215 +        uint64_t llongint;
      216 +        uint32_t nmsize, dattr;
      217 +        uint32_t nextoff = 0;
      218 +        int error;
      219 +
      220 +        /* In case we error out... */
      221 +        ctx->f_nmlen = 0;
      222 +        ctx->f_rkey = (uint32_t)-1;
      223 +        bzero(&entry_mdc, sizeof (entry_mdc));
      224 +
      225 +        /*
      226 +         * Setup mdp to point to an mbchain holding
      227 +         * what should be a single directory entry.
      228 +         */
      229 +        error = md_get_uint32le(mdp, &nextoff);
      230 +        if (error != 0)
      231 +                goto errout;
      232 +        if (nextoff >= 4) {
      233 +                /*
      234 +                 * More entries follow.  Make a new mbchain
      235 +                 * holding just this one entry, then advance.
      236 +                 */
      237 +                mblk_t *m = NULL;
      238 +                error = md_get_mbuf(mdp, nextoff - 4, &m);
      239 +                if (error != 0)
      240 +                        goto errout;
      241 +                md_initm(&entry_mdc, m);
      242 +                mdp = &entry_mdc;
      243 +                ctx->f_eofs += nextoff;
      244 +        } else {
      245 +                /* Scan directly from ctx->f_mdchain */
      246 +                ctx->f_eofs = ctx->f_left;
      247 +        }
      248 +
      249 +        /*
      250 +         * Decode the fixed-size parts
      251 +         */
      252 +        switch (ctx->f_infolevel) {
      253 +        case FileFullDirectoryInformation:
      254 +        case SMB_FIND_FULL_DIRECTORY_INFO:
      255 +                md_get_uint32le(mdp, &ctx->f_rkey);     /* resume key (idx) */
      256 +                md_get_uint64le(mdp, &llongint);        /* creation time */
      257 +                smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
      258 +                md_get_uint64le(mdp, &llongint);
      259 +                smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
      260 +                md_get_uint64le(mdp, &llongint);
      261 +                smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
      262 +                md_get_uint64le(mdp, &llongint);
      263 +                smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
      264 +                md_get_uint64le(mdp, &llongint);        /* file size */
      265 +                ctx->f_attr.fa_size = llongint;
      266 +                md_get_uint64le(mdp, &llongint);        /* alloc. size */
      267 +                ctx->f_attr.fa_allocsz = llongint;
      268 +                md_get_uint32le(mdp, &dattr);   /* ext. file attributes */
      269 +                ctx->f_attr.fa_attr = dattr;
      270 +                error = md_get_uint32le(mdp, &nmsize);  /* name size (otw) */
      271 +                if (error)
      272 +                        goto errout;
      273 +                md_get_uint32le(mdp, NULL);     /* Ea size */
      274 +                break;
      275 +
      276 +        case FileStreamInformation:
      277 +                error = md_get_uint32le(mdp, &nmsize);  /* name size (otw) */
      278 +                md_get_uint64le(mdp, &llongint);        /* file size */
      279 +                ctx->f_attr.fa_size = llongint;
      280 +                md_get_uint64le(mdp, &llongint);        /* alloc. size */
      281 +                ctx->f_attr.fa_allocsz = llongint;
      282 +                /*
      283 +                 * Stream names start with a ':' that we want to skip.
      284 +                 * This is the easiest place to take care of that.
      285 +                 * Always unicode here.
      286 +                 */
      287 +                if (nmsize >= 2) {
      288 +                        struct mdchain save_mdc;
      289 +                        uint16_t wch;
      290 +                        save_mdc = *mdp;
      291 +                        md_get_uint16le(mdp, &wch);
      292 +                        if (wch == ':') {
      293 +                                /* OK, we skipped the ':' */
      294 +                                nmsize -= 2;
      295 +                        } else {
      296 +                                SMBVDEBUG("No leading : in stream?\n");
      297 +                                /* restore position */
      298 +                                *mdp = save_mdc;
      299 +                        }
      300 +                }
      301 +                break;
      302 +
      303 +        default:
      304 +                SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
      305 +                error = EINVAL;
      306 +                goto errout;
      307 +        }
      308 +
      309 +        /*
      310 +         * Get the filename, and convert to utf-8
      311 +         * Allocated f_name in findopen
      312 +         */
      313 +        nmlen = ctx->f_namesz;
      314 +        error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
      315 +            ctx->f_name, &nmlen, nmsize);
      316 +        if (error != 0)
      317 +                goto errout;
      318 +        ctx->f_nmlen = (int)nmlen;
      319 +        md_done(&entry_mdc);
      320 +        return (0);
      321 +
      322 +errout:
      323 +        /*
      324 +         * Something bad has happened and we ran out of data
      325 +         * before we could parse all f_ecnt entries expected.
      326 +         * Give up on the current buffer.
      327 +         */
      328 +        SMBVDEBUG("ran out of data\n");
      329 +        ctx->f_eofs = ctx->f_left;
      330 +        md_done(&entry_mdc);
      331 +        return (error);
      332 +}
      333 +
      334 +/*
      335 + * Decode FileAllInformation
      336 + *
      337 + * The data is a concatenation of:
      338 + *      FileBasicInformation
      339 + *      FileStandardInformation
      340 + *      FileInternalInformation
      341 + *      FileEaInformation
      342 + *      FilePositionInformation
      343 + *      FileModeInformation
      344 + *      FileAlignmentInformation
      345 + *      FileNameInformation
      346 + */
      347 +/*ARGSUSED*/
      348 +int
      349 +smbfs_decode_file_all_info(struct smb_share *ssp,
      350 +        struct mdchain *mdp, struct smbfattr *fap)
      351 +{
      352 +        uint64_t llongint, lsize;
      353 +        uint32_t dattr;
      354 +        int error;
      355 +
      356 +        /*
      357 +         * This part is: FileBasicInformation
      358 +         */
      359 +
      360 +        /* creation time */
      361 +        md_get_uint64le(mdp, &llongint);
      362 +        smb_time_NT2local(llongint, &fap->fa_createtime);
      363 +
      364 +        /* last access time */
      365 +        md_get_uint64le(mdp, &llongint);
      366 +        smb_time_NT2local(llongint, &fap->fa_atime);
      367 +
      368 +        /* last write time */
      369 +        md_get_uint64le(mdp, &llongint);
      370 +        smb_time_NT2local(llongint, &fap->fa_mtime);
      371 +
      372 +        /* last change time */
      373 +        md_get_uint64le(mdp, &llongint);
      374 +        smb_time_NT2local(llongint, &fap->fa_ctime);
      375 +
      376 +        /* attributes */
      377 +        md_get_uint32le(mdp, &dattr);
      378 +        fap->fa_attr = dattr;
      379 +
      380 +        /* reserved */
      381 +        md_get_uint32le(mdp, NULL);
      382 +
      383 +        /*
      384 +         * This part is: FileStandardInformation
      385 +         */
      386 +
      387 +        /* allocation size */
      388 +        md_get_uint64le(mdp, &lsize);
      389 +        fap->fa_allocsz = lsize;
      390 +
      391 +        /* File size */
      392 +        error = md_get_uint64le(mdp, &lsize);
      393 +        fap->fa_size = lsize;
      394 +
      395 +        /*
      396 +         * There's more after this but we don't need it:
      397 +         * Remainder of FileStandardInformation
      398 +         *      NumLlinks, DeletOnClose, IsDir, reserved.
      399 +         * Then:
      400 +         *      FileInternalInformation
      401 +         *      FileEaInformation
      402 +         *      FilePositionInformation
      403 +         *      FileModeInformation
      404 +         *      FileAlignmentInformation
      405 +         *      FileNameInformation
      406 +         */
      407 +
      408 +        return (error);
      409 +}
      410 +
      411 +/*
      412 + * Decode FileFsAttributeInformation
      413 + *
      414 + *    ULONG FileSystemAttributes;
      415 + *    LONG MaximumComponentNameLength;
      416 + *    ULONG FileSystemNameLength;
      417 + *    WCHAR FileSystemName[1];
      418 + */
      419 +int
      420 +smbfs_decode_fs_attr_info(struct smb_share *ssp,
      421 +        struct mdchain *mdp, struct smb_fs_attr_info *fsa)
      422 +{
      423 +        struct smb_vc *vcp = SSTOVC(ssp);
      424 +        uint32_t nlen;
      425 +        int error;
      426 +
      427 +        md_get_uint32le(mdp, &fsa->fsa_aflags);
      428 +        md_get_uint32le(mdp, &fsa->fsa_maxname);
      429 +        error = md_get_uint32le(mdp, &nlen);    /* fs name length */
      430 +        if (error)
      431 +                goto out;
      432 +
      433 +        /*
      434 +         * Get the FS type name.
      435 +         */
      436 +        bzero(fsa->fsa_tname, FSTYPSZ);
      437 +        if (SMB_UNICODE_STRINGS(vcp)) {
      438 +                uint16_t tmpbuf[FSTYPSZ];
      439 +                size_t tmplen, outlen;
      440 +
      441 +                if (nlen > sizeof (tmpbuf))
      442 +                        nlen = sizeof (tmpbuf);
      443 +                error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
      444 +                if (error != 0)
      445 +                        goto out;
      446 +                tmplen = nlen / 2;      /* UCS-2 chars */
      447 +                outlen = FSTYPSZ - 1;
      448 +                error = uconv_u16tou8(tmpbuf, &tmplen,
      449 +                    (uchar_t *)fsa->fsa_tname, &outlen,
      450 +                    UCONV_IN_LITTLE_ENDIAN);
      451 +        } else {
      452 +                if (nlen > (FSTYPSZ - 1))
      453 +                        nlen = FSTYPSZ - 1;
      454 +                error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
      455 +        }
      456 +
      457 +out:
      458 +        return (error);
 185  459  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX